Compare commits
9 Commits
generic-se
...
fix-compil
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dfb3e86824 | ||
|
|
a81f0a8a5f | ||
|
|
5509ec3b35 | ||
|
|
67b1a2f3f4 | ||
|
|
7c2e78937d | ||
|
|
b7bae1502f | ||
|
|
e3d734c5ff | ||
|
|
e7b08faaa7 | ||
|
|
f3fa9f557b |
17
.github/workflows/main.yml
vendored
17
.github/workflows/main.yml
vendored
@@ -10,12 +10,12 @@ on:
|
||||
|
||||
jobs:
|
||||
linux-tests:
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-24.04
|
||||
strategy:
|
||||
matrix:
|
||||
valgrind:
|
||||
- { configure: '' , make: 'check' }
|
||||
- { configure: '--enable-valgrind' , make: 'check-valgrind' }
|
||||
- { configure: '' , cflags: '', make: 'check' }
|
||||
- { configure: '--enable-valgrind' , cflags: '-O2', make: 'check-valgrind' }
|
||||
options:
|
||||
- { configure: '' }
|
||||
- { configure: '--without-libxml2' }
|
||||
@@ -35,7 +35,7 @@ jobs:
|
||||
- name: Build the library
|
||||
run: |
|
||||
./bootstrap.sh
|
||||
./configure ${{ matrix.options.configure }} ${{ matrix.valgrind.configure }} CFLAGS="-Werror -g3"
|
||||
./configure ${{ matrix.options.configure }} ${{ matrix.valgrind.configure }} CFLAGS="-Werror -g3 ${{ matrix.valgrind.cflags }}"
|
||||
make -j$(nproc)
|
||||
- name: Run tests
|
||||
run: |
|
||||
@@ -46,7 +46,7 @@ jobs:
|
||||
cat test-suite*.log || true
|
||||
|
||||
xssl-tests:
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
strategy:
|
||||
matrix:
|
||||
xssl_versions:
|
||||
@@ -135,9 +135,14 @@ jobs:
|
||||
if: ${{ !failure() }}
|
||||
run: |
|
||||
cat testbuild.log
|
||||
- name: Error logs
|
||||
if: ${{ failure() }}
|
||||
run: |
|
||||
cat testbuild.log || true
|
||||
cat testerr.log || true
|
||||
|
||||
code-style:
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-24.04
|
||||
name: Check coding style
|
||||
continue-on-error: true
|
||||
steps:
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -46,6 +46,7 @@ examples/roster
|
||||
examples/uuid
|
||||
examples/vcard
|
||||
testbuild*.log
|
||||
testerr*.log
|
||||
test-release/
|
||||
test_stamp
|
||||
test-suite*.log
|
||||
@@ -65,6 +66,7 @@ tests/test_resolver
|
||||
tests/test_sasl
|
||||
tests/test_scram
|
||||
tests/test_send_queue
|
||||
tests/test_serialize_sm
|
||||
tests/test_sha1
|
||||
tests/test_sha256
|
||||
tests/test_sha512
|
||||
|
||||
10
ChangeLog
10
ChangeLog
@@ -1,3 +1,13 @@
|
||||
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
|
||||
- Fix SCRAM-*-PLUS SASL mechanisms with OpenSSL and TLS < v1.3 (40f2452)
|
||||
- Only signal "stream negotiation success" once (1cf09b1)
|
||||
|
||||
2
Doxyfile
2
Doxyfile
@@ -38,7 +38,7 @@ PROJECT_NAME = Strophe
|
||||
# could be handy for archiving the generated documentation or if some version
|
||||
# control system is used.
|
||||
|
||||
PROJECT_NUMBER = 0.13
|
||||
PROJECT_NUMBER = 0.14
|
||||
|
||||
# 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
|
||||
|
||||
@@ -190,6 +190,7 @@ STATIC_TESTS = \
|
||||
tests/test_jid \
|
||||
tests/test_ctx \
|
||||
tests/test_send_queue \
|
||||
tests/test_serialize_sm \
|
||||
tests/test_string \
|
||||
tests/test_resolver
|
||||
|
||||
@@ -285,6 +286,11 @@ tests_test_send_queue_CFLAGS = -I$(top_srcdir)/src
|
||||
tests_test_send_queue_LDADD = $(STROPHE_LIBS)
|
||||
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_CFLAGS = -I$(top_srcdir)/src
|
||||
|
||||
@@ -327,6 +333,7 @@ dist-archives:
|
||||
|
||||
test-release: dist
|
||||
@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 && \
|
||||
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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
m4_define([v_maj], [0])
|
||||
m4_define([v_min], [13])
|
||||
m4_define([v_patch], [1])
|
||||
m4_define([v_min], [14])
|
||||
m4_define([v_patch], [0])
|
||||
m4_define([project_version], [v_maj.v_min.v_patch])
|
||||
|
||||
m4_define([lt_cur], m4_eval(v_maj + v_min))
|
||||
@@ -18,9 +18,10 @@ PKG_PROG_PKG_CONFIG
|
||||
|
||||
AC_CANONICAL_HOST
|
||||
AS_CASE([$host_os],
|
||||
[dragonfly*], [PLATFORM="bsd"],
|
||||
[freebsd*], [PLATFORM="bsd"],
|
||||
[openbsd*], [PLATFORM="bsd"],
|
||||
[netbsd*], [PLATFORM="bsd"],
|
||||
[openbsd*], [PLATFORM="bsd"],
|
||||
[*nto*|*qnx*], [PLATFORM="qnx"],
|
||||
[*solaris*], [PLATFORM="solaris"],
|
||||
[*android*], [PLATFORM="android"],
|
||||
|
||||
@@ -115,8 +115,8 @@ int main(int argc, char **argv)
|
||||
*/
|
||||
|
||||
/* setup authentication information */
|
||||
xmpp_conn_set_string(conn, XMPP_SETTING_JID, argv[1]);
|
||||
xmpp_conn_set_string(conn, XMPP_SETTING_PASS, argv[2]);
|
||||
xmpp_conn_set_jid(conn, argv[1]);
|
||||
xmpp_conn_set_pass(conn, argv[2]);
|
||||
|
||||
/* initiate connection */
|
||||
xmpp_connect_client(conn, NULL, 0, conn_handler, ctx);
|
||||
|
||||
@@ -116,9 +116,9 @@ int main(int argc, char **argv)
|
||||
|
||||
/* setup authentication information */
|
||||
if (jid)
|
||||
xmpp_conn_set_string(conn, XMPP_SETTING_JID, jid);
|
||||
xmpp_conn_set_jid(conn, jid);
|
||||
if (password)
|
||||
xmpp_conn_set_string(conn, XMPP_SETTING_PASS, password);
|
||||
xmpp_conn_set_pass(conn, password);
|
||||
|
||||
/* initiate connection */
|
||||
if (xmpp_connect_client(conn, host, port, conn_handler, ctx) == XMPP_EOK) {
|
||||
|
||||
@@ -293,24 +293,20 @@ create_connection:
|
||||
xmpp_conn_set_flags(conn, flags);
|
||||
|
||||
/* ask for a password if key is protected */
|
||||
xmpp_conn_set_functionpointer(conn, XMPP_SETTING_PASSWORD_CALLBACK,
|
||||
password_callback);
|
||||
xmpp_conn_set_password_callback(conn, password_callback, NULL);
|
||||
/* try at max 3 times in case the user enters the password wrong */
|
||||
xmpp_conn_set_int(conn, XMPP_SETTING_PASSWORD_RETRIES, 3);
|
||||
xmpp_conn_set_password_retries(conn, 3);
|
||||
/* setup authentication information */
|
||||
if (key) {
|
||||
xmpp_conn_set_string(conn, XMPP_SETTING_CLIENT_CERT, cert);
|
||||
xmpp_conn_set_string(conn, XMPP_SETTING_CLIENT_KEY, key);
|
||||
}
|
||||
if (key)
|
||||
xmpp_conn_set_client_cert(conn, cert, key);
|
||||
if (jid)
|
||||
xmpp_conn_set_string(conn, XMPP_SETTING_JID, jid);
|
||||
xmpp_conn_set_jid(conn, jid);
|
||||
if (password)
|
||||
xmpp_conn_set_string(conn, XMPP_SETTING_PASS, password);
|
||||
xmpp_conn_set_pass(conn, password);
|
||||
|
||||
/* enable TCP keepalive, using canned callback function */
|
||||
if (tcp_keepalive)
|
||||
xmpp_conn_set_functionpointer(conn, XMPP_SETTING_SOCKOPT_CALLBACK,
|
||||
xmpp_sockopt_cb_keepalive);
|
||||
xmpp_conn_set_sockopt_callback(conn, xmpp_sockopt_cb_keepalive);
|
||||
|
||||
/* set Stream-Mangement state if available */
|
||||
if (sm_state) {
|
||||
|
||||
@@ -331,31 +331,27 @@ int main(int argc, char **argv)
|
||||
xmpp_conn_set_flags(conn, flags);
|
||||
/* configure TCP keepalive (optional) */
|
||||
if (tcp_keepalive)
|
||||
xmpp_conn_set_functionpointer(conn, XMPP_SETTING_SOCKOPT_CALLBACK,
|
||||
sockopt_cb);
|
||||
xmpp_conn_set_sockopt_callback(conn, sockopt_cb);
|
||||
|
||||
/* ask for a password if key is protected */
|
||||
xmpp_conn_set_functionpointer(conn, XMPP_SETTING_PASSWORD_CALLBACK,
|
||||
password_callback);
|
||||
xmpp_conn_set_password_callback(conn, password_callback, NULL);
|
||||
/* try at max 3 times in case the user enters the password wrong */
|
||||
xmpp_conn_set_int(conn, XMPP_SETTING_PASSWORD_RETRIES, 3);
|
||||
xmpp_conn_set_password_retries(conn, 3);
|
||||
/* setup authentication information */
|
||||
if (key) {
|
||||
xmpp_conn_set_string(conn, XMPP_SETTING_CLIENT_CERT, cert);
|
||||
xmpp_conn_set_string(conn, XMPP_SETTING_CLIENT_KEY, key);
|
||||
xmpp_conn_set_client_cert(conn, cert, key);
|
||||
}
|
||||
if (jid)
|
||||
xmpp_conn_set_string(conn, XMPP_SETTING_JID, jid);
|
||||
xmpp_conn_set_jid(conn, jid);
|
||||
if (password)
|
||||
xmpp_conn_set_string(conn, XMPP_SETTING_PASS, password);
|
||||
xmpp_conn_set_pass(conn, password);
|
||||
|
||||
if (certfail)
|
||||
xmpp_conn_set_functionpointer(conn, XMPP_SETTING_CERTFAIL_HANDLER,
|
||||
certfail_handler);
|
||||
xmpp_conn_set_certfail_handler(conn, certfail_handler);
|
||||
if (capath)
|
||||
xmpp_conn_set_string(conn, XMPP_SETTING_CAPATH, capath);
|
||||
xmpp_conn_set_capath(conn, capath);
|
||||
if (cafile)
|
||||
xmpp_conn_set_string(conn, XMPP_SETTING_CAFILE, cafile);
|
||||
xmpp_conn_set_cafile(conn, cafile);
|
||||
|
||||
/* initiate connection */
|
||||
if (xmpp_connect_client(conn, host, port, conn_handler, ctx) == XMPP_EOK) {
|
||||
|
||||
@@ -80,8 +80,8 @@ int main(int argc, char **argv)
|
||||
conn = xmpp_conn_new(ctx);
|
||||
|
||||
/* setup authentication information */
|
||||
xmpp_conn_set_string(conn, XMPP_SETTING_JID, jid);
|
||||
xmpp_conn_set_string(conn, XMPP_SETTING_PASS, pass);
|
||||
xmpp_conn_set_jid(conn, jid);
|
||||
xmpp_conn_set_pass(conn, pass);
|
||||
|
||||
/* initiate connection */
|
||||
xmpp_connect_component(conn, host, port, conn_handler, ctx);
|
||||
|
||||
@@ -342,7 +342,7 @@ int main(int argc, char **argv)
|
||||
|
||||
/* jid can be a jid or domain for "raw" connection */
|
||||
domain = xmpp_jid_domain(ctx, jid);
|
||||
xmpp_conn_set_string(conn, XMPP_SETTING_JID, domain);
|
||||
xmpp_conn_set_jid(conn, domain);
|
||||
xmpp_free(ctx, domain);
|
||||
|
||||
/* private data */
|
||||
|
||||
@@ -118,8 +118,8 @@ int main(int argc, char **argv)
|
||||
*/
|
||||
|
||||
/* setup authentication information */
|
||||
xmpp_conn_set_string(conn, XMPP_SETTING_JID, argv[1]);
|
||||
xmpp_conn_set_string(conn, XMPP_SETTING_PASS, argv[2]);
|
||||
xmpp_conn_set_jid(conn, argv[1]);
|
||||
xmpp_conn_set_pass(conn, argv[2]);
|
||||
|
||||
/* initiate connection */
|
||||
xmpp_connect_client(conn, NULL, 0, conn_handler, ctx);
|
||||
|
||||
@@ -269,8 +269,8 @@ int main(int argc, char **argv)
|
||||
log = xmpp_get_default_logger(XMPP_LEVEL_INFO);
|
||||
ctx = xmpp_ctx_new(NULL, log);
|
||||
conn = xmpp_conn_new(ctx);
|
||||
xmpp_conn_set_string(conn, XMPP_SETTING_JID, jid);
|
||||
xmpp_conn_set_string(conn, XMPP_SETTING_PASS, pass);
|
||||
xmpp_conn_set_jid(conn, jid);
|
||||
xmpp_conn_set_pass(conn, pass);
|
||||
vcard.ctx = ctx;
|
||||
xmpp_connect_client(conn, NULL, 0, conn_handler, &vcard);
|
||||
xmpp_run(ctx);
|
||||
|
||||
@@ -1232,6 +1232,7 @@ static void _sm_enable(xmpp_conn_t *conn)
|
||||
send_stanza(conn, enable, XMPP_QUEUE_SM_STROPHE);
|
||||
conn->sm_state->sm_sent_nr = 0;
|
||||
conn->sm_state->sm_enabled = 1;
|
||||
trigger_sm_callback(conn);
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -1486,6 +1487,8 @@ static int _handle_sm(xmpp_conn_t *const conn,
|
||||
name = NULL;
|
||||
}
|
||||
|
||||
trigger_sm_callback(conn);
|
||||
|
||||
err_sm:
|
||||
if (!name) {
|
||||
char *err = "Couldn't convert stanza to text!";
|
||||
|
||||
13
src/common.h
13
src/common.h
@@ -30,12 +30,17 @@
|
||||
#include "snprintf.h"
|
||||
|
||||
/** 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;
|
||||
struct _xmpp_handlist_t {
|
||||
/* common members */
|
||||
int user_handler;
|
||||
int (*handler)();
|
||||
xmpp_void_handler handler;
|
||||
void *userdata;
|
||||
int enabled; /* handlers are added disabled and enabled after the
|
||||
* handler chain is processed to prevent stanzas from
|
||||
@@ -280,8 +285,7 @@ struct _xmpp_conn_t {
|
||||
|
||||
struct {
|
||||
struct xmpp_compression *state;
|
||||
int allowed, dont_reset, level;
|
||||
int supported;
|
||||
int allowed, supported, dont_reset;
|
||||
} compression;
|
||||
|
||||
char *lang;
|
||||
@@ -324,6 +328,8 @@ struct _xmpp_conn_t {
|
||||
hash_t *id_handlers;
|
||||
xmpp_handlist_t *handlers;
|
||||
xmpp_sockopt_callback sockopt_cb;
|
||||
xmpp_sm_callback sm_callback;
|
||||
void *sm_callback_ctx;
|
||||
};
|
||||
|
||||
void conn_disconnect(xmpp_conn_t *conn);
|
||||
@@ -377,6 +383,7 @@ void handler_add(xmpp_conn_t *conn,
|
||||
void handler_system_delete_all(xmpp_conn_t *conn);
|
||||
|
||||
/* utility functions */
|
||||
void trigger_sm_callback(xmpp_conn_t *conn);
|
||||
void reset_sm_state(xmpp_sm_state_t *sm_state);
|
||||
void disconnect_mem_error(xmpp_conn_t *conn);
|
||||
|
||||
|
||||
@@ -227,7 +227,7 @@ int compression_init(xmpp_conn_t *conn)
|
||||
|
||||
comp->compression.stream.next_out = comp->compression.buffer;
|
||||
comp->compression.stream.avail_out = STROPHE_COMPRESSION_BUFFER_SIZE;
|
||||
int ret = deflateInit(&comp->compression.stream, conn->compression.level);
|
||||
int ret = deflateInit(&comp->compression.stream, Z_DEFAULT_COMPRESSION);
|
||||
if (ret != Z_OK) {
|
||||
strophe_free_and_null(conn->ctx, comp->compression.buffer);
|
||||
conn->error = ret;
|
||||
|
||||
754
src/conn.c
754
src/conn.c
@@ -21,6 +21,7 @@
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <netinet/in.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
@@ -167,8 +168,6 @@ xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t *ctx)
|
||||
tls_clear_password_cache(conn);
|
||||
conn->password_retries = 1;
|
||||
|
||||
conn->compression.level = -1;
|
||||
|
||||
conn->parser =
|
||||
parser_new(conn->ctx, _handle_stream_start, _handle_stream_end,
|
||||
_handle_stream_stanza, conn);
|
||||
@@ -219,6 +218,32 @@ xmpp_conn_t *xmpp_conn_clone(xmpp_conn_t *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.
|
||||
* Decrement the reference count by one for a connection, freeing the
|
||||
* connection object if the count reaches 0.
|
||||
@@ -342,204 +367,6 @@ int xmpp_conn_release(xmpp_conn_t *conn)
|
||||
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.
|
||||
*
|
||||
* @param conn a Strophe connection object
|
||||
@@ -571,6 +398,66 @@ const char *xmpp_conn_get_bound_jid(const xmpp_conn_t *conn)
|
||||
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
|
||||
*
|
||||
* The returned Certificate object must be free'd by calling
|
||||
@@ -587,6 +474,41 @@ xmpp_tlscert_t *xmpp_conn_get_peer_cert(xmpp_conn_t *const 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.
|
||||
*
|
||||
* This makes usually sense to be called from the
|
||||
@@ -603,6 +525,49 @@ const char *xmpp_conn_get_keyfile(const xmpp_conn_t *conn)
|
||||
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.
|
||||
*
|
||||
* @param conn a Strophe connection object
|
||||
@@ -643,6 +608,22 @@ const char *xmpp_conn_get_pass(const xmpp_conn_t *conn)
|
||||
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.
|
||||
* @param conn a Strophe connection object
|
||||
*
|
||||
@@ -1274,36 +1255,336 @@ int xmpp_conn_is_disconnected(xmpp_conn_t *conn)
|
||||
}
|
||||
|
||||
/**
|
||||
* This returns the Stream Management state of a connection object after
|
||||
* it has been disconnected.
|
||||
* One can then initialise a fresh connection object and set this Stream
|
||||
* Management state by calling \ref xmpp_conn_set_sm_state
|
||||
* This sets the Stream Management callback function
|
||||
*
|
||||
* In case one wants to dispose of the state w/o setting it into a fresh
|
||||
* connection object, one can call \ref xmpp_free_sm_state
|
||||
* After setting this API, the library will call the given callback function
|
||||
* each time when the internal SM state is updated.
|
||||
*
|
||||
* After calling this function to retrieve the state, only call one of the
|
||||
* other two.
|
||||
* 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
|
||||
* @return The Stream Management state of the connection or NULL on error
|
||||
* @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
|
||||
*/
|
||||
xmpp_sm_state_t *xmpp_conn_get_sm_state(xmpp_conn_t *conn)
|
||||
void xmpp_conn_set_sm_callback(xmpp_conn_t *conn,
|
||||
xmpp_sm_callback cb,
|
||||
void *ctx)
|
||||
{
|
||||
xmpp_sm_state_t *ret;
|
||||
conn->sm_callback = cb;
|
||||
conn->sm_callback_ctx = ctx;
|
||||
}
|
||||
|
||||
/* We can only return the SM state when we're disconnected */
|
||||
if (conn->state != XMPP_STATE_DISCONNECTED)
|
||||
return NULL;
|
||||
struct sm_restore {
|
||||
xmpp_conn_t *conn;
|
||||
const unsigned char *state;
|
||||
const unsigned char *const state_end, *const orig;
|
||||
};
|
||||
|
||||
ret = conn->sm_state;
|
||||
conn->sm_state = NULL;
|
||||
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;
|
||||
@@ -1332,6 +1613,37 @@ static void _reset_sm_state_for_reconnect(xmpp_conn_t *conn)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This returns the Stream Management state of a connection object after
|
||||
* it has been disconnected.
|
||||
* One can then initialise a fresh connection object and set this Stream
|
||||
* Management state by calling \ref xmpp_conn_set_sm_state
|
||||
*
|
||||
* In case one wants to dispose of the state w/o setting it into a fresh
|
||||
* connection object, one can call \ref xmpp_free_sm_state
|
||||
*
|
||||
* After calling this function to retrieve the state, only call one of the
|
||||
* other two.
|
||||
*
|
||||
* @param conn a Strophe connection object
|
||||
* @return The Stream Management state of the connection or NULL on error
|
||||
*
|
||||
* @ingroup Connections
|
||||
*/
|
||||
xmpp_sm_state_t *xmpp_conn_get_sm_state(xmpp_conn_t *conn)
|
||||
{
|
||||
xmpp_sm_state_t *ret;
|
||||
|
||||
/* We can only return the SM state when we're disconnected */
|
||||
if (conn->state != XMPP_STATE_DISCONNECTED)
|
||||
return NULL;
|
||||
|
||||
ret = conn->sm_state;
|
||||
conn->sm_state = NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param conn a Strophe connection object
|
||||
* @param sm_state A Stream Management state returned from a call to
|
||||
@@ -1510,7 +1822,9 @@ char *xmpp_conn_send_queue_drop_element(xmpp_conn_t *conn,
|
||||
conn->sm_state->r_sent = 0;
|
||||
}
|
||||
/* Finally drop the element */
|
||||
return _drop_send_queue_element(conn, t);
|
||||
char *r = _drop_send_queue_element(conn, t);
|
||||
trigger_sm_callback(conn);
|
||||
return r;
|
||||
}
|
||||
|
||||
/* timed handler for cleanup if normal disconnect procedure takes too long */
|
||||
@@ -1704,6 +2018,7 @@ static void _handle_stream_end(char *name, void *userdata)
|
||||
strophe_debug(conn->ctx, "xmpp", "RECV: </stream:stream>");
|
||||
/* the session has been terminated properly, i.e. it can't be resumed */
|
||||
conn->sm_state->can_resume = 0;
|
||||
trigger_sm_callback(conn);
|
||||
conn_disconnect_clean(conn);
|
||||
}
|
||||
|
||||
@@ -1779,6 +2094,7 @@ static void _conn_sm_handle_stanza(xmpp_conn_t *const conn,
|
||||
conn->sm_state->r_sent = 0;
|
||||
}
|
||||
}
|
||||
trigger_sm_callback(conn);
|
||||
}
|
||||
|
||||
static unsigned short _conn_default_port(xmpp_conn_t *conn,
|
||||
@@ -2065,8 +2381,10 @@ static int _send_raw(xmpp_conn_t *conn,
|
||||
strophe_debug_verbose(1, conn->ctx, "conn", "Q_ADD: %p", item);
|
||||
if (!(owner & XMPP_QUEUE_SM) && conn->sm_state->sm_enabled &&
|
||||
!conn->sm_state->r_sent) {
|
||||
send_raw(conn, req_ack, strlen(req_ack), XMPP_QUEUE_SM_STROPHE, item);
|
||||
conn->sm_state->r_sent = 1;
|
||||
send_raw(conn, req_ack, strlen(req_ack), XMPP_QUEUE_SM_STROPHE, item);
|
||||
} else {
|
||||
trigger_sm_callback(conn);
|
||||
}
|
||||
return XMPP_EOK;
|
||||
}
|
||||
|
||||
185
src/deprecated.c
185
src/deprecated.c
@@ -19,7 +19,6 @@
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include <limits.h>
|
||||
|
||||
/** Allocate memory in a Strophe context.
|
||||
* All Strophe functions will use this to allocate memory.
|
||||
@@ -87,10 +86,6 @@ char *xmpp_strndup(const xmpp_ctx_t *ctx, const char *s, size_t len)
|
||||
return strophe_strndup(ctx, s, len);
|
||||
}
|
||||
|
||||
/** Write to the log.
|
||||
*
|
||||
* @ingroup Deprecated
|
||||
*/
|
||||
void xmpp_log(const xmpp_ctx_t *ctx,
|
||||
xmpp_log_level_t level,
|
||||
const char *area,
|
||||
@@ -222,10 +217,6 @@ char *xmpp_strtok_r(char *s, const char *delim, char **saveptr)
|
||||
return strophe_strtok_r(s, delim, saveptr);
|
||||
}
|
||||
|
||||
/** snprintf(3) implementation.
|
||||
*
|
||||
* @ingroup Deprecated
|
||||
*/
|
||||
int xmpp_snprintf(char *str, size_t count, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
@@ -237,184 +228,11 @@ int xmpp_snprintf(char *str, size_t count, const char *fmt, ...)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** vsnprintf(3) implementation.
|
||||
*
|
||||
* @ingroup Deprecated
|
||||
*/
|
||||
int xmpp_vsnprintf(char *str, size_t count, const char *fmt, va_list 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
|
||||
* Turn on TCP keepalive and set timeout and interval. Zero timeout
|
||||
* disables TCP keepalives. The parameters are applied immediately for
|
||||
@@ -435,8 +253,7 @@ void xmpp_conn_set_keepalive(xmpp_conn_t *conn, int timeout, int interval)
|
||||
conn->ka_timeout = timeout;
|
||||
conn->ka_interval = interval;
|
||||
conn->ka_count = 0;
|
||||
xmpp_conn_set_functionpointer(conn, XMPP_SETTING_SOCKOPT_CALLBACK,
|
||||
xmpp_sockopt_cb_keepalive);
|
||||
xmpp_conn_set_sockopt_callback(conn, xmpp_sockopt_cb_keepalive);
|
||||
}
|
||||
|
||||
/** Disable TLS for this connection, called by users of the library.
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
#include <sys/select.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#define _sleep(x) usleep((x)*1000)
|
||||
#define _sleep(x) usleep((x) * 1000)
|
||||
#else
|
||||
#include <winsock2.h>
|
||||
#ifndef ETIMEDOUT
|
||||
@@ -174,6 +174,7 @@ void xmpp_run_once(xmpp_ctx_t *ctx, unsigned long timeout)
|
||||
/* if we've sent everything update the tail */
|
||||
if (!sq)
|
||||
conn->send_queue_tail = NULL;
|
||||
trigger_sm_callback(conn);
|
||||
}
|
||||
intf->flush(intf);
|
||||
|
||||
|
||||
@@ -25,8 +25,6 @@
|
||||
#include "common.h"
|
||||
#include "ostypes.h"
|
||||
|
||||
typedef int (*xmpp_void_handler)();
|
||||
|
||||
/* Remove item from the list pointed by head, but don't free it.
|
||||
* There can be a situation when user's handler deletes another handler which
|
||||
* is the previous in the list. handler_fire_stanza() and handler_fire_timed()
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
|
||||
#define PUT_32BIT_LSB_FIRST(cp, value) \
|
||||
do { \
|
||||
(cp)[0] = (value)&0xFF; \
|
||||
(cp)[0] = (value) & 0xFF; \
|
||||
(cp)[1] = ((value) >> 8) & 0xFF; \
|
||||
(cp)[2] = ((value) >> 16) & 0xFF; \
|
||||
(cp)[3] = ((value) >> 24) & 0xFF; \
|
||||
|
||||
@@ -68,9 +68,9 @@ struct _xmpp_rand_t {
|
||||
};
|
||||
|
||||
/* 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 */
|
||||
#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
|
||||
* result in the first one.
|
||||
|
||||
@@ -630,7 +630,7 @@ static void netbuf_add_16bitnum(unsigned char *buf,
|
||||
|
||||
/* assuming big endian */
|
||||
*p++ = (num >> 8) & 0xff;
|
||||
*p++ = (num)&0xff;
|
||||
*p++ = (num) & 0xff;
|
||||
|
||||
*offset += 2;
|
||||
}
|
||||
|
||||
16
src/sha.h
16
src/sha.h
@@ -53,7 +53,7 @@ extern "C" {
|
||||
(y)[0] = (uint8_t)(((x) >> 24) & 255); \
|
||||
(y)[1] = (uint8_t)(((x) >> 16) & 255); \
|
||||
(y)[2] = (uint8_t)(((x) >> 8) & 255); \
|
||||
(y)[3] = (uint8_t)((x)&255); \
|
||||
(y)[3] = (uint8_t)((x) & 255); \
|
||||
} while (0)
|
||||
|
||||
#define LOAD32H(x, y) \
|
||||
@@ -72,7 +72,7 @@ extern "C" {
|
||||
(y)[4] = (uint8_t)(((x) >> 24) & 255); \
|
||||
(y)[5] = (uint8_t)(((x) >> 16) & 255); \
|
||||
(y)[6] = (uint8_t)(((x) >> 8) & 255); \
|
||||
(y)[7] = (uint8_t)((x)&255); \
|
||||
(y)[7] = (uint8_t)((x) & 255); \
|
||||
} while (0)
|
||||
|
||||
#define LOAD64H(x, y) \
|
||||
@@ -96,13 +96,13 @@ extern "C" {
|
||||
#define CONST64(n) n##ULL
|
||||
#endif
|
||||
|
||||
#define RORc(x, y) \
|
||||
(((((uint32_t)(x)&0xFFFFFFFFUL) >> (uint32_t)((y)&31)) | \
|
||||
((uint32_t)(x) << (uint32_t)((32 - ((y)&31)) & 31))) & \
|
||||
#define RORc(x, y) \
|
||||
(((((uint32_t)(x) & 0xFFFFFFFFUL) >> (uint32_t)((y) & 31)) | \
|
||||
((uint32_t)(x) << (uint32_t)((32 - ((y) & 31)) & 31))) & \
|
||||
0xFFFFFFFFUL)
|
||||
#define ROR64c(x, y) \
|
||||
(((((x)&CONST64(0xFFFFFFFFFFFFFFFF)) >> ((uint64_t)(y)&CONST64(63))) | \
|
||||
((x) << (((uint64_t)64 - ((y)&63)) & 63))) & \
|
||||
#define ROR64c(x, y) \
|
||||
(((((x) & CONST64(0xFFFFFFFFFFFFFFFF)) >> ((uint64_t)(y) & CONST64(63))) | \
|
||||
((x) << (((uint64_t)64 - ((y) & 63)) & 63))) & \
|
||||
CONST64(0xFFFFFFFFFFFFFFFF))
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#define Ch(x, y, z) (z ^ (x & (y ^ z)))
|
||||
#define Maj(x, y, z) (((x | y) & z) | (x & y))
|
||||
#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 Sigma1(x) (S(x, 6) ^ S(x, 11) ^ S(x, 25))
|
||||
#define Gamma0(x) (S(x, 7) ^ S(x, 18) ^ R(x, 3))
|
||||
|
||||
@@ -52,7 +52,7 @@ static const uint64_t K[80] = {
|
||||
#define Ch(x, y, z) (z ^ (x & (y ^ z)))
|
||||
#define Maj(x, y, z) (((x | y) & z) | (x & y))
|
||||
#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 Sigma1(x) (S(x, 14) ^ S(x, 18) ^ S(x, 41))
|
||||
#define Gamma0(x) (S(x, 1) ^ S(x, 8) ^ R(x, 7))
|
||||
|
||||
126
strophe.h
126
strophe.h
@@ -18,6 +18,7 @@
|
||||
#define __LIBSTROPHE_STROPHE_H__
|
||||
|
||||
#include <stddef.h> /* size_t */
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -371,70 +372,37 @@ typedef int (*xmpp_sockopt_callback)(xmpp_conn_t *conn, void *sock);
|
||||
/* an example callback that sets basic keepalive parameters */
|
||||
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_clone(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);
|
||||
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_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);
|
||||
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);
|
||||
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);
|
||||
char *xmpp_conn_cert_xmppaddr(xmpp_conn_t *conn, unsigned int n);
|
||||
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);
|
||||
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_connected(xmpp_conn_t *conn);
|
||||
int xmpp_conn_is_disconnected(xmpp_conn_t *conn);
|
||||
@@ -447,8 +415,38 @@ typedef enum {
|
||||
char *xmpp_conn_send_queue_drop_element(xmpp_conn_t *conn,
|
||||
xmpp_queue_element_t which);
|
||||
|
||||
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);
|
||||
xmpp_sm_state_t *xmpp_conn_get_sm_state(xmpp_conn_t *conn);
|
||||
|
||||
/** 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);
|
||||
|
||||
@@ -478,7 +476,6 @@ int xmpp_conn_tls_start(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_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(xmpp_conn_t *conn, const char *data, size_t len);
|
||||
@@ -746,7 +743,6 @@ void xmpp_rand_nonce(xmpp_rand_t *rand, char *output, size_t len);
|
||||
* deprecation */
|
||||
#include <stdarg.h>
|
||||
|
||||
#if !defined(XMPP_DEPRECATED)
|
||||
/**
|
||||
* XMPP_DEPRECATED(x) macro to show a compiler warning for deprecated API
|
||||
* functions
|
||||
@@ -765,7 +761,6 @@ void xmpp_rand_nonce(xmpp_rand_t *rand, char *output, size_t len);
|
||||
#else
|
||||
#define XMPP_DEPRECATED(x)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
XMPP_DEPRECATED(internal) void *xmpp_alloc(const xmpp_ctx_t *ctx, size_t size);
|
||||
XMPP_DEPRECATED(internal)
|
||||
@@ -805,31 +800,6 @@ void xmpp_conn_set_keepalive(xmpp_conn_t *conn, int timeout, int interval);
|
||||
XMPP_DEPRECATED(xmpp_conn_set_flags)
|
||||
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
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
logfile="../../testbuild.log"
|
||||
errfile="../../testerr.log"
|
||||
|
||||
err_out() {
|
||||
tail $logfile
|
||||
@@ -8,6 +9,6 @@ err_out() {
|
||||
}
|
||||
|
||||
./bootstrap.sh
|
||||
./configure >> $logfile || err_out
|
||||
make -j$(( `nproc` * 2 + 1 )) >> $logfile || err_out
|
||||
make check >> $logfile || err_out
|
||||
./configure >> $logfile 2>> $errfile || err_out
|
||||
make -j$(( `nproc` * 2 + 1 )) >> $logfile 2>> $errfile || err_out
|
||||
make check >> $logfile 2>> $errfile || err_out
|
||||
|
||||
166
tests/test_serialize_sm.c
Normal file
166
tests/test_serialize_sm.c
Normal file
@@ -0,0 +1,166 @@
|
||||
/* 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;
|
||||
}
|
||||
@@ -16,7 +16,6 @@
|
||||
#include <string.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
#define XMPP_DEPRECATED(x)
|
||||
#include "strophe.h"
|
||||
|
||||
#include "test.h"
|
||||
@@ -42,14 +41,12 @@ int main()
|
||||
} client_cert[] = {
|
||||
{0, "tests/cert.pem", "tests/key.pem"},
|
||||
{1, "tests/cert.pem", "tests/key_encrypted.pem"},
|
||||
{0, "tests/cert.emptypass.pfx", NULL},
|
||||
{0, "tests/cert.nopass.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"},
|
||||
{0, "tests/cert.emptypass.pfx", NULL},
|
||||
{0, "tests/cert.nopass.pfx", NULL},
|
||||
{1, "tests/cert.pfx", NULL},
|
||||
};
|
||||
|
||||
const char *srcdir;
|
||||
@@ -81,15 +78,9 @@ int main()
|
||||
keyfile = NULL;
|
||||
|
||||
if (client_cert[m].needs_callback)
|
||||
xmpp_conn_set_functionpointer(conn, XMPP_SETTING_PASSWORD_CALLBACK,
|
||||
password_callback);
|
||||
xmpp_conn_set_password_callback(conn, password_callback, NULL);
|
||||
|
||||
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);
|
||||
}
|
||||
xmpp_conn_set_client_cert(conn, certfile, keyfile);
|
||||
|
||||
xmppaddr_num[0] = '0' + xmpp_conn_cert_xmppaddr_num(conn);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user