mirror of
https://github.com/strophe/libstrophe.git
synced 2026-08-05 03:16:21 +00:00
Compare commits
36 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
60b3b91698 | ||
|
|
89922116f8 | ||
|
|
4b40c30e7f | ||
|
|
090b10caa4 | ||
|
|
aab9cdd406 | ||
|
|
d38ecd5453 | ||
|
|
b7a30589d3 | ||
|
|
0dc045af35 | ||
|
|
b9eead3b90 | ||
|
|
979724b326 | ||
|
|
e869c1d26f | ||
|
|
79066d797b | ||
|
|
f8cda0f65c | ||
|
|
649a3b4fca | ||
|
|
a2b3b6b9e2 | ||
|
|
dfb3e86824 | ||
|
|
a81f0a8a5f | ||
|
|
5509ec3b35 | ||
|
|
67b1a2f3f4 | ||
|
|
7c2e78937d | ||
|
|
b7bae1502f | ||
|
|
e3d734c5ff | ||
|
|
e7b08faaa7 | ||
|
|
f3fa9f557b | ||
|
|
5690c4ed89 | ||
|
|
62953e9ecf | ||
|
|
5142eea2eb | ||
|
|
5dd9e4b0e0 | ||
|
|
4ec4f09b35 | ||
|
|
e24819a405 | ||
|
|
d0d1fa9835 | ||
|
|
da1229814c | ||
|
|
d82df1273c | ||
|
|
9fef4b7d02 | ||
|
|
4359536a17 | ||
|
|
03d43132bc |
@@ -1,3 +1,12 @@
|
|||||||
|
---
|
||||||
|
name: Bug report
|
||||||
|
about: Create a bug report
|
||||||
|
title: ''
|
||||||
|
labels: bug
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
|
|
||||||
Provide a general summary of the issue in the Title above
|
Provide a general summary of the issue in the Title above
|
||||||
59
.github/workflows/main.yml
vendored
59
.github/workflows/main.yml
vendored
@@ -8,14 +8,18 @@ on:
|
|||||||
pull_request:
|
pull_request:
|
||||||
branches: [master]
|
branches: [master]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
linux-tests:
|
linux-tests:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-24.04
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
valgrind:
|
valgrind:
|
||||||
- { configure: '' , make: 'check' }
|
- { configure: '' , cflags: '', make: 'check' }
|
||||||
- { configure: '--enable-valgrind' , make: 'check-valgrind' }
|
- { configure: '--enable-valgrind' , cflags: '-O2', make: 'check-valgrind' }
|
||||||
options:
|
options:
|
||||||
- { configure: '' }
|
- { configure: '' }
|
||||||
- { configure: '--without-libxml2' }
|
- { configure: '--without-libxml2' }
|
||||||
@@ -35,7 +39,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"
|
./configure ${{ matrix.options.configure }} ${{ matrix.valgrind.configure }} CFLAGS="-Werror -g3 ${{ matrix.valgrind.cflags }}"
|
||||||
make -j$(nproc)
|
make -j$(nproc)
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: |
|
run: |
|
||||||
@@ -46,13 +50,18 @@ jobs:
|
|||||||
cat test-suite*.log || true
|
cat test-suite*.log || true
|
||||||
|
|
||||||
xssl-tests:
|
xssl-tests:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-24.04
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
xssl_versions:
|
xssl_versions:
|
||||||
- { version: "master", continue: true, libressl: true }
|
- { version: "master", continue: true, libressl: true }
|
||||||
|
- { version: "OPENBSD_7_8", continue: true, libressl: true }
|
||||||
|
- { version: "v4.2.1", continue: true, libressl: true }
|
||||||
|
- { version: "OPENBSD_7_7", continue: true, libressl: true }
|
||||||
|
- { version: "v4.1.2", continue: true, libressl: true }
|
||||||
|
- { version: "OPENBSD_7_6", continue: true, libressl: true }
|
||||||
|
- { version: "OPENBSD_7_5", continue: true, libressl: true }
|
||||||
- { version: "OPENBSD_7_4", continue: true, libressl: true }
|
- { version: "OPENBSD_7_4", continue: true, libressl: true }
|
||||||
- { version: "v3.8.1", continue: true, libressl: true }
|
|
||||||
- { version: "OPENBSD_7_3", continue: true, libressl: true }
|
- { version: "OPENBSD_7_3", continue: true, libressl: true }
|
||||||
- { version: "OPENBSD_7_2", continue: true, libressl: true }
|
- { version: "OPENBSD_7_2", continue: true, libressl: true }
|
||||||
- { version: "OPENBSD_7_1", continue: true, libressl: true }
|
- { version: "OPENBSD_7_1", continue: true, libressl: true }
|
||||||
@@ -66,12 +75,17 @@ jobs:
|
|||||||
- { version: "v3.1.5", continue: true, libressl: true }
|
- { version: "v3.1.5", continue: true, libressl: true }
|
||||||
- { version: "v2.1.10", continue: true, libressl: true }
|
- { version: "v2.1.10", continue: true, libressl: true }
|
||||||
- { version: "openssl-3.0", continue: true, libressl: false }
|
- { version: "openssl-3.0", continue: true, libressl: false }
|
||||||
- { version: "openssl-3.0.10", continue: false, libressl: false }
|
- { version: "openssl-3.0.18", continue: false, libressl: false }
|
||||||
- { version: "openssl-3.1", continue: true, libressl: false }
|
- { version: "openssl-3.2", continue: true, libressl: false }
|
||||||
- { version: "openssl-3.1.2", continue: false, libressl: false }
|
- { version: "openssl-3.2.6", continue: false, libressl: false }
|
||||||
valgrind:
|
- { version: "openssl-3.3", continue: true, libressl: false }
|
||||||
- { configure: '' , make: 'check' }
|
- { version: "openssl-3.3.5", continue: false, libressl: false }
|
||||||
- { configure: '--enable-valgrind' , make: 'check-valgrind' }
|
- { version: "openssl-3.4", continue: true, libressl: false }
|
||||||
|
- { version: "openssl-3.4.3", continue: false, libressl: false }
|
||||||
|
- { version: "openssl-3.5", continue: true, libressl: false }
|
||||||
|
- { version: "openssl-3.5.3", continue: false, libressl: false }
|
||||||
|
- { version: "openssl-3.6", continue: true, libressl: false }
|
||||||
|
- { version: "openssl-3.6.0", continue: false, libressl: false }
|
||||||
name: xSSL tests
|
name: xSSL tests
|
||||||
continue-on-error: ${{ matrix.xssl_versions.continue }}
|
continue-on-error: ${{ matrix.xssl_versions.continue }}
|
||||||
steps:
|
steps:
|
||||||
@@ -89,18 +103,26 @@ jobs:
|
|||||||
- name: Build the library
|
- name: Build the library
|
||||||
run: |
|
run: |
|
||||||
./bootstrap.sh
|
./bootstrap.sh
|
||||||
./configure ${{ matrix.valgrind.configure }} PKG_CONFIG_PATH="${HOME}/xssl/lib/pkgconfig" CFLAGS="-Werror -g3" --prefix="${HOME}/xssl"
|
PKG_CONFIG_PATH="${HOME}/xssl/lib/pkgconfig" ./configure CFLAGS="-Werror -g3" --prefix="${HOME}/xssl"
|
||||||
make -j$(nproc)
|
make -j$(nproc)
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: |
|
run: |
|
||||||
make -j$(nproc) ${{ matrix.valgrind.make }}
|
LD_LIBRARY_PATH="${HOME}/xssl/lib" make -j$(nproc) check
|
||||||
|
- name: Build the library with Valgrind enabled
|
||||||
|
run: |
|
||||||
|
./bootstrap.sh
|
||||||
|
PKG_CONFIG_PATH="${HOME}/xssl/lib/pkgconfig" ./configure --enable-valgrind CFLAGS="-Werror -g3" --prefix="${HOME}/xssl"
|
||||||
|
make -j$(nproc)
|
||||||
|
- name: Run tests with Valgrind enabled
|
||||||
|
run: |
|
||||||
|
LD_LIBRARY_PATH="${HOME}/xssl/lib" make -j$(nproc) check-valgrind
|
||||||
- name: Error logs
|
- name: Error logs
|
||||||
if: ${{ failure() }}
|
if: ${{ failure() }}
|
||||||
run: |
|
run: |
|
||||||
cat test-suite*.log || true
|
cat test-suite*.log || true
|
||||||
|
|
||||||
release-test:
|
release-test:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-22.04
|
||||||
name: Check if release would work
|
name: Check if release would work
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
@@ -124,9 +146,14 @@ 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-20.04
|
runs-on: ubuntu-24.04
|
||||||
name: Check coding style
|
name: Check coding style
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
steps:
|
steps:
|
||||||
|
|||||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -46,6 +46,7 @@ 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
|
||||||
@@ -65,6 +66,7 @@ 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
|
||||||
@@ -86,3 +88,4 @@ coverage/
|
|||||||
coverage.info
|
coverage.info
|
||||||
configure~
|
configure~
|
||||||
fuzz-*.log
|
fuzz-*.log
|
||||||
|
build*/
|
||||||
|
|||||||
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
|
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)
|
||||||
|
|||||||
@@ -190,6 +190,7 @@ 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
|
||||||
|
|
||||||
@@ -285,6 +286,11 @@ 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
|
||||||
|
|
||||||
@@ -327,6 +333,7 @@ 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
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
m4_define([v_maj], [0])
|
m4_define([v_maj], [0])
|
||||||
m4_define([v_min], [13])
|
m4_define([v_min], [14])
|
||||||
m4_define([v_patch], [1])
|
m4_define([v_patch], [0])
|
||||||
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,9 +18,10 @@ 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"],
|
||||||
[openbsd*], [PLATFORM="bsd"],
|
|
||||||
[netbsd*], [PLATFORM="bsd"],
|
[netbsd*], [PLATFORM="bsd"],
|
||||||
|
[openbsd*], [PLATFORM="bsd"],
|
||||||
[*nto*|*qnx*], [PLATFORM="qnx"],
|
[*nto*|*qnx*], [PLATFORM="qnx"],
|
||||||
[*solaris*], [PLATFORM="solaris"],
|
[*solaris*], [PLATFORM="solaris"],
|
||||||
[*android*], [PLATFORM="android"],
|
[*android*], [PLATFORM="android"],
|
||||||
|
|||||||
@@ -20,11 +20,12 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <conio.h>
|
#include <conio.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#else
|
||||||
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <strophe.h>
|
#include <strophe.h>
|
||||||
|
|||||||
@@ -13,7 +13,6 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <conio.h>
|
#include <conio.h>
|
||||||
@@ -23,6 +22,7 @@
|
|||||||
#include <iphlpapi.h>
|
#include <iphlpapi.h>
|
||||||
#include <mstcpip.h> /* tcp_keepalive */
|
#include <mstcpip.h> /* tcp_keepalive */
|
||||||
#else
|
#else
|
||||||
|
#include <unistd.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <netinet/tcp.h>
|
#include <netinet/tcp.h>
|
||||||
|
|||||||
@@ -11,11 +11,16 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <libgen.h> /* basename */
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <strophe.h>
|
#include <strophe.h>
|
||||||
|
#ifndef _WIN32
|
||||||
|
#include <libgen.h> /* basename */
|
||||||
|
#else
|
||||||
|
#define strtok_r strtok_s
|
||||||
|
#define basename(x) "vcard"
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
xmpp_ctx_t *ctx;
|
xmpp_ctx_t *ctx;
|
||||||
|
|||||||
@@ -1232,6 +1232,7 @@ 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
|
||||||
@@ -1486,6 +1487,8 @@ 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!";
|
||||||
|
|||||||
25
src/common.h
25
src/common.h
@@ -29,13 +29,29 @@
|
|||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
#include "snprintf.h"
|
#include "snprintf.h"
|
||||||
|
|
||||||
|
/** Define your own `STROPHE_STATIC_ASSERT` if your compiler doesn't support one
|
||||||
|
* of the below ones or define as noop if your compiler provides no replacement.
|
||||||
|
*/
|
||||||
|
#if !defined(STROPHE_STATIC_ASSERT)
|
||||||
|
#if (__STDC_VERSION__ >= 202000L)
|
||||||
|
#define STROPHE_STATIC_ASSERT(cond, msg) static_assert(cond, msg)
|
||||||
|
#else
|
||||||
|
#define STROPHE_STATIC_ASSERT(cond, msg) _Static_assert(cond, msg)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
/** 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;
|
||||||
int (*handler)();
|
xmpp_void_handler 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
|
||||||
@@ -175,9 +191,11 @@ struct _xmpp_send_queue_t {
|
|||||||
#define SASL_MASK_EXTERNAL (1 << 6)
|
#define SASL_MASK_EXTERNAL (1 << 6)
|
||||||
#define SASL_MASK_SCRAMSHA1_PLUS (1 << 7)
|
#define SASL_MASK_SCRAMSHA1_PLUS (1 << 7)
|
||||||
#define SASL_MASK_SCRAMSHA256_PLUS (1 << 8)
|
#define SASL_MASK_SCRAMSHA256_PLUS (1 << 8)
|
||||||
|
#define SASL_MASK_SCRAMSHA512_PLUS (1 << 9)
|
||||||
|
|
||||||
#define SASL_MASK_SCRAM_PLUS \
|
#define SASL_MASK_SCRAM_PLUS \
|
||||||
(SASL_MASK_SCRAMSHA1_PLUS | SASL_MASK_SCRAMSHA256_PLUS)
|
(SASL_MASK_SCRAMSHA1_PLUS | SASL_MASK_SCRAMSHA256_PLUS | \
|
||||||
|
SASL_MASK_SCRAMSHA512_PLUS)
|
||||||
#define SASL_MASK_SCRAM_WEAK \
|
#define SASL_MASK_SCRAM_WEAK \
|
||||||
(SASL_MASK_SCRAMSHA1 | SASL_MASK_SCRAMSHA256 | SASL_MASK_SCRAMSHA512)
|
(SASL_MASK_SCRAMSHA1 | SASL_MASK_SCRAMSHA256 | SASL_MASK_SCRAMSHA512)
|
||||||
#define SASL_MASK_SCRAM (SASL_MASK_SCRAM_PLUS | SASL_MASK_SCRAM_WEAK)
|
#define SASL_MASK_SCRAM (SASL_MASK_SCRAM_PLUS | SASL_MASK_SCRAM_WEAK)
|
||||||
@@ -321,6 +339,8 @@ 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);
|
||||||
@@ -374,6 +394,7 @@ 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);
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,9 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#define strcasecmp _stricmp
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef STROPHE_COMPRESSION_BUFFER_SIZE
|
#ifndef STROPHE_COMPRESSION_BUFFER_SIZE
|
||||||
/** Max buffer size for compressed data (send & receive). */
|
/** Max buffer size for compressed data (send & receive). */
|
||||||
@@ -110,7 +113,7 @@ static int
|
|||||||
_compression_write(xmpp_conn_t *conn, const void *buff, size_t len, int flush)
|
_compression_write(xmpp_conn_t *conn, const void *buff, size_t len, int flush)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
const void *buff_end = buff + len;
|
const void *buff_end = (const char *)buff + len;
|
||||||
struct xmpp_compression *comp = conn->compression.state;
|
struct xmpp_compression *comp = conn->compression.state;
|
||||||
comp->compression.stream.next_in = (Bytef *)buff;
|
comp->compression.stream.next_in = (Bytef *)buff;
|
||||||
comp->compression.stream.avail_in = len;
|
comp->compression.stream.avail_in = len;
|
||||||
@@ -201,7 +204,7 @@ static void *_zlib_alloc(void *opaque, unsigned int items, unsigned int size)
|
|||||||
static void _init_zlib_compression(xmpp_ctx_t *ctx, struct zlib_compression *s)
|
static void _init_zlib_compression(xmpp_ctx_t *ctx, struct zlib_compression *s)
|
||||||
{
|
{
|
||||||
s->buffer = strophe_alloc(ctx, STROPHE_COMPRESSION_BUFFER_SIZE);
|
s->buffer = strophe_alloc(ctx, STROPHE_COMPRESSION_BUFFER_SIZE);
|
||||||
s->buffer_end = s->buffer + STROPHE_COMPRESSION_BUFFER_SIZE;
|
s->buffer_end = (char *)s->buffer + STROPHE_COMPRESSION_BUFFER_SIZE;
|
||||||
|
|
||||||
s->stream.opaque = ctx;
|
s->stream.opaque = ctx;
|
||||||
s->stream.zalloc = _zlib_alloc;
|
s->stream.zalloc = _zlib_alloc;
|
||||||
|
|||||||
388
src/conn.c
388
src/conn.c
@@ -21,6 +21,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#if !defined(_MSC_VER) && !defined(_WIN32)
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#endif
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
@@ -1092,6 +1095,7 @@ int conn_tls_start(xmpp_conn_t *conn)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (conn->tls != NULL) {
|
if (conn->tls != NULL) {
|
||||||
|
struct conn_interface old_intf = conn->intf;
|
||||||
conn->intf = tls_intf;
|
conn->intf = tls_intf;
|
||||||
conn->intf.conn = conn;
|
conn->intf.conn = conn;
|
||||||
if (tls_start(conn->tls)) {
|
if (tls_start(conn->tls)) {
|
||||||
@@ -1102,6 +1106,7 @@ int conn_tls_start(xmpp_conn_t *conn)
|
|||||||
tls_free(conn->tls);
|
tls_free(conn->tls);
|
||||||
conn->tls = NULL;
|
conn->tls = NULL;
|
||||||
conn->tls_failed = 1;
|
conn->tls_failed = 1;
|
||||||
|
conn->intf = old_intf;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
@@ -1252,34 +1257,334 @@ int xmpp_conn_is_disconnected(xmpp_conn_t *conn)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This returns the Stream Management state of a connection object after
|
* This sets the Stream Management callback function
|
||||||
* 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
|
* After setting this API, the library will call the given callback function
|
||||||
* connection object, one can call \ref xmpp_free_sm_state
|
* each time when the internal SM state is updated.
|
||||||
*
|
*
|
||||||
* After calling this function to retrieve the state, only call one of the
|
* This can be used in conjunction with \ref xmpp_conn_restore_sm_state to
|
||||||
* other two.
|
* e.g. implement a mechanism that retains an SM state over potential
|
||||||
|
* application terminations.
|
||||||
*
|
*
|
||||||
* @param conn a Strophe connection object
|
* @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
|
* @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 */
|
struct sm_restore {
|
||||||
if (conn->state != XMPP_STATE_DISCONNECTED)
|
xmpp_conn_t *conn;
|
||||||
return NULL;
|
const unsigned char *state;
|
||||||
|
const unsigned char *const state_end, *const orig;
|
||||||
|
};
|
||||||
|
|
||||||
ret = conn->sm_state;
|
static int sm_load_u32(struct sm_restore *sm, uint8_t type, uint32_t *val)
|
||||||
conn->sm_state = NULL;
|
{
|
||||||
|
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;
|
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)
|
static void _reset_sm_state_for_reconnect(xmpp_conn_t *conn)
|
||||||
@@ -1310,6 +1615,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 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
|
||||||
@@ -1435,6 +1771,7 @@ char *xmpp_conn_send_queue_drop_element(xmpp_conn_t *conn,
|
|||||||
xmpp_queue_element_t which)
|
xmpp_queue_element_t which)
|
||||||
{
|
{
|
||||||
xmpp_send_queue_t *t;
|
xmpp_send_queue_t *t;
|
||||||
|
int disconnected = conn->state == XMPP_STATE_DISCONNECTED;
|
||||||
|
|
||||||
/* Fast return paths */
|
/* Fast return paths */
|
||||||
/* empty queue */
|
/* empty queue */
|
||||||
@@ -1443,7 +1780,7 @@ char *xmpp_conn_send_queue_drop_element(xmpp_conn_t *conn,
|
|||||||
/* one element in queue */
|
/* one element in queue */
|
||||||
if (conn->send_queue_head == conn->send_queue_tail) {
|
if (conn->send_queue_head == conn->send_queue_tail) {
|
||||||
/* head is already sent out partially */
|
/* head is already sent out partially */
|
||||||
if (conn->send_queue_head->wip)
|
if (conn->send_queue_head->wip && !disconnected)
|
||||||
return NULL;
|
return NULL;
|
||||||
/* the element is no USER element */
|
/* the element is no USER element */
|
||||||
if (conn->send_queue_head->owner != XMPP_QUEUE_USER)
|
if (conn->send_queue_head->owner != XMPP_QUEUE_USER)
|
||||||
@@ -1467,7 +1804,7 @@ char *xmpp_conn_send_queue_drop_element(xmpp_conn_t *conn,
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* head is already sent out partially */
|
/* head is already sent out partially */
|
||||||
if (t == conn->send_queue_head && t->wip)
|
if (t == conn->send_queue_head && t->wip && !disconnected)
|
||||||
t = t->next;
|
t = t->next;
|
||||||
|
|
||||||
/* search forward to find the first USER element */
|
/* search forward to find the first USER element */
|
||||||
@@ -1481,10 +1818,15 @@ char *xmpp_conn_send_queue_drop_element(xmpp_conn_t *conn,
|
|||||||
/* In case there exists a SM stanza that is linked to the
|
/* In case there exists a SM stanza that is linked to the
|
||||||
* one we're currently dropping, also delete that one.
|
* one we're currently dropping, also delete that one.
|
||||||
*/
|
*/
|
||||||
if (t->next && t->next->userdata == t)
|
if (t->next && t->next->userdata == t) {
|
||||||
strophe_free(conn->ctx, _drop_send_queue_element(conn, t->next));
|
strophe_free(conn->ctx, _drop_send_queue_element(conn, t->next));
|
||||||
|
/* reset the flag, so we restart to send `<r>` stanzas */
|
||||||
|
conn->sm_state->r_sent = 0;
|
||||||
|
}
|
||||||
/* Finally drop the element */
|
/* 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 */
|
/* timed handler for cleanup if normal disconnect procedure takes too long */
|
||||||
@@ -1678,6 +2020,7 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1753,6 +2096,7 @@ 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,
|
||||||
@@ -2039,8 +2383,10 @@ 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) {
|
||||||
send_raw(conn, req_ack, strlen(req_ack), XMPP_QUEUE_SM_STROPHE, item);
|
|
||||||
conn->sm_state->r_sent = 1;
|
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;
|
return XMPP_EOK;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,6 +174,7 @@ 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);
|
||||||
|
|
||||||
|
|||||||
@@ -25,8 +25,6 @@
|
|||||||
#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()
|
||||||
|
|||||||
@@ -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; \
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
@@ -982,7 +982,7 @@ resolver_win32_srv_query(const char *fulldomain, unsigned char *buf, size_t len)
|
|||||||
insize = recvfrom(sock, (char *)buf, (int)len, 0,
|
insize = recvfrom(sock, (char *)buf, (int)len, 0,
|
||||||
(struct sockaddr *)&dnsaddr, &addrlen);
|
(struct sockaddr *)&dnsaddr, &addrlen);
|
||||||
if (insize == SOCKET_ERROR) {
|
if (insize == SOCKET_ERROR) {
|
||||||
if (sock_error() == WSAEWOULDBLOCK) {
|
if (sock_error(NULL) == WSAEWOULDBLOCK) {
|
||||||
Sleep(100);
|
Sleep(100);
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
|
|||||||
11
src/scram.c
11
src/scram.c
@@ -78,12 +78,23 @@ const struct hash_alg scram_sha512 = {
|
|||||||
(void (*)(void *, const uint8_t *, size_t))sha512_process,
|
(void (*)(void *, const uint8_t *, size_t))sha512_process,
|
||||||
(void (*)(void *, uint8_t *))sha512_done};
|
(void (*)(void *, uint8_t *))sha512_done};
|
||||||
|
|
||||||
|
const struct hash_alg scram_sha512_plus = {
|
||||||
|
"SCRAM-SHA-512-PLUS",
|
||||||
|
SASL_MASK_SCRAMSHA512_PLUS,
|
||||||
|
SHA512_DIGEST_SIZE,
|
||||||
|
(void (*)(const uint8_t *, size_t, uint8_t *))sha512_hash,
|
||||||
|
(void (*)(void *))sha512_init,
|
||||||
|
(void (*)(void *, const uint8_t *, size_t))sha512_process,
|
||||||
|
(void (*)(void *, uint8_t *))sha512_done};
|
||||||
|
|
||||||
/* The order of this list defines the order in which the SCRAM algorithms are
|
/* The order of this list defines the order in which the SCRAM algorithms are
|
||||||
* tried if the server supports them.
|
* tried if the server supports them.
|
||||||
* Their order is derived from
|
* Their order is derived from
|
||||||
* https://datatracker.ietf.org/doc/html/draft-ietf-kitten-password-storage
|
* https://datatracker.ietf.org/doc/html/draft-ietf-kitten-password-storage
|
||||||
*/
|
*/
|
||||||
const struct hash_alg *scram_algs[] = {
|
const struct hash_alg *scram_algs[] = {
|
||||||
|
/* *1 */
|
||||||
|
&scram_sha512_plus,
|
||||||
/* *1 */
|
/* *1 */
|
||||||
&scram_sha256_plus,
|
&scram_sha256_plus,
|
||||||
/* *1 */
|
/* *1 */
|
||||||
|
|||||||
12
src/sha.h
12
src/sha.h
@@ -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) \
|
||||||
@@ -97,12 +97,12 @@ extern "C" {
|
|||||||
#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
|
||||||
|
|||||||
@@ -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))
|
||||||
|
|||||||
@@ -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))
|
||||||
|
|||||||
@@ -123,7 +123,8 @@ static void sock_getaddrinfo(xmpp_sock_t *xsock)
|
|||||||
rc = getaddrinfo(xsock->srv_rr_cur->target, service, &hints,
|
rc = getaddrinfo(xsock->srv_rr_cur->target, service, &hints,
|
||||||
&xsock->ainfo_list);
|
&xsock->ainfo_list);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
strophe_debug(xsock->ctx, "sock", "getaddrinfo() failed with %d",
|
strophe_debug(xsock->ctx, "sock",
|
||||||
|
"getaddrinfo() failed with %s (%d)", gai_strerror(rc),
|
||||||
rc);
|
rc);
|
||||||
xsock->ainfo_list = NULL;
|
xsock->ainfo_list = NULL;
|
||||||
}
|
}
|
||||||
@@ -236,7 +237,7 @@ sock_t sock_connect(xmpp_sock_t *xsock)
|
|||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
strophe_debug(xsock->ctx, "sock",
|
strophe_debug(xsock->ctx, "sock",
|
||||||
"User's setsockopt callback"
|
"User's setsockopt callback"
|
||||||
"failed with %d (errno=%d)",
|
" failed with %d (errno=%d)",
|
||||||
rc, errno);
|
rc, errno);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
31
src/tls.c
31
src/tls.c
@@ -29,6 +29,10 @@
|
|||||||
#include "strophe.h"
|
#include "strophe.h"
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#include <BaseTsd.h>
|
||||||
|
typedef SSIZE_T ssize_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
const struct conn_interface tls_intf = {
|
const struct conn_interface tls_intf = {
|
||||||
tls_read,
|
tls_read,
|
||||||
@@ -74,6 +78,23 @@ 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
|
||||||
@@ -88,8 +109,6 @@ const char *xmpp_tlscert_get_pem(const xmpp_tlscert_t *cert)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Get the dnsName entries out of the SubjectAlternativeNames.
|
/** Get the dnsName entries out of the SubjectAlternativeNames.
|
||||||
*
|
|
||||||
* Note: Max. `MAX_NUM_DNSNAMES` are supported.
|
|
||||||
*
|
*
|
||||||
* @param cert a Strophe TLS certificate object
|
* @param cert a Strophe TLS certificate object
|
||||||
* @param n which dnsName entry
|
* @param n which dnsName entry
|
||||||
@@ -145,9 +164,13 @@ const char *xmpp_tlscert_get_description(xmpp_cert_element_t elmnt)
|
|||||||
"Expires On",
|
"Expires On",
|
||||||
"Public Key Algorithm",
|
"Public Key Algorithm",
|
||||||
"Certificate Signature Algorithm",
|
"Certificate Signature Algorithm",
|
||||||
"Fingerprint SHA-1",
|
"Certificate Fingerprint SHA-1",
|
||||||
"Fingerprint SHA-256",
|
"Certificate Fingerprint SHA-256",
|
||||||
|
"Public Key Fingerprint SHA-256",
|
||||||
};
|
};
|
||||||
|
STROPHE_STATIC_ASSERT(
|
||||||
|
ARRAY_SIZE(descriptions) == XMPP_CERT_ELEMENT_MAX,
|
||||||
|
"descriptions don't match the number of enum elements");
|
||||||
if (elmnt < 0 || elmnt >= XMPP_CERT_ELEMENT_MAX)
|
if (elmnt < 0 || elmnt >= XMPP_CERT_ELEMENT_MAX)
|
||||||
return NULL;
|
return NULL;
|
||||||
return descriptions[elmnt];
|
return descriptions[elmnt];
|
||||||
|
|||||||
@@ -334,6 +334,12 @@ static xmpp_tlscert_t *_x509_to_tlscert(xmpp_ctx_t *ctx, gnutls_x509_crt_t cert)
|
|||||||
gnutls_x509_crt_get_fingerprint(cert, GNUTLS_DIG_SHA256, smallbuf, &size);
|
gnutls_x509_crt_get_fingerprint(cert, GNUTLS_DIG_SHA256, smallbuf, &size);
|
||||||
hex_encode(buf, smallbuf, size);
|
hex_encode(buf, smallbuf, size);
|
||||||
tlscert->elements[XMPP_CERT_FINGERPRINT_SHA256] = strophe_strdup(ctx, buf);
|
tlscert->elements[XMPP_CERT_FINGERPRINT_SHA256] = strophe_strdup(ctx, buf);
|
||||||
|
size = sizeof(smallbuf);
|
||||||
|
gnutls_x509_crt_get_key_id(cert, GNUTLS_KEYID_USE_SHA256, (void *)smallbuf,
|
||||||
|
&size);
|
||||||
|
hex_encode(buf, smallbuf, size);
|
||||||
|
tlscert->elements[XMPP_CERT_PUBKEY_FINGERPRINT_SHA256] =
|
||||||
|
strophe_strdup(ctx, buf);
|
||||||
|
|
||||||
strophe_snprintf(buf, sizeof(buf), "%d", gnutls_x509_crt_get_version(cert));
|
strophe_snprintf(buf, sizeof(buf), "%d", gnutls_x509_crt_get_version(cert));
|
||||||
tlscert->elements[XMPP_CERT_VERSION] = strophe_strdup(ctx, buf);
|
tlscert->elements[XMPP_CERT_VERSION] = strophe_strdup(ctx, buf);
|
||||||
@@ -422,6 +428,8 @@ 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);
|
||||||
|
|||||||
@@ -51,8 +51,10 @@
|
|||||||
|
|
||||||
#if OPENSSL_VERSION_NUMBER < 0x30000000L
|
#if OPENSSL_VERSION_NUMBER < 0x30000000L
|
||||||
#define STROPHE_ERR_func_error_string(e) ERR_func_error_string(e)
|
#define STROPHE_ERR_func_error_string(e) ERR_func_error_string(e)
|
||||||
|
#define STROPHE_SSL_get1_peer_certificate(s) SSL_get_peer_certificate(s)
|
||||||
#else
|
#else
|
||||||
#define STROPHE_ERR_func_error_string(e) ""
|
#define STROPHE_ERR_func_error_string(e) ""
|
||||||
|
#define STROPHE_SSL_get1_peer_certificate(s) SSL_get1_peer_certificate(s)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||||
@@ -109,6 +111,7 @@ struct _tls {
|
|||||||
X509 *client_cert;
|
X509 *client_cert;
|
||||||
void *channel_binding_data;
|
void *channel_binding_data;
|
||||||
size_t channel_binding_size;
|
size_t channel_binding_size;
|
||||||
|
FILE *keylogfile;
|
||||||
int lasterror;
|
int lasterror;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -373,18 +376,26 @@ _get_fingerprint(const xmpp_ctx_t *ctx, X509 *err_cert, xmpp_cert_element_t el)
|
|||||||
{
|
{
|
||||||
unsigned char buf[EVP_MAX_MD_SIZE];
|
unsigned char buf[EVP_MAX_MD_SIZE];
|
||||||
unsigned int len;
|
unsigned int len;
|
||||||
|
int (*digest_fn)(const X509 *data, const EVP_MD *type, unsigned char *md,
|
||||||
|
unsigned int *len);
|
||||||
const EVP_MD *digest;
|
const EVP_MD *digest;
|
||||||
switch (el) {
|
switch (el) {
|
||||||
case XMPP_CERT_FINGERPRINT_SHA1:
|
case XMPP_CERT_FINGERPRINT_SHA1:
|
||||||
|
digest_fn = X509_digest;
|
||||||
digest = EVP_sha1();
|
digest = EVP_sha1();
|
||||||
break;
|
break;
|
||||||
case XMPP_CERT_FINGERPRINT_SHA256:
|
case XMPP_CERT_FINGERPRINT_SHA256:
|
||||||
|
digest_fn = X509_digest;
|
||||||
|
digest = EVP_sha256();
|
||||||
|
break;
|
||||||
|
case XMPP_CERT_PUBKEY_FINGERPRINT_SHA256:
|
||||||
|
digest_fn = X509_pubkey_digest;
|
||||||
digest = EVP_sha256();
|
digest = EVP_sha256();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (X509_digest(err_cert, digest, buf, &len) != 0) {
|
if (digest_fn(err_cert, digest, buf, &len) != 0) {
|
||||||
char fingerprint[4 * EVP_MAX_MD_SIZE];
|
char fingerprint[4 * EVP_MAX_MD_SIZE];
|
||||||
hex_encode(fingerprint, buf, len);
|
hex_encode(fingerprint, buf, len);
|
||||||
return strophe_strdup(ctx, fingerprint);
|
return strophe_strdup(ctx, fingerprint);
|
||||||
@@ -472,6 +483,8 @@ static xmpp_tlscert_t *_x509_to_tlscert(xmpp_ctx_t *ctx, X509 *cert)
|
|||||||
_get_fingerprint(ctx, cert, XMPP_CERT_FINGERPRINT_SHA1);
|
_get_fingerprint(ctx, cert, XMPP_CERT_FINGERPRINT_SHA1);
|
||||||
tlscert->elements[XMPP_CERT_FINGERPRINT_SHA256] =
|
tlscert->elements[XMPP_CERT_FINGERPRINT_SHA256] =
|
||||||
_get_fingerprint(ctx, cert, XMPP_CERT_FINGERPRINT_SHA256);
|
_get_fingerprint(ctx, cert, XMPP_CERT_FINGERPRINT_SHA256);
|
||||||
|
tlscert->elements[XMPP_CERT_PUBKEY_FINGERPRINT_SHA256] =
|
||||||
|
_get_fingerprint(ctx, cert, XMPP_CERT_PUBKEY_FINGERPRINT_SHA256);
|
||||||
|
|
||||||
strophe_snprintf(buf, sizeof(buf), "%ld", X509_get_version(cert) + 1);
|
strophe_snprintf(buf, sizeof(buf), "%ld", X509_get_version(cert) + 1);
|
||||||
tlscert->elements[XMPP_CERT_VERSION] = strophe_strdup(ctx, buf);
|
tlscert->elements[XMPP_CERT_VERSION] = strophe_strdup(ctx, buf);
|
||||||
@@ -537,6 +550,8 @@ 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]);
|
||||||
@@ -556,6 +571,36 @@ static int _tls_password_callback(char *buf, int size, int rwflag, void *u)
|
|||||||
return tls_caching_password_callback(buf, size, u);
|
return tls_caching_password_callback(buf, size, u);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if OPENSSL_VERSION_NUMBER >= 0x10101000L
|
||||||
|
static void _keylog_cb(const SSL *ssl, const char *line)
|
||||||
|
{
|
||||||
|
xmpp_conn_t *conn = SSL_get_app_data(ssl);
|
||||||
|
fwrite(line, strlen(line), 1, conn->tls->keylogfile);
|
||||||
|
fputc('\n', conn->tls->keylogfile);
|
||||||
|
fflush(conn->tls->keylogfile);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void _try_open_keylogfile(tls_t *tls)
|
||||||
|
{
|
||||||
|
#if OPENSSL_VERSION_NUMBER >= 0x10101000L
|
||||||
|
const char *first_line = "# SSL Key logfile generated by libstrophe\n";
|
||||||
|
const char *SSLKEYLOGFILE = getenv("SSLKEYLOGFILE");
|
||||||
|
if (!SSLKEYLOGFILE || *SSLKEYLOGFILE == '\0')
|
||||||
|
return;
|
||||||
|
tls->keylogfile = fopen(SSLKEYLOGFILE, "abe");
|
||||||
|
if (!tls->keylogfile) {
|
||||||
|
strophe_warn(tls->ctx, "tls", "Could not open SSL keylog file %s",
|
||||||
|
SSLKEYLOGFILE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fwrite(first_line, strlen(first_line), 1, tls->keylogfile);
|
||||||
|
SSL_CTX_set_keylog_callback(tls->ssl_ctx, _keylog_cb);
|
||||||
|
#else
|
||||||
|
UNUSED(tls);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
tls_t *tls_new(xmpp_conn_t *conn)
|
tls_t *tls_new(xmpp_conn_t *conn)
|
||||||
{
|
{
|
||||||
tls_t *tls = strophe_alloc(conn->ctx, sizeof(*tls));
|
tls_t *tls = strophe_alloc(conn->ctx, sizeof(*tls));
|
||||||
@@ -699,6 +744,8 @@ tls_t *tls_new(xmpp_conn_t *conn)
|
|||||||
ret = SSL_set_fd(tls->ssl, conn->sock);
|
ret = SSL_set_fd(tls->ssl, conn->sock);
|
||||||
if (ret <= 0)
|
if (ret <= 0)
|
||||||
goto err_free_ssl;
|
goto err_free_ssl;
|
||||||
|
|
||||||
|
_try_open_keylogfile(tls);
|
||||||
}
|
}
|
||||||
|
|
||||||
return tls;
|
return tls;
|
||||||
@@ -717,6 +764,8 @@ err:
|
|||||||
|
|
||||||
void tls_free(tls_t *tls)
|
void tls_free(tls_t *tls)
|
||||||
{
|
{
|
||||||
|
if (tls->keylogfile)
|
||||||
|
fclose(tls->keylogfile);
|
||||||
strophe_free(tls->ctx, tls->channel_binding_data);
|
strophe_free(tls->ctx, tls->channel_binding_data);
|
||||||
SSL_free(tls->ssl);
|
SSL_free(tls->ssl);
|
||||||
X509_free(tls->client_cert);
|
X509_free(tls->client_cert);
|
||||||
@@ -727,7 +776,7 @@ void tls_free(tls_t *tls)
|
|||||||
xmpp_tlscert_t *tls_peer_cert(xmpp_conn_t *conn)
|
xmpp_tlscert_t *tls_peer_cert(xmpp_conn_t *conn)
|
||||||
{
|
{
|
||||||
if (conn && conn->tls && conn->tls->ssl) {
|
if (conn && conn->tls && conn->tls->ssl) {
|
||||||
X509 *cert = SSL_get_peer_certificate(conn->tls->ssl);
|
X509 *cert = STROPHE_SSL_get1_peer_certificate(conn->tls->ssl);
|
||||||
if (cert) {
|
if (cert) {
|
||||||
xmpp_tlscert_t *tlscert = _x509_to_tlscert(conn->ctx, cert);
|
xmpp_tlscert_t *tlscert = _x509_to_tlscert(conn->ctx, cert);
|
||||||
X509_free(cert);
|
X509_free(cert);
|
||||||
@@ -999,7 +1048,7 @@ static void _tls_dump_cert_info(tls_t *tls)
|
|||||||
X509 *cert;
|
X509 *cert;
|
||||||
char *name;
|
char *name;
|
||||||
|
|
||||||
cert = SSL_get_peer_certificate(tls->ssl);
|
cert = STROPHE_SSL_get1_peer_certificate(tls->ssl);
|
||||||
if (cert == NULL)
|
if (cert == NULL)
|
||||||
strophe_debug(tls->ctx, "tls", "Certificate was not presented by peer");
|
strophe_debug(tls->ctx, "tls", "Certificate was not presented by peer");
|
||||||
else {
|
else {
|
||||||
|
|||||||
@@ -266,7 +266,7 @@ int tls_start(tls_t *tls)
|
|||||||
|
|
||||||
/* use the domain there as our name */
|
/* use the domain there as our name */
|
||||||
name = tls->conn->domain;
|
name = tls->conn->domain;
|
||||||
intf = tls->conn->intf;
|
intf = &tls->conn->intf;
|
||||||
|
|
||||||
ctxtreq = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT |
|
ctxtreq = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT |
|
||||||
ISC_REQ_CONFIDENTIALITY | ISC_RET_EXTENDED_ERROR |
|
ISC_REQ_CONFIDENTIALITY | ISC_RET_EXTENDED_ERROR |
|
||||||
@@ -479,7 +479,7 @@ int tls_read(struct conn_interface *intf, void *buff, size_t len)
|
|||||||
int read;
|
int read;
|
||||||
tls->readybufferpos += bytes;
|
tls->readybufferpos += bytes;
|
||||||
newbuff += bytes;
|
newbuff += bytes;
|
||||||
read = tls_read(tls, newbuff, len - bytes);
|
read = tls_read(intf, newbuff, len - bytes);
|
||||||
|
|
||||||
if (read == -1) {
|
if (read == -1) {
|
||||||
if (tls_is_recoverable(intf, tls->lasterror)) {
|
if (tls_is_recoverable(intf, tls->lasterror)) {
|
||||||
@@ -553,7 +553,7 @@ int tls_read(struct conn_interface *intf, void *buff, size_t len)
|
|||||||
tls->recvbufferpos = 0;
|
tls->recvbufferpos = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return tls_read(tls, buff, len);
|
return tls_read(intf, buff, len);
|
||||||
} else if (ret == SEC_E_INCOMPLETE_MESSAGE) {
|
} else if (ret == SEC_E_INCOMPLETE_MESSAGE) {
|
||||||
tls->lasterror = SEC_E_INCOMPLETE_MESSAGE;
|
tls->lasterror = SEC_E_INCOMPLETE_MESSAGE;
|
||||||
return -1;
|
return -1;
|
||||||
@@ -611,7 +611,7 @@ int tls_write(struct conn_interface *intf, const void *buff, size_t len)
|
|||||||
int sent = 0, ret, remain = len;
|
int sent = 0, ret, remain = len;
|
||||||
tls_t *tls = intf->conn->tls;
|
tls_t *tls = intf->conn->tls;
|
||||||
|
|
||||||
ret = tls_clear_pending_write(tls);
|
ret = tls_clear_pending_write(intf);
|
||||||
if (ret <= 0) {
|
if (ret <= 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -667,9 +667,9 @@ int tls_write(struct conn_interface *intf, const void *buff, size_t len)
|
|||||||
|
|
||||||
tls->sendbufferpos = 0;
|
tls->sendbufferpos = 0;
|
||||||
|
|
||||||
ret = tls_clear_pending_write(tls);
|
ret = tls_clear_pending_write(intf);
|
||||||
|
|
||||||
if (ret == -1 && !tls_is_recoverable(intf, tls_error(tls))) {
|
if (ret == -1 && !tls_is_recoverable(intf, tls_error(intf))) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -682,7 +682,7 @@ int tls_write(struct conn_interface *intf, const void *buff, size_t len)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ret == 0 ||
|
if (ret == 0 ||
|
||||||
(ret == -1 && tls_is_recoverable(intf, tls_error(tls)))) {
|
(ret == -1 && tls_is_recoverable(intf, tls_error(intf)))) {
|
||||||
return sent;
|
return sent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
36
strophe.h
36
strophe.h
@@ -18,6 +18,7 @@
|
|||||||
#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" {
|
||||||
@@ -187,6 +188,7 @@ typedef struct _xmpp_sm_t xmpp_sm_state_t;
|
|||||||
#define XMPP_CONN_FLAG_DISABLE_TLS (1UL << 0)
|
#define XMPP_CONN_FLAG_DISABLE_TLS (1UL << 0)
|
||||||
#define XMPP_CONN_FLAG_MANDATORY_TLS (1UL << 1)
|
#define XMPP_CONN_FLAG_MANDATORY_TLS (1UL << 1)
|
||||||
#define XMPP_CONN_FLAG_LEGACY_SSL (1UL << 2)
|
#define XMPP_CONN_FLAG_LEGACY_SSL (1UL << 2)
|
||||||
|
#define XMPP_CONN_FLAG_DIRECT_TLS XMPP_CONN_FLAG_LEGACY_SSL
|
||||||
/** @def XMPP_CONN_FLAG_TRUST_TLS
|
/** @def XMPP_CONN_FLAG_TRUST_TLS
|
||||||
* Trust server's certificate even if it is invalid.
|
* Trust server's certificate even if it is invalid.
|
||||||
*/
|
*/
|
||||||
@@ -259,6 +261,7 @@ typedef enum {
|
|||||||
XMPP_CERT_SIGALG, /**< Certificate Signature Algorithm */
|
XMPP_CERT_SIGALG, /**< Certificate Signature Algorithm */
|
||||||
XMPP_CERT_FINGERPRINT_SHA1, /**< Fingerprint SHA-1 */
|
XMPP_CERT_FINGERPRINT_SHA1, /**< Fingerprint SHA-1 */
|
||||||
XMPP_CERT_FINGERPRINT_SHA256, /**< Fingerprint SHA-256 */
|
XMPP_CERT_FINGERPRINT_SHA256, /**< Fingerprint SHA-256 */
|
||||||
|
XMPP_CERT_PUBKEY_FINGERPRINT_SHA256, /**< SHA-256 fingerprint of pubkey */
|
||||||
XMPP_CERT_ELEMENT_MAX /**< Last element of the enum */
|
XMPP_CERT_ELEMENT_MAX /**< Last element of the enum */
|
||||||
} xmpp_cert_element_t;
|
} xmpp_cert_element_t;
|
||||||
|
|
||||||
@@ -414,8 +417,38 @@ 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);
|
||||||
|
|
||||||
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);
|
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);
|
void xmpp_free_sm_state(xmpp_sm_state_t *sm_state);
|
||||||
|
|
||||||
@@ -611,6 +644,7 @@ 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,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
logfile="../../testbuild.log"
|
logfile="../../testbuild.log"
|
||||||
|
errfile="../../testerr.log"
|
||||||
|
|
||||||
err_out() {
|
err_out() {
|
||||||
tail $logfile
|
tail $logfile
|
||||||
@@ -8,6 +9,6 @@ err_out() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
./bootstrap.sh
|
./bootstrap.sh
|
||||||
./configure >> $logfile || err_out
|
./configure >> $logfile 2>> $errfile || err_out
|
||||||
make -j$(( `nproc` * 2 + 1 )) >> $logfile || err_out
|
make -j$(( `nproc` * 2 + 1 )) >> $logfile 2>> $errfile || err_out
|
||||||
make check >> $logfile || 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;
|
||||||
|
}
|
||||||
@@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
#undef HAVE_VSNPRINTF
|
#undef HAVE_VSNPRINTF
|
||||||
#undef HAVE_SNPRINTF
|
#undef HAVE_SNPRINTF
|
||||||
@@ -28,7 +29,14 @@ int main(void)
|
|||||||
char *int_fmt[] = {"%-1.5d", "%1.5d", "%123.9d", "%5.5d",
|
char *int_fmt[] = {"%-1.5d", "%1.5d", "%123.9d", "%5.5d",
|
||||||
"%10.5d", "% 10.5d", "%+22.33d", "%01.3d",
|
"%10.5d", "% 10.5d", "%+22.33d", "%01.3d",
|
||||||
"%4d", "0x%x", "0x%04x", NULL};
|
"%4d", "0x%x", "0x%04x", NULL};
|
||||||
long int_nums[] = {-1, 134, 91340, 341, 0203, 0x76543210, 0};
|
int int_nums[] = {-1, 134, 91340, 341, 0203,
|
||||||
|
0x76543210, INT_MIN, INT_MAX, 0};
|
||||||
|
char *long_fmt[] = {"%-1.5ld", "%1.5ld", "%123.9ld", "%5.5ld",
|
||||||
|
"%10.5ld", "% 10.5ld", "%+22.33ld", "%01.3ld",
|
||||||
|
"%4ld", "0x%lx", "0x%04lx", NULL};
|
||||||
|
long long_nums[] = {-1L, 134L, 91340L,
|
||||||
|
341L, 0203L, 0xFEDCBA9876543210L,
|
||||||
|
LONG_MIN, LONG_MAX, 0L};
|
||||||
int x, y;
|
int x, y;
|
||||||
int fail = 0;
|
int fail = 0;
|
||||||
int num = 0;
|
int num = 0;
|
||||||
@@ -60,6 +68,19 @@ int main(void)
|
|||||||
}
|
}
|
||||||
num++;
|
num++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (x = 0; long_fmt[x] != NULL; x++)
|
||||||
|
for (y = 0; long_nums[y] != 0; y++) {
|
||||||
|
strophe_snprintf(buf1, sizeof(buf1), long_fmt[x], long_nums[y]);
|
||||||
|
sprintf(buf2, long_fmt[x], long_nums[y]);
|
||||||
|
if (strcmp(buf1, buf2)) {
|
||||||
|
printf("xmpp_snprintf doesn't match Format: "
|
||||||
|
"%s\n\txmpp_snprintf = %s\n\tsprintf = %s\n",
|
||||||
|
long_fmt[x], buf1, buf2);
|
||||||
|
fail++;
|
||||||
|
}
|
||||||
|
num++;
|
||||||
|
}
|
||||||
printf("%d tests failed out of %d.\n", fail, num);
|
printf("%d tests failed out of %d.\n", fail, num);
|
||||||
return fail != 0 ? 1 : 0;
|
return fail != 0 ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -177,13 +177,9 @@ static void test_stanza_error(xmpp_ctx_t *ctx)
|
|||||||
mood = xmpp_stanza_new_from_string(ctx, str_mood);
|
mood = xmpp_stanza_new_from_string(ctx, str_mood);
|
||||||
assert(mood != NULL);
|
assert(mood != NULL);
|
||||||
|
|
||||||
assert(xmpp_stanza_get_to(error) != NULL);
|
|
||||||
COMPARE("romeo@montague.lit/home", xmpp_stanza_get_to(error));
|
COMPARE("romeo@montague.lit/home", xmpp_stanza_get_to(error));
|
||||||
assert(xmpp_stanza_get_from(error) != NULL);
|
|
||||||
COMPARE("juliet@capulet.lit/chamber", xmpp_stanza_get_from(error));
|
COMPARE("juliet@capulet.lit/chamber", xmpp_stanza_get_from(error));
|
||||||
assert(xmpp_stanza_get_id(error) != NULL);
|
|
||||||
COMPARE("e2e1", xmpp_stanza_get_id(error));
|
COMPARE("e2e1", xmpp_stanza_get_id(error));
|
||||||
assert(xmpp_stanza_get_type(error) != NULL);
|
|
||||||
COMPARE("error", xmpp_stanza_get_type(error));
|
COMPARE("error", xmpp_stanza_get_type(error));
|
||||||
|
|
||||||
/* FAIL - no list given */
|
/* FAIL - no list given */
|
||||||
@@ -212,7 +208,6 @@ static void test_stanza_error(xmpp_ctx_t *ctx)
|
|||||||
"item", "mood", NULL);
|
"item", "mood", NULL);
|
||||||
assert(item != NULL);
|
assert(item != NULL);
|
||||||
assert(xmpp_stanza_get_children(item) != NULL);
|
assert(xmpp_stanza_get_children(item) != NULL);
|
||||||
assert(xmpp_stanza_get_name(xmpp_stanza_get_children(item)) != NULL);
|
|
||||||
COMPARE("annoyed", xmpp_stanza_get_name(xmpp_stanza_get_children(item)));
|
COMPARE("annoyed", xmpp_stanza_get_name(xmpp_stanza_get_children(item)));
|
||||||
|
|
||||||
item = xmpp_stanza_get_child_by_path(
|
item = xmpp_stanza_get_child_by_path(
|
||||||
@@ -223,7 +218,6 @@ static void test_stanza_error(xmpp_ctx_t *ctx)
|
|||||||
NULL);
|
NULL);
|
||||||
assert(item != NULL);
|
assert(item != NULL);
|
||||||
assert(xmpp_stanza_get_children(item) != NULL);
|
assert(xmpp_stanza_get_children(item) != NULL);
|
||||||
assert(xmpp_stanza_get_name(xmpp_stanza_get_children(item)) != NULL);
|
|
||||||
COMPARE("annoyed", xmpp_stanza_get_name(xmpp_stanza_get_children(item)));
|
COMPARE("annoyed", xmpp_stanza_get_name(xmpp_stanza_get_children(item)));
|
||||||
|
|
||||||
ret = xmpp_stanza_get_attributes(error, attr, attrlen);
|
ret = xmpp_stanza_get_attributes(error, attr, attrlen);
|
||||||
@@ -243,6 +237,50 @@ static void test_stanza_error(xmpp_ctx_t *ctx)
|
|||||||
xmpp_stanza_release(error);
|
xmpp_stanza_release(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_stanza_bookmark(xmpp_ctx_t *ctx)
|
||||||
|
{
|
||||||
|
// clang-format off
|
||||||
|
static const char *str =
|
||||||
|
"<item xmlns=\"http://jabber.org/protocol/pubsub\" id=\"\">"
|
||||||
|
"<conference autojoin=\"\" name=\"Symbol(lit-nothing)\" xmlns=\"urn:xmpp:bookmarks:1\" />"
|
||||||
|
"</item>";
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
xmpp_stanza_t *stanza = xmpp_stanza_new_from_string(ctx, str);
|
||||||
|
assert(stanza != NULL);
|
||||||
|
const char *id = xmpp_stanza_get_id(stanza);
|
||||||
|
assert(id != NULL);
|
||||||
|
assert(strcmp(id, "") == 0);
|
||||||
|
xmpp_stanza_t *child = xmpp_stanza_get_children(stanza);
|
||||||
|
COMPARE("conference", xmpp_stanza_get_name(child));
|
||||||
|
const char *autojoin = xmpp_stanza_get_attribute(child, "autojoin");
|
||||||
|
assert(autojoin != NULL);
|
||||||
|
assert(strcmp(autojoin, "") == 0);
|
||||||
|
xmpp_stanza_release(stanza);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_stanza_copy(xmpp_ctx_t *ctx)
|
||||||
|
{
|
||||||
|
// clang-format off
|
||||||
|
static const char *str =
|
||||||
|
"<item xmlns=\"http://jabber.org/protocol/pubsub\" id=\"\">"
|
||||||
|
"<conference autojoin=\"\" name=\"Symbol(lit-nothing)\" xmlns=\"urn:xmpp:bookmarks:1\" />"
|
||||||
|
"</item>";
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
xmpp_stanza_t *stanza = xmpp_stanza_new_from_string(ctx, str);
|
||||||
|
assert(stanza != NULL);
|
||||||
|
const char *id = xmpp_stanza_get_id(stanza);
|
||||||
|
assert(id != NULL);
|
||||||
|
assert(strcmp(id, "") == 0);
|
||||||
|
xmpp_stanza_t *child = xmpp_stanza_get_children(stanza);
|
||||||
|
COMPARE("conference", xmpp_stanza_get_name(child));
|
||||||
|
xmpp_stanza_t *copy = xmpp_stanza_copy(child);
|
||||||
|
xmpp_stanza_release(stanza);
|
||||||
|
COMPARE("conference", xmpp_stanza_get_name(copy));
|
||||||
|
xmpp_stanza_release(copy);
|
||||||
|
}
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
xmpp_ctx_t *ctx;
|
xmpp_ctx_t *ctx;
|
||||||
@@ -251,6 +289,8 @@ int main()
|
|||||||
ctx = xmpp_ctx_new(&stanza_mem, NULL);
|
ctx = xmpp_ctx_new(&stanza_mem, NULL);
|
||||||
assert(ctx != NULL);
|
assert(ctx != NULL);
|
||||||
|
|
||||||
|
test_stanza_bookmark(ctx);
|
||||||
|
test_stanza_copy(ctx);
|
||||||
test_stanza_add_child(ctx);
|
test_stanza_add_child(ctx);
|
||||||
test_stanza_from_string(ctx);
|
test_stanza_from_string(ctx);
|
||||||
test_stanza_error(ctx);
|
test_stanza_error(ctx);
|
||||||
|
|||||||
Reference in New Issue
Block a user