Compare commits
66 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b1698f7b5d | ||
|
|
b1b827cde6 | ||
|
|
e73b577e0b | ||
|
|
8d2d59e914 | ||
|
|
212f3ea760 | ||
|
|
4aa7ea7e5b | ||
|
|
5f9c0399c3 | ||
|
|
b83347b464 | ||
|
|
d8a86a54d5 | ||
|
|
49289a9c05 | ||
|
|
456083d878 | ||
|
|
15e7032f0d | ||
|
|
cd2cf6eb23 | ||
|
|
666995531a | ||
|
|
9269d6b0d5 | ||
|
|
c319ee6583 | ||
|
|
cc53012cfa | ||
|
|
cc297eff45 | ||
|
|
e151096834 | ||
|
|
82040403bf | ||
|
|
a845c7ec3d | ||
|
|
5ecb0c5d0c | ||
|
|
da8dc2d3cb | ||
|
|
182695d1ca | ||
|
|
0d039f7192 | ||
|
|
ebe97e8f2a | ||
|
|
9505cace5e | ||
|
|
8ef027c54a | ||
|
|
0bdb5f1d5b | ||
|
|
49e7572059 | ||
|
|
c074a6166c | ||
|
|
4c504ee42b | ||
|
|
f226891520 | ||
|
|
43a68479ad | ||
|
|
1e422a70dd | ||
|
|
2a474bd809 | ||
|
|
704c157d24 | ||
|
|
d8528b597c | ||
|
|
c149caa32a | ||
|
|
fa63aac731 | ||
|
|
ba40bf1040 | ||
|
|
2f9bcfe145 | ||
|
|
b957213fdc | ||
|
|
f51b01a5b3 | ||
|
|
d2efc85ce3 | ||
|
|
940d76e9e2 | ||
|
|
59eb8d67ed | ||
|
|
78592650e5 | ||
|
|
92d006a41b | ||
|
|
0741820711 | ||
|
|
c9ddc2b7ef | ||
|
|
f776b34d8c | ||
|
|
f47609c1f0 | ||
|
|
443b4d3116 | ||
|
|
4cf7a0cb79 | ||
|
|
9a5fe8b96d | ||
|
|
80a7ea0b7c | ||
|
|
1092447edf | ||
|
|
d2c1daf4d5 | ||
|
|
d1a41c9d7d | ||
|
|
9931ad4fa2 | ||
|
|
5a1f282292 | ||
|
|
b360316b8b | ||
|
|
c6aaa96dcb | ||
|
|
f0706f56c4 | ||
|
|
4ef2740c36 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -35,7 +35,9 @@ examples/basic
|
||||
examples/bot
|
||||
examples/component
|
||||
examples/roster
|
||||
examples/server
|
||||
examples/uuid
|
||||
examples/vcard
|
||||
test_stamp
|
||||
test-suite.log
|
||||
tests/*.o
|
||||
|
||||
16
.travis.yml
16
.travis.yml
@@ -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
|
||||
|
||||
18
ChangeLog
18
ChangeLog
@@ -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
|
||||
|
||||
116
Makefile.am
116
Makefile.am
@@ -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,43 @@ 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/server.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 +76,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/roster \
|
||||
examples/server \
|
||||
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 +116,41 @@ examples_bot_LDADD = $(STROPHE_LIBS)
|
||||
examples_component_SOURCES = examples/component.c
|
||||
examples_component_CFLAGS = $(STROPHE_FLAGS)
|
||||
examples_component_LDADD = $(STROPHE_LIBS)
|
||||
examples_roster_SOURCES = examples/roster.c
|
||||
examples_roster_CFLAGS = $(STROPHE_FLAGS)
|
||||
examples_roster_LDADD = $(STROPHE_LIBS)
|
||||
examples_server_SOURCES = examples/server.c
|
||||
examples_server_CFLAGS = $(STROPHE_FLAGS)
|
||||
examples_server_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 +163,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)
|
||||
|
||||
@@ -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
|
||||
------------
|
||||
|
||||
|
||||
@@ -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}"],
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
83
examples/server.c
Normal file
83
examples/server.c
Normal file
@@ -0,0 +1,83 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <strophe.h>
|
||||
|
||||
#ifndef ARRAY_SIZE
|
||||
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
|
||||
#endif
|
||||
|
||||
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 *success;
|
||||
|
||||
if (strcmp(xmpp_stanza_get_name(stanza), "auth") == 0) {
|
||||
success = xmpp_stanza_new(ctx);
|
||||
xmpp_stanza_set_name(success, "success");
|
||||
xmpp_stanza_set_ns(success, XMPP_NS_SASL);
|
||||
xmpp_send(conn, success);
|
||||
xmpp_stanza_release(success);
|
||||
} else
|
||||
xmpp_disconnect(conn);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void server_handler(xmpp_server_t * const srv, xmpp_conn_t * const conn,
|
||||
const xmpp_server_event_t event, const int error,
|
||||
void * const userdata)
|
||||
{
|
||||
xmpp_ctx_t *ctx = (xmpp_ctx_t *)userdata;
|
||||
|
||||
static char *attrs[] = {
|
||||
"xmlns", XMPP_NS_CLIENT, "xmlns:stream", XMPP_NS_STREAMS,
|
||||
"id", "0123456789", "from", "127.0.0.1", "version", "1.0",
|
||||
"xml:lang", "en",
|
||||
};
|
||||
|
||||
switch (event) {
|
||||
case XMPP_SERVER_ACCEPT:
|
||||
printf("Event XMPP_SERVER_ACCEPT\n");
|
||||
break;
|
||||
case XMPP_SERVER_OPEN_STREAM:
|
||||
printf("Event XMPP_SERVER_OPEN_STREAM\n");
|
||||
xmpp_handler_add(conn, message_handler, NULL, NULL, NULL, ctx);
|
||||
xmpp_conn_open_stream(conn, attrs, ARRAY_SIZE(attrs));
|
||||
xmpp_send_raw_string(conn,
|
||||
"<stream:features>"
|
||||
"<mechanisms xmlns=\"%s\"><mechanism>PLAIN</mechanism>"
|
||||
"</mechanisms></stream:features>", XMPP_NS_SASL);
|
||||
break;
|
||||
case XMPP_SERVER_DISCONNECT:
|
||||
printf("Event XMPP_SERVER_DISCONNECT\n");
|
||||
xmpp_stop(ctx);
|
||||
break;
|
||||
default:
|
||||
printf("Unknown event\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
xmpp_ctx_t *ctx;
|
||||
xmpp_log_t *log;
|
||||
xmpp_server_t *srv;
|
||||
|
||||
xmpp_initialize();
|
||||
log = xmpp_get_default_logger(XMPP_LEVEL_DEBUG);
|
||||
ctx = xmpp_ctx_new(NULL, log);
|
||||
srv = xmpp_server_new(ctx);
|
||||
xmpp_server_listen(srv, 0, server_handler, ctx);
|
||||
|
||||
xmpp_run(ctx);
|
||||
|
||||
xmpp_server_stop(srv);
|
||||
xmpp_server_free(srv);
|
||||
xmpp_ctx_free(ctx);
|
||||
xmpp_shutdown();
|
||||
|
||||
return 0;
|
||||
}
|
||||
284
examples/vcard.c
Normal file
284
examples/vcard.c
Normal 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;
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@ LOCAL_SRC_FILES := \
|
||||
../src/resolver.c \
|
||||
../src/sasl.c \
|
||||
../src/scram.c \
|
||||
../src/server.c \
|
||||
../src/sha1.c \
|
||||
../src/snprintf.c \
|
||||
../src/sock.c \
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
1. Setup
|
||||
|
||||
yum install gcc make expat-devel libstrophe
|
||||
yum install gcc make autoconf automake expat-devel openssl-devel
|
||||
|
||||
Fedora:
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
43
src/auth.c
43
src/auth.c
@@ -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");
|
||||
|
||||
130
src/common.h
130
src/common.h
@@ -1,7 +1,7 @@
|
||||
/* common.h
|
||||
** strophe XMPP client library -- internal common structures
|
||||
**
|
||||
** Copyright (C) 2005-2009 Collecta, Inc.
|
||||
** Copyright (C) 2005-2009 Collecta, Inc.
|
||||
**
|
||||
** This software is provided AS-IS with no warranty, either express or
|
||||
** implied.
|
||||
@@ -43,6 +43,11 @@ typedef struct _xmpp_connlist_t {
|
||||
struct _xmpp_connlist_t *next;
|
||||
} xmpp_connlist_t;
|
||||
|
||||
typedef struct _xmpp_serverlist_t {
|
||||
xmpp_server_t *server;
|
||||
struct _xmpp_serverlist_t *next;
|
||||
} xmpp_serverlist_t;
|
||||
|
||||
struct _xmpp_ctx_t {
|
||||
const xmpp_mem_t *mem;
|
||||
const xmpp_log_t *log;
|
||||
@@ -50,38 +55,41 @@ struct _xmpp_ctx_t {
|
||||
xmpp_rand_t *rand;
|
||||
xmpp_loop_status_t loop_status;
|
||||
xmpp_connlist_t *connlist;
|
||||
xmpp_serverlist_t *serverlist;
|
||||
|
||||
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 +113,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 +174,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 +205,7 @@ struct _xmpp_conn_t {
|
||||
/* timeouts */
|
||||
unsigned int connect_timeout;
|
||||
|
||||
/* event handlers */
|
||||
/* event handlers */
|
||||
|
||||
/* stream open handler */
|
||||
xmpp_open_handler open_handler;
|
||||
@@ -222,6 +231,24 @@ int conn_tls_start(xmpp_conn_t * const conn);
|
||||
void conn_prepare_reset(xmpp_conn_t * const conn, xmpp_open_handler handler);
|
||||
void conn_parser_reset(xmpp_conn_t * const conn);
|
||||
|
||||
typedef enum {
|
||||
XMPP_STATE_STOPPED,
|
||||
XMPP_STATE_LISTENING
|
||||
} xmpp_server_state_t;
|
||||
|
||||
struct _xmpp_server_t {
|
||||
xmpp_ctx_t *ctx;
|
||||
xmpp_server_state_t state;
|
||||
|
||||
sock_t sock;
|
||||
unsigned short port;
|
||||
xmpp_server_handler callback;
|
||||
void *userdata;
|
||||
/* incomming connections list */
|
||||
};
|
||||
|
||||
void server_accept(xmpp_server_t * const srv);
|
||||
void server_handle_open(xmpp_conn_t * const conn);
|
||||
|
||||
typedef enum {
|
||||
XMPP_STANZA_UNKNOWN,
|
||||
@@ -247,23 +274,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);
|
||||
|
||||
25
src/conn.c
25
src/conn.c
@@ -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);
|
||||
@@ -623,14 +625,15 @@ int xmpp_conn_open_stream(xmpp_conn_t * const conn, char **attributes,
|
||||
{
|
||||
char *tag;
|
||||
|
||||
if (!conn->is_raw)
|
||||
if (!conn->is_raw && conn->type != XMPP_INCOMING)
|
||||
return XMPP_EINVOP;
|
||||
|
||||
tag = _conn_build_stream_tag(conn, attributes, attributes_len);
|
||||
if (!tag)
|
||||
return XMPP_EMEM;
|
||||
|
||||
conn_prepare_reset(conn, auth_handle_open_raw);
|
||||
if (conn->type != XMPP_INCOMING)
|
||||
conn_prepare_reset(conn, auth_handle_open_raw);
|
||||
xmpp_send_raw_string(conn, "<?xml version=\"1.0\"?>%s", tag);
|
||||
xmpp_free(conn->ctx, tag);
|
||||
|
||||
@@ -874,7 +877,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 +913,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 +931,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 +948,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 +957,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 +1222,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,
|
||||
|
||||
28
src/crypto.c
28
src/crypto.c
@@ -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
|
||||
*
|
||||
|
||||
140
src/ctx.c
140
src/ctx.c
@@ -1,9 +1,9 @@
|
||||
/* ctx.c
|
||||
** strophe XMPP client library -- run-time context implementation
|
||||
**
|
||||
** Copyright (C) 2005-2009 Collecta, Inc.
|
||||
** Copyright (C) 2005-2009 Collecta, Inc.
|
||||
**
|
||||
** This software is provided AS-IS with no warranty, either express
|
||||
** This software is provided AS-IS with no warranty, either express
|
||||
** or implied.
|
||||
**
|
||||
** This 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,36 @@ 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->serverlist = 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 +441,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;
|
||||
}
|
||||
|
||||
91
src/event.c
91
src/event.c
@@ -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
|
||||
@@ -75,7 +67,9 @@
|
||||
void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
|
||||
{
|
||||
xmpp_connlist_t *connitem;
|
||||
xmpp_serverlist_t *serveritem;
|
||||
xmpp_conn_t *conn;
|
||||
xmpp_server_t *srv;
|
||||
fd_set rfds, wfds;
|
||||
sock_t max = 0;
|
||||
int ret;
|
||||
@@ -104,8 +98,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 +112,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 +141,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 +156,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 +189,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 +199,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;
|
||||
@@ -227,6 +208,23 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
|
||||
connitem = connitem->next;
|
||||
}
|
||||
|
||||
serveritem = ctx->serverlist;
|
||||
while (serveritem) {
|
||||
srv = serveritem->server;
|
||||
|
||||
switch (srv->state) {
|
||||
case XMPP_STATE_LISTENING:
|
||||
FD_SET(srv->sock, &rfds);
|
||||
if (srv->sock > max) max = srv->sock;
|
||||
break;
|
||||
case XMPP_STATE_STOPPED:
|
||||
/* do nothing */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
serveritem = serveritem->next;
|
||||
}
|
||||
|
||||
/* check for events */
|
||||
if (max > 0)
|
||||
ret = select(max + 1, &rfds, &wfds, NULL, &tv);
|
||||
@@ -290,8 +288,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);
|
||||
@@ -315,6 +312,24 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
|
||||
connitem = connitem->next;
|
||||
}
|
||||
|
||||
serveritem = ctx->serverlist;
|
||||
while (serveritem) {
|
||||
srv = serveritem->server;
|
||||
|
||||
switch (srv->state) {
|
||||
case XMPP_STATE_LISTENING:
|
||||
if (FD_ISSET(srv->sock, &rfds)) {
|
||||
server_accept(srv);
|
||||
}
|
||||
break;
|
||||
case XMPP_STATE_STOPPED:
|
||||
/* do nothing */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
serveritem = serveritem->next;
|
||||
}
|
||||
|
||||
/* fire any ready handlers */
|
||||
handler_fire_timed(ctx);
|
||||
}
|
||||
@@ -333,7 +348,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 */
|
||||
|
||||
567
src/handler.c
567
src/handler.c
@@ -1,7 +1,7 @@
|
||||
/* handler.c
|
||||
** strophe XMPP client library -- event handler management
|
||||
**
|
||||
** Copyright (C) 2005-2009 Collecta, Inc.
|
||||
** Copyright (C) 2005-2009 Collecta, Inc.
|
||||
**
|
||||
** This software is provided AS-IS with no warranty, either express
|
||||
** or implied.
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
77
src/hash.c
77
src/hash.c
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
41
src/jid.c
41
src/jid.c
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
102
src/resolver.c
102
src/resolver.c
@@ -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)
|
||||
|
||||
@@ -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__ */
|
||||
|
||||
162
src/server.c
Normal file
162
src/server.c
Normal file
@@ -0,0 +1,162 @@
|
||||
/* server.c
|
||||
* strophe XMPP client library -- server object functions
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/** @file
|
||||
* Server management.
|
||||
*/
|
||||
|
||||
/** @defgroup Server Server management
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "strophe.h"
|
||||
|
||||
static xmpp_server_t *conn2srv(xmpp_conn_t *conn);
|
||||
static void _server_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_server_t *xmpp_server_new(xmpp_ctx_t * const ctx)
|
||||
{
|
||||
xmpp_server_t *srv;
|
||||
xmpp_serverlist_t *item;
|
||||
|
||||
srv = xmpp_alloc(ctx, sizeof(*srv));
|
||||
item = xmpp_alloc(ctx, sizeof(*item));
|
||||
if (srv == NULL || item == NULL) {
|
||||
xmpp_error(ctx, "xmpp", "Failed to allocate memory.");
|
||||
xmpp_free(ctx, srv);
|
||||
xmpp_free(ctx, item);
|
||||
srv = NULL;
|
||||
item = NULL;
|
||||
}
|
||||
|
||||
if (srv != NULL) {
|
||||
memset(srv, 0, sizeof(*srv));
|
||||
srv->state = XMPP_STATE_STOPPED;
|
||||
srv->ctx = ctx;
|
||||
srv->sock = -1;
|
||||
|
||||
item->server = srv;
|
||||
item->next = ctx->serverlist;
|
||||
ctx->serverlist = item;
|
||||
}
|
||||
return srv;
|
||||
}
|
||||
|
||||
void xmpp_server_free(xmpp_server_t * const srv)
|
||||
{
|
||||
xmpp_ctx_t *ctx = srv->ctx;
|
||||
xmpp_serverlist_t *item, *prev = NULL;
|
||||
|
||||
item = ctx->serverlist;
|
||||
while (item != NULL) {
|
||||
if (item->server == srv) {
|
||||
if (prev == NULL) ctx->serverlist = item->next;
|
||||
if (prev != NULL) prev->next = item->next;
|
||||
xmpp_free(ctx, item);
|
||||
}
|
||||
prev = item;
|
||||
item = item->next;
|
||||
}
|
||||
|
||||
xmpp_free(ctx, srv);
|
||||
}
|
||||
|
||||
int xmpp_server_listen(xmpp_server_t * const srv, unsigned short port,
|
||||
xmpp_server_handler callback, void * const userdata)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (port == 0) port = XMPP_PORT_CLIENT;
|
||||
srv->callback = callback;
|
||||
srv->userdata = userdata;
|
||||
srv->port = port;
|
||||
srv->sock = sock_listen(port);
|
||||
if (srv->sock >= 0) {
|
||||
srv->state = XMPP_STATE_LISTENING;
|
||||
xmpp_debug(srv->ctx, "xmpp", "Listening on port %u.", port);
|
||||
} else
|
||||
rc = XMPP_EINT;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void xmpp_server_stop(xmpp_server_t * const srv)
|
||||
{
|
||||
srv->state = XMPP_STATE_STOPPED;
|
||||
sock_stop_listen(srv->sock);
|
||||
xmpp_debug(srv->ctx, "xmpp", "Server stopped on %u.", srv->port);
|
||||
}
|
||||
|
||||
void server_accept(xmpp_server_t * const srv)
|
||||
{
|
||||
xmpp_conn_t *conn;
|
||||
sock_t fd;
|
||||
|
||||
fd = sock_accept(srv->sock);
|
||||
if (fd >= 0) {
|
||||
xmpp_debug(srv->ctx, "xmpp", "New incoming connection on port %u.",
|
||||
srv->port);
|
||||
|
||||
conn = xmpp_conn_new(srv->ctx);
|
||||
conn->type = XMPP_INCOMING;
|
||||
conn->state = XMPP_STATE_CONNECTED;
|
||||
conn->sock = fd;
|
||||
conn->conn_handler = _server_conn_handler;
|
||||
conn->userdata = (void *)srv;
|
||||
conn->authenticated = 1; /* don't ignore handlers */
|
||||
conn_prepare_reset(conn, server_handle_open);
|
||||
|
||||
srv->callback(srv, conn, XMPP_SERVER_ACCEPT, 0, srv->userdata);
|
||||
}
|
||||
}
|
||||
|
||||
void server_handle_open(xmpp_conn_t * const conn)
|
||||
{
|
||||
xmpp_server_t *srv = conn2srv(conn);
|
||||
|
||||
/* XXX need to reset parser and re-open stream after authentication */
|
||||
|
||||
srv->callback(srv, conn, XMPP_SERVER_OPEN_STREAM, 0, srv->userdata);
|
||||
}
|
||||
|
||||
static xmpp_server_t *conn2srv(xmpp_conn_t *conn)
|
||||
{
|
||||
xmpp_server_t *srv;
|
||||
|
||||
/* XXX dirty hack */
|
||||
if (conn->ctx->serverlist != NULL)
|
||||
srv = conn->ctx->serverlist->server;
|
||||
else
|
||||
srv = NULL;
|
||||
|
||||
return srv;
|
||||
}
|
||||
|
||||
static void _server_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_server_t *srv = (xmpp_server_t *)userdata;
|
||||
|
||||
if (status == XMPP_CONN_DISCONNECT) {
|
||||
/* remove conn from the list */
|
||||
/* XXX when client sends </stream> first, server should close stream too */
|
||||
srv->callback(srv, conn, XMPP_SERVER_DISCONNECT, error, srv->userdata);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
37
src/sock.c
37
src/sock.c
@@ -109,6 +109,43 @@ sock_t sock_connect(const char * const host, const unsigned short port)
|
||||
return sock;
|
||||
}
|
||||
|
||||
sock_t sock_listen(const unsigned short port)
|
||||
{
|
||||
struct sockaddr_in addr;
|
||||
sock_t sock;
|
||||
int rc;
|
||||
|
||||
sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (sock < 0) return -1;
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(port);
|
||||
addr.sin_addr.s_addr = INADDR_ANY;
|
||||
rc = bind(sock, (struct sockaddr *)&addr, sizeof(addr));
|
||||
if (rc == 0) {
|
||||
rc = listen(sock, 100);
|
||||
sock_set_nonblocking(sock);
|
||||
}
|
||||
if (rc != 0) close(sock);
|
||||
|
||||
return rc == 0 ? sock : -1;
|
||||
}
|
||||
|
||||
int sock_stop_listen(const sock_t sock)
|
||||
{
|
||||
return sock_close(sock);
|
||||
}
|
||||
|
||||
sock_t sock_accept(const sock_t sock)
|
||||
{
|
||||
sock_t fd;
|
||||
|
||||
fd = accept(sock, NULL, NULL);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
int sock_set_keepalive(const sock_t sock, int timeout, int interval)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@@ -32,6 +32,9 @@ int sock_error(void);
|
||||
|
||||
sock_t sock_connect(const char * const host, const unsigned short port);
|
||||
int sock_close(const sock_t sock);
|
||||
sock_t sock_listen(const unsigned short port);
|
||||
int sock_stop_listen(const sock_t sock);
|
||||
sock_t sock_accept(const sock_t sock);
|
||||
|
||||
int sock_set_blocking(const sock_t sock);
|
||||
int sock_set_nonblocking(const sock_t sock);
|
||||
|
||||
60
src/stanza.c
60
src/stanza.c
@@ -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;
|
||||
|
||||
|
||||
116
src/thread.c
116
src/thread.c
@@ -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;
|
||||
}
|
||||
40
src/thread.h
40
src/thread.h
@@ -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__ */
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
36
strophe.h
36
strophe.h
@@ -139,7 +139,8 @@ typedef enum {
|
||||
typedef enum {
|
||||
XMPP_UNKNOWN,
|
||||
XMPP_CLIENT,
|
||||
XMPP_COMPONENT
|
||||
XMPP_COMPONENT,
|
||||
XMPP_INCOMING
|
||||
} xmpp_conn_type_t;
|
||||
|
||||
typedef void (*xmpp_log_handler)(void * const userdata,
|
||||
@@ -165,6 +166,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 {
|
||||
@@ -207,7 +212,7 @@ typedef struct {
|
||||
xmpp_stanza_t *stanza;
|
||||
} xmpp_stream_error_t;
|
||||
|
||||
typedef void (*xmpp_conn_handler)(xmpp_conn_t * const conn,
|
||||
typedef void (*xmpp_conn_handler)(xmpp_conn_t * const conn,
|
||||
const xmpp_conn_event_t event,
|
||||
const int error,
|
||||
xmpp_stream_error_t * const stream_error,
|
||||
@@ -259,6 +264,30 @@ void xmpp_send_raw_string(xmpp_conn_t * const conn,
|
||||
void xmpp_send_raw(xmpp_conn_t * const conn,
|
||||
const char * const data, const size_t len);
|
||||
|
||||
/* server */
|
||||
|
||||
/* opaque server object */
|
||||
typedef struct _xmpp_server_t xmpp_server_t;
|
||||
|
||||
/* server callback */
|
||||
typedef enum {
|
||||
XMPP_SERVER_ACCEPT,
|
||||
XMPP_SERVER_OPEN_STREAM,
|
||||
XMPP_SERVER_DISCONNECT,
|
||||
XMPP_SERVER_FAIL
|
||||
} xmpp_server_event_t;
|
||||
|
||||
typedef void (*xmpp_server_handler)(xmpp_server_t * const srv,
|
||||
xmpp_conn_t * const conn,
|
||||
const xmpp_server_event_t event,
|
||||
const int error,
|
||||
void * const userdata);
|
||||
|
||||
xmpp_server_t *xmpp_server_new(xmpp_ctx_t * const ctx);
|
||||
void xmpp_server_free(xmpp_server_t * const srv);
|
||||
int xmpp_server_listen(xmpp_server_t * const srv, unsigned short port,
|
||||
xmpp_server_handler callback, void * const userdata);
|
||||
void xmpp_server_stop(xmpp_server_t * const srv);
|
||||
|
||||
/* handlers */
|
||||
|
||||
@@ -394,6 +423,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 +439,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);
|
||||
|
||||
168
strophepp.h
168
strophepp.h
@@ -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);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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");
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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" };
|
||||
|
||||
Reference in New Issue
Block a user