Compare commits
32 Commits
conn-addri
...
xep-0198
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d20957a98d | ||
|
|
8cfb2d2a03 | ||
|
|
1b10e8f987 | ||
|
|
178f566ae2 | ||
|
|
0326e5c5e2 | ||
|
|
212df6d036 | ||
|
|
4b04db6b2d | ||
|
|
fb327d4bd1 | ||
|
|
a811c868ff | ||
|
|
3f05bafffb | ||
|
|
133abd096d | ||
|
|
cecd6b20e8 | ||
|
|
2272681ea2 | ||
|
|
17f79cbbb8 | ||
|
|
2570084cae | ||
|
|
b2e6458736 | ||
|
|
c192a2b181 | ||
|
|
2e325e5e68 | ||
|
|
f0436490b0 | ||
|
|
243664926f | ||
|
|
466fa2adbf | ||
|
|
284e8f4421 | ||
|
|
6852da97ae | ||
|
|
35f37e8c23 | ||
|
|
cbe6701c14 | ||
|
|
296df2fca9 | ||
|
|
7caf88a6a8 | ||
|
|
ebaad72a35 | ||
|
|
962bf4de5e | ||
|
|
884dace400 | ||
|
|
234bef4025 | ||
|
|
45cbd51633 |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -34,6 +34,7 @@ examples/active
|
||||
examples/basic
|
||||
examples/bot
|
||||
examples/component
|
||||
examples/register
|
||||
examples/roster
|
||||
examples/uuid
|
||||
examples/vcard
|
||||
@@ -54,8 +55,9 @@ tests/test_sasl
|
||||
tests/test_scram
|
||||
tests/test_sha1
|
||||
tests/test_snprintf
|
||||
tests/test_string
|
||||
tests/test_sock
|
||||
tests/test_stanza
|
||||
tests/test_string
|
||||
m4/
|
||||
libstrophe.project
|
||||
libs/
|
||||
|
||||
12
ChangeLog
12
ChangeLog
@@ -1,3 +1,15 @@
|
||||
0.10.0
|
||||
- c-ares support
|
||||
- LibreSSL support
|
||||
- examples/register implements XEP-0077
|
||||
- New API:
|
||||
- xmpp_stanza_get_child_by_name_and_ns()
|
||||
- xmpp_conn_is_connecting()
|
||||
- xmpp_conn_is_connected()
|
||||
- xmpp_conn_is_disconnected()
|
||||
- xmpp_stanza_add_child_ex()
|
||||
- xmpp_stanza_get_context()
|
||||
|
||||
0.9.3
|
||||
- PLAIN mechanism is used only when no other mechanisms are supported
|
||||
- Legacy authentication is disabled by default, can be enabled with
|
||||
|
||||
15
Makefile.am
15
Makefile.am
@@ -11,7 +11,8 @@ SSL_LIBS = @openssl_LIBS@
|
||||
RESOLV_CFLAGS = @RESOLV_CFLAGS@
|
||||
RESOLV_LIBS = @RESOLV_LIBS@
|
||||
|
||||
STROPHE_FLAGS = -I$(top_srcdir) -Wall -Wextra -Wno-unused-parameter
|
||||
WARNING_FLAGS = @WARNING_FLAGS@
|
||||
STROPHE_FLAGS = -I$(top_srcdir) $(WARNING_FLAGS)
|
||||
STROPHE_LIBS = libstrophe.la
|
||||
|
||||
## Main build targets
|
||||
@@ -100,7 +101,8 @@ noinst_PROGRAMS = \
|
||||
examples/component \
|
||||
examples/roster \
|
||||
examples/uuid \
|
||||
examples/vcard
|
||||
examples/vcard \
|
||||
examples/register
|
||||
|
||||
examples_active_SOURCES = examples/active.c
|
||||
examples_active_CFLAGS = $(STROPHE_FLAGS)
|
||||
@@ -123,6 +125,9 @@ examples_uuid_LDADD = $(STROPHE_LIBS)
|
||||
examples_vcard_SOURCES = examples/vcard.c
|
||||
examples_vcard_CFLAGS = $(STROPHE_FLAGS)
|
||||
examples_vcard_LDADD = $(STROPHE_LIBS)
|
||||
examples_register_SOURCES = examples/register.c
|
||||
examples_register_CFLAGS = $(STROPHE_FLAGS)
|
||||
examples_register_LDADD = $(STROPHE_LIBS)
|
||||
|
||||
|
||||
## Tests
|
||||
@@ -138,6 +143,7 @@ TESTS = \
|
||||
tests/test_jid \
|
||||
tests/test_snprintf \
|
||||
tests/test_string \
|
||||
tests/test_stanza \
|
||||
tests/test_resolver
|
||||
|
||||
check_PROGRAMS = $(TESTS)
|
||||
@@ -192,3 +198,8 @@ tests_test_string_SOURCES = tests/test_string.c tests/test.h
|
||||
tests_test_string_CFLAGS = $(STROPHE_FLAGS) -I$(top_srcdir)/src
|
||||
tests_test_string_LDADD = $(STROPHE_LIBS)
|
||||
tests_test_string_LDFLAGS = -static
|
||||
|
||||
tests_test_stanza_SOURCES = tests/test_stanza.c
|
||||
tests_test_stanza_CFLAGS = $(STROPHE_FLAGS)
|
||||
tests_test_stanza_LDADD = $(STROPHE_LIBS)
|
||||
tests_test_stanza_LDFLAGS = -static
|
||||
|
||||
16
configure.ac
16
configure.ac
@@ -15,8 +15,15 @@ AS_CASE([$host_os],
|
||||
[*nto*|*qnx*], [PLATFORM="qnx"],
|
||||
[*solaris*], [PLATFORM="solaris"],
|
||||
[*android*], [PLATFORM="android"],
|
||||
[*haiku*], [PLATFORM="haiku"],
|
||||
[PLATFORM="nix"])
|
||||
|
||||
WARNING_FLAGS="-Wall"
|
||||
|
||||
AS_CASE([$PLATFORM],
|
||||
[haiku], [],
|
||||
[WARNING_FLAGS="$WARNING_FLAGS -Wextra -Wno-unused-parameter"])
|
||||
|
||||
AC_ARG_WITH([libxml2],
|
||||
[AS_HELP_STRING([--with-libxml2], [use libxml2 for XML parsing, expat is the default])])
|
||||
AC_ARG_ENABLE([tls],
|
||||
@@ -24,6 +31,9 @@ AC_ARG_ENABLE([tls],
|
||||
AC_ARG_ENABLE([cares],
|
||||
[AS_HELP_STRING([--enable-cares], [use c-ares for DNS resolution])])
|
||||
|
||||
AC_SEARCH_LIBS([socket], [network socket])
|
||||
#AC_CHECK_FUNCS([snprintf vsnprintf])
|
||||
|
||||
if test "x$enable_tls" != xno; then
|
||||
PKG_CHECK_MODULES([openssl], [openssl],
|
||||
[PC_REQUIRES="openssl ${PC_REQUIRES}"],
|
||||
@@ -64,7 +74,7 @@ if test "x$with_libxml2" != xno -a "x$with_parser" = x; then
|
||||
[
|
||||
with_parser="libxml2"
|
||||
libxml2_CFLAGS="-I${includedir}/libxml2"
|
||||
libxml2_LIBS="-lxml2"
|
||||
libxml2_LIBS="-lxml2 -lm"
|
||||
PC_LIBS="${libxml2_LIBS} ${PC_LIBS}"
|
||||
PC_CFLAGS="${libxml2_CFLAGS} ${PC_CFLAGS}"
|
||||
])
|
||||
@@ -84,8 +94,6 @@ fi
|
||||
|
||||
AC_MSG_NOTICE([libstrophe will use the $with_parser XML parser])
|
||||
|
||||
AC_SEARCH_LIBS([socket], [socket])
|
||||
|
||||
if test "x$enable_cares" = xyes; then
|
||||
PKG_CHECK_MODULES([libcares], [libcares >= 1.7.0],
|
||||
[
|
||||
@@ -103,6 +111,7 @@ AS_CASE([$PLATFORM],
|
||||
[qnx], [RESOLV_LIBS="-lsocket"],
|
||||
[solaris], [RESOLV_LIBS="-lresolv -lsocket -lnsl"],
|
||||
[android], [RESOLV_LIBS=""],
|
||||
[haiku], [RESOLV_LIBS="-lnetwork"],
|
||||
[RESOLV_LIBS="-lresolv"])
|
||||
|
||||
LIBS_TMP="${LIBS}"
|
||||
@@ -144,5 +153,6 @@ AC_SUBST(PARSER_CFLAGS)
|
||||
AC_SUBST(PARSER_LIBS)
|
||||
AC_SUBST(RESOLV_CFLAGS)
|
||||
AC_SUBST(RESOLV_LIBS)
|
||||
AC_SUBST(WARNING_FLAGS)
|
||||
AC_CONFIG_FILES([Makefile libstrophe.pc])
|
||||
AC_OUTPUT
|
||||
|
||||
357
examples/register.c
Normal file
357
examples/register.c
Normal file
@@ -0,0 +1,357 @@
|
||||
/* register.c
|
||||
* strophe XMPP client library -- In-band registration (XEP-0077)
|
||||
*
|
||||
* Copyright (C) 2020 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This example uses a "raw" connection to establish connection to a server
|
||||
* without account. Then it queries server to register new account according
|
||||
* to XEP-0077.
|
||||
*
|
||||
* How to use it. After the application connects and receives instructions
|
||||
* from the server, user will be prompted to type information such as
|
||||
* username, password, etc. Press enter without typing if you want to skip
|
||||
* a field and not to send it to the server.
|
||||
*
|
||||
* Notice, the example doesn't implement forms. Therefore, it won't work
|
||||
* in complicated scenarios.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <strophe.h>
|
||||
|
||||
typedef struct {
|
||||
xmpp_ctx_t *ctx;
|
||||
const char *jid;
|
||||
} xmpp_reg_t;
|
||||
|
||||
#define FEATURES_TIMEOUT 5000 /* 5 seconds */
|
||||
|
||||
static void iq_reg_send_form(xmpp_reg_t *reg,
|
||||
xmpp_conn_t *conn,
|
||||
xmpp_stanza_t *stanza)
|
||||
{
|
||||
xmpp_ctx_t *ctx = reg->ctx;
|
||||
xmpp_stanza_t *query;
|
||||
xmpp_stanza_t *next;
|
||||
xmpp_stanza_t *elem;
|
||||
xmpp_stanza_t *text;
|
||||
xmpp_stanza_t *iq;
|
||||
const char *name;
|
||||
ssize_t rc;
|
||||
size_t size;
|
||||
char *s;
|
||||
|
||||
query = xmpp_stanza_get_child_by_name(stanza, "query");
|
||||
if (!query) {
|
||||
xmpp_disconnect(conn);
|
||||
return;
|
||||
}
|
||||
|
||||
next = xmpp_stanza_get_children(query);
|
||||
query = xmpp_stanza_new(ctx);
|
||||
xmpp_stanza_set_name(query, "query");
|
||||
xmpp_stanza_set_ns(query, XMPP_NS_REGISTER);
|
||||
while (next) {
|
||||
name = xmpp_stanza_get_name(next);
|
||||
if (name && strcmp(name, "instructions") == 0) {
|
||||
s = xmpp_stanza_get_text(next);
|
||||
printf("instructions: %s\n", s);
|
||||
xmpp_free(ctx, s);
|
||||
} else {
|
||||
printf("%s: ", name);
|
||||
s = NULL;
|
||||
size = 0;
|
||||
rc = getline(&s, &size, stdin);
|
||||
if (rc > 0 && s[rc - 1] == '\n')
|
||||
s[rc - 1] = '\0';
|
||||
if (rc > 0 && strlen(s) > 0) {
|
||||
elem = xmpp_stanza_new(ctx);
|
||||
text = xmpp_stanza_new(ctx);
|
||||
xmpp_stanza_set_text(text, s);
|
||||
xmpp_stanza_set_name(elem, name);
|
||||
xmpp_stanza_add_child(elem, text);
|
||||
xmpp_stanza_add_child(query, elem);
|
||||
xmpp_stanza_release(text);
|
||||
xmpp_stanza_release(elem);
|
||||
}
|
||||
free(s);
|
||||
}
|
||||
next = xmpp_stanza_get_next(next);
|
||||
}
|
||||
|
||||
if (xmpp_stanza_get_children(query) == NULL) {
|
||||
fprintf(stderr, "DEBUG: nothing to send\n");
|
||||
xmpp_disconnect(conn);
|
||||
} else {
|
||||
iq = xmpp_iq_new(ctx, "set", "reg2");
|
||||
xmpp_stanza_add_child(iq, query);
|
||||
xmpp_stanza_release(query);
|
||||
xmpp_send(conn, iq);
|
||||
xmpp_stanza_release(iq);
|
||||
}
|
||||
}
|
||||
|
||||
static int iq_reg2_cb(xmpp_conn_t * const conn,
|
||||
xmpp_stanza_t * const stanza,
|
||||
void * const userdata)
|
||||
{
|
||||
const char *type;
|
||||
|
||||
type = xmpp_stanza_get_type(stanza);
|
||||
if (!type || strcmp(type, "error") == 0) {
|
||||
fprintf(stderr, "DEBUG: error during registration\n");
|
||||
goto quit;
|
||||
}
|
||||
|
||||
if (strcmp(type, "result") != 0) {
|
||||
fprintf(stderr, "DEBUG: expected type 'result', but got %s\n", type);
|
||||
goto quit;
|
||||
}
|
||||
|
||||
fprintf(stderr, "DEBUG: successful registration\n");
|
||||
|
||||
quit:
|
||||
xmpp_disconnect(conn);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iq_reg_cb(xmpp_conn_t * const conn,
|
||||
xmpp_stanza_t * const stanza,
|
||||
void * const userdata)
|
||||
{
|
||||
xmpp_reg_t *reg = (xmpp_reg_t *)userdata;
|
||||
xmpp_stanza_t *registered = NULL;
|
||||
xmpp_stanza_t *query;
|
||||
const char *type;
|
||||
|
||||
type = xmpp_stanza_get_type(stanza);
|
||||
if (!type || strcmp(type, "error") == 0) {
|
||||
fprintf(stderr, "DEBUG: error during registration\n");
|
||||
xmpp_disconnect(conn);
|
||||
goto quit;
|
||||
}
|
||||
|
||||
if (strcmp(type, "result") != 0) {
|
||||
fprintf(stderr, "DEBUG: expected type 'result', but got %s\n", type);
|
||||
xmpp_disconnect(conn);
|
||||
goto quit;
|
||||
}
|
||||
|
||||
query = xmpp_stanza_get_child_by_name(stanza, "query");
|
||||
if (query)
|
||||
registered = xmpp_stanza_get_child_by_name(query, "registered");
|
||||
if (registered != NULL) {
|
||||
fprintf(stderr, "DEBUG: already registered\n");
|
||||
xmpp_disconnect(conn);
|
||||
goto quit;
|
||||
}
|
||||
xmpp_id_handler_add(conn, iq_reg2_cb, "reg2", reg);
|
||||
iq_reg_send_form(reg, conn, stanza);
|
||||
|
||||
quit:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _handle_error(xmpp_conn_t * const conn,
|
||||
xmpp_stanza_t * const stanza,
|
||||
void * const userdata)
|
||||
{
|
||||
fprintf(stderr, "DEBUG: received stream error\n");
|
||||
xmpp_disconnect(conn);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _handle_proceedtls_default(xmpp_conn_t * const conn,
|
||||
xmpp_stanza_t * const stanza,
|
||||
void * const userdata)
|
||||
{
|
||||
const char *name = xmpp_stanza_get_name(stanza);
|
||||
|
||||
if (strcmp(name, "proceed") == 0) {
|
||||
fprintf(stderr, "DEBUG: proceeding with TLS\n");
|
||||
if (xmpp_conn_tls_start(conn) == 0) {
|
||||
xmpp_handler_delete(conn, _handle_error);
|
||||
xmpp_conn_open_stream_default(conn);
|
||||
} else {
|
||||
fprintf(stderr, "DEBUG: TLS failed\n");
|
||||
/* failed tls spoils the connection, so disconnect */
|
||||
xmpp_disconnect(conn);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _handle_missing_features(xmpp_conn_t * const conn,
|
||||
void * const userdata)
|
||||
{
|
||||
fprintf(stderr, "DEBUG: timeout\n");
|
||||
xmpp_disconnect(conn);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _handle_features(xmpp_conn_t * const conn,
|
||||
xmpp_stanza_t * const stanza,
|
||||
void * const userdata)
|
||||
{
|
||||
xmpp_reg_t *reg = (xmpp_reg_t *)userdata;
|
||||
xmpp_ctx_t *ctx = reg->ctx;
|
||||
xmpp_stanza_t *child;
|
||||
xmpp_stanza_t *iq;
|
||||
char *domain;
|
||||
|
||||
xmpp_timed_handler_delete(conn, _handle_missing_features);
|
||||
|
||||
/* secure connection if possible */
|
||||
child = xmpp_stanza_get_child_by_name(stanza, "starttls");
|
||||
if (child && (strcmp(xmpp_stanza_get_ns(child), XMPP_NS_TLS) == 0)) {
|
||||
fprintf(stderr, "DEBUG: server supports TLS, try to establish\n");
|
||||
child = xmpp_stanza_new(ctx);
|
||||
xmpp_stanza_set_name(child, "starttls");
|
||||
xmpp_stanza_set_ns(child, XMPP_NS_TLS);
|
||||
xmpp_handler_add(conn, _handle_proceedtls_default,
|
||||
XMPP_NS_TLS, NULL, NULL, NULL);
|
||||
xmpp_send(conn, child);
|
||||
xmpp_stanza_release(child);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* check whether server supports in-band registration */
|
||||
child = xmpp_stanza_get_child_by_name(stanza, "register");
|
||||
if (child && strcmp(xmpp_stanza_get_ns(child), XMPP_NS_REGISTER) == 0) {
|
||||
fprintf(stderr, "DEBUG: server doesn't support in-band registration\n");
|
||||
xmpp_disconnect(conn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
fprintf(stderr, "DEBUG: server supports in-band registration\n");
|
||||
domain = xmpp_jid_domain(ctx, reg->jid);
|
||||
iq = xmpp_iq_new(ctx, "get", "reg1");
|
||||
xmpp_stanza_set_to(iq, domain);
|
||||
child = xmpp_stanza_new(ctx);
|
||||
xmpp_stanza_set_name(child, "query");
|
||||
xmpp_stanza_set_ns(child, XMPP_NS_REGISTER);
|
||||
xmpp_stanza_add_child(iq, child);
|
||||
|
||||
xmpp_handler_add(conn, iq_reg_cb, XMPP_NS_REGISTER, "iq", NULL, reg);
|
||||
xmpp_send(conn, iq);
|
||||
|
||||
xmpp_free(ctx, domain);
|
||||
xmpp_stanza_release(child);
|
||||
xmpp_stanza_release(iq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void conn_handler(xmpp_conn_t * const conn,
|
||||
const xmpp_conn_event_t status,
|
||||
const int error,
|
||||
xmpp_stream_error_t * const stream_error,
|
||||
void * const userdata)
|
||||
{
|
||||
xmpp_reg_t *reg = (xmpp_reg_t *)userdata;
|
||||
int secured;
|
||||
|
||||
if (status == XMPP_CONN_RAW_CONNECT) {
|
||||
fprintf(stderr, "DEBUG: raw connection established\n");
|
||||
xmpp_conn_open_stream_default(conn);
|
||||
} else if (status == XMPP_CONN_CONNECT) {
|
||||
fprintf(stderr, "DEBUG: stream opened\n");
|
||||
secured = xmpp_conn_is_secured(conn);
|
||||
fprintf(stderr, "DEBUG: connection is %s.\n",
|
||||
secured ? "secured" : "NOT secured");
|
||||
|
||||
/* setup handler for stream:error */
|
||||
xmpp_handler_add(conn, _handle_error, XMPP_NS_STREAMS,
|
||||
"error", NULL, NULL);
|
||||
|
||||
/* setup handlers for incoming <stream:features> */
|
||||
xmpp_handler_add(conn, _handle_features, XMPP_NS_STREAMS,
|
||||
"features", NULL, reg);
|
||||
xmpp_timed_handler_add(conn, _handle_missing_features,
|
||||
FEATURES_TIMEOUT, NULL);
|
||||
} else {
|
||||
fprintf(stderr, "DEBUG: disconnected\n");
|
||||
xmpp_stop(reg->ctx);
|
||||
}
|
||||
}
|
||||
|
||||
xmpp_reg_t *xmpp_reg_new(void)
|
||||
{
|
||||
xmpp_reg_t *reg;
|
||||
|
||||
reg = malloc(sizeof(*reg));
|
||||
if (reg != NULL) {
|
||||
memset(reg, 0, sizeof(*reg));
|
||||
}
|
||||
return reg;
|
||||
}
|
||||
|
||||
void xmpp_reg_release(xmpp_reg_t *reg)
|
||||
{
|
||||
free(reg);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
xmpp_ctx_t *ctx;
|
||||
xmpp_conn_t *conn;
|
||||
xmpp_log_t *log;
|
||||
xmpp_reg_t *reg;
|
||||
const char *jid;
|
||||
const char *host = NULL;
|
||||
char *domain;
|
||||
|
||||
if (argc < 2 || argc > 3) {
|
||||
fprintf(stderr, "Usage: %s <jid> [<host>]\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
jid = argv[1];
|
||||
if (argc > 2)
|
||||
host = argv[2];
|
||||
|
||||
/*
|
||||
* Note, this example doesn't handle errors. Applications should check
|
||||
* return values of non-void functions.
|
||||
*/
|
||||
|
||||
xmpp_initialize();
|
||||
log = xmpp_get_default_logger(XMPP_LEVEL_DEBUG);
|
||||
ctx = xmpp_ctx_new(NULL, log);
|
||||
conn = xmpp_conn_new(ctx);
|
||||
|
||||
/* jid can be a jid or domain for "raw" connection */
|
||||
domain = xmpp_jid_domain(ctx, jid);
|
||||
xmpp_conn_set_jid(conn, domain);
|
||||
xmpp_free(ctx, domain);
|
||||
|
||||
/* private data */
|
||||
reg = xmpp_reg_new();
|
||||
reg->ctx = ctx;
|
||||
reg->jid = jid;
|
||||
|
||||
xmpp_connect_raw(conn, host, 0, conn_handler, reg);
|
||||
xmpp_run(ctx);
|
||||
|
||||
/* release private data */
|
||||
xmpp_reg_release(reg);
|
||||
|
||||
xmpp_conn_release(conn);
|
||||
xmpp_ctx_free(ctx);
|
||||
xmpp_shutdown();
|
||||
|
||||
return 0;
|
||||
}
|
||||
53
src/auth.c
53
src/auth.c
@@ -24,7 +24,7 @@
|
||||
#include "rand.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define strcasecmp stricmp
|
||||
#define strcasecmp _stricmp
|
||||
#endif
|
||||
|
||||
/* TODO: these should configurable at runtime on a per connection basis */
|
||||
@@ -99,6 +99,9 @@ static int _handle_session(xmpp_conn_t * const conn,
|
||||
void * const userdata);
|
||||
static int _handle_missing_session(xmpp_conn_t * const conn,
|
||||
void * const userdata);
|
||||
static int _handle_sm(xmpp_conn_t * const conn,
|
||||
xmpp_stanza_t * const stanza,
|
||||
void * const userdata);
|
||||
static int _handle_missing_handshake(xmpp_conn_t * const conn,
|
||||
void * const userdata);
|
||||
|
||||
@@ -814,6 +817,12 @@ static int _handle_features_sasl(xmpp_conn_t * const conn,
|
||||
strcmp(ns, XMPP_NS_SESSION) == 0;
|
||||
}
|
||||
|
||||
opt = xmpp_stanza_get_child_by_ns(stanza, XMPP_NS_SM);
|
||||
if (opt && strcmp(xmpp_stanza_get_name(opt), "sm") == 0) {
|
||||
/* stream management supported */
|
||||
conn->sm_support = 1;
|
||||
}
|
||||
|
||||
/* if bind is required, go ahead and start it */
|
||||
if (conn->bind_required) {
|
||||
/* bind resource */
|
||||
@@ -902,7 +911,7 @@ static int _handle_bind(xmpp_conn_t * const conn,
|
||||
void * const userdata)
|
||||
{
|
||||
const char *type;
|
||||
xmpp_stanza_t *iq, *session;
|
||||
xmpp_stanza_t *iq, *enable, *session, *binding, *jid_stanza;
|
||||
|
||||
/* delete missing bind handler */
|
||||
xmpp_timed_handler_delete(conn, _handle_missing_bind);
|
||||
@@ -913,12 +922,11 @@ static int _handle_bind(xmpp_conn_t * const conn,
|
||||
xmpp_error(conn->ctx, "xmpp", "Binding failed.");
|
||||
xmpp_disconnect(conn);
|
||||
} else if (type && strcmp(type, "result") == 0) {
|
||||
xmpp_stanza_t *binding = xmpp_stanza_get_child_by_name(stanza, "bind");
|
||||
binding = xmpp_stanza_get_child_by_name(stanza, "bind");
|
||||
xmpp_debug(conn->ctx, "xmpp", "Bind successful.");
|
||||
|
||||
if (binding) {
|
||||
xmpp_stanza_t *jid_stanza = xmpp_stanza_get_child_by_name(binding,
|
||||
"jid");
|
||||
jid_stanza = xmpp_stanza_get_child_by_name(binding, "jid");
|
||||
if (jid_stanza) {
|
||||
conn->bound_jid = xmpp_stanza_get_text(jid_stanza);
|
||||
}
|
||||
@@ -954,7 +962,23 @@ static int _handle_bind(xmpp_conn_t * const conn,
|
||||
/* send session establishment request */
|
||||
xmpp_send(conn, iq);
|
||||
xmpp_stanza_release(iq);
|
||||
} else {
|
||||
}
|
||||
|
||||
if (conn->sm_support) {
|
||||
enable = xmpp_stanza_new(conn->ctx);
|
||||
if (!enable) {
|
||||
disconnect_mem_error(conn);
|
||||
return 0;
|
||||
}
|
||||
xmpp_stanza_set_name(enable, "enable");
|
||||
xmpp_stanza_set_ns(enable, XMPP_NS_SM);
|
||||
handler_add(conn, _handle_sm, XMPP_NS_SM, NULL, NULL, NULL);
|
||||
xmpp_send(conn, enable);
|
||||
xmpp_stanza_release(enable);
|
||||
conn->sm_sent_nr = 0;
|
||||
}
|
||||
|
||||
if (!conn->session_required) {
|
||||
conn->authenticated = 1;
|
||||
|
||||
/* call connection handler */
|
||||
@@ -1023,6 +1047,23 @@ static int _handle_missing_legacy(xmpp_conn_t * const conn,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _handle_sm(xmpp_conn_t * const conn,
|
||||
xmpp_stanza_t * const stanza,
|
||||
void * const userdata)
|
||||
{
|
||||
const char *name;
|
||||
|
||||
name = xmpp_stanza_get_name(stanza);
|
||||
if (name && strcmp(name, "enabled") == 0) {
|
||||
conn->sm_enabled = 1;
|
||||
conn->sm_handled_nr = 0;
|
||||
} else {
|
||||
conn->sm_enabled = 0;
|
||||
xmpp_warn(conn->ctx, "auth", "Stream management failed.");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _handle_legacy(xmpp_conn_t * const conn,
|
||||
xmpp_stanza_t * const stanza,
|
||||
void * const userdata)
|
||||
|
||||
@@ -130,7 +130,7 @@ struct _xmpp_handlist_t {
|
||||
char *name;
|
||||
char *type;
|
||||
};
|
||||
};
|
||||
} u;
|
||||
};
|
||||
|
||||
#define MAX_DOMAIN_LEN 256
|
||||
@@ -178,6 +178,10 @@ struct _xmpp_conn_t {
|
||||
/* if server returns <bind/> or <session/> we must do them */
|
||||
int bind_required;
|
||||
int session_required;
|
||||
int sm_support;
|
||||
int sm_enabled;
|
||||
uint32_t sm_handled_nr;
|
||||
uint32_t sm_sent_nr;
|
||||
|
||||
char *lang;
|
||||
char *domain;
|
||||
|
||||
83
src/conn.c
83
src/conn.c
@@ -62,6 +62,8 @@ static void _handle_stream_end(char *name,
|
||||
void * const userdata);
|
||||
static void _handle_stream_stanza(xmpp_stanza_t *stanza,
|
||||
void * const userdata);
|
||||
static void _conn_sm_handle_stanza(xmpp_conn_t * const conn,
|
||||
xmpp_stanza_t *stanza);
|
||||
static unsigned short _conn_default_port(xmpp_conn_t * const conn,
|
||||
xmpp_conn_type_t type);
|
||||
static void _conn_reset(xmpp_conn_t * const conn);
|
||||
@@ -145,6 +147,10 @@ xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t * const ctx)
|
||||
|
||||
conn->bind_required = 0;
|
||||
conn->session_required = 0;
|
||||
conn->sm_support = 0;
|
||||
conn->sm_enabled = 0;
|
||||
conn->sm_handled_nr = 0;
|
||||
conn->sm_sent_nr = 0;
|
||||
|
||||
conn->parser = parser_new(conn->ctx,
|
||||
_handle_stream_start,
|
||||
@@ -254,6 +260,12 @@ int xmpp_conn_release(xmpp_conn_t * const conn)
|
||||
else {
|
||||
ctx = conn->ctx;
|
||||
|
||||
if (conn->state == XMPP_STATE_CONNECTING ||
|
||||
conn->state == XMPP_STATE_CONNECTED)
|
||||
{
|
||||
conn_disconnect(conn);
|
||||
}
|
||||
|
||||
/* remove connection from context's connlist */
|
||||
if (ctx->connlist->conn == conn) {
|
||||
item = ctx->connlist;
|
||||
@@ -299,7 +311,7 @@ int xmpp_conn_release(xmpp_conn_t * const conn)
|
||||
while (hlitem) {
|
||||
thli = hlitem;
|
||||
hlitem = hlitem->next;
|
||||
xmpp_free(conn->ctx, thli->id);
|
||||
xmpp_free(conn->ctx, thli->u.id);
|
||||
xmpp_free(conn->ctx, thli);
|
||||
}
|
||||
}
|
||||
@@ -311,9 +323,9 @@ int xmpp_conn_release(xmpp_conn_t * const conn)
|
||||
thli = hlitem;
|
||||
hlitem = hlitem->next;
|
||||
|
||||
if (thli->ns) xmpp_free(ctx, thli->ns);
|
||||
if (thli->name) xmpp_free(ctx, thli->name);
|
||||
if (thli->type) xmpp_free(ctx, thli->type);
|
||||
if (thli->u.ns) xmpp_free(ctx, thli->u.ns);
|
||||
if (thli->u.name) xmpp_free(ctx, thli->u.name);
|
||||
if (thli->u.type) xmpp_free(ctx, thli->u.type);
|
||||
xmpp_free(ctx, thli);
|
||||
}
|
||||
|
||||
@@ -1002,6 +1014,37 @@ int xmpp_conn_is_secured(xmpp_conn_t * const conn)
|
||||
return conn->secured && !conn->tls_failed && conn->tls != NULL ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TRUE if connection is in connecting state and FALSE otherwise
|
||||
*
|
||||
* @ingroup Connections
|
||||
*/
|
||||
int xmpp_conn_is_connecting(xmpp_conn_t * const conn)
|
||||
{
|
||||
return conn->state == XMPP_STATE_CONNECTING ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TRUE if connection is in connected state and FALSE otherwise
|
||||
*
|
||||
* @ingroup Connections
|
||||
*/
|
||||
int xmpp_conn_is_connected(xmpp_conn_t * const conn)
|
||||
{
|
||||
return conn->state == XMPP_STATE_CONNECTED ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TRUE if connection is in disconnected state and FALSE otherwise
|
||||
*
|
||||
* @ingroup Connections
|
||||
*/
|
||||
int xmpp_conn_is_disconnected(xmpp_conn_t * const conn)
|
||||
{
|
||||
return conn->state == XMPP_STATE_DISCONNECTED ? 1 : 0;
|
||||
}
|
||||
|
||||
|
||||
/* timed handler for cleanup if normal disconnect procedure takes too long */
|
||||
static int _disconnect_cleanup(xmpp_conn_t * const conn,
|
||||
void * const userdata)
|
||||
@@ -1179,6 +1222,36 @@ static void _handle_stream_stanza(xmpp_stanza_t *stanza,
|
||||
}
|
||||
|
||||
handler_fire_stanza(conn, stanza);
|
||||
if (conn->sm_enabled)
|
||||
_conn_sm_handle_stanza(conn, stanza);
|
||||
}
|
||||
|
||||
/* XEP-0198 stream management */
|
||||
static void _conn_sm_handle_stanza(xmpp_conn_t * const conn,
|
||||
xmpp_stanza_t *stanza)
|
||||
{
|
||||
xmpp_stanza_t *a;
|
||||
const char *name;
|
||||
const char *ns;
|
||||
char h[11];
|
||||
|
||||
ns = xmpp_stanza_get_ns(stanza);
|
||||
if (ns && strcmp(ns, XMPP_NS_SM) != 0)
|
||||
++conn->sm_handled_nr;
|
||||
else {
|
||||
name = xmpp_stanza_get_name(stanza);
|
||||
if (name && strcmp(name, "r") == 0) {
|
||||
a = xmpp_stanza_new(conn->ctx);
|
||||
if (!a)
|
||||
return; /* XXX */
|
||||
xmpp_stanza_set_name(a, "a");
|
||||
xmpp_stanza_set_ns(a, XMPP_NS_SM);
|
||||
xmpp_snprintf(h, sizeof(h), "%u", conn->sm_handled_nr);
|
||||
xmpp_stanza_set_attribute(a, "h", h);
|
||||
xmpp_send(conn, a);
|
||||
xmpp_stanza_release(a);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned short _conn_default_port(xmpp_conn_t * const conn,
|
||||
@@ -1237,6 +1310,8 @@ static void _conn_reset(xmpp_conn_t * const conn)
|
||||
conn->error = 0;
|
||||
|
||||
conn->tls_support = 0;
|
||||
conn->sm_support = 0;
|
||||
conn->sm_enabled = 0;
|
||||
conn->bind_required = 0;
|
||||
conn->session_required = 0;
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
#include "util.h"
|
||||
|
||||
/* Workaround for visual studio without va_copy support. */
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1800
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1800 || defined(__HAIKU__)
|
||||
#define va_copy(d,s) ((d) = (s))
|
||||
#endif
|
||||
|
||||
|
||||
17
src/event.c
17
src/event.c
@@ -41,16 +41,25 @@
|
||||
#define _sleep(x) usleep((x) * 1000)
|
||||
#else
|
||||
#include <winsock2.h>
|
||||
#ifndef ETIMEDOUT
|
||||
#define ETIMEDOUT WSAETIMEDOUT
|
||||
#endif
|
||||
#ifndef ECONNRESET
|
||||
#define ECONNRESET WSAECONNRESET
|
||||
#endif
|
||||
#ifndef ECONNABORTED
|
||||
#define ECONNABORTED WSAECONNABORTED
|
||||
#endif
|
||||
#define _sleep(x) Sleep(x)
|
||||
#endif
|
||||
|
||||
#include <strophe.h>
|
||||
#include "strophe.h"
|
||||
#include "common.h"
|
||||
#include "parser.h"
|
||||
|
||||
/** Max buffer size for receiving messages. */
|
||||
#define STROPE_MESSAGE_BUFFER_SIZE 4096
|
||||
|
||||
/** 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
|
||||
@@ -74,7 +83,7 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
|
||||
struct timeval tv;
|
||||
xmpp_send_queue_t *sq, *tsq;
|
||||
int towrite;
|
||||
char buf[4096];
|
||||
char buf[STROPE_MESSAGE_BUFFER_SIZE];
|
||||
uint64_t next;
|
||||
uint64_t usec;
|
||||
int tls_read_bytes = 0;
|
||||
@@ -254,9 +263,9 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
|
||||
case XMPP_STATE_CONNECTED:
|
||||
if (FD_ISSET(conn->sock, &rfds) || (conn->tls && tls_pending(conn->tls))) {
|
||||
if (conn->tls) {
|
||||
ret = tls_read(conn->tls, buf, 4096);
|
||||
ret = tls_read(conn->tls, buf, STROPE_MESSAGE_BUFFER_SIZE);
|
||||
} else {
|
||||
ret = sock_read(conn->sock, buf, 4096);
|
||||
ret = sock_read(conn->sock, buf, STROPE_MESSAGE_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
if (ret > 0) {
|
||||
|
||||
@@ -90,7 +90,7 @@ void handler_fire_stanza(xmpp_conn_t * const conn,
|
||||
/* replace old value */
|
||||
hash_add(conn->id_handlers, id, head);
|
||||
}
|
||||
xmpp_free(conn->ctx, item->id);
|
||||
xmpp_free(conn->ctx, item->u.id);
|
||||
xmpp_free(conn->ctx, item);
|
||||
}
|
||||
item = next;
|
||||
@@ -116,10 +116,10 @@ void handler_fire_stanza(xmpp_conn_t * const conn,
|
||||
}
|
||||
|
||||
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->u.ns || (ns && strcmp(ns, item->u.ns) == 0) ||
|
||||
xmpp_stanza_get_child_by_ns(stanza, item->u.ns)) &&
|
||||
(!item->u.name || (name && strcmp(name, item->u.name) == 0)) &&
|
||||
(!item->u.type || (type && strcmp(type, item->u.type) == 0))) {
|
||||
|
||||
ret = ((xmpp_handler)(item->handler))(conn, stanza, item->userdata);
|
||||
/* list may be changed during execution of a handler */
|
||||
@@ -127,9 +127,9 @@ void handler_fire_stanza(xmpp_conn_t * const conn,
|
||||
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);
|
||||
if (item->u.ns) xmpp_free(conn->ctx, item->u.ns);
|
||||
if (item->u.name) xmpp_free(conn->ctx, item->u.name);
|
||||
if (item->u.type) xmpp_free(conn->ctx, item->u.type);
|
||||
xmpp_free(conn->ctx, item);
|
||||
}
|
||||
}
|
||||
@@ -178,10 +178,10 @@ uint64_t handler_fire_timed(xmpp_ctx_t * const ctx)
|
||||
|
||||
next = item->next;
|
||||
timestamp = time_stamp();
|
||||
elapsed = time_elapsed(item->last_stamp, timestamp);
|
||||
if (elapsed >= item->period) {
|
||||
elapsed = time_elapsed(item->u.last_stamp, timestamp);
|
||||
if (elapsed >= item->u.period) {
|
||||
/* fire! */
|
||||
item->last_stamp = timestamp;
|
||||
item->u.last_stamp = timestamp;
|
||||
ret = ((xmpp_timed_handler)item->handler)(conn, item->userdata);
|
||||
/* list may be changed during execution of a handler */
|
||||
next = item->next;
|
||||
@@ -190,8 +190,8 @@ uint64_t handler_fire_timed(xmpp_ctx_t * const ctx)
|
||||
_handler_item_remove(&conn->timed_handlers, item);
|
||||
xmpp_free(conn->ctx, item);
|
||||
}
|
||||
} else if (min > (item->period - elapsed))
|
||||
min = item->period - elapsed;
|
||||
} else if (min > (item->u.period - elapsed))
|
||||
min = item->u.period - elapsed;
|
||||
|
||||
item = next;
|
||||
}
|
||||
@@ -215,7 +215,7 @@ 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->u.last_stamp = time_stamp();
|
||||
|
||||
handitem = handitem->next;
|
||||
}
|
||||
@@ -248,8 +248,8 @@ static void _timed_handler_add(xmpp_conn_t * const conn,
|
||||
item->enabled = 0;
|
||||
item->next = NULL;
|
||||
|
||||
item->period = period;
|
||||
item->last_stamp = time_stamp();
|
||||
item->u.period = period;
|
||||
item->u.last_stamp = time_stamp();
|
||||
|
||||
/* append item to list */
|
||||
if (!conn->timed_handlers)
|
||||
@@ -322,8 +322,8 @@ static void _id_handler_add(xmpp_conn_t * const conn,
|
||||
item->enabled = 0;
|
||||
item->next = NULL;
|
||||
|
||||
item->id = xmpp_strdup(conn->ctx, id);
|
||||
if (!item->id) {
|
||||
item->u.id = xmpp_strdup(conn->ctx, id);
|
||||
if (!item->u.id) {
|
||||
xmpp_free(conn->ctx, item);
|
||||
return;
|
||||
}
|
||||
@@ -368,7 +368,7 @@ void xmpp_id_handler_delete(xmpp_conn_t * const conn,
|
||||
hash_add(conn->id_handlers, id, next);
|
||||
}
|
||||
|
||||
xmpp_free(conn->ctx, item->id);
|
||||
xmpp_free(conn->ctx, item->u.id);
|
||||
xmpp_free(conn->ctx, item);
|
||||
item = next;
|
||||
} else {
|
||||
@@ -410,31 +410,31 @@ static void _handler_add(xmpp_conn_t * const conn,
|
||||
item->next = NULL;
|
||||
|
||||
if (ns) {
|
||||
item->ns = xmpp_strdup(conn->ctx, ns);
|
||||
if (!item->ns) {
|
||||
item->u.ns = xmpp_strdup(conn->ctx, ns);
|
||||
if (!item->u.ns) {
|
||||
xmpp_free(conn->ctx, item);
|
||||
return;
|
||||
}
|
||||
} else
|
||||
item->ns = NULL;
|
||||
item->u.ns = NULL;
|
||||
if (name) {
|
||||
item->name = xmpp_strdup(conn->ctx, name);
|
||||
if (!item->name) {
|
||||
if (item->ns) xmpp_free(conn->ctx, item->ns);
|
||||
item->u.name = xmpp_strdup(conn->ctx, name);
|
||||
if (!item->u.name) {
|
||||
if (item->u.ns) xmpp_free(conn->ctx, item->u.ns);
|
||||
xmpp_free(conn->ctx, item);
|
||||
return;
|
||||
}
|
||||
} else
|
||||
item->name = NULL;
|
||||
item->u.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);
|
||||
item->u.type = xmpp_strdup(conn->ctx, type);
|
||||
if (!item->u.type) {
|
||||
if (item->u.ns) xmpp_free(conn->ctx, item->u.ns);
|
||||
if (item->u.name) xmpp_free(conn->ctx, item->u.name);
|
||||
xmpp_free(conn->ctx, item);
|
||||
}
|
||||
} else
|
||||
item->type = NULL;
|
||||
item->u.type = NULL;
|
||||
|
||||
/* append to list */
|
||||
if (!conn->handlers)
|
||||
@@ -470,9 +470,9 @@ void xmpp_handler_delete(xmpp_conn_t * const conn,
|
||||
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);
|
||||
if (item->u.ns) xmpp_free(conn->ctx, item->u.ns);
|
||||
if (item->u.name) xmpp_free(conn->ctx, item->u.name);
|
||||
if (item->u.type) xmpp_free(conn->ctx, item->u.type);
|
||||
xmpp_free(conn->ctx, item);
|
||||
item = prev ? prev->next : conn->handlers;
|
||||
} else {
|
||||
@@ -636,9 +636,9 @@ void handler_system_delete_all(xmpp_conn_t *conn)
|
||||
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);
|
||||
if (item->u.ns) xmpp_free(conn->ctx, item->u.ns);
|
||||
if (item->u.name) xmpp_free(conn->ctx, item->u.name);
|
||||
if (item->u.type) xmpp_free(conn->ctx, item->u.type);
|
||||
xmpp_free(conn->ctx, item);
|
||||
item = next;
|
||||
} else
|
||||
@@ -665,7 +665,7 @@ void handler_system_delete_all(xmpp_conn_t *conn)
|
||||
if (!item->user_handler) {
|
||||
next = item->next;
|
||||
_handler_item_remove(&head, item);
|
||||
xmpp_free(conn->ctx, item->id);
|
||||
xmpp_free(conn->ctx, item->u.id);
|
||||
xmpp_free(conn->ctx, item);
|
||||
item = next;
|
||||
} else
|
||||
|
||||
14
src/md5.c
14
src/md5.c
@@ -43,8 +43,7 @@
|
||||
(cp)[3] = ((value) >> 24) & 0xFF; \
|
||||
} while(0)
|
||||
|
||||
static void MD5Transform(uint32_t buf[4], const unsigned char inext[64],
|
||||
struct MD5Context *ctx);
|
||||
static void MD5Transform(uint32_t buf[4], const unsigned char inext[64]);
|
||||
|
||||
/*
|
||||
* Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
|
||||
@@ -91,7 +90,7 @@ void MD5Update(struct MD5Context *ctx, unsigned char const *buf, uint32_t len)
|
||||
return;
|
||||
}
|
||||
memcpy(p, buf, t);
|
||||
MD5Transform(ctx->buf, ctx->in, ctx);
|
||||
MD5Transform(ctx->buf, ctx->in);
|
||||
buf += t;
|
||||
len -= t;
|
||||
}
|
||||
@@ -99,7 +98,7 @@ void MD5Update(struct MD5Context *ctx, unsigned char const *buf, uint32_t len)
|
||||
|
||||
while (len >= 64) {
|
||||
memcpy(ctx->in, buf, 64);
|
||||
MD5Transform(ctx->buf, ctx->in, ctx);
|
||||
MD5Transform(ctx->buf, ctx->in);
|
||||
buf += 64;
|
||||
len -= 64;
|
||||
}
|
||||
@@ -133,7 +132,7 @@ void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
|
||||
if (count < 8) {
|
||||
/* Two lots of padding: Pad the first block to 64 bytes */
|
||||
memset(p, 0, count);
|
||||
MD5Transform(ctx->buf, ctx->in, ctx);
|
||||
MD5Transform(ctx->buf, ctx->in);
|
||||
|
||||
/* Now fill the next block with 56 bytes */
|
||||
memset(ctx->in, 0, 56);
|
||||
@@ -146,7 +145,7 @@ void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
|
||||
PUT_32BIT_LSB_FIRST(ctx->in + 56, ctx->bits[0]);
|
||||
PUT_32BIT_LSB_FIRST(ctx->in + 60, ctx->bits[1]);
|
||||
|
||||
MD5Transform(ctx->buf, ctx->in, ctx);
|
||||
MD5Transform(ctx->buf, ctx->in);
|
||||
PUT_32BIT_LSB_FIRST(digest, ctx->buf[0]);
|
||||
PUT_32BIT_LSB_FIRST(digest + 4, ctx->buf[1]);
|
||||
PUT_32BIT_LSB_FIRST(digest + 8, ctx->buf[2]);
|
||||
@@ -180,8 +179,7 @@ void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
|
||||
* reflect the addition of 16 longwords of new data. MD5Update blocks
|
||||
* the data and converts bytes into longwords for this routine.
|
||||
*/
|
||||
static void MD5Transform(uint32_t buf[4], const unsigned char inext[64],
|
||||
struct MD5Context *ctx)
|
||||
static void MD5Transform(uint32_t buf[4], const unsigned char inext[64])
|
||||
{
|
||||
register uint32_t a, b, c, d, i;
|
||||
uint32_t in[16];
|
||||
|
||||
@@ -19,13 +19,10 @@
|
||||
|
||||
#include <expat.h>
|
||||
|
||||
#include <strophe.h>
|
||||
#include "strophe.h"
|
||||
#include "common.h"
|
||||
#include "parser.h"
|
||||
|
||||
/* 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
|
||||
@@ -48,6 +45,46 @@ struct _parser_t {
|
||||
int inner_text_used;
|
||||
};
|
||||
|
||||
/* Use the Unit Separator to delimit namespace and name in our XML */
|
||||
const XML_Char namespace_sep = '\x1F';
|
||||
|
||||
/*
|
||||
* Cached strophe ctx. It is used for memory suite.
|
||||
* Note, expat doesn't support userdata in memory suite, therefore,
|
||||
* we can support only one strophe context. If user creates more than one
|
||||
* context, this module will fallback to default library allocator for all
|
||||
* contexts other than mem_ctx.
|
||||
*/
|
||||
static xmpp_ctx_t *mem_ctx = NULL;
|
||||
|
||||
static void *parser_mem_malloc(size_t size)
|
||||
{
|
||||
if (mem_ctx != NULL)
|
||||
return xmpp_alloc(mem_ctx, size);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *parser_mem_realloc(void *ptr, size_t size)
|
||||
{
|
||||
if (mem_ctx != NULL)
|
||||
return xmpp_realloc(mem_ctx, ptr, size);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void parser_mem_free(void *ptr)
|
||||
{
|
||||
if (mem_ctx != NULL)
|
||||
xmpp_free(mem_ctx, ptr);
|
||||
}
|
||||
|
||||
static const XML_Memory_Handling_Suite parser_mem_suite = {
|
||||
.malloc_fcn = &parser_mem_malloc,
|
||||
.realloc_fcn = &parser_mem_realloc,
|
||||
.free_fcn = &parser_mem_free,
|
||||
};
|
||||
|
||||
/* return allocated string with the name from a delimited
|
||||
* namespace/name string */
|
||||
static char *_xml_name(xmpp_ctx_t *ctx, const char *nsname)
|
||||
@@ -56,7 +93,7 @@ static char *_xml_name(xmpp_ctx_t *ctx, const char *nsname)
|
||||
const char *c;
|
||||
size_t len;
|
||||
|
||||
c = strchr(nsname, NAMESPACE_SEP);
|
||||
c = strchr(nsname, namespace_sep);
|
||||
if (c == NULL) return xmpp_strdup(ctx, nsname);
|
||||
|
||||
c++;
|
||||
@@ -76,7 +113,7 @@ static char *_xml_namespace(xmpp_ctx_t *ctx, const char *nsname)
|
||||
char *result = NULL;
|
||||
const char *c;
|
||||
|
||||
c = strchr(nsname, NAMESPACE_SEP);
|
||||
c = strchr(nsname, namespace_sep);
|
||||
if (c != NULL) {
|
||||
result = xmpp_alloc(ctx, (c-nsname) + 1);
|
||||
if (result != NULL) {
|
||||
@@ -273,23 +310,38 @@ void parser_free(parser_t *parser)
|
||||
/* shuts down and restarts XML parser. true on success */
|
||||
int parser_reset(parser_t *parser)
|
||||
{
|
||||
if (parser->expat)
|
||||
XML_ParserFree(parser->expat);
|
||||
XML_Bool ret;
|
||||
const XML_Memory_Handling_Suite *mem = NULL;
|
||||
|
||||
if (parser->stanza)
|
||||
xmpp_stanza_release(parser->stanza);
|
||||
if (parser->expat) {
|
||||
ret = XML_ParserReset(parser->expat, NULL);
|
||||
if (ret != XML_TRUE) {
|
||||
XML_ParserFree(parser->expat);
|
||||
parser->expat = NULL;
|
||||
}
|
||||
} else {
|
||||
if (mem_ctx == NULL)
|
||||
mem_ctx = parser->ctx;
|
||||
if (parser->ctx == mem_ctx)
|
||||
mem = &parser_mem_suite;
|
||||
parser->expat = XML_ParserCreate_MM(NULL, mem, &namespace_sep);
|
||||
}
|
||||
|
||||
parser->expat = XML_ParserCreateNS(NULL, NAMESPACE_SEP);
|
||||
if (!parser->expat) return 0;
|
||||
|
||||
parser->depth = 0;
|
||||
parser->stanza = NULL;
|
||||
if (parser->stanza) {
|
||||
xmpp_stanza_release(parser->stanza);
|
||||
parser->stanza = NULL;
|
||||
}
|
||||
|
||||
if (parser->inner_text) {
|
||||
xmpp_free (parser->ctx, parser->inner_text);
|
||||
xmpp_free(parser->ctx, parser->inner_text);
|
||||
parser->inner_text = NULL;
|
||||
}
|
||||
|
||||
if (!parser->expat)
|
||||
return 0;
|
||||
|
||||
parser->depth = 0;
|
||||
|
||||
XML_SetUserData(parser->expat, parser);
|
||||
XML_SetElementHandler(parser->expat, _start_element, _end_element);
|
||||
XML_SetCharacterDataHandler(parser->expat, _characters);
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
#include <libxml/parser.h>
|
||||
#include <libxml/tree.h>
|
||||
|
||||
#include <strophe.h>
|
||||
#include "strophe.h"
|
||||
#include "common.h"
|
||||
#include "parser.h"
|
||||
|
||||
|
||||
35
src/rand.c
35
src/rand.c
@@ -289,25 +289,32 @@ int xmpp_rand(xmpp_rand_t *rand)
|
||||
return result;
|
||||
}
|
||||
|
||||
static void rand_byte2hex(unsigned char byte, char *hex)
|
||||
{
|
||||
static const char hex_tbl[16] = { '0', '1', '2', '3', '4', '5', '6', '7',
|
||||
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
|
||||
|
||||
hex[0] = hex_tbl[(byte >> 4) & 0x0f];
|
||||
hex[1] = hex_tbl[byte & 0x0f];
|
||||
}
|
||||
|
||||
void xmpp_rand_nonce(xmpp_rand_t *rand, char *output, size_t len)
|
||||
{
|
||||
size_t i;
|
||||
size_t rand_len = len / 2;
|
||||
#ifndef _MSC_VER
|
||||
unsigned char rand_buf[rand_len];
|
||||
#else
|
||||
unsigned char *rand_buf = (unsigned char *)_alloca(rand_len);
|
||||
#endif
|
||||
const size_t rand_len = len / 2;
|
||||
|
||||
/* current implementation returns printable HEX representation of
|
||||
* a random buffer, however base64 encoding can be used instead;
|
||||
* the only problem is that base64_encode() allocates memory and
|
||||
* as result can fail.
|
||||
/*
|
||||
* We don't want to use any allocation here, because this function
|
||||
* can't fail. Also we want to avoid VLA.
|
||||
* Current implementation uses half of the output buffer for random buffer
|
||||
* generation and then converts it to HEX representation.
|
||||
*/
|
||||
|
||||
xmpp_rand_bytes(rand, rand_buf, rand_len);
|
||||
for (i = 0; i < rand_len; ++i) {
|
||||
xmpp_snprintf(output + i * 2, len, "%02x", rand_buf[i]);
|
||||
len -= 2;
|
||||
if (rand_len > 0) {
|
||||
xmpp_rand_bytes(rand, (unsigned char *)output, rand_len);
|
||||
for (i = rand_len; i > 0; --i)
|
||||
rand_byte2hex(output[i - 1], &output[(i - 1) * 2]);
|
||||
}
|
||||
if (len > 0)
|
||||
output[len - 1] = '\0';
|
||||
}
|
||||
|
||||
@@ -21,6 +21,14 @@
|
||||
|
||||
#ifdef HAVE_CARES
|
||||
#include <ares.h>
|
||||
/* for select(2) */
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#else /* _WIN32 */
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#endif /* !_WIN32 */
|
||||
#endif /* HAVE_CARES */
|
||||
|
||||
#include <string.h> /* strncpy */
|
||||
|
||||
@@ -234,7 +234,6 @@ void crypto_SHA1_Final(SHA1_CTX* context, uint8_t* digest)
|
||||
}
|
||||
|
||||
/* Wipe variables */
|
||||
i = 0;
|
||||
memset(context->buffer, 0, 64);
|
||||
memset(context->state, 0, 20);
|
||||
memset(context->count, 0, 8);
|
||||
|
||||
79
src/stanza.c
79
src/stanza.c
@@ -188,6 +188,19 @@ int xmpp_stanza_release(xmpp_stanza_t * const stanza)
|
||||
return released;
|
||||
}
|
||||
|
||||
/** Get the strophe context that the stanza is associated with.
|
||||
*
|
||||
* @param stanza a Strophe stanza object
|
||||
*
|
||||
* @return a Strophe context
|
||||
*
|
||||
* @ingroup Stanza
|
||||
*/
|
||||
xmpp_ctx_t *xmpp_stanza_get_context(const xmpp_stanza_t * const stanza)
|
||||
{
|
||||
return stanza->ctx;
|
||||
}
|
||||
|
||||
/** Determine if a stanza is a text node.
|
||||
*
|
||||
* @param stanza a Strophe stanza object
|
||||
@@ -619,22 +632,29 @@ int xmpp_stanza_set_ns(xmpp_stanza_t * const stanza,
|
||||
}
|
||||
|
||||
/** Add a child stanza to a stanza object.
|
||||
* This function clones the child and appends it to the stanza object's
|
||||
* children.
|
||||
* If do_clone is TRUE, user keeps reference to the child stanza and must call
|
||||
* xmpp_stanza_release() to release the reference. If do_clone is FALSE, user
|
||||
* transfers ownership and must not neither call xmpp_stanza_release() for
|
||||
* the child stanza nor use it.
|
||||
*
|
||||
* @param stanza a Strophe stanza object
|
||||
* @param child the child stanza object
|
||||
* @param do_clone TRUE to increase ref count of child (default for
|
||||
* xmpp_stanza_add_child())
|
||||
*
|
||||
* @return XMPP_EOK (0) on success or a number less than 0 on failure
|
||||
*
|
||||
* @ingroup Stanza
|
||||
*/
|
||||
int xmpp_stanza_add_child(xmpp_stanza_t *stanza, xmpp_stanza_t *child)
|
||||
int xmpp_stanza_add_child_ex(xmpp_stanza_t *stanza, xmpp_stanza_t *child,
|
||||
int do_clone)
|
||||
{
|
||||
xmpp_stanza_t *s;
|
||||
|
||||
/* get a reference to the child */
|
||||
xmpp_stanza_clone(child);
|
||||
if (do_clone) {
|
||||
/* get a reference to the child */
|
||||
xmpp_stanza_clone(child);
|
||||
}
|
||||
|
||||
child->parent = stanza;
|
||||
|
||||
@@ -650,6 +670,22 @@ int xmpp_stanza_add_child(xmpp_stanza_t *stanza, xmpp_stanza_t *child)
|
||||
return XMPP_EOK;
|
||||
}
|
||||
|
||||
/** Add a child stanza to a stanza object.
|
||||
* This function clones the child and appends it to the stanza object's
|
||||
* children.
|
||||
*
|
||||
* @param stanza a Strophe stanza object
|
||||
* @param child the child stanza object
|
||||
*
|
||||
* @return XMPP_EOK (0) on success or a number less than 0 on failure
|
||||
*
|
||||
* @ingroup Stanza
|
||||
*/
|
||||
int xmpp_stanza_add_child(xmpp_stanza_t *stanza, xmpp_stanza_t *child)
|
||||
{
|
||||
return xmpp_stanza_add_child_ex(stanza, child, 1);
|
||||
}
|
||||
|
||||
/** Set the text data for a text stanza.
|
||||
* This function copies the text given and sets the stanza object's text to
|
||||
* it. Attempting to use this function on a stanza that has a name will
|
||||
@@ -835,6 +871,39 @@ xmpp_stanza_t *xmpp_stanza_get_child_by_ns(xmpp_stanza_t * const stanza,
|
||||
return child;
|
||||
}
|
||||
|
||||
/** Get the first child of stanza with name and a given namespace.
|
||||
* This function searches all the immediate children of stanza for a child
|
||||
* stanza that matches the name and namespace provided.
|
||||
* The first matching child is returned.
|
||||
*
|
||||
* @param stanza a Strophe stanza object
|
||||
* @param name a string with the name to match
|
||||
* @param ns a string with the namespace to match
|
||||
*
|
||||
* @return the matching child stanza object or NULL if no match was found
|
||||
*
|
||||
* @ingroup Stanza
|
||||
*/
|
||||
xmpp_stanza_t *xmpp_stanza_get_child_by_name_and_ns(xmpp_stanza_t * const stanza,
|
||||
const char * const name,
|
||||
const char * const ns)
|
||||
{
|
||||
xmpp_stanza_t *child;
|
||||
const char *child_ns;
|
||||
|
||||
for (child = stanza->children; child; child = child->next) {
|
||||
if (child->type == XMPP_STANZA_TAG &&
|
||||
(strcmp(name, xmpp_stanza_get_name(child)) == 0)) {
|
||||
child_ns = xmpp_stanza_get_ns(child);
|
||||
if (child_ns && strcmp(ns, child_ns) == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return child;
|
||||
}
|
||||
|
||||
/** Get the list of children.
|
||||
* This function returns the first child of the stanza object. The rest
|
||||
* of the children can be obtained by calling xmpp_stanza_get_next() to
|
||||
|
||||
@@ -110,11 +110,19 @@ tls_t *tls_new(xmpp_conn_t *conn)
|
||||
|
||||
if (tls) {
|
||||
int ret;
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
|
||||
/* Hostname verification is supported in OpenSSL 1.0.2 and newer. */
|
||||
X509_VERIFY_PARAM *param;
|
||||
#endif
|
||||
memset(tls, 0, sizeof(*tls));
|
||||
|
||||
tls->ctx = conn->ctx;
|
||||
tls->sock = conn->sock;
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||
tls->ssl_ctx = SSL_CTX_new(SSLv23_client_method());
|
||||
#else
|
||||
tls->ssl_ctx = SSL_CTX_new(TLS_client_method());
|
||||
#endif
|
||||
if (tls->ssl_ctx == NULL)
|
||||
goto err;
|
||||
|
||||
@@ -128,18 +136,34 @@ tls_t *tls_new(xmpp_conn_t *conn)
|
||||
|
||||
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_default_verify_paths(tls->ssl_ctx);
|
||||
|
||||
ret = SSL_CTX_set_default_verify_paths(tls->ssl_ctx);
|
||||
if (ret == 0 && !conn->tls_trust) {
|
||||
/*
|
||||
* Returns 1 on success and 0 on failure. A missing default
|
||||
* location is still treated as a success.
|
||||
* Ignore errors when XMPP_CONN_FLAG_TRUST_TLS is set.
|
||||
*/
|
||||
xmpp_error(tls->ctx, "tls",
|
||||
"SSL_CTX_set_default_verify_paths() failed");
|
||||
goto err_free_ctx;
|
||||
}
|
||||
|
||||
tls->ssl = SSL_new(tls->ssl_ctx);
|
||||
if (tls->ssl == NULL)
|
||||
goto err_free_ctx;
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x0908060L && !defined(OPENSSL_NO_TLSEXT)
|
||||
/* Enable SNI. */
|
||||
SSL_set_tlsext_host_name(tls->ssl, conn->domain);
|
||||
#endif
|
||||
|
||||
/* 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);
|
||||
param = SSL_get0_param(tls->ssl);
|
||||
|
||||
/*
|
||||
* Allow only complete wildcards. RFC 6125 discourages wildcard usage
|
||||
|
||||
@@ -86,7 +86,12 @@ char *xmpp_strtok_r(char *s, const char *delim, char **saveptr)
|
||||
*/
|
||||
uint64_t time_stamp(void)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
#if defined(_XBOX_ONE)
|
||||
uint64_t SystemTime;
|
||||
GetSystemTimeAsFileTime((FILETIME*)&SystemTime);
|
||||
/* Convert 100 nanosec ticks to milliseconds */
|
||||
return (SystemTime / 10000);
|
||||
#elif defined(_WIN32)
|
||||
return timeGetTime();
|
||||
#else
|
||||
struct timeval tv;
|
||||
|
||||
18
strophe.h
18
strophe.h
@@ -71,6 +71,14 @@ extern "C" {
|
||||
* Namespace definition for 'jabber:iq:roster'.
|
||||
*/
|
||||
#define XMPP_NS_ROSTER "jabber:iq:roster"
|
||||
/** @def XMPP_NS_REGISTER
|
||||
* Namespace definition for 'jabber:iq:register'.
|
||||
*/
|
||||
#define XMPP_NS_REGISTER "jabber:iq:register"
|
||||
/** @def XMPP_NS_SM
|
||||
* Namespace definition for Stream Management.
|
||||
*/
|
||||
#define XMPP_NS_SM "urn:xmpp:sm:3"
|
||||
|
||||
/* error defines */
|
||||
/** @def XMPP_EOK
|
||||
@@ -237,6 +245,9 @@ xmpp_ctx_t *xmpp_conn_get_context(xmpp_conn_t * const conn);
|
||||
void xmpp_conn_disable_tls(xmpp_conn_t * const conn);
|
||||
int xmpp_conn_is_secured(xmpp_conn_t * const conn);
|
||||
void xmpp_conn_set_keepalive(xmpp_conn_t * const conn, int timeout, int interval);
|
||||
int xmpp_conn_is_connecting(xmpp_conn_t * const conn);
|
||||
int xmpp_conn_is_connected(xmpp_conn_t * const conn);
|
||||
int xmpp_conn_is_disconnected(xmpp_conn_t * const conn);
|
||||
|
||||
int xmpp_connect_client(xmpp_conn_t * const conn,
|
||||
const char * const altdomain,
|
||||
@@ -323,6 +334,8 @@ xmpp_stanza_t *xmpp_stanza_copy(const xmpp_stanza_t * const stanza);
|
||||
/* free a stanza object and it's contents */
|
||||
int xmpp_stanza_release(xmpp_stanza_t * const stanza);
|
||||
|
||||
xmpp_ctx_t *xmpp_stanza_get_context(const xmpp_stanza_t * const stanza);
|
||||
|
||||
int xmpp_stanza_is_text(xmpp_stanza_t * const stanza);
|
||||
int xmpp_stanza_is_tag(xmpp_stanza_t * const stanza);
|
||||
|
||||
@@ -335,8 +348,13 @@ xmpp_stanza_t *xmpp_stanza_get_child_by_name(xmpp_stanza_t * const stanza,
|
||||
const char * const name);
|
||||
xmpp_stanza_t *xmpp_stanza_get_child_by_ns(xmpp_stanza_t * const stanza,
|
||||
const char * const ns);
|
||||
xmpp_stanza_t *xmpp_stanza_get_child_by_name_and_ns(xmpp_stanza_t * const stanza,
|
||||
const char * const name,
|
||||
const char * const ns);
|
||||
xmpp_stanza_t *xmpp_stanza_get_next(xmpp_stanza_t * const stanza);
|
||||
int xmpp_stanza_add_child(xmpp_stanza_t *stanza, xmpp_stanza_t *child);
|
||||
int xmpp_stanza_add_child_ex(xmpp_stanza_t *stanza, xmpp_stanza_t *child,
|
||||
int do_clone);
|
||||
|
||||
const char *xmpp_stanza_get_attribute(xmpp_stanza_t * const stanza,
|
||||
const char * const name);
|
||||
|
||||
@@ -41,7 +41,7 @@ static void digest_to_hex(const uint8_t *digest, char *output)
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
int k;
|
||||
size_t k;
|
||||
SHA1_CTX context;
|
||||
uint8_t digest[20];
|
||||
char output[80];
|
||||
|
||||
96
tests/test_stanza.c
Normal file
96
tests/test_stanza.c
Normal file
@@ -0,0 +1,96 @@
|
||||
/* test_stanza.c
|
||||
* libstrophe XMPP client library -- test routines for stanza functions
|
||||
*
|
||||
* Copyright (C) 2020 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.
|
||||
*/
|
||||
|
||||
/* gcc -o test_stanza -I./src tests/test_stanza.c -lstrophe */
|
||||
|
||||
#include <strophe.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define MAGICPTR ((void *)0xfeedbeef)
|
||||
static unsigned long used_blocks = 0;
|
||||
|
||||
static void *stanza_alloc(size_t size, void *userdata)
|
||||
{
|
||||
assert(userdata == MAGICPTR);
|
||||
|
||||
++used_blocks;
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
static void stanza_free(void *ptr, void *userdata)
|
||||
{
|
||||
assert(userdata == MAGICPTR);
|
||||
|
||||
--used_blocks;
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
static void *stanza_realloc(void *ptr, size_t size, void *userdata)
|
||||
{
|
||||
assert(userdata == MAGICPTR);
|
||||
|
||||
return realloc(ptr, size);
|
||||
}
|
||||
|
||||
static const xmpp_mem_t stanza_mem = {
|
||||
.alloc = &stanza_alloc,
|
||||
.free = &stanza_free,
|
||||
.realloc = &stanza_realloc,
|
||||
.userdata = MAGICPTR,
|
||||
};
|
||||
|
||||
static void test_stanza_add_child(xmpp_ctx_t *ctx)
|
||||
{
|
||||
xmpp_stanza_t *stanza;
|
||||
xmpp_stanza_t *child;
|
||||
unsigned long baseline = used_blocks;
|
||||
|
||||
/* xmpp_stanza_add_child */
|
||||
|
||||
stanza = xmpp_stanza_new(ctx);
|
||||
child = xmpp_stanza_new(ctx);
|
||||
assert(stanza != NULL);
|
||||
assert(child != NULL);
|
||||
xmpp_stanza_add_child(stanza, child);
|
||||
xmpp_stanza_release(stanza);
|
||||
assert(used_blocks > baseline);
|
||||
xmpp_stanza_release(child);
|
||||
assert(used_blocks == baseline);
|
||||
|
||||
/* xmpp_stanza_add_child_ex */
|
||||
|
||||
stanza = xmpp_stanza_new(ctx);
|
||||
child = xmpp_stanza_new(ctx);
|
||||
assert(stanza != NULL);
|
||||
assert(child != NULL);
|
||||
xmpp_stanza_add_child_ex(stanza, child, 0);
|
||||
xmpp_stanza_release(stanza);
|
||||
assert(used_blocks == baseline);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
xmpp_ctx_t *ctx;
|
||||
|
||||
xmpp_initialize();
|
||||
ctx = xmpp_ctx_new(&stanza_mem, NULL);
|
||||
assert(ctx != NULL);
|
||||
|
||||
test_stanza_add_child(ctx);
|
||||
|
||||
xmpp_ctx_free(ctx);
|
||||
xmpp_shutdown();
|
||||
|
||||
/* All allocated blocks must be freed. */
|
||||
assert(used_blocks == 0);
|
||||
}
|
||||
Reference in New Issue
Block a user