2006-04-19 Mikael Hallendal <micke@imendio.com>
authorhallski <hallski>
Wed, 19 Apr 2006 11:42:53 +0000 (11:42 +0000)
committerhallski <hallski>
Wed, 19 Apr 2006 11:42:53 +0000 (11:42 +0000)
* Landing a patch by Martyn Russell for Win32.

* configure.ac: Updated for Win32 work
* examples/*: Updated and improved.
* loudmouth/Makefile.am:
* loudmouth/lm-connection.c:
- Abstracted out the low level socket handling to lm-sock.[ch] to make
  this file clean from OS dependant socket code.
* loudmouth/lm-internals.h:
* loudmouth/lm-parser.c:
* loudmouth/lm-proxy.c:
* loudmouth/lm-sha.c:
* loudmouth/lm-utils.c:
- Win32 work
* loudmouth/lm-sock.[ch]:
- Network abstraction layer.

25 files changed:
.cvsignore
ChangeLog
configure.ac
docs/reference/tmpl/lm-connection.sgml
docs/reference/tmpl/lm-error.sgml
docs/reference/tmpl/lm-message-handler.sgml
docs/reference/tmpl/lm-message-node.sgml
docs/reference/tmpl/lm-message.sgml
docs/reference/tmpl/lm-proxy.sgml
docs/reference/tmpl/lm-ssl.sgml
docs/reference/tmpl/lm-utils.sgml
examples/lm-send-async.c
examples/lm-send-sync.c
examples/test-http-proxy.c
examples/test-lm.c
loudmouth/Makefile.am
loudmouth/lm-connection.c
loudmouth/lm-internals.h
loudmouth/lm-parser.c
loudmouth/lm-proxy.c
loudmouth/lm-sha.c
loudmouth/lm-sock.c [new file with mode: 0644]
loudmouth/lm-sock.h [new file with mode: 0644]
loudmouth/lm-ssl-openssl.c
loudmouth/lm-utils.c

index b5bb7814dcec99704a81cf1a1a30ae45dca5f4df..948a214ff5d7de701e3030ccbd9890b0f482e6d1 100644 (file)
@@ -6,10 +6,13 @@ config.h*
 config.log
 config.status
 config.cache
+config.guess
+config.sub
 configure
 libtool
 *.tar.gz
 loudmouth.spec
+ltmain.sh
 stamp-h*
 loudmouth-1.0.pc
 *.swp
index 4c4501eb4ac2eb4e95fa82126abb3d97650ab531..3c82f95b8e097172a3fb0878d92a6d4755805d8a 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,22 @@
+2006-04-19  Mikael Hallendal  <micke@imendio.com>
+
+       * Landing a patch by Martyn Russell for Win32.
+
+       * configure.ac: Updated for Win32 work
+       * examples/*: Updated and improved.
+       * loudmouth/Makefile.am:
+       * loudmouth/lm-connection.c:
+       - Abstracted out the low level socket handling to lm-sock.[ch] to make
+         this file clean from OS dependant socket code.
+       * loudmouth/lm-internals.h:
+       * loudmouth/lm-parser.c:
+       * loudmouth/lm-proxy.c:
+       * loudmouth/lm-sha.c: 
+       * loudmouth/lm-utils.c:
+       - Win32 work
+       * loudmouth/lm-sock.[ch]: 
+       - Network abstraction layer.
+
 2006-04-18  Mikael Hallendal  <micke@imendio.com>
 
        * loudmouth/lm-ssl-openssl.c: (_lm_ssl_begin):
index 53de05b8c84e1beeb4a669b92840fbb4d7545e08..49594db6fc6daf06f2d1e7ee8d8a7c8ac72d0096 100644 (file)
@@ -1,4 +1,4 @@
-AC_INIT(Loudmouth, 1.0.3, loudmouth)
+AC_INIT(Loudmouth, 1.1.1, loudmouth)
 AC_PREREQ(2.59)
 AC_COPYRIGHT([Copyright (C) 2003-2006 Imendio AB])
 
@@ -8,13 +8,48 @@ AM_INIT_AUTOMAKE(1.9 dist-bzip2 no-define)
 
 AM_MAINTAINER_MODE
 
+AC_CANONICAL_HOST
+
+os_win32=no
+
+case "$host_os" in
+  *mingw32*)
+    os_win32=yes
+esac
+
+if test "$os_win32" = "yes"; then
+  if test "$enable_static" = "yes" -o "$enable_static" = ""; then
+    AC_MSG_WARN([Disabling static library build, must build as DLL on Windows.])
+    enable_static=no
+  fi
+
+  if test "$enable_shared" = "no"; then
+    AC_MSG_WARN([Enabling shared library build, must build as DLL on Windows.])
+  fi
+
+  enable_shared=yes
+
+  CFLAGS="$CFLAGS -mms-bitfields"
+  LDFLAGS="$LDFLAGS -no-undefined"
+fi
+
 AC_PROG_CC
 AC_ISC_POSIX
 AC_HEADER_STDC
+AC_LIBTOOL_WIN32_DLL
 AM_PROG_LIBTOOL
 
 AM_PATH_GLIB_2_0
 
+AC_CHECK_HEADERS([arpa/inet.h fcntl.h memory.h netdb.h netinet/in.h stdlib.h string.h sys/socket.h sys/time.h unistd.h]) 
+AC_CHECK_HEADERS([winsock2.h])
+
+if test "$ac_cv_header_winsock2_h" = "yes"; then
+  # If we have <winsock2.h>, assume we find the functions
+  # in -lws2_32 (ws2_32 is winsock v2, wsock32 is v1.1)
+  LIBS="-lws2_32 -lgdi32 $LIBS"
+fi
+
 IDT_COMPILE_WARNINGS
 
 changequote(,)dnl
@@ -50,7 +85,9 @@ dnl +--------------------+
 dnl | Check for gtk-doc. |-------------------------------
 dnl +--------------------+
 
-AC_ARG_WITH(html-dir, [  --with-html-dir=PATH path to installed docs ])
+AC_ARG_WITH(html-dir, 
+            AS_HELP_STRING([--with-html-dir=PATH],
+                          [path to installed docs]))
 
 if test "x$with_html_dir" = "x" ; then
   HTML_DIR='${datadir}/gtk-doc/html'
@@ -60,18 +97,28 @@ fi
 
 AC_SUBST(HTML_DIR)
 
+AC_CHECK_PROG(GTKDOC, gtkdoc-mkdb, true, false)
+
 gtk_doc_min_version=1.0
-AC_MSG_CHECKING([gtk-doc version >= $gtk_doc_min_version])
-if pkg-config --atleast-version=$gtk_doc_min_version gtk-doc; then
-  AC_MSG_RESULT(yes)
-  GTKDOC=true
-else
-  AC_MSG_RESULT(no)
-  GTKDOC=false
+if $GTKDOC ; then 
+  gtk_doc_version=`gtkdoc-mkdb --version`
+  AC_MSG_CHECKING([for gtk-doc version ($gtk_doc_version) >= $gtk_doc_min_version])
+  if perl <<EOF ; then
+    exit (("$gtk_doc_version" =~ /^[[0-9]]+\.[[0-9]]+$/) &&
+          ("$gtk_doc_version" >= "$gtk_doc_min_version") ? 0 : 1);
+EOF
+    AC_MSG_RESULT(yes)
+  else
+    AC_MSG_RESULT(no)
+    GTKDOC=false
+  fi
 fi
 
 dnl Let people disable the gtk-doc stuff.
-AC_ARG_ENABLE(gtk-doc, [  --enable-gtk-doc  Use gtk-doc to build documentation [default=no]], enable_gtk_doc="$enableval", enable_gtk_doc=no)
+AC_ARG_ENABLE(gtk-doc,
+              AS_HELP_STRING([--enable-gtk-doc=@<:@no/yes/auto@:>@],
+                             [Use gtk-doc to build documentation [[default=auto]]]), ,
+              enable_gtk_doc=auto)
 
 if test x$enable_gtk_doc = xauto ; then
   if test x$GTKDOC = xtrue ; then
@@ -85,7 +132,11 @@ AM_CONDITIONAL(ENABLE_GTK_DOC, test x$enable_gtk_doc = xyes)
 
 dnl define a MAINT-like variable REBUILD which is set if Perl
 dnl and awk are found, so autogenerated sources can be rebuilt
-AC_ARG_ENABLE(rebuilds, [  --disable-rebuilds      disable all source autogeneration rules],,enable_rebuilds=yes)
+AC_ARG_ENABLE(rebuilds,
+              AS_HELP_STRING([--enable-rebuilds=@<:@no/yes/auto@:>@],
+                             [Enable source autogeneration rules [[default=yes]]]), ,
+              enable_rebuilds=yes)
+
 REBUILD=\#
 if test "x$enable_rebuilds" = "xyes" && \
      test -n "$PERL" && \
@@ -106,8 +157,8 @@ dnl +--------------------------------------------------------+
 dnl | Checking for SSL support                               |-
 dnl +--------------------------------------------------------+
 AC_ARG_WITH(ssl,
-           AS_HELP_STRING([--with-ssl@<:@=gnutls|openssl|no@:>@], 
-                          [Which SSL implementation to use, default is gnutls]),
+           AS_HELP_STRING([--with-ssl=@<:@gnutls|openssl|no@:>@], 
+                          [Which SSL implementation to use [[default=gnutls]]]),
            ac_ssl=$withval,
            ac_ssl=gnutls)
 
@@ -122,32 +173,43 @@ AC_ARG_WITH(openssl-libs,
            )
 
 enable_ssl=no
-if test x$ac_ssl = xgnutls; then
-       dnl Look for GnuTLS
-       AM_PATH_LM_LIBGNUTLS($GNUTLS_REQUIRED, have_libgnutls=yes, have_libgnutls=no)
-       if test x$have_libgnutls = xyes; then
-               CFLAGS="$CFLAGS $LIBGNUTLS_CFLAGS"
-               LIBS="$LIBS $LIBGNUTLS_LIBS"
-               AC_DEFINE(HAVE_GNUTLS, 1, [whether to use GnuTSL support.])
-               enable_ssl=GnuTLS
-       else
-               AC_MSG_ERROR([GnuTLS was not found, use --with-ssl=no|openssl to build without SSL support or with OpenSSL])
-       fi
-elif test x$ac_ssl = xopenssl; then
-       dnl Look for OpenSSL
-       AC_CHECK_HEADERS([openssl/ssl.h])
-       OLDLIBS="$LIBS"
-       AC_CHECK_LIB(crypto, BIO_f_base64, [
-                                           AC_CHECK_LIB(ssl, SSL_new, [ SSL_LIB="-lssl -lcrypto"
-                                                                       AC_DEFINE(HAVE_OPENSSL, [], [Have OpenSSL]) ], [ have_openssl=no ], [ -lcrypto ])
-                                           ], [ have_openssl=no ], [])
-
-       if test x$have_openssl = xno; then
-               AC_MSG_ERROR([OpenSSL was not found, use --with-ssl=no|gnutls to build without SSL support or with GnuTLS])
-       else 
-               LIBS="$OLDLIBS $SSL_LIB"
-               enable_ssl=OpenSSL
-       fi
+if test "x$ac_ssl" = "xgnutls"; then
+  dnl Look for GnuTLS
+  AM_PATH_LM_LIBGNUTLS($GNUTLS_REQUIRED, have_libgnutls=yes, have_libgnutls=no)
+  if test "x$have_libgnutls" = "xyes"; then
+    CFLAGS="$CFLAGS $LIBGNUTLS_CFLAGS"
+    LIBS="$LIBS $LIBGNUTLS_LIBS"
+    AC_DEFINE(HAVE_GNUTLS, 1, [whether to use GnuTSL support.])
+    enable_ssl=GnuTLS
+  else
+    AC_MSG_ERROR([GnuTLS was not found, use
+               --with-ssl=[[no|openssl]] to build without SSL support or
+               with OpenSSL])
+  fi
+elif test "$ac_ssl" = "openssl"; then
+  dnl Look for OpenSSL
+  AC_CHECK_HEADERS([openssl/ssl.h])
+  OLDLIBS="$LIBS"
+  AC_CHECK_LIB(crypto, 
+              BIO_f_base64, 
+              [AC_CHECK_LIB(ssl, 
+                            SSL_new, 
+                             [SSL_LIB="-lssl -lcrypto"
+                            AC_DEFINE(HAVE_OPENSSL, 
+                                      [], 
+                                      [Have OpenSSL])], 
+                            [have_openssl=no], 
+                            [-lcrypto])], 
+              [have_openssl=no], 
+              [])
+
+  if test "x$have_openssl" = "xno"; then
+    AC_MSG_ERROR([OpenSSL was not found, use --with-ssl=[[no|gnutls]] to
+                  build without SSL support or with GnuTLS])
+  else 
+    LIBS="$OLDLIBS $SSL_LIB"
+    enable_ssl=OpenSSL
+  fi
 else
        echo "Disabling SSL support"
 fi
@@ -178,9 +240,10 @@ dnl +--------------+
 dnl | Debug output |-------------------------------------------
 dnl +--------------+
 
-AC_ARG_ENABLE(debug, 
-             [  --enable-debug          Enable debug output [default=yes]],
-             enable_debug="$enableval", enable_debug=yes, enable_debug=no)
+AC_ARG_ENABLE(debug,
+              AS_HELP_STRING([--enable-debug=@<:@no/yes/auto@:>@],
+                             [Enable debugging [[default=yes]]]), ,
+              enable_debug=yes)
 
 if test x$enable_debug = xno ; then
        echo "Debugging disabled"
@@ -192,8 +255,6 @@ fi
 AC_SUBST(LOUDMOUTH_CFLAGS)
 AC_SUBST(LOUDMOUTH_LIBS)
 
-dnl Gtk doc
-GTK_DOC_CHECK(1.0)
 
 dnl +--------------------------------------+
 dnl | Check if we shoudl build C# bindings |-------------------
@@ -245,7 +306,8 @@ echo "
         Enable SSL                ${enable_ssl}
         Enable Debug:             ${enable_debug}
        Enable Unit Tests:        ${have_check}
-
+       Enable Documentation      ${enable_gtk_doc}
+       
         Now type 'make' to build Loudmouth
 "
 
index a43821cdbe5bb34de143dc9d548ead536b5701d7..114c9489ab4b86c8236399f5e69e336af84d53d9 100644 (file)
@@ -51,6 +51,9 @@ main (int argc, char **argv)
 
 </para>
 
+<!-- ##### SECTION Stability_Level ##### -->
+
+
 <!-- ##### MACRO LM_CONNECTION ##### -->
 <para>
 Convenience macro used to cast a pointer to a #LmConnection.
index 2b479e2979385233737455dc8624db3cc1021cf2..b6965d2ee5a08ff10796f3e244a20a8930cd1c73 100644 (file)
@@ -14,6 +14,9 @@ Error reporting.
 
 </para>
 
+<!-- ##### SECTION Stability_Level ##### -->
+
+
 <!-- ##### FUNCTION lm_error_quark ##### -->
 <para>
 -
index 723c7e76d6da61b0deb04aad5b43eeaa69ecf98f..6df7286a48b39886ba547061b868c54c4b9b7140 100644 (file)
@@ -14,6 +14,9 @@ A handler for incoming messages.
 
 </para>
 
+<!-- ##### SECTION Stability_Level ##### -->
+
+
 <!-- ##### USER_FUNCTION LmHandleMessageFunction ##### -->
 <para>
 The actual callback function in an #LmMessageHandler. This function is called when an incoming message arrives that haven't been handled by an handler with higher priority.
index 024f00d207b9c31c35cc7588c2353950cb57903e..a73198137914b4e251f6c45b2a1866dbd8aeac29 100644 (file)
@@ -14,6 +14,9 @@ A node in the message tree
 
 </para>
 
+<!-- ##### SECTION Stability_Level ##### -->
+
+
 <!-- ##### STRUCT LmMessageNode ##### -->
 <para>
 A struct representing a node in a message. 
index 7dd2ed941fa0fbaed2e0f2266b5053d70fe4098e..df9e60b8eedd3a937c58849529c9fec0beedc7db 100644 (file)
@@ -15,6 +15,9 @@ Represents a message that can be sent with lm_connection_send(), lm_connection_s
 
 </para>
 
+<!-- ##### SECTION Stability_Level ##### -->
+
+
 <!-- ##### STRUCT LmMessage ##### -->
 <para>
 Struct 
index 27d70a1468793d1856564f195ef99e68d1688730..93c1c54eeaee0f56828adc3c594e7670a5ef4939 100644 (file)
@@ -24,6 +24,9 @@ lm_connection_set_proxy (connection, proxy);
 
 </para>
 
+<!-- ##### SECTION Stability_Level ##### -->
+
+
 <!-- ##### STRUCT LmProxy ##### -->
 <para>
 This should not be accessed directly. Use the accessor functions as described below.
index 6ed373e81b284eeedee88825f9c1f1bed3ee489b..dae66422439f44f42848e845820724752b25b466 100644 (file)
@@ -23,6 +23,9 @@ lm_connection_set_ssl (connection, ssl);
 
 </para>
 
+<!-- ##### SECTION Stability_Level ##### -->
+
+
 <!-- ##### STRUCT LmSSL ##### -->
 <para>
 This should not be accessed directly. Use the accessor functions as described below.
index 2b62f97259210daa9d5300c5554ca560f90ce92c..6531287d39f522a2320cef942755675c552b02b5 100644 (file)
@@ -14,3 +14,6 @@ lm-utils
 
 </para>
 
+<!-- ##### SECTION Stability_Level ##### -->
+
+
index 830a34739b988a6386afe9e9edc4f8256fcb5f3a..a256f13acf98da9fdd9d1721f35b81d31b654383 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
 /*
- * Copyright (C) 2003 Imendio AB
+ * Copyright (C) 2003-2006 Imendio AB
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
 
 #include <stdlib.h>
 #include <string.h>
+
 #include <loudmouth/loudmouth.h>
 
-typedef struct {
-        const gchar *recipient;
-        const gchar *message;
-} MessageData;
+static GMainLoop *main_loop;
+static gboolean   test_success = FALSE;
 
-typedef struct {
-        const gchar *username;
-        const gchar *password;
-        const gchar *resource;
-        MessageData *msg_data;
-} ConnectData;
+static gchar      expected_fingerprint[20];
 
-static GMainLoop *main_loop;
+static gchar     *server = NULL;
+static gint       port = 5222;
+static gchar     *username = NULL;
+static gchar     *password = NULL;
+static gchar     *resource = "lm-send-async";
+static gchar     *recipient = NULL;
+static gchar     *fingerprint = NULL;
+static gchar     *message = "test asynchronous message";
+
+static GOptionEntry entries[] = 
+{
+  { "server", 's', 0, G_OPTION_ARG_STRING, &server, 
+    "Server to connect to", NULL },
+  { "port", 'P', 0, G_OPTION_ARG_INT, &port, 
+    "Port to connect to [default=5222]", NULL },
+  { "username", 'u', 0, G_OPTION_ARG_STRING, &username, 
+    "Username to connect with (e.g. 'user' in user@server.org)", NULL },
+  { "password", 'p', 0, G_OPTION_ARG_STRING, &password, 
+    "Password to try", NULL },
+  { "resource", 'r', 0, G_OPTION_ARG_STRING, &resource, 
+    "Resource connect with [default=lm-send-async]", NULL },
+  { "recipient", 'R', 0, G_OPTION_ARG_STRING, &recipient, 
+    "Recipient to send the message to (e.g. user@server.org)", NULL },
+  { "fingerprint", 'f', 0, G_OPTION_ARG_STRING, &fingerprint, 
+    "SSL Fingerprint to use", NULL },
+  { "message", 'm', 0, G_OPTION_ARG_STRING, &message, 
+    "Message to send to recipient [default=test message]", NULL },
+  { NULL }
+};
 
 static void
-print_usage (const gchar *exec_name) 
+print_finger (const char   *fpr,
+             unsigned int  size)
 {
-        g_print ("Usage: %s -s <server> -u <username> -p <password> -m <message> -t <recipient> [--port <port>] [-r <resource>]\n", exec_name);
+       gint i;
+       for (i = 0; i < size-1; i++) {
+               g_printerr ("%02X:", fpr[i]);
+       }
+       
+       g_printerr ("%02X", fpr[size-1]);
+}
+
+static LmSSLResponse
+ssl_cb (LmSSL       *ssl, 
+       LmSSLStatus  status, 
+       gpointer     ud)
+{
+       g_print ("LmSendAsync: SSL status:%d\n", status);
+
+       switch (status) {
+       case LM_SSL_STATUS_NO_CERT_FOUND:
+               g_printerr ("LmSendAsync: No certificate found!\n");
+               break;
+       case LM_SSL_STATUS_UNTRUSTED_CERT:
+               g_printerr ("LmSendAsync: Certificate is not trusted!\n"); 
+               break;
+       case LM_SSL_STATUS_CERT_EXPIRED:
+               g_printerr ("LmSendAsync: Certificate has expired!\n"); 
+               break;
+       case LM_SSL_STATUS_CERT_NOT_ACTIVATED:
+               g_printerr ("LmSendAsync: Certificate has not been activated!\n"); 
+               break;
+       case LM_SSL_STATUS_CERT_HOSTNAME_MISMATCH:
+               g_printerr ("LmSendAsync: Certificate hostname does not match expected hostname!\n"); 
+               break;
+       case LM_SSL_STATUS_CERT_FINGERPRINT_MISMATCH: {
+               const char *fpr = lm_ssl_get_fingerprint (ssl);
+               g_printerr ("LmSendAsync: Certificate fingerprint does not match expected fingerprint!\n"); 
+               g_printerr ("LmSendAsync: Remote fingerprint: ");
+               print_finger (fpr, 16);
+
+               g_printerr ("\n"
+                           "LmSendAsync: Expected fingerprint: ");
+               print_finger (expected_fingerprint, 16);
+               g_printerr ("\n");
+               break;
+       }
+       case LM_SSL_STATUS_GENERIC_ERROR:
+               g_printerr ("LmSendAsync: Generic SSL error!\n"); 
+               break;
+       }
+
+       return LM_SSL_RESPONSE_CONTINUE;
 }
 
 static void
 connection_auth_cb (LmConnection *connection, 
                     gboolean      success, 
-                    MessageData  *data)
+                    gpointer      user_data)
 {
-        LmMessage *m;
-        gboolean   result;
-        GError    *error = NULL;
-
-        if (!success) {
-                g_error ("Authentication failed");
-        }
-        
-        m = lm_message_new (data->recipient, LM_MESSAGE_TYPE_MESSAGE);
-        lm_message_node_add_child (m->node, "body", data->message);
-        
-        result = lm_connection_send (connection, m, &error);
-        lm_message_unref (m);
-        
-        if (!result) {
-                g_error ("lm_connection_send failed");
-        }
-
-        lm_connection_close (connection, NULL);
-        
-        g_main_loop_quit (main_loop);
+       if (success) {
+               GError    *error = NULL;
+               LmMessage *m;
+
+               g_print ("LmSendAsync: Authenticated successfully\n");
+               
+               m = lm_message_new (recipient, LM_MESSAGE_TYPE_MESSAGE);
+               lm_message_node_add_child (m->node, "body", message);
+               
+               if (!lm_connection_send (connection, m, &error)) {
+                       g_printerr ("LmSendAsync: Failed to send message:'%s'\n", 
+                                lm_message_node_to_string (m->node));
+               } else {
+                       g_print ("LmSendAsync: Sent message:'%s'\n", 
+                                lm_message_node_to_string (m->node));
+                       test_success = TRUE;
+               }
+               
+               lm_message_unref (m);
+       } else {
+               g_printerr ("LmSendAsync: Failed to authenticate\n");
+       }
+
+       lm_connection_close (connection, NULL);
+       g_main_loop_quit (main_loop);
 }
 
 static void
-connection_open_result_cb (LmConnection *connection,
-                           gboolean      success,
-                           ConnectData  *data)
+connection_open_cb (LmConnection *connection,
+                   gboolean      success,
+                   gpointer      user_data)
 {
-        GError *error = NULL;
-        
-        if (!success) {
-                g_error ("Connection failed");
-        }
-
-        if (!lm_connection_authenticate (connection, data->username,
-                                         data->password, data->resource,
-                                         (LmResultFunction) connection_auth_cb,
-                                         data->msg_data,
-                                         g_free,
-                                         &error)) {
-                g_error ("lm_connection_authenticate failed");
-        }
+       if (success) {
+               if (!lm_connection_authenticate (connection, username, 
+                                                password, resource,
+                                                connection_auth_cb, 
+                                                NULL, FALSE,  NULL)) {
+                       g_printerr ("LmSendAsync: Failed to send authentication\n");
+                       g_main_loop_quit (main_loop);
+                       return;
+               }
+               
+               g_print ("LmSendAsync: Sent authentication message\n");
+       } else {
+               g_printerr ("LmSendAsync: Failed to connect\n");
+               g_main_loop_quit (main_loop);
+       }
 }
 
 int
 main (int argc, char **argv)
 {
-        LmConnection *connection;
-       GMainContext *context;
-        const gchar  *server = NULL;
-        const gchar  *resource = "jabber-send";
-        const gchar  *recipient = NULL;
-        const gchar  *message = NULL;
-        const gchar  *username = NULL;
-        const gchar  *password = NULL;
-        guint         port = LM_CONNECTION_DEFAULT_PORT;
-        MessageData  *msg_data;
-        ConnectData  *connect_data;
-        GError       *error = NULL;
-        gint          i;
-
-        for (i = 1; i < argc - 1; ++i) {
-                gboolean arg = FALSE;
-                
-                if (strcmp ("-s", argv[i]) == 0) {
-                        server = argv[i+1];
-                        arg = TRUE;
-                }
-                else if (strcmp ("--port", argv[i]) == 0) {
-                        port = atoi (argv[i+1]);
-                        arg = TRUE;
-                }
-                else if (strcmp ("-m", argv[i]) == 0) {
-                        message = argv[i+1];
-                        arg = TRUE;
-                }
-                else if (strcmp ("-r", argv[i]) == 0) {
-                        resource = argv[i+1];
-                        arg = TRUE;
-                }
-                else if (strcmp ("-t", argv[i]) == 0) {
-                        recipient = argv[i+1];
-                        arg = TRUE;
-                }
-                else if (strcmp ("-u", argv[i]) == 0) {
-                        username = argv[i+1];
-                        arg = TRUE;
-                }
-                else if (strcmp ("-p", argv[i]) == 0) {
-                        password = argv[i+1];
-                        arg = TRUE;
-                }
-
-                if (arg) {
-                        ++i;
-                }
-        }
-
-        if (!server || !message || !recipient || !username || !password) {
-                print_usage (argv[0]);
-                return -1;
-        }
-        
-       context = g_main_context_new ();
-        connection = lm_connection_new_with_context (server, context);
-
-        msg_data = g_new0 (MessageData, 1);
-        msg_data->recipient = recipient;
-        msg_data->message = message;
-       
-        connect_data = g_new0 (ConnectData, 1);
-        connect_data->username = username;
-        connect_data->password = password;
-        connect_data->resource = resource;
-        connect_data->msg_data = msg_data;
-        
-        if (!lm_connection_open (connection, 
-                                 (LmResultFunction) connection_open_result_cb,
-                                 connect_data,
-                                 g_free,
-                                 &error)) {
-                g_error ("lm_connection_open failed");
+       GMainContext   *main_context;
+       GOptionContext *context;
+        LmConnection   *connection;
+
+       context = g_option_context_new ("- test send message asynchronously");
+       g_option_context_add_main_entries (context, entries, NULL);
+       g_option_context_parse (context, &argc, &argv, NULL);
+       g_option_context_free (context);
+       
+       if (!server || !username || !password || !recipient) {
+               g_printerr ("For usage, try %s --help\n", argv[0]);
+               return EXIT_FAILURE;
+       }
+
+       main_context = g_main_context_new ();
+        connection = lm_connection_new_with_context (server, main_context);
+       lm_connection_set_port (connection, port);
+
+       if (fingerprint) {
+               LmSSL *ssl;
+               char  *p;
+               int    i;
+               
+               if (port == LM_CONNECTION_DEFAULT_PORT) {
+                       lm_connection_set_port (connection,
+                                               LM_CONNECTION_DEFAULT_PORT_SSL);
+               }
+
+               for (i = 0, p = fingerprint; *p && *(p+1); i++, p += 3) {
+                       expected_fingerprint[i] = (unsigned char) g_ascii_strtoull (p, NULL, 16);
+               }
+       
+               ssl = lm_ssl_new (expected_fingerprint,
+                                 (LmSSLFunction) ssl_cb,
+                                 NULL, NULL);
+       
+               lm_connection_set_ssl (connection, ssl);
+               lm_ssl_unref (ssl);
+       }
+
+       if (!lm_connection_open (connection, 
+                                 (LmResultFunction) connection_open_cb,
+                                 NULL, NULL, NULL)) {
+                g_printerr ("LmSendAsync: Could not open a connection\n");
+               return EXIT_FAILURE;
         }
 
-        main_loop = g_main_loop_new (context, FALSE);
+        main_loop = g_main_loop_new (main_context, FALSE);
         g_main_loop_run (main_loop);
 
-        return 0;
+       return (test_success ? EXIT_SUCCESS : EXIT_FAILURE);
 }
index 5963ff468204691fc702205f9cbf64174950beea..2b0163e61ac671e044401cfd7688c9f5328157da 100644 (file)
  * gcc -o lm-send-sync `pkg-config --cflags --libs loudmouth-1.0` lm-send-sync.c
  */
 
-#include <loudmouth/loudmouth.h>
 #include <string.h>
 #include <stdlib.h>
 
+#include <loudmouth/loudmouth.h>
+
+static gchar      expected_fingerprint[20];
+
+static gchar     *server = NULL;
+static gint       port = 5222;
+static gchar     *username = NULL;
+static gchar     *password = NULL;
+static gchar     *resource = "lm-send-sync";
+static gchar     *recipient = NULL;
+static gchar     *fingerprint = NULL;
+static gchar     *message = "test synchronous message";
+
+static GOptionEntry entries[] = 
+{
+  { "server", 's', 0, G_OPTION_ARG_STRING, &server, 
+    "Server to connect to", NULL },
+  { "port", 'P', 0, G_OPTION_ARG_INT, &port, 
+    "Port to connect to [default=5222]", NULL },
+  { "username", 'u', 0, G_OPTION_ARG_STRING, &username, 
+    "Username to connect with (e.g. 'user' in user@server.org)", NULL },
+  { "password", 'p', 0, G_OPTION_ARG_STRING, &password, 
+    "Password to try", NULL },
+  { "resource", 'r', 0, G_OPTION_ARG_STRING, &resource, 
+    "Resource connect with [default=lm-send-sync]", NULL },
+  { "recipient", 'R', 0, G_OPTION_ARG_STRING, &recipient, 
+    "Recipient to send the message to (e.g. user@server.org)", NULL },
+  { "fingerprint", 'f', 0, G_OPTION_ARG_STRING, &fingerprint, 
+    "SSL Fingerprint to use", NULL },
+  { "message", 'm', 0, G_OPTION_ARG_STRING, &message, 
+    "Message to send to recipient [default=test synchronous message]", NULL },
+  { NULL }
+};
+
 static void
-print_usage (const gchar *exec_name) 
+print_finger (const char   *fpr,
+             unsigned int  size)
 {
-        g_print ("Usage: %s -s <server> -u <username> -p <password> -m <message> -t <recipient> [--port <port>] [-r <resource>]\n", exec_name);
+       gint i;
+       for (i = 0; i < size-1; i++) {
+               g_printerr ("%02X:", fpr[i]);
+       }
+       
+       g_printerr ("%02X", fpr[size-1]);
+}
+
+static LmSSLResponse
+ssl_cb (LmSSL       *ssl, 
+       LmSSLStatus  status, 
+       gpointer     ud)
+{
+       g_print ("LmSendSync: SSL status:%d\n", status);
+
+       switch (status) {
+       case LM_SSL_STATUS_NO_CERT_FOUND:
+               g_printerr ("LmSendSync: No certificate found!\n");
+               break;
+       case LM_SSL_STATUS_UNTRUSTED_CERT:
+               g_printerr ("LmSendSync: Certificate is not trusted!\n"); 
+               break;
+       case LM_SSL_STATUS_CERT_EXPIRED:
+               g_printerr ("LmSendSync: Certificate has expired!\n"); 
+               break;
+       case LM_SSL_STATUS_CERT_NOT_ACTIVATED:
+               g_printerr ("LmSendSync: Certificate has not been activated!\n"); 
+               break;
+       case LM_SSL_STATUS_CERT_HOSTNAME_MISMATCH:
+               g_printerr ("LmSendSync: Certificate hostname does not match expected hostname!\n"); 
+               break;
+       case LM_SSL_STATUS_CERT_FINGERPRINT_MISMATCH: {
+               const char *fpr = lm_ssl_get_fingerprint (ssl);
+               g_printerr ("LmSendSync: Certificate fingerprint does not match expected fingerprint!\n"); 
+               g_printerr ("LmSendSync: Remote fingerprint: ");
+               print_finger (fpr, 16);
+
+               g_printerr ("\n"
+                           "LmSendSync: Expected fingerprint: ");
+               print_finger (expected_fingerprint, 16);
+               g_printerr ("\n");
+               break;
+       }
+       case LM_SSL_STATUS_GENERIC_ERROR:
+               g_printerr ("LmSendSync: Generic SSL error!\n"); 
+               break;
+       }
+
+       return LM_SSL_RESPONSE_CONTINUE;
 }
 
 int
 main (int argc, char **argv)
 {
-        LmConnection *connection;
-        const gchar  *server = NULL;
-        const gchar  *resource = "jabber-send";
-        const gchar  *recipient = NULL;
-        const gchar  *message = NULL;
-        const gchar  *username = NULL;
-        const gchar  *password = NULL;
-        guint         port = LM_CONNECTION_DEFAULT_PORT;
-        GError       *error = NULL;
-        gint          i;
-       LmMessage    *m;
-
-        for (i = 1; i < argc - 1; ++i) {
-                gboolean arg = FALSE;
-                
-                if (strcmp ("-s", argv[i]) == 0) {
-                        server = argv[i+1];
-                        arg = TRUE;
-                }
-                else if (strcmp ("--port", argv[i]) == 0) {
-                        port = atoi (argv[i+1]);
-                        arg = TRUE;
-                }
-                else if (strcmp ("-m", argv[i]) == 0) {
-                        message = argv[i+1];
-                        arg = TRUE;
-                }
-                else if (strcmp ("-r", argv[i]) == 0) {
-                        resource = argv[i+1];
-                        arg = TRUE;
-                }
-                else if (strcmp ("-t", argv[i]) == 0) {
-                        recipient = argv[i+1];
-                        arg = TRUE;
-                }
-                else if (strcmp ("-u", argv[i]) == 0) {
-                        username = argv[i+1];
-                        arg = TRUE;
-                }
-                else if (strcmp ("-p", argv[i]) == 0) {
-                        password = argv[i+1];
-                        arg = TRUE;
-                }
-
-                if (arg) {
-                        ++i;
-                }
-        }
+       GOptionContext *context;
+       GError         *error = NULL;
+        LmConnection   *connection;
+       LmMessage      *m;
+
+       context = g_option_context_new ("- test send message synchronously");
+       g_option_context_add_main_entries (context, entries, NULL);
+       g_option_context_parse (context, &argc, &argv, NULL);
+       g_option_context_free (context);
+       
+       if (!server || !username || !password || !recipient) {
+               g_printerr ("For usage, try %s --help\n", argv[0]);
+               return EXIT_FAILURE;
+       }
 
-        if (!server || !message || !recipient || !username || !password) {
-                print_usage (argv[0]);
-                return -1;
-        }
-        
         connection = lm_connection_new (server);
+       lm_connection_set_port (connection, port);
+
+       if (fingerprint) {
+               LmSSL *ssl;
+               char  *p;
+               int    i;
+               
+               if (port == LM_CONNECTION_DEFAULT_PORT) {
+                       lm_connection_set_port (connection,
+                                               LM_CONNECTION_DEFAULT_PORT_SSL);
+               }
+
+               for (i = 0, p = fingerprint; *p && *(p+1); i++, p += 3) {
+                       expected_fingerprint[i] = (unsigned char) g_ascii_strtoull (p, NULL, 16);
+               }
+       
+               ssl = lm_ssl_new (expected_fingerprint,
+                                 (LmSSLFunction) ssl_cb,
+                                 NULL, NULL);
+       
+               lm_connection_set_ssl (connection, ssl);
+               lm_ssl_unref (ssl);
+       }
 
         if (!lm_connection_open_and_block (connection, &error)) {
-                g_error ("Failed to open: %s\n", error->message);
+                g_printerr ("LmSendSync: Could not open a connection: %s\n", error->message);
+               return EXIT_FAILURE;
         }
 
        if (!lm_connection_authenticate_and_block (connection,
                                                   username, password, resource,
                                                   &error)) {
-               g_error ("Failed to authenticate: %s\n", error->message);
+               g_printerr ("LmSendSync: Failed to authenticate: %s\n", error->message);
+               return EXIT_FAILURE;
        }
        
        m = lm_message_new (recipient, LM_MESSAGE_TYPE_MESSAGE);
        lm_message_node_add_child (m->node, "body", message);
        
        if (!lm_connection_send (connection, m, &error)) {
-               g_error ("Send failed: %s\n", error->message);
+               g_printerr ("LmSendSync: Failed to send message: %s\n", error->message);
+               return EXIT_FAILURE;
        }
 
        lm_message_unref (m);
@@ -117,6 +186,6 @@ main (int argc, char **argv)
        lm_connection_close (connection, NULL);
        lm_connection_unref (connection);
        
-        return 0;
+       return EXIT_SUCCESS;
 }
 
index 5b3546b93894e42829d80ead033a65c0f1aa5352..649d422e8ebd5ba8d52ffd3c31a4778fec35f83c 100644 (file)
@@ -24,7 +24,7 @@
 #include <string.h>
 #include <stdlib.h>
 #include <loudmouth/loudmouth.h>
-#ifdef __WIN32__
+#ifdef G_OS_WIN32
 #include <winsock2.h>
 #endif
  
index bad829116a9ff9bdf580081ca25d83aa00be4e0b..1ec2d7547510151070462c327fd7cb6c5beb2963 100644 (file)
@@ -1,7 +1,6 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
 /*
- * Copyright (C) 2003 Imendio AB
- * Copyright (C) 2003 Mikael Hallendal <micke@imendio.com>
+ * Copyright (C) 2003-2006 Imendio AB
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public License as
 
 #include <config.h>
 
-#include <glib.h>
 #include <string.h>
 #include <stdlib.h>
+
+#include <glib.h>
 #include <loudmouth/loudmouth.h>
-#ifdef __WIN32__
-#include <winsock2.h>
-#endif
 
-typedef struct {
-       gchar *name;
-       gchar *passwd;
-} UserInfo;
+static GMainLoop *main_loop = NULL;
+static gboolean   test_success = FALSE;
 
-static void 
-free_user_info (UserInfo *info)
-{
-       g_free (info->name);
-       g_free (info->passwd);
+static gchar      expected_fingerprint[20];
 
-       g_free (info);
-}
+static gchar     *server = NULL;
+static gint       port = 5222;
+static gchar     *username = NULL;
+static gchar     *password = NULL;
+static gchar     *resource = "test-lm";
+static gchar     *fingerprint = NULL;
 
-static char expected_fingerprint[20];
+static GOptionEntry entries[] = 
+{
+  { "server", 's', 0, G_OPTION_ARG_STRING, &server, 
+    "Server to connect to", NULL },
+  { "port", 'P', 0, G_OPTION_ARG_INT, &port, 
+    "Port to connect to [default=5222]", NULL },
+  { "username", 'u', 0, G_OPTION_ARG_STRING, &username, 
+    "Username to connect with (e.g. 'user' in user@server.org)", NULL },
+  { "password", 'p', 0, G_OPTION_ARG_STRING, &password, 
+    "Password to try", NULL },
+  { "resource", 'r', 0, G_OPTION_ARG_STRING, &resource, 
+    "Resource connect with [default=test-lm]", NULL },
+  { "fingerprint", 'f', 0, G_OPTION_ARG_STRING, &fingerprint, 
+    "SSL Fingerprint to use", NULL },
+  { NULL }
+};
 
 static void
-print_finger (const char *fpr, unsigned int size)
+print_finger (const char   *fpr,
+             unsigned int  size)
 {
        gint i;
-       
        for (i = 0; i < size-1; i++) {
-               g_print ("%02X:", fpr[i]);
+               g_printerr ("%02X:", fpr[i]);
        }
        
-       g_print ("%02X", fpr[size-1]);
+       g_printerr ("%02X", fpr[size-1]);
 }
 
 static LmSSLResponse
-ssl_cb (LmSSL *ssl, LmSSLStatus status, gpointer ud)
+ssl_cb (LmSSL       *ssl, 
+       LmSSLStatus  status, 
+       gpointer     ud)
 {
-       g_print ("SSL status: %d\n", status);
+       g_print ("TestLM: SSL status:%d\n", status);
+
        switch (status) {
        case LM_SSL_STATUS_NO_CERT_FOUND:
-               g_print ("No certificate found!\n");
+               g_printerr ("TestLM: No certificate found!\n");
                break;
        case LM_SSL_STATUS_UNTRUSTED_CERT:
-               g_print ("Certificate is not trusted!\n"); 
+               g_printerr ("TestLM: Certificate is not trusted!\n"); 
                break;
        case LM_SSL_STATUS_CERT_EXPIRED:
-               g_print ("Certificate has expired!\n"); 
+               g_printerr ("TestLM: Certificate has expired!\n"); 
                break;
        case LM_SSL_STATUS_CERT_NOT_ACTIVATED:
-               g_print ("Certificate has not been activated!\n"); 
+               g_printerr ("TestLM: Certificate has not been activated!\n"); 
                break;
        case LM_SSL_STATUS_CERT_HOSTNAME_MISMATCH:
-               g_print ("Certificate hostname does not match expected hostname!\n"); 
+               g_printerr ("TestLM: Certificate hostname does not match expected hostname!\n"); 
                break;
        case LM_SSL_STATUS_CERT_FINGERPRINT_MISMATCH: {
                const char *fpr = lm_ssl_get_fingerprint (ssl);
-               g_print ("Certificate fingerprint does not match expected fingerprint!\n"); 
-               g_print ("Remote fingerprint: ");
+               g_printerr ("TestLM: Certificate fingerprint does not match expected fingerprint!\n"); 
+               g_printerr ("TestLM: Remote fingerprint: ");
                print_finger (fpr, 16);
-               g_print ("\nExpected fingerprint: ");
+
+               g_printerr ("\n"
+                           "TestLM: Expected fingerprint: ");
                print_finger (expected_fingerprint, 16);
-               g_print ("\n");
+               g_printerr ("\n");
                break;
        }
        case LM_SSL_STATUS_GENERIC_ERROR:
-               g_print ("Generic SSL error!\n"); 
+               g_printerr ("TestLM: Generic SSL error!\n"); 
                break;
        }
 
@@ -96,31 +111,75 @@ ssl_cb (LmSSL *ssl, LmSSLStatus status, gpointer ud)
 }
 
 static void
-authentication_cb (LmConnection *connection, gboolean result, gpointer ud)
+connection_auth_cb (LmConnection *connection,
+                   gboolean      success, 
+                   gpointer      user_data)
 {
-       g_print ("Auth: %d\n", result);
-
-       if (result == TRUE) {
+       if (success) {
                LmMessage *m;
                
+               test_success = TRUE;
+               g_print ("TestLM: Authenticated successfully\n");
+
                m = lm_message_new_with_sub_type (NULL,
                                                  LM_MESSAGE_TYPE_PRESENCE,
                                                  LM_MESSAGE_SUB_TYPE_AVAILABLE);
-               g_print (":: %s\n", lm_message_node_to_string (m->node));
-               
                lm_connection_send (connection, m, NULL);
+               g_print ("TestLM: Sent presence message:'%s'\n", 
+                        lm_message_node_to_string (m->node));
+
                lm_message_unref (m);
+       } else {
+               g_printerr ("TestLM: Failed to authenticate\n");
+               g_main_loop_quit (main_loop);
+       }
+}
+
+static void
+connection_open_cb (LmConnection *connection, 
+                   gboolean      success,
+                   gpointer      user_data)
+{
+       if (success) {
+               lm_connection_authenticate (connection, username, 
+                                           password, resource,
+                                           connection_auth_cb, 
+                                           NULL, FALSE,  NULL);
+               
+               g_print ("TestLM: Sent authentication message\n");
+       } else {
+               g_printerr ("TestLM: Failed to connect\n");
+               g_main_loop_quit (main_loop);
        }
 }
 
 static void
-connection_open_cb (LmConnection *connection, gboolean result, UserInfo *info)
+connection_close_cb (LmConnection       *connection, 
+                    LmDisconnectReason  reason,
+                    gpointer            user_data)
 {
-       g_print ("Connected callback\n");
-       lm_connection_authenticate (connection,
-                                   info->name, info->passwd, "TestLM",
-                                   authentication_cb, NULL,FALSE,  NULL);
-       g_print ("Sent auth message\n");
+       const char *str;
+       
+       switch (reason) {
+       case LM_DISCONNECT_REASON_OK:
+               str = "LM_DISCONNECT_REASON_OK";
+               break;
+       case LM_DISCONNECT_REASON_PING_TIME_OUT:
+               str = "LM_DISCONNECT_REASON_PING_TIME_OUT";
+               break;
+       case LM_DISCONNECT_REASON_HUP:
+               str = "LM_DISCONNECT_REASON_HUP";
+               break;
+       case LM_DISCONNECT_REASON_ERROR:
+               str = "LM_DISCONNECT_REASON_ERROR";
+               break;
+       case LM_DISCONNECT_REASON_UNKNOWN:
+       default:
+               str = "LM_DISCONNECT_REASON_UNKNOWN";
+               break;
+       }
+
+       g_print ("TestLM: Disconnected, reason:%d->'%s'\n", reason, str);
 }
 
 static LmHandlerResult
@@ -129,7 +188,7 @@ handle_messages (LmMessageHandler *handler,
                 LmMessage        *m,
                 gpointer          user_data)
 {
-       g_print ("Incoming message from: %s\n",
+       g_print ("TestLM: Incoming message from: %s\n",
                 lm_message_node_get_attribute (m->node, "from"));
 
        return LM_HANDLER_RESULT_REMOVE_MESSAGE;
@@ -138,56 +197,29 @@ handle_messages (LmMessageHandler *handler,
 int 
 main (int argc, char **argv)
 {
-       GMainLoop        *main_loop;
+       GOptionContext   *context;
        LmConnection     *connection;
        LmMessageHandler *handler;
        gboolean          result;
-       UserInfo         *info;
-#ifdef __WIN32__
-       WORD wVersionRequested;
-       WSADATA wsaData;
-       int err;
-#endif
+       GError           *error = NULL;
        
-       if (argc < 4) {
-               g_print ("Usage: test-lm <server> <username> <password>\n"
-                        "       test-lm <server> <username> <password> <fingerprint>\n");
-               return 1;
-       }
-
-/* Needed to build on Win32. */
-#ifdef __WIN32__
-       wVersionRequested = MAKEWORD( 2, 2 );
-
-       err = WSAStartup( wVersionRequested, &wsaData );
-       if ( err != 0 ) {
-               /* Tell the user that we could not find a usable */
-               /* WinSock DLL.                                  */
-               return;
-       }
-
-       /* Confirm that the WinSock DLL supports 2.2.*/
-       /* Note that if the DLL supports versions greater    */
-       /* than 2.2 in addition to 2.2, it will still return */
-       /* 2.2 in wVersion since that is the version we      */
-       /* requested.                                        */
-
-       if ( LOBYTE( wsaData.wVersion ) != 2 ||
-                       HIBYTE( wsaData.wVersion ) != 2 ) {
-               /* Tell the user that we could not find a usable */
-               /* WinSock DLL.                                  */
-               WSACleanup( );
-               return;
+       context = g_option_context_new ("- test Loudmouth");
+       g_option_context_add_main_entries (context, entries, NULL);
+       g_option_context_parse (context, &argc, &argv, NULL);
+       g_option_context_free (context);
+       
+       if (!server || !username || !password) {
+               g_printerr ("For usage, try %s --help\n", argv[0]);
+               return EXIT_FAILURE;
        }
-#endif
 
-        connection = lm_connection_new (argv[1]);
-
-       if (argc > 4 && !lm_ssl_is_supported ()) {
-               g_error ("No SSL support!");
-               exit (1);
+       if (fingerprint && !lm_ssl_is_supported ()) {
+               g_printerr ("TestLM: SSL is not supported in this build\n");
+               return EXIT_FAILURE;
        }
 
+        connection = lm_connection_new (server);
+       lm_connection_set_port (connection, port);
 
        handler = lm_message_handler_new (handle_messages, NULL, NULL);
        lm_connection_register_message_handler (connection, handler, 
@@ -196,43 +228,45 @@ main (int argc, char **argv)
        
        lm_message_handler_unref (handler);
        
-       info = g_new0 (UserInfo, 1);
-       info->name = g_strdup (argv[2]);
-       info->passwd = g_strdup (argv[3]);
-       
-       if (argc > 4) {
-               int    i;
-               char  *p;
+       lm_connection_set_disconnect_function (connection,
+                                              connection_close_cb,
+                                              NULL, NULL);
+
+       if (fingerprint) {
                LmSSL *ssl;
+               char  *p;
+               int    i;
                
-               lm_connection_set_port (connection,
-                                       LM_CONNECTION_DEFAULT_PORT_SSL);
-               
-               for (i = 0, p = argv[4]; *p && *(p+1); i++, p += 3)
+               if (port == LM_CONNECTION_DEFAULT_PORT) {
+                       lm_connection_set_port (connection,
+                                               LM_CONNECTION_DEFAULT_PORT_SSL);
+               }
+
+               for (i = 0, p = fingerprint; *p && *(p+1); i++, p += 3) {
                        expected_fingerprint[i] = (unsigned char) g_ascii_strtoull (p, NULL, 16);
-               
+               }
+       
                ssl = lm_ssl_new (expected_fingerprint,
                                  (LmSSLFunction) ssl_cb,
-                                 info, 
-                                 (GDestroyNotify) free_user_info);
-               
+                                 NULL, NULL);
+       
                lm_connection_set_ssl (connection, ssl);
-
                lm_ssl_unref (ssl);
        }
 
        result = lm_connection_open (connection,
                                     (LmResultFunction) connection_open_cb,
-                                    info, NULL, NULL);
+                                    NULL, NULL, &error);
 
        if (!result) {
-               g_print ("Opening connection failed: %d\n", result);
-       } else {
-               g_print ("Returned from the connection_open\n");
+               g_printerr ("TestLM: Opening connection failed, error:%d->'%s'\n", 
+                        error->code, error->message);
+               g_free (error);
+               return EXIT_FAILURE;
        }
        
        main_loop = g_main_loop_new (NULL, FALSE);
        g_main_loop_run (main_loop);
 
-       return 0;
+       return (test_success ? EXIT_SUCCESS : EXIT_FAILURE);
 }
index 60f31317677a747acb5cd74a3237f7ec5f438cfb..ed4dde5490b4aae23193a415e9e9081291fd727e 100644 (file)
@@ -40,6 +40,8 @@ libloudmouth_1_la_SOURCES =           \
        $(ssl_sources)                  \
        lm-utils.c                      \
        lm-proxy.c                      \
+       lm-sock.h                       \
+       lm-sock.c                       \
        $(NULL)
 
 libloudmouthinclude_HEADERS =          \
index 71c7d49a9617d6b70d0d6765822c8dcdf661b36b..598aabd17754033707e8cfb47475e5c857b40f28 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
 /*
- * Copyright (C) 2003-2005 Imendio AB
+ * Copyright (C) 2003-2006 Imendio AB
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public License as
 #include <config.h>
 
 #include <string.h>
-#include <unistd.h>
+#include <sys/stat.h> 
 #include <sys/types.h>
 #include <fcntl.h>
 #include <errno.h>
-#ifndef __WIN32__
-  #include <netdb.h>
-  #include <sys/socket.h>
-  #include <netinet/in.h>
-  #include <sys/time.h>
-#else
-  #include <winsock2.h>
-#endif
 
+#include <glib.h>
+
+#include "lm-sock.h"
 #include "lm-debug.h"
 #include "lm-error.h"
 #include "lm-internals.h"
@@ -76,12 +71,15 @@ struct _LmConnection {
        guint         io_watch_in;
        guint         io_watch_err;
        guint         io_watch_hup;
-       guint         fd;
+       LmSocket      fd;
        guint         io_watch_connect;
        
        guint         open_id;
        LmCallback   *open_cb;
 
+       gboolean      async_connect_waiting;
+       gboolean      blocking;
+
        gboolean      cancel_open;
        LmCallback   *close_cb;
        LmCallback   *auth_cb;
@@ -309,12 +307,11 @@ connection_new_message_cb (LmParser     *parser,
        g_queue_push_tail (connection->incoming_messages, m);
 }
 
-gboolean
+void
 _lm_connection_succeeded (LmConnectData *connect_data)
 {
        LmConnection *connection;
        LmMessage    *m;
-       GIOFlags      flags;
        gchar        *server_from_jid;
        gchar        *ch;
 
@@ -328,72 +325,86 @@ _lm_connection_succeeded (LmConnectData *connect_data)
 
        /* Need some way to report error/success */
        if (connection->cancel_open) {
-               return FALSE;
+               lm_verbose ("Cancelling connection...\n");
+               return;
        }
        
        connection->fd = connect_data->fd;
        connection->io_channel = connect_data->io_channel;
 
        freeaddrinfo (connect_data->resolved_addrs);
+       g_free (connect_data);
 
-       /* don't need this anymore */
-       g_free(connect_data);
-
-       flags = g_io_channel_get_flags (connection->io_channel);
+       if (connection->ssl) {
+               GError *error = NULL;
 
-       /* unset the nonblock flag */
-       flags &= ~G_IO_FLAG_NONBLOCK;
+               lm_verbose ("Setting up SSL...\n");
        
-       /* unset the nonblocking stuff for some time, because GNUTLS doesn't 
-        * like that */
-       g_io_channel_set_flags (connection->io_channel, flags, NULL);
+#ifdef HAVE_GNUTLS
+               /* GNU TLS requires the socket to be blocking */
+               _lm_sock_set_blocking (connection->fd, TRUE);
+#endif
 
-       if (connection->ssl) {
                if (!_lm_ssl_begin (connection->ssl, connection->fd,
                                    connection->server,
-                                   NULL)) {
-                       shutdown (connection->fd, SHUT_RDWR);
-                       close (connection->fd);
-               
+                                   &error)) {
+                       lm_verbose ("Could not begin SSL\n");
+                                   
+                       if (error) {
+                               g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET,
+                                      "%s\n", error->message);
+                               g_error_free (error);
+                       }
+
+                       _lm_sock_shutdown (connection->fd);
+                       _lm_sock_close (connection->fd);
+
                        connection_do_close (connection);
-                       return FALSE;
+
+                       return;
                }
-       }
-       
-       g_io_channel_set_close_on_unref (connection->io_channel, TRUE);
-       g_io_channel_set_encoding (connection->io_channel, NULL, NULL);
-       
-       g_io_channel_set_buffered (connection->io_channel, FALSE);
-       g_io_channel_set_flags (connection->io_channel,
-                               flags & G_IO_FLAG_NONBLOCK, NULL);
        
+#ifdef HAVE_GNUTLS
+               _lm_sock_set_blocking (connection->fd, FALSE); 
+#endif
+       }
+
        connection->io_watch_in = 
                connection_add_watch (connection,
                                      connection->io_channel,
                                      G_IO_IN,
                                      (GIOFunc) connection_in_event,
                                      connection);
-       
-       connection->io_watch_err = 
-               connection_add_watch (connection,
-                                     connection->io_channel, 
-                                     G_IO_ERR,
-                                     (GIOFunc) connection_error_event,
-                                                  connection);
-       connection->io_watch_hup = 
-               connection_add_watch (connection,
-                                     connection->io_channel,
-                                     G_IO_HUP,
-                                     (GIOFunc) connection_hup_event,
-                                     connection);
+
+       /* FIXME: if we add these, we don't get ANY
+        * response from the server, this is to do with the way that
+        * windows handles watches, see bug #331214.
+        */
+#ifndef G_OS_WIN32
+               connection->io_watch_err =
+                       connection_add_watch (connection,
+                                             connection->io_channel,
+                                             G_IO_ERR,
+                                             (GIOFunc) connection_error_event,
+                                             connection);
+               
+               connection->io_watch_hup =
+                       connection_add_watch (connection,
+                                             connection->io_channel,
+                                             G_IO_HUP,
+                                             (GIOFunc) connection_hup_event,
+                                             connection);
+#endif
 
        /* FIXME: Set up according to XMPP 1.0 specification */
        /*        StartTLS and the like */
        if (!connection_send (connection, 
                              "<?xml version='1.0' encoding='UTF-8'?>", -1,
                              NULL)) {
+               lm_verbose ("Failed to send xml version and encoding\n");
                connection_do_close (connection);
-               return FALSE;
+
+               return;
        }
 
        if (connection->jid != NULL && (ch = strchr (connection->jid, '@')) != NULL) {
@@ -410,17 +421,13 @@ _lm_connection_succeeded (LmConnectData *connect_data)
                                        NULL);
        
        lm_verbose ("Opening stream...");
-       
+
        if (!lm_connection_send (connection, m, NULL)) {
-               lm_message_unref (m);
+               lm_verbose ("Failed to send stream information\n");
                connection_do_close (connection);
-               return FALSE;
        }
                
        lm_message_unref (m);
-
-       /* Success */
-       return FALSE;
 }
 
 void 
@@ -430,7 +437,7 @@ _lm_connection_failed_with_error (LmConnectData *connect_data, int error)
        
        g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET,
               "Connection failed: %s (error %d)\n",
-              strerror (error), error);
+              _lm_sock_get_error_str (error), error);
        
        connection = connect_data->connection;
        
@@ -444,6 +451,7 @@ _lm_connection_failed_with_error (LmConnectData *connect_data, int error)
 
        if (connect_data->io_channel != NULL) {
                g_io_channel_unref (connect_data->io_channel);
+               /* FIXME: need to check for last unref and close the socket */
        }
        
        if (connect_data->current_addr == NULL) {
@@ -466,43 +474,106 @@ _lm_connection_failed_with_error (LmConnectData *connect_data, int error)
 void 
 _lm_connection_failed (LmConnectData *connect_data)
 {
-       _lm_connection_failed_with_error (connect_data,errno);
+       _lm_connection_failed_with_error (connect_data, 
+                                         _lm_sock_get_last_error());
 }
        
 static gboolean 
 connection_connect_cb (GIOChannel   *source, 
                       GIOCondition  condition,
-                      gpointer      data) 
+                      LmConnectData *connect_data) 
 {
-       LmConnectData *connect_data;
-       int            error;
-       guint          len  = sizeof(error);
+       LmConnection    *connection;
+       struct addrinfo *addr;
+       int              err;
+       socklen_t        len;
+       LmSocket         fd; 
 
-       connect_data = (LmConnectData *) data;
+       connection = connect_data->connection;
+       addr = connect_data->current_addr;
+       fd = g_io_channel_unix_get_fd (source);
        
        if (condition == G_IO_ERR) {
-               /* get the real error from the socket */
-               getsockopt (connect_data->fd, SOL_SOCKET, SO_ERROR, 
-                           &error, &len);
-               _lm_connection_failed_with_error (connect_data, error);
-               return FALSE;
-       } else if (condition == G_IO_OUT) {
+               _lm_sock_get_error (fd, &err, &len);
+               if (!_lm_sock_is_blocking_error (err)) {
+                       g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET,
+                              "Connection failed.\n");
+
+                       _lm_connection_failed_with_error (connect_data, err);
+
+                       connection->io_watch_connect = 0;
+                       return FALSE;
+               }
+       }
+
+       if (connection->async_connect_waiting) {
+               gint res;
+
+               fd = g_io_channel_unix_get_fd (source);
+
+               res = _lm_sock_connect (fd, addr->ai_addr, (int)addr->ai_addrlen);  
+               if (res < 0) {
+                       err = _lm_sock_get_last_error ();
+                       if (_lm_sock_is_blocking_success (err)) {
+                               connection->async_connect_waiting = FALSE;
+
+                               g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET,
+                                      "Connection success.\n");
+                               
+                               _lm_connection_succeeded (connect_data);
+                       }
+                       
+                       if (connection->async_connect_waiting && 
+                           !_lm_sock_is_blocking_error (err)) {
+                               g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET,
+                                      "Connection failed.\n");
+
+                               _lm_sock_close (connect_data->fd);
+                               _lm_connection_failed_with_error (connect_data, err);
+
+                               connection->io_watch_connect = 0;
+                               return FALSE;
+                       }
+               } 
+       } else {                
+               /* for blocking sockets, G_IO_OUT means we are connected */
+               g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET,
+                      "Connection success.\n");
+               
                _lm_connection_succeeded (connect_data);
-       } else {
-               g_assert_not_reached ();
        }
 
-       return FALSE;
+       return TRUE; 
+}
+
+static const char *
+connection_condition_to_str (GIOCondition condition)
+{
+       static char buf[256];
+
+       buf[0] = '\0';
+
+       if(condition & G_IO_ERR)
+               strcat(buf, "G_IO_ERR ");
+       if(condition & G_IO_HUP)
+               strcat(buf, "G_IO_HUP ");
+       if(condition & G_IO_NVAL)
+               strcat(buf, "G_IO_NVAL ");
+       if(condition & G_IO_IN)
+               strcat(buf, "G_IO_IN ");
+       if(condition & G_IO_OUT)
+               strcat(buf, "G_IO_OUT ");
+
+       return buf;
 }
 
 static void
 connection_do_connect (LmConnectData *connect_data) 
 {
        LmConnection    *connection;
-       int              fd;
-       int              res;
+       LmSocket         fd;
+       int              res, err;
        int              port;
-       int              flags;
        char             name[NI_MAXHOST];
        char             portname[NI_MAXSERV];
        struct addrinfo *addr;
@@ -518,37 +589,47 @@ connection_do_connect (LmConnectData *connect_data)
        
        ((struct sockaddr_in *) addr->ai_addr)->sin_port = port;
 
-       getnameinfo (addr->ai_addr,
-                    addr->ai_addrlen,
-                    name,     sizeof (name),
-                    portname, sizeof (portname),
-                    NI_NUMERICHOST | NI_NUMERICSERV);
-
-       g_log (LM_LOG_DOMAIN,LM_LOG_LEVEL_NET,
-              "Trying %s port %s...\n", name, portname);
-       
-       fd = socket (addr->ai_family, 
-                    addr->ai_socktype, 
-                    addr->ai_protocol);
+       res = getnameinfo (addr->ai_addr,
+                          (socklen_t)addr->ai_addrlen,
+                          name,     sizeof (name),
+                          portname, sizeof (portname),
+                          NI_NUMERICHOST | NI_NUMERICSERV);
        
-       if (fd < 0) {
+       if (res < 0) {
                _lm_connection_failed (connect_data);
                return;
        }
 
-       flags = fcntl (fd, F_GETFL, 0);
-       fcntl (fd, F_SETFL, flags | O_NONBLOCK);
+       g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET,
+              "Trying %s port %s...\n", name, portname);
        
-       res = connect (fd, addr->ai_addr, addr->ai_addrlen);
-       connect_data->fd = fd;
+       fd = _lm_sock_makesocket (addr->ai_family,
+                                 addr->ai_socktype, 
+                                 addr->ai_protocol);
        
-       if (res < 0 && errno != EINPROGRESS) {
-               close (fd);
+       if (!_LM_SOCK_VALID (fd)) {
+               g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET, 
+                      "Failed making socket, error:%d...\n",
+                      _lm_sock_get_last_error ());
+
                _lm_connection_failed (connect_data);
+
                return;
        }
-       
+
+       /* Even though it says _unix_new(), it is supported by glib on
+        * win32 because glib does some cool stuff to find out if it
+        * can treat it as a FD or a windows SOCKET.
+        */
+       connect_data->fd = fd;
        connect_data->io_channel = g_io_channel_unix_new (fd);
+       
+       g_io_channel_set_encoding (connect_data->io_channel, NULL, NULL);
+       g_io_channel_set_buffered (connect_data->io_channel, FALSE);
+
+       _lm_sock_set_blocking (connect_data->fd, 
+                              connection->blocking);
+       
        if (connection->proxy) {
                connection->io_watch_connect =
                connection_add_watch (connection,
@@ -565,7 +646,19 @@ connection_do_connect (LmConnectData *connect_data)
                                      connect_data);
        }
 
-       return;
+       connection->async_connect_waiting = !connection->blocking;
+
+       res = _lm_sock_connect (connect_data->fd, 
+                               addr->ai_addr, (int)addr->ai_addrlen);  
+       if (res < 0) {
+               err = _lm_sock_get_last_error ();
+               if (!_lm_sock_is_blocking_error (err)) {
+                       _lm_sock_close (connect_data->fd);
+                       _lm_connection_failed_with_error (connect_data, err);
+
+                       return;
+               }
+       }
 }
 
 static guint
@@ -595,7 +688,7 @@ static gboolean
 connection_send_keep_alive (LmConnection *connection)
 { 
        if (!connection_send (connection, " ", -1, NULL)) {
-               lm_verbose ("Error while sending keep alive package");
+               lm_verbose ("Error while sending keep alive package!\n");
        }
 
        return TRUE;
@@ -653,9 +746,13 @@ connection_buffered_write_cb (GIOChannel   *source,
        g_string_erase (out_buf, 0, (gsize) b_written);
        if (out_buf->len == 0) {
                lm_verbose ("Output buffer is empty, going back to normal output\n");
-               g_source_destroy (g_main_context_find_source_by_id (
-                       connection->context, connection->io_watch_out));
-               connection->io_watch_out = 0;
+
+               if (connection->io_watch_out != 0) {
+                       g_source_destroy (g_main_context_find_source_by_id (
+                                                 connection->context, connection->io_watch_out));
+                       connection->io_watch_out = 0;
+               }
+
                g_string_free (out_buf, TRUE);
                connection->out_buf = NULL;
                return FALSE;
@@ -707,7 +804,7 @@ connection_do_open (LmConnection *connection, GError **error)
        if (lm_connection_is_open (connection)) {
                g_set_error (error,
                             LM_ERROR,
-                            LM_ERROR_CONNECTION_OPEN,
+                            LM_ERROR_CONNECTION_NOT_OPEN,
                             "Connection is already open, call lm_connection_close() first");
                return FALSE;
        }
@@ -735,33 +832,47 @@ connection_do_open (LmConnection *connection, GError **error)
        
        connection->cancel_open = FALSE;
        connection->state = LM_CONNECTION_STATE_OPENING;
+       connection->async_connect_waiting = FALSE;
        
        if (connection->proxy) {
+               int          err;
                const gchar *proxy_server;
 
                proxy_server = lm_proxy_get_server (connection->proxy);
-               /* connect through proxy */
-               g_log (LM_LOG_DOMAIN,LM_LOG_LEVEL_NET,
-                      "Going to connect to %s\n", proxy_server);
 
-               if (getaddrinfo (proxy_server, NULL, &req, &ans) != 0) {
+               /* Connect through proxy */
+               g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET,
+                      "Going to connect to proxy %s\n", proxy_server);
+
+               err = getaddrinfo (proxy_server, NULL, &req, &ans);
+               if (err != 0) {
+                       const char *str;
+
+                       str = _lm_sock_addrinfo_get_error_str (err);
                        g_set_error (error,
                                     LM_ERROR,                 
                                     LM_ERROR_CONNECTION_FAILED,   
-                                    "getaddrinfo() failed");
+                                    str);
                        return FALSE;
                }
-       } else { /* connect directly */
-               g_log (LM_LOG_DOMAIN,LM_LOG_LEVEL_NET,
+       } else { 
+               int err;
+
+               /* Connect directly */
+               g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET,
                       "Going to connect to %s\n", 
                       connection->server);
 
-               if (getaddrinfo (connection->server,
-                                NULL, &req, &ans) != 0) {
+               err = getaddrinfo (connection->server, 
+                                  NULL, &req, &ans);
+               if (err != 0) {
+                       const char *str;
+
+                       str = _lm_sock_addrinfo_get_error_str (err);
                        g_set_error (error,
                                     LM_ERROR,                 
                                     LM_ERROR_CONNECTION_FAILED,   
-                                    "getaddrinfo() failed");
+                                    str);
                        return FALSE;
                }
        }
@@ -789,12 +900,23 @@ connection_do_close (LmConnection *connection)
        connection_stop_keep_alive (connection);
 
        if (connection->io_channel) {
-               g_source_destroy (g_main_context_find_source_by_id (
-                       connection->context, connection->io_watch_in));
-               g_source_destroy (g_main_context_find_source_by_id (
-                       connection->context, connection->io_watch_err));
-               g_source_destroy (g_main_context_find_source_by_id (
-                       connection->context, connection->io_watch_hup));
+               if (connection->io_watch_in != 0) {
+                       g_source_destroy (g_main_context_find_source_by_id (
+                                                 connection->context, connection->io_watch_in));
+                       connection->io_watch_in = 0;
+               }
+
+               if (connection->io_watch_err != 0) {
+                       g_source_destroy (g_main_context_find_source_by_id (
+                                                 connection->context, connection->io_watch_err));
+                       connection->io_watch_err = 0;
+               }
+
+               if (connection->io_watch_hup != 0) {
+                       g_source_destroy (g_main_context_find_source_by_id (
+                                                 connection->context, connection->io_watch_hup));
+                       connection->io_watch_hup = 0;
+               }
 
                if (connection->io_watch_out != 0) {
                        g_source_destroy (g_main_context_find_source_by_id (
@@ -820,10 +942,12 @@ connection_do_close (LmConnection *connection)
        if (!lm_connection_is_open (connection)) {
                /* lm_connection_is_open is FALSE for state OPENING as well */
                connection->state = LM_CONNECTION_STATE_CLOSED;
+               connection->async_connect_waiting = FALSE;
                return;
        }
        
        connection->state = LM_CONNECTION_STATE_CLOSED;
+       connection->async_connect_waiting = FALSE;
        if (connection->ssl) {
                _lm_ssl_close (connection->ssl);
        }
@@ -911,7 +1035,7 @@ connection_in_event (GIOChannel   *source,
        g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET, 
               "-----------------------------------\n");
        g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET, "'%s'\n", buf);
-       g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET, 
+       g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET, 
               "-----------------------------------\n");
 
        lm_verbose ("Read: %d chars\n", (int)bytes_read);
@@ -926,12 +1050,13 @@ connection_error_event (GIOChannel   *source,
                        GIOCondition  condition,
                        LmConnection *connection)
 {
+       lm_verbose ("Error event: %d->'%s'\n", 
+                   condition, connection_condition_to_str (condition));
+
        if (!connection->io_channel) {
                return FALSE;
        }
 
-       lm_verbose ("Error event: %d\n", condition);
-       
        connection_do_close (connection);
        connection_signal_disconnect (connection, LM_DISCONNECT_REASON_ERROR);
        
@@ -943,12 +1068,13 @@ connection_hup_event (GIOChannel   *source,
                      GIOCondition  condition,
                      LmConnection *connection)
 {
+       lm_verbose ("HUP event: %d->'%s'\n", 
+                   condition, connection_condition_to_str (condition));
+
        if (!connection->io_channel) {
                return FALSE;
        }
 
-       lm_verbose ("HUP event\n");
-
        connection_do_close (connection);
        connection_signal_disconnect (connection, LM_DISCONNECT_REASON_HUP);
        
@@ -964,6 +1090,9 @@ connection_send (LmConnection  *connection,
        gint b_written;
        
        if (connection->state < LM_CONNECTION_STATE_OPENING) {
+               g_log (LM_LOG_DOMAIN,LM_LOG_LEVEL_NET,
+                      "Connection is not open.\n");
+
                g_set_error (error,
                             LM_ERROR,
                             LM_ERROR_CONNECTION_NOT_OPEN,
@@ -1297,7 +1426,8 @@ lm_connection_new (const gchar *server)
        gint          i;
        
        lm_debug_init ();
-       
+       _lm_sock_library_init ();
+
        connection = g_new0 (LmConnection, 1);
 
        if (server) {
@@ -1383,6 +1513,7 @@ lm_connection_open (LmConnection      *connection,
        
        connection->open_cb = _lm_utils_new_callback (function, 
                                                      user_data, notify);
+       connection->blocking = FALSE;
 
        return connection_do_open (connection, error);
 }
@@ -1405,17 +1536,20 @@ lm_connection_open_and_block (LmConnection *connection, GError **error)
        g_return_val_if_fail (connection != NULL, FALSE);
 
        connection->open_cb = NULL;
+       connection->blocking = TRUE;
+
        result = connection_do_open (connection, error);
 
        if (result == FALSE) {
                return FALSE;
        }
-       
+               
        while ((state = lm_connection_get_state (connection)) == LM_CONNECTION_STATE_OPENING) {
                if (g_main_context_pending (connection->context)) {
                        g_main_context_iteration (connection->context, TRUE);
                } else {
-                       usleep (10);
+                       /* Sleep for 1 millisecond */
+                       g_usleep (1000);
                }
        }
 
@@ -2008,7 +2142,7 @@ lm_connection_send_with_reply_and_block (LmConnection  *connection,
 
        while (!reply) {
                const gchar *m_id;
-               gint         n;
+               guint        n;
 
                g_main_context_iteration (connection->context, TRUE);
        
index 5b75e26089735d77d2e3a25a26855c3a5d4d5000..900d35ac6e52bfb7906b444f5faf4027337aa4df 100644 (file)
 #ifndef __LM_INTERNALS_H__
 #define __LM_INTERNALS_H__
 
+#include <glib.h>
+
+#include <sys/types.h>
+
 #include "lm-message.h"
 #include "lm-message-handler.h"
 #include "lm-message-node.h"
+#include "lm-sock.h"
+
+#ifndef G_OS_WIN32
+typedef int LmSocket;
+#else  /* G_OS_WIN32 */
+typedef SOCKET LmSocket;
+#endif /* G_OS_WIN32 */
 
 typedef struct {
        gpointer       func;
@@ -39,14 +50,14 @@ typedef struct {
        /* struct to save resolved address */
        struct addrinfo *resolved_addrs;
        struct addrinfo *current_addr;
-       int              fd;
-       GIOChannel           *io_channel;
+       LmSocket         fd;
+       GIOChannel      *io_channel;
 } LmConnectData;
 
 void             _lm_connection_failed_with_error (LmConnectData *connect_data,
                                                    int error);
 void             _lm_connection_failed            (LmConnectData *connect_data);
-gboolean         _lm_connection_succeeded (LmConnectData *connect_data);
+void             _lm_connection_succeeded         (LmConnectData *connect_data);
 LmCallback *     _lm_utils_new_callback             (gpointer          func, 
                                                     gpointer          data,
                                                     GDestroyNotify    notify);
@@ -70,6 +81,25 @@ LmHandlerResult
 _lm_message_handler_handle_message                (LmMessageHandler *handler,
                                                   LmConnection     *connection,
                                                   LmMessage        *messag);
-
+gboolean         _lm_sock_library_init            (void);
+void             _lm_sock_library_shutdown        (void);
+void             _lm_sock_set_blocking            (LmSocket               sock,
+                                                  gboolean               block);
+void             _lm_sock_shutdown                (LmSocket               sock);
+void             _lm_sock_close                   (LmSocket               sock);
+LmSocket         _lm_sock_makesocket              (int                    af,
+                                                  int                    type,
+                                                  int                    protocol);
+int              _lm_sock_connect                 (LmSocket               sock,
+                                                  const struct sockaddr *name,
+                                                  int                    namelen);
+gboolean         _lm_sock_is_blocking_error       (int                    err);
+gboolean         _lm_sock_is_blocking_success     (int                    err);
+int              _lm_sock_get_last_error          (void);
+void             _lm_sock_get_error               (LmSocket               sock, 
+                                                  void                  *error, 
+                                                  socklen_t             *len);
+const gchar *    _lm_sock_get_error_str           (int                    err);
+const gchar *    _lm_sock_addrinfo_get_error_str  (int                    err);
 
 #endif /* __LM_INTERNALS_H__ */
index d5c82132c21d7a375d219d09c7a95700fee2e79c..4ba47c2f8a1a9bbf16c2c68d7fb788d771a5a96e 100644 (file)
@@ -252,7 +252,7 @@ lm_parser_parse (LmParser *parser, const gchar *string)
         }
         
         if (g_markup_parse_context_parse (parser->context, string, 
-                                          strlen (string), NULL)) {
+                                          (gssize)strlen (string), NULL)) {
         } else {
                 g_warning ("Parsing failed\n");
         }
index d646ec407d513b3b62d03204ddc250eae558b182..5a909e070d0c60305118a8af7b02ce2bc2882136 100644 (file)
 
 #include <glib.h>
 #include <string.h>
+
+#ifndef G_OS_WIN32
+
 #include <unistd.h>
-#ifndef __WIN32__
-  #include <sys/socket.h>
-#else 
-  #include <winsock2.h>
-#endif
+#include <sys/socket.h>
+
+#else  /* G_OS_WIN32 */
+
+#include <winsock2.h>
+
+#endif /* G_OS_WIN32 */
 
 #include "lm-internals.h"
 #include "lm-proxy.h"
@@ -187,7 +192,7 @@ _lm_proxy_connect_cb (GIOChannel *source, GIOCondition condition, gpointer data)
        LmConnectData *connect_data;
        LmProxy       *proxy;
        int            error;
-       guint          len = sizeof(error);
+       socklen_t      len;
 
        connect_data = (LmConnectData *) data;
        connection = connect_data->connection;
@@ -196,8 +201,7 @@ _lm_proxy_connect_cb (GIOChannel *source, GIOCondition condition, gpointer data)
        g_return_val_if_fail (proxy != NULL, FALSE);
 
        if (condition == G_IO_ERR) {
-               getsockopt (connect_data->fd, SOL_SOCKET, SO_ERROR,
-                           &error, &len);
+               _lm_sock_get_error (connect_data->fd, &error, &len);
                _lm_connection_failed_with_error (connect_data, error);
                return FALSE;
        } else if (condition == G_IO_OUT) {
index 06f3aaf4d5900c9e02889b74f58c0376abb4c2b5..aa20648ab223de6b9217ffca8d255dba67e9cced 100644 (file)
@@ -189,7 +189,7 @@ SHA1Init (SHA1Context *sc)
   setEndian ();
 #endif /* RUNTIME_ENDIAN */
 
-#ifdef __WIN32__
+#ifdef G_OS_WIN32
   sc->totalLength = 0L;
 #else
   sc->totalLength = 0LL;
@@ -597,7 +597,7 @@ SHA1Final (SHA1Context *sc, guint8 hash[SHA1_HASH_SIZE])
   }
 }
 
-#ifdef __WIN32__
+#ifdef G_OS_WIN32
 #define snprintf _snprintf
 #endif
 
diff --git a/loudmouth/lm-sock.c b/loudmouth/lm-sock.c
new file mode 100644 (file)
index 0000000..f9f52b4
--- /dev/null
@@ -0,0 +1,291 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2006 Imendio AB
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+#include <glib.h>
+#include <glib/gi18n.h>
+
+#ifndef G_OS_WIN32
+
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <fcntl.h>
+#define LM_SHUTDOWN SHUT_RDWR
+
+#else  /* G_OS_WIN32 */
+
+#include <winsock2.h>
+#define LM_SHUTDOWN SD_BOTH
+
+#endif /* G_OS_WIN32 */
+
+#include "lm-internals.h"
+#include "lm-connection.h"
+#include "lm-sock.h"
+#include "lm-debug.h"
+
+static gboolean initialised = FALSE;
+
+gboolean
+_lm_sock_library_init (void)
+{
+#ifdef G_OS_WIN32
+       WORD    version;
+       WSADATA data;
+       int     error;
+#endif /* G_OS_WIN32 */
+       
+       if (initialised) {
+               return TRUE;
+       }
+
+       lm_verbose ("Socket library initialising...\n");
+       
+#ifdef G_OS_WIN32
+       lm_verbose ("Checking for winsock 2.0 or above...\n");
+       
+       version = MAKEWORD (2, 0);
+               
+       error = WSAStartup (version, &data);
+       if (error != 0) {
+               g_printerr ("WSAStartup() failed, error:%d\n", error);
+               return FALSE;
+       }
+       
+       /* Confirm that the WinSock DLL supports 2.0.
+        * Note that if the DLL supports versions greater  
+        * than 2.0 in addition to 2.0, it will still return 
+        * 2.0 in wVersion since that is the version we      
+        * requested.                                        
+        */
+       if (LOBYTE (data.wVersion) != 2 ||
+           HIBYTE (data.wVersion) != 0) {
+               /* Tell the user that we could not find a usable
+                * WinSock DLL.                                  
+                */
+               g_printerr ("Socket library version is not sufficient!\n");
+               WSACleanup ();
+               return FALSE;
+       }
+#endif /* G_OS_WIN32 */
+
+       initialised = TRUE;
+       
+       return TRUE;
+}
+
+void
+_lm_sock_library_shutdown (void)
+{
+       if (!initialised) {
+               return;
+       }
+
+       lm_verbose ("Socket library shutting down...\n");
+
+#ifdef G_OS_WIN32
+       WSACleanup ();
+#endif /* G_OS_WIN32 */
+
+       initialised = FALSE;
+}
+
+void
+_lm_sock_set_blocking (LmSocket sock, 
+                      gboolean block)
+{
+       int res;
+
+#ifndef G_OS_WIN32
+       res = fcntl (sock, F_SETFL, block ? 0 : O_NONBLOCK);
+#else  /* G_OS_WIN32 */
+       u_long mode = (block ? 0 : 1);
+       res = ioctlsocket (sock, FIONBIO, &mode);
+#endif /* G_OS_WIN32 */
+
+       if (res != 0) {
+               g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET,
+                      "Could not set connection to be %s\n",
+                      block ? "blocking" : "non-blocking");
+       }
+}
+
+void
+_lm_sock_shutdown (LmSocket sock)
+{
+       shutdown (sock, LM_SHUTDOWN);
+}
+
+void
+_lm_sock_close (LmSocket sock)
+{
+#ifndef G_OS_WIN32
+       close (sock);
+#else  /* G_OS_WIN32 */
+       closesocket (sock);
+#endif /* G_OS_WIN32 */
+}
+
+LmSocket 
+_lm_sock_makesocket (int af,
+                    int type, 
+                    int protocol)
+{
+       return (LmSocket)socket (af, type, protocol);
+}
+
+int 
+_lm_sock_connect (LmSocket               sock, 
+                 const struct sockaddr *name, 
+                 int                    namelen)
+{
+       return connect (sock, name, namelen);
+}
+
+gboolean
+_lm_sock_is_blocking_error (int err)
+{
+#ifndef G_OS_WIN32
+       return (err == _LM_SOCK_EINPROGRESS);
+#else  /* G_OS_WIN32 */
+       return (err == _LM_SOCK_EINPROGRESS || 
+               err == _LM_SOCK_EWOULDBLOCK || 
+               err == _LM_SOCK_EINVAL);
+#endif /* G_OS_WIN32 */
+}
+
+gboolean
+_lm_sock_is_blocking_success (int err)
+{
+       return (err == _LM_SOCK_EALREADY || err == _LM_SOCK_EISCONN);
+}
+
+int 
+_lm_sock_get_last_error (void)
+{
+#ifndef G_OS_WIN32
+       return errno;
+#else  /* G_OS_WIN32 */
+       return WSAGetLastError ();
+#endif /* G_OS_WIN32 */
+}
+
+void 
+_lm_sock_get_error (LmSocket   sock, 
+                   void      *error, 
+                   socklen_t *len)
+{
+       getsockopt (sock, SOL_SOCKET, SO_ERROR, (void*) error, len);
+}
+
+const gchar *
+_lm_sock_get_error_str (int err)
+{
+#ifndef G_OS_WIN32
+       return strerror (err);
+#else  /* G_OS_WIN32 */
+       switch (err) {
+       case WSAEINTR:              return _("Connect interrupted and canceled");
+       case WSAEACCES:             return _("Permission denied"); 
+       case WSAEFAULT:             return _("Bad address");
+       case WSAEINVAL:             return _("Invalid argument");
+       case WSAEMFILE:             return _("Too many open sockets");
+       case WSAEWOULDBLOCK:        return _("Resource temporarily unavailable");
+       case WSAEINPROGRESS:        return _("Operation now in progress");
+       case WSAEALREADY:           return _("Operation already in progress");
+       case WSAENOTSOCK:           return _("Socket operation on nonsocket");
+       case WSAEDESTADDRREQ:       return _("Destination address required");
+       case WSAEMSGSIZE:           return _("Message too long");
+       case WSAEPROTOTYPE:         return _("Protocol wrong type for socket");
+       case WSAENOPROTOOPT:        return _("Bad protocol option");
+       case WSAEPROTONOSUPPORT:    return _("Protocol not supported");
+       case WSAESOCKTNOSUPPORT:    return _("Socket type not supported");
+       case WSAEOPNOTSUPP:         return _("Operation not supported");
+       case WSAEPFNOSUPPORT:       return _("Protocol family not supported");
+       case WSAEAFNOSUPPORT:       return _("Address family not supported by protocol family");
+       case WSAEADDRINUSE:         return _("Address already in use");
+       case WSAEADDRNOTAVAIL:      return _("Can not assign requested address");
+       case WSAENETDOWN:           return _("Network is down");
+       case WSAENETUNREACH:        return _("Network is unreachable");
+       case WSAENETRESET:          return _("Network dropped connection on reset");
+       case WSAECONNABORTED:       return _("Software caused connection abort");
+       case WSAECONNRESET:         return _("Connection reset by peer");
+       case WSAENOBUFS:            return _("No buffer space available");
+       case WSAEISCONN:            return _("Socket is already connected");
+       case WSAENOTCONN:           return _("Socket is not connected");
+       case WSAESHUTDOWN:          return _("Can not send after socket shutdown");
+       case WSAETIMEDOUT:          return _("Connection timed out");
+       case WSAECONNREFUSED:       return _("Connection refused");
+       case WSAEHOSTDOWN:          return _("Host is down");
+       case WSAEHOSTUNREACH:       return _("No route to host");
+       case WSAEPROCLIM:           return _("Too many processes");
+       case WSASYSNOTREADY:        return _("Network subsystem is unavailable");
+       case WSAVERNOTSUPPORTED:    return _("Winsock library version is out of range ");
+       case WSANOTINITIALISED:     return _("Successful WSAStartup not yet performed");
+       case WSAEDISCON:            return _("Graceful shutdown in progress");
+       case WSATYPE_NOT_FOUND:     return _("Class type not found");
+       case WSAHOST_NOT_FOUND:     return _("Host not found");
+       case WSATRY_AGAIN:          return _("Nonauthoritative host not found");
+       case WSANO_RECOVERY:        return _("This is a nonrecoverable error");
+       case WSANO_DATA:            return _("Valid name, no data record of requested type");
+       case WSA_INVALID_HANDLE:    return _("Specified event object handle is invalid");
+       case WSA_INVALID_PARAMETER: return _("One or more parameters are invalid");
+       case WSA_IO_INCOMPLETE:     return _("Overlapped I/O event object no in signaled state");
+       case WSA_IO_PENDING:        return _("Overlapped operations will complete later");
+       case WSA_NOT_ENOUGH_MEMORY: return _("Insufficient memory available");
+       case WSA_OPERATION_ABORTED: return _("Overlapped operation aborted");
+               /* os dependent */
+       case WSASYSCALLFAILURE:     return _("System call failure");
+       }
+       
+       return _("Unknown");
+#endif /* G_OS_WIN32 */
+}
+
+const gchar *
+_lm_sock_addrinfo_get_error_str (int err)
+{
+       switch (err) {
+       case EAI_AGAIN:    
+               return _("The nameserver failed to return an "
+                        "address, try again later");
+       case EAI_BADFLAGS: 
+               return _("Internal error trying to obtain remote address");
+       case EAI_FAIL:     
+               return _("The nameserver encountered errors "
+                        "looking up this address");
+       case EAI_NODATA:   
+               return _("The remote host exists but no address "
+                        "is available");
+       case EAI_NONAME:   
+               return _("The remote address is unknown");
+       case EAI_FAMILY:
+       case EAI_SERVICE:
+       case EAI_SOCKTYPE:
+               return _("The remote address is not obtainable "
+                        "for that socket type.");
+       default:
+               break;
+       }
+
+       return _("The remote address could not be obtained ");
+}
diff --git a/loudmouth/lm-sock.h b/loudmouth/lm-sock.h
new file mode 100644 (file)
index 0000000..77fb078
--- /dev/null
@@ -0,0 +1,80 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2006 Imendio AB 
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __LM_SOCK_H__
+#define __LM_SOCK_H__
+
+G_BEGIN_DECLS
+
+#if !defined (LM_INSIDE_LOUDMOUTH_H) && !defined (LM_COMPILATION)
+#error "Only <loudmouth/loudmouth.h> can be included directly, this file may di\sappear or change contents."
+#endif
+
+#include <glib.h>
+
+#ifndef G_OS_WIN32
+
+#include <unistd.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+
+#define _LM_SOCK_EINPROGRESS EINPROGRESS
+#define _LM_SOCK_EWOULDBLOCK EWOULDBLOOK
+#define _LM_SOCK_EALREADY    EALREADY
+#define _LM_SOCK_EISCONN     EISCONN
+#define _LM_SOCK_EINVAL      EINVAL
+#define _LM_SOCK_VALID(S)    ((S) >= 0)
+
+#else  /* G_OS_WIN32 */
+
+/* This means that we require Windows XP or above to build on
+ * Windows, the reason for this, is that getaddrinfo() and
+ * freeaddrinfo() require ws2tcpip.h functions that are only available
+ * on these platforms. 
+ *
+ * This MUST be defined before windows.h is included.
+ */
+
+
+#if (_WIN32_WINNT < 0x0501)
+#undef  WINVER
+#define WINVER 0x0501
+#undef  _WIN32_WINNT
+#define _WIN32_WINNT WINVER
+#endif
+
+#include <winsock2.h>
+#include <ws2tcpip.h>
+
+#define _LM_SOCK_EINPROGRESS WSAEINPROGRESS
+#define _LM_SOCK_EWOULDBLOCK WSAEWOULDBLOCK
+#define _LM_SOCK_EALREADY    WSAEALREADY
+#define _LM_SOCK_EISCONN     WSAEISCONN
+#define _LM_SOCK_EINVAL      WSAEINVAL
+#define _LM_SOCK_VALID(S)    ((S) != INVALID_SOCKET)
+
+#endif /* G_OS_WIN32 */
+
+G_END_DECLS
+
+#endif /* __LM_SOCK__ */
index d58c995d9c0d6b2ad1b85e57854572328d985a60..36b38d627e664d3e912aca0e5ca1f774d56e1fd3 100644 (file)
@@ -116,7 +116,6 @@ _lm_ssl_initialize (LmSSL *ssl)
 
        meth = SSLv23_method ();
        ssl->ctx = SSL_CTX_new (meth);
-
 }
 
 gboolean
index aa862795638ee4d385831f0d0d0c4b358d289b9f..8f1dd99353292ed8316871fdacb9377e5c2b68f0 100644 (file)
 #include <stdio.h>
 #include <time.h>
 
+#include <glib.h>
+
+#ifndef G_OS_WIN32
+#include <unistd.h>
+#endif
+
 #include "lm-internals.h"
 #include "lm-utils.h"