2 Commits

Author SHA1 Message Date
Steffen Jaeckel
541c22cb13 Allow configuring compression level
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2024-11-18 10:13:43 +01:00
Steffen Jaeckel
06f2ba19b4 Introduce generic xmpp_conn_set_*() API
Instead of having a multitude of setter API functions for configuration
options, provide generic ones for the different types we have.

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2024-11-18 10:13:43 +01:00
34 changed files with 576 additions and 887 deletions

View File

@@ -10,12 +10,12 @@ on:
jobs: jobs:
linux-tests: linux-tests:
runs-on: ubuntu-24.04 runs-on: ubuntu-20.04
strategy: strategy:
matrix: matrix:
valgrind: valgrind:
- { configure: '' , cflags: '', make: 'check' } - { configure: '' , make: 'check' }
- { configure: '--enable-valgrind' , cflags: '-O2', make: 'check-valgrind' } - { configure: '--enable-valgrind' , make: 'check-valgrind' }
options: options:
- { configure: '' } - { configure: '' }
- { configure: '--without-libxml2' } - { configure: '--without-libxml2' }
@@ -35,7 +35,7 @@ jobs:
- name: Build the library - name: Build the library
run: | run: |
./bootstrap.sh ./bootstrap.sh
./configure ${{ matrix.options.configure }} ${{ matrix.valgrind.configure }} CFLAGS="-Werror -g3 ${{ matrix.valgrind.cflags }}" ./configure ${{ matrix.options.configure }} ${{ matrix.valgrind.configure }} CFLAGS="-Werror -g3"
make -j$(nproc) make -j$(nproc)
- name: Run tests - name: Run tests
run: | run: |
@@ -46,7 +46,7 @@ jobs:
cat test-suite*.log || true cat test-suite*.log || true
xssl-tests: xssl-tests:
runs-on: ubuntu-24.04 runs-on: ubuntu-22.04
strategy: strategy:
matrix: matrix:
xssl_versions: xssl_versions:
@@ -111,7 +111,7 @@ jobs:
cat test-suite*.log || true cat test-suite*.log || true
release-test: release-test:
runs-on: ubuntu-22.04 runs-on: ubuntu-20.04
name: Check if release would work name: Check if release would work
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
@@ -135,14 +135,9 @@ jobs:
if: ${{ !failure() }} if: ${{ !failure() }}
run: | run: |
cat testbuild.log cat testbuild.log
- name: Error logs
if: ${{ failure() }}
run: |
cat testbuild.log || true
cat testerr.log || true
code-style: code-style:
runs-on: ubuntu-24.04 runs-on: ubuntu-20.04
name: Check coding style name: Check coding style
continue-on-error: true continue-on-error: true
steps: steps:

2
.gitignore vendored
View File

@@ -46,7 +46,6 @@ examples/roster
examples/uuid examples/uuid
examples/vcard examples/vcard
testbuild*.log testbuild*.log
testerr*.log
test-release/ test-release/
test_stamp test_stamp
test-suite*.log test-suite*.log
@@ -66,7 +65,6 @@ tests/test_resolver
tests/test_sasl tests/test_sasl
tests/test_scram tests/test_scram
tests/test_send_queue tests/test_send_queue
tests/test_serialize_sm
tests/test_sha1 tests/test_sha1
tests/test_sha256 tests/test_sha256
tests/test_sha512 tests/test_sha512

View File

@@ -1,13 +1,3 @@
0.14.0
- Add SM-state serialization mechanism (#239)
- Add support for `SCRAM-SHA-512-PLUS` (da122981)
- Add support for `SSLKEYLOGFILE` with OpenSSL (d82df127)
- Fix some issues related to Stream Management (03d43132, 4359536a)
- Fix a potential segfault (9fef4b7d)
- New API:
- xmpp_conn_set_sm_callback()
- xmpp_conn_restore_sm_state()
0.13.1 0.13.1
- Fix SCRAM-*-PLUS SASL mechanisms with OpenSSL and TLS < v1.3 (40f2452) - Fix SCRAM-*-PLUS SASL mechanisms with OpenSSL and TLS < v1.3 (40f2452)
- Only signal "stream negotiation success" once (1cf09b1) - Only signal "stream negotiation success" once (1cf09b1)

View File

@@ -38,7 +38,7 @@ PROJECT_NAME = Strophe
# could be handy for archiving the generated documentation or if some version # could be handy for archiving the generated documentation or if some version
# control system is used. # control system is used.
PROJECT_NUMBER = 0.14 PROJECT_NUMBER = 0.13
# Using the PROJECT_BRIEF tag one can provide an optional one line description # Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a # for a project that appears at the top of each page and should give viewer a

View File

@@ -190,7 +190,6 @@ STATIC_TESTS = \
tests/test_jid \ tests/test_jid \
tests/test_ctx \ tests/test_ctx \
tests/test_send_queue \ tests/test_send_queue \
tests/test_serialize_sm \
tests/test_string \ tests/test_string \
tests/test_resolver tests/test_resolver
@@ -286,11 +285,6 @@ tests_test_send_queue_CFLAGS = -I$(top_srcdir)/src
tests_test_send_queue_LDADD = $(STROPHE_LIBS) tests_test_send_queue_LDADD = $(STROPHE_LIBS)
tests_test_send_queue_LDFLAGS = -static tests_test_send_queue_LDFLAGS = -static
tests_test_serialize_sm_SOURCES = tests/test_serialize_sm.c tests/test.c tests/test.h
tests_test_serialize_sm_CFLAGS = -I$(top_srcdir)/src
tests_test_serialize_sm_LDADD = $(STROPHE_LIBS)
tests_test_serialize_sm_LDFLAGS = -static
tests_test_snprintf_SOURCES = tests/test_snprintf.c tests_test_snprintf_SOURCES = tests/test_snprintf.c
tests_test_snprintf_CFLAGS = -I$(top_srcdir)/src tests_test_snprintf_CFLAGS = -I$(top_srcdir)/src
@@ -333,7 +327,6 @@ dist-archives:
test-release: dist test-release: dist
@touch testbuild-$(PACKAGE_VERSION).log && ln -sf testbuild-$(PACKAGE_VERSION).log testbuild.log @touch testbuild-$(PACKAGE_VERSION).log && ln -sf testbuild-$(PACKAGE_VERSION).log testbuild.log
@touch testerr-$(PACKAGE_VERSION).log && ln -sf testerr-$(PACKAGE_VERSION).log testerr.log
@mkdir -p test-release && cp $(PACKAGE_TARNAME)-$(PACKAGE_VERSION).tar.* test-release && pushd test-release && \ @mkdir -p test-release && cp $(PACKAGE_TARNAME)-$(PACKAGE_VERSION).tar.* test-release && pushd test-release && \
tar xzf $(PACKAGE_TARNAME)-$(PACKAGE_VERSION).tar.gz && pushd $(PACKAGE_TARNAME)-$(PACKAGE_VERSION) && ./testbuild.sh && popd && rm -rf $(PACKAGE_TARNAME)-$(PACKAGE_VERSION) && \ tar xzf $(PACKAGE_TARNAME)-$(PACKAGE_VERSION).tar.gz && pushd $(PACKAGE_TARNAME)-$(PACKAGE_VERSION) && ./testbuild.sh && popd && rm -rf $(PACKAGE_TARNAME)-$(PACKAGE_VERSION) && \
echo "Success" && popd echo "Success" && popd

View File

@@ -1,6 +1,6 @@
m4_define([v_maj], [0]) m4_define([v_maj], [0])
m4_define([v_min], [14]) m4_define([v_min], [13])
m4_define([v_patch], [0]) m4_define([v_patch], [1])
m4_define([project_version], [v_maj.v_min.v_patch]) m4_define([project_version], [v_maj.v_min.v_patch])
m4_define([lt_cur], m4_eval(v_maj + v_min)) m4_define([lt_cur], m4_eval(v_maj + v_min))
@@ -18,10 +18,9 @@ PKG_PROG_PKG_CONFIG
AC_CANONICAL_HOST AC_CANONICAL_HOST
AS_CASE([$host_os], AS_CASE([$host_os],
[dragonfly*], [PLATFORM="bsd"],
[freebsd*], [PLATFORM="bsd"], [freebsd*], [PLATFORM="bsd"],
[netbsd*], [PLATFORM="bsd"],
[openbsd*], [PLATFORM="bsd"], [openbsd*], [PLATFORM="bsd"],
[netbsd*], [PLATFORM="bsd"],
[*nto*|*qnx*], [PLATFORM="qnx"], [*nto*|*qnx*], [PLATFORM="qnx"],
[*solaris*], [PLATFORM="solaris"], [*solaris*], [PLATFORM="solaris"],
[*android*], [PLATFORM="android"], [*android*], [PLATFORM="android"],

View File

@@ -115,8 +115,8 @@ int main(int argc, char **argv)
*/ */
/* setup authentication information */ /* setup authentication information */
xmpp_conn_set_jid(conn, argv[1]); xmpp_conn_set_string(conn, XMPP_SETTING_JID, argv[1]);
xmpp_conn_set_pass(conn, argv[2]); xmpp_conn_set_string(conn, XMPP_SETTING_PASS, argv[2]);
/* initiate connection */ /* initiate connection */
xmpp_connect_client(conn, NULL, 0, conn_handler, ctx); xmpp_connect_client(conn, NULL, 0, conn_handler, ctx);

View File

@@ -116,9 +116,9 @@ int main(int argc, char **argv)
/* setup authentication information */ /* setup authentication information */
if (jid) if (jid)
xmpp_conn_set_jid(conn, jid); xmpp_conn_set_string(conn, XMPP_SETTING_JID, jid);
if (password) if (password)
xmpp_conn_set_pass(conn, password); xmpp_conn_set_string(conn, XMPP_SETTING_PASS, password);
/* initiate connection */ /* initiate connection */
if (xmpp_connect_client(conn, host, port, conn_handler, ctx) == XMPP_EOK) { if (xmpp_connect_client(conn, host, port, conn_handler, ctx) == XMPP_EOK) {

View File

@@ -293,20 +293,24 @@ create_connection:
xmpp_conn_set_flags(conn, flags); xmpp_conn_set_flags(conn, flags);
/* ask for a password if key is protected */ /* ask for a password if key is protected */
xmpp_conn_set_password_callback(conn, password_callback, NULL); xmpp_conn_set_functionpointer(conn, XMPP_SETTING_PASSWORD_CALLBACK,
password_callback);
/* try at max 3 times in case the user enters the password wrong */ /* try at max 3 times in case the user enters the password wrong */
xmpp_conn_set_password_retries(conn, 3); xmpp_conn_set_int(conn, XMPP_SETTING_PASSWORD_RETRIES, 3);
/* setup authentication information */ /* setup authentication information */
if (key) if (key) {
xmpp_conn_set_client_cert(conn, cert, key); xmpp_conn_set_string(conn, XMPP_SETTING_CLIENT_CERT, cert);
xmpp_conn_set_string(conn, XMPP_SETTING_CLIENT_KEY, key);
}
if (jid) if (jid)
xmpp_conn_set_jid(conn, jid); xmpp_conn_set_string(conn, XMPP_SETTING_JID, jid);
if (password) if (password)
xmpp_conn_set_pass(conn, password); xmpp_conn_set_string(conn, XMPP_SETTING_PASS, password);
/* enable TCP keepalive, using canned callback function */ /* enable TCP keepalive, using canned callback function */
if (tcp_keepalive) if (tcp_keepalive)
xmpp_conn_set_sockopt_callback(conn, xmpp_sockopt_cb_keepalive); xmpp_conn_set_functionpointer(conn, XMPP_SETTING_SOCKOPT_CALLBACK,
xmpp_sockopt_cb_keepalive);
/* set Stream-Mangement state if available */ /* set Stream-Mangement state if available */
if (sm_state) { if (sm_state) {

View File

@@ -331,27 +331,31 @@ int main(int argc, char **argv)
xmpp_conn_set_flags(conn, flags); xmpp_conn_set_flags(conn, flags);
/* configure TCP keepalive (optional) */ /* configure TCP keepalive (optional) */
if (tcp_keepalive) if (tcp_keepalive)
xmpp_conn_set_sockopt_callback(conn, sockopt_cb); xmpp_conn_set_functionpointer(conn, XMPP_SETTING_SOCKOPT_CALLBACK,
sockopt_cb);
/* ask for a password if key is protected */ /* ask for a password if key is protected */
xmpp_conn_set_password_callback(conn, password_callback, NULL); xmpp_conn_set_functionpointer(conn, XMPP_SETTING_PASSWORD_CALLBACK,
password_callback);
/* try at max 3 times in case the user enters the password wrong */ /* try at max 3 times in case the user enters the password wrong */
xmpp_conn_set_password_retries(conn, 3); xmpp_conn_set_int(conn, XMPP_SETTING_PASSWORD_RETRIES, 3);
/* setup authentication information */ /* setup authentication information */
if (key) { if (key) {
xmpp_conn_set_client_cert(conn, cert, key); xmpp_conn_set_string(conn, XMPP_SETTING_CLIENT_CERT, cert);
xmpp_conn_set_string(conn, XMPP_SETTING_CLIENT_KEY, key);
} }
if (jid) if (jid)
xmpp_conn_set_jid(conn, jid); xmpp_conn_set_string(conn, XMPP_SETTING_JID, jid);
if (password) if (password)
xmpp_conn_set_pass(conn, password); xmpp_conn_set_string(conn, XMPP_SETTING_PASS, password);
if (certfail) if (certfail)
xmpp_conn_set_certfail_handler(conn, certfail_handler); xmpp_conn_set_functionpointer(conn, XMPP_SETTING_CERTFAIL_HANDLER,
certfail_handler);
if (capath) if (capath)
xmpp_conn_set_capath(conn, capath); xmpp_conn_set_string(conn, XMPP_SETTING_CAPATH, capath);
if (cafile) if (cafile)
xmpp_conn_set_cafile(conn, cafile); xmpp_conn_set_string(conn, XMPP_SETTING_CAFILE, cafile);
/* initiate connection */ /* initiate connection */
if (xmpp_connect_client(conn, host, port, conn_handler, ctx) == XMPP_EOK) { if (xmpp_connect_client(conn, host, port, conn_handler, ctx) == XMPP_EOK) {

View File

@@ -80,8 +80,8 @@ int main(int argc, char **argv)
conn = xmpp_conn_new(ctx); conn = xmpp_conn_new(ctx);
/* setup authentication information */ /* setup authentication information */
xmpp_conn_set_jid(conn, jid); xmpp_conn_set_string(conn, XMPP_SETTING_JID, jid);
xmpp_conn_set_pass(conn, pass); xmpp_conn_set_string(conn, XMPP_SETTING_PASS, pass);
/* initiate connection */ /* initiate connection */
xmpp_connect_component(conn, host, port, conn_handler, ctx); xmpp_connect_component(conn, host, port, conn_handler, ctx);

View File

@@ -342,7 +342,7 @@ int main(int argc, char **argv)
/* jid can be a jid or domain for "raw" connection */ /* jid can be a jid or domain for "raw" connection */
domain = xmpp_jid_domain(ctx, jid); domain = xmpp_jid_domain(ctx, jid);
xmpp_conn_set_jid(conn, domain); xmpp_conn_set_string(conn, XMPP_SETTING_JID, domain);
xmpp_free(ctx, domain); xmpp_free(ctx, domain);
/* private data */ /* private data */

View File

@@ -118,8 +118,8 @@ int main(int argc, char **argv)
*/ */
/* setup authentication information */ /* setup authentication information */
xmpp_conn_set_jid(conn, argv[1]); xmpp_conn_set_string(conn, XMPP_SETTING_JID, argv[1]);
xmpp_conn_set_pass(conn, argv[2]); xmpp_conn_set_string(conn, XMPP_SETTING_PASS, argv[2]);
/* initiate connection */ /* initiate connection */
xmpp_connect_client(conn, NULL, 0, conn_handler, ctx); xmpp_connect_client(conn, NULL, 0, conn_handler, ctx);

View File

@@ -269,8 +269,8 @@ int main(int argc, char **argv)
log = xmpp_get_default_logger(XMPP_LEVEL_INFO); log = xmpp_get_default_logger(XMPP_LEVEL_INFO);
ctx = xmpp_ctx_new(NULL, log); ctx = xmpp_ctx_new(NULL, log);
conn = xmpp_conn_new(ctx); conn = xmpp_conn_new(ctx);
xmpp_conn_set_jid(conn, jid); xmpp_conn_set_string(conn, XMPP_SETTING_JID, jid);
xmpp_conn_set_pass(conn, pass); xmpp_conn_set_string(conn, XMPP_SETTING_PASS, pass);
vcard.ctx = ctx; vcard.ctx = ctx;
xmpp_connect_client(conn, NULL, 0, conn_handler, &vcard); xmpp_connect_client(conn, NULL, 0, conn_handler, &vcard);
xmpp_run(ctx); xmpp_run(ctx);

View File

@@ -1232,7 +1232,6 @@ static void _sm_enable(xmpp_conn_t *conn)
send_stanza(conn, enable, XMPP_QUEUE_SM_STROPHE); send_stanza(conn, enable, XMPP_QUEUE_SM_STROPHE);
conn->sm_state->sm_sent_nr = 0; conn->sm_state->sm_sent_nr = 0;
conn->sm_state->sm_enabled = 1; conn->sm_state->sm_enabled = 1;
trigger_sm_callback(conn);
} }
static int static int
@@ -1487,8 +1486,6 @@ static int _handle_sm(xmpp_conn_t *const conn,
name = NULL; name = NULL;
} }
trigger_sm_callback(conn);
err_sm: err_sm:
if (!name) { if (!name) {
char *err = "Couldn't convert stanza to text!"; char *err = "Couldn't convert stanza to text!";

View File

@@ -30,17 +30,12 @@
#include "snprintf.h" #include "snprintf.h"
/** handlers **/ /** handlers **/
#if (__STDC_VERSION__ >= 202000L)
typedef void *xmpp_void_handler;
#else
typedef int (*xmpp_void_handler)();
#endif
typedef struct _xmpp_handlist_t xmpp_handlist_t; typedef struct _xmpp_handlist_t xmpp_handlist_t;
struct _xmpp_handlist_t { struct _xmpp_handlist_t {
/* common members */ /* common members */
int user_handler; int user_handler;
xmpp_void_handler handler; int (*handler)();
void *userdata; void *userdata;
int enabled; /* handlers are added disabled and enabled after the int enabled; /* handlers are added disabled and enabled after the
* handler chain is processed to prevent stanzas from * handler chain is processed to prevent stanzas from
@@ -285,7 +280,8 @@ struct _xmpp_conn_t {
struct { struct {
struct xmpp_compression *state; struct xmpp_compression *state;
int allowed, supported, dont_reset; int allowed, dont_reset, level;
int supported;
} compression; } compression;
char *lang; char *lang;
@@ -328,8 +324,6 @@ struct _xmpp_conn_t {
hash_t *id_handlers; hash_t *id_handlers;
xmpp_handlist_t *handlers; xmpp_handlist_t *handlers;
xmpp_sockopt_callback sockopt_cb; xmpp_sockopt_callback sockopt_cb;
xmpp_sm_callback sm_callback;
void *sm_callback_ctx;
}; };
void conn_disconnect(xmpp_conn_t *conn); void conn_disconnect(xmpp_conn_t *conn);
@@ -383,7 +377,6 @@ void handler_add(xmpp_conn_t *conn,
void handler_system_delete_all(xmpp_conn_t *conn); void handler_system_delete_all(xmpp_conn_t *conn);
/* utility functions */ /* utility functions */
void trigger_sm_callback(xmpp_conn_t *conn);
void reset_sm_state(xmpp_sm_state_t *sm_state); void reset_sm_state(xmpp_sm_state_t *sm_state);
void disconnect_mem_error(xmpp_conn_t *conn); void disconnect_mem_error(xmpp_conn_t *conn);

View File

@@ -227,7 +227,7 @@ int compression_init(xmpp_conn_t *conn)
comp->compression.stream.next_out = comp->compression.buffer; comp->compression.stream.next_out = comp->compression.buffer;
comp->compression.stream.avail_out = STROPHE_COMPRESSION_BUFFER_SIZE; comp->compression.stream.avail_out = STROPHE_COMPRESSION_BUFFER_SIZE;
int ret = deflateInit(&comp->compression.stream, Z_DEFAULT_COMPRESSION); int ret = deflateInit(&comp->compression.stream, conn->compression.level);
if (ret != Z_OK) { if (ret != Z_OK) {
strophe_free_and_null(conn->ctx, comp->compression.buffer); strophe_free_and_null(conn->ctx, comp->compression.buffer);
conn->error = ret; conn->error = ret;

View File

@@ -21,7 +21,6 @@
*/ */
#include <errno.h> #include <errno.h>
#include <netinet/in.h>
#include <stdarg.h> #include <stdarg.h>
#include <string.h> #include <string.h>
#include <limits.h> #include <limits.h>
@@ -168,6 +167,8 @@ xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t *ctx)
tls_clear_password_cache(conn); tls_clear_password_cache(conn);
conn->password_retries = 1; conn->password_retries = 1;
conn->compression.level = -1;
conn->parser = conn->parser =
parser_new(conn->ctx, _handle_stream_start, _handle_stream_end, parser_new(conn->ctx, _handle_stream_start, _handle_stream_end,
_handle_stream_stanza, conn); _handle_stream_stanza, conn);
@@ -218,32 +219,6 @@ xmpp_conn_t *xmpp_conn_clone(xmpp_conn_t *conn)
return conn; return conn;
} }
/** Register sockopt callback
* Set function to be called when a new socket is created to allow setting
* socket options before connection is started.
*
* If the connection is already connected, this callback will be called
* immediately.
*
* To set options that can only be applied to disconnected sockets, the
* callback must be registered before connecting.
*
* @param conn The Strophe connection object this callback is being registered
* for
* @param callback a xmpp_sockopt_callback callback function that will receive
* notifications of connection status
*
* @ingroup Connections
*/
void xmpp_conn_set_sockopt_callback(xmpp_conn_t *conn,
xmpp_sockopt_callback callback)
{
conn->sockopt_cb = callback;
if (conn->state != XMPP_STATE_DISCONNECTED)
callback(conn, &conn->sock);
}
/** Release a Strophe connection object. /** Release a Strophe connection object.
* Decrement the reference count by one for a connection, freeing the * Decrement the reference count by one for a connection, freeing the
* connection object if the count reaches 0. * connection object if the count reaches 0.
@@ -367,6 +342,204 @@ int xmpp_conn_release(xmpp_conn_t *conn)
return released; return released;
} }
/** Configure a connection-related int setting
*
* `setting` can be one of:
* - \ref XMPP_SETTING_PASSWORD_RETRIES
* Set the number of retry attempts to decrypt a private key file. \n
* In case the user enters the password manually it can be useful to
* directly retry if the decryption of the key file failed.
*
* - \ref XMPP_SETTING_COMPRESSION_LEVEL
* Set the compression level. \n
* For zlib the valid range is `-1` to `9`.
*
* @param conn a Strophe connection object
* @param setting The setting that shall be configured
* @param value The value, the settings should get
*
* @ingroup Connections
*/
void xmpp_conn_set_int(xmpp_conn_t *conn,
xmpp_conn_setting_t setting,
int value)
{
switch (setting) {
case XMPP_SETTING_PASSWORD_RETRIES:
if (value <= 0)
conn->password_retries = 1;
else
conn->password_retries = value;
break;
case XMPP_SETTING_COMPRESSION_LEVEL:
conn->compression.level = value;
break;
default:
strophe_warn(conn->ctx, "xmpp", "Invalid Int setting %d", setting);
return;
}
}
/** Configure a connection-related string setting
*
* `setting` can be one of:
* - \ref XMPP_SETTING_JID
* Set the JID of the user that will be bound to the connection. \n
* This should not be used after a connection is created. \n
* If the supplied JID is missing the node, SASL ANONYMOUS authentication
* will be used.
*
* - \ref XMPP_SETTING_PASS
* Set the password used to authenticate the connection.
*
* - \ref XMPP_SETTING_CAFILE
* Set CAfile.
*
* - \ref XMPP_SETTING_CAPATH
* Set CApath.
*
* - \ref XMPP_SETTING_CLIENT_CERT
* Set the Client Certificate or PKCS#12 encoded file that will be bound to
* the connection. \n
* This should not be used after a connection is created. \n
* In case the PKCS#12 file is encrypted, a callback must be set via
* \ref xmpp_conn_set_functionpointer with the option
* \ref XMPP_SETTING_PASSWORD_CALLBACK so the TLS stack can retrieve the
* password.
*
* - \ref XMPP_SETTING_CLIENT_KEY
* Set the Private Key that will be bound to the connection. \n
* This should not be used after a connection is created. \n
* In case the Private Key is encrypted, a callback must be set via
* \ref xmpp_conn_set_functionpointer with the option
* \ref XMPP_SETTING_PASSWORD_CALLBACK so the TLS stack can retrieve the
* password.
*
*
*
* If any value was previously set, it will be discarded.
* The function will make a copy of the value given.
*
* @param conn a Strophe connection object
* @param setting The setting that shall be configured
* @param value The value, the settings should get
*
* @ingroup Connections
*/
void xmpp_conn_set_string(xmpp_conn_t *conn,
xmpp_conn_setting_t setting,
const char *value)
{
char **target;
switch (setting) {
case XMPP_SETTING_JID:
target = &conn->jid;
break;
case XMPP_SETTING_PASS:
target = &conn->pass;
break;
case XMPP_SETTING_CAFILE:
target = &conn->tls_cafile;
break;
case XMPP_SETTING_CAPATH:
target = &conn->tls_capath;
break;
case XMPP_SETTING_CLIENT_CERT:
target = &conn->tls_client_cert;
break;
case XMPP_SETTING_CLIENT_KEY:
target = &conn->tls_client_key;
break;
default:
strophe_warn(conn->ctx, "xmpp", "Invalid String setting %d", setting);
return;
}
if (*target)
strophe_free(conn->ctx, *target);
*target = NULL;
if (value) {
*target = strophe_strdup(conn->ctx, value);
}
}
/** Configure a connection-related pointer setting
*
* `setting` can be one of:
* - \ref XMPP_SETTING_PASSWORD_CALLBACK_USERDATA
* Set the userdata pointer that is pass when the password-retrieval
* callback is called. \ref XMPP_SETTING_PASSWORD_CALLBACK
*
* @param conn a Strophe connection object
* @param setting The setting that shall be configured
* @param value The value, the settings should get
*
* @ingroup Connections
*/
void xmpp_conn_set_pointer(xmpp_conn_t *conn,
xmpp_conn_setting_t setting,
void *value)
{
switch (setting) {
case XMPP_SETTING_PASSWORD_CALLBACK_USERDATA:
conn->password_callback_userdata = value;
break;
default:
strophe_warn(conn->ctx, "xmpp", "Invalid Pointer setting %d", setting);
return;
}
}
/** Configure a connection-related functionpointer setting
*
* `setting` can be one of:
* - \ref XMPP_SETTING_PASSWORD_CALLBACK
* Set the Callback function which will be called when the TLS stack can't
* decrypt a password protected key file. The userdata pointer can be set
* via \ref xmpp_conn_set_pointer with the setting
* \ref XMPP_SETTING_PASSWORD_CALLBACK_USERDATA
*
* - \ref XMPP_SETTING_CERTFAIL_HANDLER
* Set the Handler function which will be called when the TLS stack can't
* verify the CA of the server we're trying to connect to.
*
* - \ref XMPP_SETTING_SOCKOPT_CALLBACK
* Set function to be called when a new socket is created to allow setting
* socket options before connection is started. \n
* If the connection is already connected, this callback will be called
* immediately. \n
* To set options that can only be applied to disconnected sockets, the
* callback must be registered before connecting.
*
* @param conn a Strophe connection object
* @param setting The setting that shall be configured
* @param value The value, the settings should get
*
* @ingroup Connections
*/
void xmpp_conn_set_functionpointer_impl(xmpp_conn_t *conn,
xmpp_conn_setting_t setting,
xmpp_conn_pfn_t value)
{
switch (setting) {
case XMPP_SETTING_PASSWORD_CALLBACK:
conn->password_callback = (xmpp_password_callback)value;
break;
case XMPP_SETTING_CERTFAIL_HANDLER:
conn->certfail_handler = (xmpp_certfail_handler)value;
break;
case XMPP_SETTING_SOCKOPT_CALLBACK:
conn->sockopt_cb = (xmpp_sockopt_callback)value;
if (conn->state != XMPP_STATE_DISCONNECTED)
conn->sockopt_cb(conn, &conn->sock);
break;
default:
strophe_warn(conn->ctx, "xmpp", "Invalid Functionpointer setting %d",
setting);
return;
}
}
/** Get the JID which is or will be bound to the connection. /** Get the JID which is or will be bound to the connection.
* *
* @param conn a Strophe connection object * @param conn a Strophe connection object
@@ -398,66 +571,6 @@ const char *xmpp_conn_get_bound_jid(const xmpp_conn_t *conn)
return conn->bound_jid; return conn->bound_jid;
} }
/** Set the JID of the user that will be bound to the connection.
* If any JID was previously set, it will be discarded. This should not be
* be used after a connection is created. The function will make a copy of
* the JID string. If the supplied JID is missing the node, SASL
* ANONYMOUS authentication will be used.
*
* @param conn a Strophe connection object
* @param jid a full or bare JID
*
* @ingroup Connections
*/
void xmpp_conn_set_jid(xmpp_conn_t *conn, const char *jid)
{
if (conn->jid)
strophe_free(conn->ctx, conn->jid);
conn->jid = strophe_strdup(conn->ctx, jid);
}
/** Set the Handler function which will be called when the TLS stack can't
* verify the CA of the server we're trying to connect to.
*
* @param conn a Strophe connection object
* @param hndl certfail Handler function
*
* @ingroup TLS
*/
void xmpp_conn_set_certfail_handler(xmpp_conn_t *const conn,
xmpp_certfail_handler hndl)
{
conn->certfail_handler = hndl;
}
/** Set the CAfile
*
* @param conn a Strophe connection object
* @param path path to a certificate file
*
* @ingroup TLS
*/
void xmpp_conn_set_cafile(xmpp_conn_t *const conn, const char *path)
{
if (conn->tls_cafile)
strophe_free(conn->ctx, conn->tls_cafile);
conn->tls_cafile = strophe_strdup(conn->ctx, path);
}
/** Set the CApath
*
* @param conn a Strophe connection object
* @param path path to a folder containing certificates
*
* @ingroup TLS
*/
void xmpp_conn_set_capath(xmpp_conn_t *const conn, const char *path)
{
if (conn->tls_capath)
strophe_free(conn->ctx, conn->tls_capath);
conn->tls_capath = strophe_strdup(conn->ctx, path);
}
/** Retrieve the peer certificate /** Retrieve the peer certificate
* *
* The returned Certificate object must be free'd by calling * The returned Certificate object must be free'd by calling
@@ -474,41 +587,6 @@ xmpp_tlscert_t *xmpp_conn_get_peer_cert(xmpp_conn_t *const conn)
return tls_peer_cert(conn); return tls_peer_cert(conn);
} }
/** Set the Callback function which will be called when the TLS stack can't
* decrypt a password protected key file.
*
* @param conn a Strophe connection object
* @param cb The callback function that shall be called
* @param userdata An opaque data pointer that will be passed to the callback
*
* @ingroup TLS
*/
void xmpp_conn_set_password_callback(xmpp_conn_t *conn,
xmpp_password_callback cb,
void *userdata)
{
conn->password_callback = cb;
conn->password_callback_userdata = userdata;
}
/** Set the number of retry attempts to decrypt a private key file.
*
* In case the user enters the password manually it can be useful to
* directly retry if the decryption of the key file failed.
*
* @param conn a Strophe connection object
* @param retries The number of retries that should be tried
*
* @ingroup TLS
*/
void xmpp_conn_set_password_retries(xmpp_conn_t *conn, unsigned int retries)
{
if (retries == 0)
conn->password_retries = 1;
else
conn->password_retries = retries;
}
/** Retrieve the path of the key file that shall be unlocked. /** Retrieve the path of the key file that shall be unlocked.
* *
* This makes usually sense to be called from the * This makes usually sense to be called from the
@@ -525,49 +603,6 @@ const char *xmpp_conn_get_keyfile(const xmpp_conn_t *conn)
return conn->tls_client_key; return conn->tls_client_key;
} }
/** Set the Client Certificate and Private Key or PKCS#12 encoded file that
* will be bound to the connection. If any of them was previously set, it
* will be discarded. This should not be used after a connection is created.
* The function will make a copy of the strings passed in.
*
* In case the Private Key is encrypted, a callback must be set via
* \ref xmpp_conn_set_password_callback so the TLS stack can retrieve the
* password.
*
* In case one wants to use a PKCS#12 encoded file, it should be passed via
* the `cert` parameter and `key` should be NULL. Passing a PKCS#12 file in
* `key` is deprecated.
*
* @param conn a Strophe connection object
* @param cert path to a certificate file or a P12 file
* @param key path to a private key file or a P12 file
*
* @ingroup TLS
*/
void xmpp_conn_set_client_cert(xmpp_conn_t *const conn,
const char *const cert,
const char *const key)
{
strophe_debug(conn->ctx, "conn", "set client cert %s %s", cert, key);
if (conn->tls_client_cert)
strophe_free(conn->ctx, conn->tls_client_cert);
conn->tls_client_cert = NULL;
if (conn->tls_client_key)
strophe_free(conn->ctx, conn->tls_client_key);
conn->tls_client_key = NULL;
if (cert && key) {
conn->tls_client_cert = strophe_strdup(conn->ctx, cert);
conn->tls_client_key = strophe_strdup(conn->ctx, key);
} else if (cert && !key) {
conn->tls_client_cert = strophe_strdup(conn->ctx, cert);
} else if (!cert && key) {
strophe_warn(conn->ctx, "xmpp",
"xmpp_conn_set_client_cert: Passing PKCS#12 in 'key' "
"parameter is deprecated. Use 'cert' instead");
conn->tls_client_cert = strophe_strdup(conn->ctx, key);
}
}
/** Get the number of xmppAddr entries in the client certificate. /** Get the number of xmppAddr entries in the client certificate.
* *
* @param conn a Strophe connection object * @param conn a Strophe connection object
@@ -608,22 +643,6 @@ const char *xmpp_conn_get_pass(const xmpp_conn_t *conn)
return conn->pass; return conn->pass;
} }
/** Set the password used to authenticate the connection.
* If any password was previously set, it will be discarded. The function
* will make a copy of the password string.
*
* @param conn a Strophe connection object
* @param pass the password
*
* @ingroup Connections
*/
void xmpp_conn_set_pass(xmpp_conn_t *conn, const char *pass)
{
if (conn->pass)
strophe_free(conn->ctx, conn->pass);
conn->pass = pass ? strophe_strdup(conn->ctx, pass) : NULL;
}
/** Get the strophe context that the connection is associated with. /** Get the strophe context that the connection is associated with.
* @param conn a Strophe connection object * @param conn a Strophe connection object
* *
@@ -1254,365 +1273,6 @@ int xmpp_conn_is_disconnected(xmpp_conn_t *conn)
return conn->state == XMPP_STATE_DISCONNECTED; return conn->state == XMPP_STATE_DISCONNECTED;
} }
/**
* This sets the Stream Management callback function
*
* After setting this API, the library will call the given callback function
* each time when the internal SM state is updated.
*
* This can be used in conjunction with \ref xmpp_conn_restore_sm_state to
* e.g. implement a mechanism that retains an SM state over potential
* application terminations.
*
* @param conn a Strophe connection object
* @param cb a callback function or NULL to disable
* @param ctx a context that will be passed on invocation of the callback
* function
*
* @ingroup Connections
*/
void xmpp_conn_set_sm_callback(xmpp_conn_t *conn,
xmpp_sm_callback cb,
void *ctx)
{
conn->sm_callback = cb;
conn->sm_callback_ctx = ctx;
}
struct sm_restore {
xmpp_conn_t *conn;
const unsigned char *state;
const unsigned char *const state_end, *const orig;
};
static int sm_load_u32(struct sm_restore *sm, uint8_t type, uint32_t *val)
{
if (*sm->state != type) {
strophe_error(
sm->conn->ctx, "conn",
"Invalid CBOR type at position %u: 0x%02x, expected: 0x%02x",
sm->state - sm->orig, *sm->state, type);
return XMPP_EINVOP;
}
sm->state++;
if ((sm->state + 4) > sm->state_end) {
strophe_error(sm->conn->ctx, "conn",
"Provided sm_state data is too short");
return XMPP_EINVOP;
}
uint32_t v;
memcpy(&v, sm->state, 4);
sm->state += 4;
*val = ntohl(v);
return 0;
}
static int sm_load_string(struct sm_restore *sm, char **val, size_t *len)
{
uint32_t l;
int ret = sm_load_u32(sm, 0x7a, &l);
if (ret)
return ret;
if ((sm->state + l) > sm->state_end) {
strophe_error(sm->conn->ctx, "conn",
"Provided sm_state data is too short");
return XMPP_EINVOP;
}
*val = strophe_alloc(sm->conn->ctx, l + 1);
if (!*val)
return XMPP_EMEM;
memcpy(*val, sm->state, l);
(*val)[l] = '\0';
sm->state += l;
*len = l;
return 0;
}
/**
* This restores the serialized Stream Management state
*
* After setting this API, the library will call the given callback function
* each time when the internal SM state is updated.
*
* This can be used in conjunction with \ref xmpp_conn_restore_sm_state to
* e.g. implement a mechanism that retains an SM state over potential
* application terminations.
*
* @param conn a Strophe connection object
* @param sm_state a buffer as passed to the SM callback
* @param sm_state_len the length of `sm_state`
*
* @ingroup Connections
*/
int xmpp_conn_restore_sm_state(xmpp_conn_t *conn,
const unsigned char *sm_state,
size_t sm_state_len)
{
/* We can only set the SM state when we're disconnected */
if (conn->state != XMPP_STATE_DISCONNECTED) {
strophe_error(conn->ctx, "conn",
"SM state can only be set the when we're disconnected");
return XMPP_EINVOP;
}
if (conn->sm_state) {
strophe_error(conn->ctx, "conn", "SM state is already set!");
return XMPP_EINVOP;
}
if (sm_state_len < 5 * 6) {
strophe_error(conn->ctx, "conn", "Provided sm_state data is too short");
return XMPP_EINVOP;
}
struct sm_restore sm = {.conn = conn,
.state = sm_state,
.state_end = sm_state + sm_state_len,
.orig = sm_state};
/* Check for pointer wrap-around, which should never happen */
if (sm.state_end < sm.state) {
strophe_error(conn->ctx, "conn",
"Internal error, pointer wrapped around");
return XMPP_EINVOP;
}
if (memcmp(sm.state, "\x1a\x00\x00\x00\x00", 5) != 0) {
strophe_error(conn->ctx, "conn", "Unknown sm_state version");
return XMPP_EINVOP;
}
sm.state += 5;
conn->sm_state = strophe_alloc(conn->ctx, sizeof(*conn->sm_state));
if (!conn->sm_state)
return XMPP_EMEM;
memset(conn->sm_state, 0, sizeof(*conn->sm_state));
conn->sm_state->ctx = conn->ctx;
conn->sm_state->sm_support = 1;
conn->sm_state->sm_enabled = 1;
conn->sm_state->can_resume = 1;
conn->sm_state->resume = 1;
int ret;
ret = sm_load_u32(&sm, 0x1a, &conn->sm_state->sm_sent_nr);
if (ret)
goto err_reload;
ret = sm_load_u32(&sm, 0x1a, &conn->sm_state->sm_handled_nr);
if (ret)
goto err_reload;
size_t id_len;
ret = sm_load_string(&sm, &conn->sm_state->id, &id_len);
if (ret)
goto err_reload;
uint32_t len, i;
ret = sm_load_u32(&sm, 0x9a, &len);
if (ret)
goto err_reload;
conn->send_queue_user_len = conn->send_queue_len = len;
for (i = 0; i < len; i++) {
xmpp_send_queue_t *item = strophe_alloc(conn->ctx, sizeof(*item));
if (!item) {
ret = XMPP_EMEM;
goto err_reload;
}
memset(item, 0, sizeof(*item));
if (!conn->send_queue_tail) {
conn->send_queue_head = item;
conn->send_queue_tail = item;
} else {
conn->send_queue_tail->next = item;
conn->send_queue_tail = item;
}
ret = sm_load_string(&sm, &item->data, &item->len);
if (ret)
goto err_reload;
item->owner = XMPP_QUEUE_USER;
}
ret = sm_load_u32(&sm, 0xba, &len);
if (ret)
goto err_reload;
for (i = 0; i < len; i++) {
xmpp_send_queue_t *item = strophe_alloc(conn->ctx, sizeof(*item));
if (!item) {
ret = XMPP_EMEM;
goto err_reload;
}
memset(item, 0, sizeof(*item));
add_queue_back(&conn->sm_state->sm_queue, item);
ret = sm_load_u32(&sm, 0x1a, &item->sm_h);
if (ret)
goto err_reload;
ret = sm_load_string(&sm, &item->data, &item->len);
if (ret)
goto err_reload;
item->owner = XMPP_QUEUE_USER;
}
return XMPP_EOK;
err_reload:
xmpp_free_sm_state(conn->sm_state);
return ret;
}
static int sm_store_u32(unsigned char **next_,
const unsigned char *const end,
uint8_t type,
uint32_t val)
{
unsigned char *next = *next_;
if (next + 5 > end)
return 1;
*next++ = type;
uint32_t v = htonl(val);
memcpy(next, &v, 4);
next += 4;
*next_ = next;
return 0;
}
static size_t sm_state_serialize(xmpp_conn_t *conn, unsigned char **buf)
{
if (!conn->sm_state->sm_support || !conn->sm_state->sm_enabled ||
!conn->sm_state->can_resume) {
*buf = NULL;
return 0;
}
uint32_t id_len = strlen(conn->sm_state->id);
xmpp_send_queue_t *peek = conn->sm_state->sm_queue.head;
size_t sm_queue_len = 0;
size_t sm_queue_size = 0;
while (peek) {
sm_queue_len++;
sm_queue_size += 10 + peek->len;
peek = peek->next;
}
uint32_t send_queue_len = 0;
size_t send_queue_size = 0;
peek = conn->send_queue_head;
while (peek) {
send_queue_len++;
send_queue_size += 5 + peek->len;
peek = peek->next;
}
size_t buf_size =
5 + 5 + 5 + 5 + id_len + 5 + send_queue_size + 5 + sm_queue_size;
*buf = strophe_alloc(conn->ctx, buf_size);
if (*buf == NULL)
return 0;
unsigned char *next = *buf;
const unsigned char *const end = next + buf_size;
/* Check for pointer wrap-around, which should never happen */
if (end < next) {
strophe_error(conn->ctx, "conn",
"Internal error, pointer wrapped around");
return 0;
}
memcpy(next, "\x1a\x00\x00\x00\x00", 5); // Version
next += 5;
if (sm_store_u32(&next, end, 0x1a, conn->sm_state->sm_sent_nr))
goto err_serialize;
if (sm_store_u32(&next, end, 0x1a, conn->sm_state->sm_handled_nr))
goto err_serialize;
if (sm_store_u32(&next, end, 0x7a, id_len))
goto err_serialize;
memcpy(next, conn->sm_state->id, id_len);
next += id_len;
if (sm_store_u32(&next, end, 0x9a, send_queue_len))
goto err_serialize;
peek = conn->send_queue_head;
while (peek) {
if (sm_store_u32(&next, end, 0x7a, (uint32_t)peek->len))
goto err_serialize;
if (next + peek->len > end)
goto err_serialize;
memcpy(next, peek->data, peek->len);
next += peek->len;
peek = peek->next;
}
if (sm_store_u32(&next, end, 0xba, sm_queue_len))
goto err_serialize;
peek = conn->sm_state->sm_queue.head;
while (peek) {
if (sm_store_u32(&next, end, 0x1a, peek->sm_h))
goto err_serialize;
if (sm_store_u32(&next, end, 0x7a, (uint32_t)peek->len))
goto err_serialize;
if (next + peek->len > end)
goto err_serialize;
memcpy(next, peek->data, peek->len);
next += peek->len;
peek = peek->next;
}
return buf_size;
err_serialize:
strophe_error(conn->ctx, "conn", "Can't serialize more data, buffer full");
strophe_free(conn->ctx, buf);
return 0;
}
void trigger_sm_callback(xmpp_conn_t *conn)
{
if (!conn || !conn->sm_callback)
return;
unsigned char *buf;
size_t size = sm_state_serialize(conn, &buf);
conn->sm_callback(conn, conn->sm_callback_ctx, buf, size);
strophe_free(conn->ctx, buf);
}
static void _reset_sm_state_for_reconnect(xmpp_conn_t *conn)
{
xmpp_sm_state_t *s = conn->sm_state;
if (s->previd) {
strophe_free(conn->ctx, s->previd);
s->previd = NULL;
}
if (s->can_resume) {
s->previd = s->id;
s->id = NULL;
s->bound_jid = conn->bound_jid;
conn->bound_jid = NULL;
} else if (s->id) {
strophe_free(conn->ctx, s->id);
s->id = NULL;
}
s->r_sent = s->sm_enabled = s->sm_support = s->resume = 0;
if (s->bind) {
xmpp_stanza_release(s->bind);
s->bind = NULL;
}
}
/** /**
* This returns the Stream Management state of a connection object after * This returns the Stream Management state of a connection object after
* it has been disconnected. * it has been disconnected.
@@ -1644,6 +1304,34 @@ xmpp_sm_state_t *xmpp_conn_get_sm_state(xmpp_conn_t *conn)
return ret; return ret;
} }
static void _reset_sm_state_for_reconnect(xmpp_conn_t *conn)
{
xmpp_sm_state_t *s = conn->sm_state;
if (s->previd) {
strophe_free(conn->ctx, s->previd);
s->previd = NULL;
}
if (s->can_resume) {
s->previd = s->id;
s->id = NULL;
s->bound_jid = conn->bound_jid;
conn->bound_jid = NULL;
} else if (s->id) {
strophe_free(conn->ctx, s->id);
s->id = NULL;
}
s->r_sent = s->sm_enabled = s->sm_support = s->resume = 0;
if (s->bind) {
xmpp_stanza_release(s->bind);
s->bind = NULL;
}
}
/** /**
* @param conn a Strophe connection object * @param conn a Strophe connection object
* @param sm_state A Stream Management state returned from a call to * @param sm_state A Stream Management state returned from a call to
@@ -1822,9 +1510,7 @@ char *xmpp_conn_send_queue_drop_element(xmpp_conn_t *conn,
conn->sm_state->r_sent = 0; conn->sm_state->r_sent = 0;
} }
/* Finally drop the element */ /* Finally drop the element */
char *r = _drop_send_queue_element(conn, t); return _drop_send_queue_element(conn, t);
trigger_sm_callback(conn);
return r;
} }
/* timed handler for cleanup if normal disconnect procedure takes too long */ /* timed handler for cleanup if normal disconnect procedure takes too long */
@@ -2018,7 +1704,6 @@ static void _handle_stream_end(char *name, void *userdata)
strophe_debug(conn->ctx, "xmpp", "RECV: </stream:stream>"); strophe_debug(conn->ctx, "xmpp", "RECV: </stream:stream>");
/* the session has been terminated properly, i.e. it can't be resumed */ /* the session has been terminated properly, i.e. it can't be resumed */
conn->sm_state->can_resume = 0; conn->sm_state->can_resume = 0;
trigger_sm_callback(conn);
conn_disconnect_clean(conn); conn_disconnect_clean(conn);
} }
@@ -2094,7 +1779,6 @@ static void _conn_sm_handle_stanza(xmpp_conn_t *const conn,
conn->sm_state->r_sent = 0; conn->sm_state->r_sent = 0;
} }
} }
trigger_sm_callback(conn);
} }
static unsigned short _conn_default_port(xmpp_conn_t *conn, static unsigned short _conn_default_port(xmpp_conn_t *conn,
@@ -2381,10 +2065,8 @@ static int _send_raw(xmpp_conn_t *conn,
strophe_debug_verbose(1, conn->ctx, "conn", "Q_ADD: %p", item); strophe_debug_verbose(1, conn->ctx, "conn", "Q_ADD: %p", item);
if (!(owner & XMPP_QUEUE_SM) && conn->sm_state->sm_enabled && if (!(owner & XMPP_QUEUE_SM) && conn->sm_state->sm_enabled &&
!conn->sm_state->r_sent) { !conn->sm_state->r_sent) {
conn->sm_state->r_sent = 1;
send_raw(conn, req_ack, strlen(req_ack), XMPP_QUEUE_SM_STROPHE, item); send_raw(conn, req_ack, strlen(req_ack), XMPP_QUEUE_SM_STROPHE, item);
} else { conn->sm_state->r_sent = 1;
trigger_sm_callback(conn);
} }
return XMPP_EOK; return XMPP_EOK;
} }

View File

@@ -19,6 +19,7 @@
*/ */
#include "common.h" #include "common.h"
#include <limits.h>
/** Allocate memory in a Strophe 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.
@@ -86,6 +87,10 @@ char *xmpp_strndup(const xmpp_ctx_t *ctx, const char *s, size_t len)
return strophe_strndup(ctx, s, len); return strophe_strndup(ctx, s, len);
} }
/** Write to the log.
*
* @ingroup Deprecated
*/
void xmpp_log(const xmpp_ctx_t *ctx, void xmpp_log(const xmpp_ctx_t *ctx,
xmpp_log_level_t level, xmpp_log_level_t level,
const char *area, const char *area,
@@ -217,6 +222,10 @@ char *xmpp_strtok_r(char *s, const char *delim, char **saveptr)
return strophe_strtok_r(s, delim, saveptr); return strophe_strtok_r(s, delim, saveptr);
} }
/** snprintf(3) implementation.
*
* @ingroup Deprecated
*/
int xmpp_snprintf(char *str, size_t count, const char *fmt, ...) int xmpp_snprintf(char *str, size_t count, const char *fmt, ...)
{ {
va_list ap; va_list ap;
@@ -228,11 +237,184 @@ int xmpp_snprintf(char *str, size_t count, const char *fmt, ...)
return ret; return ret;
} }
/** vsnprintf(3) implementation.
*
* @ingroup Deprecated
*/
int xmpp_vsnprintf(char *str, size_t count, const char *fmt, va_list arg) int xmpp_vsnprintf(char *str, size_t count, const char *fmt, va_list arg)
{ {
return strophe_vsnprintf(str, count, fmt, arg); return strophe_vsnprintf(str, count, fmt, arg);
} }
/** Set the JID of the user that will be bound to the connection.
* If any JID was previously set, it will be discarded. This should not be
* be used after a connection is created. The function will make a copy of
* the JID string. If the supplied JID is missing the node, SASL
* ANONYMOUS authentication will be used.
*
* @param conn a Strophe connection object
* @param jid a full or bare JID
*
* @ingroup Deprecated
*/
void xmpp_conn_set_jid(xmpp_conn_t *conn, const char *jid)
{
xmpp_conn_set_string(conn, XMPP_SETTING_JID, jid);
}
/** Set the password used to authenticate the connection.
* If any password was previously set, it will be discarded. The function
* will make a copy of the password string.
*
* @param conn a Strophe connection object
* @param pass the password
*
* @ingroup Deprecated
*/
void xmpp_conn_set_pass(xmpp_conn_t *conn, const char *pass)
{
xmpp_conn_set_string(conn, XMPP_SETTING_PASS, pass);
}
/** Set the CAfile
*
* @param conn a Strophe connection object
* @param path path to a certificate file
*
* @ingroup Deprecated
*/
void xmpp_conn_set_cafile(xmpp_conn_t *const conn, const char *path)
{
xmpp_conn_set_string(conn, XMPP_SETTING_CAFILE, path);
}
/** Set the CApath
*
* @param conn a Strophe connection object
* @param path path to a folder containing certificates
*
* @ingroup Deprecated
*/
void xmpp_conn_set_capath(xmpp_conn_t *const conn, const char *path)
{
xmpp_conn_set_string(conn, XMPP_SETTING_CAPATH, path);
}
/** Set the Client Certificate and Private Key or PKCS#12 encoded file that
* will be bound to the connection. If any of them was previously set, it
* will be discarded. This should not be used after a connection is created.
* The function will make a copy of the strings passed in.
*
* In case the Private Key is encrypted, a callback must be set via
* \ref xmpp_conn_set_password_callback so the TLS stack can retrieve the
* password.
*
* In case one wants to use a PKCS#12 encoded file, it should be passed via
* the `cert` parameter and `key` should be NULL. Passing a PKCS#12 file in
* `key` is deprecated.
*
* @param conn a Strophe connection object
* @param cert path to a certificate file or a P12 file
* @param key path to a private key file or a P12 file
*
* @ingroup Deprecated
*/
void xmpp_conn_set_client_cert(xmpp_conn_t *const conn,
const char *const cert,
const char *const key)
{
strophe_debug(conn->ctx, "conn", "set client cert %s %s", cert, key);
if (!cert && key) {
xmpp_conn_set_string(conn, XMPP_SETTING_CLIENT_CERT, key);
strophe_warn(conn->ctx, "xmpp",
"xmpp_conn_set_client_cert: Passing PKCS#12 in 'key' "
"parameter is deprecated. Use 'cert' instead");
} else {
xmpp_conn_set_string(conn, XMPP_SETTING_CLIENT_CERT, cert);
xmpp_conn_set_string(conn, XMPP_SETTING_CLIENT_KEY, key);
}
}
/** Set the number of retry attempts to decrypt a private key file.
*
* In case the user enters the password manually it can be useful to
* directly retry if the decryption of the key file failed.
*
* @param conn a Strophe connection object
* @param retries The number of retries that should be tried
*
* @ingroup Deprecated
*/
void xmpp_conn_set_password_retries(xmpp_conn_t *conn, unsigned int retries)
{
int val;
if (retries > INT_MAX) {
val = INT_MAX;
strophe_warn(conn->ctx, "xmpp", "retries capped from %u to %d", retries,
val);
} else {
val = (int)retries;
}
xmpp_conn_set_int(conn, XMPP_SETTING_PASSWORD_RETRIES, val);
}
/** Set the Callback function which will be called when the TLS stack can't
* decrypt a password protected key file.
*
* @param conn a Strophe connection object
* @param cb The callback function that shall be called
* @param userdata An opaque data pointer that will be passed to the callback
*
* @ingroup Deprecated
*/
void xmpp_conn_set_password_callback(xmpp_conn_t *conn,
xmpp_password_callback cb,
void *userdata)
{
xmpp_conn_set_functionpointer(conn, XMPP_SETTING_PASSWORD_CALLBACK, cb);
xmpp_conn_set_pointer(conn, XMPP_SETTING_PASSWORD_CALLBACK_USERDATA,
userdata);
}
/** Set the Handler function which will be called when the TLS stack can't
* verify the CA of the server we're trying to connect to.
*
* @param conn a Strophe connection object
* @param hndl certfail Handler function
*
* @ingroup Deprecated
*/
void xmpp_conn_set_certfail_handler(xmpp_conn_t *const conn,
xmpp_certfail_handler hndl)
{
xmpp_conn_set_functionpointer(conn, XMPP_SETTING_CERTFAIL_HANDLER, hndl);
}
/** Register sockopt callback
* Set function to be called when a new socket is created to allow setting
* socket options before connection is started.
*
* If the connection is already connected, this callback will be called
* immediately.
*
* To set options that can only be applied to disconnected sockets, the
* callback must be registered before connecting.
*
* @param conn The Strophe connection object this callback is being registered
* for
* @param callback a xmpp_sockopt_callback callback function that will receive
* notifications of connection status
*
* @ingroup Deprecated
*/
void xmpp_conn_set_sockopt_callback(xmpp_conn_t *conn,
xmpp_sockopt_callback callback)
{
xmpp_conn_set_functionpointer(conn, XMPP_SETTING_SOCKOPT_CALLBACK,
callback);
}
/** Set TCP keepalive parameters /** Set TCP keepalive parameters
* Turn on TCP keepalive and set timeout and interval. Zero timeout * Turn on TCP keepalive and set timeout and interval. Zero timeout
* disables TCP keepalives. The parameters are applied immediately for * disables TCP keepalives. The parameters are applied immediately for
@@ -253,7 +435,8 @@ void xmpp_conn_set_keepalive(xmpp_conn_t *conn, int timeout, int interval)
conn->ka_timeout = timeout; conn->ka_timeout = timeout;
conn->ka_interval = interval; conn->ka_interval = interval;
conn->ka_count = 0; conn->ka_count = 0;
xmpp_conn_set_sockopt_callback(conn, xmpp_sockopt_cb_keepalive); xmpp_conn_set_functionpointer(conn, XMPP_SETTING_SOCKOPT_CALLBACK,
xmpp_sockopt_cb_keepalive);
} }
/** Disable TLS for this connection, called by users of the library. /** Disable TLS for this connection, called by users of the library.

View File

@@ -39,7 +39,7 @@
#include <sys/select.h> #include <sys/select.h>
#include <errno.h> #include <errno.h>
#include <unistd.h> #include <unistd.h>
#define _sleep(x) usleep((x) * 1000) #define _sleep(x) usleep((x)*1000)
#else #else
#include <winsock2.h> #include <winsock2.h>
#ifndef ETIMEDOUT #ifndef ETIMEDOUT
@@ -174,7 +174,6 @@ void xmpp_run_once(xmpp_ctx_t *ctx, unsigned long timeout)
/* if we've sent everything update the tail */ /* if we've sent everything update the tail */
if (!sq) if (!sq)
conn->send_queue_tail = NULL; conn->send_queue_tail = NULL;
trigger_sm_callback(conn);
} }
intf->flush(intf); intf->flush(intf);

View File

@@ -25,6 +25,8 @@
#include "common.h" #include "common.h"
#include "ostypes.h" #include "ostypes.h"
typedef int (*xmpp_void_handler)();
/* Remove item from the list pointed by head, but don't free it. /* 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 * 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() * is the previous in the list. handler_fire_stanza() and handler_fire_timed()

View File

@@ -37,7 +37,7 @@
#define PUT_32BIT_LSB_FIRST(cp, value) \ #define PUT_32BIT_LSB_FIRST(cp, value) \
do { \ do { \
(cp)[0] = (value) & 0xFF; \ (cp)[0] = (value)&0xFF; \
(cp)[1] = ((value) >> 8) & 0xFF; \ (cp)[1] = ((value) >> 8) & 0xFF; \
(cp)[2] = ((value) >> 16) & 0xFF; \ (cp)[2] = ((value) >> 16) & 0xFF; \
(cp)[3] = ((value) >> 24) & 0xFF; \ (cp)[3] = ((value) >> 24) & 0xFF; \

View File

@@ -68,9 +68,9 @@ struct _xmpp_rand_t {
}; };
/* returns smallest number mupliple of y that not less than x */ /* returns smallest number mupliple of y that not less than x */
#define round_up(x, y) (((x) + (y) - 1) / (y) * (y)) #define round_up(x, y) (((x) + (y)-1) / (y) * (y))
/* returns smallest integer number that not less than x/y */ /* returns smallest integer number that not less than x/y */
#define div_round_up(x, y) (((x) + (y) - 1) / (y)) #define div_round_up(x, y) (((x) + (y)-1) / (y))
/* adds two arrays as numbers in big-endian representation and stores /* adds two arrays as numbers in big-endian representation and stores
* result in the first one. * result in the first one.

View File

@@ -630,7 +630,7 @@ static void netbuf_add_16bitnum(unsigned char *buf,
/* assuming big endian */ /* assuming big endian */
*p++ = (num >> 8) & 0xff; *p++ = (num >> 8) & 0xff;
*p++ = (num) & 0xff; *p++ = (num)&0xff;
*offset += 2; *offset += 2;
} }

View File

@@ -53,7 +53,7 @@ extern "C" {
(y)[0] = (uint8_t)(((x) >> 24) & 255); \ (y)[0] = (uint8_t)(((x) >> 24) & 255); \
(y)[1] = (uint8_t)(((x) >> 16) & 255); \ (y)[1] = (uint8_t)(((x) >> 16) & 255); \
(y)[2] = (uint8_t)(((x) >> 8) & 255); \ (y)[2] = (uint8_t)(((x) >> 8) & 255); \
(y)[3] = (uint8_t)((x) & 255); \ (y)[3] = (uint8_t)((x)&255); \
} while (0) } while (0)
#define LOAD32H(x, y) \ #define LOAD32H(x, y) \
@@ -72,7 +72,7 @@ extern "C" {
(y)[4] = (uint8_t)(((x) >> 24) & 255); \ (y)[4] = (uint8_t)(((x) >> 24) & 255); \
(y)[5] = (uint8_t)(((x) >> 16) & 255); \ (y)[5] = (uint8_t)(((x) >> 16) & 255); \
(y)[6] = (uint8_t)(((x) >> 8) & 255); \ (y)[6] = (uint8_t)(((x) >> 8) & 255); \
(y)[7] = (uint8_t)((x) & 255); \ (y)[7] = (uint8_t)((x)&255); \
} while (0) } while (0)
#define LOAD64H(x, y) \ #define LOAD64H(x, y) \
@@ -96,13 +96,13 @@ extern "C" {
#define CONST64(n) n##ULL #define CONST64(n) n##ULL
#endif #endif
#define RORc(x, y) \ #define RORc(x, y) \
(((((uint32_t)(x) & 0xFFFFFFFFUL) >> (uint32_t)((y) & 31)) | \ (((((uint32_t)(x)&0xFFFFFFFFUL) >> (uint32_t)((y)&31)) | \
((uint32_t)(x) << (uint32_t)((32 - ((y) & 31)) & 31))) & \ ((uint32_t)(x) << (uint32_t)((32 - ((y)&31)) & 31))) & \
0xFFFFFFFFUL) 0xFFFFFFFFUL)
#define ROR64c(x, y) \ #define ROR64c(x, y) \
(((((x) & CONST64(0xFFFFFFFFFFFFFFFF)) >> ((uint64_t)(y) & CONST64(63))) | \ (((((x)&CONST64(0xFFFFFFFFFFFFFFFF)) >> ((uint64_t)(y)&CONST64(63))) | \
((x) << (((uint64_t)64 - ((y) & 63)) & 63))) & \ ((x) << (((uint64_t)64 - ((y)&63)) & 63))) & \
CONST64(0xFFFFFFFFFFFFFFFF)) CONST64(0xFFFFFFFFFFFFFFFF))
#ifdef __cplusplus #ifdef __cplusplus

View File

@@ -9,7 +9,7 @@
#define Ch(x, y, z) (z ^ (x & (y ^ z))) #define Ch(x, y, z) (z ^ (x & (y ^ z)))
#define Maj(x, y, z) (((x | y) & z) | (x & y)) #define Maj(x, y, z) (((x | y) & z) | (x & y))
#define S(x, n) RORc((x), (n)) #define S(x, n) RORc((x), (n))
#define R(x, n) (((x) & 0xFFFFFFFFUL) >> (n)) #define R(x, n) (((x)&0xFFFFFFFFUL) >> (n))
#define Sigma0(x) (S(x, 2) ^ S(x, 13) ^ S(x, 22)) #define Sigma0(x) (S(x, 2) ^ S(x, 13) ^ S(x, 22))
#define Sigma1(x) (S(x, 6) ^ S(x, 11) ^ S(x, 25)) #define Sigma1(x) (S(x, 6) ^ S(x, 11) ^ S(x, 25))
#define Gamma0(x) (S(x, 7) ^ S(x, 18) ^ R(x, 3)) #define Gamma0(x) (S(x, 7) ^ S(x, 18) ^ R(x, 3))

View File

@@ -52,7 +52,7 @@ static const uint64_t K[80] = {
#define Ch(x, y, z) (z ^ (x & (y ^ z))) #define Ch(x, y, z) (z ^ (x & (y ^ z)))
#define Maj(x, y, z) (((x | y) & z) | (x & y)) #define Maj(x, y, z) (((x | y) & z) | (x & y))
#define S(x, n) ROR64c(x, n) #define S(x, n) ROR64c(x, n)
#define R(x, n) (((x) & CONST64(0xFFFFFFFFFFFFFFFF)) >> ((uint64_t)n)) #define R(x, n) (((x)&CONST64(0xFFFFFFFFFFFFFFFF)) >> ((uint64_t)n))
#define Sigma0(x) (S(x, 28) ^ S(x, 34) ^ S(x, 39)) #define Sigma0(x) (S(x, 28) ^ S(x, 34) ^ S(x, 39))
#define Sigma1(x) (S(x, 14) ^ S(x, 18) ^ S(x, 41)) #define Sigma1(x) (S(x, 14) ^ S(x, 18) ^ S(x, 41))
#define Gamma0(x) (S(x, 1) ^ S(x, 8) ^ R(x, 7)) #define Gamma0(x) (S(x, 1) ^ S(x, 8) ^ R(x, 7))

View File

@@ -74,23 +74,6 @@ xmpp_conn_t *xmpp_tlscert_get_conn(const xmpp_tlscert_t *cert)
return cert->conn; return cert->conn;
} }
/** Get the userdata of a Strophe connection which is assigned to this
* certificate.
*
* @param cert a Strophe TLS certificate object
*
* @return the userdata of a Strophe connection object where this certificate
* originates from
*
* @ingroup TLS
*/
void *xmpp_tlscert_get_userdata(const xmpp_tlscert_t *cert)
{
if (cert->conn == NULL)
return NULL;
return cert->conn->userdata;
}
/** Get the complete PEM of this certificate. /** Get the complete PEM of this certificate.
* *
* @param cert a Strophe TLS certificate object * @param cert a Strophe TLS certificate object

View File

@@ -422,8 +422,6 @@ static int _tls_verify(gnutls_session_t session)
return -1; return -1;
} }
tlscert->conn = tls->conn;
if (tls->conn->certfail_handler(tlscert, (char *)out.data) == 0) { if (tls->conn->certfail_handler(tlscert, (char *)out.data) == 0) {
xmpp_tlscert_free(tlscert); xmpp_tlscert_free(tlscert);
gnutls_x509_crt_deinit(cert); gnutls_x509_crt_deinit(cert);

View File

@@ -540,8 +540,6 @@ static int _tls_verify(int preverify_ok, X509_STORE_CTX *x509_ctx)
if (!tlscert) if (!tlscert)
return 0; return 0;
tlscert->conn = conn;
strophe_debug(conn->ctx, "tls", "preverify_ok:%d\nSubject: %s\nIssuer: %s", strophe_debug(conn->ctx, "tls", "preverify_ok:%d\nSubject: %s\nIssuer: %s",
preverify_ok, tlscert->elements[XMPP_CERT_SUBJECT], preverify_ok, tlscert->elements[XMPP_CERT_SUBJECT],
tlscert->elements[XMPP_CERT_ISSUER]); tlscert->elements[XMPP_CERT_ISSUER]);

127
strophe.h
View File

@@ -18,7 +18,6 @@
#define __LIBSTROPHE_STROPHE_H__ #define __LIBSTROPHE_STROPHE_H__
#include <stddef.h> /* size_t */ #include <stddef.h> /* size_t */
#include <stdint.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@@ -372,37 +371,70 @@ typedef int (*xmpp_sockopt_callback)(xmpp_conn_t *conn, void *sock);
/* an example callback that sets basic keepalive parameters */ /* an example callback that sets basic keepalive parameters */
int xmpp_sockopt_cb_keepalive(xmpp_conn_t *conn, void *sock); int xmpp_sockopt_cb_keepalive(xmpp_conn_t *conn, void *sock);
void xmpp_send_error(xmpp_conn_t *conn, xmpp_error_type_t type, char *text);
xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t *ctx); xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t *ctx);
xmpp_conn_t *xmpp_conn_clone(xmpp_conn_t *conn); xmpp_conn_t *xmpp_conn_clone(xmpp_conn_t *conn);
int xmpp_conn_release(xmpp_conn_t *conn); int xmpp_conn_release(xmpp_conn_t *conn);
/** Connection settings
*/
typedef enum xmpp_conn_setting_t {
/* String values */
XMPP_SETTING_JID = 0x0, /**< JID */
XMPP_SETTING_PASS, /**< Password */
XMPP_SETTING_CAFILE, /**< CAfile */
XMPP_SETTING_CAPATH, /**< CApath */
XMPP_SETTING_CLIENT_CERT, /**< Client Certificate */
XMPP_SETTING_CLIENT_KEY, /**< Key of Client Certificate */
/* Int values */
XMPP_SETTING_PASSWORD_RETRIES = 0x40, /**< Number of retry attempts to
decrypt a private key file. */
XMPP_SETTING_COMPRESSION_LEVEL, /**< Compression level. */
/* Pointer values */
XMPP_SETTING_PASSWORD_CALLBACK_USERDATA = 0x80, /**< Userdata for password
callback function */
/* Functionpointer values */
XMPP_SETTING_PASSWORD_CALLBACK = 0xC0, /**< Callback function to retrieve
password for key file. */
XMPP_SETTING_CERTFAIL_HANDLER, /**< Handler function when certificate chain
can't be verified */
XMPP_SETTING_SOCKOPT_CALLBACK, /**< Callback function when a new socket is
created. */
} xmpp_conn_setting_t;
void xmpp_conn_set_int(xmpp_conn_t *conn,
xmpp_conn_setting_t setting,
int value);
void xmpp_conn_set_string(xmpp_conn_t *conn,
xmpp_conn_setting_t setting,
const char *value);
void xmpp_conn_set_pointer(xmpp_conn_t *conn,
xmpp_conn_setting_t setting,
void *value);
/* Provide a wrapper macro, so users don't have to cast their function pointer
* type manually. */
typedef int (*xmpp_conn_pfn_t)();
#define xmpp_conn_set_functionpointer(c, s, p) \
do { \
xmpp_conn_set_functionpointer_impl(c, s, (xmpp_conn_pfn_t)p); \
} while (0)
void xmpp_conn_set_functionpointer_impl(xmpp_conn_t *conn,
xmpp_conn_setting_t setting,
xmpp_conn_pfn_t pfn);
long xmpp_conn_get_flags(const xmpp_conn_t *conn); long xmpp_conn_get_flags(const xmpp_conn_t *conn);
int xmpp_conn_set_flags(xmpp_conn_t *conn, long flags); int xmpp_conn_set_flags(xmpp_conn_t *conn, long flags);
const char *xmpp_conn_get_jid(const xmpp_conn_t *conn); const char *xmpp_conn_get_jid(const xmpp_conn_t *conn);
const char *xmpp_conn_get_bound_jid(const xmpp_conn_t *conn); const char *xmpp_conn_get_bound_jid(const xmpp_conn_t *conn);
void xmpp_conn_set_jid(xmpp_conn_t *conn, const char *jid);
void xmpp_conn_set_cafile(xmpp_conn_t *const conn, const char *path);
void xmpp_conn_set_capath(xmpp_conn_t *const conn, const char *path);
void xmpp_conn_set_certfail_handler(xmpp_conn_t *const conn,
xmpp_certfail_handler hndl);
xmpp_tlscert_t *xmpp_conn_get_peer_cert(xmpp_conn_t *const conn); xmpp_tlscert_t *xmpp_conn_get_peer_cert(xmpp_conn_t *const conn);
void xmpp_conn_set_password_callback(xmpp_conn_t *conn,
xmpp_password_callback cb,
void *userdata);
void xmpp_conn_set_password_retries(xmpp_conn_t *conn, unsigned int retries);
const char *xmpp_conn_get_keyfile(const xmpp_conn_t *conn); const char *xmpp_conn_get_keyfile(const xmpp_conn_t *conn);
void xmpp_conn_set_client_cert(xmpp_conn_t *conn,
const char *cert,
const char *key);
unsigned int xmpp_conn_cert_xmppaddr_num(xmpp_conn_t *conn); unsigned int xmpp_conn_cert_xmppaddr_num(xmpp_conn_t *conn);
char *xmpp_conn_cert_xmppaddr(xmpp_conn_t *conn, unsigned int n); char *xmpp_conn_cert_xmppaddr(xmpp_conn_t *conn, unsigned int n);
const char *xmpp_conn_get_pass(const xmpp_conn_t *conn); const char *xmpp_conn_get_pass(const xmpp_conn_t *conn);
void xmpp_conn_set_pass(xmpp_conn_t *conn, const char *pass);
xmpp_ctx_t *xmpp_conn_get_context(xmpp_conn_t *conn); xmpp_ctx_t *xmpp_conn_get_context(xmpp_conn_t *conn);
int xmpp_conn_is_secured(xmpp_conn_t *conn); int xmpp_conn_is_secured(xmpp_conn_t *conn);
void xmpp_conn_set_sockopt_callback(xmpp_conn_t *conn,
xmpp_sockopt_callback callback);
int xmpp_conn_is_connecting(xmpp_conn_t *conn); int xmpp_conn_is_connecting(xmpp_conn_t *conn);
int xmpp_conn_is_connected(xmpp_conn_t *conn); int xmpp_conn_is_connected(xmpp_conn_t *conn);
int xmpp_conn_is_disconnected(xmpp_conn_t *conn); int xmpp_conn_is_disconnected(xmpp_conn_t *conn);
@@ -415,38 +447,8 @@ typedef enum {
char *xmpp_conn_send_queue_drop_element(xmpp_conn_t *conn, char *xmpp_conn_send_queue_drop_element(xmpp_conn_t *conn,
xmpp_queue_element_t which); xmpp_queue_element_t which);
int xmpp_conn_set_sm_state(xmpp_conn_t *conn, xmpp_sm_state_t *sm_state);
xmpp_sm_state_t *xmpp_conn_get_sm_state(xmpp_conn_t *conn); xmpp_sm_state_t *xmpp_conn_get_sm_state(xmpp_conn_t *conn);
int xmpp_conn_set_sm_state(xmpp_conn_t *conn, xmpp_sm_state_t *sm_state);
/** The function which will be called when Strophe updates its internal SM
* state.
*
* Please note that you have to create a copy of the buffer, since the library
* will free the buffer right after return of the callback function.
*
*
* @param conn The Strophe connection object this callback
* originates from.
* @param ctx The `ctx` pointer as passed to
* \ref xmpp_conn_set_sm_callback
* @param sm_state A pointer to a buffer containing the serialized SM
* state.
* @param sm_state_len The length of `sm_state`.
*
* @return 0 on success, -1 on error
*
* @ingroup Connections
*/
typedef void (*xmpp_sm_callback)(xmpp_conn_t *conn,
void *ctx,
const unsigned char *sm_state,
size_t sm_state_len);
void xmpp_conn_set_sm_callback(xmpp_conn_t *conn,
xmpp_sm_callback cb,
void *ctx);
int xmpp_conn_restore_sm_state(xmpp_conn_t *conn,
const unsigned char *sm_state,
size_t sm_state_len);
void xmpp_free_sm_state(xmpp_sm_state_t *sm_state); void xmpp_free_sm_state(xmpp_sm_state_t *sm_state);
@@ -476,6 +478,7 @@ int xmpp_conn_tls_start(xmpp_conn_t *conn);
void xmpp_disconnect(xmpp_conn_t *conn); void xmpp_disconnect(xmpp_conn_t *conn);
void xmpp_send(xmpp_conn_t *conn, xmpp_stanza_t *stanza); void xmpp_send(xmpp_conn_t *conn, xmpp_stanza_t *stanza);
void xmpp_send_error(xmpp_conn_t *conn, xmpp_error_type_t type, char *text);
void xmpp_send_raw_string(xmpp_conn_t *conn, const char *fmt, ...); void xmpp_send_raw_string(xmpp_conn_t *conn, const char *fmt, ...);
void xmpp_send_raw(xmpp_conn_t *conn, const char *data, size_t len); void xmpp_send_raw(xmpp_conn_t *conn, const char *data, size_t len);
@@ -642,7 +645,6 @@ void xmpp_ctx_set_timeout(xmpp_ctx_t *ctx, unsigned long timeout);
xmpp_ctx_t *xmpp_tlscert_get_ctx(const xmpp_tlscert_t *cert); xmpp_ctx_t *xmpp_tlscert_get_ctx(const xmpp_tlscert_t *cert);
xmpp_conn_t *xmpp_tlscert_get_conn(const xmpp_tlscert_t *cert); xmpp_conn_t *xmpp_tlscert_get_conn(const xmpp_tlscert_t *cert);
void *xmpp_tlscert_get_userdata(const xmpp_tlscert_t *cert);
const char *xmpp_tlscert_get_pem(const xmpp_tlscert_t *cert); const char *xmpp_tlscert_get_pem(const xmpp_tlscert_t *cert);
const char *xmpp_tlscert_get_dnsname(const xmpp_tlscert_t *cert, size_t n); const char *xmpp_tlscert_get_dnsname(const xmpp_tlscert_t *cert, size_t n);
const char *xmpp_tlscert_get_string(const xmpp_tlscert_t *cert, const char *xmpp_tlscert_get_string(const xmpp_tlscert_t *cert,
@@ -744,6 +746,7 @@ void xmpp_rand_nonce(xmpp_rand_t *rand, char *output, size_t len);
* deprecation */ * deprecation */
#include <stdarg.h> #include <stdarg.h>
#if !defined(XMPP_DEPRECATED)
/** /**
* XMPP_DEPRECATED(x) macro to show a compiler warning for deprecated API * XMPP_DEPRECATED(x) macro to show a compiler warning for deprecated API
* functions * functions
@@ -762,6 +765,7 @@ void xmpp_rand_nonce(xmpp_rand_t *rand, char *output, size_t len);
#else #else
#define XMPP_DEPRECATED(x) #define XMPP_DEPRECATED(x)
#endif #endif
#endif
XMPP_DEPRECATED(internal) void *xmpp_alloc(const xmpp_ctx_t *ctx, size_t size); XMPP_DEPRECATED(internal) void *xmpp_alloc(const xmpp_ctx_t *ctx, size_t size);
XMPP_DEPRECATED(internal) XMPP_DEPRECATED(internal)
@@ -801,6 +805,31 @@ void xmpp_conn_set_keepalive(xmpp_conn_t *conn, int timeout, int interval);
XMPP_DEPRECATED(xmpp_conn_set_flags) XMPP_DEPRECATED(xmpp_conn_set_flags)
void xmpp_conn_disable_tls(xmpp_conn_t *conn); void xmpp_conn_disable_tls(xmpp_conn_t *conn);
XMPP_DEPRECATED(xmpp_conn_set_string)
void xmpp_conn_set_jid(xmpp_conn_t *conn, const char *jid);
XMPP_DEPRECATED(xmpp_conn_set_string)
void xmpp_conn_set_pass(xmpp_conn_t *conn, const char *pass);
XMPP_DEPRECATED(xmpp_conn_set_string)
void xmpp_conn_set_cafile(xmpp_conn_t *const conn, const char *path);
XMPP_DEPRECATED(xmpp_conn_set_string)
void xmpp_conn_set_capath(xmpp_conn_t *const conn, const char *path);
XMPP_DEPRECATED(xmpp_conn_set_string)
void xmpp_conn_set_client_cert(xmpp_conn_t *conn,
const char *cert,
const char *key);
XMPP_DEPRECATED(xmpp_conn_set_int)
void xmpp_conn_set_password_retries(xmpp_conn_t *conn, unsigned int retries);
XMPP_DEPRECATED(xmpp_conn_set_functionpointer)
void xmpp_conn_set_password_callback(xmpp_conn_t *conn,
xmpp_password_callback cb,
void *userdata);
XMPP_DEPRECATED(xmpp_conn_set_functionpointer)
void xmpp_conn_set_certfail_handler(xmpp_conn_t *const conn,
xmpp_certfail_handler hndl);
XMPP_DEPRECATED(xmpp_conn_set_functionpointer)
void xmpp_conn_set_sockopt_callback(xmpp_conn_t *conn,
xmpp_sockopt_callback callback);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@@ -1,7 +1,6 @@
#!/bin/sh #!/bin/sh
logfile="../../testbuild.log" logfile="../../testbuild.log"
errfile="../../testerr.log"
err_out() { err_out() {
tail $logfile tail $logfile
@@ -9,6 +8,6 @@ err_out() {
} }
./bootstrap.sh ./bootstrap.sh
./configure >> $logfile 2>> $errfile || err_out ./configure >> $logfile || err_out
make -j$(( `nproc` * 2 + 1 )) >> $logfile 2>> $errfile || err_out make -j$(( `nproc` * 2 + 1 )) >> $logfile || err_out
make check >> $logfile 2>> $errfile || err_out make check >> $logfile || err_out

View File

@@ -1,166 +0,0 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* test_serialize_sm.c
** libstrophe XMPP client library -- test routines for the send queue
**
** Copyright (C) 2024 Stephen Paul Weber
**
** This software is provided AS-IS with no warranty, either express
** or implied.
**
** This program is dual licensed under the MIT or GPLv3 licenses.
*/
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include "strophe.h"
#include "common.h"
#include "test.h"
void callback(xmpp_conn_t *conn,
void *ctx,
const unsigned char *sm_state,
size_t sm_state_len)
{
int *callback_count = ctx;
(*callback_count)++;
COMPARE_BUF("\x1a\x00\x00\x00\x00", 5, sm_state, 5);
COMPARE_BUF("\x1a\x00\x00\x00\x00", 5, sm_state + 10, 5);
COMPARE_BUF("\x7a\x00\x00\x00\x04SMID", 9, sm_state + 15, 9);
if (*callback_count == 1) {
COMPARE_BUF("\x1a\x00\x00\x00\x00", 5, sm_state + 5, 5);
COMPARE_BUF("\x9a\x00\x00\x00\x02", 5, sm_state + 24, 5);
COMPARE_BUF("\x7a\x00\x00\x00\x03"
"foo",
8, sm_state + 29, 8);
COMPARE_BUF("\x7a\x00\x00\x00\x1a<r xmlns='urn:xmpp:sm:3'/>", 31,
sm_state + 37, 31);
COMPARE_BUF("\xba\x00\x00\x00\x00", 5, sm_state + 68, 5);
ENSURE_EQ(sm_state_len, 73);
xmpp_conn_t *newconn = xmpp_conn_new(conn->ctx);
xmpp_conn_restore_sm_state(newconn, sm_state, sm_state_len);
ENSURE_EQ(newconn->sm_state->sm_sent_nr, 0);
ENSURE_EQ(newconn->sm_state->sm_handled_nr, 0);
COMPARE(newconn->sm_state->id, "SMID");
ENSURE_EQ(newconn->send_queue_len, 2);
ENSURE_EQ(newconn->send_queue_user_len, 2);
ENSURE_EQ((size_t)(newconn->sm_state->sm_queue.head), 0);
xmpp_conn_release(newconn);
}
if (*callback_count == 2) {
COMPARE_BUF("\x1a\x00\x00\x00\x01", 5, sm_state + 5, 5);
COMPARE_BUF("\x9a\x00\x00\x00\x01", 5, sm_state + 24, 5);
COMPARE_BUF("\x7a\x00\x00\x00\x1a<r xmlns='urn:xmpp:sm:3'/>", 31,
sm_state + 29, 31);
COMPARE_BUF("\xba\x00\x00\x00\x01", 5, sm_state + 60, 5);
COMPARE_BUF("\x1a\x00\x00\x00\x00", 5, sm_state + 65, 5);
COMPARE_BUF("\x7a\x00\x00\x00\x03"
"foo",
8, sm_state + 70, 8);
ENSURE_EQ(sm_state_len, 78);
xmpp_conn_t *newconn = xmpp_conn_new(conn->ctx);
xmpp_conn_restore_sm_state(newconn, sm_state, sm_state_len);
ENSURE_EQ(newconn->sm_state->sm_sent_nr, 1);
ENSURE_EQ(newconn->sm_state->sm_handled_nr, 0);
COMPARE(newconn->sm_state->id, "SMID");
ENSURE_EQ(newconn->send_queue_len, 1);
ENSURE_EQ(newconn->send_queue_user_len, 1);
ENSURE_EQ(newconn->sm_state->sm_queue.head->sm_h, 0);
xmpp_conn_release(newconn);
}
if (*callback_count == 3) {
COMPARE_BUF("\x1a\x00\x00\x00\x01", 5, sm_state + 5, 5);
COMPARE_BUF("\x9a\x00\x00\x00\x00", 5, sm_state + 24, 5);
COMPARE_BUF("\xba\x00\x00\x00\x01", 5, sm_state + 29, 5);
COMPARE_BUF("\x1a\x00\x00\x00\x00", 5, sm_state + 34, 5);
COMPARE_BUF("\x7a\x00\x00\x00\x03"
"foo",
8, sm_state + 39, 8);
ENSURE_EQ(sm_state_len, 47);
xmpp_conn_t *newconn = xmpp_conn_new(conn->ctx);
xmpp_conn_restore_sm_state(newconn, sm_state, sm_state_len);
ENSURE_EQ(newconn->sm_state->sm_sent_nr, 1);
ENSURE_EQ(newconn->sm_state->sm_handled_nr, 0);
COMPARE(newconn->sm_state->id, "SMID");
ENSURE_EQ(newconn->send_queue_len, 0);
ENSURE_EQ(newconn->send_queue_user_len, 0);
ENSURE_EQ(newconn->sm_state->sm_queue.head->sm_h, 0);
xmpp_conn_release(newconn);
}
}
int fake_read(struct conn_interface *intf, void *buff, size_t len)
{
return 0;
}
int fake_write(struct conn_interface *intf, const void *buff, size_t len)
{
return len;
}
int fake_flush(struct conn_interface *intf)
{
return 0;
}
int fake_error_is_recoverable(struct conn_interface *intf, int err)
{
return 0;
}
int main()
{
xmpp_ctx_t *ctx;
xmpp_conn_t *conn;
xmpp_log_t *log;
xmpp_conn_state_t state;
xmpp_sm_state_t *sm_state;
char *ret;
unsigned int n;
int callback_count = 0;
xmpp_initialize();
log = xmpp_get_default_logger(XMPP_LEVEL_DEBUG);
ctx = xmpp_ctx_new(NULL, log);
conn = xmpp_conn_new(ctx);
sm_state = strophe_alloc(ctx, sizeof(*sm_state));
memset(sm_state, 0, sizeof(*sm_state));
sm_state->ctx = ctx;
sm_state->sm_support = sm_state->sm_enabled = sm_state->can_resume = 1;
sm_state->id = strophe_strdup(ctx, "SMID");
xmpp_conn_set_sm_state(conn, sm_state);
xmpp_conn_set_sm_callback(conn, callback, &callback_count);
ENSURE_EQ(xmpp_conn_send_queue_len(conn), 0);
struct conn_interface intf = {fake_read, fake_write,
fake_flush, fake_flush,
fake_flush, fake_error_is_recoverable,
conn};
conn->intf = intf;
state = conn->state;
conn->state = XMPP_STATE_CONNECTED;
conn->sock = 123;
xmpp_send_raw(conn, "foo", 3);
ENSURE_EQ(xmpp_conn_send_queue_len(conn), 1);
ENSURE_EQ(callback_count, 1);
xmpp_run_once(ctx, 0);
ENSURE_EQ(callback_count, 3);
conn->state = state;
xmpp_conn_release(conn);
xmpp_ctx_free(ctx);
xmpp_shutdown();
return 0;
}

View File

@@ -16,6 +16,7 @@
#include <string.h> #include <string.h>
#include <sys/param.h> #include <sys/param.h>
#define XMPP_DEPRECATED(x)
#include "strophe.h" #include "strophe.h"
#include "test.h" #include "test.h"
@@ -41,12 +42,14 @@ int main()
} client_cert[] = { } client_cert[] = {
{0, "tests/cert.pem", "tests/key.pem"}, {0, "tests/cert.pem", "tests/key.pem"},
{1, "tests/cert.pem", "tests/key_encrypted.pem"}, {1, "tests/cert.pem", "tests/key_encrypted.pem"},
{0, NULL, "tests/cert.emptypass.pfx"},
{0, NULL, "tests/cert.nopass.pfx"},
{1, NULL, "tests/cert.pfx"},
{0, "tests/cert.emptypass.pfx", NULL}, {0, "tests/cert.emptypass.pfx", NULL},
{0, "tests/cert.nopass.pfx", NULL}, {0, "tests/cert.nopass.pfx", NULL},
{1, "tests/cert.pfx", NULL}, {1, "tests/cert.pfx", NULL},
/* Backward compatibility checks for change introduced in #208
* To be removed, once xmpp_conn_set_client_cert() is gone */
{0, NULL, "tests/cert.emptypass.pfx"},
{0, NULL, "tests/cert.nopass.pfx"},
{1, NULL, "tests/cert.pfx"},
}; };
const char *srcdir; const char *srcdir;
@@ -78,9 +81,15 @@ int main()
keyfile = NULL; keyfile = NULL;
if (client_cert[m].needs_callback) if (client_cert[m].needs_callback)
xmpp_conn_set_password_callback(conn, password_callback, NULL); xmpp_conn_set_functionpointer(conn, XMPP_SETTING_PASSWORD_CALLBACK,
password_callback);
xmpp_conn_set_client_cert(conn, certfile, keyfile); if (certfile) {
xmpp_conn_set_string(conn, XMPP_SETTING_CLIENT_CERT, certfile);
xmpp_conn_set_string(conn, XMPP_SETTING_CLIENT_KEY, keyfile);
} else {
xmpp_conn_set_client_cert(conn, certfile, keyfile);
}
xmppaddr_num[0] = '0' + xmpp_conn_cert_xmppaddr_num(conn); xmppaddr_num[0] = '0' + xmpp_conn_cert_xmppaddr_num(conn);