66 Commits

Author SHA1 Message Date
Dmitry Podgorny
9dfe01bf83 WIP examples: PLAIN auth mechanism over raw connection 2017-07-15 21:38:46 +03:00
Dmitry Podgorny
b1b827cde6 conn: clear features support on connection reset
Features may be changed when client reconnects.
2017-07-15 21:32:55 +03:00
Dmitry Podgorny
e73b577e0b auth: use xmpp_iq_new() for iq stanzas 2017-07-15 20:35:16 +03:00
Dmitry Podgorny
8d2d59e914 tls/openssl: add OpenSSL-1.1.0 support (#109)
OpenSSL-1.1.0 marks cleanup functions as deprecated and changes
initialization function. It implements implicit de-initialization.

Reported by @zygmund2000.
2017-07-12 02:07:14 +03:00
Dmitry Podgorny
212f3ea760 snprintf: fix compilation with GCC 7 (#108)
GCC 7 enables -Wimplicit-fallthrough=3 with -Wextra. Add comments to
suppress these warning explicitly.

Reported by @akoww
2017-07-11 03:21:31 +03:00
Dmitry Podgorny
4aa7ea7e5b parser/expat: update #47
@curse666 suggested solution for #46 which reduces memory usage in expat
module. Current patch fixes few issues:
  - Inner text is lost for depth 1 stanzas
  - Incorrect handling of mixed xml <x>text<y/></x>
  - Reduced number of realloc() calls
2017-07-06 22:32:20 +03:00
curse666
5f9c0399c3 Update parser_expat.c
solution for #46.
2017-07-06 19:25:20 +03:00
Dmitry Podgorny
b83347b464 examples: use xmpp_iq_new() 2017-07-06 15:47:19 +03:00
Dmitry Podgorny
d8a86a54d5 event: set socket to wfds when sending queue is not empty
Don't sleep in select(2) when system is ready to send data.
2017-07-05 20:36:34 +03:00
Dmitry Podgorny
49289a9c05 event: reduce copy-paste 2017-07-05 20:34:38 +03:00
Dmitry Podgorny
456083d878 stanza: fix memory leaks
Free attribute "to" before replacing it in xmpp_stanza_reply().
Free value on insertion error in xmpp_stanza_set_attribute().
Don't copy attributes manually. Use xmpp_stanza_set_attribute() instead.
2017-07-05 20:20:45 +03:00
Dmitry Podgorny
15e7032f0d examples/bot: handle quit message 2017-07-05 19:40:25 +03:00
Dmitry Podgorny
cd2cf6eb23 ctx: set default event loop timeout to 1 second
Default timeout was 1 millisecond and it consumed CPU by running the
loop in xmpp_run(). The CPU usage was unacceptable and thus xmpp_run()
was not used by users. Also user can set the timeout by
xmpp_ctx_set_timeout() now.

Event loop already handles the situation when there is a timed handler
which needs to be run before the timeout is reached. Also system awakes
event loop when data arrives to socket.

The only drawback is when timed handler sends data it will be actually
sent after select(2) returns. But this situation can be handled easily by
adding socket to wfds when xmpp_conn_t contains data in sending queue.
2017-07-05 15:47:13 +03:00
Dmitry Podgorny
666995531a ChangeLog: mention recent changes
- Certificate verification is enabled for all openssl versions by
   default
 - xmpp_ctx_set_timeout()
 - Move xmpp_ctx_set_timeout() to event loop section in strophe.h
2017-07-04 19:22:26 +03:00
Dmitry Podgorny
9269d6b0d5 conn: add flag XMPP_CONN_FLAG_TRUST_TLS
TLS modules accept invalid server's certificates when the flag is set.
2017-07-04 17:20:33 +03:00
Dmitry Podgorny
c319ee6583 handler: fix memory leak and use-after-free errors
The errors are related to newly added handler_system_delete_all().
2017-07-01 16:24:30 +03:00
Dmitry Podgorny
cc53012cfa tls/openssl: enable cert verification for openssl older then 1.0.2
TODO: add flag to trust certificate even if verification fails.
2017-07-01 15:51:49 +03:00
Dmitry Podgorny
cc297eff45 handler: shut compiler up
Fixes the next warning:
    src/handler.c:683:25: error: ‘key2’ may be used uninitialized in
    this function [-Werror=uninitialized]

In fact key2 initialised and used under the same condition.
2017-06-29 20:43:03 +03:00
Dmitry Podgorny
e151096834 handler: don't call time_stamp() twice in handler_fire_timed() 2017-06-29 20:22:55 +03:00
Dmitry Podgorny
82040403bf tests/hash: enable the test 2017-06-29 20:22:55 +03:00
Dmitry Podgorny
a845c7ec3d hash: avoid allocation when replace value in hash_add()
Memory allocation may fail. We don't need to allocate new entry when we
already have one.
2017-06-29 20:22:55 +03:00
Dmitry Podgorny
5ecb0c5d0c conn: clear system handlers on reconnect
xmpp_conn_t object can be reused with saving user's handlers.
However, saving system handlers can lead to a fail during connection
process. This is because old object may contain timed handlers for
missed features or other handlers that would handle incoming stanzas
incorrectly.
2017-06-29 20:22:55 +03:00
Dmitry Podgorny
da8dc2d3cb auth: don't delete stream:error handler
Instead, keep the same handler until connection is disconnected. Stream
is opened 3 times during usual workflow. Deleting/restoring the handler
every time brings more places for possible mistakes.
2017-06-29 20:13:16 +03:00
Dmitry Podgorny
182695d1ca resolver: fix type mismatch in windows part
Backported from NetXMS project.
2017-06-29 20:00:25 +03:00
Dmitry Podgorny
0d039f7192 parser/libxml2: fix missed {} for multi-line block 2017-06-29 19:33:26 +03:00
Dmitry Podgorny
ebe97e8f2a travis-ci: don't use custom CFLAGS
Makefile.am provides -Wall and -Werror now.
2017-06-29 19:00:54 +03:00
Dmitry Podgorny
9505cace5e ctx: don't check whether log level is less than XMPP_LEVEL_DEBUG
XMPP_LEVEL_DEBUG is always 0.
2017-06-29 18:49:54 +03:00
Dmitry Podgorny
8ef027c54a ctx: fix indentation in xmpp_ctx_set_timeout() 2017-06-29 18:49:54 +03:00
Dmitry Podgorny
0bdb5f1d5b examples/vcard: fix warn_unused_result related to fwrite() 2017-06-29 18:49:54 +03:00
Steffen Jaeckel
49e7572059 fix function-pointer storage
the C standard says that you're not allowed to cast a function pointer to
something else

 6.3.2.3 §8:

A pointer to a function of one type may be converted to a pointer
to a function of another type and back again
2017-06-29 16:58:11 +02:00
Steffen Jaeckel
c074a6166c enable some warnings & fix 'em 2017-06-29 16:58:11 +02:00
Steffen Jaeckel
4c504ee42b add xmpp_ctx_set_timeout() 2017-06-29 16:58:11 +02:00
Steffen Jaeckel
f226891520 fix openssl memory leaks 2017-06-29 16:54:41 +02:00
Dmitry Podgorny
43a68479ad ChangeLog: mention about disabled insecure SSL/TLS
See f47609c1f0
2017-06-26 01:09:24 +03:00
Dmitry Podgorny
1e422a70dd crypto: add public function xmpp_sha1_digest()
For example, XEP-0115 requires binary digest to be base64-encoded.
Add short function to simplify such a digest computation for a single
buffer. This function doesn't allocate memory. Therefore, it can't
fail and doesn't require strophe context (xmpp_ctx_t).
2017-06-26 00:56:03 +03:00
Dmitry Podgorny
2a474bd809 tls/schannel: fix memory leak
Assume InitializeSecurityContext() doesn't change pszTargetName.
Reported by @youzpp in metajack/libstrophe#35.
2017-06-25 22:12:16 +03:00
Dmitry Podgorny
704c157d24 hash: don't use signed types during index calculation
Reported by @ITikhonov in pasis/libcouplet#10
2017-06-25 21:59:27 +03:00
Dmitry Podgorny
d8528b597c parser/libxml2: shorten parser_feed() 2017-06-25 21:19:15 +03:00
Dmitry Podgorny
c149caa32a examples: add vcard example
New exmaple shows how to request vCard and handle result. See XEP-0054
for details.
PHOTO element is stored to an image file.
2017-06-23 22:09:28 +03:00
Dmitry Podgorny
fa63aac731 auth: delete error handler before re-opening stream 2017-06-23 21:51:44 +03:00
Dmitry Podgorny
ba40bf1040 handler: fix possible corruption of handler lists
User's handler may delete other handlers. If deleted handler is the next
or the previous to the running one it leads to a list corruption.
Don't cache previous/next items when we walk through a handler's list.
2017-06-23 21:47:10 +03:00
Alexander Krotov
2f9bcfe145 Test xmpp_jid_bare 2017-06-23 20:00:41 +03:00
Alexander Krotov
b957213fdc Simplify xmpp_jid_{bare,domain,resource} 2017-06-23 19:55:12 +03:00
Alexander Krotov
f51b01a5b3 Remove unused mutex wrappers 2017-06-23 17:58:42 +03:00
Dmitry Podgorny
d2efc85ce3 Makefile.am: refactoring
Put filenames to separated lines to simplify adding/removing new files.
Add missed files to EXTRA_DIST.
2017-06-23 17:00:26 +03:00
Dmitry Podgorny
940d76e9e2 rpm: update dependencies 2017-06-23 16:57:27 +03:00
Dmitry Podgorny
59eb8d67ed ChangeLog: mention significant changes since 0.9.1 2017-06-23 16:55:31 +03:00
Dmitry Podgorny
78592650e5 tls/schannel: reflect changes of the tls interface
tls_new() accepts xmpp_conn_t object now.
2017-06-23 15:37:09 +03:00
Alexander Krotov
92d006a41b Disable hostname verification for pre-1.0.2 OpenSSL 2017-06-23 13:45:24 +03:00
Alexander Krotov
0741820711 Verify certificate hostname when using OpenSSL (fixes #100) 2017-06-23 03:00:26 +03:00
Alexander Krotov
c9ddc2b7ef Make tls_new accept xmpp_conn_t 2017-06-23 02:59:05 +03:00
Alexander Krotov
f776b34d8c Fix tls_openssl.c indentation 2017-06-22 19:44:41 +03:00
Alexander Krotov
f47609c1f0 Disable insecure SSL/TLS versions 2017-06-20 22:44:39 +03:00
Alexander Krotov
443b4d3116 Use more variables in bot.c message_handler()
to avoid calling the same function twice.
2017-06-20 01:38:53 +03:00
Steffen Jaeckel
4cf7a0cb79 split travis build into multiple jobs 2017-04-04 18:25:27 +02:00
Dmitry Podgorny
9a5fe8b96d handler: allow to add same handler callback with different userdata
According to #97. A single callback can distinguish different cases
using the userdata. Current implementation doesn't allow to delete a
particular couple (handler, userdata), but rather deletes all handlers
regardless of the userdata.
2017-03-24 22:38:16 +02:00
Dmitry Podgorny
80a7ea0b7c Fix spacing in handler.c 2016-12-02 16:56:45 +02:00
Dmitry Podgorny
1092447edf Fix spacing in c++ files 2016-09-27 15:40:08 +03:00
Dmitry Podgorny
d2c1daf4d5 Fix spacing in ctx.c and common.h 2016-09-27 15:14:38 +03:00
Dariusz Dwornikowski
d1a41c9d7d Fixed occurred spelling error fixes: #96 2016-09-23 08:31:31 +02:00
Dmitry Podgorny
9931ad4fa2 Updated ChangeLog
- Fixed bug #95 (DNS lookup failing on Cygwin)
- Removed dependency on the check package
2016-09-16 01:10:25 +03:00
Dmitry Podgorny
5a1f282292 README: remove mention of the check dependency 2016-09-16 01:07:21 +03:00
Dmitry Podgorny
b360316b8b tests/resolver: added test case with pointers 2016-09-16 01:01:43 +03:00
Dmitry Podgorny
c6aaa96dcb resolver: fixed few bugs
Fixed a bug which caused resolver to return a wrong target name with a
missed ".". The bug was in the part of message_name_get() where a pointer
is handled.
Added checks for buffer overflow.
Added 2 test cases to check a corner case and error handling.
2016-09-15 19:26:10 +03:00
Dmitry Podgorny
f0706f56c4 tests: remove dependency on check package
Only check_parser depends on the check. Convert it. All tests will be
rewritten at once when new testsuite is implemented.
2016-09-15 12:46:11 +03:00
James Booth
4ef2740c36 Update version to 0.9.1 2016-09-14 19:53:25 +01:00
47 changed files with 1821 additions and 915 deletions

2
.gitignore vendored
View File

@@ -34,8 +34,10 @@ examples/active
examples/basic
examples/bot
examples/component
examples/ext_auth
examples/roster
examples/uuid
examples/vcard
test_stamp
test-suite.log
tests/*.o

View File

@@ -2,10 +2,14 @@ language: c
install:
- sudo apt-get update
- sudo apt-get -y install libtool pkg-config libexpat1-dev libxml2-dev libssl-dev check
script:
before_script:
- ./bootstrap.sh
- ./configure --without-libxml2 && make CFLAGS="-Wall -Werror" && make CFLAGS="-Wall -Werror" check-TESTS
- make clean
- ./configure --with-libxml2 && make CFLAGS="-Wall -Werror" && make CFLAGS="-Wall -Werror" check-TESTS
- make clean
- ./configure --disable-tls && make CFLAGS="-Wall -Werror" && make CFLAGS="-Wall -Werror" check-TESTS
script:
- ./configure ${CONFIGURE_OPT} && make && make check-TESTS
env:
- CONFIGURE_OPT="--without-libxml2"
- CONFIGURE_OPT="--with-libxml2"
- CONFIGURE_OPT="--disable-tls --without-libxml2"
- CONFIGURE_OPT="--disable-tls --with-libxml2"
matrix:
fast_finish: true

View File

@@ -1,3 +1,21 @@
0.9.2
- OpenSSL tls module verifies certificate by default. Set flag
XMPP_CONN_FLAG_TRUST_TLS to ignore result of the verification
- Certificate hostname verification is forced for openssl-1.0.2 and
newer
- OpenSSL tls module disables insecure SSLv2 SSLv3 and TLSv1
- Support of handlers with the same callback function, but different
userdata
- System handlers are deleted on xmpp_conn_t reconnection. Old system
handlers could cause problems
- New functions:
- xmpp_ctx_set_timeout()
- xmpp_sha1_digest()
0.9.1
- Fixed bug #95 (DNS lookup failing on Cygwin)
- Removed dependency on the check package
0.9.0
- IPv6 support
- Legacy SSL support

View File

@@ -11,7 +11,7 @@ SSL_LIBS = @openssl_LIBS@
RESOLV_LIBS = @RESOLV_LIBS@
STROPHE_FLAGS = -I$(top_srcdir)
STROPHE_FLAGS = -I$(top_srcdir) -Wall -Wextra -Werror -Wno-unused-parameter
STROPHE_LIBS = libstrophe.la
## Main build targets
@@ -21,14 +21,42 @@ libstrophe_la_CFLAGS = $(SSL_CFLAGS) $(STROPHE_FLAGS) $(PARSER_CFLAGS)
libstrophe_la_LDFLAGS = $(SSL_LIBS) $(PARSER_LIBS) $(RESOLV_LIBS) -no-undefined
# Export only public API
libstrophe_la_LDFLAGS += -export-symbols-regex '^xmpp_'
libstrophe_la_SOURCES = src/auth.c src/conn.c src/crypto.c src/ctx.c \
src/event.c src/handler.c src/hash.c src/jid.c src/md5.c \
src/resolver.c src/sasl.c src/scram.c src/sha1.c \
src/snprintf.c src/sock.c src/stanza.c src/util.c \
src/rand.c src/uuid.c \
src/common.h src/hash.h src/md5.h src/ostypes.h src/parser.h \
src/resolver.h src/sasl.h src/scram.h src/sha1.h src/snprintf.h \
src/sock.h src/tls.h src/util.h src/rand.h
libstrophe_la_SOURCES = \
src/auth.c \
src/conn.c \
src/crypto.c \
src/ctx.c \
src/event.c \
src/handler.c \
src/hash.c \
src/jid.c \
src/md5.c \
src/rand.c \
src/resolver.c \
src/sasl.c \
src/scram.c \
src/sha1.c \
src/snprintf.c \
src/sock.c \
src/stanza.c \
src/util.c \
src/uuid.c
libstrophe_la_SOURCES += \
src/common.h \
src/hash.h \
src/md5.h \
src/ostypes.h \
src/parser.h \
src/rand.h \
src/resolver.h \
src/sasl.h \
src/scram.h \
src/sha1.h \
src/snprintf.h \
src/sock.h \
src/tls.h \
src/util.h
if DISABLE_TLS
libstrophe_la_SOURCES += src/tls_dummy.c
@@ -47,19 +75,37 @@ noinst_HEADERS = strophepp.h
pkgconfig_DATA = libstrophe.pc
EXTRA_DIST = docs rpm Doxyfile LICENSE.txt GPL-LICENSE.txt MIT-LICENSE.txt \
src/tls_dummy.c src/tls_gnutls.c src/tls_schannel.c \
examples/README.md
EXTRA_DIST = \
Doxyfile \
GPL-LICENSE.txt \
LICENSE.txt \
MIT-LICENSE.txt \
bootstrap.sh \
build-android.sh \
docs/footer.html \
examples/README.md \
jni/Android.mk \
jni/Application.mk \
rpm/README \
rpm/libstrophe.spec \
src/tls_gnutls.c \
src/tls_schannel.c \
tests/res_query_dump.c
## Examples
noinst_PROGRAMS = examples/active examples/roster examples/basic examples/bot \
examples/component examples/uuid
noinst_PROGRAMS = \
examples/active \
examples/basic \
examples/bot \
examples/component \
examples/ext_auth \
examples/roster \
examples/uuid \
examples/vcard
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)
@@ -69,21 +115,41 @@ examples_bot_LDADD = $(STROPHE_LIBS)
examples_component_SOURCES = examples/component.c
examples_component_CFLAGS = $(STROPHE_FLAGS)
examples_component_LDADD = $(STROPHE_LIBS)
examples_ext_auth_SOURCES = examples/ext_auth.c
examples_ext_auth_CFLAGS = $(STROPHE_FLAGS)
examples_ext_auth_LDADD = $(STROPHE_LIBS)
examples_roster_SOURCES = examples/roster.c
examples_roster_CFLAGS = $(STROPHE_FLAGS)
examples_roster_LDADD = $(STROPHE_LIBS)
examples_uuid_SOURCES = examples/uuid.c
examples_uuid_CFLAGS = $(STROPHE_FLAGS)
examples_uuid_LDADD = $(STROPHE_LIBS)
examples_vcard_SOURCES = examples/vcard.c
examples_vcard_CFLAGS = $(STROPHE_FLAGS)
examples_vcard_LDADD = $(STROPHE_LIBS)
## Tests
TESTS = tests/check_parser tests/test_sha1 tests/test_md5 tests/test_rand \
tests/test_scram tests/test_ctx tests/test_base64 tests/test_jid \
tests/test_snprintf tests/test_string tests/test_resolver
TESTS = \
tests/check_parser \
tests/test_sha1 \
tests/test_md5 \
tests/test_rand \
tests/test_scram \
tests/test_ctx \
tests/test_base64 \
tests/test_hash \
tests/test_jid \
tests/test_snprintf \
tests/test_string \
tests/test_resolver
check_PROGRAMS = $(TESTS)
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 = $(PARSER_CFLAGS) $(STROPHE_FLAGS) \
-I$(top_srcdir)/src
tests_check_parser_LDADD = @check_LIBS@ $(STROPHE_LIBS)
tests_check_parser_LDADD = $(STROPHE_LIBS)
tests_check_parser_LDFLAGS = -static
tests_test_ctx_SOURCES = tests/test_ctx.c
@@ -96,6 +162,11 @@ tests_test_base64_CFLAGS = $(STROPHE_FLAGS) -I$(top_srcdir)/src
tests_test_base64_LDADD = $(STROPHE_LIBS)
tests_test_base64_LDFLAGS = -static
tests_test_hash_SOURCES = tests/test_hash.c
tests_test_hash_CFLAGS = $(STROPHE_FLAGS) -I$(top_srcdir)/src
tests_test_hash_LDADD = $(STROPHE_LIBS)
tests_test_hash_LDFLAGS = -static
tests_test_jid_SOURCES = tests/test_jid.c
tests_test_jid_CFLAGS = $(STROPHE_FLAGS) -I$(top_srcdir)/src
tests_test_jid_LDADD = $(STROPHE_LIBS)

View File

@@ -58,9 +58,6 @@ libstrophe requires:
To build libstrophe using autotools you will need autoconf, automake,
libtool and pkg-config.
In addition, if you wish to run the unit tests, you will need the
check package.
Installation
------------

View File

@@ -1,4 +1,4 @@
AC_INIT([libstrophe], [0.9.0], [jack@metajack.im])
AC_INIT([libstrophe], [0.9.1], [jack@metajack.im])
AC_CONFIG_MACRO_DIR([m4])
AM_INIT_AUTOMAKE([foreign])
LT_INIT([dlopen])
@@ -22,9 +22,6 @@ AC_ARG_WITH([libxml2],
AC_ARG_ENABLE([tls],
[AS_HELP_STRING([--disable-tls], [disable TLS support])])
PKG_CHECK_MODULES([check], [check >= 0.9.4],
[], [AC_MSG_WARN([libcheck not found; unit tests will not be compilable])])
if test "x$enable_tls" != xno; then
PKG_CHECK_MODULES([openssl], [openssl],
[PC_REQUIRES="openssl ${PC_REQUIRES}"],

View File

@@ -55,10 +55,7 @@ void conn_handler(xmpp_conn_t * const conn, const xmpp_conn_event_t status,
fprintf(stderr, "DEBUG: connected\n");
/* create iq stanza for request */
iq = xmpp_stanza_new(ctx);
xmpp_stanza_set_name(iq, "iq");
xmpp_stanza_set_type(iq, "get");
xmpp_stanza_set_id(iq, "active1");
iq = xmpp_iq_new(ctx, "get", "active1");
xmpp_stanza_set_to(iq, "xxxxxxxxx.com");
query = xmpp_stanza_new(ctx);

View File

@@ -73,15 +73,19 @@ int version_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void
int message_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata)
{
xmpp_ctx_t *ctx = (xmpp_ctx_t*)userdata;
xmpp_stanza_t *reply;
xmpp_stanza_t *body, *reply;
const char *type;
char *intext, *replytext;
int quit = 0;
if (!xmpp_stanza_get_child_by_name(stanza, "body"))
body = xmpp_stanza_get_child_by_name(stanza, "body");
if (body == NULL)
return 1;
if (xmpp_stanza_get_type(stanza) != NULL && !strcmp(xmpp_stanza_get_type(stanza), "error"))
type = xmpp_stanza_get_type(stanza);
if (type != NULL && strcmp(type, "error") == 0)
return 1;
intext = xmpp_stanza_get_text(xmpp_stanza_get_child_by_name(stanza, "body"));
intext = xmpp_stanza_get_text(body);
printf("Incoming message from %s: %s\n", xmpp_stanza_get_from(stanza), intext);
@@ -89,15 +93,24 @@ int message_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void
if (xmpp_stanza_get_type(reply) == NULL)
xmpp_stanza_set_type(reply, "chat");
replytext = (char *) malloc(strlen(" to you too!") + strlen(intext) + 1);
strcpy(replytext, intext);
strcat(replytext, " to you too!");
if (strcmp(intext, "quit") == 0) {
replytext = strdup("bye!");
quit = 1;
} else {
replytext = (char *) malloc(strlen(" to you too!") + strlen(intext) + 1);
strcpy(replytext, intext);
strcat(replytext, " to you too!");
}
xmpp_free(ctx, intext);
xmpp_message_set_body(reply, replytext);
xmpp_send(conn, reply);
xmpp_stanza_release(reply);
free(replytext);
if (quit)
xmpp_disconnect(conn);
return 1;
}

290
examples/ext_auth.c Normal file
View File

@@ -0,0 +1,290 @@
/* ext_auth.c
* strophe XMPP client library -- PLAIN mechanism example with a raw connection
*
* Copyright (C) 2016 Dmitry Podgorny <pasis.ua@gmail.com>
*
* This software is provided AS-IS with no warranty, either express
* or implied.
*
* This program is dual licensed under the MIT and GPLv3 licenses.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strophe.h>
typedef struct {
xmpp_ctx_t *ctx;
const char *jid;
const char *pass;
char *domain;
int authenticated;
} xmpp_auth_t;
#define FEATURES_TIMEOUT 5000 /* 5 seconds */
static int _handle_error(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza,
void * const userdata)
{
fprintf(stderr, "DEBUG: received stream error\n");
xmpp_disconnect(conn);
return 0;
}
static int _handle_proceedtls_default(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza,
void * const userdata)
{
xmpp_auth_t *auth = (xmpp_auth_t *)userdata;
const char *name = xmpp_stanza_get_name(stanza);
(void)auth;
if (strcmp(name, "proceed") == 0) {
if (xmpp_conn_tls_start(conn) == 0) {
xmpp_handler_delete(conn, _handle_error);
xmpp_conn_open_stream_default(conn);
} else {
/* failed tls spoils the connection, so disconnect */
xmpp_disconnect(conn);
}
} else
xmpp_disconnect(conn);
return 0;
}
static int _plain_mechanim_exists(xmpp_ctx_t *ctx, xmpp_stanza_t *features)
{
xmpp_stanza_t *mechanisms;
xmpp_stanza_t *child;
char *text;
int found = 0;
mechanisms = xmpp_stanza_get_child_by_name(features, "mechanisms");
child = mechanisms ? xmpp_stanza_get_children(mechanisms) : NULL;
while (!found && mechanisms && child) {
/* TODO xmpp_stanza_get_name(child) is "mechanism" */
text = xmpp_stanza_get_text(child);
found = text && strcmp(text, "PLAIN") == 0;
xmpp_free(ctx, text);
child = xmpp_stanza_get_next(child);
}
return found;
}
static char *_plain_mechanism_authdata(xmpp_auth_t *auth)
{
char *node, *b64;
unsigned char *msg;
size_t node_len, pass_len;
node = xmpp_jid_node(auth->ctx, auth->jid);
node_len = strlen(node);
pass_len = strlen(auth->pass);
msg = malloc(node_len + pass_len + 2);
msg[0] = '\0';
memcpy(msg + 1, node, node_len);
msg[node_len + 1] = '\0';
memcpy(msg + node_len + 2, auth->pass, pass_len);
b64 = xmpp_base64_encode(auth->ctx, msg, node_len + pass_len + 2);
free(msg);
xmpp_free(auth->ctx, node);
return b64;
}
static int _plain_mechanism_handle_result(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza,
void * const userdata)
{
xmpp_auth_t *auth = (xmpp_auth_t *)userdata;
const char *name;
name = xmpp_stanza_get_name(stanza);
if (strcmp(name, "success") == 0) {
/* SASL PLAIN auth successful, we need to restart the stream */
fprintf(stderr, "DEBUG: SASL PLAIN auth successful\n");
auth->authenticated = 1;
xmpp_handler_delete(conn, _handle_error);
xmpp_conn_open_stream_default(conn);
} else {
fprintf(stderr, "DEBUG: SASL authentication failed: %s\n", name);
xmpp_disconnect(conn);
}
return 0;
}
static int _handle_missing_features(xmpp_conn_t * const conn,
void * const userdata)
{
fprintf(stderr, "DEBUG: timeout\n");
xmpp_disconnect(conn);
return 0;
}
static int _handle_features(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza,
void * const userdata)
{
xmpp_auth_t *auth = (xmpp_auth_t *)userdata;
xmpp_ctx_t *ctx = auth->ctx;
xmpp_stanza_t *plain, *child;
char *str;
xmpp_timed_handler_delete(conn, _handle_missing_features);
if (auth->authenticated) {
/* after successful SASL authentication */
/* TODO bind, session and we'are done */
xmpp_disconnect(conn); /* XXX */
return 0;
}
/* secure connection if possible */
child = xmpp_stanza_get_child_by_name(stanza, "starttls");
if (child && (strcmp(xmpp_stanza_get_ns(child), XMPP_NS_TLS) == 0)) {
child = xmpp_stanza_new(ctx);
xmpp_stanza_set_name(child, "starttls");
xmpp_stanza_set_ns(child, XMPP_NS_TLS);
xmpp_handler_add(conn, _handle_proceedtls_default,
XMPP_NS_TLS, NULL, NULL, userdata);
xmpp_send(conn, child);
xmpp_stanza_release(child);
return 0;
}
/* check if PLAIN mechanism is supported */
if (!_plain_mechanim_exists(ctx, stanza)) {
fprintf(stderr, "DEBUG: PLAIN mechanism is NOT supported\n");
xmpp_disconnect(conn);
return 0;
}
/* perform authentication */
plain = xmpp_stanza_new(ctx);
xmpp_stanza_set_name(plain, "auth");
xmpp_stanza_set_ns(plain, XMPP_NS_SASL);
xmpp_stanza_set_attribute(plain, "mechanism", "PLAIN");
str = _plain_mechanism_authdata(auth);
child = xmpp_stanza_new(ctx);
xmpp_stanza_set_text(child, str);
xmpp_free(ctx, str);
xmpp_stanza_add_child(plain, child);
xmpp_stanza_release(child);
xmpp_handler_add(conn, _plain_mechanism_handle_result,
XMPP_NS_SASL, NULL, NULL, userdata);
xmpp_send(conn, plain);
xmpp_stanza_release(plain);
return 0;
}
static void conn_handler(xmpp_conn_t * const conn,
const xmpp_conn_event_t status,
const int error,
xmpp_stream_error_t * const stream_error,
void * const userdata)
{
xmpp_auth_t *auth = (xmpp_auth_t *)userdata;
xmpp_ctx_t *ctx = auth->ctx;
int secured;
if (status == XMPP_CONN_RAW_CONNECT) {
fprintf(stderr, "DEBUG: raw connection established\n");
xmpp_conn_open_stream_default(conn);
} else if (status == XMPP_CONN_CONNECT) {
fprintf(stderr, "DEBUG: stream opened\n");
secured = xmpp_conn_is_secured(conn);
fprintf(stderr, "DEBUG: connection is %s.\n",
secured ? "secured" : "NOT secured");
/* setup handler for stream:error */
xmpp_handler_add(conn, _handle_error, XMPP_NS_STREAMS,
"error", NULL, NULL);
/* setup handlers for incoming <stream:features> */
xmpp_handler_add(conn, _handle_features, XMPP_NS_STREAMS,
"features", NULL, auth);
xmpp_timed_handler_add(conn, _handle_missing_features,
FEATURES_TIMEOUT, NULL);
} else {
fprintf(stderr, "DEBUG: disconnected\n");
xmpp_stop(ctx);
}
}
static xmpp_auth_t *xmpp_auth_new(void)
{
xmpp_auth_t *auth;
auth = malloc(sizeof(*auth));
if (auth != NULL) {
memset(auth, 0, sizeof(*auth));
}
return auth;
}
static void xmpp_auth_release(xmpp_auth_t *auth)
{
free(auth);
}
int main(int argc, char **argv)
{
xmpp_ctx_t *ctx;
xmpp_conn_t *conn;
xmpp_log_t *log;
xmpp_auth_t *auth;
const char *jid;
const char *pass;
const char *host = NULL;
if (argc < 3 || argc > 4) {
fprintf(stderr, "Usage: %s <jid> <pass> [<host>]\n", argv[0]);
return 1;
}
jid = argv[1];
pass = argv[2];
if (argc > 3)
host = argv[3];
/*
* Note, this example doesn't handle errors. Applications should check
* return values of non-void functions.
*/
xmpp_initialize();
log = xmpp_get_default_logger(XMPP_LEVEL_DEBUG);
ctx = xmpp_ctx_new(NULL, log);
conn = xmpp_conn_new(ctx);
xmpp_conn_set_jid(conn, jid);
/* private data */
auth = xmpp_auth_new();
auth->ctx = ctx;
auth->jid = jid;
auth->pass = pass;
auth->domain = xmpp_jid_domain(ctx, jid);
xmpp_connect_raw(conn, host, 0, conn_handler, auth);
xmpp_run(ctx);
/* release private data */
xmpp_auth_release(auth);
xmpp_conn_release(conn);
xmpp_ctx_free(ctx);
xmpp_shutdown();
return 0;
}

View File

@@ -62,10 +62,7 @@ void conn_handler(xmpp_conn_t * const conn, const xmpp_conn_event_t status,
fprintf(stderr, "DEBUG: connected\n");
/* create iq stanza for request */
iq = xmpp_stanza_new(ctx);
xmpp_stanza_set_name(iq, "iq");
xmpp_stanza_set_type(iq, "get");
xmpp_stanza_set_id(iq, "roster1");
iq = xmpp_iq_new(ctx, "get", "roster1");
query = xmpp_stanza_new(ctx);
xmpp_stanza_set_name(query, "query");

284
examples/vcard.c Normal file
View File

@@ -0,0 +1,284 @@
/* vcard.c
* strophe XMPP client library -- vCard example
*
* Copyright (C) 2016 Dmitry Podgorny <pasis.ua@gmail.com>
*
* This software is provided AS-IS with no warranty, either express
* or implied.
*
* This program is dual licensed under the MIT and GPLv3 licenses.
*/
#include <assert.h>
#include <libgen.h> /* basename */
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <strophe.h>
typedef struct {
xmpp_ctx_t *ctx;
const char *recipient;
const char *img_path;
} vcard_t;
typedef void (*vcard_cb_t)(vcard_t *, xmpp_stanza_t *);
#define REQ_TIMEOUT 5000
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
static void vcard_photo(vcard_t *vc, xmpp_stanza_t *stanza)
{
xmpp_stanza_t *tmp;
char *s;
char *tok;
char *saveptr = NULL;
char *copy;
unsigned char *img;
size_t img_size;
size_t written;
FILE *fd;
tmp = xmpp_stanza_get_child_by_name(stanza, "TYPE");
assert(tmp != NULL);
s = xmpp_stanza_get_text(tmp);
assert(s != NULL);
printf("PHOTO: %s, saving to file %s\n", s, vc->img_path);
xmpp_free(vc->ctx, s);
tmp = xmpp_stanza_get_child_by_name(stanza, "BINVAL");
assert(tmp != NULL);
s = xmpp_stanza_get_text(tmp);
assert(s != NULL);
/* remove \n and \r */
copy = (char *)malloc(strlen(s) + 1);
assert(copy != NULL);
copy[0] = '\0';
tok = strtok_r(s, "\n\r", &saveptr);
while (tok != NULL) {
strcat(copy, tok);
tok = strtok_r(NULL, "\n\r", &saveptr);
}
xmpp_base64_decode_bin(vc->ctx, copy, strlen(copy), &img, &img_size);
assert(img != NULL);
fd = fopen(vc->img_path, "w");
assert(fd != NULL);
written = fwrite(img, 1, img_size, fd);
if (written < img_size)
printf("Saving photo failed\n");
fclose(fd);
free(copy);
xmpp_free(vc->ctx, s);
xmpp_free(vc->ctx, img);
}
static void vcard_print_string(vcard_t *vc, xmpp_stanza_t *stanza,
const char *info)
{
char *s = xmpp_stanza_get_text(stanza);
assert(s != NULL);
printf("%s: %s\n", info, s);
xmpp_free(vc->ctx, s);
}
static void vcard_bday(vcard_t *vc, xmpp_stanza_t *stanza)
{
vcard_print_string(vc, stanza, "Birthday");
}
static void vcard_desc(vcard_t *vc, xmpp_stanza_t *stanza)
{
vcard_print_string(vc, stanza, "Description");
}
static void vcard_email(vcard_t *vc, xmpp_stanza_t *stanza)
{
xmpp_stanza_t *userid = xmpp_stanza_get_child_by_name(stanza, "USERID");
if (userid != NULL)
vcard_print_string(vc, userid, "E-mail");
}
static void vcard_fn(vcard_t *vc, xmpp_stanza_t *stanza)
{
vcard_print_string(vc, stanza, "Full name");
}
static void vcard_name(vcard_t *vc, xmpp_stanza_t *stanza)
{
xmpp_stanza_t *name = xmpp_stanza_get_child_by_name(stanza, "GIVEN");
xmpp_stanza_t *family = xmpp_stanza_get_child_by_name(stanza, "FAMILY");
if (name != NULL)
vcard_print_string(vc, name, "Given name");
if (family != NULL)
vcard_print_string(vc, family, "Family name");
}
static void vcard_nick(vcard_t *vc, xmpp_stanza_t *stanza)
{
vcard_print_string(vc, stanza, "Nickname");
}
static void vcard_url(vcard_t *vc, xmpp_stanza_t *stanza)
{
vcard_print_string(vc, stanza, "URL");
}
static vcard_cb_t vcard_cb_get(xmpp_stanza_t *stanza)
{
vcard_cb_t cb = NULL;
const char *tag;
size_t i;
static struct {
const char *tag;
vcard_cb_t cb;
} vcard_tbl[] = {
{ "PHOTO", vcard_photo },
{ "BDAY", vcard_bday },
{ "DESC", vcard_desc },
{ "EMAIL", vcard_email },
{ "FN", vcard_fn },
{ "N", vcard_name },
{ "NICKNAME", vcard_nick },
{ "URL", vcard_url },
};
tag = xmpp_stanza_get_name(stanza);
if (tag == NULL)
goto exit;
for (i = 0; i < ARRAY_SIZE(vcard_tbl); ++i) {
if (strcmp(tag, vcard_tbl[i].tag) == 0) {
cb = vcard_tbl[i].cb;
break;
}
}
exit:
return cb;
}
static int timedout(xmpp_conn_t * const conn, void * const userdata)
{
fprintf(stderr, "Timeout reached.\n");
xmpp_disconnect(conn);
return 0;
}
static int recv_vcard(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza,
void * const userdata)
{
vcard_t *vc = userdata;
vcard_cb_t cb;
xmpp_stanza_t *child;
char *s;
size_t s_size;
int rc;
printf("Received vCard.\n\n");
child = xmpp_stanza_get_child_by_name(stanza, "error");
if (child != NULL) {
rc = xmpp_stanza_to_text(child, &s, &s_size);
assert(rc == XMPP_EOK);
printf("Error returned: %s.\n", s);
xmpp_free(vc->ctx, s);
goto exit;
}
child = xmpp_stanza_get_child_by_name(stanza, "vCard");
assert(child != NULL);
child = xmpp_stanza_get_children(child);
while (child != NULL) {
cb = vcard_cb_get(child);
if (cb != NULL)
cb(vc, child);
child = xmpp_stanza_get_next(child);
}
exit:
xmpp_disconnect(conn);
return 0;
}
static void send_vcard_req(xmpp_conn_t *conn, const char *to, const char *id)
{
printf("Requesting vCard from %s.\n", to);
xmpp_send_raw_string(conn, "<iq from='%s' to='%s' type='get' id='%s'>"
"<vCard xmlns='vcard-temp'/></iq>",
xmpp_conn_get_bound_jid(conn), to, id);
}
static void conn_handler(xmpp_conn_t * const conn,
const xmpp_conn_event_t status,
const int error,
xmpp_stream_error_t * const stream_error,
void * const userdata)
{
vcard_t *vc = userdata;
if (status == XMPP_CONN_CONNECT) {
send_vcard_req(conn, vc->recipient, "vc1");
xmpp_id_handler_add(conn, recv_vcard, "vc1", vc);
xmpp_timed_handler_add(conn, timedout, REQ_TIMEOUT, NULL);
} else {
if (error != 0)
fprintf(stderr, "Disconnected with error=%d.\n", error);
if (stream_error != NULL)
fprintf(stderr, "Stream error type=%d text=%s.\n",
stream_error->type, stream_error->text);
xmpp_stop(vc->ctx);
}
}
int main(int argc, char **argv)
{
xmpp_log_t *log;
xmpp_ctx_t *ctx;
xmpp_conn_t *conn;
const char *jid;
const char *pass;
char *prog;
vcard_t vcard;
if (argc < 4 || argc > 5) {
prog = argc > 0 ? strdup(argv[0]) : NULL;
printf("Usage: %s <login-jid> <password> <recipient-jid> "
"[image-file]\n\n", prog == NULL ? "vcard" : basename(prog));
printf("If vCard contains a photo it will be stored to "
"image-file. If you don't provide the image-file "
"default filename will be generated.\n");
free(prog);
return 1;
}
jid = argv[1];
pass = argv[2];
vcard.recipient = argv[3];
vcard.img_path = argc > 4 ? argv[4] : "vcard.jpg";
xmpp_initialize();
log = xmpp_get_default_logger(XMPP_LEVEL_INFO);
ctx = xmpp_ctx_new(NULL, log);
conn = xmpp_conn_new(ctx);
xmpp_conn_set_jid(conn, jid);
xmpp_conn_set_pass(conn, pass);
vcard.ctx = ctx;
xmpp_connect_client(conn, NULL, 0, conn_handler, &vcard);
xmpp_run(ctx);
xmpp_conn_release(conn);
xmpp_ctx_free(ctx);
xmpp_shutdown();
return 0;
}

View File

@@ -1,6 +1,6 @@
1. Setup
yum install gcc make expat-devel libstrophe
yum install gcc make autoconf automake expat-devel openssl-devel
Fedora:

View File

@@ -8,10 +8,12 @@ License: MIT/GPLv3
URL: http://strophe.im/libstrophe/
Source0: libstrophe_git.tar.gz
BuildRequires: autoconf
BuildRequires: automake
BuildRequires: libtool
BuildRequires: openssl-devel
BuildRequires: expat-devel
Requires: openssl
Requires: expat
%description

View File

@@ -62,6 +62,7 @@
static void _auth(xmpp_conn_t * const conn);
static void _handle_open_sasl(xmpp_conn_t * const conn);
static void _handle_open_tls(xmpp_conn_t * const conn);
static int _handle_component_auth(xmpp_conn_t * const conn);
static int _handle_component_hs_response(xmpp_conn_t * const conn,
@@ -288,7 +289,7 @@ static int _handle_proceedtls_default(xmpp_conn_t * const conn,
xmpp_debug(conn->ctx, "xmpp", "proceeding with TLS");
if (conn_tls_start(conn) == 0) {
conn_prepare_reset(conn, auth_handle_open);
conn_prepare_reset(conn, _handle_open_tls);
conn_open_stream(conn);
} else {
/* failed tls spoils the connection, so disconnect */
@@ -315,7 +316,7 @@ static int _handle_sasl_result(xmpp_conn_t * const conn,
/* fall back to next auth method */
_auth(conn);
} else if (strcmp(name, "success") == 0) {
/* SASL PLAIN auth successful, we need to restart the stream */
/* SASL auth successful, we need to restart the stream */
xmpp_debug(conn->ctx, "xmpp", "SASL %s auth successful",
(char *)userdata);
@@ -564,7 +565,7 @@ static void _auth(xmpp_conn_t * const conn)
}
if (conn->tls_support) {
tls_t *tls = tls_new(conn->ctx, conn->sock);
tls_t *tls = tls_new(conn);
/* If we couldn't init tls, it isn't there, so go on */
if (!tls) {
@@ -721,14 +722,11 @@ static void _auth(xmpp_conn_t * const conn)
} else if (conn->type == XMPP_CLIENT) {
/* legacy client authentication */
iq = xmpp_stanza_new(conn->ctx);
iq = xmpp_iq_new(conn->ctx, "set", "_xmpp_auth1");
if (!iq) {
disconnect_mem_error(conn);
return;
}
xmpp_stanza_set_name(iq, "iq");
xmpp_stanza_set_type(iq, "set");
xmpp_stanza_set_id(iq, "_xmpp_auth1");
query = xmpp_stanza_new(conn->ctx);
if (!query) {
@@ -838,15 +836,23 @@ void auth_handle_open(xmpp_conn_t * const conn)
/* reset all timed handlers */
handler_reset_timed(conn, 0);
/* setup handler for stream:error */
handler_add(conn, _handle_error,
XMPP_NS_STREAMS, "error", NULL, NULL);
/* setup handler for stream:error, we will keep this handler
* for reopened streams until connection is disconnected */
handler_add(conn, _handle_error, XMPP_NS_STREAMS, "error", NULL, NULL);
/* setup handlers for incoming <stream:features> */
handler_add(conn, _handle_features,
XMPP_NS_STREAMS, "features", NULL, NULL);
handler_add_timed(conn, _handle_missing_features,
FEATURES_TIMEOUT, NULL);
handler_add_timed(conn, _handle_missing_features, FEATURES_TIMEOUT, NULL);
}
/* called when stream:stream tag received after TLS establishment */
static void _handle_open_tls(xmpp_conn_t * const conn)
{
/* setup handlers for incoming <stream:features> */
handler_add(conn, _handle_features,
XMPP_NS_STREAMS, "features", NULL, NULL);
handler_add_timed(conn, _handle_missing_features, FEATURES_TIMEOUT, NULL);
}
/* called when stream:stream tag received after SASL auth */
@@ -896,16 +902,12 @@ static int _handle_features_sasl(xmpp_conn_t * const conn,
BIND_TIMEOUT, NULL);
/* send bind request */
iq = xmpp_stanza_new(conn->ctx);
iq = xmpp_iq_new(conn->ctx, "set", "_xmpp_bind1");
if (!iq) {
disconnect_mem_error(conn);
return 0;
}
xmpp_stanza_set_name(iq, "iq");
xmpp_stanza_set_type(iq, "set");
xmpp_stanza_set_id(iq, "_xmpp_bind1");
bind = xmpp_stanza_copy(bind);
if (!bind) {
xmpp_stanza_release(iq);
@@ -1008,20 +1010,17 @@ static int _handle_bind(xmpp_conn_t * const conn,
SESSION_TIMEOUT, NULL);
/* send session request */
iq = xmpp_stanza_new(conn->ctx);
iq = xmpp_iq_new(conn->ctx, "set", "_xmpp_session1");
if (!iq) {
disconnect_mem_error(conn);
return 0;
}
xmpp_stanza_set_name(iq, "iq");
xmpp_stanza_set_type(iq, "set");
xmpp_stanza_set_id(iq, "_xmpp_session1");
session = xmpp_stanza_new(conn->ctx);
if (!session) {
xmpp_stanza_release(iq);
disconnect_mem_error(conn);
return 0;
}
xmpp_stanza_set_name(session, "session");

View File

@@ -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.
@@ -50,38 +50,40 @@ struct _xmpp_ctx_t {
xmpp_rand_t *rand;
xmpp_loop_status_t loop_status;
xmpp_connlist_t *connlist;
unsigned long timeout;
};
/* 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,
const size_t size);
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,
const xmpp_log_level_t level,
const char * const area,
const char * const fmt,
va_list ap);
void xmpp_log(const xmpp_ctx_t * const ctx,
const xmpp_log_level_t level,
const char * const area,
const char * const fmt,
va_list ap);
/* wrappers for xmpp_log at specific levels */
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,
...);
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,
...);
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,
...);
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,
...);
/** connection **/
@@ -105,29 +107,29 @@ typedef struct _xmpp_handlist_t xmpp_handlist_t;
struct _xmpp_handlist_t {
/* common members */
int user_handler;
void *handler;
int (*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 */
* 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;
};
/* timed handlers */
struct {
unsigned long period;
uint64_t last_stamp;
};
/* id handlers */
struct {
char *id;
};
/* normal handlers */
struct {
char *ns;
char *name;
char *type;
};
};
};
@@ -166,9 +168,10 @@ struct _xmpp_conn_t {
int tls_disabled;
int tls_mandatory;
int tls_legacy_ssl;
int tls_trust;
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 */
mechanisms */
int secured; /* set when stream is secured with TLS */
/* if server returns <bind/> or <session/> we must do them */
@@ -196,7 +199,7 @@ struct _xmpp_conn_t {
/* timeouts */
unsigned int connect_timeout;
/* event handlers */
/* event handlers */
/* stream open handler */
xmpp_open_handler open_handler;
@@ -247,23 +250,24 @@ struct _xmpp_stanza_t {
/* handler management */
void handler_fire_stanza(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza);
xmpp_stanza_t * const stanza);
uint64_t handler_fire_timed(xmpp_ctx_t * const ctx);
void handler_reset_timed(xmpp_conn_t *conn, int user_only);
void handler_add_timed(xmpp_conn_t * const conn,
xmpp_timed_handler handler,
const unsigned long period,
void * const userdata);
xmpp_timed_handler handler,
const unsigned long period,
void * const userdata);
void handler_add_id(xmpp_conn_t * const conn,
xmpp_handler handler,
const char * const id,
void * const userdata);
xmpp_handler handler,
const char * const id,
void * const userdata);
void handler_add(xmpp_conn_t * const conn,
xmpp_handler handler,
const char * const ns,
const char * const name,
const char * const type,
void * const userdata);
xmpp_handler handler,
const char * const ns,
const char * const name,
const char * const type,
void * const userdata);
void handler_system_delete_all(xmpp_conn_t *conn);
/* utility functions */
void disconnect_mem_error(xmpp_conn_t * const conn);

View File

@@ -128,6 +128,7 @@ xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t * const ctx)
conn->tls_disabled = 0;
conn->tls_mandatory = 0;
conn->tls_legacy_ssl = 0;
conn->tls_trust = 0;
conn->tls_failed = 0;
conn->sasl_support = 0;
conn->secured = 0;
@@ -264,6 +265,8 @@ int xmpp_conn_release(xmpp_conn_t * const conn)
}
}
_conn_reset(conn);
/* free handler stuff
* note that userdata is the responsibility of the client
* and the handler pointers don't need to be freed since they
@@ -305,7 +308,6 @@ int xmpp_conn_release(xmpp_conn_t * const conn)
}
parser_free(conn->parser);
_conn_reset(conn);
if (conn->jid) xmpp_free(ctx, conn->jid);
if (conn->pass) xmpp_free(ctx, conn->pass);
@@ -874,7 +876,7 @@ int conn_tls_start(xmpp_conn_t * const conn)
conn->tls = NULL;
rc = XMPP_EINVOP;
} else {
conn->tls = tls_new(conn->ctx, conn->sock);
conn->tls = tls_new(conn);
rc = conn->tls == NULL ? XMPP_EMEM : 0;
}
@@ -910,7 +912,8 @@ long xmpp_conn_get_flags(const xmpp_conn_t * const conn)
flags = XMPP_CONN_FLAG_DISABLE_TLS * conn->tls_disabled |
XMPP_CONN_FLAG_MANDATORY_TLS * conn->tls_mandatory |
XMPP_CONN_FLAG_LEGACY_SSL * conn->tls_legacy_ssl;
XMPP_CONN_FLAG_LEGACY_SSL * conn->tls_legacy_ssl |
XMPP_CONN_FLAG_TRUST_TLS * conn->tls_trust;
return flags;
}
@@ -927,6 +930,7 @@ long xmpp_conn_get_flags(const xmpp_conn_t * const conn)
* - XMPP_CONN_FLAG_DISABLE_TLS
* - XMPP_CONN_FLAG_MANDATORY_TLS
* - XMPP_CONN_FLAG_LEGACY_SSL
* - XMPP_CONN_FLAG_TRUST_TLS
*
* @param conn a Strophe connection object
* @param flags ORed connection flags
@@ -943,7 +947,8 @@ int xmpp_conn_set_flags(xmpp_conn_t * const conn, long flags)
return XMPP_EINVOP;
}
if (flags & XMPP_CONN_FLAG_DISABLE_TLS &&
flags & (XMPP_CONN_FLAG_MANDATORY_TLS | XMPP_CONN_FLAG_LEGACY_SSL)) {
flags & (XMPP_CONN_FLAG_MANDATORY_TLS | XMPP_CONN_FLAG_LEGACY_SSL |
XMPP_CONN_FLAG_TRUST_TLS)) {
xmpp_error(conn->ctx, "conn", "Flags 0x%04lx conflict", flags);
return XMPP_EINVOP;
}
@@ -951,6 +956,7 @@ int xmpp_conn_set_flags(xmpp_conn_t * const conn, long flags)
conn->tls_disabled = (flags & XMPP_CONN_FLAG_DISABLE_TLS) ? 1 : 0;
conn->tls_mandatory = (flags & XMPP_CONN_FLAG_MANDATORY_TLS) ? 1 : 0;
conn->tls_legacy_ssl = (flags & XMPP_CONN_FLAG_LEGACY_SSL) ? 1 : 0;
conn->tls_trust = (flags & XMPP_CONN_FLAG_TRUST_TLS) ? 1 : 0;
return 0;
}
@@ -1215,6 +1221,12 @@ static void _conn_reset(xmpp_conn_t * const conn)
conn->secured = 0;
conn->tls_failed = 0;
conn->error = 0;
conn->tls_support = 0;
conn->bind_required = 0;
conn->session_required = 0;
handler_system_delete_all(conn);
}
static int _conn_connect(xmpp_conn_t * const conn,

View File

@@ -81,7 +81,35 @@ char *xmpp_sha1(xmpp_ctx_t *ctx, const unsigned char *data, size_t len)
return digest_to_string_alloc(ctx, digest);
}
/** Compute SHA1 message digest
* Stores digest in user's buffer which must be at least XMPP_SHA1_DIGEST_SIZE
* bytes long.
*
* @param data buffer for digest computation
* @param len size of the data buffer
* @param digest output buffer of XMPP_SHA1_DIGEST_SIZE bytes
*
* @ingroup Digests
*/
void xmpp_sha1_digest(const unsigned char *data, size_t len,
unsigned char *digest)
{
crypto_SHA1((const uint8_t *)data, len, digest);
}
/** Create new SHA1 object
* SHA1 object is used to compute SHA1 digest of a buffer that is split
* in multiple chunks or provided in stream mode. A single buffer can be
* processed by short functions xmpp_sha1() and xmpp_sha1_digest().
* Follow the next use-case for xmpp_sha1_t object:
* @code
* xmpp_sha1_t *sha1 = xmpp_sha1_new(ctx);
* // Repeat update for all chunks of data
* xmpp_sha1_update(sha1, data, len);
* xmpp_sha1_final(sha1);
* char *digest = xmpp_sha1_to_string_alloc(sha1);
* xmpp_sha1_free(sha1);
* @endcode
*
* @param ctx a Strophe context onject
*

139
src/ctx.c
View File

@@ -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 program is dual licensed under the MIT and GPLv3 licenses.
@@ -36,7 +36,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.
*/
@@ -91,6 +91,14 @@ void xmpp_shutdown(void)
#define LIBXMPP_VERSION_MINOR (0)
#endif
#ifndef EVENT_LOOP_DEFAULT_TIMEOUT
/** @def EVENT_LOOP_DEFAULT_TIMEOUT
* The default timeout in milliseconds for the event loop.
* This is set to 1 second.
*/
#define EVENT_LOOP_DEFAULT_TIMEOUT 1000
#endif
/** Check that Strophe supports a specific API version.
*
* @param major the major version number
@@ -103,12 +111,12 @@ void xmpp_shutdown(void)
int xmpp_version_check(int major, int minor)
{
return (major == LIBXMPP_VERSION_MAJOR) &&
(minor >= LIBXMPP_VERSION_MINOR);
(minor >= LIBXMPP_VERSION_MINOR);
}
/* We define the global default allocator, logger, and context here. */
/* Wrap stdlib routines malloc, free, and realloc for default memory
/* Wrap stdlib routines malloc, free, and realloc for default memory
* management.
*/
static void *_malloc(const size_t size, void * const userdata)
@@ -137,9 +145,9 @@ static xmpp_mem_t xmpp_default_mem = {
/* log levels and names */
static const char * const _xmpp_log_level_name[4] = {"DEBUG", "INFO", "WARN", "ERROR"};
static const xmpp_log_level_t _xmpp_default_logger_levels[] = {XMPP_LEVEL_DEBUG,
XMPP_LEVEL_INFO,
XMPP_LEVEL_WARN,
XMPP_LEVEL_ERROR};
XMPP_LEVEL_INFO,
XMPP_LEVEL_WARN,
XMPP_LEVEL_ERROR};
/** Log a message.
* The default logger writes to stderr.
@@ -151,20 +159,20 @@ static const xmpp_log_level_t _xmpp_default_logger_levels[] = {XMPP_LEVEL_DEBUG,
* @param msg the log message
*/
static void xmpp_default_logger(void * const userdata,
const xmpp_log_level_t level,
const char * const area,
const char * const msg)
const xmpp_log_level_t level,
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);
fprintf(stderr, "%s %s %s\n", area, _xmpp_log_level_name[level], msg);
}
static const xmpp_log_t _xmpp_default_loggers[] = {
{&xmpp_default_logger, (void*)&_xmpp_default_logger_levels[XMPP_LEVEL_DEBUG]},
{&xmpp_default_logger, (void*)&_xmpp_default_logger_levels[XMPP_LEVEL_INFO]},
{&xmpp_default_logger, (void*)&_xmpp_default_logger_levels[XMPP_LEVEL_WARN]},
{&xmpp_default_logger, (void*)&_xmpp_default_logger_levels[XMPP_LEVEL_ERROR]}
{&xmpp_default_logger, (void*)&_xmpp_default_logger_levels[XMPP_LEVEL_DEBUG]},
{&xmpp_default_logger, (void*)&_xmpp_default_logger_levels[XMPP_LEVEL_INFO]},
{&xmpp_default_logger, (void*)&_xmpp_default_logger_levels[XMPP_LEVEL_WARN]},
{&xmpp_default_logger, (void*)&_xmpp_default_logger_levels[XMPP_LEVEL_ERROR]}
};
/** Get a default logger with filtering.
@@ -182,7 +190,6 @@ 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;
return (xmpp_log_t*)&_xmpp_default_loggers[level];
}
@@ -192,7 +199,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
@@ -225,7 +232,7 @@ void xmpp_free(const xmpp_ctx_t * const ctx, void *p)
* @return a pointer to the reallocated memory or NULL on an error
*/
void *xmpp_realloc(const xmpp_ctx_t * const ctx, void *p,
const size_t size)
const size_t size)
{
return ctx->mem->realloc(p, size, ctx->mem->userdata);
}
@@ -234,7 +241,7 @@ void *xmpp_realloc(const xmpp_ctx_t * const ctx, void *p,
* 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
@@ -244,10 +251,10 @@ void *xmpp_realloc(const xmpp_ctx_t * const ctx, void *p,
* @param ap variable argument list supplied for the format string
*/
void xmpp_log(const xmpp_ctx_t * const ctx,
const xmpp_log_level_t level,
const char * const area,
const char * const fmt,
va_list ap)
const xmpp_log_level_t level,
const char * const area,
const char * const fmt,
va_list ap)
{
int oldret, ret;
char smbuf[1024];
@@ -257,23 +264,23 @@ void xmpp_log(const xmpp_ctx_t * const ctx,
va_copy(copy, ap);
ret = xmpp_vsnprintf(smbuf, sizeof(smbuf), fmt, ap);
if (ret >= (int)sizeof(smbuf)) {
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");
xmpp_free(ctx, buf);
va_end(copy);
return;
}
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");
xmpp_free(ctx, buf);
va_end(copy);
return;
}
} else {
buf = smbuf;
buf = smbuf;
}
va_end(copy);
@@ -286,7 +293,7 @@ void xmpp_log(const xmpp_ctx_t * const ctx,
/** 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
@@ -386,34 +393,35 @@ void xmpp_debug(const xmpp_ctx_t * const ctx,
*
* @ingroup Context
*/
xmpp_ctx_t *xmpp_ctx_new(const xmpp_mem_t * const mem,
const xmpp_log_t * const log)
xmpp_ctx_t *xmpp_ctx_new(const xmpp_mem_t * const mem,
const xmpp_log_t * const log)
{
xmpp_ctx_t *ctx = NULL;
if (mem == NULL)
ctx = xmpp_default_mem.alloc(sizeof(xmpp_ctx_t), NULL);
ctx = xmpp_default_mem.alloc(sizeof(xmpp_ctx_t), NULL);
else
ctx = mem->alloc(sizeof(xmpp_ctx_t), mem->userdata);
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 (mem != NULL)
ctx->mem = mem;
else
ctx->mem = &xmpp_default_mem;
if (log == NULL)
ctx->log = &xmpp_default_log;
else
ctx->log = log;
if (log == NULL)
ctx->log = &xmpp_default_log;
else
ctx->log = log;
ctx->connlist = NULL;
ctx->loop_status = XMPP_LOOP_NOTSTARTED;
ctx->rand = xmpp_rand_new(ctx);
if (ctx->rand == NULL) {
xmpp_free(ctx, ctx);
ctx = NULL;
}
ctx->connlist = NULL;
ctx->loop_status = XMPP_LOOP_NOTSTARTED;
ctx->rand = xmpp_rand_new(ctx);
ctx->timeout = EVENT_LOOP_DEFAULT_TIMEOUT;
if (ctx->rand == NULL) {
xmpp_free(ctx, ctx);
ctx = NULL;
}
}
return ctx;
@@ -432,3 +440,14 @@ void xmpp_ctx_free(xmpp_ctx_t * const ctx)
xmpp_free(ctx, ctx); /* pull the hole in after us */
}
/** Set the timeout to use when calling xmpp_run().
*
* @param ctx a Strophe context object
* @param timeout the time to wait for events in milliseconds
*
* @ingroup Context
*/
void xmpp_ctx_set_timeout(xmpp_ctx_t * const ctx, const unsigned long timeout)
{
ctx->timeout = timeout;
}

View File

@@ -51,14 +51,6 @@
#include "common.h"
#include "parser.h"
#ifndef DEFAULT_TIMEOUT
/** @def DEFAULT_TIMEOUT
* The default timeout in milliseconds for the event loop.
* This is set to 1 millisecond.
*/
#define DEFAULT_TIMEOUT 1
#endif
/** 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
@@ -104,8 +96,8 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
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.");
/* an error occurred */
xmpp_debug(ctx, "xmpp", "Send error occurred, disconnecting.");
conn->error = ECONNABORTED;
conn_disconnect(conn);
}
@@ -118,30 +110,17 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
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 */
if (ret < 0 && !tls_is_recoverable(tls_error(conn->tls)))
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;
}
} else {
ret = sock_write(conn->sock, &sq->data[sq->written], towrite);
if (ret < 0 && !sock_is_recoverable(sock_error())) {
/* an error occured */
if (ret < 0 && !sock_is_recoverable(sock_error()))
conn->error = sock_error();
break;
} else if (ret < towrite) {
/* not all data could be sent now */
if (ret >= 0) sq->written += ret;
break;
}
}
if (ret > 0 && ret < towrite)
sq->written += ret; /* not all data could be sent now */
if (ret != towrite)
break; /* partial write or an error */
/* all data for this queue item written, delete and move on */
xmpp_free(ctx, sq->data);
@@ -160,7 +139,7 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
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.");
xmpp_debug(ctx, "xmpp", "Send error occurred, disconnecting.");
conn->error = ECONNABORTED;
conn_disconnect(conn);
}
@@ -175,9 +154,8 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
}
/* fire any ready timed handlers, then
make sure we don't wait past the time when timed handlers need
to be called */
/* 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;
@@ -209,6 +187,8 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
break;
case XMPP_STATE_CONNECTED:
FD_SET(conn->sock, &rfds);
if (conn->send_queue_len > 0)
FD_SET(conn->sock, &wfds);
break;
case XMPP_STATE_DISCONNECTED:
/* do nothing */
@@ -217,9 +197,8 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
}
/* Check if there is something in the SSL buffer. */
if (conn->tls) {
if (conn->tls)
tls_read_bytes += tls_pending(conn->tls);
}
if (conn->state != XMPP_STATE_DISCONNECTED && conn->sock > max)
max = conn->sock;
@@ -290,8 +269,7 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
}
} else {
if (conn->tls) {
if (!tls_is_recoverable(tls_error(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);
@@ -333,7 +311,7 @@ void xmpp_run(xmpp_ctx_t *ctx)
ctx->loop_status = XMPP_LOOP_RUNNING;
while (ctx->loop_status == XMPP_LOOP_RUNNING) {
xmpp_run_once(ctx, DEFAULT_TIMEOUT);
xmpp_run_once(ctx, ctx->timeout);
}
/* make it possible to start event loop again */

View File

@@ -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.
@@ -24,6 +24,31 @@
#include "common.h"
#include "ostypes.h"
/* Remove item from the list pointed by head, but don't free it.
* There can be a situation when user's handler deletes another handler which
* is the previous in the list. handler_fire_stanza() and handler_fire_timed()
* must handle this situation correctly. Current function helps to avoid
* list corruption in described scenario.
*
* TODO Convert handler lists to double-linked lists. Current implementation
* works for O(n).
*/
static void _handler_item_remove(xmpp_handlist_t **head,
xmpp_handlist_t *item)
{
xmpp_handlist_t *i = *head;
if (i == item)
*head = item->next;
else if (i != NULL) {
while (i->next != NULL && i->next != item)
i = i->next;
if (i->next == item) {
i->next = item->next;
}
}
}
/** Fire off all stanza handlers that match.
* This function is called internally by the event loop whenever stanzas
* are received from the XMPP server.
@@ -32,92 +57,83 @@
* @param stanza a Strophe stanza object
*/
void handler_fire_stanza(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza)
xmpp_stanza_t * const stanza)
{
xmpp_handlist_t *item, *prev;
xmpp_handlist_t *item, *next, *head, *head_old;
const char *id, *ns, *name, *type;
int ret;
/* 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;
head = (xmpp_handlist_t *)hash_get(conn->id_handlers, id);
/* enable all added handlers */
for (item = head; item; item = item->next)
item->enabled = 1;
if (item->user_handler && !conn->authenticated) {
item = next;
continue;
}
item = head;
while (item) {
/* don't fire user handlers until authentication succeeds and
and skip newly added handlers */
if ((item->user_handler && !conn->authenticated) || !item->enabled) {
item = 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);
}
ret = ((xmpp_handler)(item->handler))(conn, stanza, item->userdata);
next = item->next;
if (!ret) {
/* handler is one-shot, so delete it */
head_old = head;
_handler_item_remove(&head, item);
if (head != head_old) {
/* replace old value */
hash_add(conn->id_handlers, id, head);
}
xmpp_free(conn->ctx, item->id);
xmpp_free(conn->ctx, item);
item = NULL;
}
if (item)
prev = item;
item = next;
}
xmpp_free(conn->ctx, 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;
item->enabled = 1;
prev = NULL;
item = conn->handlers;
while (item) {
/* skip newly added handlers */
if (!item->enabled) {
prev = item;
item = item->next;
continue;
}
/* don't fire user handlers until authentication succeeds and
skip newly added handlers */
if ((item->user_handler && !conn->authenticated) || !item->enabled) {
item = item->next;
continue;
}
/* don't call user handlers until authentication succeeds */
if (item->user_handler && !conn->authenticated) {
prev = item;
item = item->next;
continue;
}
next = item->next;
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 ((!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;
ret = ((xmpp_handler)(item->handler))(conn, stanza, item->userdata);
/* list may be changed during execution of a handler */
next = item->next;
if (!ret) {
/* handler is one-shot, so delete it */
_handler_item_remove(&conn->handlers, item);
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;
xmpp_free(conn->ctx, item);
}
}
item = next;
}
}
@@ -131,57 +147,56 @@ 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;
xmpp_handlist_t *item, *next;
xmpp_conn_t *conn;
uint64_t elapsed, min;
uint64_t timestamp;
int ret;
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;
conn = connitem->conn;
if (conn->state != XMPP_STATE_CONNECTED) {
connitem = connitem->next;
continue;
}
handitem = connitem->conn->timed_handlers;
while (handitem) {
/* skip newly added handlers */
if (!handitem->enabled) {
handitem = handitem->next;
continue;
}
/* enable all handlers that were added */
for (item = conn->timed_handlers; item; item = item->next)
item->enabled = 1;
/* only fire user handlers after authentication */
if (handitem->user_handler && !connitem->conn->authenticated) {
handitem = handitem->next;
continue;
}
item = conn->timed_handlers;
while (item) {
/* don't fire user handlers until authentication succeeds and
skip newly added handlers */
if ((item->user_handler && !conn->authenticated) || !item->enabled) {
item = item->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;
next = item->next;
timestamp = time_stamp();
elapsed = time_elapsed(item->last_stamp, timestamp);
if (elapsed >= item->period) {
/* fire! */
item->last_stamp = timestamp;
ret = ((xmpp_timed_handler)item->handler)(conn, item->userdata);
/* list may be changed during execution of a handler */
next = item->next;
if (!ret) {
/* delete handler if it returned false */
_handler_item_remove(&conn->timed_handlers, item);
xmpp_free(conn->ctx, item);
}
} else if (min > (item->period - elapsed))
min = item->period - elapsed;
/* delete handler if it returned false */
if (fired && !ret)
xmpp_timed_handler_delete(connitem->conn, temp->handler);
}
item = next;
}
connitem = connitem->next;
connitem = connitem->next;
}
return min;
@@ -199,25 +214,27 @@ void handler_reset_timed(xmpp_conn_t *conn, int user_only)
handitem = conn->timed_handlers;
while (handitem) {
if ((user_only && handitem->user_handler) || !user_only)
handitem->last_stamp = time_stamp();
handitem = handitem->next;
if ((user_only && handitem->user_handler) || !user_only)
handitem->last_stamp = time_stamp();
handitem = handitem->next;
}
}
static void _timed_handler_add(xmpp_conn_t * const conn,
xmpp_timed_handler handler,
const unsigned long period,
void * const userdata,
const int user_handler)
xmpp_timed_handler handler,
const unsigned long period,
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->handler == handler && item->userdata == userdata) {
xmpp_warn(conn->ctx, "xmpp", "Timed handler already exists.");
break;
}
}
if (item) return;
@@ -226,7 +243,7 @@ static void _timed_handler_add(xmpp_conn_t * const conn,
if (!item) return;
item->user_handler = user_handler;
item->handler = (void *)handler;
item->handler = handler;
item->userdata = userdata;
item->enabled = 0;
item->next = NULL;
@@ -236,12 +253,12 @@ static void _timed_handler_add(xmpp_conn_t * const conn,
/* append item to list */
if (!conn->timed_handlers)
conn->timed_handlers = item;
conn->timed_handlers = item;
else {
tail = conn->timed_handlers;
while (tail->next)
tail = tail->next;
tail->next = item;
tail = conn->timed_handlers;
while (tail->next)
tail = tail->next;
tail->next = item;
}
}
@@ -253,7 +270,7 @@ static void _timed_handler_add(xmpp_conn_t * const conn,
* @ingroup Handlers
*/
void xmpp_timed_handler_delete(xmpp_conn_t * const conn,
xmpp_timed_handler handler)
xmpp_timed_handler handler)
{
xmpp_handlist_t *item, *prev;
@@ -262,35 +279,36 @@ void xmpp_timed_handler_delete(xmpp_conn_t * const conn,
prev = NULL;
item = conn->timed_handlers;
while (item) {
if (item->handler == (void *)handler)
break;
prev = item;
item = item->next;
}
if (item->handler == handler) {
if (prev)
prev->next = item->next;
else
conn->timed_handlers = item->next;
if (item) {
if (prev)
prev->next = item->next;
else
conn->timed_handlers = item->next;
xmpp_free(conn->ctx, item);
xmpp_free(conn->ctx, item);
item = prev ? prev->next : conn->timed_handlers;
} else {
prev = item;
item = item->next;
}
}
}
static void _id_handler_add(xmpp_conn_t * const conn,
xmpp_handler handler,
const char * const id,
void * const userdata, int user_handler)
xmpp_handler handler,
const char * const id,
void * const userdata, int user_handler)
{
xmpp_handlist_t *item, *tail;
/* check if handler is already in the list */
item = (xmpp_handlist_t *)hash_get(conn->id_handlers, id);
while (item) {
if (item->handler == (void *)handler)
break;
item = item->next;
if (item->handler == handler && item->userdata == userdata) {
xmpp_warn(conn->ctx, "xmpp", "Id handler already exists.");
break;
}
item = item->next;
}
if (item) return;
@@ -299,25 +317,25 @@ static void _id_handler_add(xmpp_conn_t * const conn,
if (!item) return;
item->user_handler = user_handler;
item->handler = (void *)handler;
item->handler = handler;
item->userdata = userdata;
item->enabled = 0;
item->next = NULL;
item->id = xmpp_strdup(conn->ctx, id);
if (!item->id) {
xmpp_free(conn->ctx, item);
return;
xmpp_free(conn->ctx, item);
return;
}
/* put on list in hash table */
tail = (xmpp_handlist_t *)hash_get(conn->id_handlers, id);
if (!tail)
hash_add(conn->id_handlers, id, item);
hash_add(conn->id_handlers, id, item);
else {
while (tail->next)
tail = tail->next;
tail->next = item;
while (tail->next)
tail = tail->next;
tail->next = item;
}
}
@@ -330,49 +348,54 @@ static void _id_handler_add(xmpp_conn_t * const conn,
* @ingroup Handlers
*/
void xmpp_id_handler_delete(xmpp_conn_t * const conn,
xmpp_handler handler,
const char * const id)
xmpp_handler handler,
const char * const id)
{
xmpp_handlist_t *item, *prev;
xmpp_handlist_t *item, *prev, *next;
prev = NULL;
item = (xmpp_handlist_t *)hash_get(conn->id_handlers, id);
if (!item) return;
while (item) {
if (item->handler == (void *)handler)
break;
next = item->next;
prev = item;
item = item->next;
}
if (item->handler == handler) {
if (prev)
prev->next = next;
else {
hash_drop(conn->id_handlers, id);
hash_add(conn->id_handlers, id, next);
}
if (item) {
if (prev)
prev->next = item->next;
else {
hash_drop(conn->id_handlers, id);
hash_add(conn->id_handlers, id, item->next);
}
xmpp_free(conn->ctx, item->id);
xmpp_free(conn->ctx, item);
xmpp_free(conn->ctx, item->id);
xmpp_free(conn->ctx, item);
item = next;
} else {
prev = item;
item = next;
}
}
}
/* add a stanza handler */
static void _handler_add(xmpp_conn_t * const conn,
xmpp_handler handler,
const char * const ns,
const char * const name,
const char * const type,
void * const userdata, int user_handler)
xmpp_handler handler,
const char * const ns,
const char * const name,
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;
/* same handler function can process different stanzas and
distinguish them according to userdata. */
if (item->handler == handler && item->userdata == userdata) {
xmpp_warn(conn->ctx, "xmpp", "Stanza handler already exists.");
break;
}
}
if (item) return;
@@ -381,46 +404,46 @@ static void _handler_add(xmpp_conn_t * const conn,
if (!item) return;
item->user_handler = user_handler;
item->handler = (void *)handler;
item->handler = 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;
}
item->ns = xmpp_strdup(conn->ctx, ns);
if (!item->ns) {
xmpp_free(conn->ctx, item);
return;
}
} else
item->ns = NULL;
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;
}
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;
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);
}
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;
item->type = NULL;
/* append to list */
if (!conn->handlers)
conn->handlers = item;
conn->handlers = item;
else {
tail = conn->handlers;
while (tail->next)
tail = tail->next;
tail->next = item;
tail = conn->handlers;
while (tail->next)
tail = tail->next;
tail->next = item;
}
}
@@ -432,7 +455,7 @@ static void _handler_add(xmpp_conn_t * const conn,
* @ingroup Handlers
*/
void xmpp_handler_delete(xmpp_conn_t * const conn,
xmpp_handler handler)
xmpp_handler handler)
{
xmpp_handlist_t *prev, *item;
@@ -441,23 +464,21 @@ void xmpp_handler_delete(xmpp_conn_t * const conn,
prev = NULL;
item = conn->handlers;
while (item) {
if (item->handler == (void *)handler)
break;
prev = item;
item = item->next;
}
if (item->handler == handler) {
if (prev)
prev->next = item->next;
else
conn->handlers = 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);
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 = prev ? prev->next : conn->handlers;
} else {
prev = item;
item = item->next;
}
}
}
@@ -466,7 +487,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.
*
@@ -478,9 +499,9 @@ void xmpp_handler_delete(xmpp_conn_t * const conn,
* @ingroup Handlers
*/
void xmpp_timed_handler_add(xmpp_conn_t * const conn,
xmpp_timed_handler handler,
const unsigned long period,
void * const userdata)
xmpp_timed_handler handler,
const unsigned long period,
void * const userdata)
{
_timed_handler_add(conn, handler, period, userdata, 1);
}
@@ -495,9 +516,9 @@ void xmpp_timed_handler_add(xmpp_conn_t * const conn,
* @param userdata an opaque data pointer that will be passed to the handler
*/
void handler_add_timed(xmpp_conn_t * const conn,
xmpp_timed_handler handler,
const unsigned long period,
void * const userdata)
xmpp_timed_handler handler,
const unsigned long period,
void * const userdata)
{
_timed_handler_add(conn, handler, period, userdata, 0);
}
@@ -519,9 +540,9 @@ void handler_add_timed(xmpp_conn_t * const conn,
* @ingroup Handlers
*/
void xmpp_id_handler_add(xmpp_conn_t * const conn,
xmpp_handler handler,
const char * const id,
void * const userdata)
xmpp_handler handler,
const char * const id,
void * const userdata)
{
_id_handler_add(conn, handler, id, userdata, 1);
}
@@ -536,9 +557,9 @@ void xmpp_id_handler_add(xmpp_conn_t * const conn,
* @param userdata an opaque data pointer that will be passed to the handler
*/
void handler_add_id(xmpp_conn_t * const conn,
xmpp_handler handler,
const char * const id,
void * const userdata)
xmpp_handler handler,
const char * const id,
void * const userdata)
{
_id_handler_add(conn, handler, id, userdata, 0);
}
@@ -566,11 +587,11 @@ void handler_add_id(xmpp_conn_t * const conn,
* @ingroup Handlers
*/
void xmpp_handler_add(xmpp_conn_t * const conn,
xmpp_handler handler,
const char * const ns,
const char * const name,
const char * const type,
void * const userdata)
xmpp_handler handler,
const char * const ns,
const char * const name,
const char * const type,
void * const userdata)
{
_handler_add(conn, handler, ns, name, type, userdata, 1);
}
@@ -587,11 +608,83 @@ void xmpp_handler_add(xmpp_conn_t * const conn,
* @param userdata an opaque data pointer that will be passed to the handler
*/
void handler_add(xmpp_conn_t * const conn,
xmpp_handler handler,
const char * const ns,
const char * const name,
const char * const type,
void * const userdata)
xmpp_handler handler,
const char * const ns,
const char * const name,
const char * const type,
void * const userdata)
{
_handler_add(conn, handler, ns, name, type, userdata, 0);
}
/** Delete all system handlers.
* This function is used to reset conn object before re-connecting.
*
* @param conn a Strophe connection object
*/
void handler_system_delete_all(xmpp_conn_t *conn)
{
xmpp_handlist_t *item, *next, *head, *head_old;
hash_iterator_t *iter;
const char *key;
char *key2 = NULL;
/* TODO unify all kinds of handlers and avoid copy-paste below */
item = conn->handlers;
while (item) {
if (!item->user_handler) {
next = item->next;
_handler_item_remove(&conn->handlers, item);
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 = next;
} else
item = item->next;
}
item = conn->timed_handlers;
while (item) {
if (!item->user_handler) {
next = item->next;
_handler_item_remove(&conn->timed_handlers, item);
xmpp_free(conn->ctx, item);
item = next;
} else
item = item->next;
}
iter = hash_iter_new(conn->id_handlers);
key = iter == NULL ? NULL : hash_iter_next(iter);
while (key != NULL) {
head = head_old = (xmpp_handlist_t *)hash_get(conn->id_handlers, key);
item = head;
while (item) {
if (!item->user_handler) {
next = item->next;
_handler_item_remove(&head, item);
xmpp_free(conn->ctx, item->id);
xmpp_free(conn->ctx, item);
item = next;
} else
item = item->next;
}
if (head != head_old)
key2 = xmpp_strdup(conn->ctx, key);
/* Hash table implementation is not perfect, so we need to find next
key before dropping current one. Otherwise, we will get access to
freed memory. */
key = hash_iter_next(iter);
if (head != head_old) {
/* hash_add() replaces value if the key exists */
if (head != NULL)
hash_add(conn->id_handlers, key2, head);
else
hash_drop(conn->id_handlers, key2);
xmpp_free(conn->ctx, key2);
}
}
if (iter) hash_iter_release(iter);
}

View File

@@ -106,18 +106,35 @@ void hash_release(hash_t * const table)
/** hash a key for our table lookup */
static int _hash_key(hash_t *table, const char *key)
{
int hash = 0;
int shift = 0;
const char *c = key;
unsigned hash = 0;
unsigned shift = 0;
const unsigned char *c = (const unsigned char *)key;
while (*c != '\0') {
while (*c != 0) {
/* assume 32 bit ints */
hash ^= ((int)*c++ << shift);
hash ^= ((unsigned)*c++ << shift);
shift += 8;
if (shift > 24) shift = 0;
}
return hash % (unsigned)table->length;
}
return hash % table->length;
hashentry_t *_hash_entry_find(hash_t *table, const char *key)
{
hashentry_t *entry;
int table_index = _hash_key(table, key);
/* look up the hash entry */
entry = table->entries[table_index];
while (entry != NULL) {
/* traverse the linked list looking for the key */
if (!strcmp(key, entry->key)) {
/* match */
break;
}
entry = entry->next;
}
return entry;
}
/** add a key, value pair to a hash table.
@@ -130,23 +147,25 @@ int hash_add(hash_t *table, const char * const key, void *data)
hashentry_t *entry = NULL;
int table_index = _hash_key(table, key);
/* drop existing entry, if any */
hash_drop(table, key);
/* find and replace existing entry, if any */
entry = _hash_entry_find(table, key);
/* allocate and fill a new entry */
entry = xmpp_alloc(ctx, sizeof(hashentry_t));
if (!entry) return -1;
entry->key = xmpp_strdup(ctx, key);
if (!entry->key) {
xmpp_free(ctx, entry);
return -1;
if (entry == NULL) {
/* allocate and fill a new entry */
entry = xmpp_alloc(ctx, sizeof(hashentry_t));
if (!entry) return -1;
entry->key = xmpp_strdup(ctx, key);
if (!entry->key) {
xmpp_free(ctx, entry);
return -1;
}
/* insert ourselves in the linked list */
entry->next = table->entries[table_index];
table->entries[table_index] = entry;
table->num_keys++;
}
entry->value = data;
/* insert ourselves in the linked list */
/* TODO: this leaks duplicate keys */
entry->next = table->entries[table_index];
table->entries[table_index] = entry;
table->num_keys++;
return 0;
}
@@ -155,22 +174,9 @@ int hash_add(hash_t *table, const char * const key, void *data)
void *hash_get(hash_t *table, const char *key)
{
hashentry_t *entry;
int table_index = _hash_key(table, key);
void *result = NULL;
/* look up the hash entry */
entry = table->entries[table_index];
while (entry != NULL) {
/* traverse the linked list looking for the key */
if (!strcmp(key, entry->key)) {
/* match */
result = entry->value;
return result;
}
entry = entry->next;
}
/* no match */
return result;
entry = _hash_entry_find(table, key);
return entry == NULL ? NULL : entry->value;
}
/** delete a key from a hash table */
@@ -273,4 +279,3 @@ const char * hash_iter_next(hash_iterator_t *iter)
iter->entry = entry;
return entry->key;
}

View File

@@ -72,15 +72,13 @@ char *xmpp_jid_new(xmpp_ctx_t *ctx, const char *node,
char *xmpp_jid_bare(xmpp_ctx_t *ctx, const char *jid)
{
char *result;
const char *c;
size_t len;
c = strchr(jid, '/');
if (c == NULL) return xmpp_strdup(ctx, jid);
result = xmpp_alloc(ctx, c-jid+1);
len = strcspn(jid, "/");
result = xmpp_alloc(ctx, len + 1);
if (result != NULL) {
memcpy(result, jid, c-jid);
result[c-jid] = '\0';
memcpy(result, jid, len);
result[len] = '\0';
}
return result;
@@ -121,7 +119,8 @@ char *xmpp_jid_node(xmpp_ctx_t *ctx, const char *jid)
char *xmpp_jid_domain(xmpp_ctx_t *ctx, const char *jid)
{
char *result = NULL;
const char *c,*s;
const char *c;
size_t dlen;
c = strchr(jid, '@');
if (c == NULL) {
@@ -131,15 +130,11 @@ char *xmpp_jid_domain(xmpp_ctx_t *ctx, const char *jid)
/* advance past the separator */
c++;
}
s = strchr(c, '/');
if (s == NULL) {
/* no resource */
s = c + strlen(c);
}
result = xmpp_alloc(ctx, (s-c) + 1);
dlen = strcspn(c, "/"); /* do not include resource */
result = xmpp_alloc(ctx, dlen + 1);
if (result != NULL) {
memcpy(result, c, (s-c));
result[s-c] = '\0';
memcpy(result, c, dlen);
result[dlen] = '\0';
}
return result;
@@ -155,20 +150,8 @@ char *xmpp_jid_domain(xmpp_ctx_t *ctx, const char *jid)
*/
char *xmpp_jid_resource(xmpp_ctx_t *ctx, const char *jid)
{
char *result = NULL;
const char *c;
size_t len;
c = strchr(jid, '/');
if (c != NULL) {
c++;
len = strlen(c);
result = xmpp_alloc(ctx, len + 1);
if (result != NULL) {
memcpy(result, c, len);
result[len] = '\0';
}
}
return result;
return c != NULL ? xmpp_strdup(ctx, c + 1) : NULL;
}

View File

@@ -1,7 +1,7 @@
/* oocontext.cpp
** strophe XMPP client library -- C++ 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
** or implied.
@@ -14,7 +14,7 @@
#include "strophe.h"
#include "strophepp.h"
XMPP::Context::Context()
XMPP::Context::Context()
{
m_mem.alloc = callAlloc;
m_mem.realloc = callRealloc;
@@ -48,8 +48,8 @@ void XMPP::Context::free(void *p)
}
void XMPP::Context::log(const xmpp_log_level_t level,
const char * const area,
const char * const msg)
const char * const area,
const char * const msg)
{
/* do nothing by default */
}
@@ -65,7 +65,7 @@ void *XMPP::Context::callAlloc(const size_t size, void * const userdata)
}
void *XMPP::Context::callRealloc(void *p, const size_t size,
void * const userdata)
void * const userdata)
{
return reinterpret_cast<Context *>(userdata)->realloc(p, size);
}
@@ -76,10 +76,9 @@ void XMPP::Context::callFree(void *p, void * const userdata)
}
void XMPP::Context::callLog(void * const userdata,
const xmpp_log_level_t level,
const char * const area,
const char * const msg)
const xmpp_log_level_t level,
const char * const area,
const char * const msg)
{
reinterpret_cast<Context *>(userdata)->log(level, area, msg);
}

View File

@@ -1,7 +1,7 @@
/* oostanza.cpp
** strophe XMPP client library -- C++ 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
** or implied.
@@ -28,8 +28,8 @@ void *Stanza::operator new(size_t size, Context *ctx)
if (!p) return p;
*reinterpret_cast<Context **>(p) = ctx;
p = reinterpret_cast<void *>(reinterpret_cast<char *>(p) +
sizeof(Context *));
p = reinterpret_cast<void *>(reinterpret_cast<char *>(p) +
sizeof(Context *));
return p;
}
@@ -61,7 +61,7 @@ Stanza *Stanza::create(Context *ctx)
void Stanza::release()
{
if (::xmpp_stanza_release(m_stanza))
delete this;
delete this;
}
Stanza *Stanza::clone()
@@ -75,5 +75,3 @@ Stanza *Stanza::copy()
// TODO
return NULL;
}

View File

@@ -26,6 +26,12 @@
/* Use the Unit Separator to delimit namespace and name in our XML*/
#define NAMESPACE_SEP ('\x1F')
/* Allocate inner text by this number bytes more. Expat splits string
* "new\nline" into 3 strings: "new" "\n" "line". Expecting this pattern,
* we can leave few bytes in the inner_text for "\n". It should reduce
* number of re-allocations in 2 times for multi-line texts. */
#define INNER_TEXT_PADDING 2
struct _parser_t {
xmpp_ctx_t *ctx;
XML_Parser expat;
@@ -35,6 +41,11 @@ struct _parser_t {
void *userdata;
int depth;
xmpp_stanza_t *stanza;
char* inner_text;
/* number of allocated bytes */
int inner_text_size;
/* excluding terminal '\0' */
int inner_text_used;
};
/* return allocated string with the name from a delimited
@@ -92,6 +103,26 @@ static void _set_attributes(xmpp_stanza_t *stanza, const XML_Char **attrs)
}
}
static void complete_inner_text(parser_t *parser)
{
xmpp_stanza_t *stanza;
if (parser->inner_text) {
/* create and populate stanza */
stanza = xmpp_stanza_new(parser->ctx);
/* FIXME: disconnect on allocation error */
if (stanza) {
xmpp_stanza_set_text(stanza, parser->inner_text);
xmpp_stanza_add_child(parser->stanza, stanza);
xmpp_stanza_release(stanza);
}
xmpp_free(parser->ctx, parser->inner_text);
parser->inner_text = NULL;
parser->inner_text_size = 0;
parser->inner_text_used = 0;
}
}
static void _start_element(void *userdata,
const XML_Char *nsname,
const XML_Char **attrs)
@@ -125,6 +156,7 @@ static void _start_element(void *userdata,
xmpp_stanza_set_ns(child, ns);
if (parser->stanza != NULL) {
complete_inner_text(parser);
xmpp_stanza_add_child(parser->stanza, child);
xmpp_stanza_release(child);
}
@@ -149,36 +181,46 @@ static void _end_element(void *userdata, const XML_Char *name)
if (parser->endcb)
parser->endcb((char *)name, parser->userdata);
} else {
if (parser->stanza->parent) {
/* we're finishing a child stanza, so set current to the parent */
parser->stanza = parser->stanza->parent;
} else {
complete_inner_text(parser);
if (parser->stanza->parent) {
/* we're finishing a child stanza, so set current to the parent */
parser->stanza = parser->stanza->parent;
} else {
if (parser->stanzacb)
parser->stanzacb(parser->stanza,
parser->userdata);
xmpp_stanza_release(parser->stanza);
parser->stanza = NULL;
}
xmpp_stanza_release(parser->stanza);
parser->stanza = NULL;
}
}
}
static void _characters(void *userdata, const XML_Char *s, int len)
{
parser_t *parser = (parser_t *)userdata;
xmpp_stanza_t *stanza;
char *p;
if (parser->depth < 2) return;
/* create and populate stanza */
stanza = xmpp_stanza_new(parser->ctx);
if (!stanza) {
/* FIXME: allocation error, disconnect */
return;
/* Join all parts to a single resulting string. Stanza is created in
* _start_element() and _end_element(). */
if (parser->inner_text_used + len >= parser->inner_text_size) {
parser->inner_text_size = parser->inner_text_used + len + 1 +
INNER_TEXT_PADDING;
p = xmpp_realloc(parser->ctx, parser->inner_text,
parser->inner_text_size);
if (p == NULL) {
xmpp_free(parser->ctx, parser->inner_text);
parser->inner_text = NULL;
parser->inner_text_used = 0;
parser->inner_text_size = 0;
return;
}
parser->inner_text = p;
parser->inner_text[parser->inner_text_used] = '\0';
}
xmpp_stanza_set_text_with_size(stanza, s, len);
xmpp_stanza_add_child(parser->stanza, stanza);
xmpp_stanza_release(stanza);
parser->inner_text_used += len;
strncat(parser->inner_text, s, len);
}
parser_t *parser_new(xmpp_ctx_t *ctx,
@@ -199,6 +241,9 @@ parser_t *parser_new(xmpp_ctx_t *ctx,
parser->userdata = userdata;
parser->depth = 0;
parser->stanza = NULL;
parser->inner_text = NULL;
parser->inner_text_size = 0;
parser->inner_text_used = 0;
parser_reset(parser);
}
@@ -217,6 +262,11 @@ void parser_free(parser_t *parser)
if (parser->expat)
XML_ParserFree(parser->expat);
if (parser->inner_text) {
xmpp_free (parser->ctx, parser->inner_text);
parser->inner_text = NULL;
}
xmpp_free(parser->ctx, parser);
}
@@ -235,6 +285,11 @@ int parser_reset(parser_t *parser)
parser->depth = 0;
parser->stanza = NULL;
if (parser->inner_text) {
xmpp_free (parser->ctx, parser->inner_text);
parser->inner_text = NULL;
}
XML_SetUserData(parser->expat, parser);
XML_SetElementHandler(parser->expat, _start_element, _end_element);
XML_SetCharacterDataHandler(parser->expat, _characters);

View File

@@ -116,11 +116,12 @@ static void _start_element(void *userdata,
if (parser->depth == 0) {
/* notify the owner */
if (parser->startcb)
if (parser->startcb) {
cbattrs = _convert_attrs(parser, nattrs, attrs);
parser->startcb((char *)name, cbattrs,
parser->userdata);
_free_cbattrs(parser, cbattrs);
}
} else {
/* build stanzas at depth 1 */
if (!parser->stanza && parser->depth != 1) {
@@ -273,11 +274,7 @@ int parser_reset(parser_t *parser)
/* feed a chunk of data to the parser */
int parser_feed(parser_t *parser, char *chunk, int len)
{
/* xmlParseChunk API returns 0 on success which is opposite logic to
/* xmlParseChunk API returns 0 on success which is opposite logic to
the status returned by parser_feed */
if(!xmlParseChunk(parser->xmlctx, chunk, len, 0)) {
return 1;
} else {
return 0;
}
return !xmlParseChunk(parser->xmlctx, chunk, len, 0);
}

View File

@@ -23,6 +23,7 @@
#include "ostypes.h"
#include "snprintf.h"
#include "util.h" /* xmpp_min */
#include "resolver.h"
#define MESSAGE_HEADER_LEN 12
@@ -65,6 +66,26 @@ static uint8_t message_header_rcode(const struct message_header *header)
return header->octet3 & 0x0f;
}
/*
* Append a label or a dot to the target name with buffer overflow checks.
* Returns length of the non-truncated resulting string, may be bigger than
* name_max.
*/
static size_t message_name_append_safe(char *name, size_t name_len,
size_t name_max,
const char *tail, size_t tail_len)
{
size_t copy_len;
copy_len = name_max > name_len ? name_max - name_len : 0;
copy_len = xmpp_min(tail_len, copy_len);
if (copy_len > 0)
strncpy(&name[name_len], tail, copy_len);
return name_len + tail_len;
}
/* Returns length of the compressed name. This is NOT the same as strlen(). */
static unsigned message_name_get(const unsigned char *buf, size_t buf_len,
unsigned buf_offset,
char *name, size_t name_max)
@@ -72,25 +93,41 @@ static unsigned message_name_get(const unsigned char *buf, size_t buf_len,
size_t name_len = 0;
unsigned i = buf_offset;
unsigned pointer;
unsigned rc;
unsigned char label_len;
while ((label_len = buf[i++]) != 0) {
/* label */
while (1) {
if (i >= buf_len) return 0;
label_len = buf[i++];
if (label_len == 0) break;
/* Label */
if ((label_len & 0xc0) == 0) {
if (i + label_len - 1 >= buf_len) return 0;
if (name != NULL) {
if (name_len != 0)
name[name_len++] = '.';
strncpy(&name[name_len], (char *)&buf[i], label_len);
name_len = message_name_append_safe(name, name_len, name_max,
(char *)&buf[i], label_len);
name_len = message_name_append_safe(name, name_len, name_max,
".", 1);
}
i += label_len;
name_len += label_len;
/* pointer */
/* Pointer */
} else if ((label_len & 0xc0) == 0xc0) {
if (i >= buf_len) return 0;
pointer = (label_len & 0x3f) << 8 | buf[i++];
(void)message_name_get(buf, buf_len, pointer, &name[name_len],
name_max - name_len);
/* pointer is always the last */
if (name != NULL && name_len >= name_max && name_max > 0) {
/* We have filled the name buffer. Don't pass it recursively. */
name[name_max - 1] = '\0';
name = NULL;
name_max = 0;
}
rc = message_name_get(buf, buf_len, pointer,
name != NULL ? &name[name_len] : NULL,
name_max > name_len ? name_max - name_len : 0);
if (rc == 0) return 0;
/* Pointer is always the last. */
break;
/* The 10 and 01 combinations are reserved for future use. */
@@ -98,8 +135,21 @@ static unsigned message_name_get(const unsigned char *buf, size_t buf_len,
return 0;
}
}
if (label_len == 0 && name != NULL)
name[name_len] = '\0';
if (label_len == 0) {
if (name_len == 0) name_len = 1;
/*
* At this point name_len is length of the resulting name,
* including '\0'. This value can be exported to allocate buffer
* of precise size.
*/
if (name != NULL && name_max > 0) {
/*
* Overwrite leading '.' with a '\0'. If the resulting name is
* bigger than name_max it is truncated.
*/
name[xmpp_min(name_len, name_max) - 1] = '\0';
}
}
return i - buf_offset;
}
@@ -167,6 +217,15 @@ static void resolver_srv_list_sort(resolver_srv_rr_t **srv_rr_list)
*srv_rr_list = rr_head;
}
#define BUF_OVERFLOW_CHECK(ptr, len) do { \
if ((ptr) >= (len)) { \
if (*srv_rr_list != NULL) \
resolver_srv_free(ctx, *srv_rr_list); \
*srv_rr_list = NULL; \
return XMPP_DOMAIN_NOT_FOUND; \
} \
} while (0)
int resolver_srv_lookup_buf(xmpp_ctx_t *ctx, const unsigned char *buf,
size_t len, resolver_srv_rr_t **srv_rr_list)
{
@@ -200,17 +259,20 @@ int resolver_srv_lookup_buf(xmpp_ctx_t *ctx, const unsigned char *buf,
/* skip question section */
for (i = 0; i < header.qdcount; ++i) {
BUF_OVERFLOW_CHECK(j, len);
name_len = message_name_len(buf, len, j);
if (name_len == 0) {
/* error in name format */
return XMPP_DOMAIN_NOT_FOUND;
}
/* error in name format */
if (name_len == 0) return XMPP_DOMAIN_NOT_FOUND;
j += name_len + 4;
}
for (i = 0; i < header.ancount; ++i) {
BUF_OVERFLOW_CHECK(j, len);
name_len = message_name_len(buf, len, j);
/* error in name format */
if (name_len == 0) return XMPP_DOMAIN_NOT_FOUND;
j += name_len;
BUF_OVERFLOW_CHECK(j + 16, len);
type = xmpp_ntohs_ptr(&buf[j]);
class = xmpp_ntohs_ptr(&buf[j + 2]);
rdlength = xmpp_ntohs_ptr(&buf[j + 8]);
@@ -369,7 +431,7 @@ static void netbuf_add_domain_name(unsigned char *buf, int buflen, int *offset,
*p++ = '\0';
*offset += p - start;
*offset += (int)(p - start);
}
static void netbuf_add_dnsquery_header(unsigned char *buf, int buflen, int *offset, struct dnsquery_header *header)
@@ -649,14 +711,14 @@ static int resolver_win32_srv_query(const char *fulldomain,
header.rd = 1;
header.qdcount = 1;
netbuf_add_dnsquery_header(buf, len, &offset, &header);
netbuf_add_dnsquery_header(buf, (int)len, &offset, &header);
memset(&question, 0, sizeof(question));
strncpy(question.qname, fulldomain, 1024);
question.qtype = 33; /* SRV */
question.qclass = 1; /* INTERNET! */
netbuf_add_dnsquery_question(buf, len, &offset, &question);
netbuf_add_dnsquery_question(buf, (int)len, &offset, &question);
insize = 0;
for (i = 0; i < numdnsservers && insize <= 0; i++)
@@ -674,7 +736,7 @@ static int resolver_win32_srv_query(const char *fulldomain,
sendto(sock, (char *)buf, offset, 0, (struct sockaddr *)&dnsaddr, addrlen);
for (j = 0; j < 50; j++)
{
insize = recvfrom(sock, (char *)buf, len, 0, (struct sockaddr *)&dnsaddr, &addrlen);
insize = recvfrom(sock, (char *)buf, (int)len, 0, (struct sockaddr *)&dnsaddr, &addrlen);
if (insize == SOCKET_ERROR)
{
if (sock_error() == WSAEWOULDBLOCK)

View File

@@ -65,4 +65,5 @@ int resolver_srv_lookup(xmpp_ctx_t *ctx, const char *service, const char *proto,
* @param srv_rr_list a list allocated by lookup functions
*/
void resolver_srv_free(xmpp_ctx_t *ctx, resolver_srv_rr_t *srv_rr_list);
#endif /* __LIBSTROPHE_RESOLVER_H__ */

View File

@@ -286,6 +286,7 @@ static int dopr (char *buffer, size_t maxlen, const char *format, va_list args)
break;
case 'X':
flags |= DP_F_UP;
//-fallthrough
case 'x':
flags |= DP_F_UNSIGNED;
if (cflags == DP_C_SHORT)
@@ -306,6 +307,7 @@ static int dopr (char *buffer, size_t maxlen, const char *format, va_list args)
break;
case 'E':
flags |= DP_F_UP;
//-fallthrough
case 'e':
if (cflags == DP_C_LDOUBLE)
fvalue = va_arg (args, LDOUBLE);
@@ -314,6 +316,7 @@ static int dopr (char *buffer, size_t maxlen, const char *format, va_list args)
break;
case 'G':
flags |= DP_F_UP;
//-fallthrough
case 'g':
if (cflags == DP_C_LDOUBLE)
fvalue = va_arg (args, LDOUBLE);

View File

@@ -76,35 +76,27 @@ xmpp_stanza_t *xmpp_stanza_clone(xmpp_stanza_t * const stanza)
static int _stanza_copy_attributes(xmpp_stanza_t * dst,
const xmpp_stanza_t * const src)
{
hash_iterator_t *iter = NULL;
hash_iterator_t *iter;
const char *key;
void *val;
const char *val;
int rc = XMPP_EOK;
dst->attributes = hash_new(src->ctx, 8, xmpp_free);
if (!dst->attributes)
return -1;
iter = hash_iter_new(src->attributes);
if (!iter)
goto error;
while ((key = hash_iter_next(iter))) {
val = xmpp_strdup(src->ctx,
(char *)hash_get(src->attributes, key));
if (!val)
goto error;
if (!iter) rc = XMPP_EMEM;
if (hash_add(dst->attributes, key, val)) {
xmpp_free(src->ctx, val);
goto error;
}
while (rc == XMPP_EOK && (key = hash_iter_next(iter))) {
val = hash_get(src->attributes, key);
if (!val) rc = XMPP_EINT;
if (rc == XMPP_EOK)
rc = xmpp_stanza_set_attribute(dst, key, val);
}
hash_iter_release(iter);
return 0;
error:
if (iter != NULL)
hash_iter_release(iter);
hash_release(dst->attributes);
return -1;
if (rc != XMPP_EOK && dst->attributes) {
hash_release(dst->attributes);
dst->attributes = NULL;
}
return rc;
}
/** Copy a stanza and its children.
@@ -431,7 +423,7 @@ int xmpp_stanza_to_text(xmpp_stanza_t *stanza,
ret = _render_stanza_recursive(stanza, buffer, length);
if (ret < 0) return ret;
if (ret > length - 1) {
if ((size_t)ret > length - 1) {
tmp = xmpp_realloc(stanza->ctx, buffer, ret + 1);
if (!tmp) {
xmpp_free(stanza->ctx, buffer);
@@ -443,7 +435,7 @@ int xmpp_stanza_to_text(xmpp_stanza_t *stanza,
buffer = tmp;
ret = _render_stanza_recursive(stanza, buffer, length);
if (ret > length - 1) return XMPP_EMEM;
if ((size_t)ret > length - 1) return XMPP_EMEM;
}
buffer[length - 1] = 0;
@@ -570,6 +562,7 @@ int xmpp_stanza_set_attribute(xmpp_stanza_t * const stanza,
const char * const value)
{
char *val;
int rc;
if (stanza->type != XMPP_STANZA_TAG) return XMPP_EINVOP;
@@ -584,7 +577,11 @@ int xmpp_stanza_set_attribute(xmpp_stanza_t * const stanza,
return XMPP_EMEM;
}
hash_add(stanza->attributes, key, val);
rc = hash_add(stanza->attributes, key, val);
if (rc < 0) {
xmpp_free(stanza->ctx, val);
return XMPP_EMEM;
}
return XMPP_EOK;
}
@@ -1047,7 +1044,12 @@ int xmpp_stanza_del_attribute(xmpp_stanza_t * const stanza,
*/
xmpp_stanza_t *xmpp_stanza_reply(xmpp_stanza_t * const stanza)
{
xmpp_stanza_t *copy;
xmpp_stanza_t *copy = NULL;
const char *from;
int rc;
from = xmpp_stanza_get_from(stanza);
if (!from) goto copy_error;
copy = xmpp_stanza_new(stanza->ctx);
if (!copy) goto copy_error;
@@ -1060,12 +1062,14 @@ xmpp_stanza_t *xmpp_stanza_reply(xmpp_stanza_t * const stanza)
}
if (stanza->attributes) {
if (_stanza_copy_attributes(copy, stanza) == -1)
if (_stanza_copy_attributes(copy, stanza) < 0)
goto copy_error;
}
xmpp_stanza_set_to(copy, xmpp_stanza_get_from(stanza));
xmpp_stanza_del_attribute(copy, "to");
xmpp_stanza_del_attribute(copy, "from");
rc = xmpp_stanza_set_to(copy, from);
if (rc != XMPP_EOK) goto copy_error;
return copy;

View File

@@ -1,116 +0,0 @@
/* thread.c
** strophe XMPP client library -- thread abstraction
**
** Copyright (C) 2005-2009 Collecta, Inc.
**
** This software is provided AS-IS with no warranty, either express
** or implied.
**
** This program is dual licensed under the MIT and GPLv3 licenses.
*/
/** @file
* Thread absraction.
*/
#include <stdio.h>
#include <stdlib.h>
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#else
#include <pthread.h>
#endif
#include "strophe.h"
#include "common.h"
#include "thread.h"
struct _mutex_t {
const xmpp_ctx_t *ctx;
#ifdef _WIN32
HANDLE mutex;
#else
pthread_mutex_t *mutex;
#endif
};
/* mutex functions */
mutex_t *mutex_create(const xmpp_ctx_t * ctx)
{
mutex_t *mutex;
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) {
xmpp_free(ctx, mutex->mutex);
mutex->mutex = NULL;
}
#endif
if (!mutex->mutex) {
xmpp_free(ctx, mutex);
mutex = NULL;
}
}
return mutex;
}
int mutex_destroy(mutex_t *mutex)
{
int ret = 1;
const xmpp_ctx_t *ctx;
#ifdef _WIN32
if (mutex->mutex)
ret = CloseHandle(mutex->mutex);
#else
if (mutex->mutex)
ret = pthread_mutex_destroy(mutex->mutex) == 0;
#endif
ctx = mutex->ctx;
xmpp_free(ctx, mutex);
return ret;
}
int mutex_lock(mutex_t *mutex)
{
int ret;
#ifdef _WIN32
ret = WaitForSingleObject(mutex->mutex, INFINITE) == 0;
#else
ret = pthread_mutex_lock(mutex->mutex) == 0;
#endif
return ret;
}
int mutex_trylock(mutex_t *mutex)
{
/* TODO */
return 0;
}
int mutex_unlock(mutex_t *mutex)
{
int ret;
#ifdef _WIN32
ret = ReleaseMutex(mutex->mutex);
#else
ret = pthread_mutex_unlock(mutex->mutex) == 0;
#endif
return ret;
}

View File

@@ -1,40 +0,0 @@
/* thread.h
** strophe XMPP client library -- thread abstraction header
**
** Copyright (C) 2005-2009 Collecta, Inc.
**
** This software is provided AS-IS with no warranty, either express
** or implied.
**
** This program is dual licensed under the MIT and GPLv3 licenses.
*/
/** @file
* Threading abstraction API.
*/
#ifndef __LIBSTROPHE_THREAD_H__
#define __LIBSTROPHE_THREAD_H__
#include <stdio.h>
#include <stdlib.h>
#ifdef _WIN32
#include <windows.h>
#else
#include <pthread.h>
#endif
#include "strophe.h"
typedef struct _mutex_t mutex_t;
/* mutex functions */
mutex_t *mutex_create(const xmpp_ctx_t *ctx);
int mutex_destroy(mutex_t *mutex);
int mutex_lock(mutex_t *mutex);
int mutex_trylock(mutex_t *mutex);
int mutex_unlock(mutex_t *mutex);
#endif /* __LIBSTROPHE_THREAD_H__ */

View File

@@ -24,7 +24,7 @@ typedef struct _tls tls_t;
void tls_initialize(void);
void tls_shutdown(void);
tls_t *tls_new(xmpp_ctx_t *ctx, sock_t sock);
tls_t *tls_new(xmpp_conn_t *conn);
void tls_free(tls_t *tls);
int tls_set_credentials(tls_t *tls, const char *cafilename);

View File

@@ -33,7 +33,7 @@ void tls_shutdown(void)
return;
}
tls_t *tls_new(xmpp_ctx_t *ctx, sock_t sock)
tls_t *tls_new(xmpp_conn_t *conn)
{
/* always fail */
return NULL;

View File

@@ -46,13 +46,13 @@ void tls_shutdown(void)
gnutls_global_deinit();
}
tls_t *tls_new(xmpp_ctx_t *ctx, sock_t sock)
tls_t *tls_new(xmpp_conn_t *conn)
{
tls_t *tls = xmpp_alloc(ctx, sizeof(tls_t));
tls_t *tls = xmpp_alloc(conn->ctx, sizeof(tls_t));
if (tls) {
tls->ctx = ctx;
tls->sock = sock;
tls->ctx = conn->ctx;
tls->sock = conn->sock;
gnutls_init(&tls->session, GNUTLS_CLIENT);
gnutls_certificate_allocate_credentials(&tls->cred);
@@ -61,7 +61,7 @@ tls_t *tls_new(xmpp_ctx_t *ctx, sock_t sock)
gnutls_set_default_priority(tls->session);
/* fixme: this may require setting a callback on win32? */
gnutls_transport_set_int(tls->session, sock);
gnutls_transport_set_int(tls->session, conn->sock);
}
return tls;

View File

@@ -24,6 +24,8 @@
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/opensslv.h>
#include <openssl/x509v3.h>
#include "common.h"
#include "tls.h"
@@ -49,13 +51,34 @@ static void _tls_log_error(xmpp_ctx_t *ctx);
void tls_initialize(void)
{
#if OPENSSL_VERSION_NUMBER < 0x10100000L
SSL_library_init();
SSL_load_error_strings();
#else
OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL);
#endif
}
void tls_shutdown(void)
{
return;
/*
* FIXME: Don't free global tables, program or other libraries may use
* openssl after libstrophe finalization. Maybe better leak some fixed
* memory rather than cause random crashes of the main program.
*/
#if OPENSSL_VERSION_NUMBER < 0x10100000L
ERR_free_strings();
EVP_cleanup();
CRYPTO_cleanup_all_ex_data();
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
SSL_COMP_free_compression_methods();
#endif
#if OPENSSL_VERSION_NUMBER < 0x10000000L
ERR_remove_state(0);
#else
ERR_remove_thread_state(NULL);
#endif
#endif
}
int tls_error(tls_t *tls)
@@ -63,29 +86,55 @@ int tls_error(tls_t *tls)
return tls->lasterror;
}
tls_t *tls_new(xmpp_ctx_t *ctx, sock_t sock)
tls_t *tls_new(xmpp_conn_t *conn)
{
tls_t *tls = xmpp_alloc(ctx, sizeof(*tls));
tls_t *tls = xmpp_alloc(conn->ctx, sizeof(*tls));
int mode;
if (tls) {
int ret;
memset(tls, 0, sizeof(*tls));
tls->ctx = ctx;
tls->sock = sock;
tls->ctx = conn->ctx;
tls->sock = conn->sock;
tls->ssl_ctx = SSL_CTX_new(SSLv23_client_method());
if (tls->ssl_ctx == NULL)
goto err;
/* Enable bug workarounds. */
SSL_CTX_set_options(tls->ssl_ctx, SSL_OP_ALL);
/* Disable insecure SSL/TLS versions. */
SSL_CTX_set_options(tls->ssl_ctx, SSL_OP_NO_SSLv2); /* DROWN */
SSL_CTX_set_options(tls->ssl_ctx, SSL_OP_NO_SSLv3); /* POODLE */
SSL_CTX_set_options(tls->ssl_ctx, SSL_OP_NO_TLSv1); /* BEAST */
SSL_CTX_set_client_cert_cb(tls->ssl_ctx, NULL);
SSL_CTX_set_mode(tls->ssl_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE);
SSL_CTX_set_verify(tls->ssl_ctx, SSL_VERIFY_NONE, NULL);
SSL_CTX_set_default_verify_paths(tls->ssl_ctx);
tls->ssl = SSL_new(tls->ssl_ctx);
if (tls->ssl == NULL)
goto err_free_ctx;
ret = SSL_set_fd(tls->ssl, sock);
/* Trust server's certificate when user sets the flag explicitly. */
mode = conn->tls_trust ? SSL_VERIFY_NONE : SSL_VERIFY_PEER;
SSL_set_verify(tls->ssl, mode, 0);
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
/* Hostname verification is supported in OpenSSL 1.0.2 and newer. */
X509_VERIFY_PARAM *param = SSL_get0_param(tls->ssl);
/*
* Allow only complete wildcards. RFC 6125 discourages wildcard usage
* completely, and lists internationalized domain names as a reason
* against partial wildcards.
* See https://tools.ietf.org/html/rfc6125#section-7.2 for more information.
*/
X509_VERIFY_PARAM_set_hostflags(param, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
X509_VERIFY_PARAM_set1_host(param, conn->domain, 0);
#endif
ret = SSL_set_fd(tls->ssl, conn->sock);
if (ret <= 0)
goto err_free_ssl;
}
@@ -97,8 +146,8 @@ err_free_ssl:
err_free_ctx:
SSL_CTX_free(tls->ssl_ctx);
err:
xmpp_free(ctx, tls);
_tls_log_error(ctx);
xmpp_free(conn->ctx, tls);
_tls_log_error(conn->ctx);
return NULL;
}
@@ -118,6 +167,7 @@ int tls_start(tls_t *tls)
{
int error;
int ret;
long x509_res;
/* Since we're non-blocking, loop the connect call until it
succeeds or fails */
@@ -134,8 +184,12 @@ int tls_start(tls_t *tls)
/* success or fatal error */
break;
}
_tls_set_error(tls, error);
x509_res = SSL_get_verify_result(tls->ssl);
xmpp_debug(tls->ctx, "tls", "Certificate verification %s",
x509_res == X509_V_OK ? "passed" : "FAILED");
_tls_set_error(tls, error);
return ret <= 0 ? 0 : 1;
}

View File

@@ -23,6 +23,7 @@
struct _tls {
xmpp_ctx_t *ctx;
xmpp_conn_t *conn;
sock_t sock;
HANDLE hsec32;
@@ -60,8 +61,10 @@ void tls_shutdown(void)
return;
}
tls_t *tls_new(xmpp_ctx_t *ctx, sock_t sock)
tls_t *tls_new(xmpp_conn_t *conn)
{
xmpp_ctx_t *ctx = conn->ctx;
sock_t sock = conn->sock;
tls_t *tls;
PSecurityFunctionTable (*pInitSecurityInterface)(void);
SCHANNEL_CRED scred;
@@ -92,6 +95,7 @@ tls_t *tls_new(xmpp_ctx_t *ctx, sock_t sock)
memset(tls, 0, sizeof(*tls));
tls->ctx = ctx;
tls->conn = conn;
tls->sock = sock;
if (!(tls->hsec32 = LoadLibrary ("secur32.dll"))) {
@@ -216,24 +220,10 @@ int tls_start(tls_t *tls)
SecBuffer sbin[2], sbout[1];
SECURITY_STATUS ret;
int sent;
char *name = NULL;
char *name;
/* search the ctx's conns for our sock, and use the domain there as our
* name */
{
xmpp_connlist_t *listentry = tls->ctx->connlist;
while (listentry) {
xmpp_conn_t *conn = listentry->conn;
if (conn->sock == tls->sock) {
name = strdup(conn->domain);
listentry = NULL;
} else {
listentry = listentry->next;
}
}
}
/* use the domain there as our name */
name = tls->conn->domain;
ctxtreq = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT
| ISC_REQ_CONFIDENTIALITY | ISC_RET_EXTENDED_ERROR

View File

@@ -18,6 +18,9 @@
#include "ostypes.h"
/* TODO evaluate x and y only once */
#define xmpp_min(x, y) ((x) < (y) ? (x) : (y))
/* string functions */
char *xmpp_strtok_r(char *s, const char *delim, char **saveptr);

View File

@@ -165,6 +165,10 @@ typedef struct _xmpp_stanza_t xmpp_stanza_t;
#define XMPP_CONN_FLAG_DISABLE_TLS (1UL << 0)
#define XMPP_CONN_FLAG_MANDATORY_TLS (1UL << 1)
#define XMPP_CONN_FLAG_LEGACY_SSL (1UL << 2)
/** @def XMPP_CONN_FLAG_TRUST_TLS
* Trust server's certificate even if it is invalid.
*/
#define XMPP_CONN_FLAG_TRUST_TLS (1UL << 3)
/* connect callback */
typedef enum {
@@ -394,6 +398,7 @@ char *xmpp_jid_resource(xmpp_ctx_t *ctx, const char *jid);
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);
void xmpp_ctx_set_timeout(xmpp_ctx_t * const ctx, const unsigned long timeout);
/* UUID */
@@ -409,6 +414,8 @@ char *xmpp_uuid_gen(xmpp_ctx_t *ctx);
typedef struct _xmpp_sha1_t xmpp_sha1_t;
char *xmpp_sha1(xmpp_ctx_t *ctx, const unsigned char *data, size_t len);
void xmpp_sha1_digest(const unsigned char *data, size_t len,
unsigned char *digest);
xmpp_sha1_t *xmpp_sha1_new(xmpp_ctx_t *ctx);
void xmpp_sha1_free(xmpp_sha1_t *sha1);

View File

@@ -5,7 +5,7 @@
**
** This software is provided AS-IS with no warranty, either express or
** implied.
**
**
** This program is dual licensed under the MIT and GPLv3 licenses.
*/
@@ -21,112 +21,112 @@
namespace XMPP {
class Context {
private:
xmpp_mem_t m_mem;
xmpp_log_t m_log;
xmpp_ctx_t *m_ctx;
xmpp_mem_t m_mem;
xmpp_log_t m_log;
xmpp_ctx_t *m_ctx;
public:
Context();
virtual ~Context();
Context();
virtual ~Context();
virtual void *alloc(const size_t size);
virtual void *realloc(void *p, const size_t size);
virtual void free(void *p);
virtual void log(const xmpp_log_level_t level,
const char * const area,
const char * const msg);
virtual void *alloc(const size_t size);
virtual void *realloc(void *p, const size_t size);
virtual void free(void *p);
virtual void log(const xmpp_log_level_t level,
const char * const area,
const char * const msg);
xmpp_ctx_t *getContext();
xmpp_ctx_t *getContext();
private:
static void *callAlloc(const size_t size, void * const userdata);
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,
const xmpp_log_level_t level,
const char * const area,
const char * const msg);
static void *callAlloc(const size_t size, void * const userdata);
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,
const xmpp_log_level_t level,
const char * const area,
const char * const msg);
};
class Stanza {
private:
Context *m_ctx;
xmpp_stanza_t *m_stanza;
Context *m_ctx;
xmpp_stanza_t *m_stanza;
void *operator new(size_t size, Context *ctx);
void operator delete(void *p);
Stanza(Context *ctx);
virtual ~Stanza();
void *operator new(size_t size, Context *ctx);
void operator delete(void *p);
Stanza(Context *ctx);
virtual ~Stanza();
public:
static Stanza *create(Context *ctx);
void release();
Stanza *clone();
Stanza *copy();
int toText(const char ** const buf, size_t * const buflen);
Stanza *getChildren();
Stanza *getChildByName(const char * const name);
Stanza *getNext();
static Stanza *create(Context *ctx);
void release();
Stanza *clone();
Stanza *copy();
int toText(const char ** const buf, size_t * const buflen);
Stanza *getChildren();
Stanza *getChildByName(const char * const name);
Stanza *getNext();
char *getAttribute(const char * const name);
char *getNamespace();
char *getText();
char *getName();
void addChild(Stanza *child);
void setNamespace(const char * const ns);
void setAttribute(const char * const key, const char * const value);
void setName(const char * const name);
void setText(const char * const text);
void setText(const char * const text, const size_t size);
char *getType();
char *getId();
char *getTo();
char *getFrom();
void setType(const char * const type);
void setId(const char * const id);
void setTo(const char * const to);
void setFrom(const char * const from);
char *getNamespace();
char *getText();
char *getName();
void addChild(Stanza *child);
void setNamespace(const char * const ns);
void setAttribute(const char * const key, const char * const value);
void setName(const char * const name);
void setText(const char * const text);
void setText(const char * const text, const size_t size);
char *getType();
char *getId();
char *getTo();
char *getFrom();
void setType(const char * const type);
void setId(const char * const id);
void setTo(const char * const to);
void setFrom(const char * const from);
};
class Connection {
private:
Context *m_ctx;
xmpp_conn_t *conn;
Context *m_ctx;
xmpp_conn_t *conn;
void *operator new(size_t size, Context *ctx);
Connection(Context *ctx);
void *operator new(size_t size, Context *ctx);
Connection(Context *ctx);
public:
static Connection *create(Context *ctx);
virtual ~Connection();
Connection *clone();
void operator delete(void *p);
static Connection *create(Context *ctx);
virtual ~Connection();
Connection *clone();
void operator delete(void *p);
const char *getJID();
void setJID(const char * const jid);
const char *getPass();
void setPass(const char * const pass);
bool connectClient(const char * const domain,
xmpp_conn_handler callback,
void * const userdata);
void disconnect();
void send(Stanza *stanza);
const char *getJID();
void setJID(const char * const jid);
const char *getPass();
void setPass(const char * const pass);
bool connectClient(const char * const domain,
xmpp_conn_handler callback,
void * const userdata);
void disconnect();
void send(Stanza *stanza);
void addTimedHandler(xmpp_timed_handler handler,
const unsigned long perdio,
void * const userdata);
void deleteTimedHandler(xmpp_timed_handler handler);
void addHandler(xmpp_handler handler,
const char * const ns,
const char * const name,
const char * const type,
void * const userdata);
void deleteHandler(xmpp_handler handler);
void addIdHandler(xmpp_handler handler,
const char * const id,
void * const userdata);
void deleteIdHandler(xmpp_handler handler);
void addTimedHandler(xmpp_timed_handler handler,
const unsigned long perdio,
void * const userdata);
void deleteTimedHandler(xmpp_timed_handler handler);
void addHandler(xmpp_handler handler,
const char * const ns,
const char * const name,
const char * const type,
void * const userdata);
void deleteHandler(xmpp_handler handler);
void addIdHandler(xmpp_handler handler,
const char * const id,
void * const userdata);
void deleteIdHandler(xmpp_handler handler);
};
}

View File

@@ -10,27 +10,34 @@
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <check.h>
#include <strophe.h>
#include "strophe.h"
#include "parser.h"
#include "test.h"
START_TEST(create_destroy)
#define fail_unless(expr) do { \
int result = (expr); \
if (!result) { \
printf("%s:%d: Assertion failed: %s\n", \
__FILE__, __LINE__, #expr); \
exit(1); \
} \
} while (0)
static void create_destroy(void)
{
xmpp_ctx_t *ctx;
parser_t *parser;
ctx = xmpp_ctx_new(NULL, NULL);
parser = parser_new(ctx, NULL, NULL, NULL, NULL);
fail_unless(parser != NULL, "Parser creation failed.");
fail_unless(parser != NULL);
parser_free(parser);
xmpp_ctx_free(ctx);
}
END_TEST
int cbtest_got_start = 0;
void cbtest_handle_start(char *name, char **attrs, void *userdata)
@@ -53,7 +60,7 @@ void cbtest_handle_stanza(xmpp_stanza_t *stanza, void *userdata)
cbtest_got_stanza = 1;
}
START_TEST(callbacks)
static void callbacks(void)
{
xmpp_ctx_t *ctx;
parser_t *parser;
@@ -79,16 +86,18 @@ START_TEST(callbacks)
parser_free(parser);
xmpp_ctx_free(ctx);
}
END_TEST
Suite *parser_suite(void)
int main()
{
Suite *s = suite_create("Parser");
TCase *tc_core = tcase_create("Core");
tcase_add_test(tc_core, create_destroy);
tcase_add_test(tc_core, callbacks);
suite_add_tcase(s, tc_core);
return s;
}
printf("XML parser tests.\n");
TEST_MAIN
printf("create-destroy: ");
create_destroy();
printf("ok\n");
printf("callbacks: ");
callbacks();
printf("ok\n");
return 0;
}

View File

@@ -61,7 +61,7 @@ int main(int argc, char **argv)
len = res_query(fulldomain, C_IN, T_SRV, buf, sizeof(buf));
if (len < 0) {
fprintf(stderr, "res_query(): Error occured (errno=%d)\n", errno);
fprintf(stderr, "res_query(): Error occurred (errno=%d)\n", errno);
}
if (len == 0) {
fprintf(stderr, "res_query(): Empty result\n");

View File

@@ -134,8 +134,7 @@ int main(int argc, char *argv[])
unsigned char *udec;
char *dec;
char *enc;
size_t len;
int i;
size_t len, i;
printf("BASE64 tests.\n");

View File

@@ -76,6 +76,18 @@ int main(int argc, char **argv)
return 1;
}
/* test replacing old values */
for (i = 0; i < nkeys; i++) {
err = hash_add(table, keys[0], (void*)values[i]);
if (err) return err;
if (hash_num_keys(table) != nkeys) return 1;
result = hash_get(table, keys[0]);
if (result == NULL) return 1;
if (strcmp(result, values[i]) != 0) return 1;
}
/* restore value for the 1st key */
hash_add(table, keys[0], (void*)values[0]);
/* test cloning */
clone = hash_clone(table);

View File

@@ -27,54 +27,67 @@ static const char *_s(const char *s)
int test_jid(xmpp_ctx_t *ctx)
{
char *bare;
char *node;
char *domain;
char *resource;
bare = xmpp_jid_bare(ctx, jid1);
node = xmpp_jid_node(ctx, jid1);
domain = xmpp_jid_domain(ctx, jid1);
resource = xmpp_jid_resource(ctx, jid1);
printf("jid '%s' parsed to %s, %s, %s\n",
jid1, _s(node), _s(domain), _s(resource));
if (bare == NULL || strcmp(bare, "foo@bar.com")) return 1;
if (node == NULL || strcmp(node, "foo")) return 1;
if (domain == NULL || strcmp(domain, "bar.com")) return 1;
if (resource != NULL) return 1;
if (bare) xmpp_free(ctx, bare);
if (node) xmpp_free(ctx, node);
if (domain) xmpp_free(ctx, domain);
if (resource) xmpp_free(ctx, resource);
bare = xmpp_jid_bare(ctx, jid2);
node = xmpp_jid_node(ctx, jid2);
domain = xmpp_jid_domain(ctx, jid2);
resource = xmpp_jid_resource(ctx, jid2);
printf("jid '%s' parsed to %s, %s, %s\n",
jid2, _s(node), _s(domain), _s(resource));
if (bare == NULL || strcmp(bare, "anyone@example.com")) return 1;
if (node == NULL || strcmp(node, "anyone")) return 1;
if (domain == NULL || strcmp(domain, "example.com")) return 1;
if (resource == NULL || strcmp(resource, "hullo")) return 1;
if (bare) xmpp_free(ctx, bare);
if (node) xmpp_free(ctx, node);
if (domain) xmpp_free(ctx, domain);
if (resource) xmpp_free(ctx, resource);
bare = xmpp_jid_bare(ctx, jid3);
node = xmpp_jid_node(ctx, jid3);
domain = xmpp_jid_domain(ctx, jid3);
resource = xmpp_jid_resource(ctx, jid3);
printf("jid '%s' parsed to %s, %s, %s\n",
jid3, _s(node), _s(domain), _s(resource));
if (bare == NULL || strcmp(bare, "manic.porter@xyz.net")) return 1;
if (node == NULL || strcmp(node, "manic.porter")) return 1;
if (domain == NULL || strcmp(domain, "xyz.net")) return 1;
if (resource == NULL || strcmp(resource, "frob")) return 1;
if (bare) xmpp_free(ctx, bare);
if (node) xmpp_free(ctx, node);
if (domain) xmpp_free(ctx, domain);
if (resource) xmpp_free(ctx, resource);
bare = xmpp_jid_bare(ctx, jid4);
node = xmpp_jid_node(ctx, jid4);
domain = xmpp_jid_domain(ctx, jid4);
resource = xmpp_jid_resource(ctx, jid4);
printf("jid '%s' parsed to %s, %s, %s\n",
jid4, _s(node), _s(domain), _s(resource));
if (bare == NULL || strcmp(bare, "domain.tld")) return 1;
if (node != NULL) return 1;
if (domain == NULL || strcmp(domain, "domain.tld")) return 1;
if (resource != NULL) return 1;
if (bare) xmpp_free(ctx, bare);
if (node) xmpp_free(ctx, node);
if (domain) xmpp_free(ctx, domain);
if (resource) xmpp_free(ctx, resource);

View File

@@ -13,6 +13,7 @@
#include <stdio.h>
#include "strophe.h"
#include "rand.h"
#include "resolver.h"
#include "test.h"
@@ -84,7 +85,6 @@ static const unsigned char data3[] = {
0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63, 0x6f,
0x6d, 0x00,
};
/* res_query("_xmpp-client._tcp.jabber.calyxinstitute.org", C_IN, T_SRV, ...) */
static const unsigned char data4[] = {
0x8d, 0x58, 0x81, 0x80, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, // .X........
@@ -103,6 +103,34 @@ static const unsigned char data4[] = {
0x61, 0x6c, 0x79, 0x78, 0x69, 0x6e, 0x73, 0x74, 0x69, 0x74, // alyxinstit
0x75, 0x74, 0x65, 0x03, 0x6f, 0x72, 0x67, 0x00, // ute.org.
};
/* res_query("_xmpp-client._tcp.jabber.org", C_IN, T_SRV, ...) with pointers */
static const unsigned char data5[] = {
0x00, 0x00, 0x81, 0x80, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, // ..........
0x00, 0x00, 0x0c, 0x5f, 0x78, 0x6d, 0x70, 0x70, 0x2d, 0x63, // ..._xmpp-c
0x6c, 0x69, 0x65, 0x6e, 0x74, 0x04, 0x5f, 0x74, 0x63, 0x70, // lient._tcp
0x06, 0x6a, 0x61, 0x62, 0x62, 0x65, 0x72, 0x03, 0x6f, 0x72, // .jabber.or
0x67, 0x00, 0x00, 0x21, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x21, // g..!.....!
0x00, 0x01, 0x00, 0x00, 0x01, 0x9e, 0x00, 0x12, 0x00, 0x1f, // ..........
0x00, 0x1e, 0x14, 0x66, 0x09, 0x68, 0x65, 0x72, 0x6d, 0x65, // ...f.herme
0x73, 0x32, 0x76, 0x36, 0xc0, 0x1e, 0xc0, 0x0c, 0x00, 0x21, // s2v6.....!
0x00, 0x01, 0x00, 0x00, 0x01, 0x9e, 0x00, 0x10, 0x00, 0x1e, // ..........
0x00, 0x1e, 0x14, 0x66, 0x07, 0x68, 0x65, 0x72, 0x6d, 0x65, // ...f.herme
0x73, 0x32, 0xc0, 0x1e, // s2..
};
/* hacked data2 with two empty-string targets. */
static const unsigned char data6[] = {
0xf2, 0x98, 0x81, 0x80, 0x00, 0x01, 0x00, 0x02,
0x00, 0x00, 0x00, 0x00, 0x0c, 0x5f, 0x78, 0x6d,
0x70, 0x70, 0x2d, 0x63, 0x6c, 0x69, 0x65, 0x6e,
0x74, 0x04, 0x5f, 0x74, 0x63, 0x70, 0x06, 0x6a,
0x61, 0x62, 0x62, 0x65, 0x72, 0x03, 0x6f, 0x72,
0x67, 0x00, 0x00, 0x21, 0x00, 0x01, 0xc0, 0x0c,
0x00, 0x21, 0x00, 0x01, 0x00, 0x00, 0x03, 0x83,
0x00, 0x07, 0x00, 0x1e, 0x00, 0x1e, 0x14, 0x66,
0x00, 0xc0, 0x0c, 0x00, 0x21, 0x00, 0x01, 0x00,
0x00, 0x03, 0x83, 0x00, 0x08, 0x00, 0x1f, 0x00,
0x1e, 0x14, 0x66, 0xc0, 0x40,
};
static const struct {
const unsigned char *data;
@@ -139,13 +167,27 @@ static const struct {
.port = 5222,
.target_nr = 2,
},
{
.data = data5,
.len = sizeof(data5),
.target = "hermes2.jabber.org",
.port = 5222,
.target_nr = 2,
},
{
.data = data6,
.len = sizeof(data6),
.target = "",
.port = 5222,
.target_nr = 2,
},
};
static int srv_rr_list_len(resolver_srv_rr_t *list)
{
int nr;
for(nr = 0; list != NULL; ++nr, list = list->next);
for (nr = 0; list != NULL; ++nr, list = list->next);
return nr;
}
@@ -153,8 +195,10 @@ static int srv_rr_list_len(resolver_srv_rr_t *list)
int main(int argc, char **argv)
{
xmpp_ctx_t *ctx;
xmpp_rand_t *rand;
resolver_srv_rr_t *srv_rr_list;
char *domain;
unsigned char *buf;
unsigned short port;
size_t i;
int ret;
@@ -187,6 +231,25 @@ int main(int argc, char **argv)
resolver_srv_free(ctx, srv_rr_list);
}
/*
* The next test case must not crash and is supposed to be checked
* under valgrind.
*/
printf("Test of a broken message: ");
rand = xmpp_rand_new(ctx);
assert(rand != NULL);
assert(sizeof(data2) > 64);
buf = xmpp_alloc(ctx, sizeof(data2));
assert(buf != NULL);
memcpy(buf, data2, 64);
xmpp_rand_bytes(rand, &buf[64], sizeof(data2) - 64);
ret = resolver_srv_lookup_buf(ctx, buf, sizeof(data2), &srv_rr_list);
if (ret == XMPP_DOMAIN_FOUND && srv_rr_list != NULL)
resolver_srv_free(ctx, srv_rr_list);
xmpp_free(ctx, buf);
xmpp_rand_free(ctx, rand);
printf("ok\n");
xmpp_ctx_free(ctx);
return 0;

View File

@@ -79,7 +79,7 @@ static int test_strdup_one(xmpp_ctx_t *ctx, const char *s)
static int test_strdup(void)
{
xmpp_ctx_t *ctx;
int i;
size_t i;
int rc = 0;
static const char *tests[] = { "", "\0", "test", "s p a c e", "\n\r" };