diff --git a/.gitignore b/.gitignore index 70d9cf39..36439b77 100644 --- a/.gitignore +++ b/.gitignore @@ -7,20 +7,31 @@ compile aclocal.m4 config.log config.status +config.guess +config.sub depcomp autom4te.cache +libtool +ltmain.sh .dirstamp .deps .sconsign* +src/*.lo src/*.o examples/*.o tests/*.o tests/check_parser +*.la *.a *.tar.gz *.zip +*.pc +*~ +*.swp docs/html TAGS +tags +cscope.out examples/basic examples/active examples/roster @@ -33,3 +44,6 @@ tests/test_hash tests/test_jid tests/test_sasl tests/test_sock +.libs/ +examples/.libs/ +src/.libs/ diff --git a/Makefile.am b/Makefile.am index 788d37c9..969bc539 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,58 +1,38 @@ AUTOMAKE_OPTIONS = subdir-objects -CFLAGS = -g -Wall +COUPLET_LIBS = libcouplet.la -PARSER_CFLAGS=@PARSER_CFLAGS@ -PARSER_LIBS=@PARSER_LIBS@ - -SSL_LIBS = -lssl -lcrypto -lz - -STROPHE_FLAGS = -I$(top_srcdir) -STROPHE_LIBS = libstrophe.a $(PARSER_LIBS) $(SSL_LIBS) +pkgconfigdir = $(libdir)/pkgconfig ## Main build targets -lib_LIBRARIES = libstrophe.a +lib_LTLIBRARIES = libcouplet.la -libstrophe_a_CFLAGS=$(STROPHE_FLAGS) $(PARSER_CFLAGS) -libstrophe_a_SOURCES = src/auth.c src/conn.c src/ctx.c \ +libcouplet_la_SOURCES = src/auth.c src/conn.c src/ctx.c \ src/event.c src/handler.c src/hash.c \ src/jid.c src/md5.c src/sasl.c src/sha1.c \ src/snprintf.c src/sock.c src/stanza.c src/thread.c \ - src/tls_openssl.c src/util.c \ + src/tls_openssl.c src/util.c src/list.c \ src/common.h src/hash.h src/md5.h src/ostypes.h src/parser.h \ - src/sasl.h src/sha1.h src/sock.h src/thread.h src/tls.h src/util.h + src/sasl.h src/sha1.h src/sock.h src/thread.h src/tls.h src/util.h \ + src/list.h if PARSER_EXPAT -libstrophe_a_SOURCES += src/parser_expat.c +libcouplet_la_SOURCES += src/parser_expat.c else -libstrophe_a_SOURCES += src/parser_libxml2.c +libcouplet_la_SOURCES += src/parser_libxml2.c endif -include_HEADERS = strophe.h -noinst_HEADERS = strophepp.h +include_HEADERS = couplet.h +noinst_HEADERS = coupletpp.h EXTRA_DIST = docs -## Examples -noinst_PROGRAMS = examples/active examples/roster examples/basic examples/bot -examples_active_SOURCES = examples/active.c -examples_active_CFLAGS = $(STROPHE_FLAGS) -examples_active_LDADD = $(STROPHE_LIBS) -examples_roster_SOURCES = examples/roster.c -examples_roster_CFLAGS = $(STROPHE_FLAGS) -examples_roster_LDADD = $(STROPHE_LIBS) -examples_basic_SOURCES = examples/basic.c -examples_basic_CFLAGS = $(STROPHE_FLAGS) -examples_basic_LDADD = $(STROPHE_LIBS) -examples_bot_SOURCES = examples/bot.c -examples_bot_CFLAGS = $(STROPHE_FLAGS) -examples_bot_LDADD = $(STROPHE_LIBS) - +pkgconfig_DATA = libcouplet.pc ## Tests TESTS = tests/check_parser check_PROGRAMS = tests/check_parser tests_check_parser_SOURCES = tests/check_parser.c tests/test.h -tests_check_parser_CFLAGS = @check_CFLAGS@ $(PARSER_CFLAGS) $(STROPHE_FLAGS) \ +tests_check_parser_CFLAGS = @check_CFLAGS@ $(AM_CFLAGS) \ -I$(top_srcdir)/src -tests_check_parser_LDADD = @check_LIBS@ $(STROPHE_LIBS) +tests_check_parser_LDADD = @check_LIBS@ $(COUPLET_LIBS) diff --git a/README.markdown b/README.markdown index 4c0b3f83..9a68b77e 100644 --- a/README.markdown +++ b/README.markdown @@ -1,14 +1,8 @@ -# libstrophe +# libcouplet -libstrophe is a lightweight XMPP client library written in C. It has -minimal dependencies and is configurable for various environments. It -runs well on both Linux, Unix, and Windows based platforms. - -Its goals are: - -- usable quickly -- well documented -- reliable +libcouplet is a fork of libstrophe - a lightweight XMPP client library +written in C. Goal of the fork is make library suitable for multi-thread +applications. ## Build Instructions @@ -23,27 +17,33 @@ From the top-level directory, run the following commands: ./configure make -This will create a static library, also in the top-level -directory, which can be linked into other programs. The -public API is defined in `strophe.h` which is also in the -top-level directory. - The `examples` directory contains some examples of how to use the library; these may be helpful in addition to the API documentation ## Requirements -libstrophe requires: +libcouplet requires: - expat or libxml2 - expat is the default; use --with-libxml2 to switch +- openssl - libresolv on UNIX systems - make sure you include -lresolv - if you are compiling by hand. + if you are compiling by hand. In addition, if you wish to run the unit tests, you will need the check package. +Windows systems aren't supported for now. + +### Gentoo + +libcouplet can be installed from Gentoo overlay 'stuff': + + layman -a stuff + echo =dev-libs/libcouplet-9999 ** >> /etc/portage/package.keywords + emerge libcouplet + ### OS X (with Homebrew package manager) You can install the requirements with: diff --git a/bootstrap.sh b/bootstrap.sh index 473f746b..3b72d881 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -5,6 +5,7 @@ if [ -d /usr/local/share/aclocal ]; then ACFLAGS="-I /usr/local/share/aclocal" fi +libtoolize aclocal ${ACFLAGS} automake --add-missing --foreign --copy autoconf diff --git a/configure.ac b/configure.ac index 97444e53..8fbde770 100644 --- a/configure.ac +++ b/configure.ac @@ -1,48 +1,50 @@ -AC_INIT([libstrophe], [0.8-snapshot], [jack@metajack.im]) +AC_INIT([libcouplet], [0.8], [pasis.ua@gmail.com]) AM_INIT_AUTOMAKE +AC_CONFIG_FILES([Makefile libcouplet.pc]) AC_PROG_CC -AC_PROG_RANLIB AM_PROG_CC_C_O - -AC_CHECK_HEADER(openssl/ssl.h, [], [AC_MSG_ERROR([couldn't find openssl headers, openssl required])]) -PKG_CHECK_MODULES([check], [check >= 0.9.4], [], [AC_MSG_WARN([libcheck not found; unit tests will not be compilable])]) +LT_INIT AC_ARG_WITH([libxml2], - [AS_HELP_STRING([--with-libxml2], [use libxml2 for XML parsing])], - [with_libxml2=check], - [with_libxml2=no]) - -if test "x$with_libxml2" != xno; then - PKG_CHECK_MODULES([libxml2], [libxml-2.0 >= 2.7], - [with_libxml2=yes], - [AC_MSG_ERROR([couldn't find libxml2])]) -else - AC_CHECK_HEADER(expat.h, [], [AC_MSG_ERROR([couldn't find expat headers; expat required])]) + [AS_HELP_STRING([--with-libxml2], [use libxml2 for XML parsing])]) + +PKG_CHECK_MODULES([openssl], [openssl], [], + [AC_MSG_ERROR([openssl is required for libcouplet])]) +PKG_CHECK_MODULES([check], [check >= 0.9.4], [], + [AC_MSG_WARN([libcheck not found; unit tests will not be compilable])]) +AC_CHECK_LIB(pthread, pthread_create, [], + [AC_MSG_ERROR([pthread support is required])]) +AC_CHECK_LIB(resolv, res_query, [], + [AC_MSG_ERROR([libresolv is not found])]) + +if test "x$with_libxml2" = xyes; then + PKG_CHECK_MODULES([libxml2], [libxml-2.0 >= 2.7], [], + [AC_MSG_ERROR([libxml2 is required for libcouplet])]) +else + PKG_CHECK_MODULES([expat], [expat], [], + [AC_MSG_ERROR([expat is required for libcouplet])]) fi if test "x$with_libxml2" = xyes; then - with_parser=libxml2 PARSER_NAME=libxml2 - PARSER_CFLAGS=\$\(libxml2_CFLAGS\) - PARSER_LIBS=\$\(libxml2_LIBS\) + LIBS="$LIBS $libxml2_LIBS" + AM_CFLAGS="$AM_CFLAGS $libxml2_CFLAGS" else - with_parser=expat PARSER_NAME=expat - PARSER_CFLAGS= - PARSER_LIBS=-lexpat + LIBS="$LIBS $expat_LIBS" + AM_CFLAGS="$AM_CFLAGS $expat_CFLAGS" fi -AC_MSG_NOTICE([libstrophe will use the $with_parser XML parser]) -AC_SEARCH_LIBS([socket], [socket]) +LIBS="$LIBS $openssl_LIBS" +AM_CFLAGS="$AM_CFLAGS $openssl_CFLAGS -I. -Wall" -AC_LINK_IFELSE([AC_LANG_CALL([#include ], [res_query])], [],[LIBS="$LIBS -lresolv"]) +AC_MSG_NOTICE([libcouplet will use the $PARSER_NAME XML parser]) +AC_SEARCH_LIBS([socket], [socket]) AC_CHECK_HEADERS([arpa/nameser_compat.h]) -AM_CONDITIONAL([PARSER_EXPAT], [test x$with_parser != xlibxml2]) +AM_CONDITIONAL([PARSER_EXPAT], [test x$PARSER_NAME != xlibxml2]) AC_SUBST(PARSER_NAME) -AC_SUBST(PARSER_CFLAGS) -AC_SUBST(PARSER_LIBS) -AC_CONFIG_FILES([Makefile]) +AC_SUBST(AM_CFLAGS) AC_OUTPUT diff --git a/strophe.h b/couplet.h similarity index 89% rename from strophe.h rename to couplet.h index e3a2f4df..fc2b0f1c 100644 --- a/strophe.h +++ b/couplet.h @@ -1,4 +1,4 @@ -/* strophe.h +/* couplet.h ** strophe XMPP client library C API ** ** Copyright (C) 2005-2009 Collecta, Inc. @@ -74,6 +74,10 @@ extern "C" { * Namespace definition for 'jabber:iq:roster'. */ #define XMPP_NS_ROSTER "jabber:iq:roster" +/** @def XMPP_NS_PING + * Namespace definition for 'urn:xmpp:ping'. + */ +#define XMPP_NS_PING "urn:xmpp:ping" /* error defines */ /** @def XMPP_EOK @@ -82,7 +86,7 @@ extern "C" { #define XMPP_EOK 0 /** @def XMPP_EMEM * Memory related failure error code. - * + * * This is returned on allocation errors and signals that the host may * be out of memory. */ @@ -98,6 +102,23 @@ extern "C" { * Internal failure error code. */ #define XMPP_EINT -3 +/** @def XMPP_EINVAL + * Invalid argument. + */ +#define XMPP_EINVAL -4 + +/** @def XMPP_FQDN_MAX_LEN + * Maximum length of FQDN. + * + * Should be set to 255 according to RFC2181. + */ +#define XMPP_FQDN_MAX_LEN 255 +/** @def XMPP_CLIENT_PORT + * Default xmpp-client TCP port. + * + * The recomended port is 5222 according to RFC3920. + */ +#define XMPP_CLIENT_PORT 5222 /* initialization and shutdown */ void xmpp_initialize(void); @@ -117,7 +138,7 @@ typedef struct _xmpp_log_t xmpp_log_t; /* opaque run time context containing the above hooks */ typedef struct _xmpp_ctx_t xmpp_ctx_t; -xmpp_ctx_t *xmpp_ctx_new(const xmpp_mem_t * const mem, +xmpp_ctx_t *xmpp_ctx_new(const xmpp_mem_t * const mem, const xmpp_log_t * const log); void xmpp_ctx_free(xmpp_ctx_t * const ctx); @@ -141,7 +162,7 @@ typedef enum { XMPP_COMPONENT } xmpp_conn_type_t; -typedef void (*xmpp_log_handler)(void * const userdata, +typedef void (*xmpp_log_handler)(void * const userdata, const xmpp_log_level_t level, const char * const area, const char * const msg); @@ -201,7 +222,7 @@ typedef struct { xmpp_stanza_t *stanza; } xmpp_stream_error_t; -typedef void (*xmpp_conn_handler)(xmpp_conn_t * const conn, +typedef void (*xmpp_conn_handler)(xmpp_conn_t * const conn, const xmpp_conn_event_t event, const int error, xmpp_stream_error_t * const stream_error, @@ -219,7 +240,7 @@ void xmpp_conn_set_pass(xmpp_conn_t * const conn, const char * const pass); xmpp_ctx_t* xmpp_conn_get_context(xmpp_conn_t * const conn); void xmpp_conn_disable_tls(xmpp_conn_t * const conn); -int xmpp_connect_client(xmpp_conn_t * const conn, +int xmpp_connect_client(xmpp_conn_t * const conn, const char * const altdomain, unsigned short altport, xmpp_conn_handler callback, @@ -233,16 +254,16 @@ void xmpp_disconnect(xmpp_conn_t * const conn); void xmpp_send(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza); -void xmpp_send_raw_string(xmpp_conn_t * const conn, +void xmpp_send_raw_string(xmpp_conn_t * const conn, const char * const fmt, ...); -void xmpp_send_raw(xmpp_conn_t * const conn, +void xmpp_send_raw(xmpp_conn_t * const conn, const char * const data, const size_t len); /* handlers */ /* if the handle returns false it is removed */ -typedef int (*xmpp_timed_handler)(xmpp_conn_t * const conn, +typedef int (*xmpp_timed_handler)(xmpp_conn_t * const conn, void * const userdata); void xmpp_timed_handler_add(xmpp_conn_t * const conn, @@ -301,11 +322,11 @@ int xmpp_stanza_is_text(xmpp_stanza_t * const stanza); int xmpp_stanza_is_tag(xmpp_stanza_t * const stanza); /** marshall a stanza into text for transmission or display **/ -int xmpp_stanza_to_text(xmpp_stanza_t *stanza, +int xmpp_stanza_to_text(xmpp_stanza_t *stanza, char ** const buf, size_t * const buflen); xmpp_stanza_t *xmpp_stanza_get_children(xmpp_stanza_t * const stanza); -xmpp_stanza_t *xmpp_stanza_get_child_by_name(xmpp_stanza_t * const stanza, +xmpp_stanza_t *xmpp_stanza_get_child_by_name(xmpp_stanza_t * const stanza, const char * const name); xmpp_stanza_t *xmpp_stanza_get_child_by_ns(xmpp_stanza_t * const stanza, const char * const ns); @@ -323,7 +344,7 @@ char *xmpp_stanza_get_name(xmpp_stanza_t * const stanza); int xmpp_stanza_add_child(xmpp_stanza_t *stanza, xmpp_stanza_t *child); int xmpp_stanza_set_ns(xmpp_stanza_t * const stanza, const char * const ns); /* set_attribute adds/replaces attributes */ -int xmpp_stanza_set_attribute(xmpp_stanza_t * const stanza, +int xmpp_stanza_set_attribute(xmpp_stanza_t * const stanza, const char * const key, const char * const value); int xmpp_stanza_set_name(xmpp_stanza_t *stanza, @@ -331,15 +352,15 @@ int xmpp_stanza_set_name(xmpp_stanza_t *stanza, int xmpp_stanza_set_text(xmpp_stanza_t *stanza, const char * const text); int xmpp_stanza_set_text_with_size(xmpp_stanza_t *stanza, - const char * const text, + const char * const text, const size_t size); /* common stanza helpers */ char *xmpp_stanza_get_type(xmpp_stanza_t * const stanza); char *xmpp_stanza_get_id(xmpp_stanza_t * const stanza); -int xmpp_stanza_set_id(xmpp_stanza_t * const stanza, +int xmpp_stanza_set_id(xmpp_stanza_t * const stanza, const char * const id); -int xmpp_stanza_set_type(xmpp_stanza_t * const stanza, +int xmpp_stanza_set_type(xmpp_stanza_t * const stanza, const char * const type); /* unimplemented @@ -363,6 +384,7 @@ void xmpp_presence_new(); */ /** event loop **/ +void xmpp_run_send_queue_once(xmpp_ctx_t *ctx); void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout); void xmpp_run(xmpp_ctx_t *ctx); void xmpp_stop(xmpp_ctx_t *ctx); diff --git a/strophepp.h b/coupletpp.h similarity index 96% rename from strophepp.h rename to coupletpp.h index 00431366..121ec638 100644 --- a/strophepp.h +++ b/coupletpp.h @@ -1,4 +1,4 @@ -/* strophepp.h +/* coupletpp.h ** strophe XMPP client library C++ API ** ** Copyright (C) 2005-2009 Collecta, Inc. @@ -19,7 +19,7 @@ #ifndef __LIBSTROPHE_STROPHEPP_H__ #define __LIBSTROPHE_STROPHEPP_H__ -#include "strophe.h" +#include "couplet.h" namespace XMPP { class Context { @@ -43,10 +43,10 @@ namespace XMPP { private: static void *callAlloc(const size_t size, void * const userdata); - static void *callRealloc(void *p, const size_t size, + static void *callRealloc(void *p, const size_t size, void * const userdata); static void callFree(void *p, void * const userdata); - static void callLog(void * const userdata, + static void callLog(void * const userdata, const xmpp_log_level_t level, const char * const area, const char * const msg); @@ -67,7 +67,7 @@ namespace XMPP { void release(); Stanza *clone(); Stanza *copy(); - + int toText(const char ** const buf, size_t * const buflen); Stanza *getChildren(); Stanza *getChildByName(const char * const name); diff --git a/examples/active.c b/examples/active.c index 8fdde725..4695c210 100644 --- a/examples/active.c +++ b/examples/active.c @@ -20,7 +20,7 @@ #include #include -#include +#include int handle_reply(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, diff --git a/examples/basic.c b/examples/basic.c index 0a317ee8..0acc73ac 100644 --- a/examples/basic.c +++ b/examples/basic.c @@ -14,7 +14,7 @@ #include -#include +#include /* define a handler for connection events */ diff --git a/examples/bot.c b/examples/bot.c index 03ba9c81..534ad40e 100644 --- a/examples/bot.c +++ b/examples/bot.c @@ -23,7 +23,7 @@ #include #include -#include +#include int version_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) diff --git a/examples/roster.c b/examples/roster.c index 379a998f..13651cd4 100644 --- a/examples/roster.c +++ b/examples/roster.c @@ -19,7 +19,7 @@ #include #include -#include +#include int handle_reply(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, diff --git a/expat b/expat deleted file mode 160000 index adf19a31..00000000 --- a/expat +++ /dev/null @@ -1 +0,0 @@ -Subproject commit adf19a31860c5b439c84f2ec1fde245b4815529a diff --git a/libcouplet.pc.in b/libcouplet.pc.in new file mode 100644 index 00000000..d6db556e --- /dev/null +++ b/libcouplet.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: libcouplet +Description: Fork of libstrophe - a simple, lightweight C library for writing XMPP clients +Requires: +Version: @PACKAGE_VERSION@ +Libs: -L${libdir} -lcouplet +Cflags: -I${includedir} diff --git a/src/auth.c b/src/auth.c index 23719256..30d72d8a 100644 --- a/src/auth.c +++ b/src/auth.c @@ -1,7 +1,7 @@ /* auth.c ** strophe XMPP client library -- auth functions and handlers ** -** Copyright (C) 2005-2009 Collecta, Inc. +** Copyright (C) 2005-2009 Collecta, Inc. ** ** This software is provided AS-IS with no warranty, either express or ** implied. @@ -12,7 +12,7 @@ ** distribution. */ -/** @file +/** @file * Authentication function and handlers. */ @@ -20,7 +20,7 @@ #include #include -#include "strophe.h" +#include "couplet.h" #include "common.h" #include "sasl.h" @@ -56,7 +56,6 @@ #endif static void _auth(xmpp_conn_t * const conn); -static void _handle_open_tls(xmpp_conn_t * const conn); static void _handle_open_sasl(xmpp_conn_t * const conn); static int _handle_missing_legacy(xmpp_conn_t * const conn, void * const userdata); @@ -100,7 +99,7 @@ static int _handle_error(xmpp_conn_t * const conn, /* free old stream error if it's still there */ if (conn->stream_error) { xmpp_stanza_release(conn->stream_error->stanza); - if (conn->stream_error->text) + if (conn->stream_error->text) xmpp_free(conn->ctx, conn->stream_error->text); xmpp_free(conn->ctx, conn->stream_error); } @@ -221,7 +220,7 @@ static int _handle_features(xmpp_conn_t * const conn, /* check for SASL */ child = xmpp_stanza_get_child_by_name(stanza, "mechanisms"); if (child && (strcmp(xmpp_stanza_get_ns(child), XMPP_NS_SASL) == 0)) { - for (mech = xmpp_stanza_get_children(child); mech; + for (mech = xmpp_stanza_get_children(child); mech; mech = xmpp_stanza_get_next(mech)) { if (strcmp(xmpp_stanza_get_name(mech), "mechanism") == 0) { text = xmpp_stanza_get_text(mech); @@ -238,7 +237,7 @@ static int _handle_features(xmpp_conn_t * const conn, } _auth(conn); - + return 0; } @@ -263,7 +262,7 @@ static int _handle_proceedtls_default(xmpp_conn_t * const conn, { char *name; name = xmpp_stanza_get_name(stanza); - xmpp_debug(conn->ctx, "xmpp", + xmpp_debug(conn->ctx, "xmpp", "handle proceedtls called for %s", name); if (strcmp(name, "proceed") == 0) { @@ -277,7 +276,7 @@ static int _handle_proceedtls_default(xmpp_conn_t * const conn, tls_free(conn->tls); conn->tls = NULL; conn->tls_failed = 1; - + /* failed tls spoils the connection, so disconnect */ xmpp_disconnect(conn); } @@ -303,14 +302,14 @@ static int _handle_sasl_result(xmpp_conn_t * const conn, /* the server should send a or stanza */ if (strcmp(name, "failure") == 0) { - xmpp_debug(conn->ctx, "xmpp", "SASL %s auth failed", + xmpp_debug(conn->ctx, "xmpp", "SASL %s auth failed", (char *)userdata); - + /* fall back to next auth method */ _auth(conn); } else if (strcmp(name, "success") == 0) { /* SASL PLAIN auth successful, we need to restart the stream */ - xmpp_debug(conn->ctx, "xmpp", "SASL %s auth successful", + xmpp_debug(conn->ctx, "xmpp", "SASL %s auth successful", (char *)userdata); /* reset parser */ @@ -355,10 +354,10 @@ static int _handle_digestmd5_challenge(xmpp_conn_t * const conn, if (!auth) { disconnect_mem_error(conn); return 0; - } + } xmpp_stanza_set_name(auth, "response"); xmpp_stanza_set_ns(auth, XMPP_NS_SASL); - + authdata = xmpp_stanza_new(conn->ctx); if (!authdata) { disconnect_mem_error(conn); @@ -371,7 +370,7 @@ static int _handle_digestmd5_challenge(xmpp_conn_t * const conn, xmpp_stanza_add_child(auth, authdata); xmpp_stanza_release(authdata); - handler_add(conn, _handle_digestmd5_rspauth, + handler_add(conn, _handle_digestmd5_rspauth, XMPP_NS_SASL, NULL, NULL, NULL); xmpp_send(conn, auth); @@ -404,7 +403,7 @@ static int _handle_digestmd5_rspauth(xmpp_conn_t * const conn, if (!auth) { disconnect_mem_error(conn); return 0; - } + } xmpp_stanza_set_name(auth, "response"); xmpp_stanza_set_ns(auth, XMPP_NS_SASL); xmpp_send(conn, auth); @@ -426,7 +425,7 @@ static xmpp_stanza_t *_make_starttls(xmpp_conn_t * const conn) xmpp_stanza_set_name(starttls, "starttls"); xmpp_stanza_set_ns(starttls, XMPP_NS_TLS); } - + return starttls; } @@ -442,14 +441,14 @@ static xmpp_stanza_t *_make_sasl_auth(xmpp_conn_t * const conn, xmpp_stanza_set_ns(auth, XMPP_NS_SASL); xmpp_stanza_set_attribute(auth, "mechanism", mechanism); } - + return auth; } -/* authenticate the connection - * this may get called multiple times. if any auth method fails, +/* authenticate the connection + * this may get called multiple times. if any auth method fails, * this will get called again until one auth method succeeds or every - * method fails + * method fails */ static void _auth(xmpp_conn_t * const conn) { @@ -489,7 +488,7 @@ static void _auth(xmpp_conn_t * const conn) return; } - handler_add(conn, _handle_proceedtls_default, + handler_add(conn, _handle_proceedtls_default, XMPP_NS_TLS, NULL, NULL, NULL); xmpp_send(conn, auth); @@ -514,7 +513,7 @@ static void _auth(xmpp_conn_t * const conn) /* SASL ANONYMOUS was tried, unset flag */ conn->sasl_support &= ~SASL_MASK_ANONYMOUS; } else if (anonjid) { - xmpp_error(conn->ctx, "auth", + xmpp_error(conn->ctx, "auth", "No node in JID, and SASL ANONYMOUS unsupported."); xmpp_disconnect(conn); } else if (conn->sasl_support & SASL_MASK_DIGESTMD5) { @@ -525,7 +524,7 @@ static void _auth(xmpp_conn_t * const conn) } - handler_add(conn, _handle_digestmd5_challenge, + handler_add(conn, _handle_digestmd5_challenge, XMPP_NS_SASL, NULL, NULL, NULL); xmpp_send(conn, auth); @@ -543,7 +542,7 @@ static void _auth(xmpp_conn_t * const conn) if (!authdata) { disconnect_mem_error(conn); return; - } + } authid = _get_authid(conn); if (!authid) { disconnect_mem_error(conn); @@ -554,6 +553,7 @@ static void _auth(xmpp_conn_t * const conn) disconnect_mem_error(conn); return; } + xmpp_free(conn->ctx, authid); xmpp_stanza_set_text(authdata, str); xmpp_free(conn->ctx, str); @@ -570,7 +570,7 @@ static void _auth(xmpp_conn_t * const conn) conn->sasl_support &= ~SASL_MASK_PLAIN; } else if (conn->type == XMPP_CLIENT) { /* legacy client authentication */ - + iq = xmpp_stanza_new(conn->ctx); if (!iq) { disconnect_mem_error(conn); @@ -656,7 +656,7 @@ static void _auth(xmpp_conn_t * const conn) } else { xmpp_stanza_release(authdata); xmpp_stanza_release(iq); - xmpp_error(conn->ctx, "auth", + xmpp_error(conn->ctx, "auth", "Cannot authenticate without resource"); xmpp_disconnect(conn); return; @@ -665,7 +665,7 @@ static void _auth(xmpp_conn_t * const conn) xmpp_stanza_release(authdata); handler_add_id(conn, _handle_legacy, "_xmpp_auth1", NULL); - handler_add_timed(conn, _handle_missing_legacy, + handler_add_timed(conn, _handle_missing_legacy, LEGACY_TIMEOUT, NULL); xmpp_send(conn, iq); @@ -677,7 +677,7 @@ static void _auth(xmpp_conn_t * const conn) /** Set up handlers at stream start. * This function is called internally to Strophe for handling the opening * of an XMPP stream. It's called by the parser when a stream is opened - * or reset, and adds the initial handlers for and + * or reset, and adds the initial handlers for and * . This function is not intended for use outside * of Strophe. * @@ -739,7 +739,7 @@ static int _handle_features_sasl(xmpp_conn_t * const conn, /* if bind is required, go ahead and start it */ if (conn->bind_required) { /* bind resource */ - + /* setup response handlers */ handler_add_id(conn, _handle_bind, "_xmpp_bind1", NULL); handler_add_timed(conn, _handle_missing_bind, @@ -771,7 +771,7 @@ static int _handle_features_sasl(xmpp_conn_t * const conn, resource = NULL; } - /* if we have a resource to request, do it. otherwise the + /* if we have a resource to request, do it. otherwise the server will assign us one */ if (resource) { res = xmpp_stanza_new(conn->ctx); @@ -822,7 +822,7 @@ static int _handle_missing_features_sasl(xmpp_conn_t * const conn, xmpp_disconnect(conn); return 0; } - + static int _handle_bind(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) @@ -854,7 +854,7 @@ static int _handle_bind(xmpp_conn_t * const conn, if (conn->session_required) { /* setup response handlers */ handler_add_id(conn, _handle_session, "_xmpp_session1", NULL); - handler_add_timed(conn, _handle_missing_session, + handler_add_timed(conn, _handle_missing_session, SESSION_TIMEOUT, NULL); /* send session request */ @@ -885,9 +885,9 @@ static int _handle_bind(xmpp_conn_t * const conn, xmpp_stanza_release(iq); } else { conn->authenticated = 1; - + /* call connection handler */ - conn->conn_handler(conn, XMPP_CONN_CONNECT, 0, NULL, + conn->conn_handler(conn, XMPP_CONN_CONNECT, 0, NULL, conn->userdata); } } else { @@ -924,7 +924,7 @@ static int _handle_session(xmpp_conn_t * const conn, xmpp_debug(conn->ctx, "xmpp", "Session establishment successful."); conn->authenticated = 1; - + /* call connection handler */ conn->conn_handler(conn, XMPP_CONN_CONNECT, 0, NULL, conn->userdata); } else { diff --git a/src/common.h b/src/common.h index 9434e6ff..b0243938 100644 --- a/src/common.h +++ b/src/common.h @@ -1,7 +1,7 @@ /* common.h ** strophe XMPP client library -- internal common structures ** -** Copyright (C) 2005-2009 Collecta, Inc. +** Copyright (C) 2005-2009 Collecta, Inc. ** ** This software is provided AS-IS with no warranty, either express or ** implied. @@ -26,45 +26,48 @@ #endif -#include "strophe.h" +#include "couplet.h" #include "sock.h" #include "tls.h" #include "hash.h" #include "util.h" #include "parser.h" +#include "thread.h" +#include "list.h" + +/** @def XMPP_RCV_BUF + * Receive buffer size + */ +#define XMPP_RCV_BUF 4096 /** run-time context **/ typedef enum { - XMPP_LOOP_NOTSTARTED, - XMPP_LOOP_RUNNING, - XMPP_LOOP_QUIT + XMPP_LOOP_NOTSTARTED, + XMPP_LOOP_RUNNING, + XMPP_LOOP_QUIT } xmpp_loop_status_t; -typedef struct _xmpp_connlist_t { - xmpp_conn_t *conn; - struct _xmpp_connlist_t *next; -} xmpp_connlist_t; - struct _xmpp_ctx_t { - const xmpp_mem_t *mem; - const xmpp_log_t *log; + const xmpp_mem_t *mem; + const xmpp_log_t *log; - xmpp_loop_status_t loop_status; - xmpp_connlist_t *connlist; + xmpp_loop_status_t loop_status; + list_head_t *connlist; + xmpp_sem_t *send_queue_sem; }; /* convenience functions for accessing the context */ void *xmpp_alloc(const xmpp_ctx_t * const ctx, const size_t size); -void *xmpp_realloc(const xmpp_ctx_t * const ctx, void *p, +void *xmpp_realloc(const xmpp_ctx_t * const ctx, void *p, const size_t size); char *xmpp_strdup(const xmpp_ctx_t * const ctx, const char * const s); -void xmpp_log(const xmpp_ctx_t * const ctx, +void xmpp_log(const xmpp_ctx_t * const ctx, const xmpp_log_level_t level, const char * const area, - const char * const fmt, + const char * const fmt, va_list ap); /* wrappers for xmpp_log at specific levels */ @@ -88,8 +91,8 @@ void xmpp_debug(const xmpp_ctx_t * const ctx, /** jid */ /* these return new strings that must be xmpp_free()'d */ char *xmpp_jid_new(xmpp_ctx_t *ctx, const char *node, - const char *domain, - const char *resource); + const char *domain, + const char *resource); char *xmpp_jid_bare(xmpp_ctx_t *ctx, const char *jid); char *xmpp_jid_node(xmpp_ctx_t *ctx, const char *jid); char *xmpp_jid_domain(xmpp_ctx_t *ctx, const char *jid); @@ -100,118 +103,126 @@ char *xmpp_jid_resource(xmpp_ctx_t *ctx, const char *jid); /* opaque connection object */ typedef enum { - XMPP_STATE_DISCONNECTED, - XMPP_STATE_CONNECTING, - XMPP_STATE_CONNECTED + XMPP_STATE_DISCONNECTED, + XMPP_STATE_CONNECTING, + XMPP_STATE_CONNECTED } xmpp_conn_state_t; typedef struct _xmpp_send_queue_t xmpp_send_queue_t; struct _xmpp_send_queue_t { - char *data; - size_t len; - size_t written; + char *data; + size_t len; + size_t written; +}; - xmpp_send_queue_t *next; +typedef struct _xmpp_handler_t xmpp_handler_t; +struct _xmpp_handler_t { + /* common members */ + int user_handler; + void *handler; + void *userdata; + + union { + /* timed handlers */ + struct { + unsigned long period; + uint64_t last_stamp; + }; + /* id handlers */ + struct { + char *id; + }; + /* normal handlers */ + struct { + char *ns; + char *name; + char *type; + }; + }; }; +/** @TODO This is still used by id_handlers + * It should be removed after rewriting id handlers with generic lists + */ typedef struct _xmpp_handlist_t xmpp_handlist_t; struct _xmpp_handlist_t { - /* common members */ - int user_handler; - void *handler; - void *userdata; - int enabled; /* handlers are added disabled and enabled after the - * handler chain is processed to prevent stanzas from - * getting processed by newly added handlers */ - xmpp_handlist_t *next; - - union { - /* timed handlers */ - struct { - unsigned long period; - uint64_t last_stamp; - }; - /* id handlers */ - struct { - char *id; - }; - /* normal handlers */ - struct { - char *ns; - char *name; - char *type; - }; - }; + /* common members */ + int user_handler; + void *handler; + void *userdata; + + int enabled; + xmpp_handlist_t *next; + + char *id; }; -#define SASL_MASK_PLAIN 0x01 -#define SASL_MASK_DIGESTMD5 0x02 -#define SASL_MASK_ANONYMOUS 0x04 +#define SASL_MASK_PLAIN 0x01 +#define SASL_MASK_DIGESTMD5 0x02 +#define SASL_MASK_ANONYMOUS 0x04 typedef void (*xmpp_open_handler)(xmpp_conn_t * const conn); struct _xmpp_conn_t { - unsigned int ref; - xmpp_ctx_t *ctx; - xmpp_conn_type_t type; - - xmpp_conn_state_t state; - uint64_t timeout_stamp; - int error; - xmpp_stream_error_t *stream_error; - sock_t sock; - tls_t *tls; - - int tls_support; - int tls_disabled; - int tls_failed; /* set when tls fails, so we don't try again */ - int sasl_support; /* if true, field is a bitfield of supported - mechanisms */ - int secured; /* set when stream is secured with TLS */ - - /* if server returns or we must do them */ - int bind_required; - int session_required; - - char *lang; - char *domain; - char *connectdomain; - char *connectport; - char *jid; - char *pass; - char *bound_jid; - char *stream_id; - - /* send queue and parameters */ - int blocking_send; - int send_queue_max; - int send_queue_len; - xmpp_send_queue_t *send_queue_head; - xmpp_send_queue_t *send_queue_tail; - - /* xml parser */ - int reset_parser; - parser_t *parser; - - /* timeouts */ - unsigned int connect_timeout; - - /* event handlers */ - - /* stream open handler */ - xmpp_open_handler open_handler; - - /* user handlers only get called after authentication */ - int authenticated; - - /* connection events handler */ - xmpp_conn_handler conn_handler; - void *userdata; - - /* other handlers */ - xmpp_handlist_t *timed_handlers; - hash_t *id_handlers; - xmpp_handlist_t *handlers; + unsigned int ref; + xmpp_ctx_t *ctx; + xmpp_conn_type_t type; + + xmpp_conn_state_t state; + uint64_t timeout_stamp; + int error; + xmpp_stream_error_t *stream_error; + sock_t sock; + tls_t *tls; + + int tls_support; + int tls_disabled; + int tls_failed; /* set when tls fails, so we don't try again */ + int sasl_support; /* if true, field is a bitfield of supported + * mechanisms */ + int secured; /* set when stream is secured with TLS */ + + /* if server returns or we must do them */ + int bind_required; + int session_required; + + char *lang; + char *domain; + char *connectdomain; + char *connectport; + char *jid; + char *pass; + char *bound_jid; + char *stream_id; + + /* send queue and parameters */ + int blocking_send; + int send_queue_max; + list_head_t *send_queue; + + /* xml parser */ + int reset_parser; + parser_t *parser; + + /* timeouts */ + unsigned int connect_timeout; + + /* event handlers */ + + /* stream open handler */ + xmpp_open_handler open_handler; + + /* user handlers only get called after authentication */ + int authenticated; + + /* connection events handler */ + xmpp_conn_handler conn_handler; + void *userdata; + + /* other handlers */ + list_head_t *timed_handlers; + hash_t *id_handlers; + list_head_t *handlers; }; void conn_disconnect(xmpp_conn_t * const conn); @@ -222,25 +233,25 @@ void conn_parser_reset(xmpp_conn_t * const conn); typedef enum { - XMPP_STANZA_UNKNOWN, - XMPP_STANZA_TEXT, - XMPP_STANZA_TAG + XMPP_STANZA_UNKNOWN, + XMPP_STANZA_TEXT, + XMPP_STANZA_TAG } xmpp_stanza_type_t; struct _xmpp_stanza_t { - int ref; - xmpp_ctx_t *ctx; + int ref; + xmpp_ctx_t *ctx; + + xmpp_stanza_type_t type; - xmpp_stanza_type_t type; - - xmpp_stanza_t *prev; - xmpp_stanza_t *next; - xmpp_stanza_t *children; - xmpp_stanza_t *parent; + xmpp_stanza_t *prev; + xmpp_stanza_t *next; + xmpp_stanza_t *children; + xmpp_stanza_t *parent; - char *data; + char *data; - hash_t *attributes; + hash_t *attributes; }; /* handler management */ diff --git a/src/conn.c b/src/conn.c index 26df4186..e0cd299e 100644 --- a/src/conn.c +++ b/src/conn.c @@ -1,7 +1,7 @@ /* conn.c ** strophe XMPP client library -- connection object functions ** -** Copyright (C) 2005-2009 Collecta, Inc. +** Copyright (C) 2005-2009 Collecta, Inc. ** ** This software is provided AS-IS with no warranty, either express ** or implied. @@ -12,7 +12,7 @@ ** distribution. */ -/** @file +/** @file * Connection management. */ @@ -23,11 +23,13 @@ #include #include -#include +#include "couplet.h" #include "common.h" #include "util.h" #include "parser.h" +#include "thread.h" +#include "list.h" #ifndef DEFAULT_SEND_QUEUE_MAX /** @def DEFAULT_SEND_QUEUE_MAX @@ -36,7 +38,7 @@ #define DEFAULT_SEND_QUEUE_MAX 64 #endif #ifndef DISCONNECT_TIMEOUT -/** @def DISCONNECT_TIMEOUT +/** @def DISCONNECT_TIMEOUT * The time to wait (in milliseconds) for graceful disconnection to * complete before the connection is reset. The default is 2 seconds. */ @@ -44,21 +46,18 @@ #endif #ifndef CONNECT_TIMEOUT /** @def CONNECT_TIMEOUT - * The time to wait (in milliseconds) for a connection attempt to succeed + * The time to wait (in milliseconds) for a connection attempt to succeed * or error. The default is 5 seconds. */ #define CONNECT_TIMEOUT 5000 /* 5 seconds */ #endif -static int _disconnect_cleanup(xmpp_conn_t * const conn, - void * const userdata); +static int _disconnect_cleanup(xmpp_conn_t * const conn, void * const userdata); -static void _handle_stream_start(char *name, char **attrs, - void * const userdata); -static void _handle_stream_end(char *name, - void * const userdata); -static void _handle_stream_stanza(xmpp_stanza_t *stanza, - void * const userdata); +static void _handle_stream_start(char *name, char **attrs, + void * const userdata); +static void _handle_stream_end(char *name, void * const userdata); +static void _handle_stream_stanza(xmpp_stanza_t *stanza, void * const userdata); /** Create a new Strophe connection object. * @@ -70,17 +69,20 @@ static void _handle_stream_stanza(xmpp_stanza_t *stanza, */ xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t * const ctx) { - xmpp_conn_t *conn = NULL; - xmpp_connlist_t *tail, *item; + xmpp_conn_t *conn; + list_t *item; - if (ctx == NULL) return NULL; + if (!ctx) + return NULL; conn = xmpp_alloc(ctx, sizeof(xmpp_conn_t)); - - if (conn != NULL) { + + if (!conn) + return NULL; + conn->ctx = ctx; conn->type = XMPP_UNKNOWN; - conn->state = XMPP_STATE_DISCONNECTED; + conn->state = XMPP_STATE_DISCONNECTED; conn->sock = -1; conn->tls = NULL; conn->timeout_stamp = 0; @@ -90,77 +92,85 @@ xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t * const ctx) /* default send parameters */ conn->blocking_send = 0; conn->send_queue_max = DEFAULT_SEND_QUEUE_MAX; - conn->send_queue_len = 0; - conn->send_queue_head = NULL; - conn->send_queue_tail = NULL; + conn->send_queue = list_init(ctx); + if (!conn->send_queue) + goto out_free_conn; /* default timeouts */ conn->connect_timeout = CONNECT_TIMEOUT; - conn->lang = xmpp_strdup(conn->ctx, "en"); - if (!conn->lang) { - xmpp_free(conn->ctx, conn); - return NULL; - } + conn->lang = xmpp_strdup(ctx, "en"); + if (!conn->lang) + goto out_free_send_queue; + conn->domain = NULL; conn->jid = NULL; conn->pass = NULL; conn->stream_id = NULL; - conn->bound_jid = NULL; + conn->bound_jid = NULL; conn->tls_support = 0; conn->tls_disabled = 0; conn->tls_failed = 0; conn->sasl_support = 0; - conn->secured = 0; + conn->secured = 0; conn->bind_required = 0; conn->session_required = 0; - conn->parser = parser_new(conn->ctx, - _handle_stream_start, - _handle_stream_end, - _handle_stream_stanza, - conn); - conn->reset_parser = 0; - conn_prepare_reset(conn, auth_handle_open); + conn->parser = parser_new(ctx, + _handle_stream_start, + _handle_stream_end, + _handle_stream_stanza, + conn); + if (!conn->parser) + goto out_free_lang; + conn->reset_parser = 0; + conn_prepare_reset(conn, auth_handle_open); conn->authenticated = 0; conn->conn_handler = NULL; conn->userdata = NULL; - conn->timed_handlers = NULL; /* we own (and will free) the hash values */ - conn->id_handlers = hash_new(conn->ctx, 32, NULL); - conn->handlers = NULL; + conn->id_handlers = hash_new(ctx, 32, NULL); + conn->timed_handlers = list_init(ctx); + if (!conn->timed_handlers) + goto out_free_parser; + conn->handlers = list_init(ctx); + if (!conn->handlers) + goto out_free_timed_handlers; /* give the caller a reference to connection */ conn->ref = 1; /* add connection to ctx->connlist */ - tail = conn->ctx->connlist; - while (tail && tail->next) tail = tail->next; - - item = xmpp_alloc(conn->ctx, sizeof(xmpp_connlist_t)); - if (!item) { - xmpp_error(conn->ctx, "xmpp", "failed to allocate memory"); - xmpp_free(conn->ctx, conn->lang); - parser_free(conn->parser); - xmpp_free(conn->ctx, conn); - conn = NULL; - } else { - item->conn = conn; - item->next = NULL; - - if (tail) tail->next = item; - else conn->ctx->connlist = item; + item = list_init_item(ctx); + if (!item) + goto out_free_handlers; + else { + item->data = (void *)conn; + list_push(ctx->connlist, item); } - } - - return conn; + + return conn; + +out_free_handlers: + list_destroy(conn->handlers); +out_free_timed_handlers: + list_destroy(conn->timed_handlers); +out_free_parser: + parser_free(conn->parser); +out_free_lang: + xmpp_free(ctx, conn->lang); +out_free_send_queue: + list_destroy(conn->send_queue); +out_free_conn: + xmpp_free(ctx, conn); + return NULL; } /** Clone a Strophe connection object. - * + * * @param conn a Strophe connection object * * @return the same conn object passed in with its reference count @@ -170,12 +180,12 @@ xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t * const ctx) */ xmpp_conn_t *xmpp_conn_clone(xmpp_conn_t * const conn) { - conn->ref++; - return conn; + conn->ref++; + return conn; } /** Release a Strophe connection object. - * Decrement the reference count by one for a connection, freeing the + * Decrement the reference count by one for a connection, freeing the * connection object if the count reaches 0. * * @param conn a Strophe connection object @@ -186,103 +196,99 @@ xmpp_conn_t *xmpp_conn_clone(xmpp_conn_t * const conn) */ int xmpp_conn_release(xmpp_conn_t * const conn) { - xmpp_ctx_t *ctx; - xmpp_connlist_t *item, *prev; - xmpp_handlist_t *hlitem, *thli; - hash_iterator_t *iter; - const char *key; - int released = 0; - - if (conn->ref > 1) - conn->ref--; - else { + xmpp_ctx_t *ctx; + list_t *item; + xmpp_handler_t *temp; + xmpp_handlist_t *hlitem, *thli; + hash_iterator_t *iter; + const char *key; + + if (conn->ref > 1) { + conn->ref--; + return 0; + } + ctx = conn->ctx; /* remove connection from context's connlist */ - if (ctx->connlist->conn == conn) { - item = ctx->connlist; - ctx->connlist = item->next; - xmpp_free(ctx, item); - } else { - prev = NULL; - item = ctx->connlist; - while (item && item->conn != conn) { - prev = item; - item = item->next; - } - - if (!item) { - xmpp_error(ctx, "xmpp", "Connection not in context's list\n"); - } else { - prev->next = item->next; + item = list_pop_by_data(ctx->connlist, (void *)conn); + if (item) xmpp_free(ctx, item); - } - } + else + xmpp_error(ctx, "xmpp", "Connection not in context's list\n"); /* free handler stuff * note that userdata is the responsibility of the client * and the handler pointers don't need to be freed since they * are pointers to functions */ - hlitem = conn->timed_handlers; - while (hlitem) { - thli = hlitem; - hlitem = hlitem->next; - - xmpp_free(ctx, thli); + while ((item = list_shift(conn->timed_handlers))) { + xmpp_free(ctx, item->data); + xmpp_free(ctx, item); } + list_destroy(conn->timed_handlers); /* id handlers - * we have to traverse the hash table freeing list elements + * we have to traverse the hash table freeing list elements * then release the hash table */ iter = hash_iter_new(conn->id_handlers); while ((key = hash_iter_next(iter))) { - hlitem = (xmpp_handlist_t *)hash_get(conn->id_handlers, key); - while (hlitem) { - thli = hlitem; - hlitem = hlitem->next; - xmpp_free(conn->ctx, thli->id); - xmpp_free(conn->ctx, thli); - } + hlitem = (xmpp_handlist_t *)hash_get(conn->id_handlers, key); + while (hlitem) { + thli = hlitem; + hlitem = hlitem->next; + xmpp_free(ctx, thli->id); + xmpp_free(ctx, thli); + } } hash_iter_release(iter); hash_release(conn->id_handlers); - hlitem = conn->handlers; - while (hlitem) { - thli = hlitem; - hlitem = hlitem->next; + while ((item = list_shift(conn->handlers))) { + temp = (xmpp_handler_t *)item->data; - if (thli->ns) xmpp_free(ctx, thli->ns); - if (thli->name) xmpp_free(ctx, thli->name); - if (thli->type) xmpp_free(ctx, thli->type); - xmpp_free(ctx, thli); + if (temp->ns) + xmpp_free(ctx, temp->ns); + if (temp->name) + xmpp_free(ctx, temp->name); + if (temp->type) + xmpp_free(ctx, temp->type); + xmpp_free(ctx, temp); + xmpp_free(ctx, item); } + list_destroy(conn->handlers); if (conn->stream_error) { - xmpp_stanza_release(conn->stream_error->stanza); - if (conn->stream_error->text) - xmpp_free(ctx, conn->stream_error->text); - xmpp_free(ctx, conn->stream_error); + xmpp_stanza_release(conn->stream_error->stanza); + if (conn->stream_error->text) + xmpp_free(ctx, conn->stream_error->text); + xmpp_free(ctx, conn->stream_error); } - parser_free(conn->parser); - - if (conn->domain) xmpp_free(ctx, conn->domain); - if (conn->jid) xmpp_free(ctx, conn->jid); - if (conn->bound_jid) xmpp_free(ctx, conn->bound_jid); - if (conn->pass) xmpp_free(ctx, conn->pass); - if (conn->stream_id) xmpp_free(ctx, conn->stream_id); - if (conn->lang) xmpp_free(ctx, conn->lang); + parser_free(conn->parser); + + /* free send_queue */ + list_destroy(conn->send_queue); + + if (conn->domain) + xmpp_free(ctx, conn->domain); + if (conn->jid) + xmpp_free(ctx, conn->jid); + if (conn->bound_jid) + xmpp_free(ctx, conn->bound_jid); + if (conn->pass) + xmpp_free(ctx, conn->pass); + if (conn->stream_id) + xmpp_free(ctx, conn->stream_id); + if (conn->lang) + xmpp_free(ctx, conn->lang); xmpp_free(ctx, conn); - released = 1; - } - return released; + return 1; } /** Get the JID which is or will be bound to the connection. - * + * * @param conn a Strophe connection object * * @return a string containing the full JID or NULL if it has not been set @@ -291,7 +297,7 @@ int xmpp_conn_release(xmpp_conn_t * const conn) */ const char *xmpp_conn_get_jid(const xmpp_conn_t * const conn) { - return conn->jid; + return conn->jid; } /** @@ -309,11 +315,11 @@ const char *xmpp_conn_get_jid(const xmpp_conn_t * const conn) */ const char *xmpp_conn_get_bound_jid(const xmpp_conn_t * const conn) { - return conn->bound_jid; + return conn->bound_jid; } /** Set the JID of the user that will be bound to the connection. - * If any JID was previously set, it will be discarded. This should not be + * If any JID was previously set, it will be discarded. This should not be * be used after a connection is created. The function will make a copy of * the JID string. If the supllied JID is missing the node, SASL * ANONYMOUS authentication will be used. @@ -325,8 +331,9 @@ const char *xmpp_conn_get_bound_jid(const xmpp_conn_t * const conn) */ void xmpp_conn_set_jid(xmpp_conn_t * const conn, const char * const jid) { - if (conn->jid) xmpp_free(conn->ctx, conn->jid); - conn->jid = xmpp_strdup(conn->ctx, jid); + if (conn->jid) + xmpp_free(conn->ctx, conn->jid); + conn->jid = xmpp_strdup(conn->ctx, jid); } /** Get the password used for authentication of a connection. @@ -339,13 +346,13 @@ void xmpp_conn_set_jid(xmpp_conn_t * const conn, const char * const jid) */ const char *xmpp_conn_get_pass(const xmpp_conn_t * const conn) { - return conn->pass; + return conn->pass; } /** Set the password used to authenticate the connection. * If any password was previously set, it will be discarded. The function * will make a copy of the password string. - * + * * @param conn a Strophe connection object * @param pass the password * @@ -353,15 +360,16 @@ const char *xmpp_conn_get_pass(const xmpp_conn_t * const conn) */ void xmpp_conn_set_pass(xmpp_conn_t * const conn, const char * const pass) { - if (conn->pass) xmpp_free(conn->ctx, conn->pass); - conn->pass = xmpp_strdup(conn->ctx, pass); + if (conn->pass) + xmpp_free(conn->ctx, conn->pass); + conn->pass = xmpp_strdup(conn->ctx, pass); } /** Get the strophe context that the connection is associated with. * @param conn a Strophe connection object -* +* * @return a Strophe context -* +* * @ingroup Connections */ xmpp_ctx_t* xmpp_conn_get_context(xmpp_conn_t * const conn) @@ -374,7 +382,7 @@ xmpp_ctx_t* xmpp_conn_get_context(xmpp_conn_t * const conn) * process to the XMPP server, and notifiations of connection state changes * will be sent to the callback function. The domain and port to connect to * are usually determined by an SRV lookup for the xmpp-client service at - * the domain specified in the JID. If SRV lookup fails, altdomain and + * the domain specified in the JID. If SRV lookup fails, altdomain and * altport will be used instead if specified. * * @param conn a Strophe connection object @@ -390,56 +398,57 @@ xmpp_ctx_t* xmpp_conn_get_context(xmpp_conn_t * const conn) * * @ingroup Connections */ -int xmpp_connect_client(xmpp_conn_t * const conn, +int xmpp_connect_client(xmpp_conn_t * const conn, const char * const altdomain, unsigned short altport, xmpp_conn_handler callback, void * const userdata) { - char connectdomain[2048]; - int connectport; - const char * domain; - - conn->type = XMPP_CLIENT; - - conn->domain = xmpp_jid_domain(conn->ctx, conn->jid); - if (!conn->domain) return -1; - - if (altdomain) { - xmpp_debug(conn->ctx, "xmpp", "Connecting via altdomain."); - strcpy(connectdomain, altdomain); - connectport = altport ? altport : 5222; - } else if (!sock_srv_lookup("xmpp-client", "tcp", conn->domain, - connectdomain, 2048, &connectport)) { - xmpp_debug(conn->ctx, "xmpp", "SRV lookup failed."); - if (!altdomain) - domain = conn->domain; - else - domain = altdomain; - xmpp_debug(conn->ctx, "xmpp", "Using alternate domain %s, port %d", - altdomain, altport); - strcpy(connectdomain, domain); - connectport = altport ? altport : 5222; - } - conn->sock = sock_connect(connectdomain, connectport); - xmpp_debug(conn->ctx, "xmpp", "sock_connect to %s:%d returned %d", - connectdomain, connectport, conn->sock); - if (conn->sock == -1) return -1; - - /* setup handler */ - conn->conn_handler = callback; - conn->userdata = userdata; - - /* FIXME: it could happen that the connect returns immediately as - * successful, though this is pretty unlikely. This would be a little - * hard to fix, since we'd have to detect and fire off the callback - * from within the event loop */ - - conn->state = XMPP_STATE_CONNECTING; - conn->timeout_stamp = time_stamp(); - xmpp_debug(conn->ctx, "xmpp", "attempting to connect to %s", connectdomain); - - return 0; + char connectdomain[XMPP_FQDN_MAX_LEN + 1]; + int connectport; + + conn->type = XMPP_CLIENT; + + conn->domain = xmpp_jid_domain(conn->ctx, conn->jid); + if (!conn->domain) + return -1; + + if (altdomain) { + if (strlen(altdomain) > XMPP_FQDN_MAX_LEN) + return XMPP_EINVAL; + xmpp_debug(conn->ctx, "xmpp", "Connecting via altdomain."); + strcpy(connectdomain, altdomain); + connectport = altport ? altport : XMPP_CLIENT_PORT; + } else if (!sock_srv_lookup("xmpp-client", "tcp", conn->domain, + connectdomain, XMPP_FQDN_MAX_LEN + 1, &connectport)) { + xmpp_debug(conn->ctx, "xmpp", "SRV lookup failed."); + if (strlen(conn->domain) > XMPP_FQDN_MAX_LEN) + return XMPP_EINVAL; + xmpp_debug(conn->ctx, "xmpp", "Using domain %s, port %d", + altdomain, altport); + strcpy(connectdomain, conn->domain); + connectport = altport ? altport : XMPP_CLIENT_PORT; + } + conn->sock = sock_connect(connectdomain, connectport); + xmpp_debug(conn->ctx, "xmpp", "sock_connect to %s:%d returned %d", + connectdomain, connectport, conn->sock); + if (conn->sock == -1) + return -1; + + /* setup handler */ + conn->conn_handler = callback; + conn->userdata = userdata; + + /* FIXME: it could happen that the connect returns immediately as + * successful, though this is pretty unlikely. This would be a little + * hard to fix, since we'd have to detect and fire off the callback + * from within the event loop */ + + conn->state = XMPP_STATE_CONNECTING; + conn->timeout_stamp = time_stamp(); + xmpp_debug(conn->ctx, "xmpp", "attempting to connect to %s", connectdomain); + + return 0; } /** Cleanly disconnect the connection. @@ -450,10 +459,10 @@ int xmpp_connect_client(xmpp_conn_t * const conn, */ void conn_disconnect_clean(xmpp_conn_t * const conn) { - /* remove the timed handler */ - xmpp_timed_handler_delete(conn, _disconnect_cleanup); + /* remove the timed handler */ + xmpp_timed_handler_delete(conn, _disconnect_cleanup); - conn_disconnect(conn); + conn_disconnect(conn); } /** Disconnect from the XMPP server. @@ -462,47 +471,45 @@ void conn_disconnect_clean(xmpp_conn_t * const conn) * * @param conn a Strophe connection object */ -void conn_disconnect(xmpp_conn_t * const conn) +void conn_disconnect(xmpp_conn_t * const conn) { - xmpp_debug(conn->ctx, "xmpp", "Closing socket."); - conn->state = XMPP_STATE_DISCONNECTED; - if (conn->tls) { - tls_stop(conn->tls); - tls_free(conn->tls); - conn->tls = NULL; - } - sock_close(conn->sock); + xmpp_debug(conn->ctx, "xmpp", "Closing socket."); + conn->state = XMPP_STATE_DISCONNECTED; + if (conn->tls) { + tls_stop(conn->tls); + tls_free(conn->tls); + conn->tls = NULL; + } + sock_close(conn->sock); - /* fire off connection handler */ - conn->conn_handler(conn, XMPP_CONN_DISCONNECT, conn->error, - conn->stream_error, conn->userdata); + /* fire off connection handler */ + conn->conn_handler(conn, XMPP_CONN_DISCONNECT, conn->error, + conn->stream_error, conn->userdata); } /* prepares a parser reset. this is called from handlers. we can't * reset the parser immediately as it is not re-entrant. */ void conn_prepare_reset(xmpp_conn_t * const conn, xmpp_open_handler handler) { - conn->reset_parser = 1; - conn->open_handler = handler; + conn->reset_parser = 1; + conn->open_handler = handler; } /* reset the parser */ void conn_parser_reset(xmpp_conn_t * const conn) { - conn->reset_parser = 0; - parser_reset(conn->parser); + conn->reset_parser = 0; + parser_reset(conn->parser); } /* timed handler for cleanup if normal disconnect procedure takes too long */ -static int _disconnect_cleanup(xmpp_conn_t * const conn, +static int _disconnect_cleanup(xmpp_conn_t * const conn, void * const userdata) { - xmpp_debug(conn->ctx, "xmpp", - "disconnection forced by cleanup timeout"); - - conn_disconnect(conn); + xmpp_debug(conn->ctx, "xmpp", "disconnection forced by cleanup timeout"); + conn_disconnect(conn); - return 0; + return 0; } /** Initiate termination of the connection to the XMPP server. @@ -516,20 +523,20 @@ static int _disconnect_cleanup(xmpp_conn_t * const conn, */ void xmpp_disconnect(xmpp_conn_t * const conn) { - if (conn->state != XMPP_STATE_CONNECTING && - conn->state != XMPP_STATE_CONNECTED) - return; + if (conn->state != XMPP_STATE_CONNECTING && + conn->state != XMPP_STATE_CONNECTED) + return; - /* close the stream */ - xmpp_send_raw_string(conn, ""); + /* close the stream */ + xmpp_send_raw_string(conn, ""); - /* setup timed handler in case disconnect takes too long */ - handler_add_timed(conn, _disconnect_cleanup, - DISCONNECT_TIMEOUT, NULL); + /* setup timed handler in case disconnect takes too long */ + handler_add_timed(conn, _disconnect_cleanup, + DISCONNECT_TIMEOUT, NULL); } /** Send a raw string to the XMPP server. - * This function is a convenience function to send raw string data to the + * This function is a convenience function to send raw string data to the * XMPP server. It is used by Strophe to send short messages instead of * building up an XML stanza with DOM methods. This should be used with care * as it does not validate the data; invalid data may result in immediate @@ -539,47 +546,46 @@ void xmpp_disconnect(xmpp_conn_t * const conn) * @param fmt a printf-style format string followed by a variable list of * arguments to format */ -void xmpp_send_raw_string(xmpp_conn_t * const conn, +void xmpp_send_raw_string(xmpp_conn_t * const conn, const char * const fmt, ...) { - va_list ap; - size_t len; - char buf[1024]; /* small buffer for common case */ - char *bigbuf; - - va_start(ap, fmt); - len = xmpp_vsnprintf(buf, 1024, fmt, ap); - va_end(ap); - - if (len >= 1024) { - /* we need more space for this data, so we allocate a big - * enough buffer and print to that */ - len++; /* account for trailing \0 */ - bigbuf = xmpp_alloc(conn->ctx, len); - if (!bigbuf) { - xmpp_debug(conn->ctx, "xmpp", "Could not allocate memory for send_raw_string"); - return; - } + va_list ap; + size_t len; + char buf[1024]; /* small buffer for common case */ + char *bigbuf; + va_start(ap, fmt); - xmpp_vsnprintf(bigbuf, len, fmt, ap); + len = xmpp_vsnprintf(buf, 1024, fmt, ap); va_end(ap); - xmpp_debug(conn->ctx, "conn", "SENT: %s", bigbuf); - - /* len - 1 so we don't send trailing \0 */ - xmpp_send_raw(conn, bigbuf, len - 1); - - xmpp_free(conn->ctx, bigbuf); - } else { - xmpp_debug(conn->ctx, "conn", "SENT: %s", buf); - - xmpp_send_raw(conn, buf, len); - } + if (len >= 1024) { + /* we need more space for this data, so we allocate a big + * enough buffer and print to that */ + len++; /* account for trailing \0 */ + bigbuf = xmpp_alloc(conn->ctx, len); + if (!bigbuf) { + xmpp_debug(conn->ctx, "xmpp", + "Could not allocate memory for send_raw_string"); + return; + } + va_start(ap, fmt); + xmpp_vsnprintf(bigbuf, len, fmt, ap); + va_end(ap); + + xmpp_debug(conn->ctx, "conn", "SENT: %s", bigbuf); + /* len - 1 so we don't send trailing \0 */ + xmpp_send_raw(conn, bigbuf, len - 1); + + xmpp_free(conn->ctx, bigbuf); + } else { + xmpp_debug(conn->ctx, "conn", "SENT: %s", buf); + xmpp_send_raw(conn, buf, len); + } } /** Send raw bytes to the XMPP server. - * This function is a convenience function to send raw bytes to the - * XMPP server. It is usedly primarly by xmpp_send_raw_string. This + * This function is a convenience function to send raw bytes to the + * XMPP server. It is usedly primarly by xmpp_send_raw_string. This * function should be used with care as it does not validate the bytes and * invalid data may result in stream termination by the XMPP server. * @@ -590,35 +596,44 @@ void xmpp_send_raw_string(xmpp_conn_t * const conn, void xmpp_send_raw(xmpp_conn_t * const conn, const char * const data, const size_t len) { - xmpp_send_queue_t *item; + xmpp_ctx_t *ctx; + xmpp_send_queue_t *sq; + list_t *item; + + if (conn->state != XMPP_STATE_CONNECTED) + return; + + ctx = conn->ctx; + + /* create send queue item for queue */ + sq = xmpp_alloc(ctx, sizeof(xmpp_send_queue_t)); + if (!sq) + return; + + sq->data = xmpp_alloc(ctx, len); + if (!sq->data) + goto out_free_sq; + + item = list_init_item(ctx); + if (!item) + goto out_free_data; - if (conn->state != XMPP_STATE_CONNECTED) return; + memcpy(sq->data, data, len); + sq->len = len; + sq->written = 0; + item->data = (void *)sq; - /* create send queue item for queue */ - item = xmpp_alloc(conn->ctx, sizeof(xmpp_send_queue_t)); - if (!item) return; + /* add item to the send queue */ + list_push(conn->send_queue, item); + /* unlock send_queue_thread */ + xmpp_sem_post(ctx->send_queue_sem); - item->data = xmpp_alloc(conn->ctx, len); - if (!item->data) { - xmpp_free(conn->ctx, item); return; - } - memcpy(item->data, data, len); - item->len = len; - item->next = NULL; - item->written = 0; - - /* add item to the send queue */ - if (!conn->send_queue_tail) { - /* first item, set head and tail */ - conn->send_queue_head = item; - conn->send_queue_tail = item; - } else { - /* add to the tail */ - conn->send_queue_tail->next = item; - conn->send_queue_tail = item; - } - conn->send_queue_len++; + +out_free_data: + xmpp_free(ctx, sq->data); +out_free_sq: + xmpp_free(ctx, sq); } /** Send an XML stanza to the XMPP server. @@ -630,20 +645,17 @@ void xmpp_send_raw(xmpp_conn_t * const conn, * * @ingroup Connections */ -void xmpp_send(xmpp_conn_t * const conn, - xmpp_stanza_t * const stanza) +void xmpp_send(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza) { - char *buf; - size_t len; - int ret; - - if (conn->state == XMPP_STATE_CONNECTED) { - if ((ret = xmpp_stanza_to_text(stanza, &buf, &len)) == 0) { - xmpp_send_raw(conn, buf, len); - xmpp_debug(conn->ctx, "conn", "SENT: %s", buf); - xmpp_free(conn->ctx, buf); + char *buf; + size_t len; + + if (conn->state == XMPP_STATE_CONNECTED && + !xmpp_stanza_to_text(stanza, &buf, &len)) { + xmpp_send_raw(conn, buf, len); + xmpp_debug(conn->ctx, "conn", "SENT: %s", buf); + xmpp_free(conn->ctx, buf); } - } } /** Send the opening <stream:stream> tag to the server. @@ -654,17 +666,17 @@ void xmpp_send(xmpp_conn_t * const conn, */ void conn_open_stream(xmpp_conn_t * const conn) { - xmpp_send_raw_string(conn, - "" \ - "", - conn->domain, - conn->lang, - conn->type == XMPP_CLIENT ? XMPP_NS_CLIENT : XMPP_NS_COMPONENT, - XMPP_NS_STREAMS); + xmpp_send_raw_string(conn, + "" \ + "", + conn->domain, + conn->lang, + conn->type == XMPP_CLIENT ? XMPP_NS_CLIENT : XMPP_NS_COMPONENT, + XMPP_NS_STREAMS); } /** Disable TLS for this connection, called by users of the library. @@ -675,99 +687,106 @@ void conn_open_stream(xmpp_conn_t * const conn) */ void xmpp_conn_disable_tls(xmpp_conn_t * const conn) { - conn->tls_disabled = 1; + conn->tls_disabled = 1; } static void _log_open_tag(xmpp_conn_t *conn, char **attrs) { - char buf[4096]; - size_t len, pos; - int i; - - if (!attrs) return; - - pos = 0; - len = xmpp_snprintf(buf, 4096, ""); - if (len < 0) return; - - xmpp_debug(conn->ctx, "xmpp", "RECV: %s", buf); + char buf[4096]; + size_t pos; + int len; + int i; + + if (!attrs) + return; + + pos = 0; + len = xmpp_snprintf(buf, 4096, ""); + if (len < 0) + return; + + xmpp_debug(conn->ctx, "xmpp", "RECV: %s", buf); } static char *_get_stream_attribute(char **attrs, char *name) { - int i; + int i; - if (!attrs) return NULL; + if (!attrs) + return NULL; - for (i = 0; attrs[i]; i += 2) - if (strcmp(name, attrs[i]) == 0) - return attrs[i+1]; + for (i = 0; attrs[i]; i += 2) + if (!strcmp(name, attrs[i])) + return attrs[i+1]; - return NULL; + return NULL; } -static void _handle_stream_start(char *name, char **attrs, - void * const userdata) +static void _handle_stream_start(char *name, char **attrs, + void * const userdata) { - xmpp_conn_t *conn = (xmpp_conn_t *)userdata; - char *id; - - if (strcmp(name, "stream:stream") != 0) { - printf("name = %s\n", name); - xmpp_error(conn->ctx, "conn", "Server did not open valid stream."); - conn_disconnect(conn); - } else { - _log_open_tag(conn, attrs); - - if (conn->stream_id) xmpp_free(conn->ctx, conn->stream_id); - - id = _get_stream_attribute(attrs, "id"); - if (id) - conn->stream_id = xmpp_strdup(conn->ctx, id); - - if (!conn->stream_id) { - xmpp_error(conn->ctx, "conn", "Memory allocation failed."); - conn_disconnect(conn); - } - } - - /* call stream open handler */ - conn->open_handler(conn); + xmpp_conn_t *conn = (xmpp_conn_t *)userdata; + char *id; + + if (strcmp(name, "stream:stream")) { + printf("name = %s\n", name); + xmpp_error(conn->ctx, "conn", "Server did not open valid stream."); + conn_disconnect(conn); + } else { + _log_open_tag(conn, attrs); + + if (conn->stream_id) + xmpp_free(conn->ctx, conn->stream_id); + + id = _get_stream_attribute(attrs, "id"); + if (id) + conn->stream_id = xmpp_strdup(conn->ctx, id); + + if (!conn->stream_id) { + xmpp_error(conn->ctx, "conn", "Memory allocation failed."); + conn_disconnect(conn); + } + } + + /* call stream open handler */ + conn->open_handler(conn); } static void _handle_stream_end(char *name, - void * const userdata) + void * const userdata) { - xmpp_conn_t *conn = (xmpp_conn_t *)userdata; + xmpp_conn_t *conn = (xmpp_conn_t *)userdata; - /* stream is over */ - xmpp_debug(conn->ctx, "xmpp", "RECV: "); - conn_disconnect_clean(conn); + /* stream is over */ + xmpp_debug(conn->ctx, "xmpp", "RECV: "); + conn_disconnect_clean(conn); } static void _handle_stream_stanza(xmpp_stanza_t *stanza, - void * const userdata) + void * const userdata) { - xmpp_conn_t *conn = (xmpp_conn_t *)userdata; - char *buf; - size_t len; + xmpp_conn_t *conn = (xmpp_conn_t *)userdata; + char *buf; + size_t len; - if (xmpp_stanza_to_text(stanza, &buf, &len) == 0) { - xmpp_debug(conn->ctx, "xmpp", "RECV: %s", buf); - xmpp_free(conn->ctx, buf); - } + if (!xmpp_stanza_to_text(stanza, &buf, &len)) { + xmpp_debug(conn->ctx, "xmpp", "RECV: %s", buf); + xmpp_free(conn->ctx, buf); + } - handler_fire_stanza(conn, stanza); + handler_fire_stanza(conn, stanza); } diff --git a/src/ctx.c b/src/ctx.c index a2975dcb..48ab91da 100644 --- a/src/ctx.c +++ b/src/ctx.c @@ -1,9 +1,9 @@ /* ctx.c ** strophe XMPP client library -- run-time context implementation ** -** Copyright (C) 2005-2009 Collecta, Inc. +** Copyright (C) 2005-2009 Collecta, Inc. ** -** This software is provided AS-IS with no warranty, either express +** This software is provided AS-IS with no warranty, either express ** or implied. ** ** This software is distributed under license and may not be copied, @@ -39,7 +39,7 @@ * result in strange (and platform dependent) behavior. * * Specifically, the socket library on Win32 platforms must be initialized - * before use (although this is not the case on POSIX systems). The TLS + * before use (although this is not the case on POSIX systems). The TLS * subsystem must also seed the random number generator. */ @@ -48,9 +48,11 @@ #include #include -#include "strophe.h" +#include "couplet.h" #include "common.h" #include "util.h" +#include "thread.h" +#include "list.h" /** Initialize the Strophe library. * This function initializes subcomponents of the Strophe library and must @@ -58,10 +60,10 @@ * * @ingroup Init */ - void xmpp_initialize(void) +void xmpp_initialize(void) { - sock_initialize(); - tls_initialize(); + sock_initialize(); + tls_initialize(); } /** Shutdown the Strophe library. @@ -70,8 +72,8 @@ */ void xmpp_shutdown(void) { - tls_shutdown(); - sock_shutdown(); + tls_shutdown(); + sock_shutdown(); } /* version information */ @@ -100,36 +102,36 @@ void xmpp_shutdown(void) */ int xmpp_version_check(int major, int minor) { - return (major == LIBXMPP_VERSION_MAJOR) && - (minor >= LIBXMPP_VERSION_MINOR); + return (major == LIBXMPP_VERSION_MAJOR) && + (minor >= LIBXMPP_VERSION_MINOR); } /* We define the global default allocator, logger, and context here. */ -/* Wrap stdlib routines malloc, free, and realloc for default memory - * management. +/* Wrap stdlib routines malloc, free, and realloc for default memory + * management. */ static void *_malloc(const size_t size, void * const userdata) { - return malloc(size); + return malloc(size); } static void _free(void *p, void * const userdata) { - free(p); + free(p); } static void *_realloc(void *p, const size_t size, void * const userdata) { - return realloc(p, size); + return realloc(p, size); } /* default memory function map */ static xmpp_mem_t xmpp_default_mem = { - _malloc, /* use the thinly wrapped stdlib routines by default */ - _free, - _realloc, - NULL + _malloc, /* use the thinly wrapped stdlib routines by default */ + _free, + _realloc, + NULL }; /* log levels and names */ @@ -153,9 +155,9 @@ void xmpp_default_logger(void * const userdata, const char * const area, const char * const msg) { - xmpp_log_level_t filter_level = * (xmpp_log_level_t*)userdata; - if (level >= filter_level) - fprintf(stderr, "%s %s %s\n", area, _xmpp_log_level_name[level], msg); + xmpp_log_level_t filter_level = * (xmpp_log_level_t*)userdata; + if (level >= filter_level) + fprintf(stderr, "%s %s %s\n", area, _xmpp_log_level_name[level], msg); } static const xmpp_log_t _xmpp_default_loggers[] = { @@ -178,11 +180,11 @@ static const xmpp_log_t _xmpp_default_loggers[] = { */ xmpp_log_t *xmpp_get_default_logger(xmpp_log_level_t level) { - /* clamp to the known range */ - if (level > XMPP_LEVEL_ERROR) level = XMPP_LEVEL_ERROR; - if (level < XMPP_LEVEL_DEBUG) level = XMPP_LEVEL_DEBUG; + /* clamp to the known range */ + if (level > XMPP_LEVEL_ERROR) level = XMPP_LEVEL_ERROR; + if (level < XMPP_LEVEL_DEBUG) level = XMPP_LEVEL_DEBUG; - return (xmpp_log_t*)&_xmpp_default_loggers[level]; + return (xmpp_log_t*)&_xmpp_default_loggers[level]; } static xmpp_log_t xmpp_default_log = { NULL, NULL }; @@ -190,7 +192,7 @@ static xmpp_log_t xmpp_default_log = { NULL, NULL }; /* convenience functions for accessing the context */ /** Allocate memory in a Strophe context. - * All Strophe functions will use this to allocate memory. + * All Strophe functions will use this to allocate memory. * * @param ctx a Strophe context object * @param size the number of bytes to allocate @@ -199,7 +201,7 @@ static xmpp_log_t xmpp_default_log = { NULL, NULL }; */ void *xmpp_alloc(const xmpp_ctx_t * const ctx, const size_t size) { - return ctx->mem->alloc(size, ctx->mem->userdata); + return ctx->mem->alloc(size, ctx->mem->userdata); } /** Free memory in a Strophe context. @@ -210,7 +212,7 @@ void *xmpp_alloc(const xmpp_ctx_t * const ctx, const size_t size) */ void xmpp_free(const xmpp_ctx_t * const ctx, void *p) { - ctx->mem->free(p, ctx->mem->userdata); + ctx->mem->free(p, ctx->mem->userdata); } /** Reallocate memory in a Strophe context. @@ -225,14 +227,14 @@ void xmpp_free(const xmpp_ctx_t * const ctx, void *p) void *xmpp_realloc(const xmpp_ctx_t * const ctx, void *p, const size_t size) { - return ctx->mem->realloc(p, size, ctx->mem->userdata); + return ctx->mem->realloc(p, size, ctx->mem->userdata); } /** Write a log message to the logger. * Write a log message to the logger for the context for the specified * level and area. This function takes a printf-style format string and a * variable argument list (in va_list) format. This function is not meant - * to be called directly, but is used via xmpp_error, xmpp_warn, xmpp_info, + * to be called directly, but is used via xmpp_error, xmpp_warn, xmpp_info, * and xmpp_debug. * * @param ctx a Strophe context object @@ -247,39 +249,46 @@ void xmpp_log(const xmpp_ctx_t * const ctx, const char * const fmt, va_list ap) { - int oldret, ret; - char smbuf[1024]; - char *buf; - va_list copy; - - buf = smbuf; - va_copy(copy, ap); - ret = xmpp_vsnprintf(buf, 1023, fmt, ap); - if (ret > 1023) { - buf = (char *)xmpp_alloc(ctx, ret + 1); - if (!buf) { - buf = NULL; - xmpp_error(ctx, "log", "Failed allocating memory for log message."); - va_end(copy); - return; - } - oldret = ret; - ret = xmpp_vsnprintf(buf, ret + 1, fmt, copy); - if (ret > oldret) { - xmpp_error(ctx, "log", "Unexpected error"); - return; - } - } else { - va_end(copy); - } - - if (ctx->log->handler) - ctx->log->handler(ctx->log->userdata, level, area, buf); + int oldret, ret; + char smbuf[1024]; + char *bigbuf = NULL; + va_list ap_copy; + + if (!ctx || !ctx->log || !ctx->log->handler) + return; + + va_copy(ap_copy, ap); + ret = xmpp_vsnprintf(smbuf, 1023, fmt, ap_copy); + va_end(ap_copy); + if (ret > 1023) { + bigbuf = (char *)xmpp_alloc(ctx, ret + 1); + if (!bigbuf) { + bigbuf = NULL; + /** @TODO avoid recursive calls */ + xmpp_error(ctx, "log", "Failed allocating memory for log message."); + return; + } + oldret = ret; + va_copy(ap_copy, ap); + ret = xmpp_vsnprintf(bigbuf, ret + 1, fmt, ap_copy); + va_end(ap_copy); + + if (ret > oldret) { + /** @TODO avoid recursive calls */ + xmpp_error(ctx, "log", "Unexpected error"); + xmpp_free(ctx, bigbuf); + return; + } + + ctx->log->handler(ctx->log->userdata, level, area, bigbuf); + xmpp_free(ctx, bigbuf); + } else + ctx->log->handler(ctx->log->userdata, level, area, smbuf); } /** Write to the log at the ERROR level. * This is a convenience function for writing to the log at the - * ERROR level. It takes a printf-style format string followed by a + * ERROR level. It takes a printf-style format string followed by a * variable list of arguments for formatting. * * @param ctx a Strophe context object @@ -288,15 +297,15 @@ void xmpp_log(const xmpp_ctx_t * const ctx, * arguments to format */ void xmpp_error(const xmpp_ctx_t * const ctx, - const char * const area, - const char * const fmt, - ...) + const char * const area, + const char * const fmt, + ...) { - va_list ap; + va_list ap; - va_start(ap, fmt); - xmpp_log(ctx, XMPP_LEVEL_ERROR, area, fmt, ap); - va_end(ap); + va_start(ap, fmt); + xmpp_log(ctx, XMPP_LEVEL_ERROR, area, fmt, ap); + va_end(ap); } /** Write to the log at the WARN level. @@ -310,15 +319,15 @@ void xmpp_error(const xmpp_ctx_t * const ctx, * arguments to format */ void xmpp_warn(const xmpp_ctx_t * const ctx, - const char * const area, - const char * const fmt, - ...) + const char * const area, + const char * const fmt, + ...) { - va_list ap; + va_list ap; - va_start(ap, fmt); - xmpp_log(ctx, XMPP_LEVEL_WARN, area, fmt, ap); - va_end(ap); + va_start(ap, fmt); + xmpp_log(ctx, XMPP_LEVEL_WARN, area, fmt, ap); + va_end(ap); } /** Write to the log at the INFO level. @@ -332,15 +341,15 @@ void xmpp_warn(const xmpp_ctx_t * const ctx, * arguments to format */ void xmpp_info(const xmpp_ctx_t * const ctx, - const char * const area, - const char * const fmt, - ...) + const char * const area, + const char * const fmt, + ...) { - va_list ap; + va_list ap; - va_start(ap, fmt); - xmpp_log(ctx, XMPP_LEVEL_INFO, area, fmt, ap); - va_end(ap); + va_start(ap, fmt); + xmpp_log(ctx, XMPP_LEVEL_INFO, area, fmt, ap); + va_end(ap); } /** Write to the log at the DEBUG level. @@ -354,15 +363,15 @@ void xmpp_info(const xmpp_ctx_t * const ctx, * arguments to format */ void xmpp_debug(const xmpp_ctx_t * const ctx, - const char * const area, - const char * const fmt, - ...) + const char * const area, + const char * const fmt, + ...) { - va_list ap; + va_list ap; - va_start(ap, fmt); - xmpp_log(ctx, XMPP_LEVEL_DEBUG, area, fmt, ap); - va_end(ap); + va_start(ap, fmt); + xmpp_log(ctx, XMPP_LEVEL_DEBUG, area, fmt, ap); + va_end(ap); } /** Create and initialize a Strophe context object. @@ -379,32 +388,44 @@ void xmpp_debug(const xmpp_ctx_t * const ctx, * * @ingroup Context */ -xmpp_ctx_t *xmpp_ctx_new(const xmpp_mem_t * const mem, +xmpp_ctx_t *xmpp_ctx_new(const xmpp_mem_t * const mem, const xmpp_log_t * const log) { - xmpp_ctx_t *ctx = NULL; + xmpp_ctx_t *ctx = NULL; - if (mem == NULL) - ctx = xmpp_default_mem.alloc(sizeof(xmpp_ctx_t), NULL); - else - ctx = mem->alloc(sizeof(xmpp_ctx_t), mem->userdata); + if (mem == NULL) + ctx = xmpp_default_mem.alloc(sizeof(xmpp_ctx_t), NULL); + else + ctx = mem->alloc(sizeof(xmpp_ctx_t), mem->userdata); - if (ctx != NULL) { - if (mem != NULL) - ctx->mem = mem; - else - ctx->mem = &xmpp_default_mem; + if (!ctx) + return NULL; - if (log == NULL) - ctx->log = &xmpp_default_log; + if (!mem) + ctx->mem = &xmpp_default_mem; else - ctx->log = log; + ctx->mem = mem; - ctx->connlist = NULL; - ctx->loop_status = XMPP_LOOP_NOTSTARTED; - } + if (!log) + ctx->log = &xmpp_default_log; + else + ctx->log = log; - return ctx; + ctx->loop_status = XMPP_LOOP_NOTSTARTED; + ctx->connlist = list_init(ctx); + if (!ctx->connlist) + goto out_free_ctx; + ctx->send_queue_sem = xmpp_sem_create(ctx); + if (!ctx->send_queue_sem) + goto out_free_connlist; + + return ctx; + +out_free_connlist: + list_destroy(ctx->connlist); +out_free_ctx: + xmpp_free(ctx, ctx); + return NULL; } /** Free a Strophe context object that is no longer in use. @@ -415,7 +436,9 @@ xmpp_ctx_t *xmpp_ctx_new(const xmpp_mem_t * const mem, */ void xmpp_ctx_free(xmpp_ctx_t * const ctx) { - /* mem and log are owned by their suppliers */ - xmpp_free(ctx, ctx); /* pull the hole in after us */ -} + list_destroy(ctx->connlist); + xmpp_sem_destroy(ctx->send_queue_sem); + /* mem and log are owned by their suppliers */ + xmpp_free(ctx, ctx); /* pull the hole in after us */ +} diff --git a/src/event.c b/src/event.c index 1eaa643c..1c65b705 100644 --- a/src/event.c +++ b/src/event.c @@ -1,7 +1,7 @@ /* event.c ** strophe XMPP client library -- event loop and management ** -** Copyright (C) 2005-2009 Collecta, Inc. +** Copyright (C) 2005-2009 Collecta, Inc. ** ** This software is provided AS-IS with no warranty, either express ** or implied. @@ -17,15 +17,15 @@ */ /** @defgroup EventLoop Event loop - * These functions manage the Strophe event loop. - * + * These functions manage the Strophe event loop. + * * Simple tools can use xmpp_run() and xmpp_stop() to manage the life * cycle of the program. A common idiom is to set up a few initial * event handers, call xmpp_run(), and then respond and react to * events as they come in. At some point, one of the handlers will * call xmpp_stop() to quit the event loop which leads to the program * terminating. - * + * * More complex programs will have their own event loops, and should * ensure that xmpp_run_once() is called regularly from there. For * example, a GUI program will already include an event loop to @@ -47,9 +47,11 @@ #define ECONNABORTED WSAECONNABORTED #endif -#include +#include "couplet.h" #include "common.h" #include "parser.h" +#include "thread.h" +#include "list.h" #ifndef DEFAULT_TIMEOUT /** @def DEFAULT_TIMEOUT @@ -59,9 +61,137 @@ #define DEFAULT_TIMEOUT 1 #endif +/** Run send loop once. + * This function will run send any data that has been queued by xmpp_send + * and related functions. + * + * @param ctx a Strophe context object + * + * @ingroup EventLoop + */ +void xmpp_run_send_queue_once(xmpp_ctx_t *ctx) +{ + list_t *connitem; + list_t *sqitem; + xmpp_conn_t *conn; + xmpp_send_queue_t *sq; + int sent; + int ret; + int towrite; + + /* send queued data */ + connitem = list_get_first(ctx->connlist); + while (connitem) { + conn = (xmpp_conn_t *)connitem->data; + if (conn->state != XMPP_STATE_CONNECTED) + goto loop_next; + + /* if we're running tls, there may be some remaining data waiting to + * be sent, so push that out */ + if (conn->tls) { + ret = tls_clear_pending_write(conn->tls); + + if (ret < 0 && !tls_is_recoverable(tls_error(conn->tls))) { + /* an error occured */ + xmpp_debug(ctx, "xmpp", "Send error occured, disconnecting."); + conn->error = ECONNABORTED; + conn_disconnect(conn); + } + } + + /* write all data from the send queue to the socket */ + sqitem = list_shift(conn->send_queue); + while (sqitem) { + sent = 1; + sq = (xmpp_send_queue_t *)sqitem->data; + towrite = sq->len - sq->written; + + if (conn->tls) { + ret = tls_write(conn->tls, &sq->data[sq->written], towrite); + + if (ret < 0 && !tls_is_recoverable(tls_error(conn->tls))) { + /* an error occured */ + conn->error = tls_error(conn->tls); + sent = 0; + } else if (ret < towrite) { + /* not all data could be sent now */ + if (ret >= 0) + sq->written += ret; + sent = 0; + } + + } else { + ret = sock_write(conn->sock, &sq->data[sq->written], towrite); + + if (ret < 0 && !sock_is_recoverable(sock_error())) { + /* an error occured */ + conn->error = sock_error(); + sent = 0; + } else if (ret < towrite) { + /* not all data could be sent now */ + if (ret >= 0) + sq->written += ret; + sent = 0; + } + } + + if (!sent) { + /* insert sq to the head of send queue */ + list_insert(conn->send_queue, sqitem); + break; + } + + /* all data for this queue item written, delete and move on */ + xmpp_free(ctx, sq->data); + xmpp_free(ctx, sq); + xmpp_free(ctx, sqitem); + sqitem = list_shift(conn->send_queue); + } + + /* tear down connection on error */ + if (conn->error) { + /* FIXME: need to tear down send queues and random other things + * maybe this should be abstracted */ + xmpp_debug(ctx, "xmpp", "Send error occured, disconnecting."); + conn->error = ECONNABORTED; + conn_disconnect(conn); + } + +loop_next: + connitem = list_get_next(ctx->connlist, connitem); + } +} + +/** Start the sending loop. + * This function is start routine for a separated thread. It continuously + * calls xmpp_run_send_queue_once. + * + * @param data is a pointer to a Strophe context object + * + * @return always NULL + * + * @ingroup EventLoop + */ +void *xmpp_send_queue_thread(void *data) +{ + xmpp_ctx_t *ctx = (xmpp_ctx_t *)data; + + if (!ctx) + return NULL; + + /** @TODO make condition for break */ + /* infinite loop */ + while (1) { + /* lock thread if nothing to be sent */ + xmpp_sem_wait(ctx->send_queue_sem); + xmpp_run_send_queue_once(ctx); + } + + return NULL; +} + /** Run the event loop once. - * This function will run send any data that has been queued by - * xmpp_send and related functions and run through the Strophe even + * This function will run through the Strophe event * loop a single time, and will not wait more than timeout * milliseconds for events. This is provided to support integration * with event loops outside the library, and if used, should be @@ -74,249 +204,168 @@ */ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout) { - xmpp_connlist_t *connitem; - xmpp_conn_t *conn; - fd_set rfds, wfds; - sock_t max = 0; - int ret; - struct timeval tv; - xmpp_send_queue_t *sq, *tsq; - int towrite; - char buf[4096]; - uint64_t next; - long usec; - int tls_read_bytes = 0; - - if (ctx->loop_status == XMPP_LOOP_QUIT) return; - ctx->loop_status = XMPP_LOOP_RUNNING; - - /* send queued data */ - connitem = ctx->connlist; - while (connitem) { - conn = connitem->conn; - if (conn->state != XMPP_STATE_CONNECTED) { - connitem = connitem->next; - continue; - } - - /* if we're running tls, there may be some remaining data waiting to - * be sent, so push that out */ - if (conn->tls) { - ret = tls_clear_pending_write(conn->tls); - - if (ret < 0 && !tls_is_recoverable(tls_error(conn->tls))) { - /* an error occured */ - xmpp_debug(ctx, "xmpp", "Send error occured, disconnecting."); - conn->error = ECONNABORTED; - conn_disconnect(conn); - } + list_t *connitem; + xmpp_conn_t *conn; + fd_set rfds, wfds; + sock_t max = 0; + int ret; + struct timeval tv; + char buf[XMPP_RCV_BUF]; + uint64_t next; + long usec; + int tls_read_bytes = 0; + + if (ctx->loop_status == XMPP_LOOP_QUIT) + return; + ctx->loop_status = XMPP_LOOP_RUNNING; + + /* reset parsers if needed */ + connitem = list_get_first(ctx->connlist); + while (connitem) { + conn = (xmpp_conn_t *)connitem->data; + if (conn->reset_parser) + conn_parser_reset(conn); + connitem = list_get_next(ctx->connlist, connitem); } - /* write all data from the send queue to the socket */ - sq = conn->send_queue_head; - while (sq) { - towrite = sq->len - sq->written; - - if (conn->tls) { - ret = tls_write(conn->tls, &sq->data[sq->written], towrite); - - if (ret < 0 && !tls_is_recoverable(tls_error(conn->tls))) { - /* an error occured */ - conn->error = tls_error(conn->tls); - break; - } else if (ret < towrite) { - /* not all data could be sent now */ - if (ret >= 0) sq->written += ret; - break; + /* fire any ready timed handlers, then + * make sure we don't wait past the time when timed handlers need + * to be called */ + next = handler_fire_timed(ctx); + + usec = ((next < timeout) ? next : timeout) * 1000; + tv.tv_sec = usec / 1000000; + tv.tv_usec = usec % 1000000; + + FD_ZERO(&rfds); + FD_ZERO(&wfds); + + /* find events to watch */ + connitem = list_get_first(ctx->connlist); + while (connitem) { + conn = (xmpp_conn_t *)connitem->data; + + switch (conn->state) { + case XMPP_STATE_CONNECTING: + /* connect has been called and we're waiting for it to complete */ + /* connection will give us write or error events */ + + /* make sure the timeout hasn't expired */ + if (time_elapsed(conn->timeout_stamp, time_stamp()) <= + conn->connect_timeout) + FD_SET(conn->sock, &wfds); + else { + conn->error = ETIMEDOUT; + xmpp_info(ctx, "xmpp", "Connection attempt timed out."); + conn_disconnect(conn); + } + break; + case XMPP_STATE_CONNECTED: + FD_SET(conn->sock, &rfds); + break; + case XMPP_STATE_DISCONNECTED: + /* do nothing */ + default: + break; } - } else { - ret = sock_write(conn->sock, &sq->data[sq->written], towrite); - - if (ret < 0 && !sock_is_recoverable(sock_error())) { - /* an error occured */ - conn->error = sock_error(); - break; - } else if (ret < towrite) { - /* not all data could be sent now */ - if (ret >= 0) sq->written += ret; - break; - } - } - - /* all data for this queue item written, delete and move on */ - xmpp_free(ctx, sq->data); - tsq = sq; - sq = sq->next; - xmpp_free(ctx, tsq); - - /* pop the top item */ - conn->send_queue_head = sq; - /* if we've sent everything update the tail */ - if (!sq) conn->send_queue_tail = NULL; - } + /* Check if there is something in the SSL buffer. */ + if (conn->tls) + tls_read_bytes += tls_pending(conn->tls); - /* tear down connection on error */ - if (conn->error) { - /* FIXME: need to tear down send queues and random other things - * maybe this should be abstracted */ - xmpp_debug(ctx, "xmpp", "Send error occured, disconnecting."); - conn->error = ECONNABORTED; - conn_disconnect(conn); - } - - connitem = connitem->next; - } - - /* reset parsers if needed */ - for (connitem = ctx->connlist; connitem; connitem = connitem->next) { - if (connitem->conn->reset_parser) - conn_parser_reset(connitem->conn); - } - - - /* fire any ready timed handlers, then - make sure we don't wait past the time when timed handlers need - to be called */ - next = handler_fire_timed(ctx); - - usec = ((next < timeout) ? next : timeout) * 1000; - tv.tv_sec = usec / 1000000; - tv.tv_usec = usec % 1000000; - - FD_ZERO(&rfds); - FD_ZERO(&wfds); - - /* find events to watch */ - connitem = ctx->connlist; - while (connitem) { - conn = connitem->conn; - - switch (conn->state) { - case XMPP_STATE_CONNECTING: - /* connect has been called and we're waiting for it to complete */ - /* connection will give us write or error events */ - - /* make sure the timeout hasn't expired */ - if (time_elapsed(conn->timeout_stamp, time_stamp()) <= - conn->connect_timeout) - FD_SET(conn->sock, &wfds); - else { - conn->error = ETIMEDOUT; - xmpp_info(ctx, "xmpp", "Connection attempt timed out."); - conn_disconnect(conn); - } - break; - case XMPP_STATE_CONNECTED: - FD_SET(conn->sock, &rfds); - break; - case XMPP_STATE_DISCONNECTED: - /* do nothing */ - default: - break; - } - - /* Check if there is something in the SSL buffer. */ - if (conn->tls) { - tls_read_bytes += tls_pending(conn->tls); + if (conn->sock > max) + max = conn->sock; + + connitem = list_get_next(ctx->connlist, connitem); } - - if (conn->sock > max) max = conn->sock; - - connitem = connitem->next; - } - - /* check for events */ - ret = select(max + 1, &rfds, &wfds, NULL, &tv); - - /* select errored */ - if (ret < 0) { - if (!sock_is_recoverable(sock_error())) - xmpp_error(ctx, "xmpp", "event watcher internal error %d", - sock_error()); - return; - } - - /* no events happened */ - if (ret == 0 && tls_read_bytes == 0) return; - - /* process events */ - connitem = ctx->connlist; - while (connitem) { - conn = connitem->conn; - - switch (conn->state) { - case XMPP_STATE_CONNECTING: - if (FD_ISSET(conn->sock, &wfds)) { - /* connection complete */ - - /* check for error */ - if (sock_connect_error(conn->sock) != 0) { - /* connection failed */ - xmpp_debug(ctx, "xmpp", "connection failed"); - conn_disconnect(conn); - break; - } - conn->state = XMPP_STATE_CONNECTED; - xmpp_debug(ctx, "xmpp", "connection successful"); + /* check for events */ + ret = select(max + 1, &rfds, &wfds, NULL, &tv); - - /* send stream init */ - conn_open_stream(conn); - } + /* select errored */ + if (ret < 0) { + if (!sock_is_recoverable(sock_error())) + xmpp_error(ctx, "xmpp", "event watcher internal error %d", + sock_error()); + return; + } - break; - case XMPP_STATE_CONNECTED: - if (FD_ISSET(conn->sock, &rfds) || (conn->tls && tls_pending(conn->tls))) { - if (conn->tls) { - ret = tls_read(conn->tls, buf, 4096); - } else { - ret = sock_read(conn->sock, buf, 4096); - } + /* no events happened */ + if (ret == 0 && tls_read_bytes == 0) + return; + + /* process events */ + connitem = list_get_first(ctx->connlist); + while (connitem) { + conn = (xmpp_conn_t *)connitem->data; + + switch (conn->state) { + case XMPP_STATE_CONNECTING: + if (FD_ISSET(conn->sock, &wfds)) { + /* connection complete */ + + /* check for error */ + if (sock_connect_error(conn->sock) != 0) { + /* connection failed */ + xmpp_debug(ctx, "xmpp", "connection failed"); + conn_disconnect(conn); + break; + } + + conn->state = XMPP_STATE_CONNECTED; + xmpp_debug(ctx, "xmpp", "connection successful"); + + /* send stream init */ + conn_open_stream(conn); + } - if (ret > 0) { - ret = parser_feed(conn->parser, buf, ret); - if (!ret) { - /* parse error, we need to shut down */ - /* FIXME */ - xmpp_debug(ctx, "xmpp", "parse error, disconnecting"); - conn_disconnect(conn); - } - } else { - if (conn->tls) { - if (!tls_is_recoverable(tls_error(conn->tls))) - { - xmpp_debug(ctx, "xmpp", "Unrecoverable TLS error, %d.", tls_error(conn->tls)); - conn->error = tls_error(conn->tls); - conn_disconnect(conn); + break; + case XMPP_STATE_CONNECTED: + if (FD_ISSET(conn->sock, &rfds) || (conn->tls && tls_pending(conn->tls))) { + if (conn->tls) + ret = tls_read(conn->tls, buf, XMPP_RCV_BUF); + else + ret = sock_read(conn->sock, buf, XMPP_RCV_BUF); + + if (ret > 0) { + ret = parser_feed(conn->parser, buf, ret); + if (!ret) { + /* parse error, we need to shut down */ + /* FIXME */ + xmpp_debug(ctx, "xmpp", "parse error, disconnecting"); + conn_disconnect(conn); + } + } else if (conn->tls) { + if (!tls_is_recoverable(tls_error(conn->tls))) { + xmpp_debug(ctx, "xmpp", "Unrecoverable TLS error, %d.", tls_error(conn->tls)); + conn->error = tls_error(conn->tls); + conn_disconnect(conn); + } + } else { + /* return of 0 means socket closed by server */ + xmpp_debug(ctx, "xmpp", "Socket closed by remote host."); + conn->error = ECONNRESET; + conn_disconnect(conn); + } } - } else { - /* return of 0 means socket closed by server */ - xmpp_debug(ctx, "xmpp", "Socket closed by remote host."); - conn->error = ECONNRESET; - conn_disconnect(conn); - } + + break; + case XMPP_STATE_DISCONNECTED: + /* do nothing */ + default: + break; } - } - break; - case XMPP_STATE_DISCONNECTED: - /* do nothing */ - default: - break; + connitem = list_get_next(ctx->connlist, connitem); } - connitem = connitem->next; - } - - /* fire any ready handlers */ - handler_fire_timed(ctx); + /* fire any ready handlers */ + handler_fire_timed(ctx); } /** Start the event loop. - * This function continuously calls xmpp_run_once and does not return - * until xmpp_stop has been called. + * This function starts sending loop thread and continuously calls + * xmpp_run_once. Loop does not stop until xmpp_stop has been called. * * @param ctx a Strophe context object * @@ -324,14 +373,21 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout) */ void xmpp_run(xmpp_ctx_t *ctx) { - if (ctx->loop_status != XMPP_LOOP_NOTSTARTED) return; + thread_t *thread; + + if (ctx->loop_status != XMPP_LOOP_NOTSTARTED) + return; + + thread = thread_create(ctx, &xmpp_send_queue_thread, ctx); + /** @TODO check return value */ + + ctx->loop_status = XMPP_LOOP_RUNNING; + while (ctx->loop_status == XMPP_LOOP_RUNNING) + xmpp_run_once(ctx, DEFAULT_TIMEOUT); - ctx->loop_status = XMPP_LOOP_RUNNING; - while (ctx->loop_status == XMPP_LOOP_RUNNING) { - xmpp_run_once(ctx, DEFAULT_TIMEOUT); - } + /** @TODO stop sending thread */ - xmpp_debug(ctx, "event", "Event loop completed."); + xmpp_debug(ctx, "event", "Event loop completed."); } /** Stop the event loop. @@ -344,8 +400,8 @@ void xmpp_run(xmpp_ctx_t *ctx) */ void xmpp_stop(xmpp_ctx_t *ctx) { - xmpp_debug(ctx, "event", "Stopping event loop."); + xmpp_debug(ctx, "event", "Stopping event loop."); - if (ctx->loop_status == XMPP_LOOP_RUNNING) - ctx->loop_status = XMPP_LOOP_QUIT; + if (ctx->loop_status == XMPP_LOOP_RUNNING) + ctx->loop_status = XMPP_LOOP_QUIT; } diff --git a/src/handler.c b/src/handler.c index d382ca89..43ef843a 100644 --- a/src/handler.c +++ b/src/handler.c @@ -1,7 +1,7 @@ /* handler.c ** strophe XMPP client library -- event handler management ** -** Copyright (C) 2005-2009 Collecta, Inc. +** Copyright (C) 2005-2009 Collecta, Inc. ** ** This software is provided AS-IS with no warranty, either express ** or implied. @@ -29,8 +29,9 @@ #include "ostypes.h" #endif -#include "strophe.h" +#include "couplet.h" #include "common.h" +#include "list.h" /** Fire off all stanza handlers that match. * This function is called internally by the event loop whenever stanzas @@ -42,91 +43,82 @@ void handler_fire_stanza(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza) { - xmpp_handlist_t *item, *prev; - char *id, *ns, *name, *type; - - /* call id handlers */ - id = xmpp_stanza_get_id(stanza); - if (id) { - prev = NULL; - item = (xmpp_handlist_t *)hash_get(conn->id_handlers, id); - while (item) { - xmpp_handlist_t *next = item->next; - - if (item->user_handler && !conn->authenticated) { - item = next; - continue; - } - - if (!((xmpp_handler)(item->handler))(conn, stanza, item->userdata)) { - /* handler is one-shot, so delete it */ - if (prev) - prev->next = next; - else { - hash_drop(conn->id_handlers, id); - hash_add(conn->id_handlers, id, next); + list_t *hlistitem, *tail; + xmpp_handler_t *item; + xmpp_handlist_t *hitem, *prev; + char *id, *ns, *name, *type; + xmpp_ctx_t *ctx = conn->ctx; + + /* call id handlers */ + id = xmpp_stanza_get_id(stanza); + if (id) { + prev = NULL; + hitem = (xmpp_handlist_t *)hash_get(conn->id_handlers, id); + while (hitem) { + xmpp_handlist_t *next = hitem->next; + + if (hitem->user_handler && !conn->authenticated) { + hitem = next; + continue; + } + + if (!((xmpp_handler)(hitem->handler))(conn, stanza, hitem->userdata)) { + /* handler is one-shot, so delete it */ + if (prev) + prev->next = next; + else { + hash_drop(conn->id_handlers, id); + hash_add(conn->id_handlers, id, next); + } + xmpp_free(ctx, hitem->id); + xmpp_free(ctx, hitem); + hitem = NULL; + } + if (hitem) + prev = hitem; + hitem = next; } - xmpp_free(conn->ctx, item->id); - xmpp_free(conn->ctx, item); - item = NULL; - } - if (item) - prev = item; - item = next; } - } - - /* call handlers */ - ns = xmpp_stanza_get_ns(stanza); - name = xmpp_stanza_get_name(stanza); - type = xmpp_stanza_get_type(stanza); - - /* enable all added handlers */ - for (item = conn->handlers; item; item = item->next) - item->enabled = 1; - prev = NULL; - item = conn->handlers; - while (item) { - /* skip newly added handlers */ - if (!item->enabled) { - prev = item; - item = item->next; - continue; - } + /* call handlers */ + ns = xmpp_stanza_get_ns(stanza); + name = xmpp_stanza_get_name(stanza); + type = xmpp_stanza_get_type(stanza); + + tail = list_get_last(conn->handlers); + while ((hlistitem = list_shift(conn->handlers))) { + item = (xmpp_handler_t *)hlistitem->data; + + /* don't call user handlers until authentication succeeds */ + if (item->user_handler && !conn->authenticated) + goto loop_handlers_continue; + + if ((!item->ns || (ns && strcmp(ns, item->ns) == 0) || + xmpp_stanza_get_child_by_ns(stanza, item->ns)) && + (!item->name || (name && strcmp(name, item->name) == 0)) && + (!item->type || (type && strcmp(type, item->type) == 0))) + if (!((xmpp_handler)(item->handler))(conn, stanza, item->userdata)) { + /* handler is one-shot, so delete it */ + if (item->ns) + xmpp_free(ctx, item->ns); + if (item->name) + xmpp_free(ctx, item->name); + if (item->type) + xmpp_free(ctx, item->type); + xmpp_free(ctx, item); + xmpp_free(ctx, hlistitem); + /* don't put hlistitem back to list */ + goto loop_handlers_continue; + } - /* don't call user handlers until authentication succeeds */ - if (item->user_handler && !conn->authenticated) { - prev = item; - item = item->next; - continue; - } + /* handler hasn't been deleted, put it back to list */ + list_push(conn->handlers, hlistitem); - if ((!item->ns || (ns && strcmp(ns, item->ns) == 0) || - xmpp_stanza_get_child_by_ns(stanza, item->ns)) && - (!item->name || (name && strcmp(name, item->name) == 0)) && - (!item->type || (type && strcmp(type, item->type) == 0))) - if (!((xmpp_handler)(item->handler))(conn, stanza, item->userdata)) { - /* handler is one-shot, so delete it */ - if (prev) - prev->next = item->next; - else - conn->handlers = item->next; - if (item->ns) xmpp_free(conn->ctx, item->ns); - if (item->name) xmpp_free(conn->ctx, item->name); - if (item->type) xmpp_free(conn->ctx, item->type); - xmpp_free(conn->ctx, item); - item = NULL; - } - - if (item) { - prev = item; - item = item->next; - } else if (prev) - item = prev->next; - else - item = conn->handlers; - } +loop_handlers_continue: + /* skip newly added and watched handlers */ + if (hlistitem == tail) + break; + } } /** Fire off all timed handlers that are ready. @@ -138,61 +130,57 @@ void handler_fire_stanza(xmpp_conn_t * const conn, */ uint64_t handler_fire_timed(xmpp_ctx_t * const ctx) { - xmpp_connlist_t *connitem; - xmpp_handlist_t *handitem, *temp; - int ret, fired; - uint64_t elapsed, min; - - min = (uint64_t)(-1); - - connitem = ctx->connlist; - while (connitem) { - if (connitem->conn->state != XMPP_STATE_CONNECTED) { - connitem = connitem->next; - continue; - } - - /* enable all handlers that were added */ - for (handitem = connitem->conn->timed_handlers; handitem; - handitem = handitem->next) - handitem->enabled = 1; - - handitem = connitem->conn->timed_handlers; - while (handitem) { - /* skip newly added handlers */ - if (!handitem->enabled) { - handitem = handitem->next; - continue; - } - - /* only fire user handlers after authentication */ - if (handitem->user_handler && !connitem->conn->authenticated) { - handitem = handitem->next; - continue; - } - - fired = 0; - elapsed = time_elapsed(handitem->last_stamp, time_stamp()); - if (elapsed >= handitem->period) { - /* fire! */ - fired = 1; - handitem->last_stamp = time_stamp(); - ret = ((xmpp_timed_handler)handitem->handler)(connitem->conn, handitem->userdata); - } else if (min > (handitem->period - elapsed)) - min = handitem->period - elapsed; - - temp = handitem; - handitem = handitem->next; - - /* delete handler if it returned false */ - if (fired && !ret) - xmpp_timed_handler_delete(connitem->conn, temp->handler); - } + list_t *connitem; + list_t *hlistitem, *tail; + xmpp_handler_t *handitem; + xmpp_conn_t *conn; + int ret, fired; + uint64_t elapsed, min; + + min = (uint64_t)(-1); + + connitem = list_get_first(ctx->connlist); + while (connitem) { + conn = (xmpp_conn_t *)connitem->data; + if (conn->state != XMPP_STATE_CONNECTED) + goto loop_conn_continue; + + tail = list_get_last(conn->timed_handlers); + while ((hlistitem = list_shift(conn->timed_handlers))) { + fired = 0; + handitem = (xmpp_handler_t *)hlistitem->data; + + /* only fire user handlers after authentication */ + if (handitem->user_handler && !conn->authenticated) + goto loop_handlers_continue; + + elapsed = time_elapsed(handitem->last_stamp, time_stamp()); + if (elapsed >= handitem->period) { + /* fire! */ + fired = 1; + handitem->last_stamp = time_stamp(); + ret = ((xmpp_timed_handler)handitem->handler)(conn, handitem->userdata); + } else if (min > (handitem->period - elapsed)) + min = handitem->period - elapsed; + +loop_handlers_continue: + /* delete handler if it returned false */ + if (fired && !ret) { + xmpp_free(ctx, handitem); + xmpp_free(ctx, hlistitem); + } else + list_push(conn->timed_handlers, hlistitem); + + /* skip newly added and watched handlers */ + if (hlistitem == tail) + break; + } - connitem = connitem->next; - } +loop_conn_continue: + connitem = list_get_next(ctx->connlist, connitem); + } - return min; + return min; } /** Reset all timed handlers. @@ -203,54 +191,57 @@ uint64_t handler_fire_timed(xmpp_ctx_t * const ctx) */ void handler_reset_timed(xmpp_conn_t *conn, int user_only) { - xmpp_handlist_t *handitem; + list_t *hlistitem; + xmpp_handler_t *handitem; - handitem = conn->timed_handlers; - while (handitem) { - if ((user_only && handitem->user_handler) || !user_only) - handitem->last_stamp = time_stamp(); - - handitem = handitem->next; - } + hlistitem = list_get_first(conn->timed_handlers); + while (hlistitem) { + handitem = (xmpp_handler_t *)hlistitem->data; + if ((user_only && handitem->user_handler) || !user_only) + handitem->last_stamp = time_stamp(); + + hlistitem = list_get_next(conn->timed_handlers, hlistitem); + } } static void _timed_handler_add(xmpp_conn_t * const conn, xmpp_timed_handler handler, const unsigned long period, - void * const userdata, + void * const userdata, const int user_handler) { - xmpp_handlist_t *item, *tail; - - /* check if handler is already in the list */ - for (item = conn->timed_handlers; item; item = item->next) { - if (item->handler == (void *)handler) - break; - } - if (item) return; - - /* build new item */ - item = xmpp_alloc(conn->ctx, sizeof(xmpp_handlist_t)); - if (!item) return; - - item->user_handler = user_handler; - item->handler = (void *)handler; - item->userdata = userdata; - item->enabled = 0; - item->next = NULL; - - item->period = period; - item->last_stamp = time_stamp(); - - /* append item to list */ - if (!conn->timed_handlers) - conn->timed_handlers = item; - else { - tail = conn->timed_handlers; - while (tail->next) - tail = tail->next; - tail->next = item; - } + list_t *hlistitem; + xmpp_handler_t *item; + + /* check if handler is already in the list */ + hlistitem = list_get_first(conn->timed_handlers); + while (hlistitem) { + item = (xmpp_handler_t *)hlistitem->data; + if (item->handler == (void *)handler) + break; + hlistitem = list_get_next(conn->timed_handlers, hlistitem); + } + if (hlistitem) + return; + + /* build new item */ + item = (xmpp_handler_t *)xmpp_alloc(conn->ctx, sizeof(xmpp_handler_t)); + if (!item) + return; + + item->user_handler = user_handler; + item->handler = (void *)handler; + item->userdata = userdata; + item->period = period; + item->last_stamp = time_stamp(); + + hlistitem = list_init_item(conn->ctx); + if (!hlistitem) { + xmpp_free(conn->ctx, item); + return; + } + hlistitem->data = (void *)item; + list_push(conn->timed_handlers, hlistitem); } /** Delete a timed handler. @@ -263,27 +254,25 @@ static void _timed_handler_add(xmpp_conn_t * const conn, void xmpp_timed_handler_delete(xmpp_conn_t * const conn, xmpp_timed_handler handler) { - xmpp_handlist_t *item, *prev; - - if (!conn->timed_handlers) return; + list_t *cur, *prev; + xmpp_handler_t *item; - prev = NULL; - item = conn->timed_handlers; - while (item) { - if (item->handler == (void *)handler) - break; - prev = item; - item = item->next; - } - - if (item) { - if (prev) - prev->next = item->next; - else - conn->timed_handlers = item->next; - - xmpp_free(conn->ctx, item); - } + prev = NULL; + cur = list_get_first(conn->timed_handlers); + while (cur) { + item = (xmpp_handler_t *)cur->data; + if (item->handler == (void *)handler) { + if (!prev) + cur = list_shift(conn->timed_handlers); + else + cur = list_pop_next(conn->timed_handlers, prev); + xmpp_free(conn->ctx, item); + xmpp_free(conn->ctx, cur); + break; + } + prev = cur; + cur = list_get_next(conn->timed_handlers, cur); + } } static void _id_handler_add(xmpp_conn_t * const conn, @@ -323,7 +312,7 @@ static void _id_handler_add(xmpp_conn_t * const conn, if (!tail) hash_add(conn->id_handlers, id, item); else { - while (tail->next) + while (tail->next) tail = tail->next; tail->next = item; } @@ -375,61 +364,70 @@ static void _handler_add(xmpp_conn_t * const conn, const char * const type, void * const userdata, int user_handler) { - xmpp_handlist_t *item, *tail; - - /* check if handler already in list */ - for (item = conn->handlers; item; item = item->next) { - if (item->handler == (void *)handler) - break; - } - if (item) return; + list_t *hlistitem; + xmpp_handler_t *item; + xmpp_ctx_t *ctx = conn->ctx; + + /* check if handler is already in the list */ + hlistitem = list_get_first(conn->handlers); + while (hlistitem) { + item = (xmpp_handler_t *)hlistitem->data; + if (item->handler == (void *)handler) + break; + hlistitem = list_get_next(conn->handlers, hlistitem); + } + if (hlistitem) + return; - /* build new item */ - item = (xmpp_handlist_t *)xmpp_alloc(conn->ctx, sizeof(xmpp_handlist_t)); - if (!item) return; + item = (xmpp_handler_t *)xmpp_alloc(ctx, sizeof(xmpp_handler_t)); + if (!item) + return; + + item->user_handler = user_handler; + item->handler = (void *)handler; + item->userdata = userdata; + + if (ns) { + item->ns = xmpp_strdup(ctx, ns); + if (!item->ns) + goto out_free_item; + } else + item->ns = NULL; + + if (name) { + item->name = xmpp_strdup(ctx, name); + if (!item->name) + goto out_free_ns; + } else + item->name = NULL; + + if (type) { + item->type = xmpp_strdup(ctx, type); + if (!item->type) + goto out_free_name; + } else + item->type = NULL; + + hlistitem = list_init_item(ctx); + if (!hlistitem) + goto out_free_type; + + hlistitem->data = (void *)item; + list_push(conn->handlers, hlistitem); - item->user_handler = user_handler; - item->handler = (void *)handler; - item->userdata = userdata; - item->enabled = 0; - item->next = NULL; - - if (ns) { - item->ns = xmpp_strdup(conn->ctx, ns); - if (!item->ns) { - xmpp_free(conn->ctx, item); - return; - } - } else - item->ns = NULL; - if (name) { - item->name = xmpp_strdup(conn->ctx, name); - if (!item->name) { - if (item->ns) xmpp_free(conn->ctx, item->ns); - xmpp_free(conn->ctx, item); - return; - } - } else - item->name = NULL; - if (type) { - item->type = xmpp_strdup(conn->ctx, type); - if (!item->type) { - if (item->ns) xmpp_free(conn->ctx, item->ns); - if (item->name) xmpp_free(conn->ctx, item->name); - xmpp_free(conn->ctx, item); - } - } else - item->type = NULL; + return; - /* append to list */ - if (!conn->handlers) - conn->handlers = item; - else { - tail = conn->handlers; - while (tail->next) - tail = tail->next; - tail->next = item; - } +out_free_type: + if (item->type) + xmpp_free(ctx, item->type); +out_free_name: + if (item->name) + xmpp_free(ctx, item->name); +out_free_ns: + if (item->ns) + xmpp_free(ctx, item->ns); +out_free_item: + xmpp_free(ctx, item); } /** Delete a stanza handler. @@ -442,31 +440,32 @@ static void _handler_add(xmpp_conn_t * const conn, void xmpp_handler_delete(xmpp_conn_t * const conn, xmpp_handler handler) { - xmpp_handlist_t *prev, *item; + list_t *cur, *prev; + xmpp_handler_t *item; - if (!conn->handlers) return; - - prev = NULL; - item = conn->handlers; - while (item) { - if (item->handler == (void *)handler) - break; - - prev = item; - item = item->next; - } - - if (item) { - if (prev) - prev->next = item->next; - else - conn->handlers = item->next; - - if (item->ns) xmpp_free(conn->ctx, item->ns); - if (item->name) xmpp_free(conn->ctx, item->name); - if (item->type) xmpp_free(conn->ctx, item->type); - xmpp_free(conn->ctx, item); - } + prev = NULL; + cur = list_get_first(conn->handlers); + while (cur) { + item = (xmpp_handler_t *)cur->data; + if (item->handler == (void *)handler) { + if (!prev) + cur = list_shift(conn->handlers); + else + cur = list_pop_next(conn->handlers, prev); + + if (item->ns) + xmpp_free(conn->ctx, item->ns); + if (item->name) + xmpp_free(conn->ctx, item->name); + if (item->type) + xmpp_free(conn->ctx, item->type); + xmpp_free(conn->ctx, item); + xmpp_free(conn->ctx, cur); + break; + } + prev = cur; + cur = list_get_next(conn->handlers, cur); + } } /** Add a timed handler. @@ -474,7 +473,7 @@ void xmpp_handler_delete(xmpp_conn_t * const conn, * and continue firing regularly after that. Strophe will try its best * to fire handlers as close to the period times as it can, but accuracy * will vary depending on the resolution of the event loop. - * + * * If the handler function returns true, it will be kept, and if it * returns false, it will be deleted from the list of handlers. * @@ -490,7 +489,7 @@ void xmpp_timed_handler_add(xmpp_conn_t * const conn, const unsigned long period, void * const userdata) { - _timed_handler_add(conn, handler, period, userdata, 1); + _timed_handler_add(conn, handler, period, userdata, 1); } /** Add a timed system handler. @@ -507,7 +506,7 @@ void handler_add_timed(xmpp_conn_t * const conn, const unsigned long period, void * const userdata) { - _timed_handler_add(conn, handler, period, userdata, 0); + _timed_handler_add(conn, handler, period, userdata, 0); } /** Add an id based stanza handler. @@ -531,7 +530,7 @@ void xmpp_id_handler_add(xmpp_conn_t * const conn, const char * const id, void * const userdata) { - _id_handler_add(conn, handler, id, userdata, 1); + _id_handler_add(conn, handler, id, userdata, 1); } /** Add an id based system stanza handler. @@ -548,7 +547,7 @@ void handler_add_id(xmpp_conn_t * const conn, const char * const id, void * const userdata) { - _id_handler_add(conn, handler, id, userdata, 0); + _id_handler_add(conn, handler, id, userdata, 0); } /** Add a stanza handler. @@ -580,7 +579,7 @@ void xmpp_handler_add(xmpp_conn_t * const conn, const char * const type, void * const userdata) { - _handler_add(conn, handler, ns, name, type, userdata, 1); + _handler_add(conn, handler, ns, name, type, userdata, 1); } /** Add a system stanza handler. @@ -601,5 +600,5 @@ void handler_add(xmpp_conn_t * const conn, const char * const type, void * const userdata) { - _handler_add(conn, handler, ns, name, type, userdata, 0); + _handler_add(conn, handler, ns, name, type, userdata, 0); } diff --git a/src/hash.c b/src/hash.c index 3acbc151..27d27562 100644 --- a/src/hash.c +++ b/src/hash.c @@ -1,7 +1,7 @@ /* hash.c ** strophe XMPP client library -- hash table implementation -** -** Copyright (C) 2005-2009 Collecta, Inc. +** +** Copyright (C) 2005-2009 Collecta, Inc. ** ** This software is provided AS-IS with no warranty, either express ** or implied. @@ -19,7 +19,7 @@ #include #include -#include "strophe.h" +#include "couplet.h" #include "common.h" #include "hash.h" @@ -47,7 +47,7 @@ struct _hash_iterator_t { hashentry_t *entry; int index; }; - + /** allocate and initialize a new hash table */ hash_t *hash_new(xmpp_ctx_t * const ctx, const int size, hash_free_func free) @@ -70,7 +70,7 @@ hash_t *hash_new(xmpp_ctx_t * const ctx, const int size, /* give the caller a reference */ result->ref = 1; } - + return result; } @@ -87,7 +87,7 @@ void hash_release(hash_t * const table) xmpp_ctx_t *ctx = table->ctx; hashentry_t *entry, *next; int i; - + if (table->ref > 1) table->ref--; else { diff --git a/src/hash.h b/src/hash.h index 94c0b14e..e069ec90 100644 --- a/src/hash.h +++ b/src/hash.h @@ -1,7 +1,7 @@ /* hash.h ** strophe XMPP client library -- hash table interface -** -** Copyright (C) 2005-2009 Collecta, Inc. +** +** Copyright (C) 2005-2009 Collecta, Inc. ** ** This software is provided AS-IS with no warranty, either express ** or implied. diff --git a/src/jid.c b/src/jid.c index 53b2c484..67635445 100644 --- a/src/jid.c +++ b/src/jid.c @@ -1,7 +1,7 @@ /* jid.c ** strophe XMPP client library -- helper functions for parsing JIDs ** -** Copyright (C) 2005-2009 Collecta, Inc. +** Copyright (C) 2005-2009 Collecta, Inc. ** ** This software is provided AS-IS with no warranty, either express ** or implied. @@ -18,7 +18,7 @@ #include -#include "strophe.h" +#include "couplet.h" #include "common.h" /** Create a JID string from component parts node, domain, and resource. @@ -66,7 +66,7 @@ char *xmpp_jid_new(xmpp_ctx_t *ctx, const char *node, } /** Create a bare JID from a JID. - * + * * @param ctx the Strophe context object * @param jid the JID * @@ -90,7 +90,7 @@ char *xmpp_jid_bare(xmpp_ctx_t *ctx, const char *jid) } /** Create a node string from a JID. - * + * * @param ctx a Strophe context object * @param jid the JID * @@ -153,7 +153,7 @@ char *xmpp_jid_domain(xmpp_ctx_t *ctx, const char *jid) * @param ctx a Strophe context object * @param jid the JID * - * @return an allocated string with the resource or NULL if no resource + * @return an allocated string with the resource or NULL if no resource * is found or an error occurs */ char *xmpp_jid_resource(xmpp_ctx_t *ctx, const char *jid) diff --git a/src/list.c b/src/list.c new file mode 100644 index 00000000..e21eee0c --- /dev/null +++ b/src/list.c @@ -0,0 +1,254 @@ +/* list.c + * libcouplet - fork of libstrophe, XMPP client library + * General list routines + * + * Copyright (C) 2012 Dmitry Podgorny + * + * This software is provided AS-IS with no warranty + * + * You can redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation, either version + * 3 of the License, or any later version. + */ + +/** @file + * General list routines + */ + +#include "list.h" +#include "couplet.h" +#include "common.h" + +/** Create new list. + * + * @param ctx a context object + * + * @return a pointer to allocated list_head_t structure or NULL pointer + */ +list_head_t *list_init(xmpp_ctx_t * const ctx) +{ + list_head_t *list; + + if (!ctx) + return NULL; + + list = (list_head_t *)xmpp_alloc(ctx, sizeof(*list)); + if (list) { + list->mutex = mutex_create(ctx); + if (!list->mutex) { + xmpp_free(ctx, list); + return NULL; + } + list->ctx = ctx; + list->head = NULL; + list->tail = NULL; + } + + return list; +} + +/** Destroy the list + * + * @param list a list object + */ +void list_destroy(list_head_t *list) +{ + /** @TODO avoid memory leak issue when the list isn't empty */ + mutex_destroy(list->mutex); + xmpp_free(list->ctx, list); +} + +/** Create new list item + * + * @param ctx a context object + * + * @return a pointer to allocated list_t structure or NULL pointer + */ +list_t *list_init_item(const xmpp_ctx_t * const ctx) +{ + list_t *item; + + if (!ctx) + return NULL; + + item = (list_t *)xmpp_alloc(ctx, sizeof(*item)); + if (item) { + item->data = NULL; + item->next = NULL; + } + + return item; +} + +/** Get the first element of the list + * Function just returns head of the list + * + * @param list a list object + * + * @return pointer to head of the list or NULL pointer if the list is empty + */ +list_t *list_get_first(const list_head_t * const list) +{ + list_t *item; + + mutex_lock(list->mutex); + item = list->head; + mutex_unlock(list->mutex); + + return item; +} + +/** Get element that follows the item + * + * @param list a list object + * @param item s list item object + * + * @return pointer to the next element if exists or NULL pointer otherwise + */ +list_t *list_get_next(const list_head_t * const list, const list_t * const item) +{ + list_t *next; + + mutex_lock(list->mutex); + next = item->next; + mutex_unlock(list->mutex); + + return next; +} + +/** Get the last element of the list + * Function just returns tail of the list + * + * @param list a list object + * + * @return pointer to tail of the list or NULL pointer if the list is empty + */ +list_t *list_get_last(const list_head_t * const list) +{ + list_t *last; + + mutex_lock(list->mutex); + last = list->tail; + mutex_unlock(list->mutex); + + return last; +} + +/** Get the first element of the list and remove it + * + * @param list a list object + * + * @return pointer to the first element or NULL pointer if such doesn't exist + */ +list_t *list_shift(list_head_t * const list) +{ + list_t *item; + + mutex_lock(list->mutex); + item = list->head; + if (item) { + list->head = item->next; + if (!list->head) + list->tail = NULL; + } + mutex_unlock(list->mutex); + + return item; +} + +/** Remove the item if exists + * Function searches the item within the list and removes it if exists + * + * @param list a list object + * @param item list element for search + * + * @return pointer to the item if it was removed and NULL pointer otherwise + */ +list_t *list_pop_by_data(list_head_t * const list, const void * const data) +{ + list_t *prev = NULL; + list_t *cur; + + mutex_lock(list->mutex); + cur = list->head; + while (cur) { + if (cur->data == data) { + if (prev) + prev->next = cur->next; + else + list->head = cur->next; + if (!cur->next) + list->tail = prev; + break; + } + prev = cur; + cur = cur->next; + } + mutex_unlock(list->mutex); + + return cur; +} + +/** Get next element and remove it from the list + * + * @param list a list object + * @param item a list item object + * + * @return pointer to the next element + */ +list_t *list_pop_next(list_head_t * const list, list_t * const item) +{ + list_t *next; + + if (!item) + return NULL; + + mutex_lock(list->mutex); + next = item->next; + if (next) + item->next = next->next; + if (!item->next) + list->tail = item; + mutex_unlock(list->mutex); + + return next; +} + +/** Insert the element to the head of the list + * + * @param list a list object + * @param item an element for insertion + */ +void list_insert(list_head_t * const list, list_t * const item) +{ + if (!item) + return; + + item->next = NULL; + mutex_lock(list->mutex); + item->next = list->head; + list->head = item; + if (!item->next) + list->tail = item; + mutex_unlock(list->mutex); +} + +/** Append the element to the end of the list + * + * @param list a list object + * @param item an element + */ +void list_push(list_head_t * const list, list_t * const item) +{ + if (!item) + return; + + item->next = NULL; + mutex_lock(list->mutex); + if (!list->tail) + list->head = item; + else + list->tail->next = item; + list->tail = item; + mutex_unlock(list->mutex); +} diff --git a/src/list.h b/src/list.h new file mode 100644 index 00000000..643d888c --- /dev/null +++ b/src/list.h @@ -0,0 +1,62 @@ +/* list.h + * libcouplet - fork of libstrophe, XMPP client library + * General list routines + * + * Copyright (C) 2012 Dmitry Podgorny + * + * This software is provided AS-IS with no warranty + * + * You can redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation, either version + * 3 of the License, or any later version. + */ + +/** @file + * General list routines header + */ + +#ifndef __LIBCOUPLET_LIST_H__ +#define __LIBCOUPLET_LIST_H__ + +#include "couplet.h" +#include "thread.h" + +struct _list_t { + void *data; + struct _list_t *next; +}; + +typedef struct _list_t list_t; + +struct _list_head_t { + xmpp_ctx_t *ctx; + mutex_t *mutex; + list_t *head; + list_t *tail; +}; + +typedef struct _list_head_t list_head_t; + +list_head_t *list_init(xmpp_ctx_t * const ctx); +void list_destroy(list_head_t *list); +list_t *list_init_item(const xmpp_ctx_t * const ctx); +list_t *list_get_first(const list_head_t * const list); +list_t *list_get_next(const list_head_t * const list, const list_t * const item); +list_t *list_get_last(const list_head_t * const list); +list_t *list_shift(list_head_t * const list); +list_t *list_pop_by_data(list_head_t * const list, const void * const data); +list_t *list_pop_next(list_head_t * const list, list_t * const item); +void list_insert(list_head_t * const list, list_t * const item); +void list_push(list_head_t * const list, list_t * const item); + +static inline void list_lock_mutex(const list_head_t * const list) +{ + mutex_lock(list->mutex); +} + +static inline void list_unlock_mutex(const list_head_t * const list) +{ + mutex_unlock(list->mutex); +} + +#endif diff --git a/src/md5.c b/src/md5.c index c4ac4ac4..94e5b3ea 100644 --- a/src/md5.c +++ b/src/md5.c @@ -107,7 +107,7 @@ void MD5Update(struct MD5Context *ctx, unsigned char const *buf, uint32_t len) } /* - * Final wrapup - pad to 64-byte boundary with the bit pattern + * Final wrapup - pad to 64-byte boundary with the bit pattern * 1 0* (64-bit count of bits processed, MSB-first) */ void MD5Final(unsigned char digest[16], struct MD5Context *ctx) @@ -184,7 +184,7 @@ void MD5Transform(uint32_t buf[4], const unsigned char inext[64], { register uint32_t a, b, c, d, i; uint32_t in[16]; - + for (i = 0; i < 16; i++) in[i] = GET_32BIT_LSB_FIRST(inext + 4 * i); diff --git a/src/oocontext.cpp b/src/oocontext.cpp index 50717e45..dc2dd2e2 100644 --- a/src/oocontext.cpp +++ b/src/oocontext.cpp @@ -14,8 +14,8 @@ #include -#include "strophe.h" -#include "strophepp.h" +#include "couplet.h" +#include "coupletpp.h" XMPP::Context::Context() { diff --git a/src/oostanza.cpp b/src/oostanza.cpp index 178bfbf4..74924ee3 100644 --- a/src/oostanza.cpp +++ b/src/oostanza.cpp @@ -12,8 +12,8 @@ ** distribution. */ -#include "strophe.h" -#include "strophepp.h" +#include "couplet.h" +#include "coupletpp.h" using namespace XMPP; diff --git a/src/ostypes.h b/src/ostypes.h index 0794b2ba..3be371e6 100644 --- a/src/ostypes.h +++ b/src/ostypes.h @@ -1,8 +1,8 @@ /* ostypes.h -** strophe XMPP client library -- type definitions for platforms +** strophe XMPP client library -- type definitions for platforms ** without stdint.h ** -** Copyright (C) 2005-2009 Collecta, Inc. +** Copyright (C) 2005-2009 Collecta, Inc. ** ** This software is provided AS-IS with no warranty, either express ** or implied. @@ -21,7 +21,7 @@ #define __LIBSTROPHE_OSTYPES_H__ #ifdef _WIN32 -typedef unsigned __int64 uint64_t; +typedef unsigned __int64 uint64_t; #endif #endif /* __LIBSTROPHE_OSTYPES_H__ */ diff --git a/src/parser.h b/src/parser.h index 89ff71b1..8e580b50 100644 --- a/src/parser.h +++ b/src/parser.h @@ -1,7 +1,7 @@ /* parser.h ** strophe XMPP client library -- parser structures and functions ** -** Copyright (C) 2005-2009 Collecta, Inc. +** Copyright (C) 2005-2009 Collecta, Inc. ** ** This software is provided AS-IS with no warranty, either express or ** implied. @@ -19,7 +19,7 @@ #ifndef __LIBSTROPHE_PARSER_H__ #define __LIBSTROPHE_PARSER_H__ -#include "strophe.h" +#include "couplet.h" typedef struct _parser_t parser_t; @@ -31,7 +31,7 @@ typedef void (*parser_stanza_callback)(xmpp_stanza_t *stanza, void * const userdata); -parser_t *parser_new(xmpp_ctx_t *ctx, +parser_t *parser_new(xmpp_ctx_t *ctx, parser_start_callback startcb, parser_end_callback endcb, parser_stanza_callback stanzacb, diff --git a/src/parser_expat.c b/src/parser_expat.c index 9ab4e38f..dce475bc 100644 --- a/src/parser_expat.c +++ b/src/parser_expat.c @@ -1,7 +1,7 @@ /* parser.c ** strophe XMPP client library -- xml parser handlers and utility functions ** -** Copyright (C) 2005-2009 Collecta, Inc. +** Copyright (C) 2005-2009 Collecta, Inc. ** ** This software is provided AS-IS with no warranty, either express ** or implied. @@ -22,7 +22,7 @@ #include -#include +#include "couplet.h" #include "common.h" #include "parser.h" @@ -58,7 +58,7 @@ static void _start_element(void *userdata, if (parser->depth == 0) { /* notify the owner */ if (parser->startcb) - parser->startcb((char *)name, (char **)attrs, + parser->startcb((char *)name, (char **)attrs, parser->userdata); } else { /* build stanzas at depth 1 */ @@ -85,7 +85,7 @@ static void _start_element(void *userdata, /* add child to parent */ xmpp_stanza_add_child(parser->stanza, child); - + /* the child is owned by the toplevel stanza now */ xmpp_stanza_release(child); @@ -180,7 +180,7 @@ int parser_reset(parser_t *parser) if (parser->expat) XML_ParserFree(parser->expat); - if (parser->stanza) + if (parser->stanza) xmpp_stanza_release(parser->stanza); parser->expat = XML_ParserCreate(NULL); diff --git a/src/parser_libxml2.c b/src/parser_libxml2.c index ab10a4b3..500c07d4 100644 --- a/src/parser_libxml2.c +++ b/src/parser_libxml2.c @@ -1,7 +1,7 @@ /* parser.c ** strophe XMPP client library -- xml parser handlers and utility functions ** -** Copyright (C) 2005-2009 Collecta, Inc. +** Copyright (C) 2005-2009 Collecta, Inc. ** ** This software is provided AS-IS with no warranty, either express ** or implied. @@ -23,7 +23,7 @@ #include #include -#include +#include "couplet.h" #include "common.h" #include "parser.h" @@ -50,7 +50,7 @@ static void _set_attributes(xmpp_stanza_t *stanza, const xmlChar **attrs) } } -static void _start_element(void *userdata, +static void _start_element(void *userdata, const xmlChar *name, const xmlChar **attrs) { parser_t *parser = (parser_t *)userdata; @@ -59,7 +59,7 @@ static void _start_element(void *userdata, if (parser->depth == 0) { /* notify the owner */ if (parser->startcb) - parser->startcb((char *)name, (char **)attrs, + parser->startcb((char *)name, (char **)attrs, parser->userdata); } else { /* build stanzas at depth 1 */ @@ -86,7 +86,7 @@ static void _start_element(void *userdata, /* add child to parent */ xmpp_stanza_add_child(parser->stanza, child); - + /* the child is owned by the toplevel stanza now */ xmpp_stanza_release(child); @@ -186,10 +186,10 @@ int parser_reset(parser_t *parser) if (parser->xmlctx) xmlFreeParserCtxt(parser->xmlctx); - if (parser->stanza) + if (parser->stanza) xmpp_stanza_release(parser->stanza); - parser->xmlctx = xmlCreatePushParserCtxt(&parser->handlers, + parser->xmlctx = xmlCreatePushParserCtxt(&parser->handlers, parser, NULL, 0, NULL); if (!parser->xmlctx) return 0; diff --git a/src/sasl.c b/src/sasl.c index 73fbbc9b..3e301b58 100644 --- a/src/sasl.c +++ b/src/sasl.c @@ -1,7 +1,7 @@ /* sasl.c ** strophe XMPP client library -- SASL authentication helpers -** -** Copyright (C) 2005-2009 Collecta, Inc. +** +** Copyright (C) 2005-2009 Collecta, Inc. ** ** This software is provided AS-IS with no warranty, either express ** or implied. @@ -18,22 +18,22 @@ #include -#include "strophe.h" +#include "couplet.h" #include "common.h" #include "sasl.h" #include "md5.h" /* make sure the stdint.h types are available */ #if defined(_MSC_VER) /* Microsoft Visual C++ */ - typedef signed char int8_t; - typedef short int int16_t; - typedef int int32_t; - typedef __int64 int64_t; - - typedef unsigned char uint8_t; - typedef unsigned short int uint16_t; - typedef unsigned int uint32_t; - /* no uint64_t */ +typedef signed char int8_t; +typedef short int int16_t; +typedef int int32_t; +typedef __int64 int64_t; + +typedef unsigned char uint8_t; +typedef unsigned short int uint16_t; +typedef unsigned int uint32_t; +/* no uint64_t */ #else #include #endif @@ -41,26 +41,26 @@ /** generate authentication string for the SASL PLAIN mechanism */ char *sasl_plain(xmpp_ctx_t *ctx, const char *authid, const char *password) { - int idlen, passlen; - char *result = NULL; - char *msg; - - /* our message is Base64(authzid,\0,authid,\0,password) - if there is no authzid, that field is left empty */ - - idlen = strlen(authid); - passlen = strlen(password); - msg = xmpp_alloc(ctx, 2 + idlen + passlen); - if (msg != NULL) { - msg[0] = '\0'; - memcpy(msg+1, authid, idlen); - msg[1+idlen] = '\0'; - memcpy(msg+1+idlen+1, password, passlen); - result = base64_encode(ctx, (unsigned char *)msg, 2 + idlen + passlen); - xmpp_free(ctx, msg); - } - - return result; + int idlen, passlen; + char *result = NULL; + char *msg; + + /* our message is Base64(authzid,\0,authid,\0,password) + * if there is no authzid, that field is left empty */ + + idlen = strlen(authid); + passlen = strlen(password); + msg = xmpp_alloc(ctx, 2 + idlen + passlen); + if (msg) { + msg[0] = '\0'; + memcpy(msg+1, authid, idlen); + msg[1+idlen] = '\0'; + memcpy(msg+1+idlen+1, password, passlen); + result = base64_encode(ctx, (unsigned char *)msg, 2 + idlen + passlen); + xmpp_free(ctx, msg); + } + + return result; } /** helpers for digest auth */ @@ -68,296 +68,307 @@ char *sasl_plain(xmpp_ctx_t *ctx, const char *authid, const char *password) { /* create a new, null-terminated string from a substring */ static char *_make_string(xmpp_ctx_t *ctx, const char *s, const unsigned len) { - char *result; - - result = xmpp_alloc(ctx, len + 1); - if (result != NULL) { - memcpy(result, s, len); - result[len] = '\0'; - } - return result; + char *result; + + result = xmpp_alloc(ctx, len + 1); + if (result != NULL) { + memcpy(result, s, len); + result[len] = '\0'; + } + + return result; } /* create a new, null-terminated string quoting another string */ static char *_make_quoted(xmpp_ctx_t *ctx, const char *s) { - char *result; - int len = strlen(s); - - result = xmpp_alloc(ctx, len + 3); - if (result != NULL) { - result[0] = '"'; - memcpy(result+1, s, len); - result[len+1] = '"'; - result[len+2] = '\0'; - } - return result; + char *result; + int len = strlen(s); + + result = xmpp_alloc(ctx, len + 3); + if (result != NULL) { + result[0] = '"'; + memcpy(result+1, s, len); + result[len+1] = '"'; + result[len+2] = '\0'; + } + + return result; } /* split key, value pairs into a hash */ static hash_t *_parse_digest_challenge(xmpp_ctx_t *ctx, const char *msg) { - hash_t *result; - unsigned char *text; - char *key, *value; - unsigned char *s, *t; - - text = base64_decode(ctx, msg, strlen(msg)); - if (text == NULL) { - xmpp_error(ctx, "SASL", "couldn't Base64 decode challenge!"); - return NULL; - } - - result = hash_new(ctx, 10, xmpp_free); - if (result != NULL) { - s = text; - while (*s != '\0') { - /* skip any leading commas and spaces */ - while ((*s == ',') || (*s == ' ')) s++; - /* accumulate a key ending at '=' */ - t = s; - while ((*t != '=') && (*t != '\0')) t++; - if (*t == '\0') break; /* bad string */ - key = _make_string(ctx, (char *)s, (t-s)); - if (key == NULL) break; - /* advance our start pointer past the key */ - s = t + 1; - t = s; - /* if we see quotes, grab the string in between */ - if ((*s == '\'') || (*s == '"')) { - t++; - while ((*t != *s) && (*t != '\0')) - t++; - value = _make_string(ctx, (char *)s+1, (t-s-1)); - if (*t == *s) { - s = t + 1; - } else { - s = t; + hash_t *result; + unsigned char *text; + char *key, *value; + unsigned char *s, *t; + + text = base64_decode(ctx, msg, strlen(msg)); + if (!text) { + xmpp_error(ctx, "SASL", "couldn't Base64 decode challenge!"); + return NULL; + } + + result = hash_new(ctx, 10, xmpp_free); + if (result) { + s = text; + while (*s != '\0') { + /* skip any leading commas and spaces */ + while ((*s == ',') || (*s == ' ')) + s++; + /* accumulate a key ending at '=' */ + t = s; + while ((*t != '=') && (*t != '\0')) + t++; + if (*t == '\0') /* bad string */ + break; + key = _make_string(ctx, (char *)s, (t-s)); + if (!key) + break; + /* advance our start pointer past the key */ + s = t + 1; + t = s; + /* if we see quotes, grab the string in between */ + if ((*s == '\'') || (*s == '"')) { + t++; + while ((*t != *s) && (*t != '\0')) + t++; + value = _make_string(ctx, (char *)s+1, (t-s-1)); + if (*t == *s) + s = t + 1; + else + s = t; + /* otherwise, accumulate a value ending in ',' or '\0' */ + } else { + while ((*t != ',') && (*t != '\0')) + t++; + value = _make_string(ctx, (char *)s, (t-s)); + s = t; + } + if (!value) { + xmpp_free(ctx, key); + break; + } + /* TODO: check for collisions per spec */ + hash_add(result, key, value); + /* hash table now owns the value, free the key */ + xmpp_free(ctx, key); } - /* otherwise, accumulate a value ending in ',' or '\0' */ - } else { - while ((*t != ',') && (*t != '\0')) t++; - value = _make_string(ctx, (char *)s, (t-s)); - s = t; - } - if (value == NULL) { - xmpp_free(ctx, key); - break; - } - /* TODO: check for collisions per spec */ - hash_add(result, key, value); - /* hash table now owns the value, free the key */ - xmpp_free(ctx, key); } - } - xmpp_free(ctx, text); + xmpp_free(ctx, text); - return result; + return result; } /** expand a 16 byte MD5 digest to a 32 byte hex representation */ static void _digest_to_hex(const char *digest, char *hex) { - int i; - const char hexdigit[] = "0123456789abcdef"; + int i; + const char hexdigit[] = "0123456789abcdef"; - for (i = 0; i < 16; i++) { - *hex++ = hexdigit[ (digest[i] >> 4) & 0x0F ]; - *hex++ = hexdigit[ digest[i] & 0x0F ]; - } + for (i = 0; i < 16; i++) { + *hex++ = hexdigit[ (digest[i] >> 4) & 0x0F ]; + *hex++ = hexdigit[ digest[i] & 0x0F ]; + } } /** append 'key="value"' to a buffer, growing as necessary */ -static char *_add_key(xmpp_ctx_t *ctx, hash_t *table, const char *key, +static char *_add_key(xmpp_ctx_t *ctx, hash_t *table, const char *key, char *buf, int *len, int quote) { - int olen,nlen; - int keylen, valuelen; - const char *value, *qvalue; - char *c; - - /* allocate a zero-length string if necessary */ - if (buf == NULL) { - buf = xmpp_alloc(ctx, 1); - buf[0] = '\0'; - } - if (buf == NULL) return NULL; - - /* get current string length */ - olen = strlen(buf); - value = hash_get(table, key); - if (value == NULL) { - xmpp_error(ctx, "SASL", "couldn't retrieve value for '%s'", key); - value = ""; - } - if (quote) { - qvalue = _make_quoted(ctx, value); - } else { - qvalue = value; - } - /* added length is key + '=' + value */ - /* (+ ',' if we're not the first entry */ - keylen = strlen(key); - valuelen = strlen(qvalue); - nlen = (olen ? 1 : 0) + keylen + 1 + valuelen + 1; - buf = xmpp_realloc(ctx, buf, olen+nlen); - - if (buf != NULL) { - c = buf + olen; - if (olen) *c++ = ','; - memcpy(c, key, keylen); c += keylen; - *c++ = '='; - memcpy(c, qvalue, valuelen); c += valuelen; - *c++ = '\0'; - } - - if (quote) xmpp_free(ctx, (char *)qvalue); - - return buf; + int olen,nlen; + int keylen, valuelen; + const char *value, *qvalue; + char *c; + + /* allocate a zero-length string if necessary */ + if (!buf) { + buf = xmpp_alloc(ctx, 1); + if (!buf) + return NULL; + buf[0] = '\0'; + } + + /* get current string length */ + olen = strlen(buf); + value = hash_get(table, key); + if (!value) { + xmpp_error(ctx, "SASL", "couldn't retrieve value for '%s'", key); + value = ""; + } + if (quote) + qvalue = _make_quoted(ctx, value); + else + qvalue = value; + + /* added length is key + '=' + value */ + /* (+ ',' if we're not the first entry */ + keylen = strlen(key); + valuelen = strlen(qvalue); + nlen = (olen ? 1 : 0) + keylen + 1 + valuelen + 1; + buf = xmpp_realloc(ctx, buf, olen+nlen); + + if (buf) { + c = buf + olen; + if (olen) + *c++ = ','; + memcpy(c, key, keylen); c += keylen; + *c++ = '='; + memcpy(c, qvalue, valuelen); c += valuelen; + *c++ = '\0'; + } + + if (quote) + xmpp_free(ctx, (char *)qvalue); + + return buf; } /** generate auth response string for the SASL DIGEST-MD5 mechanism */ char *sasl_digest_md5(xmpp_ctx_t *ctx, const char *challenge, - const char *jid, const char *password) { - hash_t *table; - char *result = NULL; - char *node, *domain, *realm; - char *value; - char *response; - int rlen; - struct MD5Context MD5; - unsigned char digest[16], HA1[16], HA2[16]; - char hex[32]; - - /* our digest response is - Hex( KD( HEX(MD5(A1)), - nonce ':' nc ':' cnonce ':' qop ':' HEX(MD5(A2)) - )) - - where KD(k, s) = MD5(k ':' s), - A1 = MD5( node ':' realm ':' password ) ':' nonce ':' cnonce - A2 = "AUTHENTICATE" ':' "xmpp/" domain - - If there is an authzid it is ':'-appended to A1 */ - - /* parse the challenge */ - table = _parse_digest_challenge(ctx, challenge); - if (table == NULL) { - xmpp_error(ctx, "SASL", "couldn't parse digest challenge"); - return NULL; - } + const char *jid, const char *password) +{ + hash_t *table; + char *result = NULL; + char *node, *domain, *realm; + char *value; + char *response; + int rlen; + struct MD5Context MD5; + unsigned char digest[16], HA1[16], HA2[16]; + char hex[32]; + + /* our digest response is + * Hex( KD( HEX(MD5(A1)), + * nonce ':' nc ':' cnonce ':' qop ':' HEX(MD5(A2)) + * )) + * + * where KD(k, s) = MD5(k ':' s), + * A1 = MD5( node ':' realm ':' password ) ':' nonce ':' cnonce + * A2 = "AUTHENTICATE" ':' "xmpp/" domain + * + * If there is an authzid it is ':'-appended to A1 + */ + + /* parse the challenge */ + table = _parse_digest_challenge(ctx, challenge); + if (!table) { + xmpp_error(ctx, "SASL", "couldn't parse digest challenge"); + return NULL; + } - node = xmpp_jid_node(ctx, jid); - domain = xmpp_jid_domain(ctx, jid); + node = xmpp_jid_node(ctx, jid); + domain = xmpp_jid_domain(ctx, jid); - /* generate default realm of domain if one didn't come from the - server */ - realm = hash_get(table, "realm"); - if (realm == NULL || strlen(realm) == 0) { - hash_add(table, "realm", xmpp_strdup(ctx, domain)); + /* generate default realm of domain if one didn't come from the + * server */ realm = hash_get(table, "realm"); - } - - /* add our response fields */ - hash_add(table, "username", xmpp_strdup(ctx, node)); - /* TODO: generate a random cnonce */ - hash_add(table, "cnonce", xmpp_strdup(ctx, "00DEADBEEF00")); - hash_add(table, "nc", xmpp_strdup(ctx, "00000001")); - hash_add(table, "qop", xmpp_strdup(ctx, "auth")); - value = xmpp_alloc(ctx, 5 + strlen(domain) + 1); - memcpy(value, "xmpp/", 5); - memcpy(value+5, domain, strlen(domain)); - value[5+strlen(domain)] = '\0'; - hash_add(table, "digest-uri", value); - - /* generate response */ - - /* construct MD5(node : realm : password) */ - MD5Init(&MD5); - MD5Update(&MD5, (unsigned char *)node, strlen(node)); - MD5Update(&MD5, (unsigned char *)":", 1); - MD5Update(&MD5, (unsigned char *)realm, strlen(realm)); - MD5Update(&MD5, (unsigned char *)":", 1); - MD5Update(&MD5, (unsigned char *)password, strlen(password)); - MD5Final(digest, &MD5); - - /* digest now contains the first field of A1 */ - - MD5Init(&MD5); - MD5Update(&MD5, digest, 16); - MD5Update(&MD5, (unsigned char *)":", 1); - value = hash_get(table, "nonce"); - MD5Update(&MD5, (unsigned char *)value, strlen(value)); - MD5Update(&MD5, (unsigned char *)":", 1); - value = hash_get(table, "cnonce"); - MD5Update(&MD5, (unsigned char *)value, strlen(value)); - MD5Final(digest, &MD5); - - /* now digest is MD5(A1) */ - memcpy(HA1, digest, 16); - - /* construct MD5(A2) */ - MD5Init(&MD5); - MD5Update(&MD5, (unsigned char *)"AUTHENTICATE:", 13); - value = hash_get(table, "digest-uri"); - MD5Update(&MD5, (unsigned char *)value, strlen(value)); - if (strcmp(hash_get(table, "qop"), "auth") != 0) { - MD5Update(&MD5, (unsigned char *)":00000000000000000000000000000000", - 33); - } - MD5Final(digest, &MD5); - - memcpy(HA2, digest, 16); - - /* construct response */ - MD5Init(&MD5); - _digest_to_hex((char *)HA1, hex); - MD5Update(&MD5, (unsigned char *)hex, 32); - MD5Update(&MD5, (unsigned char *)":", 1); - value = hash_get(table, "nonce"); - MD5Update(&MD5, (unsigned char *)value, strlen(value)); - MD5Update(&MD5, (unsigned char *)":", 1); - value = hash_get(table, "nc"); - MD5Update(&MD5, (unsigned char *)value, strlen(value)); - MD5Update(&MD5, (unsigned char *)":", 1); - value = hash_get(table, "cnonce"); - MD5Update(&MD5, (unsigned char *)value, strlen(value)); - MD5Update(&MD5, (unsigned char *)":", 1); - value = hash_get(table, "qop"); - MD5Update(&MD5, (unsigned char *)value, strlen(value)); - MD5Update(&MD5, (unsigned char *)":", 1); - _digest_to_hex((char *)HA2, hex); - MD5Update(&MD5, (unsigned char *)hex, 32); - MD5Final(digest, &MD5); - - response = xmpp_alloc(ctx, 32+1); - _digest_to_hex((char *)digest, hex); - memcpy(response, hex, 32); - response[32] = '\0'; - hash_add(table, "response", response); - - /* construct reply */ - result = NULL; - rlen = 0; - result = _add_key(ctx, table, "username", result, &rlen, 1); - result = _add_key(ctx, table, "realm", result, &rlen, 1); - result = _add_key(ctx, table, "nonce", result, &rlen, 1); - result = _add_key(ctx, table, "cnonce", result, &rlen, 1); - result = _add_key(ctx, table, "nc", result, &rlen, 0); - result = _add_key(ctx, table, "qop", result, &rlen, 0); - result = _add_key(ctx, table, "digest-uri", result, &rlen, 1); - result = _add_key(ctx, table, "response", result, &rlen, 0); - result = _add_key(ctx, table, "charset", result, &rlen, 0); - - xmpp_free(ctx, node); - xmpp_free(ctx, domain); - hash_release(table); /* also frees value strings */ - - /* reuse response for the base64 encode of our result */ - response = base64_encode(ctx, (unsigned char *)result, strlen(result)); - xmpp_free(ctx, result); - - return response; + if (!realm || !strlen(realm)) { + hash_add(table, "realm", xmpp_strdup(ctx, domain)); + realm = hash_get(table, "realm"); + } + + /* add our response fields */ + hash_add(table, "username", xmpp_strdup(ctx, node)); + /* TODO: generate a random cnonce */ + hash_add(table, "cnonce", xmpp_strdup(ctx, "00DEADBEEF00")); + hash_add(table, "nc", xmpp_strdup(ctx, "00000001")); + hash_add(table, "qop", xmpp_strdup(ctx, "auth")); + value = xmpp_alloc(ctx, 5 + strlen(domain) + 1); + memcpy(value, "xmpp/", 5); + memcpy(value+5, domain, strlen(domain)); + value[5+strlen(domain)] = '\0'; + hash_add(table, "digest-uri", value); + + /* generate response */ + + /* construct MD5(node : realm : password) */ + MD5Init(&MD5); + MD5Update(&MD5, (unsigned char *)node, strlen(node)); + MD5Update(&MD5, (unsigned char *)":", 1); + MD5Update(&MD5, (unsigned char *)realm, strlen(realm)); + MD5Update(&MD5, (unsigned char *)":", 1); + MD5Update(&MD5, (unsigned char *)password, strlen(password)); + MD5Final(digest, &MD5); + + /* digest now contains the first field of A1 */ + + MD5Init(&MD5); + MD5Update(&MD5, digest, 16); + MD5Update(&MD5, (unsigned char *)":", 1); + value = hash_get(table, "nonce"); + MD5Update(&MD5, (unsigned char *)value, strlen(value)); + MD5Update(&MD5, (unsigned char *)":", 1); + value = hash_get(table, "cnonce"); + MD5Update(&MD5, (unsigned char *)value, strlen(value)); + MD5Final(digest, &MD5); + + /* now digest is MD5(A1) */ + memcpy(HA1, digest, 16); + + /* construct MD5(A2) */ + MD5Init(&MD5); + MD5Update(&MD5, (unsigned char *)"AUTHENTICATE:", 13); + value = hash_get(table, "digest-uri"); + MD5Update(&MD5, (unsigned char *)value, strlen(value)); + if (strcmp(hash_get(table, "qop"), "auth")) { + MD5Update(&MD5, (unsigned char *)":00000000000000000000000000000000", 33); + } + MD5Final(digest, &MD5); + + memcpy(HA2, digest, 16); + + /* construct response */ + MD5Init(&MD5); + _digest_to_hex((char *)HA1, hex); + MD5Update(&MD5, (unsigned char *)hex, 32); + MD5Update(&MD5, (unsigned char *)":", 1); + value = hash_get(table, "nonce"); + MD5Update(&MD5, (unsigned char *)value, strlen(value)); + MD5Update(&MD5, (unsigned char *)":", 1); + value = hash_get(table, "nc"); + MD5Update(&MD5, (unsigned char *)value, strlen(value)); + MD5Update(&MD5, (unsigned char *)":", 1); + value = hash_get(table, "cnonce"); + MD5Update(&MD5, (unsigned char *)value, strlen(value)); + MD5Update(&MD5, (unsigned char *)":", 1); + value = hash_get(table, "qop"); + MD5Update(&MD5, (unsigned char *)value, strlen(value)); + MD5Update(&MD5, (unsigned char *)":", 1); + _digest_to_hex((char *)HA2, hex); + MD5Update(&MD5, (unsigned char *)hex, 32); + MD5Final(digest, &MD5); + + response = xmpp_alloc(ctx, 32 + 1); + /** @TODO check 'response' for NULL */ + _digest_to_hex((char *)digest, hex); + memcpy(response, hex, 32); + response[32] = '\0'; + hash_add(table, "response", response); + + /* construct reply */ + result = NULL; + rlen = 0; + result = _add_key(ctx, table, "username", result, &rlen, 1); + result = _add_key(ctx, table, "realm", result, &rlen, 1); + result = _add_key(ctx, table, "nonce", result, &rlen, 1); + result = _add_key(ctx, table, "cnonce", result, &rlen, 1); + result = _add_key(ctx, table, "nc", result, &rlen, 0); + result = _add_key(ctx, table, "qop", result, &rlen, 0); + result = _add_key(ctx, table, "digest-uri", result, &rlen, 1); + result = _add_key(ctx, table, "response", result, &rlen, 0); + result = _add_key(ctx, table, "charset", result, &rlen, 0); + + xmpp_free(ctx, node); + xmpp_free(ctx, domain); + hash_release(table); /* also frees value strings */ + + /* reuse response for the base64 encode of our result */ + response = base64_encode(ctx, (unsigned char *)result, strlen(result)); + xmpp_free(ctx, result); + + return response; } @@ -366,250 +377,220 @@ char *sasl_digest_md5(xmpp_ctx_t *ctx, const char *challenge, /** map of all byte values to the base64 values, or to '65' which indicates an invalid character. '=' is '64' */ static const char _base64_invcharmap[256] = { - 65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65, - 65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65, - 65,65,65,65, 65,65,65,65, 65,65,65,62, 65,65,65,63, - 52,53,54,55, 56,57,58,59, 60,61,65,65, 65,64,65,65, - 65, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14, - 15,16,17,18, 19,20,21,22, 23,24,25,65, 65,65,65,65, - 65,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40, - 41,42,43,44, 45,46,47,48, 49,50,51,65, 65,65,65,65, - 65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65, - 65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65, - 65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65, - 65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65, - 65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65, - 65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65, - 65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65, - 65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65 + 65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65, + 65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65, + 65,65,65,65, 65,65,65,65, 65,65,65,62, 65,65,65,63, + 52,53,54,55, 56,57,58,59, 60,61,65,65, 65,64,65,65, + 65, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14, + 15,16,17,18, 19,20,21,22, 23,24,25,65, 65,65,65,65, + 65,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40, + 41,42,43,44, 45,46,47,48, 49,50,51,65, 65,65,65,65, + 65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65, + 65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65, + 65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65, + 65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65, + 65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65, + 65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65, + 65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65, + 65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65 }; /** map of all 6-bit values to their corresponding byte in the base64 alphabet. Padding char is the value '64' */ static const char _base64_charmap[65] = { - 'A','B','C','D', 'E','F','G','H', - 'I','J','K','L', 'M','N','O','P', - 'Q','R','S','T', 'U','V','W','X', - 'Y','Z','a','b', 'c','d','e','f', - 'g','h','i','j', 'k','l','m','n', - 'o','p','q','r', 's','t','u','v', - 'w','x','y','z', '0','1','2','3', - '4','5','6','7', '8','9','+','/', - '=' + 'A','B','C','D', 'E','F','G','H', + 'I','J','K','L', 'M','N','O','P', + 'Q','R','S','T', 'U','V','W','X', + 'Y','Z','a','b', 'c','d','e','f', + 'g','h','i','j', 'k','l','m','n', + 'o','p','q','r', 's','t','u','v', + 'w','x','y','z', '0','1','2','3', + '4','5','6','7', '8','9','+','/', + '=' }; int base64_encoded_len(xmpp_ctx_t *ctx, const unsigned len) { - /* encoded steam is 4 bytes for every three, rounded up */ - return ((len + 2)/3) << 2; + /* encoded steam is 4 bytes for every three, rounded up */ + return ((len + 2)/3) << 2; } -char *base64_encode(xmpp_ctx_t *ctx, +char *base64_encode(xmpp_ctx_t *ctx, const unsigned char * const buffer, const unsigned len) { - int clen; - char *cbuf, *c; - uint32_t word, hextet; - int i; - - clen = base64_encoded_len(ctx, len); - cbuf = xmpp_alloc(ctx, clen + 1); - if (cbuf != NULL) { - c = cbuf; - /* loop over data, turning every 3 bytes into 4 characters */ - for (i = 0; i < len - 2; i += 3) { - word = buffer[i] << 16 | buffer[i+1] << 8 | buffer[i+2]; - hextet = (word & 0x00FC0000) >> 18; - *c++ = _base64_charmap[hextet]; - hextet = (word & 0x0003F000) >> 12; - *c++ = _base64_charmap[hextet]; - hextet = (word & 0x00000FC0) >> 6; - *c++ = _base64_charmap[hextet]; - hextet = (word & 0x000003F); - *c++ = _base64_charmap[hextet]; - } - /* zero, one or two bytes left */ - switch (len - i) { - case 0: - break; - case 1: - hextet = (buffer[len-1] & 0xFC) >> 2; - *c++ = _base64_charmap[hextet]; - hextet = (buffer[len-1] & 0x03) << 4; - *c++ = _base64_charmap[hextet]; - *c++ = _base64_charmap[64]; /* pad */ - *c++ = _base64_charmap[64]; /* pad */ - break; - case 2: - hextet = (buffer[len-2] & 0xFC) >> 2; - *c++ = _base64_charmap[hextet]; - hextet = ((buffer[len-2] & 0x03) << 4) | - ((buffer[len-1] & 0xF0) >> 4); - *c++ = _base64_charmap[hextet]; - hextet = (buffer[len-1] & 0x0F) << 2; - *c++ = _base64_charmap[hextet]; - *c++ = _base64_charmap[64]; /* pad */ - break; + int clen; + char *cbuf, *c; + uint32_t word, hextet; + int i; + + clen = base64_encoded_len(ctx, len); + cbuf = xmpp_alloc(ctx, clen + 1); + if (cbuf) { + c = cbuf; + /* loop over data, turning every 3 bytes into 4 characters */ + for (i = 0; i < len - 2; i += 3) { + word = buffer[i] << 16 | buffer[i+1] << 8 | buffer[i+2]; + hextet = (word & 0x00FC0000) >> 18; + *c++ = _base64_charmap[hextet]; + hextet = (word & 0x0003F000) >> 12; + *c++ = _base64_charmap[hextet]; + hextet = (word & 0x00000FC0) >> 6; + *c++ = _base64_charmap[hextet]; + hextet = (word & 0x000003F); + *c++ = _base64_charmap[hextet]; + } + /* zero, one or two bytes left */ + switch (len - i) { + case 0: + break; + case 1: + hextet = (buffer[len-1] & 0xFC) >> 2; + *c++ = _base64_charmap[hextet]; + hextet = (buffer[len-1] & 0x03) << 4; + *c++ = _base64_charmap[hextet]; + *c++ = _base64_charmap[64]; /* pad */ + *c++ = _base64_charmap[64]; /* pad */ + break; + case 2: + hextet = (buffer[len-2] & 0xFC) >> 2; + *c++ = _base64_charmap[hextet]; + hextet = ((buffer[len-2] & 0x03) << 4) | + ((buffer[len-1] & 0xF0) >> 4); + *c++ = _base64_charmap[hextet]; + hextet = (buffer[len-1] & 0x0F) << 2; + *c++ = _base64_charmap[hextet]; + *c++ = _base64_charmap[64]; /* pad */ + break; + } + /* add a terminal null */ + *c = '\0'; } - /* add a terminal null */ - *c = '\0'; - } - return cbuf; + return cbuf; } -int base64_decoded_len(xmpp_ctx_t *ctx, +int base64_decoded_len(xmpp_ctx_t *ctx, const char * const buffer, const unsigned len) { - int nudge; - int c; - - /* count the padding characters for the remainder */ - nudge = -1; - c = _base64_invcharmap[(int)buffer[len-1]]; - if (c < 64) nudge = 0; - else if (c == 64) { - c = _base64_invcharmap[(int)buffer[len-2]]; - if (c < 64) nudge = 1; + int nudge; + int c; + + /* count the padding characters for the remainder */ + nudge = -1; + c = _base64_invcharmap[(int)buffer[len-1]]; + if (c < 64) + nudge = 0; else if (c == 64) { - c = _base64_invcharmap[(int)buffer[len-3]]; - if (c < 64) nudge = 2; - } - } - if (nudge < 0) return 0; /* reject bad coding */ - - /* decoded steam is 3 bytes for every four */ - return 3 * (len >> 2) - nudge; + c = _base64_invcharmap[(int)buffer[len-2]]; + if (c < 64) + nudge = 1; + else if (c == 64) { + c = _base64_invcharmap[(int)buffer[len-3]]; + if (c < 64) + nudge = 2; + } + } + if (nudge < 0) + return 0; /* reject bad coding */ + + /* decoded steam is 3 bytes for every four */ + return 3 * (len >> 2) - nudge; } unsigned char *base64_decode(xmpp_ctx_t *ctx, const char * const buffer, const unsigned len) { - int dlen; - unsigned char *dbuf, *d; - uint32_t word, hextet; - int i; - - /* len must be a multiple of 4 */ - if (len & 0x03) return NULL; - - dlen = base64_decoded_len(ctx, buffer, len); - dbuf = xmpp_alloc(ctx, dlen + 1); - if (dbuf != NULL) { - d = dbuf; - /* loop over each set of 4 characters, decoding 3 bytes */ - for (i = 0; i < len - 3; i += 4) { - hextet = _base64_invcharmap[(int)buffer[i]]; - if (hextet & 0xC0) break; - word = hextet << 18; - hextet = _base64_invcharmap[(int)buffer[i+1]]; - if (hextet & 0xC0) break; - word |= hextet << 12; - hextet = _base64_invcharmap[(int)buffer[i+2]]; - if (hextet & 0xC0) break; - word |= hextet << 6; - hextet = _base64_invcharmap[(int)buffer[i+3]]; - if (hextet & 0xC0) break; - word |= hextet; - *d++ = (word & 0x00FF0000) >> 16; - *d++ = (word & 0x0000FF00) >> 8; - *d++ = (word & 0x000000FF); - } - if (hextet > 64) goto _base64_decode_error; - /* handle the remainder */ - switch (dlen % 3) { - case 0: - /* nothing to do */ - break; - case 1: - /* redo the last quartet, checking for correctness */ - hextet = _base64_invcharmap[(int)buffer[len-4]]; - if (hextet & 0xC0) goto _base64_decode_error; - word = hextet << 2; - hextet = _base64_invcharmap[(int)buffer[len-3]]; - if (hextet & 0xC0) goto _base64_decode_error; - word |= hextet >> 4; - *d++ = word & 0xFF; - hextet = _base64_invcharmap[(int)buffer[len-2]]; - if (hextet != 64) goto _base64_decode_error; - hextet = _base64_invcharmap[(int)buffer[len-1]]; - if (hextet != 64) goto _base64_decode_error; - break; - case 2: - /* redo the last quartet, checking for correctness */ - hextet = _base64_invcharmap[(int)buffer[len-4]]; - if (hextet & 0xC0) goto _base64_decode_error; - word = hextet << 10; - hextet = _base64_invcharmap[(int)buffer[len-3]]; - if (hextet & 0xC0) goto _base64_decode_error; - word |= hextet << 4; - hextet = _base64_invcharmap[(int)buffer[len-2]]; - if (hextet & 0xC0) goto _base64_decode_error; - word |= hextet >> 2; - *d++ = (word & 0xFF00) >> 8; - *d++ = (word & 0x00FF); - hextet = _base64_invcharmap[(int)buffer[len-1]]; - if (hextet != 64) goto _base64_decode_error; - break; + int dlen; + unsigned char *dbuf, *d; + uint32_t word, hextet = 0; + int i; + + /* handle zero-length buffers */ + if (!len) + return NULL; + /* len must be a multiple of 4 */ + if (len & 0x03) + return NULL; + + dlen = base64_decoded_len(ctx, buffer, len); + d = dbuf = xmpp_alloc(ctx, dlen + 1); + if (dbuf) { + /* loop over each set of 4 characters, decoding 3 bytes */ + for (i = 0; i < len - 3; i += 4) { + hextet = _base64_invcharmap[(int)buffer[i]]; + if (hextet & 0xC0) + break; + word = hextet << 18; + hextet = _base64_invcharmap[(int)buffer[i+1]]; + if (hextet & 0xC0) + break; + word |= hextet << 12; + hextet = _base64_invcharmap[(int)buffer[i+2]]; + if (hextet & 0xC0) + break; + word |= hextet << 6; + hextet = _base64_invcharmap[(int)buffer[i+3]]; + if (hextet & 0xC0) + break; + word |= hextet; + *d++ = (word & 0x00FF0000) >> 16; + *d++ = (word & 0x0000FF00) >> 8; + *d++ = (word & 0x000000FF); + } + if (hextet > 64) + goto _base64_decode_error; + /* handle the remainder */ + switch (dlen % 3) { + case 0: + /* nothing to do */ + break; + case 1: + /* redo the last quartet, checking for correctness */ + hextet = _base64_invcharmap[(int)buffer[len-4]]; + if (hextet & 0xC0) + goto _base64_decode_error; + word = hextet << 2; + hextet = _base64_invcharmap[(int)buffer[len-3]]; + if (hextet & 0xC0) + goto _base64_decode_error; + word |= hextet >> 4; + *d++ = word & 0xFF; + hextet = _base64_invcharmap[(int)buffer[len-2]]; + if (hextet != 64) + goto _base64_decode_error; + hextet = _base64_invcharmap[(int)buffer[len-1]]; + if (hextet != 64) + goto _base64_decode_error; + break; + case 2: + /* redo the last quartet, checking for correctness */ + hextet = _base64_invcharmap[(int)buffer[len-4]]; + if (hextet & 0xC0) + goto _base64_decode_error; + word = hextet << 10; + hextet = _base64_invcharmap[(int)buffer[len-3]]; + if (hextet & 0xC0) + goto _base64_decode_error; + word |= hextet << 4; + hextet = _base64_invcharmap[(int)buffer[len-2]]; + if (hextet & 0xC0) + goto _base64_decode_error; + word |= hextet >> 2; + *d++ = (word & 0xFF00) >> 8; + *d++ = (word & 0x00FF); + hextet = _base64_invcharmap[(int)buffer[len-1]]; + if (hextet != 64) + goto _base64_decode_error; + break; + } } - } - *d = '\0'; - return dbuf; - -_base64_decode_error: - /* invalid character; abort decoding! */ - xmpp_free(ctx, dbuf); - return NULL; -} - -/*** self tests ***/ -#ifdef TEST - -#include + if (d) + *d = '\0'; -int test_charmap_identity(void) -{ - int i, v, u; - - for (i = 0; i < 65; i++) { - v = _base64_charmap[i]; - if (v > 255) return 1; - u = _base64_invcharmap[v]; -/* printf("map: %d -> %d -> %d\n", i, v, u); */ - if (u != i) return 1; - } + return dbuf; - return 0; -} - -int test_charmap_range(void) -{ - int i, v; - - for (i = 64; i < 256; i++) { - v = _base64_invcharmap[i]; - if (i < 64) return 1; - } - - return 0; -} - -int main(int argc, char *argv[]) -{ - int ret = 0; - - printf("testing charmap identity..."); - ret = test_charmap_identity(); - if (ret) return ret; - printf(" ok.\n"); - - printf("testing charmap range..."); - ret = test_charmap_range(); - if (ret) return ret; - printf(" ok.\n"); - - printf("no error\n"); - return 0; +_base64_decode_error: + /* invalid character; abort decoding! */ + xmpp_free(ctx, dbuf); + return NULL; } - -#endif /* TEST */ diff --git a/src/sasl.h b/src/sasl.h index 09d5b8d0..5cc1e7b2 100644 --- a/src/sasl.h +++ b/src/sasl.h @@ -1,7 +1,7 @@ /* sasl.h ** strophe XMPP client library -- SASL authentication helpers -** -** Copyright (C) 2005-2009 Collecta, Inc. +** +** Copyright (C) 2005-2009 Collecta, Inc. ** ** This software is provided AS-IS with no warranty, either express ** or implied. @@ -19,7 +19,7 @@ #ifndef __LIBSTROPHE_SASL_H__ #define __LIBSTROPHE_SASL_H__ -#include "strophe.h" +#include "couplet.h" /** low-level sasl routines */ @@ -32,7 +32,7 @@ char *sasl_digest_md5(xmpp_ctx_t *ctx, const char *challenge, int base64_encoded_len(xmpp_ctx_t *ctx, const unsigned len); -char *base64_encode(xmpp_ctx_t *ctx, +char *base64_encode(xmpp_ctx_t *ctx, const unsigned char * const buffer, const unsigned len); int base64_decoded_len(xmpp_ctx_t *ctx, diff --git a/src/sha1.c b/src/sha1.c index ec4cb6c7..9001edd5 100644 --- a/src/sha1.c +++ b/src/sha1.c @@ -8,7 +8,7 @@ By Steve Reid 100% Public Domain ----------------- -Modified 7/98 +Modified 7/98 By James H. Brown Still 100% Public Domain @@ -30,7 +30,7 @@ Since the file IO in main() reads 16K at a time, any file 8K or larger would be guaranteed to generate the wrong hash (e.g. Test Vector #3, a million "a"s). -I also changed the declaration of variables i & j in SHA1Update to +I also changed the declaration of variables i & j in SHA1Update to unsigned long from unsigned int for the same reason. These changes should make no difference to any 32 bit implementations since @@ -57,7 +57,7 @@ Still 100% public domain Modified 4/01 By Saul Kravitz Still 100% PD -Modified to run on Compaq Alpha hardware. +Modified to run on Compaq Alpha hardware. ----------------- Modified 07/2002 @@ -91,7 +91,7 @@ A million repetitions of "a" typedef short int int16_t; typedef int int32_t; typedef __int64 int64_t; - + typedef unsigned char uint8_t; typedef unsigned short int uint16_t; typedef unsigned int uint32_t; @@ -130,7 +130,7 @@ void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64]); void SHAPrintContext(SHA1_CTX *context, char *msg){ printf("%s (%d,%d) %x %x %x %x %x\n", msg, - context->count[0], context->count[1], + context->count[0], context->count[1], context->state[0], context->state[1], context->state[2], @@ -259,7 +259,7 @@ void SHA1_Final(SHA1_CTX* context, uint8_t digest[SHA1_DIGEST_SIZE]) digest[i] = (uint8_t) ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255); } - + /* Wipe variables */ i = 0; memset(context->buffer, 0, 64); @@ -271,7 +271,7 @@ void SHA1_Final(SHA1_CTX* context, uint8_t digest[SHA1_DIGEST_SIZE]) SHA1_Transform(context->state, context->buffer); #endif } - + /*************************************************************/ #if 0 @@ -296,7 +296,7 @@ FILE* file; fputs("Unable to open file.", stderr); return(-1); } - } + } SHA1_Init(&context); while (!feof(file)) { /* note: what if ferror(file) */ i = fread(buffer, 1, 16384, file); @@ -327,13 +327,13 @@ static char *test_results[] = { "A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D", "84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1", "34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F"}; - + void digest_to_hex(const uint8_t digest[SHA1_DIGEST_SIZE], char *output) { int i,j; char *c = output; - + for (i = 0; i < SHA1_DIGEST_SIZE/4; i++) { for (j = 0; j < 4; j++) { sprintf(c,"%02X", digest[i*4+j]); @@ -344,7 +344,7 @@ void digest_to_hex(const uint8_t digest[SHA1_DIGEST_SIZE], char *output) } *(c - 1) = '\0'; } - + int main(int argc, char** argv) { int k; @@ -353,8 +353,8 @@ int main(int argc, char** argv) char output[80]; fprintf(stdout, "verifying SHA-1 implementation... "); - - for (k = 0; k < 2; k++){ + + for (k = 0; k < 2; k++){ SHA1_Init(&context); SHA1_Update(&context, (uint8_t*)test_data[k], strlen(test_data[k])); SHA1_Final(&context, digest); @@ -366,7 +366,7 @@ int main(int argc, char** argv) fprintf(stderr,"\t%s returned\n", output); fprintf(stderr,"\t%s is correct\n", test_results[k]); return (1); - } + } } /* million 'a' vector we feed separately */ SHA1_Init(&context); diff --git a/src/snprintf.c b/src/snprintf.c index bd1cdc3b..35531988 100644 --- a/src/snprintf.c +++ b/src/snprintf.c @@ -35,9 +35,9 @@ * original. Also, there is now a builtin-test, just compile with: * gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm * and run snprintf for results. - * + * * Thomas Roessler 01/27/98 for mutt 0.89i - * The PGP code was using unsigned hexadecimal formats. + * The PGP code was using unsigned hexadecimal formats. * Unfortunately, unsigned formats simply didn't work. * * Michael Elkins 03/05/98 for mutt 0.90.8 @@ -107,7 +107,7 @@ int xmpp_snprintf (char *str, size_t count, const char *fmt, ...); int xmpp_vsnprintf (char *str, size_t count, const char *fmt, va_list arg); -static int dopr (char *buffer, size_t maxlen, const char *format, +static int dopr (char *buffer, size_t maxlen, const char *format, va_list args); static int fmtstr (char *buffer, size_t *currlen, size_t maxlen, char *value, int flags, int min, int max); @@ -162,7 +162,7 @@ static int dopr (char *buffer, size_t maxlen, const char *format, va_list args) int cflags; int total; size_t currlen; - + state = DP_S_DEFAULT; currlen = flags = cflags = min = 0; max = -1; @@ -174,17 +174,17 @@ static int dopr (char *buffer, size_t maxlen, const char *format, va_list args) if (ch == '\0') state = DP_S_DONE; - switch(state) + switch(state) { case DP_S_DEFAULT: - if (ch == '%') + if (ch == '%') state = DP_S_FLAGS; - else + else total += dopr_outch (buffer, &currlen, maxlen, ch); ch = *format++; break; case DP_S_FLAGS: - switch (ch) + switch (ch) { case '-': flags |= DP_F_MINUS; @@ -212,49 +212,49 @@ static int dopr (char *buffer, size_t maxlen, const char *format, va_list args) } break; case DP_S_MIN: - if (isdigit(ch)) + if (isdigit(ch)) { min = 10*min + char_to_int (ch); ch = *format++; - } - else if (ch == '*') + } + else if (ch == '*') { min = va_arg (args, int); ch = *format++; state = DP_S_DOT; - } - else + } + else state = DP_S_DOT; break; case DP_S_DOT: - if (ch == '.') + if (ch == '.') { state = DP_S_MAX; ch = *format++; - } - else + } + else state = DP_S_MOD; break; case DP_S_MAX: - if (isdigit(ch)) + if (isdigit(ch)) { if (max < 0) max = 0; max = 10*max + char_to_int (ch); ch = *format++; - } - else if (ch == '*') + } + else if (ch == '*') { max = va_arg (args, int); ch = *format++; state = DP_S_MOD; - } - else + } + else state = DP_S_MOD; break; case DP_S_MOD: /* Currently, we don't support Long Long, bummer */ - switch (ch) + switch (ch) { case 'h': cflags = DP_C_SHORT; @@ -274,11 +274,11 @@ static int dopr (char *buffer, size_t maxlen, const char *format, va_list args) state = DP_S_CONV; break; case DP_S_CONV: - switch (ch) + switch (ch) { case 'd': case 'i': - if (cflags == DP_C_SHORT) + if (cflags == DP_C_SHORT) value = va_arg (args, int); else if (cflags == DP_C_LONG) value = va_arg (args, long int); @@ -355,19 +355,19 @@ static int dopr (char *buffer, size_t maxlen, const char *format, va_list args) max, flags); break; case 'n': - if (cflags == DP_C_SHORT) + if (cflags == DP_C_SHORT) { short int *num; num = va_arg (args, short int *); *num = currlen; - } - else if (cflags == DP_C_LONG) + } + else if (cflags == DP_C_LONG) { long int *num; num = va_arg (args, long int *); *num = currlen; - } - else + } + else { int *num; num = va_arg (args, int *); @@ -399,9 +399,9 @@ static int dopr (char *buffer, size_t maxlen, const char *format, va_list args) } if (buffer != NULL) { - if (currlen < maxlen - 1) + if (currlen < maxlen - 1) buffer[currlen] = '\0'; - else + else buffer[maxlen - 1] = '\0'; } return total; @@ -413,7 +413,7 @@ static int fmtstr (char *buffer, size_t *currlen, size_t maxlen, int padlen, strln; /* amount to pad */ int cnt = 0; int total = 0; - + if (value == 0) { value = ""; @@ -423,9 +423,9 @@ static int fmtstr (char *buffer, size_t *currlen, size_t maxlen, if (max >= 0 && max < strln) strln = max; padlen = min - strln; - if (padlen < 0) + if (padlen < 0) padlen = 0; - if (flags & DP_F_MINUS) + if (flags & DP_F_MINUS) padlen = -padlen; /* Left Justify */ while (padlen > 0) @@ -459,7 +459,7 @@ static int fmtint (char *buffer, size_t *currlen, size_t maxlen, int zpadlen = 0; /* amount to zero pad */ int caps = 0; int total = 0; - + if (max < 0) max = 0; @@ -478,7 +478,7 @@ static int fmtint (char *buffer, size_t *currlen, size_t maxlen, if (flags & DP_F_SPACE) signvalue = ' '; } - + if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */ do { @@ -499,7 +499,7 @@ static int fmtint (char *buffer, size_t *currlen, size_t maxlen, zpadlen = MAX(zpadlen, spadlen); spadlen = 0; } - if (flags & DP_F_MINUS) + if (flags & DP_F_MINUS) spadlen = -spadlen; /* Left Justifty */ #ifdef DEBUG_SNPRINTF @@ -508,18 +508,18 @@ static int fmtint (char *buffer, size_t *currlen, size_t maxlen, #endif /* Spaces */ - while (spadlen > 0) + while (spadlen > 0) { total += dopr_outch (buffer, currlen, maxlen, ' '); --spadlen; } /* Sign */ - if (signvalue) + if (signvalue) total += dopr_outch (buffer, currlen, maxlen, signvalue); /* Zeros */ - if (zpadlen > 0) + if (zpadlen > 0) { while (zpadlen > 0) { @@ -529,9 +529,9 @@ static int fmtint (char *buffer, size_t *currlen, size_t maxlen, } /* Digits */ - while (place > 0) + while (place > 0) total += dopr_outch (buffer, currlen, maxlen, convert[--place]); - + /* Left Justified spaces */ while (spadlen < 0) { total += dopr_outch (buffer, currlen, maxlen, ' '); @@ -560,7 +560,7 @@ static LDOUBLE _snp_pow10 (int exp) result *= 10; exp--; } - + return result; } @@ -586,13 +586,13 @@ static int fmtfp (char *buffer, size_t *currlen, size_t maxlen, int iplace = 0; int fplace = 0; int padlen = 0; /* amount to pad */ - int zpadlen = 0; + int zpadlen = 0; int caps = 0; int total = 0; long intpart; long fracpart; - - /* + + /* * AIX manpage says the default is 0, but Solaris says the default * is 6, and sprintf on AIX defaults to 6 */ @@ -616,8 +616,8 @@ static int fmtfp (char *buffer, size_t *currlen, size_t maxlen, intpart = ufvalue; - /* - * Sorry, we only support 9 digits past the decimal because of our + /* + * Sorry, we only support 9 digits past the decimal because of our * conversion method */ if (max > 9) @@ -657,18 +657,18 @@ static int fmtfp (char *buffer, size_t *currlen, size_t maxlen, fconvert[fplace] = 0; /* -1 for decimal point, another -1 if we are printing a sign */ - padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0); + padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0); zpadlen = max - fplace; if (zpadlen < 0) zpadlen = 0; - if (padlen < 0) + if (padlen < 0) padlen = 0; - if (flags & DP_F_MINUS) + if (flags & DP_F_MINUS) padlen = -padlen; /* Left Justifty */ - if ((flags & DP_F_ZERO) && (padlen > 0)) + if ((flags & DP_F_ZERO) && (padlen > 0)) { - if (signvalue) + if (signvalue) { total += dopr_outch (buffer, currlen, maxlen, signvalue); --padlen; @@ -685,10 +685,10 @@ static int fmtfp (char *buffer, size_t *currlen, size_t maxlen, total += dopr_outch (buffer, currlen, maxlen, ' '); --padlen; } - if (signvalue) + if (signvalue) total += dopr_outch (buffer, currlen, maxlen, signvalue); - while (iplace > 0) + while (iplace > 0) total += dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]); /* @@ -699,7 +699,7 @@ static int fmtfp (char *buffer, size_t *currlen, size_t maxlen, { total += dopr_outch (buffer, currlen, maxlen, '.'); - while (fplace > 0) + while (fplace > 0) total += dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]); } @@ -709,7 +709,7 @@ static int fmtfp (char *buffer, size_t *currlen, size_t maxlen, --zpadlen; } - while (padlen < 0) + while (padlen < 0) { total += dopr_outch (buffer, currlen, maxlen, ' '); ++padlen; @@ -749,7 +749,7 @@ int xmpp_snprintf (va_alist) va_dcl #endif VA_LOCAL_DECL; int total; - + VA_START (fmt); VA_SHIFT (str, char *); VA_SHIFT (count, size_t ); @@ -784,7 +784,7 @@ int main (void) "%.1f", NULL }; - double fp_nums[] = { -1.5, 134.21, 91340.2, 341.1234, 0203.9, 0.96, 0.996, + double fp_nums[] = { -1.5, 134.21, 91340.2, 341.1234, 0203.9, 0.96, 0.996, 0.9996, 1.996, 4.136, 0}; char *int_fmt[] = { "%-1.5d", @@ -812,7 +812,7 @@ int main (void) sprintf (buf2, fp_fmt[x], fp_nums[y]); if (strcmp (buf1, buf2)) { - printf("xmpp_snprintf doesn't match Format: %s\n\txmpp_snprintf = %s\n\tsprintf = %s\n", + printf("xmpp_snprintf doesn't match Format: %s\n\txmpp_snprintf = %s\n\tsprintf = %s\n", fp_fmt[x], buf1, buf2); fail++; } @@ -826,7 +826,7 @@ int main (void) sprintf (buf2, int_fmt[x], int_nums[y]); if (strcmp (buf1, buf2)) { - printf("xmpp_snprintf doesn't match Format: %s\n\txmpp_snprintf = %s\n\tsprintf = %s\n", + printf("xmpp_snprintf doesn't match Format: %s\n\txmpp_snprintf = %s\n\tsprintf = %s\n", int_fmt[x], buf1, buf2); fail++; } diff --git a/src/sock.c b/src/sock.c index d3f2798b..f9b42b3d 100644 --- a/src/sock.c +++ b/src/sock.c @@ -1,7 +1,7 @@ /* sock.c ** strophe XMPP client library -- socket abstraction implementation ** -** Copyright (C) 2005-2009 Collecta, Inc. +** Copyright (C) 2005-2009 Collecta, Inc. ** ** This software is provided AS-IS with no warranty, either express ** or implied. @@ -42,6 +42,7 @@ #endif #include "sock.h" +#include "couplet.h" void sock_initialize(void) { @@ -82,7 +83,7 @@ sock_t sock_connect(const char * const host, const unsigned int port) char service[6]; struct addrinfo *res, *ainfo, hints; int err; - + sock = -1; snprintf(service, 6, "%u", port); @@ -97,7 +98,7 @@ sock_t sock_connect(const char * const host, const unsigned int port) ainfo = res; while (ainfo) { - if ((sock = socket(ainfo->ai_family, ainfo->ai_socktype, + if ((sock = socket(ainfo->ai_family, ainfo->ai_socktype, ainfo->ai_protocol)) >= 0) { sock_set_nonblocking(sock); @@ -157,7 +158,7 @@ int sock_write(const sock_t sock, const void * const buff, const size_t len) int sock_is_recoverable(const int error) { #ifdef _WIN32 - return (error == WSAEINTR || error == WSAEWOULDBLOCK || + return (error == WSAEINTR || error == WSAEWOULDBLOCK || error == WSAEINPROGRESS); #else return (error == EAGAIN || error == EINTR); @@ -292,7 +293,7 @@ void netbuf_get_16bitnum(unsigned char *buf, int buflen, int *offset, unsigned s *offset += 2; } -void netbuf_add_domain_name(unsigned char *buf, int buflen, int *offset, +void netbuf_add_domain_name(unsigned char *buf, int buflen, int *offset, char *name) { unsigned char *start = buf + *offset; @@ -300,7 +301,7 @@ void netbuf_add_domain_name(unsigned char *buf, int buflen, int *offset, unsigned char *wordstart, *wordend; wordstart = (unsigned char *)name; - + while (*wordstart) { int len; @@ -426,7 +427,7 @@ int netbuf_get_domain_name(unsigned char *buf, int buflen, int *offset, char *na } partlen = *p++; - + for (i=0; i < partlen; i++) { *p2++ = *p++; @@ -451,7 +452,7 @@ void netbuf_add_dnsquery_header(unsigned char *buf, int buflen, int *offset, str unsigned char *p; netbuf_add_16bitnum(buf, buflen, offset, header->id); - + p = buf + *offset; *p++ = ((header->qr & 0x01) << 7) | ((header->opcode & 0x0F) << 3) @@ -472,7 +473,7 @@ void netbuf_add_dnsquery_header(unsigned char *buf, int buflen, int *offset, str void netbuf_get_dnsquery_header(unsigned char *buf, int buflen, int *offset, struct dnsquery_header *header) { unsigned char *p; - + netbuf_get_16bitnum(buf, buflen, offset, &(header->id)); p = buf + *offset; @@ -544,7 +545,7 @@ int sock_srv_lookup(const char *service, const char *proto, const char *domain, if (!set) { HINSTANCE hdnsapi = NULL; - + DNS_STATUS (WINAPI * pDnsQuery_A)(PCSTR, WORD, DWORD, PIP4_ARRAY, PDNS_RECORD*, PVOID*); void (WINAPI * pDnsRecordListFree)(PDNS_RECORD, DNS_FREE_TYPE); @@ -577,7 +578,7 @@ int sock_srv_lookup(const char *service, const char *proto, const char *domain, pDnsRecordListFree(dnsrecords, DnsFreeRecordList); } - + FreeLibrary(hdnsapi); } } @@ -655,7 +656,7 @@ int sock_srv_lookup(const char *service, const char *proto, const char *domain, { error = RegQueryValueEx(search, "DhcpNameServer", NULL, NULL, (LPBYTE)name, &len); } - + if (error == ERROR_SUCCESS) { char *parse = "0123456789.", *start, *end; @@ -867,24 +868,24 @@ int sock_srv_lookup(const char *service, const char *proto, const char *domain, if (!set) { unsigned char buf[65535]; int len; - + if ((len = res_query(fulldomain, C_IN, T_SRV, buf, 65535)) > 0) { int offset; int i; struct dnsquery_header header; struct dnsquery_question question; struct dnsquery_resourcerecord rr; - + offset = 0; netbuf_get_dnsquery_header(buf, 65536, &offset, &header); - + for (i = 0; i < header.qdcount; i++) { netbuf_get_dnsquery_question(buf, 65536, &offset, &question); } for (i = 0; i < header.ancount; i++) { netbuf_get_dnsquery_resourcerecord(buf, 65536, &offset, &rr); - + if (rr.type == 33) { struct dnsquery_srvrdata *srvrdata = &(rr.rdata); @@ -897,7 +898,7 @@ int sock_srv_lookup(const char *service, const char *proto, const char *domain, for (i = 0; i < header.ancount; i++) { netbuf_get_dnsquery_resourcerecord(buf, 65536, &offset, &rr); - } + } } } #endif @@ -905,7 +906,7 @@ int sock_srv_lookup(const char *service, const char *proto, const char *domain, if (!set) { snprintf(resulttarget, resulttargetlength, "%s", domain); - *resultport = 5222; + *resultport = XMPP_CLIENT_PORT; return 0; } diff --git a/src/sock.h b/src/sock.h index 4fd98ba4..0291f3a4 100644 --- a/src/sock.h +++ b/src/sock.h @@ -1,7 +1,7 @@ /* sock.h ** strophe XMPP client library -- socket abstraction header ** -** Copyright (C) 2005-2009 Collecta, Inc. +** Copyright (C) 2005-2009 Collecta, Inc. ** ** This software is provided AS-IS with no warranty, either express ** or implied. diff --git a/src/stanza.c b/src/stanza.c index 6bf11b80..135e9980 100644 --- a/src/stanza.c +++ b/src/stanza.c @@ -1,7 +1,7 @@ /* stanza.c ** strophe XMPP client library -- XMPP stanza object and utilities ** -** Copyright (C) 2005-2009 Collecta, Inc. +** Copyright (C) 2005-2009 Collecta, Inc. ** ** This software is provided AS-IS with no warranty, either express ** or implied. @@ -22,7 +22,7 @@ #include #include -#include "strophe.h" +#include "couplet.h" #include "common.h" #include "hash.h" @@ -58,12 +58,12 @@ xmpp_stanza_t *xmpp_stanza_new(xmpp_ctx_t *ctx) stanza->attributes = NULL; } - return stanza; + return stanza; } /** Clone a stanza object. * This function increments the reference count of the stanza object. - * + * * @param stanza a Strophe stanza object * * @return the stanza object with it's reference count incremented @@ -115,7 +115,7 @@ xmpp_stanza_t *xmpp_stanza_copy(const xmpp_stanza_t * const stanza) val = xmpp_strdup(stanza->ctx, (char *)hash_get(stanza->attributes, key)); if (!val) goto copy_error; - + if (hash_add(copy->attributes, key, val)) goto copy_error; } @@ -145,7 +145,7 @@ xmpp_stanza_t *xmpp_stanza_copy(const xmpp_stanza_t * const stanza) } /** Release a stanza object and all of its children. - * This function releases a stanza object and potentially all of its + * This function releases a stanza object and potentially all of its * children, which may cause the object(s) to be freed. * * @param stanza a Strophe stanza object @@ -181,11 +181,11 @@ int xmpp_stanza_release(xmpp_stanza_t * const stanza) } /** Determine if a stanza is a text node. - * + * * @param stanza a Strophe stanza object * * @return TRUE if the stanza is a text node, FALSE otherwise - * + * * @ingroup Stanza */ int xmpp_stanza_is_text(xmpp_stanza_t * const stanza) @@ -194,11 +194,11 @@ int xmpp_stanza_is_text(xmpp_stanza_t * const stanza) } /** Determine if a stanza is a tag node. - * + * * @param stanza a Strophe stanza object * * @return TRUE if the stanza is a tag node, FALSE otherwise - * + * * @ingroup Stanza */ int xmpp_stanza_is_tag(xmpp_stanza_t * const stanza) @@ -278,7 +278,7 @@ static int _render_stanza_recursive(xmpp_stanza_t *stanza, ret = xmpp_snprintf(ptr, left, ">"); if (ret < 0) return XMPP_EMEM; _render_update(&written, buflen, ret, &left, &ptr); - + /* iterate and recurse over child stanzas */ child = stanza->children; while (child) { @@ -293,7 +293,7 @@ static int _render_stanza_recursive(xmpp_stanza_t *stanza, /* write end tag */ ret = xmpp_snprintf(ptr, left, "", stanza->data); if (ret < 0) return XMPP_EMEM; - + _render_update(&written, buflen, ret, &left, &ptr); } } @@ -350,7 +350,7 @@ int xmpp_stanza_to_text(xmpp_stanza_t *stanza, ret = _render_stanza_recursive(stanza, buffer, length); if (ret > length - 1) return XMPP_EMEM; } - + buffer[length - 1] = 0; *buf = buffer; @@ -360,7 +360,7 @@ int xmpp_stanza_to_text(xmpp_stanza_t *stanza, } /** Set the name of a stanza. - * + * * @param stanza a Strophe stanza object * @param name a string with the name of the stanza * @@ -369,7 +369,7 @@ int xmpp_stanza_to_text(xmpp_stanza_t *stanza, * * @ingroup Stanza */ -int xmpp_stanza_set_name(xmpp_stanza_t *stanza, +int xmpp_stanza_set_name(xmpp_stanza_t *stanza, const char * const name) { if (stanza->type == XMPP_STANZA_TEXT) return XMPP_EINVOP; @@ -417,14 +417,14 @@ int xmpp_stanza_get_attribute_count(xmpp_stanza_t * const stanza) /** Get all attributes for a stanza object. * This function populates the array with attributes from the stanza. The - * attr array will be in the format: attr[i] = attribute name, + * attr array will be in the format: attr[i] = attribute name, * attr[i+1] = attribute value. * * @param stanza a Strophe stanza object * @param attr the string array to populate * @param attrlen the size of the array * - * @return the number of slots used in the array, which will be 2 times the + * @return the number of slots used in the array, which will be 2 times the * number of attributes in the stanza * * @ingroup Stanza @@ -461,7 +461,7 @@ int xmpp_stanza_get_attributes(xmpp_stanza_t * const stanza, } /** Set an attribute for a stanza object. - * + * * @param stanza a Strophe stanza object * @param key a string with the attribute name * @param value a string with the attribute value @@ -557,7 +557,7 @@ int xmpp_stanza_set_text(xmpp_stanza_t *stanza, const char * const text) { if (stanza->type == XMPP_STANZA_TAG) return XMPP_EINVOP; - + stanza->type = XMPP_STANZA_TEXT; if (stanza->data) xmpp_free(stanza->ctx, stanza->data); @@ -577,7 +577,7 @@ int xmpp_stanza_set_text(xmpp_stanza_t *stanza, * @param size the length of the text * * @return XMPP_EOK (0) on success and a number less than 0 on failure - * + * * @ingroup Stanza */ int xmpp_stanza_set_text_with_size(xmpp_stanza_t *stanza, @@ -654,7 +654,7 @@ char *xmpp_stanza_get_type(xmpp_stanza_t * const stanza) { if (stanza->type != XMPP_STANZA_TAG) return NULL; - + if (!stanza->attributes) return NULL; @@ -664,7 +664,7 @@ char *xmpp_stanza_get_type(xmpp_stanza_t * const stanza) /** Get the first child of stanza with name. * This function searches all the immediate children of stanza for a child * stanza that matches the name. The first matching child is returned. - * + * * @param stanza a Strophe stanza object * @param name a string with the name to match * @@ -672,11 +672,11 @@ char *xmpp_stanza_get_type(xmpp_stanza_t * const stanza) * * @ingroup Stanza */ -xmpp_stanza_t *xmpp_stanza_get_child_by_name(xmpp_stanza_t * const stanza, +xmpp_stanza_t *xmpp_stanza_get_child_by_name(xmpp_stanza_t * const stanza, const char * const name) { xmpp_stanza_t *child; - + for (child = stanza->children; child; child = child->next) { if (child->type == XMPP_STANZA_TAG && (strcmp(name, xmpp_stanza_get_name(child)) == 0)) @@ -690,7 +690,7 @@ xmpp_stanza_t *xmpp_stanza_get_child_by_name(xmpp_stanza_t * const stanza, * This function searches all the immediate children of a stanza for a child * stanza that matches the namespace provided. The first matching child * is returned. - * + * * @param stanza a Strophe stanza object * @param ns a string with the namespace to match * @@ -708,7 +708,7 @@ xmpp_stanza_t *xmpp_stanza_get_child_by_ns(xmpp_stanza_t * const stanza, strcmp(ns, xmpp_stanza_get_ns(child)) == 0) break; } - + return child; } @@ -723,13 +723,13 @@ xmpp_stanza_t *xmpp_stanza_get_child_by_ns(xmpp_stanza_t * const stanza, * * @ingroup Stanza */ -xmpp_stanza_t *xmpp_stanza_get_children(xmpp_stanza_t * const stanza) +xmpp_stanza_t *xmpp_stanza_get_children(xmpp_stanza_t * const stanza) { return stanza->children; } /** Get the next sibling of a stanza. - * + * * @param stanza a Strophe stanza object * * @return the next sibling stanza or NULL if there are no more siblings @@ -790,7 +790,7 @@ char *xmpp_stanza_get_text(xmpp_stanza_t * const stanza) /** Get the text data pointer for a text stanza. * This function copies returns the raw pointer to the text data in the - * stanza. This should only be used in very special cases where the + * stanza. This should only be used in very special cases where the * caller needs to translate the datatype as this will save a double * allocation. The caller should not hold onto this pointer, and is * responsible for allocating a copy if it needs one. @@ -859,7 +859,7 @@ char *xmpp_stanza_get_attribute(xmpp_stanza_t * const stanza, { if (stanza->type != XMPP_STANZA_TAG) return NULL; - + if (!stanza->attributes) return NULL; diff --git a/src/thread.c b/src/thread.c index 5a7e8c3d..4cd437e9 100644 --- a/src/thread.c +++ b/src/thread.c @@ -1,7 +1,7 @@ /* thread.c ** strophe XMPP client library -- thread abstraction ** -** Copyright (C) 2005-2009 Collecta, Inc. +** Copyright (C) 2005-2009 Collecta, Inc. ** ** This software is provided AS-IS with no warranty, either express ** or implied. @@ -26,94 +26,227 @@ #include #endif -#include "strophe.h" +#include "couplet.h" #include "common.h" #include "thread.h" struct _mutex_t { - const xmpp_ctx_t *ctx; + const xmpp_ctx_t *ctx; #ifdef _WIN32 - HANDLE mutex; + HANDLE mutex; #else - pthread_mutex_t *mutex; + pthread_mutex_t *mutex; #endif }; +struct _thread_t { + const xmpp_ctx_t *ctx; + +#ifdef _WIN32 +# error "win32 is not supported for now" +#else + pthread_t *thread; +#endif +}; + +struct _xmpp_sem_t { + const xmpp_ctx_t *ctx; + +#ifdef _WIN32 +# error "win32 is not supported for now" +#else + sem_t *sem; +#endif +}; + +/* semaphore functions */ + +xmpp_sem_t *xmpp_sem_create(const xmpp_ctx_t *ctx) +{ + xmpp_sem_t *sem; + + sem = xmpp_alloc(ctx, sizeof(xmpp_sem_t)); + if (!sem) + return NULL; + +#ifdef _WIN32 +# error "win32 is not supported for now" +#else + sem->sem = xmpp_alloc(ctx, sizeof(*sem->sem)); + if (sem->sem && sem_init(sem->sem, 0, 0)) { + /* semaphore is allocated but not initialized */ + xmpp_free(ctx, sem->sem); + sem->sem = NULL; + } +#endif + + if (!sem->sem) { + xmpp_free(ctx, sem); + sem = NULL; + } else + sem->ctx = ctx; + + return sem; +} + +void xmpp_sem_wait(xmpp_sem_t *sem) +{ +#ifdef _WIN32 +# error "win32 is not supported for now" +#else + sem_wait(sem->sem); +#endif +} + +void xmpp_sem_post(xmpp_sem_t *sem) +{ +#ifdef _WIN32 +# error "win32 is not supported for now" +#else + sem_post(sem->sem); +#endif +} + +int xmpp_sem_destroy(xmpp_sem_t *sem) +{ + const xmpp_ctx_t *ctx = NULL; + int ret = 1; + + if (sem) + ctx = sem->ctx; + if (!ctx) + return 0; + +#ifdef _WIN32 +# error "win32 is not supported for now" +#else + if (sem->sem) { + ret = sem_destroy(sem->sem) == 0; + xmpp_free(ctx, sem->sem); + } +#endif + xmpp_free(ctx, sem); + + return ret; +} + +/* thread functions */ + +thread_t *thread_create(const xmpp_ctx_t *ctx, thread_func_t start_func, void *arg) +{ + thread_t *thread; + + if (!ctx) + return NULL; + + thread = xmpp_alloc(ctx, sizeof(thread_t)); + if (!thread) + return NULL; + +#ifdef _WIN32 +# error "win32 is not supported for now" +#else + thread->thread = xmpp_alloc(ctx, sizeof(*thread->thread)); + if (thread->thread && + pthread_create(thread->thread, NULL, start_func, arg)) { + /* thread is allocated but not initialized */ + xmpp_free(ctx, thread->thread); + thread->thread = NULL; + } +#endif + + if (!thread->thread) { + xmpp_free(ctx, thread); + thread = NULL; + } else + thread->ctx = ctx; + + return thread; +} + /* mutex functions */ mutex_t *mutex_create(const xmpp_ctx_t * ctx) { - mutex_t *mutex; + mutex_t *mutex; + + mutex = xmpp_alloc(ctx, sizeof(mutex_t)); + if (!mutex) + return NULL; - mutex = xmpp_alloc(ctx, sizeof(mutex_t)); - if (mutex) { - mutex->ctx = ctx; #ifdef _WIN32 mutex->mutex = CreateMutex(NULL, FALSE, NULL); #else mutex->mutex = xmpp_alloc(ctx, sizeof(pthread_mutex_t)); - if (mutex->mutex) - if (pthread_mutex_init(mutex->mutex, NULL) != 0) { + if (mutex->mutex && pthread_mutex_init(mutex->mutex, NULL)) { + /* mutex is allocated but not initialized */ xmpp_free(ctx, mutex->mutex); mutex->mutex = NULL; - } + } #endif + if (!mutex->mutex) { - xmpp_free(ctx, mutex); - mutex = NULL; - } - } + xmpp_free(ctx, mutex); + mutex = NULL; + } else + mutex->ctx = ctx; - return mutex; + return mutex; } int mutex_destroy(mutex_t *mutex) { - int ret = 1; - const xmpp_ctx_t *ctx; + int ret = 1; + const xmpp_ctx_t *ctx = NULL; + + if (mutex) + ctx = mutex->ctx; + if (!ctx) + return XMPP_EMEM; #ifdef _WIN32 - if (mutex->mutex) - ret = CloseHandle(mutex->mutex); + if (mutex->mutex) + ret = CloseHandle(mutex->mutex); #else - if (mutex->mutex) - ret = pthread_mutex_destroy(mutex->mutex) == 0; + if (mutex->mutex) { + ret = pthread_mutex_destroy(mutex->mutex) == 0; + xmpp_free(ctx, mutex->mutex); + } #endif - ctx = mutex->ctx; - xmpp_free(ctx, mutex); + xmpp_free(ctx, mutex); - return ret; + return ret; } int mutex_lock(mutex_t *mutex) { - int ret; + int ret; #ifdef _WIN32 - ret = WaitForSingleObject(mutex->mutex, INFINITE) == 0; + ret = WaitForSingleObject(mutex->mutex, INFINITE) == 0; #else - ret = pthread_mutex_lock(mutex->mutex) == 0; + ret = pthread_mutex_lock(mutex->mutex) == 0; #endif - return ret; + return ret; } int mutex_trylock(mutex_t *mutex) { - /* TODO */ - return 0; + /* TODO */ + return 0; } int mutex_unlock(mutex_t *mutex) { - int ret; + int ret; #ifdef _WIN32 - ret = ReleaseMutex(mutex->mutex); + ret = ReleaseMutex(mutex->mutex); #else - ret = pthread_mutex_unlock(mutex->mutex) == 0; + ret = pthread_mutex_unlock(mutex->mutex) == 0; #endif - return ret; + return ret; } diff --git a/src/thread.h b/src/thread.h index 6dc155ab..41917a4d 100644 --- a/src/thread.h +++ b/src/thread.h @@ -1,7 +1,7 @@ /* thread.h ** strophe XMPP client library -- thread abstraction header ** -** Copyright (C) 2005-2009 Collecta, Inc. +** Copyright (C) 2005-2009 Collecta, Inc. ** ** This software is provided AS-IS with no warranty, either express ** or implied. @@ -26,11 +26,27 @@ #include #else #include +#include #endif -#include "strophe.h" +#include "couplet.h" typedef struct _mutex_t mutex_t; +typedef struct _thread_t thread_t; +typedef struct _xmpp_sem_t xmpp_sem_t; + +typedef void *(*thread_func_t) (void *); + +/* semaphore functions */ + +xmpp_sem_t *xmpp_sem_create(const xmpp_ctx_t *ctx); +void xmpp_sem_wait(xmpp_sem_t *sem); +void xmpp_sem_post(xmpp_sem_t *sem); +int xmpp_sem_destroy(xmpp_sem_t *sem); + +/* thread functions */ + +thread_t *thread_create(const xmpp_ctx_t *ctx, thread_func_t start_func, void *arg); /* mutex functions */ diff --git a/src/tls.h b/src/tls.h index fa670b91..5fd283e8 100644 --- a/src/tls.h +++ b/src/tls.h @@ -1,7 +1,7 @@ /* tls.h ** strophe XMPP client library -- TLS abstraction header ** -** Copyright (C) 2005-2009 Collecta, Inc. +** Copyright (C) 2005-2009 Collecta, Inc. ** ** This software is provided AS-IS with no warranty, either express ** or implied. diff --git a/src/tls_dummy.c b/src/tls_dummy.c index 00505fe5..e4843ee7 100644 --- a/src/tls_dummy.c +++ b/src/tls_dummy.c @@ -1,7 +1,7 @@ /* tls_dummy.c ** strophe XMPP client library -- TLS abstraction dummy impl. ** -** Copyright (C) 2005-2009 Collecta, Inc. +** Copyright (C) 2005-2009 Collecta, Inc. ** ** This software is provided AS-IS with no warranty, either express ** or implied. diff --git a/src/tls_gnutls.c b/src/tls_gnutls.c index 7841331f..6ca019eb 100644 --- a/src/tls_gnutls.c +++ b/src/tls_gnutls.c @@ -1,7 +1,7 @@ /* tls.c ** strophe XMPP client library -- TLS abstraction header ** -** Copyright (C) 2005-2009 Collecta, Inc. +** Copyright (C) 2005-2009 Collecta, Inc. ** ** This software is provided AS-IS with no warranty, either express ** or implied. @@ -62,7 +62,7 @@ tls_t *tls_new(xmpp_ctx_t *ctx, sock_t sock) gnutls_certificate_type_set_priority(tls->session, cert_type_priority); /* fixme: this may require setting a callback on win32? */ - gnutls_transport_set_ptr(tls->session, + gnutls_transport_set_ptr(tls->session, (gnutls_transport_ptr_t)sock); } @@ -85,7 +85,7 @@ int tls_set_credentials(tls_t *tls, const char *cafilename) cafilename, GNUTLS_X509_FMT_PEM); if (err < 0) return err; - err = gnutls_credentials_set(tls->session, GNUTLS_CRD_CERTIFICATE, + err = gnutls_credentials_set(tls->session, GNUTLS_CRD_CERTIFICATE, tls->cred); return err; diff --git a/src/tls_openssl.c b/src/tls_openssl.c index e0874680..5754d712 100644 --- a/src/tls_openssl.c +++ b/src/tls_openssl.c @@ -1,7 +1,7 @@ /* tls_openssl.c ** strophe XMPP client library -- TLS abstraction openssl impl. ** -** Copyright (C) 2005-008 Collecta, Inc. +** Copyright (C) 2005-008 Collecta, Inc. ** ** This software is provided AS-IS with no warranty, either express ** or implied. @@ -115,9 +115,9 @@ int tls_start(tls_t *tls) tv.tv_sec = 0; tv.tv_usec = 1000; - FD_ZERO(&fds); + FD_ZERO(&fds); FD_SET(tls->sock, &fds); - + select(tls->sock + 1, &fds, &fds, NULL, &tv); } } diff --git a/src/tls_schannel.c b/src/tls_schannel.c index c1db394e..2e356067 100644 --- a/src/tls_schannel.c +++ b/src/tls_schannel.c @@ -1,7 +1,7 @@ /* tls_schannel.c ** strophe XMPP client library -- TLS abstraction schannel impl. ** -** Copyright (C) 2005-2009 Collecta, Inc. +** Copyright (C) 2005-2009 Collecta, Inc. ** ** This software is provided AS-IS with no warranty, either express ** or implied. @@ -102,7 +102,7 @@ tls_t *tls_new(xmpp_ctx_t *ctx, sock_t sock) return NULL; } - if (!(pInitSecurityInterface = + if (!(pInitSecurityInterface = (void *)GetProcAddress(tls->hsec32, "InitSecurityInterfaceA"))) { tls_free(tls); return NULL; @@ -196,7 +196,7 @@ void tls_free(tls_t *tls) FreeLibrary(tls->hsec32); tls->hsec32 = NULL; } - + xmpp_free(tls->ctx, tls); return; } @@ -218,16 +218,16 @@ int tls_start(tls_t *tls) /* search the ctx's conns for our sock, and use the domain there as our * name */ { - xmpp_connlist_t *listentry = tls->ctx->connlist; + list_t *listentry = list_get_first(tls->ctx->connlist); while (listentry) { - xmpp_conn_t *conn = listentry->conn; + xmpp_conn_t *conn = (xmpp_conn_t *)listentry->data; if (conn->sock == tls->sock) { name = strdup(conn->domain); listentry = NULL; } else { - listentry = listentry->next; + listentry = list_get_next(tls->ctx->connlist, listentry); } } } @@ -297,7 +297,7 @@ int tls_start(tls_t *tls) FD_ZERO(&fds); FD_SET(tls->sock, &fds); - + select(tls->sock, &fds, NULL, NULL, &tv); } @@ -310,7 +310,7 @@ int tls_start(tls_t *tls) FD_ZERO(&fds); FD_SET(tls->sock, &fds); - + select(tls->sock, &fds, NULL, NULL, &tv); inbytes = sock_read(tls->sock, p, tls->spi->cbMaxToken - len); @@ -360,7 +360,7 @@ int tls_start(tls_t *tls) return 0; } - tls->sft->QueryContextAttributes(&(tls->hctxt), SECPKG_ATTR_STREAM_SIZES, + tls->sft->QueryContextAttributes(&(tls->hctxt), SECPKG_ATTR_STREAM_SIZES, &(tls->spcss)); tls->recvbuffermaxlen = tls->spcss.cbHeader + tls->spcss.cbMaximumMessage @@ -401,7 +401,7 @@ int tls_is_recoverable(int error) int tls_pending(tls_t *tls) { // There are 3 cases: // - there is data in ready buffer, so it is by default pending - // - there is data in recv buffer. If it is not decrypted yet, means it + // - there is data in recv buffer. If it is not decrypted yet, means it // was incomplete. This should be processed again only if there is data // on the physical connection // - there is data on the physical connection. This case is treated @@ -494,7 +494,7 @@ int tls_read(tls_t *tls, void * const buff, const size_t len) ret = tls->sft->DecryptMessage(&(tls->hctxt), &sbddec, 0, NULL); if (ret == SEC_E_OK) { - memcpy(tls->readybuffer, sbdec[1].pvBuffer, sbdec[1].cbBuffer); + memcpy(tls->readybuffer, sbdec[1].pvBuffer, sbdec[1].cbBuffer); tls->readybufferpos = 0; tls->readybufferlen = sbdec[1].cbBuffer; /* have we got some data left over? If so, copy it to the start @@ -626,8 +626,8 @@ int tls_write(tls_t *tls, const void * const buff, const size_t len) if (ret == -1 && !tls_is_recoverable(tls_error(tls))) { return -1; - } - + } + if (remain > tls->spcss.cbMaximumMessage) { sent += tls->spcss.cbMaximumMessage; remain -= tls->spcss.cbMaximumMessage; diff --git a/src/util.c b/src/util.c index c442fe71..1cef0a40 100644 --- a/src/util.c +++ b/src/util.c @@ -1,7 +1,7 @@ /* util.c ** strophe XMPP client library -- various utility functions ** -** Copyright (C) 2005-2009 Collecta, Inc. +** Copyright (C) 2005-2009 Collecta, Inc. ** ** This software is provided AS-IS with no warranty, either express ** or implied. @@ -27,7 +27,7 @@ #include #endif -#include "strophe.h" +#include "couplet.h" #include "common.h" #include "util.h" @@ -95,7 +95,7 @@ uint64_t time_elapsed(uint64_t t1, uint64_t t2) /** Disconnect the stream with a memory error. * This is a convenience function used internally by various parts of - * the Strophe library for terminating the connection because of a + * the Strophe library for terminating the connection because of a * memory error. * * @param conn a Strophe connection object diff --git a/src/util.h b/src/util.h index dc00381a..8ba11db2 100644 --- a/src/util.h +++ b/src/util.h @@ -1,7 +1,7 @@ /* util.h ** strophe XMPP client library -- various utility functions ** -** Copyright (C) 2005-2009 Collecta, Inc. +** Copyright (C) 2005-2009 Collecta, Inc. ** ** This software is provided AS-IS with no warranty, either express ** or implied. diff --git a/tests/check_parser.c b/tests/check_parser.c index 902d9e1a..5c332232 100644 --- a/tests/check_parser.c +++ b/tests/check_parser.c @@ -16,7 +16,7 @@ #include -#include +#include #include "parser.h" #include "test.h" diff --git a/tests/test_base64.c b/tests/test_base64.c index dd158c7a..6899ae1b 100644 --- a/tests/test_base64.c +++ b/tests/test_base64.c @@ -15,7 +15,7 @@ #include #include -#include "strophe.h" +#include "couplet.h" #include "common.h" #include "sasl.h" diff --git a/tests/test_ctx.c b/tests/test_ctx.c index 011b9141..1bbb44ab 100644 --- a/tests/test_ctx.c +++ b/tests/test_ctx.c @@ -16,7 +16,7 @@ #include #include -#include "strophe.h" +#include "couplet.h" #include "common.h" static int log_called = 0; diff --git a/tests/test_hash.c b/tests/test_hash.c index e4906e7f..3c007411 100644 --- a/tests/test_hash.c +++ b/tests/test_hash.c @@ -16,7 +16,7 @@ #include #include -#include "strophe.h" +#include "couplet.h" #include "common.h" #include "hash.h" diff --git a/tests/test_jid.c b/tests/test_jid.c index 6b921694..f40f0f17 100644 --- a/tests/test_jid.c +++ b/tests/test_jid.c @@ -15,7 +15,7 @@ #include #include -#include "strophe.h" +#include "couplet.h" #include "common.h" static const char jid1[] = "foo@bar.com"; diff --git a/tests/test_sasl.c b/tests/test_sasl.c index 829e5f81..3017224e 100644 --- a/tests/test_sasl.c +++ b/tests/test_sasl.c @@ -15,7 +15,7 @@ #include #include -#include "strophe.h" +#include "couplet.h" #include "common.h" #include "sasl.h"