Compare commits
49 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f8cda0f65c | ||
|
|
649a3b4fca | ||
|
|
a2b3b6b9e2 | ||
|
|
dfb3e86824 | ||
|
|
a81f0a8a5f | ||
|
|
5509ec3b35 | ||
|
|
67b1a2f3f4 | ||
|
|
7c2e78937d | ||
|
|
b7bae1502f | ||
|
|
e3d734c5ff | ||
|
|
e7b08faaa7 | ||
|
|
f3fa9f557b | ||
|
|
5690c4ed89 | ||
|
|
62953e9ecf | ||
|
|
5142eea2eb | ||
|
|
5dd9e4b0e0 | ||
|
|
4ec4f09b35 | ||
|
|
e24819a405 | ||
|
|
d0d1fa9835 | ||
|
|
da1229814c | ||
|
|
d82df1273c | ||
|
|
9fef4b7d02 | ||
|
|
4359536a17 | ||
|
|
03d43132bc | ||
|
|
4d59a9fe45 | ||
|
|
40f2452fb0 | ||
|
|
1cf09b1870 | ||
|
|
5edc480932 | ||
|
|
641211ecae | ||
|
|
d8fd6e6d14 | ||
|
|
9410530507 | ||
|
|
d6d71e97f8 | ||
|
|
3f03de031c | ||
|
|
c7d410f38b | ||
|
|
fa960429b8 | ||
|
|
bfd0872aea | ||
|
|
c5b6026fc6 | ||
|
|
7fbf507f58 | ||
|
|
69f42360cf | ||
|
|
f40fcbe5d1 | ||
|
|
13d0354176 | ||
|
|
53d8eb17b6 | ||
|
|
9735af515a | ||
|
|
c30bd0d9ab | ||
|
|
fdd717a246 | ||
|
|
7894d15929 | ||
|
|
f49ccb3262 | ||
|
|
069787db51 | ||
|
|
9eba8e8738 |
67
.github/workflows/main.yml
vendored
67
.github/workflows/main.yml
vendored
@@ -10,12 +10,12 @@ on:
|
|||||||
|
|
||||||
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' }
|
||||||
@@ -24,6 +24,7 @@ jobs:
|
|||||||
- { configure: '--disable-tls' }
|
- { configure: '--disable-tls' }
|
||||||
- { configure: '--enable-cares' }
|
- { configure: '--enable-cares' }
|
||||||
- { configure: '--disable-getrandom' }
|
- { configure: '--disable-getrandom' }
|
||||||
|
- { configure: '--disable-static' }
|
||||||
name: Regular Tests
|
name: Regular Tests
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
@@ -34,7 +35,7 @@ jobs:
|
|||||||
- name: Build the library
|
- name: Build the library
|
||||||
run: |
|
run: |
|
||||||
./bootstrap.sh
|
./bootstrap.sh
|
||||||
./configure ${{ matrix.options.configure }} ${{ matrix.valgrind.configure }} CFLAGS="-Werror -g3"
|
./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: |
|
||||||
@@ -45,26 +46,35 @@ 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_1", continue: true, libressl: true }
|
- { version: "OPENBSD_7_5", continue: true, libressl: true }
|
||||||
|
- { version: "v3.9.2", continue: true, libressl: true }
|
||||||
|
- { version: "OPENBSD_7_4", continue: true, libressl: true }
|
||||||
|
- { version: "v3.8.4", continue: true, libressl: true }
|
||||||
|
- { version: "OPENBSD_7_3", continue: true, libressl: true }
|
||||||
|
- { version: "OPENBSD_7_2", continue: true, libressl: true }
|
||||||
|
- { version: "OPENBSD_7_1", continue: true, libressl: true }
|
||||||
# https://github.com/libressl-portable/portable/issues/760
|
# https://github.com/libressl-portable/portable/issues/760
|
||||||
# - { version: "v3.5.2", continue: true, libressl: true }
|
# - { version: "v3.5.2", continue: true, libressl: true }
|
||||||
- { version: "OPENBSD_7_0", continue: true, libressl: true }
|
- { version: "OPENBSD_7_0", continue: true, libressl: true }
|
||||||
# OPENBSD_7_0 is basically the "fixed v3.4.3"
|
# OPENBSD_7_0 is basically the "fixed v3.4.3"
|
||||||
# - { version: "v3.4.3", continue: true, libressl: true }
|
# - { version: "v3.4.3", continue: true, libressl: true }
|
||||||
- { version: "v3.4.2", continue: true, libressl: true }
|
- { version: "v3.4.2", continue: true, libressl: true }
|
||||||
- { version: "OPENBSD_6_9", continue: true, libressl: true }
|
- { version: "OPENBSD_6_9", continue: true, libressl: true }
|
||||||
- { 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.4", continue: false, libressl: false }
|
- { version: "openssl-3.0.13", continue: false, libressl: false }
|
||||||
valgrind:
|
- { version: "openssl-3.1", continue: true, libressl: false }
|
||||||
- { configure: '' , make: 'check' }
|
- { version: "openssl-3.1.5", continue: false, libressl: false }
|
||||||
- { configure: '--enable-valgrind' , make: 'check-valgrind' }
|
- { version: "openssl-3.2", continue: true, libressl: false }
|
||||||
|
- { version: "openssl-3.2.1", continue: false, libressl: false }
|
||||||
|
- { version: "openssl-3.3", continue: true, libressl: false }
|
||||||
|
- { version: "openssl-3.3.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:
|
||||||
@@ -82,18 +92,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
|
||||||
@@ -117,9 +135,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:
|
||||||
|
|||||||
2
.gitignore
vendored
2
.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
|
||||||
|
|||||||
28
ChangeLog
28
ChangeLog
@@ -1,3 +1,29 @@
|
|||||||
|
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)
|
||||||
|
- Fix `sock_connect()` not looping over all DNS records returned if no `sockopt_cb` is set (5edc480)
|
||||||
|
- Replace usage of EBADFD, it's not in POSIX (#235)
|
||||||
|
|
||||||
|
0.13.0
|
||||||
|
- Fix connected/connecting signaling to user (#227)
|
||||||
|
- Fix wording of licensing terms (#225)
|
||||||
|
- Prepare for future changes in OpenSSL (#226)
|
||||||
|
- Improve Stream Management (#227) (#230)
|
||||||
|
- Add SCRAM-PLUS Variants (#228)
|
||||||
|
- Introduce XEP-0138 stream compression (#231)
|
||||||
|
- Deprecated the following API (#227):
|
||||||
|
- xmpp_conn_disable_tls() - replaced by a flag set by xmpp_conn_set_flags()
|
||||||
|
|
||||||
0.12.3
|
0.12.3
|
||||||
- Improve TCP-connection establishment (#221)
|
- Improve TCP-connection establishment (#221)
|
||||||
- Handle case where the server doesn't provide the `bind` feature (#224)
|
- Handle case where the server doesn't provide the `bind` feature (#224)
|
||||||
@@ -21,7 +47,7 @@
|
|||||||
- Fix some build steps when builddir != srcdir (#208)
|
- Fix some build steps when builddir != srcdir (#208)
|
||||||
- Allow the user to disable build of examples (#209)
|
- Allow the user to disable build of examples (#209)
|
||||||
- CI builds against OpenSSL 3 (#206)
|
- CI builds against OpenSSL 3 (#206)
|
||||||
- Change the call signature of the following API:
|
- Change the call signature of the following API (#208):
|
||||||
- xmpp_conn_set_client_cert() - the PKCS#12 file has now to be passed via the `cert`
|
- xmpp_conn_set_client_cert() - the PKCS#12 file has now to be passed via the `cert`
|
||||||
parameter. Originally it was via `key`. Currently both styles are supported,
|
parameter. Originally it was via `key`. Currently both styles are supported,
|
||||||
but in a future release only passing via `cert` will be accepted.
|
but in a future release only passing via `cert` will be accepted.
|
||||||
|
|||||||
2
Doxyfile
2
Doxyfile
@@ -38,7 +38,7 @@ PROJECT_NAME = Strophe
|
|||||||
# could be handy for archiving the generated documentation or if some version
|
# could be handy for archiving the generated documentation or if some version
|
||||||
# control system is used.
|
# control system is used.
|
||||||
|
|
||||||
PROJECT_NUMBER = 0.12
|
PROJECT_NUMBER = 0.14
|
||||||
|
|
||||||
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
||||||
# for a project that appears at the top of each page and should give viewer a
|
# for a project that appears at the top of each page and should give viewer a
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
libstrophe XMPP client library
|
libstrophe XMPP client library
|
||||||
Copyright (C) 2005-2009 Collecta, Inc.
|
Copyright (C) 2005-2009 Collecta, Inc.
|
||||||
|
|
||||||
This program is dual licensed under the MIT and GPLv3 licenses.
|
This program is dual licensed under the MIT or GPLv3 licenses.
|
||||||
Please the files MIT-LICENSE.txt and GPL-LICENSE.txt for details.
|
Please the files MIT-LICENSE.txt and GPL-LICENSE.txt for details.
|
||||||
|
|||||||
42
Makefile.am
42
Makefile.am
@@ -10,6 +10,9 @@ COVERAGE_POST=@COVERAGE_POST@
|
|||||||
PARSER_CFLAGS=@PARSER_CFLAGS@
|
PARSER_CFLAGS=@PARSER_CFLAGS@
|
||||||
PARSER_LIBS=@PARSER_LIBS@
|
PARSER_LIBS=@PARSER_LIBS@
|
||||||
|
|
||||||
|
ZLIB_CFLAGS=@ZLIB_CFLAGS@
|
||||||
|
ZLIB_LIBS=@ZLIB_LIBS@
|
||||||
|
|
||||||
if TLS_WITH_GNUTLS
|
if TLS_WITH_GNUTLS
|
||||||
SSL_CFLAGS = @gnutls_CFLAGS@
|
SSL_CFLAGS = @gnutls_CFLAGS@
|
||||||
SSL_LIBS = @gnutls_LIBS@
|
SSL_LIBS = @gnutls_LIBS@
|
||||||
@@ -32,8 +35,8 @@ STROPHE_LIBS = $(COVERAGE_PRE) libstrophe.la $(COVERAGE_POST) $(COVERAGE_LDFLAGS
|
|||||||
## Main build targets
|
## Main build targets
|
||||||
lib_LTLIBRARIES = libstrophe.la
|
lib_LTLIBRARIES = libstrophe.la
|
||||||
|
|
||||||
libstrophe_la_CFLAGS = $(SSL_CFLAGS) $(STROPHE_FLAGS) $(PARSER_CFLAGS) $(RESOLV_CFLAGS) $(COVERAGE_CFLAGS)
|
libstrophe_la_CFLAGS = $(SSL_CFLAGS) $(STROPHE_FLAGS) $(PARSER_CFLAGS) $(RESOLV_CFLAGS) $(COVERAGE_CFLAGS) $(ZLIB_CFLAGS)
|
||||||
libstrophe_la_LDFLAGS = $(SSL_LIBS) $(PARSER_LIBS) $(RESOLV_LIBS) $(MINGW_LIBS) -no-undefined
|
libstrophe_la_LDFLAGS = $(SSL_LIBS) $(PARSER_LIBS) $(RESOLV_LIBS) $(MINGW_LIBS) $(ZLIB_LIBS) -no-undefined
|
||||||
# Export only public API
|
# Export only public API
|
||||||
libstrophe_la_LDFLAGS += -export-symbols-regex '^xmpp_' -version-info @VERSION_INFO@
|
libstrophe_la_LDFLAGS += -export-symbols-regex '^xmpp_' -version-info @VERSION_INFO@
|
||||||
|
|
||||||
@@ -82,6 +85,12 @@ if NEED_SNPRINTF
|
|||||||
libstrophe_la_SOURCES += src/snprintf.c
|
libstrophe_la_SOURCES += src/snprintf.c
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if DISABLE_COMPRESSION
|
||||||
|
libstrophe_la_SOURCES += src/compression_dummy.c
|
||||||
|
else
|
||||||
|
libstrophe_la_SOURCES += src/compression.c
|
||||||
|
endif
|
||||||
|
|
||||||
if DISABLE_TLS
|
if DISABLE_TLS
|
||||||
libstrophe_la_SOURCES += src/tls_dummy.c
|
libstrophe_la_SOURCES += src/tls_dummy.c
|
||||||
else
|
else
|
||||||
@@ -175,23 +184,30 @@ endif
|
|||||||
|
|
||||||
|
|
||||||
## Tests
|
## Tests
|
||||||
TESTS = \
|
STATIC_TESTS = \
|
||||||
tests/check_parser \
|
tests/check_parser \
|
||||||
|
tests/test_hash \
|
||||||
|
tests/test_jid \
|
||||||
|
tests/test_ctx \
|
||||||
|
tests/test_send_queue \
|
||||||
|
tests/test_serialize_sm \
|
||||||
|
tests/test_string \
|
||||||
|
tests/test_resolver
|
||||||
|
|
||||||
|
TESTS = \
|
||||||
tests/test_sha1 \
|
tests/test_sha1 \
|
||||||
tests/test_sha256 \
|
tests/test_sha256 \
|
||||||
tests/test_sha512 \
|
tests/test_sha512 \
|
||||||
tests/test_md5 \
|
tests/test_md5 \
|
||||||
tests/test_rand \
|
tests/test_rand \
|
||||||
tests/test_scram \
|
tests/test_scram \
|
||||||
tests/test_ctx \
|
|
||||||
tests/test_base64 \
|
tests/test_base64 \
|
||||||
tests/test_hash \
|
|
||||||
tests/test_jid \
|
|
||||||
tests/test_send_queue \
|
|
||||||
tests/test_snprintf \
|
tests/test_snprintf \
|
||||||
tests/test_string \
|
tests/test_stanza
|
||||||
tests/test_stanza \
|
|
||||||
tests/test_resolver
|
if !DISABLE_STATIC
|
||||||
|
TESTS += $(STATIC_TESTS)
|
||||||
|
endif
|
||||||
|
|
||||||
if !DISABLE_TLS
|
if !DISABLE_TLS
|
||||||
TESTS += tests/test_xmppaddr
|
TESTS += tests/test_xmppaddr
|
||||||
@@ -270,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
|
||||||
|
|
||||||
@@ -312,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
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ libstrophe is a lightweight XMPP client library written in C. It has
|
|||||||
minimal dependencies and is configurable for various environments. It
|
minimal dependencies and is configurable for various environments. It
|
||||||
runs well on Linux, Unix and Windows based platforms.
|
runs well on Linux, Unix and Windows based platforms.
|
||||||
|
|
||||||
libstrophe is dual licensed under MIT and GPLv3.
|
libstrophe is dual licensed under MIT or GPLv3.
|
||||||
|
|
||||||
Build Instructions
|
Build Instructions
|
||||||
------------------
|
------------------
|
||||||
@@ -88,7 +88,7 @@ or if you have everything configured properly:
|
|||||||
|
|
||||||
Then open `docs/html/index.html`.
|
Then open `docs/html/index.html`.
|
||||||
|
|
||||||
An online version of the documentation of the latest release is available on http://strophe.im/libstrophe/
|
An online version of the documentation of the latest release is available on https://strophe.im/libstrophe/
|
||||||
|
|
||||||
Releases
|
Releases
|
||||||
--------
|
--------
|
||||||
|
|||||||
25
configure.ac
25
configure.ac
@@ -1,6 +1,6 @@
|
|||||||
m4_define([v_maj], [0])
|
m4_define([v_maj], [0])
|
||||||
m4_define([v_min], [12])
|
m4_define([v_min], [14])
|
||||||
m4_define([v_patch], [3])
|
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"],
|
||||||
@@ -51,6 +52,8 @@ AC_ARG_ENABLE([cares],
|
|||||||
[AS_HELP_STRING([--enable-cares], [use c-ares for DNS resolution])])
|
[AS_HELP_STRING([--enable-cares], [use c-ares for DNS resolution])])
|
||||||
AC_ARG_ENABLE([getrandom],
|
AC_ARG_ENABLE([getrandom],
|
||||||
[AS_HELP_STRING([--disable-getrandom], [disable usage of the getrandom() system call])])
|
[AS_HELP_STRING([--disable-getrandom], [disable usage of the getrandom() system call])])
|
||||||
|
AC_ARG_ENABLE([zlib],
|
||||||
|
[AS_HELP_STRING([--disable-zlib], [disable compression support])])
|
||||||
|
|
||||||
AC_ARG_ENABLE([fuzzing],
|
AC_ARG_ENABLE([fuzzing],
|
||||||
[AS_HELP_STRING([--enable-fuzzing], [turn on fuzzing test])],
|
[AS_HELP_STRING([--enable-fuzzing], [turn on fuzzing test])],
|
||||||
@@ -247,6 +250,18 @@ fi
|
|||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if test "x$enable_zlib" != xno; then
|
||||||
|
PKG_CHECK_MODULES([zlib], [zlib >= 1.2.0],
|
||||||
|
[
|
||||||
|
PC_REQUIRES="zlib ${PC_REQUIRES}"
|
||||||
|
ZLIB_CFLAGS=$zlib_CFLAGS
|
||||||
|
ZLIB_LIBS=$zlib_LIBS
|
||||||
|
AC_DEFINE([HAVE_ZLIB])
|
||||||
|
],
|
||||||
|
[AC_MSG_ERROR([zlib not found])])
|
||||||
|
# TODO: if pkg-config doesn't find, check the library manually
|
||||||
|
fi
|
||||||
|
|
||||||
m4_ifdef([PKG_INSTALLDIR], [PKG_INSTALLDIR],
|
m4_ifdef([PKG_INSTALLDIR], [PKG_INSTALLDIR],
|
||||||
[AC_ARG_WITH([pkgconfigdir],
|
[AC_ARG_WITH([pkgconfigdir],
|
||||||
[AS_HELP_STRING([--with-pkgconfigdir],
|
[AS_HELP_STRING([--with-pkgconfigdir],
|
||||||
@@ -255,7 +270,9 @@ m4_ifdef([PKG_INSTALLDIR], [PKG_INSTALLDIR],
|
|||||||
AC_SUBST([pkgconfigdir], [${with_pkgconfigdir}])])
|
AC_SUBST([pkgconfigdir], [${with_pkgconfigdir}])])
|
||||||
|
|
||||||
AM_CONDITIONAL([PARSER_EXPAT], [test x$with_parser != xlibxml2])
|
AM_CONDITIONAL([PARSER_EXPAT], [test x$with_parser != xlibxml2])
|
||||||
|
AM_CONDITIONAL([DISABLE_COMPRESSION], [test x$enable_zlib = xno])
|
||||||
AM_CONDITIONAL([DISABLE_TLS], [test x$enable_tls = xno])
|
AM_CONDITIONAL([DISABLE_TLS], [test x$enable_tls = xno])
|
||||||
|
AM_CONDITIONAL([DISABLE_STATIC], [test x$enable_static = xno])
|
||||||
AM_CONDITIONAL([NEED_SNPRINTF], [test x$have_snprintf = xno])
|
AM_CONDITIONAL([NEED_SNPRINTF], [test x$have_snprintf = xno])
|
||||||
AM_CONDITIONAL([TLS_WITH_GNUTLS], [test x$with_gnutls = xyes])
|
AM_CONDITIONAL([TLS_WITH_GNUTLS], [test x$with_gnutls = xyes])
|
||||||
AM_CONDITIONAL([TLS_WITH_SCHANNEL], [test x$with_schannel = xyes])
|
AM_CONDITIONAL([TLS_WITH_SCHANNEL], [test x$with_schannel = xyes])
|
||||||
@@ -289,5 +306,7 @@ AC_SUBST(PARSER_LIBS)
|
|||||||
AC_SUBST(RESOLV_CFLAGS)
|
AC_SUBST(RESOLV_CFLAGS)
|
||||||
AC_SUBST(RESOLV_LIBS)
|
AC_SUBST(RESOLV_LIBS)
|
||||||
AC_SUBST(WARNING_FLAGS)
|
AC_SUBST(WARNING_FLAGS)
|
||||||
|
AC_SUBST(ZLIB_CFLAGS)
|
||||||
|
AC_SUBST(ZLIB_LIBS)
|
||||||
AC_CONFIG_FILES([Makefile libstrophe.pc])
|
AC_CONFIG_FILES([Makefile libstrophe.pc])
|
||||||
AC_OUTPUT
|
AC_OUTPUT
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
|
||||||
/* active.c
|
/* active.c
|
||||||
** libstrophe XMPP client library -- basic usage example
|
** libstrophe XMPP client library -- basic usage example
|
||||||
**
|
**
|
||||||
@@ -6,7 +7,7 @@
|
|||||||
** This software is provided AS-IS with no warranty, either express
|
** This software is provided AS-IS with no warranty, either express
|
||||||
** or implied.
|
** or implied.
|
||||||
**
|
**
|
||||||
** This program is dual licensed under the MIT and GPLv3 licenses.
|
** This program is dual licensed under the MIT or GPLv3 licenses.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* This example demonstrates basic handler functions by printing out
|
/* This example demonstrates basic handler functions by printing out
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
|
||||||
/* basic.c
|
/* basic.c
|
||||||
** libstrophe XMPP client library -- basic usage example
|
** libstrophe XMPP client library -- basic usage example
|
||||||
**
|
**
|
||||||
@@ -6,7 +7,7 @@
|
|||||||
** This software is provided AS-IS with no warranty, either express
|
** This software is provided AS-IS with no warranty, either express
|
||||||
** or implied.
|
** or implied.
|
||||||
**
|
**
|
||||||
** This program is dual licensed under the MIT and GPLv3 licenses.
|
** This program is dual licensed under the MIT or GPLv3 licenses.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
|
||||||
/* bot.c
|
/* bot.c
|
||||||
** libstrophe XMPP client library -- basic usage example
|
** libstrophe XMPP client library -- basic usage example
|
||||||
**
|
**
|
||||||
@@ -6,7 +7,7 @@
|
|||||||
** This software is provided AS-IS with no warranty, either express
|
** This software is provided AS-IS with no warranty, either express
|
||||||
** or implied.
|
** or implied.
|
||||||
**
|
**
|
||||||
** This program is dual licensed under the MIT and GPLv3 licenses.
|
** This program is dual licensed under the MIT or GPLv3 licenses.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* simple bot example
|
/* simple bot example
|
||||||
@@ -76,13 +77,19 @@ int version_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int _quit_handler(xmpp_conn_t *conn, void *userdata)
|
||||||
|
{
|
||||||
|
(void)userdata;
|
||||||
|
xmpp_disconnect(conn);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int message_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
|
int message_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
|
||||||
{
|
{
|
||||||
xmpp_ctx_t *ctx = (xmpp_ctx_t *)userdata;
|
xmpp_ctx_t *ctx = (xmpp_ctx_t *)userdata;
|
||||||
xmpp_stanza_t *body, *reply;
|
xmpp_stanza_t *body, *reply;
|
||||||
const char *type;
|
const char *type;
|
||||||
char *intext, *replytext;
|
char *intext, *replytext;
|
||||||
int quit = 0;
|
|
||||||
|
|
||||||
body = xmpp_stanza_get_child_by_name(stanza, "body");
|
body = xmpp_stanza_get_child_by_name(stanza, "body");
|
||||||
if (body == NULL)
|
if (body == NULL)
|
||||||
@@ -102,11 +109,11 @@ int message_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
|
|||||||
|
|
||||||
if (strcmp(intext, "quit") == 0) {
|
if (strcmp(intext, "quit") == 0) {
|
||||||
replytext = strdup("bye!");
|
replytext = strdup("bye!");
|
||||||
quit = 1;
|
xmpp_timed_handler_add(conn, _quit_handler, 500, NULL);
|
||||||
} else if (strcmp(intext, "reconnect") == 0) {
|
} else if (strcmp(intext, "reconnect") == 0) {
|
||||||
replytext = strdup("alright, let's see what happens!");
|
replytext = strdup("alright, let's see what happens!");
|
||||||
reconnect = 1;
|
reconnect = 1;
|
||||||
quit = 1;
|
xmpp_timed_handler_add(conn, _quit_handler, 500, NULL);
|
||||||
} else {
|
} else {
|
||||||
replytext = (char *)malloc(strlen(" to you too!") + strlen(intext) + 1);
|
replytext = (char *)malloc(strlen(" to you too!") + strlen(intext) + 1);
|
||||||
strcpy(replytext, intext);
|
strcpy(replytext, intext);
|
||||||
@@ -119,9 +126,6 @@ int message_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
|
|||||||
xmpp_stanza_release(reply);
|
xmpp_stanza_release(reply);
|
||||||
free(replytext);
|
free(replytext);
|
||||||
|
|
||||||
if (quit)
|
|
||||||
xmpp_disconnect(conn);
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -213,7 +217,10 @@ static void usage(int exit_code)
|
|||||||
" --legacy-ssl Use old style SSL.\n"
|
" --legacy-ssl Use old style SSL.\n"
|
||||||
" --legacy-auth Allow legacy authentication.\n"
|
" --legacy-auth Allow legacy authentication.\n"
|
||||||
"Note: --disable-tls conflicts with --mandatory-tls or "
|
"Note: --disable-tls conflicts with --mandatory-tls or "
|
||||||
"--legacy-ssl\n");
|
"--legacy-ssl\n"
|
||||||
|
" --zlib Enable compression via zlib.\n"
|
||||||
|
" --dont-reset When using zlib, don't do a full-flush "
|
||||||
|
"after compression.\n");
|
||||||
|
|
||||||
exit(exit_code);
|
exit(exit_code);
|
||||||
}
|
}
|
||||||
@@ -243,6 +250,10 @@ int main(int argc, char **argv)
|
|||||||
flags |= XMPP_CONN_FLAG_LEGACY_SSL;
|
flags |= XMPP_CONN_FLAG_LEGACY_SSL;
|
||||||
else if (strcmp(argv[i], "--legacy-auth") == 0)
|
else if (strcmp(argv[i], "--legacy-auth") == 0)
|
||||||
flags |= XMPP_CONN_FLAG_LEGACY_AUTH;
|
flags |= XMPP_CONN_FLAG_LEGACY_AUTH;
|
||||||
|
else if (strcmp(argv[i], "--zlib") == 0)
|
||||||
|
flags |= XMPP_CONN_FLAG_ENABLE_COMPRESSION;
|
||||||
|
else if (strcmp(argv[i], "--dont-reset") == 0)
|
||||||
|
flags |= XMPP_CONN_FLAG_COMPRESSION_DONT_RESET;
|
||||||
else if ((strcmp(argv[i], "--jid") == 0) && (++i < argc))
|
else if ((strcmp(argv[i], "--jid") == 0) && (++i < argc))
|
||||||
jid = argv[i];
|
jid = argv[i];
|
||||||
else if ((strcmp(argv[i], "--pass") == 0) && (++i < argc))
|
else if ((strcmp(argv[i], "--pass") == 0) && (++i < argc))
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
|
||||||
/* complex.c
|
/* complex.c
|
||||||
** libstrophe XMPP client library -- more complex usage example
|
** libstrophe XMPP client library -- more complex usage example
|
||||||
**
|
**
|
||||||
@@ -6,7 +7,7 @@
|
|||||||
** This software is provided AS-IS with no warranty, either express
|
** This software is provided AS-IS with no warranty, either express
|
||||||
** or implied.
|
** or implied.
|
||||||
**
|
**
|
||||||
** This program is dual licensed under the MIT and GPLv3 licenses.
|
** This program is dual licensed under the MIT or GPLv3 licenses.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@@ -238,6 +239,9 @@ static void usage(int exit_code)
|
|||||||
" --enable-certfail Enable certfail handler.\n"
|
" --enable-certfail Enable certfail handler.\n"
|
||||||
" --legacy-ssl Use old style SSL.\n"
|
" --legacy-ssl Use old style SSL.\n"
|
||||||
" --legacy-auth Allow legacy authentication.\n"
|
" --legacy-auth Allow legacy authentication.\n"
|
||||||
|
" --zlib Enable compression via zlib.\n"
|
||||||
|
" --dont-reset When using zlib, don't do a full-flush "
|
||||||
|
"after compression.\n"
|
||||||
" --verbose Increase the verbosity level.\n"
|
" --verbose Increase the verbosity level.\n"
|
||||||
" --tcp-keepalive Configure TCP keepalive.\n\n"
|
" --tcp-keepalive Configure TCP keepalive.\n\n"
|
||||||
"Note: --disable-tls conflicts with --mandatory-tls or "
|
"Note: --disable-tls conflicts with --mandatory-tls or "
|
||||||
@@ -272,6 +276,10 @@ int main(int argc, char **argv)
|
|||||||
flags |= XMPP_CONN_FLAG_LEGACY_SSL;
|
flags |= XMPP_CONN_FLAG_LEGACY_SSL;
|
||||||
else if (strcmp(argv[i], "--legacy-auth") == 0)
|
else if (strcmp(argv[i], "--legacy-auth") == 0)
|
||||||
flags |= XMPP_CONN_FLAG_LEGACY_AUTH;
|
flags |= XMPP_CONN_FLAG_LEGACY_AUTH;
|
||||||
|
else if (strcmp(argv[i], "--zlib") == 0)
|
||||||
|
flags |= XMPP_CONN_FLAG_ENABLE_COMPRESSION;
|
||||||
|
else if (strcmp(argv[i], "--dont-reset") == 0)
|
||||||
|
flags |= XMPP_CONN_FLAG_COMPRESSION_DONT_RESET;
|
||||||
else if (strcmp(argv[i], "--verbose") == 0)
|
else if (strcmp(argv[i], "--verbose") == 0)
|
||||||
verbosity++;
|
verbosity++;
|
||||||
else if (strcmp(argv[i], "--tcp-keepalive") == 0)
|
else if (strcmp(argv[i], "--tcp-keepalive") == 0)
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
|
||||||
/* component.c
|
/* component.c
|
||||||
** libstrophe XMPP client library -- external component (XEP-0114) example
|
** libstrophe XMPP client library -- external component (XEP-0114) example
|
||||||
**
|
**
|
||||||
@@ -6,7 +7,7 @@
|
|||||||
** This software is provided AS-IS with no warranty, either express
|
** This software is provided AS-IS with no warranty, either express
|
||||||
** or implied.
|
** or implied.
|
||||||
**
|
**
|
||||||
** This program is dual licensed under the MIT and GPLv3 licenses.
|
** This program is dual licensed under the MIT or GPLv3 licenses.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* This example demonstrates simple connection to a server
|
/* This example demonstrates simple connection to a server
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
|
||||||
/* perf.c
|
/* perf.c
|
||||||
* strophe XMPP client library -- performance measure
|
* strophe XMPP client library -- performance measure
|
||||||
*
|
*
|
||||||
@@ -6,7 +7,7 @@
|
|||||||
* This software is provided AS-IS with no warranty, either express
|
* This software is provided AS-IS with no warranty, either express
|
||||||
* or implied.
|
* or implied.
|
||||||
*
|
*
|
||||||
* This program is dual licensed under the MIT and GPLv3 licenses.
|
* This program is dual licensed under the MIT or GPLv3 licenses.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @file
|
/** @file
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
|
||||||
/* register.c
|
/* register.c
|
||||||
* strophe XMPP client library -- In-band registration (XEP-0077)
|
* strophe XMPP client library -- In-band registration (XEP-0077)
|
||||||
*
|
*
|
||||||
@@ -6,7 +7,7 @@
|
|||||||
* This software is provided AS-IS with no warranty, either express
|
* This software is provided AS-IS with no warranty, either express
|
||||||
* or implied.
|
* or implied.
|
||||||
*
|
*
|
||||||
* This program is dual licensed under the MIT and GPLv3 licenses.
|
* This program is dual licensed under the MIT or GPLv3 licenses.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
|
||||||
/* roster.c
|
/* roster.c
|
||||||
** libstrophe XMPP client library -- handler example
|
** libstrophe XMPP client library -- handler example
|
||||||
**
|
**
|
||||||
@@ -6,7 +7,7 @@
|
|||||||
** This software is provided AS-IS with no warranty, either express
|
** This software is provided AS-IS with no warranty, either express
|
||||||
** or implied.
|
** or implied.
|
||||||
**
|
**
|
||||||
** This program is dual licensed under the MIT and GPLv3 licenses.
|
** This program is dual licensed under the MIT or GPLv3 licenses.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* This example demonstrates basic handler functions by printing out
|
/* This example demonstrates basic handler functions by printing out
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
|
||||||
/* vcard.c
|
/* vcard.c
|
||||||
* strophe XMPP client library -- vCard example
|
* strophe XMPP client library -- vCard example
|
||||||
*
|
*
|
||||||
@@ -6,7 +7,7 @@
|
|||||||
* This software is provided AS-IS with no warranty, either express
|
* This software is provided AS-IS with no warranty, either express
|
||||||
* or implied.
|
* or implied.
|
||||||
*
|
*
|
||||||
* This program is dual licensed under the MIT and GPLv3 licenses.
|
* This program is dual licensed under the MIT or GPLv3 licenses.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ includedir=@includedir@
|
|||||||
|
|
||||||
Name: libstrophe
|
Name: libstrophe
|
||||||
Description: A simple, lightweight C library for writing XMPP clients
|
Description: A simple, lightweight C library for writing XMPP clients
|
||||||
URL: http://strophe.im/libstrophe/
|
URL: https://strophe.im/libstrophe/
|
||||||
Version: @VERSION@
|
Version: @VERSION@
|
||||||
Requires:
|
Requires:
|
||||||
Requires.private: @PC_REQUIRES@
|
Requires.private: @PC_REQUIRES@
|
||||||
|
|||||||
586
src/auth.c
586
src/auth.c
@@ -1,3 +1,4 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
|
||||||
/* auth.c
|
/* auth.c
|
||||||
** strophe XMPP client library -- auth functions and handlers
|
** strophe XMPP client library -- auth functions and handlers
|
||||||
**
|
**
|
||||||
@@ -6,7 +7,7 @@
|
|||||||
** This software is provided AS-IS with no warranty, either express or
|
** This software is provided AS-IS with no warranty, either express or
|
||||||
** implied.
|
** implied.
|
||||||
**
|
**
|
||||||
** This program is dual licensed under the MIT and GPLv3 licenses.
|
** This program is dual licensed under the MIT or GPLv3 licenses.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @file
|
/** @file
|
||||||
@@ -61,6 +62,7 @@
|
|||||||
|
|
||||||
static void _auth(xmpp_conn_t *conn);
|
static void _auth(xmpp_conn_t *conn);
|
||||||
static void _auth_legacy(xmpp_conn_t *conn);
|
static void _auth_legacy(xmpp_conn_t *conn);
|
||||||
|
static void _handle_open_compress(xmpp_conn_t *conn);
|
||||||
static void _handle_open_sasl(xmpp_conn_t *conn);
|
static void _handle_open_sasl(xmpp_conn_t *conn);
|
||||||
static void _handle_open_tls(xmpp_conn_t *conn);
|
static void _handle_open_tls(xmpp_conn_t *conn);
|
||||||
|
|
||||||
@@ -71,6 +73,9 @@ static int _handle_component_hs_response(xmpp_conn_t *conn,
|
|||||||
|
|
||||||
static int
|
static int
|
||||||
_handle_features_sasl(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata);
|
_handle_features_sasl(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata);
|
||||||
|
static int _handle_features_compress(xmpp_conn_t *conn,
|
||||||
|
xmpp_stanza_t *stanza,
|
||||||
|
void *userdata);
|
||||||
static int
|
static int
|
||||||
_handle_sasl_result(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata);
|
_handle_sasl_result(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata);
|
||||||
static int _handle_digestmd5_challenge(xmpp_conn_t *conn,
|
static int _handle_digestmd5_challenge(xmpp_conn_t *conn,
|
||||||
@@ -82,7 +87,8 @@ static int _handle_digestmd5_rspauth(xmpp_conn_t *conn,
|
|||||||
static int _handle_scram_challenge(xmpp_conn_t *conn,
|
static int _handle_scram_challenge(xmpp_conn_t *conn,
|
||||||
xmpp_stanza_t *stanza,
|
xmpp_stanza_t *stanza,
|
||||||
void *userdata);
|
void *userdata);
|
||||||
static char *_make_scram_init_msg(xmpp_conn_t *conn);
|
struct scram_user_data;
|
||||||
|
static int _make_scram_init_msg(struct scram_user_data *scram);
|
||||||
|
|
||||||
static int _handle_missing_features_sasl(xmpp_conn_t *conn, void *userdata);
|
static int _handle_missing_features_sasl(xmpp_conn_t *conn, void *userdata);
|
||||||
static int _handle_missing_bind(xmpp_conn_t *conn, void *userdata);
|
static int _handle_missing_bind(xmpp_conn_t *conn, void *userdata);
|
||||||
@@ -205,12 +211,54 @@ static int _handle_missing_features(xmpp_conn_t *conn, void *userdata)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef void (*text_handler)(xmpp_conn_t *conn, const char *text);
|
||||||
|
static void _foreach_child(xmpp_conn_t *conn,
|
||||||
|
xmpp_stanza_t *parent,
|
||||||
|
const char *name,
|
||||||
|
text_handler hndl)
|
||||||
|
{
|
||||||
|
xmpp_stanza_t *children;
|
||||||
|
for (children = xmpp_stanza_get_children(parent); children;
|
||||||
|
children = xmpp_stanza_get_next(children)) {
|
||||||
|
const char *child_name = xmpp_stanza_get_name(children);
|
||||||
|
if (child_name && strcmp(child_name, name) == 0) {
|
||||||
|
char *text = xmpp_stanza_get_text(children);
|
||||||
|
if (text == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
hndl(conn, text);
|
||||||
|
|
||||||
|
strophe_free(conn->ctx, text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _handle_sasl_children(xmpp_conn_t *conn, const char *text)
|
||||||
|
{
|
||||||
|
if (strcasecmp(text, "PLAIN") == 0) {
|
||||||
|
conn->sasl_support |= SASL_MASK_PLAIN;
|
||||||
|
} else if (strcasecmp(text, "EXTERNAL") == 0 &&
|
||||||
|
(conn->tls_client_cert || conn->tls_client_key)) {
|
||||||
|
conn->sasl_support |= SASL_MASK_EXTERNAL;
|
||||||
|
} else if (strcasecmp(text, "DIGEST-MD5") == 0) {
|
||||||
|
conn->sasl_support |= SASL_MASK_DIGESTMD5;
|
||||||
|
} else if (strcasecmp(text, "ANONYMOUS") == 0) {
|
||||||
|
conn->sasl_support |= SASL_MASK_ANONYMOUS;
|
||||||
|
} else {
|
||||||
|
size_t n;
|
||||||
|
for (n = 0; n < scram_algs_num; ++n) {
|
||||||
|
if (strcasecmp(text, scram_algs[n]->scram_name) == 0) {
|
||||||
|
conn->sasl_support |= scram_algs[n]->mask;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
_handle_features(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
|
_handle_features(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
|
||||||
{
|
{
|
||||||
xmpp_stanza_t *child, *mech;
|
xmpp_stanza_t *child;
|
||||||
const char *ns;
|
|
||||||
char *text;
|
|
||||||
|
|
||||||
UNUSED(userdata);
|
UNUSED(userdata);
|
||||||
|
|
||||||
@@ -220,10 +268,9 @@ _handle_features(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
|
|||||||
/* check for TLS */
|
/* check for TLS */
|
||||||
if (!conn->secured) {
|
if (!conn->secured) {
|
||||||
if (!conn->tls_disabled) {
|
if (!conn->tls_disabled) {
|
||||||
child = xmpp_stanza_get_child_by_name(stanza, "starttls");
|
if (xmpp_stanza_get_child_by_name_and_ns(stanza, "starttls",
|
||||||
if (child) {
|
XMPP_NS_TLS)) {
|
||||||
ns = xmpp_stanza_get_ns(child);
|
conn->tls_support = 1;
|
||||||
conn->tls_support = ns != NULL && strcmp(ns, XMPP_NS_TLS) == 0;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
conn->tls_support = 0;
|
conn->tls_support = 0;
|
||||||
@@ -231,36 +278,10 @@ _handle_features(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* check for SASL */
|
/* check for SASL */
|
||||||
child = xmpp_stanza_get_child_by_name(stanza, "mechanisms");
|
child = xmpp_stanza_get_child_by_name_and_ns(stanza, "mechanisms",
|
||||||
ns = child ? xmpp_stanza_get_ns(child) : NULL;
|
XMPP_NS_SASL);
|
||||||
if (child && ns && strcmp(ns, XMPP_NS_SASL) == 0) {
|
if (child) {
|
||||||
for (mech = xmpp_stanza_get_children(child); mech;
|
_foreach_child(conn, child, "mechanism", _handle_sasl_children);
|
||||||
mech = xmpp_stanza_get_next(mech)) {
|
|
||||||
if (xmpp_stanza_get_name(mech) &&
|
|
||||||
strcmp(xmpp_stanza_get_name(mech), "mechanism") == 0) {
|
|
||||||
text = xmpp_stanza_get_text(mech);
|
|
||||||
if (text == NULL)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (strcasecmp(text, "PLAIN") == 0)
|
|
||||||
conn->sasl_support |= SASL_MASK_PLAIN;
|
|
||||||
else if (strcasecmp(text, "EXTERNAL") == 0 &&
|
|
||||||
(conn->tls_client_cert || conn->tls_client_key))
|
|
||||||
conn->sasl_support |= SASL_MASK_EXTERNAL;
|
|
||||||
else if (strcasecmp(text, "DIGEST-MD5") == 0)
|
|
||||||
conn->sasl_support |= SASL_MASK_DIGESTMD5;
|
|
||||||
else if (strcasecmp(text, "SCRAM-SHA-1") == 0)
|
|
||||||
conn->sasl_support |= SASL_MASK_SCRAMSHA1;
|
|
||||||
else if (strcasecmp(text, "SCRAM-SHA-256") == 0)
|
|
||||||
conn->sasl_support |= SASL_MASK_SCRAMSHA256;
|
|
||||||
else if (strcasecmp(text, "SCRAM-SHA-512") == 0)
|
|
||||||
conn->sasl_support |= SASL_MASK_SCRAMSHA512;
|
|
||||||
else if (strcasecmp(text, "ANONYMOUS") == 0)
|
|
||||||
conn->sasl_support |= SASL_MASK_ANONYMOUS;
|
|
||||||
|
|
||||||
strophe_free(conn->ctx, text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Disable PLAIN when other secure mechanisms are supported */
|
/* Disable PLAIN when other secure mechanisms are supported */
|
||||||
@@ -334,7 +355,9 @@ _handle_sasl_result(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
|
|||||||
(char *)userdata);
|
(char *)userdata);
|
||||||
|
|
||||||
/* reset parser */
|
/* reset parser */
|
||||||
conn_prepare_reset(conn, _handle_open_sasl);
|
conn_prepare_reset(conn, conn->compression.allowed
|
||||||
|
? _handle_open_compress
|
||||||
|
: _handle_open_sasl);
|
||||||
|
|
||||||
/* send stream tag */
|
/* send stream tag */
|
||||||
conn_open_stream(conn);
|
conn_open_stream(conn);
|
||||||
@@ -438,7 +461,11 @@ static int _handle_digestmd5_rspauth(xmpp_conn_t *conn,
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct scram_user_data {
|
struct scram_user_data {
|
||||||
|
xmpp_conn_t *conn;
|
||||||
|
int sasl_plus;
|
||||||
char *scram_init;
|
char *scram_init;
|
||||||
|
char *channel_binding;
|
||||||
|
const char *first_bare;
|
||||||
const struct hash_alg *alg;
|
const struct hash_alg *alg;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -470,8 +497,9 @@ static int _handle_scram_challenge(xmpp_conn_t *conn,
|
|||||||
if (!challenge)
|
if (!challenge)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
response = sasl_scram(conn->ctx, scram_ctx->alg, challenge,
|
response =
|
||||||
scram_ctx->scram_init, conn->jid, conn->pass);
|
sasl_scram(conn->ctx, scram_ctx->alg, scram_ctx->channel_binding,
|
||||||
|
challenge, scram_ctx->first_bare, conn->jid, conn->pass);
|
||||||
strophe_free(conn->ctx, challenge);
|
strophe_free(conn->ctx, challenge);
|
||||||
if (!response)
|
if (!response)
|
||||||
goto err;
|
goto err;
|
||||||
@@ -505,7 +533,8 @@ static int _handle_scram_challenge(xmpp_conn_t *conn,
|
|||||||
*/
|
*/
|
||||||
rc = _handle_sasl_result(conn, stanza,
|
rc = _handle_sasl_result(conn, stanza,
|
||||||
(void *)scram_ctx->alg->scram_name);
|
(void *)scram_ctx->alg->scram_name);
|
||||||
strophe_free(conn->ctx, scram_ctx->scram_init);
|
strophe_free_and_null(conn->ctx, scram_ctx->channel_binding);
|
||||||
|
strophe_free_and_null(conn->ctx, scram_ctx->scram_init);
|
||||||
strophe_free(conn->ctx, scram_ctx);
|
strophe_free(conn->ctx, scram_ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -516,33 +545,103 @@ err_release_auth:
|
|||||||
err_free_response:
|
err_free_response:
|
||||||
strophe_free(conn->ctx, response);
|
strophe_free(conn->ctx, response);
|
||||||
err:
|
err:
|
||||||
strophe_free(conn->ctx, scram_ctx->scram_init);
|
strophe_free_and_null(conn->ctx, scram_ctx->channel_binding);
|
||||||
|
strophe_free_and_null(conn->ctx, scram_ctx->scram_init);
|
||||||
strophe_free(conn->ctx, scram_ctx);
|
strophe_free(conn->ctx, scram_ctx);
|
||||||
disconnect_mem_error(conn);
|
disconnect_mem_error(conn);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *_make_scram_init_msg(xmpp_conn_t *conn)
|
static int _make_scram_init_msg(struct scram_user_data *scram)
|
||||||
{
|
{
|
||||||
|
xmpp_conn_t *conn = scram->conn;
|
||||||
xmpp_ctx_t *ctx = conn->ctx;
|
xmpp_ctx_t *ctx = conn->ctx;
|
||||||
size_t message_len;
|
const void *binding_data;
|
||||||
char *node;
|
const char *binding_type;
|
||||||
char *message;
|
char *node, *message;
|
||||||
char nonce[32];
|
size_t message_len, binding_type_len = 0, binding_data_len;
|
||||||
|
int l, is_secured = xmpp_conn_is_secured(conn);
|
||||||
|
/* This buffer must be able to hold:
|
||||||
|
* "p=<10 bytes binding type>,,<36 bytes binding data>"
|
||||||
|
* + alignment */
|
||||||
|
char buf[56];
|
||||||
|
|
||||||
|
if (scram->sasl_plus) {
|
||||||
|
if (!is_secured) {
|
||||||
|
strophe_error(
|
||||||
|
ctx, "xmpp",
|
||||||
|
"SASL: Server requested a -PLUS variant to authenticate, "
|
||||||
|
"but the connection is not secured. This is an error on "
|
||||||
|
"the server side we can't do anything about.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (tls_init_channel_binding(conn->tls, &binding_type,
|
||||||
|
&binding_type_len)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
/* directly account for the '=' char in 'p=<binding-type>' */
|
||||||
|
binding_type_len += 1;
|
||||||
|
}
|
||||||
|
|
||||||
node = xmpp_jid_node(ctx, conn->jid);
|
node = xmpp_jid_node(ctx, conn->jid);
|
||||||
if (!node) {
|
if (!node) {
|
||||||
return NULL;
|
return -1;
|
||||||
}
|
}
|
||||||
xmpp_rand_nonce(ctx->rand, nonce, sizeof(nonce));
|
/* 32 bytes nonce is enough */
|
||||||
message_len = strlen(node) + strlen(nonce) + 8 + 1;
|
xmpp_rand_nonce(ctx->rand, buf, 33);
|
||||||
|
message_len = strlen(node) + strlen(buf) + 8 + binding_type_len + 1;
|
||||||
message = strophe_alloc(ctx, message_len);
|
message = strophe_alloc(ctx, message_len);
|
||||||
if (message) {
|
if (!message) {
|
||||||
strophe_snprintf(message, message_len, "n,,n=%s,r=%s", node, nonce);
|
goto err_node;
|
||||||
}
|
}
|
||||||
|
/* increase length to account for 'y,,', 'n,,' or 'p,,'.
|
||||||
|
* In the 'p' case the '=' sign has already been accounted for above.
|
||||||
|
*/
|
||||||
|
binding_type_len += 3;
|
||||||
|
if (scram->sasl_plus) {
|
||||||
|
l = strophe_snprintf(message, message_len, "p=%s,,n=%s,r=%s",
|
||||||
|
binding_type, node, buf);
|
||||||
|
} else {
|
||||||
|
l = strophe_snprintf(message, message_len, "%c,,n=%s,r=%s",
|
||||||
|
is_secured ? 'y' : 'n', node, buf);
|
||||||
|
}
|
||||||
|
if (l < 0 || (size_t)l >= message_len) {
|
||||||
|
goto err_msg;
|
||||||
|
}
|
||||||
|
if (binding_type_len > sizeof(buf)) {
|
||||||
|
goto err_msg;
|
||||||
|
}
|
||||||
|
/* Make `first_bare` point to the 'n' of 'n=<node>' of the
|
||||||
|
* client-first-message */
|
||||||
|
scram->first_bare = message + binding_type_len;
|
||||||
|
memcpy(buf, message, binding_type_len);
|
||||||
|
if (scram->sasl_plus) {
|
||||||
|
binding_data =
|
||||||
|
tls_get_channel_binding_data(conn->tls, &binding_data_len);
|
||||||
|
if (!binding_data) {
|
||||||
|
goto err_msg;
|
||||||
|
}
|
||||||
|
if (binding_data_len > sizeof(buf) - binding_type_len) {
|
||||||
|
strophe_error(ctx, "xmpp", "Channel binding data is too long (%zu)",
|
||||||
|
binding_data_len);
|
||||||
|
goto err_msg;
|
||||||
|
}
|
||||||
|
memcpy(&buf[binding_type_len], binding_data, binding_data_len);
|
||||||
|
binding_type_len += binding_data_len;
|
||||||
|
}
|
||||||
|
scram->channel_binding =
|
||||||
|
xmpp_base64_encode(ctx, (void *)buf, binding_type_len);
|
||||||
|
memset(buf, 0, binding_type_len);
|
||||||
strophe_free(ctx, node);
|
strophe_free(ctx, node);
|
||||||
|
scram->scram_init = message;
|
||||||
|
|
||||||
return message;
|
return 0;
|
||||||
|
|
||||||
|
err_msg:
|
||||||
|
strophe_free(ctx, message);
|
||||||
|
err_node:
|
||||||
|
strophe_free(ctx, node);
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static xmpp_stanza_t *_make_starttls(xmpp_conn_t *conn)
|
static xmpp_stanza_t *_make_starttls(xmpp_conn_t *conn)
|
||||||
@@ -635,7 +734,7 @@ static void _auth(xmpp_conn_t *conn)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (anonjid && conn->sasl_support & SASL_MASK_ANONYMOUS) {
|
if (anonjid && (conn->sasl_support & SASL_MASK_ANONYMOUS)) {
|
||||||
/* some crap here */
|
/* some crap here */
|
||||||
auth = _make_sasl_auth(conn, "ANONYMOUS");
|
auth = _make_sasl_auth(conn, "ANONYMOUS");
|
||||||
if (!auth) {
|
if (!auth) {
|
||||||
@@ -701,22 +800,26 @@ static void _auth(xmpp_conn_t *conn)
|
|||||||
"Password hasn't been set, and SASL ANONYMOUS unsupported.");
|
"Password hasn't been set, and SASL ANONYMOUS unsupported.");
|
||||||
xmpp_disconnect(conn);
|
xmpp_disconnect(conn);
|
||||||
} else if (conn->sasl_support & SASL_MASK_SCRAM) {
|
} else if (conn->sasl_support & SASL_MASK_SCRAM) {
|
||||||
|
size_t n;
|
||||||
scram_ctx = strophe_alloc(conn->ctx, sizeof(*scram_ctx));
|
scram_ctx = strophe_alloc(conn->ctx, sizeof(*scram_ctx));
|
||||||
if (conn->sasl_support & SASL_MASK_SCRAMSHA512)
|
memset(scram_ctx, 0, sizeof(*scram_ctx));
|
||||||
scram_ctx->alg = &scram_sha512;
|
for (n = 0; n < scram_algs_num; ++n) {
|
||||||
else if (conn->sasl_support & SASL_MASK_SCRAMSHA256)
|
if (conn->sasl_support & scram_algs[n]->mask) {
|
||||||
scram_ctx->alg = &scram_sha256;
|
scram_ctx->alg = scram_algs[n];
|
||||||
else if (conn->sasl_support & SASL_MASK_SCRAMSHA1)
|
break;
|
||||||
scram_ctx->alg = &scram_sha1;
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auth = _make_sasl_auth(conn, scram_ctx->alg->scram_name);
|
auth = _make_sasl_auth(conn, scram_ctx->alg->scram_name);
|
||||||
if (!auth) {
|
if (!auth) {
|
||||||
disconnect_mem_error(conn);
|
disconnect_mem_error(conn);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* don't free scram_init on success */
|
scram_ctx->conn = conn;
|
||||||
scram_ctx->scram_init = _make_scram_init_msg(conn);
|
scram_ctx->sasl_plus =
|
||||||
if (!scram_ctx->scram_init) {
|
scram_ctx->alg->mask & SASL_MASK_SCRAM_PLUS ? 1 : 0;
|
||||||
|
if (_make_scram_init_msg(scram_ctx)) {
|
||||||
strophe_free(conn->ctx, scram_ctx);
|
strophe_free(conn->ctx, scram_ctx);
|
||||||
xmpp_stanza_release(auth);
|
xmpp_stanza_release(auth);
|
||||||
disconnect_mem_error(conn);
|
disconnect_mem_error(conn);
|
||||||
@@ -752,7 +855,7 @@ static void _auth(xmpp_conn_t *conn)
|
|||||||
|
|
||||||
send_stanza(conn, auth, XMPP_QUEUE_STROPHE);
|
send_stanza(conn, auth, XMPP_QUEUE_STROPHE);
|
||||||
|
|
||||||
/* SASL SCRAM-SHA-1 was tried, unset flag */
|
/* SASL algorithm was tried, unset flag */
|
||||||
conn->sasl_support &= ~scram_ctx->alg->mask;
|
conn->sasl_support &= ~scram_ctx->alg->mask;
|
||||||
} else if (conn->sasl_support & SASL_MASK_DIGESTMD5) {
|
} else if (conn->sasl_support & SASL_MASK_DIGESTMD5) {
|
||||||
auth = _make_sasl_auth(conn, "DIGEST-MD5");
|
auth = _make_sasl_auth(conn, "DIGEST-MD5");
|
||||||
@@ -812,10 +915,10 @@ static void _auth(xmpp_conn_t *conn)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _auth_success(xmpp_conn_t *conn)
|
static void _stream_negotiation_success(xmpp_conn_t *conn)
|
||||||
{
|
{
|
||||||
tls_clear_password_cache(conn);
|
tls_clear_password_cache(conn);
|
||||||
conn->authenticated = 1;
|
conn->stream_negotiation_completed = 1;
|
||||||
/* call connection handler */
|
/* call connection handler */
|
||||||
conn->conn_handler(conn, XMPP_CONN_CONNECT, 0, NULL, conn->userdata);
|
conn->conn_handler(conn, XMPP_CONN_CONNECT, 0, NULL, conn->userdata);
|
||||||
}
|
}
|
||||||
@@ -865,6 +968,17 @@ static void _handle_open_sasl(xmpp_conn_t *conn)
|
|||||||
NULL);
|
NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* called when stream:stream tag received after compression has been enabled */
|
||||||
|
static void _handle_open_compress(xmpp_conn_t *conn)
|
||||||
|
{
|
||||||
|
strophe_debug(conn->ctx, "xmpp", "Reopened stream successfully.");
|
||||||
|
|
||||||
|
/* setup stream:features handlers */
|
||||||
|
handler_add(conn, _handle_features_compress, XMPP_NS_STREAMS, "features",
|
||||||
|
NULL, NULL);
|
||||||
|
handler_add_timed(conn, _handle_missing_features, FEATURES_TIMEOUT, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
static int _do_bind(xmpp_conn_t *conn, xmpp_stanza_t *bind)
|
static int _do_bind(xmpp_conn_t *conn, xmpp_stanza_t *bind)
|
||||||
{
|
{
|
||||||
xmpp_stanza_t *iq, *res, *text;
|
xmpp_stanza_t *iq, *res, *text;
|
||||||
@@ -877,6 +991,7 @@ static int _do_bind(xmpp_conn_t *conn, xmpp_stanza_t *bind)
|
|||||||
/* send bind request */
|
/* send bind request */
|
||||||
iq = xmpp_iq_new(conn->ctx, "set", "_xmpp_bind1");
|
iq = xmpp_iq_new(conn->ctx, "set", "_xmpp_bind1");
|
||||||
if (!iq) {
|
if (!iq) {
|
||||||
|
xmpp_stanza_release(bind);
|
||||||
disconnect_mem_error(conn);
|
disconnect_mem_error(conn);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -921,24 +1036,78 @@ static int _do_bind(xmpp_conn_t *conn, xmpp_stanza_t *bind)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int _handle_compress_result(xmpp_conn_t *const conn,
|
||||||
|
xmpp_stanza_t *const stanza,
|
||||||
|
void *const userdata)
|
||||||
|
{
|
||||||
|
const char *name = xmpp_stanza_get_name(stanza);
|
||||||
|
|
||||||
|
UNUSED(userdata);
|
||||||
|
|
||||||
|
if (!name)
|
||||||
|
return 0;
|
||||||
|
if (strcmp(name, "compressed") == 0) {
|
||||||
|
/* Stream compression enabled, we need to restart the stream */
|
||||||
|
strophe_debug(conn->ctx, "xmpp", "Stream compression enabled");
|
||||||
|
|
||||||
|
/* reset parser */
|
||||||
|
conn_prepare_reset(conn, _handle_open_sasl);
|
||||||
|
|
||||||
|
/* make compression effective */
|
||||||
|
compression_init(conn);
|
||||||
|
|
||||||
|
/* send stream tag */
|
||||||
|
conn_open_stream(conn);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _handle_features_compress(xmpp_conn_t *conn,
|
||||||
|
xmpp_stanza_t *stanza,
|
||||||
|
void *userdata)
|
||||||
|
{
|
||||||
|
const char *compress = "<compress xmlns='" XMPP_NS_COMPRESSION
|
||||||
|
"'><method>zlib</method></compress>";
|
||||||
|
xmpp_stanza_t *child;
|
||||||
|
|
||||||
|
/* remove missing features handler */
|
||||||
|
xmpp_timed_handler_delete(conn, _handle_missing_features);
|
||||||
|
|
||||||
|
/* check for compression */
|
||||||
|
child = xmpp_stanza_get_child_by_name_and_ns(stanza, "compression",
|
||||||
|
XMPP_NS_FEATURE_COMPRESSION);
|
||||||
|
if (conn->compression.allowed && child) {
|
||||||
|
_foreach_child(conn, child, "method",
|
||||||
|
compression_handle_feature_children);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (conn->compression.supported) {
|
||||||
|
send_raw(conn, compress, strlen(compress), XMPP_QUEUE_STROPHE, NULL);
|
||||||
|
handler_add(conn, _handle_compress_result, XMPP_NS_COMPRESSION, NULL,
|
||||||
|
NULL, NULL);
|
||||||
|
} else {
|
||||||
|
return _handle_features_sasl(conn, stanza, userdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
_handle_features_sasl(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
|
_handle_features_sasl(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
|
||||||
{
|
{
|
||||||
xmpp_stanza_t *bind, *session, *opt;
|
xmpp_stanza_t *bind, *session;
|
||||||
xmpp_stanza_t *resume;
|
xmpp_stanza_t *resume;
|
||||||
const char *ns;
|
|
||||||
char h[11];
|
char h[11];
|
||||||
|
|
||||||
UNUSED(userdata);
|
UNUSED(userdata);
|
||||||
|
|
||||||
/* remove missing features handler */
|
/* Remove missing features handler */
|
||||||
xmpp_timed_handler_delete(conn, _handle_missing_features_sasl);
|
xmpp_timed_handler_delete(conn, _handle_missing_features_sasl);
|
||||||
|
|
||||||
/* check whether resource binding is required */
|
/* Check whether resource binding is required */
|
||||||
bind = xmpp_stanza_get_child_by_name(stanza, "bind");
|
bind = xmpp_stanza_get_child_by_name_and_ns(stanza, "bind", XMPP_NS_BIND);
|
||||||
if (bind) {
|
if (bind) {
|
||||||
ns = xmpp_stanza_get_ns(bind);
|
conn->bind_required = 1;
|
||||||
conn->bind_required = ns != NULL && strcmp(ns, XMPP_NS_BIND) == 0;
|
|
||||||
bind = xmpp_stanza_copy(bind);
|
bind = xmpp_stanza_copy(bind);
|
||||||
if (!bind) {
|
if (!bind) {
|
||||||
disconnect_mem_error(conn);
|
disconnect_mem_error(conn);
|
||||||
@@ -948,25 +1117,31 @@ _handle_features_sasl(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
|
|||||||
conn->bind_required = 0;
|
conn->bind_required = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check whether session establishment is required */
|
/* Check whether session establishment is required.
|
||||||
session = xmpp_stanza_get_child_by_name(stanza, "session");
|
*
|
||||||
|
* The mechanism is deprecated, but we still support it.
|
||||||
|
*
|
||||||
|
* RFC3921 contains Ch. 3 "Session Establishment".
|
||||||
|
*
|
||||||
|
* RFC6121 removes this and explains in Ch. 1.4:
|
||||||
|
* "Interoperability Note: [...] Implementation and deployment experience
|
||||||
|
* has shown that this additional step is unnecessary. [...]" */
|
||||||
|
session = xmpp_stanza_get_child_by_name_and_ns(stanza, "session",
|
||||||
|
XMPP_NS_SESSION);
|
||||||
if (session) {
|
if (session) {
|
||||||
ns = xmpp_stanza_get_ns(session);
|
conn->session_required =
|
||||||
opt = xmpp_stanza_get_child_by_name(session, "optional");
|
xmpp_stanza_get_child_by_name(session, "optional") == NULL;
|
||||||
if (!opt)
|
|
||||||
conn->session_required =
|
|
||||||
ns != NULL && strcmp(ns, XMPP_NS_SESSION) == 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check stream-management support */
|
||||||
if (xmpp_stanza_get_child_by_name_and_ns(stanza, "sm", XMPP_NS_SM)) {
|
if (xmpp_stanza_get_child_by_name_and_ns(stanza, "sm", XMPP_NS_SM)) {
|
||||||
/* stream management supported */
|
|
||||||
conn->sm_state->sm_support = 1;
|
conn->sm_state->sm_support = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* we are expecting either <bind/> and <session/> since this is a
|
/* We are expecting either <bind/> and optionally <session/> since this is a
|
||||||
XMPP style connection or we <resume/> the previous session */
|
XMPP style connection or we <resume/> the previous session */
|
||||||
|
|
||||||
/* check whether we can <resume/> the previous session */
|
/* Check whether we can <resume/> the previous session */
|
||||||
if (!conn->sm_disable && conn->sm_state->can_resume &&
|
if (!conn->sm_disable && conn->sm_state->can_resume &&
|
||||||
conn->sm_state->previd && conn->sm_state->bound_jid) {
|
conn->sm_state->previd && conn->sm_state->bound_jid) {
|
||||||
resume = xmpp_stanza_new(conn->ctx);
|
resume = xmpp_stanza_new(conn->ctx);
|
||||||
@@ -1013,11 +1188,58 @@ static int _handle_missing_features_sasl(xmpp_conn_t *conn, void *userdata)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void _session_start(xmpp_conn_t *conn)
|
||||||
|
{
|
||||||
|
xmpp_stanza_t *session;
|
||||||
|
xmpp_stanza_t *iq = xmpp_iq_new(conn->ctx, "set", "_xmpp_session1");
|
||||||
|
if (!iq) {
|
||||||
|
disconnect_mem_error(conn);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
session = xmpp_stanza_new(conn->ctx);
|
||||||
|
if (!session) {
|
||||||
|
xmpp_stanza_release(iq);
|
||||||
|
disconnect_mem_error(conn);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* setup response handlers */
|
||||||
|
handler_add_id(conn, _handle_session, "_xmpp_session1", NULL);
|
||||||
|
handler_add_timed(conn, _handle_missing_session, SESSION_TIMEOUT, NULL);
|
||||||
|
|
||||||
|
xmpp_stanza_set_name(session, "session");
|
||||||
|
xmpp_stanza_set_ns(session, XMPP_NS_SESSION);
|
||||||
|
|
||||||
|
xmpp_stanza_add_child_ex(iq, session, 0);
|
||||||
|
|
||||||
|
/* send session establishment request */
|
||||||
|
send_stanza(conn, iq, XMPP_QUEUE_STROPHE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _sm_enable(xmpp_conn_t *conn)
|
||||||
|
{
|
||||||
|
xmpp_stanza_t *enable = xmpp_stanza_new(conn->ctx);
|
||||||
|
if (!enable) {
|
||||||
|
disconnect_mem_error(conn);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
xmpp_stanza_set_name(enable, "enable");
|
||||||
|
xmpp_stanza_set_ns(enable, XMPP_NS_SM);
|
||||||
|
if (!conn->sm_state->dont_request_resume)
|
||||||
|
xmpp_stanza_set_attribute(enable, "resume", "true");
|
||||||
|
handler_add(conn, _handle_sm, XMPP_NS_SM, NULL, NULL, NULL);
|
||||||
|
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
|
static int
|
||||||
_handle_bind(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
|
_handle_bind(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
|
||||||
{
|
{
|
||||||
const char *type;
|
const char *type;
|
||||||
xmpp_stanza_t *iq, *enable, *session, *binding, *jid_stanza;
|
xmpp_stanza_t *binding, *jid_stanza;
|
||||||
|
|
||||||
UNUSED(userdata);
|
UNUSED(userdata);
|
||||||
|
|
||||||
@@ -1042,50 +1264,18 @@ _handle_bind(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
|
|||||||
|
|
||||||
/* establish a session if required */
|
/* establish a session if required */
|
||||||
if (conn->session_required) {
|
if (conn->session_required) {
|
||||||
/* setup response handlers */
|
_session_start(conn);
|
||||||
handler_add_id(conn, _handle_session, "_xmpp_session1", NULL);
|
|
||||||
handler_add_timed(conn, _handle_missing_session, SESSION_TIMEOUT,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
/* send session request */
|
|
||||||
iq = xmpp_iq_new(conn->ctx, "set", "_xmpp_session1");
|
|
||||||
if (!iq) {
|
|
||||||
disconnect_mem_error(conn);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
session = xmpp_stanza_new(conn->ctx);
|
|
||||||
if (!session) {
|
|
||||||
xmpp_stanza_release(iq);
|
|
||||||
disconnect_mem_error(conn);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
xmpp_stanza_set_name(session, "session");
|
|
||||||
xmpp_stanza_set_ns(session, XMPP_NS_SESSION);
|
|
||||||
|
|
||||||
xmpp_stanza_add_child_ex(iq, session, 0);
|
|
||||||
|
|
||||||
/* send session establishment request */
|
|
||||||
send_stanza(conn, iq, XMPP_QUEUE_STROPHE);
|
|
||||||
}
|
}
|
||||||
|
/* send enable directly after the bind request */
|
||||||
if (conn->sm_state->sm_support && !conn->sm_disable) {
|
else if (conn->sm_state->sm_support && !conn->sm_disable) {
|
||||||
enable = xmpp_stanza_new(conn->ctx);
|
_sm_enable(conn);
|
||||||
if (!enable) {
|
|
||||||
disconnect_mem_error(conn);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
xmpp_stanza_set_name(enable, "enable");
|
|
||||||
xmpp_stanza_set_ns(enable, XMPP_NS_SM);
|
|
||||||
if (!conn->sm_state->dont_request_resume)
|
|
||||||
xmpp_stanza_set_attribute(enable, "resume", "true");
|
|
||||||
handler_add(conn, _handle_sm, XMPP_NS_SM, NULL, NULL, NULL);
|
|
||||||
send_stanza(conn, enable, XMPP_QUEUE_SM_STROPHE);
|
|
||||||
}
|
}
|
||||||
|
/* if there's no xmpp session required and we didn't try to enable
|
||||||
if (!conn->session_required) {
|
* stream-management, we're done here and the stream-negotiation was
|
||||||
_auth_success(conn);
|
* successful
|
||||||
|
*/
|
||||||
|
else {
|
||||||
|
_stream_negotiation_success(conn);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
strophe_error(conn->ctx, "xmpp", "Server sent malformed bind reply.");
|
strophe_error(conn->ctx, "xmpp", "Server sent malformed bind reply.");
|
||||||
@@ -1121,8 +1311,11 @@ _handle_session(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
|
|||||||
xmpp_disconnect(conn);
|
xmpp_disconnect(conn);
|
||||||
} else if (type && strcmp(type, "result") == 0) {
|
} else if (type && strcmp(type, "result") == 0) {
|
||||||
strophe_debug(conn->ctx, "xmpp", "Session establishment successful.");
|
strophe_debug(conn->ctx, "xmpp", "Session establishment successful.");
|
||||||
|
if (conn->sm_state->sm_support && !conn->sm_disable) {
|
||||||
_auth_success(conn);
|
_sm_enable(conn);
|
||||||
|
} else {
|
||||||
|
_stream_negotiation_success(conn);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
strophe_error(conn->ctx, "xmpp",
|
strophe_error(conn->ctx, "xmpp",
|
||||||
"Server sent malformed session reply.");
|
"Server sent malformed session reply.");
|
||||||
@@ -1153,23 +1346,59 @@ static int _handle_missing_legacy(xmpp_conn_t *conn, void *userdata)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int _get_h_attribute(xmpp_stanza_t *stanza, unsigned long *ul_h)
|
||||||
|
{
|
||||||
|
const char *h = xmpp_stanza_get_attribute(stanza, "h");
|
||||||
|
if (!h || string_to_ul(h, ul_h)) {
|
||||||
|
strophe_error(
|
||||||
|
stanza->ctx, "xmpp",
|
||||||
|
"SM error: failed parsing 'h', \"%s\" got converted to %llu.",
|
||||||
|
STR_MAYBE_NULL(h), *ul_h);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _sm_queue_cleanup(xmpp_conn_t *conn, unsigned long ul_h)
|
||||||
|
{
|
||||||
|
xmpp_send_queue_t *e;
|
||||||
|
while ((e = peek_queue_front(&conn->sm_state->sm_queue))) {
|
||||||
|
if (e->sm_h >= ul_h)
|
||||||
|
break;
|
||||||
|
e = pop_queue_front(&conn->sm_state->sm_queue);
|
||||||
|
strophe_free(conn->ctx, queue_element_free(conn->ctx, e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _sm_queue_resend(xmpp_conn_t *conn)
|
||||||
|
{
|
||||||
|
xmpp_send_queue_t *e;
|
||||||
|
while ((e = pop_queue_front(&conn->sm_state->sm_queue))) {
|
||||||
|
/* Re-send what was already sent out and is still in the
|
||||||
|
* SM queue (i.e. it hasn't been ACK'ed by the server)
|
||||||
|
*/
|
||||||
|
strophe_debug_verbose(2, conn->ctx, "conn", "SM_Q_RESEND: %p, h=%lu", e,
|
||||||
|
e->sm_h);
|
||||||
|
send_raw(conn, e->data, e->len, e->owner, NULL);
|
||||||
|
strophe_free(conn->ctx, queue_element_free(conn->ctx, e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int _handle_sm(xmpp_conn_t *const conn,
|
static int _handle_sm(xmpp_conn_t *const conn,
|
||||||
xmpp_stanza_t *const stanza,
|
xmpp_stanza_t *const stanza,
|
||||||
void *const userdata)
|
void *const userdata)
|
||||||
{
|
{
|
||||||
xmpp_stanza_t *failed_cause;
|
xmpp_stanza_t *failed_cause, *bind = NULL;
|
||||||
const char *name, *id, *previd, *resume, *h, *cause;
|
const char *name, *id, *previd, *resume, *cause;
|
||||||
xmpp_send_queue_t *e;
|
|
||||||
unsigned long ul_h = 0;
|
unsigned long ul_h = 0;
|
||||||
|
|
||||||
UNUSED(userdata);
|
UNUSED(userdata);
|
||||||
|
|
||||||
name = xmpp_stanza_get_name(stanza);
|
name = xmpp_stanza_get_name(stanza);
|
||||||
if (!name)
|
if (!name)
|
||||||
goto LBL_ERR;
|
goto err_sm;
|
||||||
|
|
||||||
if (strcmp(name, "enabled") == 0) {
|
if (strcmp(name, "enabled") == 0) {
|
||||||
conn->sm_state->sm_enabled = 1;
|
|
||||||
conn->sm_state->sm_handled_nr = 0;
|
conn->sm_state->sm_handled_nr = 0;
|
||||||
resume = xmpp_stanza_get_attribute(stanza, "resume");
|
resume = xmpp_stanza_get_attribute(stanza, "resume");
|
||||||
if (resume && (strcasecmp(resume, "true") || strcmp(resume, "1"))) {
|
if (resume && (strcasecmp(resume, "true") || strcmp(resume, "1"))) {
|
||||||
@@ -1179,11 +1408,17 @@ static int _handle_sm(xmpp_conn_t *const conn,
|
|||||||
"SM error: server said it can resume, but "
|
"SM error: server said it can resume, but "
|
||||||
"didn't provide an ID.");
|
"didn't provide an ID.");
|
||||||
name = NULL;
|
name = NULL;
|
||||||
goto LBL_ERR;
|
goto err_sm;
|
||||||
}
|
}
|
||||||
conn->sm_state->can_resume = 1;
|
conn->sm_state->can_resume = 1;
|
||||||
conn->sm_state->id = strophe_strdup(conn->ctx, id);
|
conn->sm_state->id = strophe_strdup(conn->ctx, id);
|
||||||
}
|
}
|
||||||
|
/* We maybe have stuff in the SM queue if we tried to resume, but the
|
||||||
|
* server doesn't remember all details of our session, but the `h` was
|
||||||
|
* still available.
|
||||||
|
*/
|
||||||
|
_sm_queue_resend(conn);
|
||||||
|
_stream_negotiation_success(conn);
|
||||||
} else if (strcmp(name, "resumed") == 0) {
|
} else if (strcmp(name, "resumed") == 0) {
|
||||||
previd = xmpp_stanza_get_attribute(stanza, "previd");
|
previd = xmpp_stanza_get_attribute(stanza, "previd");
|
||||||
if (!previd || strcmp(previd, conn->sm_state->previd)) {
|
if (!previd || strcmp(previd, conn->sm_state->previd)) {
|
||||||
@@ -1191,16 +1426,11 @@ static int _handle_sm(xmpp_conn_t *const conn,
|
|||||||
"SM error: previd didn't match, ours is \"%s\".",
|
"SM error: previd didn't match, ours is \"%s\".",
|
||||||
conn->sm_state->previd);
|
conn->sm_state->previd);
|
||||||
name = NULL;
|
name = NULL;
|
||||||
goto LBL_ERR;
|
goto err_sm;
|
||||||
}
|
}
|
||||||
h = xmpp_stanza_get_attribute(stanza, "h");
|
if (_get_h_attribute(stanza, &ul_h)) {
|
||||||
if (!h || string_to_ul(h, &ul_h)) {
|
|
||||||
strophe_error(conn->ctx, "xmpp",
|
|
||||||
"SM error: failed parsing 'h', it got converted "
|
|
||||||
"to %llu.",
|
|
||||||
ul_h);
|
|
||||||
name = NULL;
|
name = NULL;
|
||||||
goto LBL_ERR;
|
goto err_sm;
|
||||||
}
|
}
|
||||||
conn->sm_state->sm_enabled = 1;
|
conn->sm_state->sm_enabled = 1;
|
||||||
conn->sm_state->id = conn->sm_state->previd;
|
conn->sm_state->id = conn->sm_state->previd;
|
||||||
@@ -1211,54 +1441,55 @@ static int _handle_sm(xmpp_conn_t *const conn,
|
|||||||
conn->sm_state->sm_sent_nr = conn->sm_state->sm_queue.head->sm_h;
|
conn->sm_state->sm_sent_nr = conn->sm_state->sm_queue.head->sm_h;
|
||||||
else
|
else
|
||||||
conn->sm_state->sm_sent_nr = ul_h;
|
conn->sm_state->sm_sent_nr = ul_h;
|
||||||
while ((e = pop_queue_front(&conn->sm_state->sm_queue))) {
|
_sm_queue_cleanup(conn, ul_h);
|
||||||
if (e->sm_h >= ul_h) {
|
_sm_queue_resend(conn);
|
||||||
/* Re-send what was already sent out and is still in the
|
|
||||||
* SM queue (i.e. it hasn't been ACK'ed by the server)
|
|
||||||
*/
|
|
||||||
send_raw(conn, e->data, e->len, e->owner, NULL);
|
|
||||||
}
|
|
||||||
strophe_free(conn->ctx, queue_element_free(conn->ctx, e));
|
|
||||||
}
|
|
||||||
strophe_debug(conn->ctx, "xmpp", "Session resumed successfully.");
|
strophe_debug(conn->ctx, "xmpp", "Session resumed successfully.");
|
||||||
_auth_success(conn);
|
_stream_negotiation_success(conn);
|
||||||
} else if (strcmp(name, "failed") == 0) {
|
} else if (strcmp(name, "failed") == 0) {
|
||||||
name = NULL;
|
name = NULL;
|
||||||
|
conn->sm_state->sm_enabled = 0;
|
||||||
|
|
||||||
failed_cause =
|
failed_cause =
|
||||||
xmpp_stanza_get_child_by_ns(stanza, XMPP_NS_STANZAS_IETF);
|
xmpp_stanza_get_child_by_ns(stanza, XMPP_NS_STANZAS_IETF);
|
||||||
if (!failed_cause)
|
if (!failed_cause)
|
||||||
goto LBL_ERR;
|
goto err_sm;
|
||||||
|
|
||||||
cause = xmpp_stanza_get_name(failed_cause);
|
cause = xmpp_stanza_get_name(failed_cause);
|
||||||
if (!cause)
|
if (!cause)
|
||||||
goto LBL_ERR;
|
goto err_sm;
|
||||||
|
|
||||||
if (!strcmp(cause, "item-not-found") ||
|
if (!strcmp(cause, "item-not-found")) {
|
||||||
!strcmp(cause, "feature-not-implemented")) {
|
|
||||||
if (conn->sm_state->resume) {
|
if (conn->sm_state->resume) {
|
||||||
conn->sm_state->resume = 0;
|
/* It's no error if there's no `h` attribute included
|
||||||
conn->sm_state->can_resume = 0;
|
* but if there is, it gives a hint at what the server
|
||||||
/* remember that the server reports having support
|
* already received.
|
||||||
* for resumption, but actually it doesn't ...
|
|
||||||
*/
|
*/
|
||||||
conn->sm_state->dont_request_resume =
|
if (!_get_h_attribute(stanza, &ul_h)) {
|
||||||
!strcmp(cause, "feature-not-implemented");
|
/* In cases there's no `h` included, drop all elements. */
|
||||||
strophe_free(conn->ctx, conn->sm_state->previd);
|
ul_h = (unsigned long)-1;
|
||||||
conn->sm_state->previd = NULL;
|
}
|
||||||
strophe_free(conn->ctx, conn->sm_state->bound_jid);
|
_sm_queue_cleanup(conn, ul_h);
|
||||||
conn->sm_state->bound_jid = NULL;
|
|
||||||
_do_bind(conn, conn->sm_state->bind);
|
|
||||||
conn->sm_state->bind = NULL;
|
|
||||||
}
|
}
|
||||||
|
} else if (!strcmp(cause, "feature-not-implemented")) {
|
||||||
|
conn->sm_state->resume = 0;
|
||||||
|
conn->sm_state->can_resume = 0;
|
||||||
|
/* remember that the server reports having support
|
||||||
|
* for resumption, but actually it doesn't ...
|
||||||
|
*/
|
||||||
|
conn->sm_state->dont_request_resume = 1;
|
||||||
}
|
}
|
||||||
conn->sm_state->sm_handled_nr = 0;
|
bind = conn->sm_state->bind;
|
||||||
|
conn->sm_state->bind = NULL;
|
||||||
|
reset_sm_state(conn->sm_state);
|
||||||
|
_do_bind(conn, bind);
|
||||||
} else {
|
} else {
|
||||||
/* unknown stanza received */
|
/* unknown stanza received */
|
||||||
name = NULL;
|
name = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
LBL_ERR:
|
trigger_sm_callback(conn);
|
||||||
|
|
||||||
|
err_sm:
|
||||||
if (!name) {
|
if (!name) {
|
||||||
char *err = "Couldn't convert stanza to text!";
|
char *err = "Couldn't convert stanza to text!";
|
||||||
char *buf;
|
char *buf;
|
||||||
@@ -1277,7 +1508,8 @@ LBL_ERR:
|
|||||||
buf);
|
buf);
|
||||||
if (buf != err)
|
if (buf != err)
|
||||||
strophe_free(conn->ctx, buf);
|
strophe_free(conn->ctx, buf);
|
||||||
conn->sm_state->sm_enabled = 0;
|
/* Don't disable for <failure> cases, they're no hard errors */
|
||||||
|
conn->sm_state->sm_enabled = bind != NULL;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1310,7 +1542,7 @@ _handle_legacy(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
|
|||||||
/* auth succeeded */
|
/* auth succeeded */
|
||||||
strophe_debug(conn->ctx, "xmpp", "Legacy auth succeeded.");
|
strophe_debug(conn->ctx, "xmpp", "Legacy auth succeeded.");
|
||||||
|
|
||||||
_auth_success(conn);
|
_stream_negotiation_success(conn);
|
||||||
} else {
|
} else {
|
||||||
strophe_error(conn->ctx, "xmpp",
|
strophe_error(conn->ctx, "xmpp",
|
||||||
"Server sent us a legacy authentication "
|
"Server sent us a legacy authentication "
|
||||||
@@ -1500,7 +1732,7 @@ int _handle_component_hs_response(xmpp_conn_t *conn,
|
|||||||
xmpp_disconnect(conn);
|
xmpp_disconnect(conn);
|
||||||
return XMPP_EINT;
|
return XMPP_EINT;
|
||||||
} else {
|
} else {
|
||||||
_auth_success(conn);
|
_stream_negotiation_success(conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We don't need this handler anymore, return 0 so it can be deleted
|
/* We don't need this handler anymore, return 0 so it can be deleted
|
||||||
@@ -1522,8 +1754,8 @@ int _handle_missing_handshake(xmpp_conn_t *conn, void *userdata)
|
|||||||
void auth_handle_open_raw(xmpp_conn_t *conn)
|
void auth_handle_open_raw(xmpp_conn_t *conn)
|
||||||
{
|
{
|
||||||
handler_reset_timed(conn, 0);
|
handler_reset_timed(conn, 0);
|
||||||
/* user handlers are not called before authentication is completed. */
|
/* user handlers are not called before stream negotiation has completed. */
|
||||||
_auth_success(conn);
|
_stream_negotiation_success(conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
void auth_handle_open_stub(xmpp_conn_t *conn)
|
void auth_handle_open_stub(xmpp_conn_t *conn)
|
||||||
|
|||||||
71
src/common.h
71
src/common.h
@@ -1,3 +1,4 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
|
||||||
/* common.h
|
/* common.h
|
||||||
** strophe XMPP client library -- internal common structures
|
** strophe XMPP client library -- internal common structures
|
||||||
**
|
**
|
||||||
@@ -6,7 +7,7 @@
|
|||||||
** This software is provided AS-IS with no warranty, either express or
|
** This software is provided AS-IS with no warranty, either express or
|
||||||
** implied.
|
** implied.
|
||||||
**
|
**
|
||||||
** This program is dual licensed under the MIT and GPLv3 licenses.
|
** This program is dual licensed under the MIT or GPLv3 licenses.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @file
|
/** @file
|
||||||
@@ -29,12 +30,17 @@
|
|||||||
#include "snprintf.h"
|
#include "snprintf.h"
|
||||||
|
|
||||||
/** handlers **/
|
/** handlers **/
|
||||||
|
#if (__STDC_VERSION__ >= 202000L)
|
||||||
|
typedef void *xmpp_void_handler;
|
||||||
|
#else
|
||||||
|
typedef int (*xmpp_void_handler)();
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef struct _xmpp_handlist_t xmpp_handlist_t;
|
typedef struct _xmpp_handlist_t xmpp_handlist_t;
|
||||||
struct _xmpp_handlist_t {
|
struct _xmpp_handlist_t {
|
||||||
/* common members */
|
/* common members */
|
||||||
int user_handler;
|
int user_handler;
|
||||||
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
|
||||||
@@ -92,6 +98,13 @@ void *strophe_realloc(const xmpp_ctx_t *ctx, void *p, size_t size);
|
|||||||
char *strophe_strdup(const xmpp_ctx_t *ctx, const char *s);
|
char *strophe_strdup(const xmpp_ctx_t *ctx, const char *s);
|
||||||
char *strophe_strndup(const xmpp_ctx_t *ctx, const char *s, size_t len);
|
char *strophe_strndup(const xmpp_ctx_t *ctx, const char *s, size_t len);
|
||||||
void strophe_free(const xmpp_ctx_t *ctx, void *p);
|
void strophe_free(const xmpp_ctx_t *ctx, void *p);
|
||||||
|
#define strophe_free_and_null(ctx, p) \
|
||||||
|
do { \
|
||||||
|
if (p) { \
|
||||||
|
strophe_free(ctx, (p)); \
|
||||||
|
(p) = NULL; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
/* wrappers for xmpp_log at specific levels */
|
/* wrappers for xmpp_log at specific levels */
|
||||||
void strophe_error(const xmpp_ctx_t *ctx,
|
void strophe_error(const xmpp_ctx_t *ctx,
|
||||||
@@ -119,6 +132,12 @@ void strophe_log_internal(const xmpp_ctx_t *ctx,
|
|||||||
const char *fmt,
|
const char *fmt,
|
||||||
va_list ap);
|
va_list ap);
|
||||||
|
|
||||||
|
#if defined(__OpenBSD__)
|
||||||
|
#define STR_MAYBE_NULL(p) (p) ? (p) : "(null)"
|
||||||
|
#else
|
||||||
|
#define STR_MAYBE_NULL(p) (p)
|
||||||
|
#endif
|
||||||
|
|
||||||
/** connection **/
|
/** connection **/
|
||||||
|
|
||||||
/* opaque connection object */
|
/* opaque connection object */
|
||||||
@@ -159,9 +178,16 @@ struct _xmpp_send_queue_t {
|
|||||||
#define SASL_MASK_SCRAMSHA256 (1 << 4)
|
#define SASL_MASK_SCRAMSHA256 (1 << 4)
|
||||||
#define SASL_MASK_SCRAMSHA512 (1 << 5)
|
#define SASL_MASK_SCRAMSHA512 (1 << 5)
|
||||||
#define SASL_MASK_EXTERNAL (1 << 6)
|
#define SASL_MASK_EXTERNAL (1 << 6)
|
||||||
|
#define SASL_MASK_SCRAMSHA1_PLUS (1 << 7)
|
||||||
|
#define SASL_MASK_SCRAMSHA256_PLUS (1 << 8)
|
||||||
|
#define SASL_MASK_SCRAMSHA512_PLUS (1 << 9)
|
||||||
|
|
||||||
#define SASL_MASK_SCRAM \
|
#define SASL_MASK_SCRAM_PLUS \
|
||||||
|
(SASL_MASK_SCRAMSHA1_PLUS | SASL_MASK_SCRAMSHA256_PLUS | \
|
||||||
|
SASL_MASK_SCRAMSHA512_PLUS)
|
||||||
|
#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)
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
XMPP_PORT_CLIENT = 5222,
|
XMPP_PORT_CLIENT = 5222,
|
||||||
@@ -180,14 +206,36 @@ struct _xmpp_sm_t {
|
|||||||
int sm_support;
|
int sm_support;
|
||||||
int sm_enabled;
|
int sm_enabled;
|
||||||
int can_resume, resume, dont_request_resume;
|
int can_resume, resume, dont_request_resume;
|
||||||
|
xmpp_queue_t sm_queue;
|
||||||
|
int r_sent;
|
||||||
uint32_t sm_handled_nr;
|
uint32_t sm_handled_nr;
|
||||||
uint32_t sm_sent_nr;
|
uint32_t sm_sent_nr;
|
||||||
xmpp_queue_t sm_queue;
|
|
||||||
char *id, *previd, *bound_jid;
|
char *id, *previd, *bound_jid;
|
||||||
xmpp_stanza_t *bind;
|
xmpp_stanza_t *bind;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct conn_interface {
|
||||||
|
int (*read)(struct conn_interface *intf, void *buff, size_t len);
|
||||||
|
int (*write)(struct conn_interface *intf, const void *buff, size_t len);
|
||||||
|
int (*flush)(struct conn_interface *intf);
|
||||||
|
int (*pending)(struct conn_interface *intf);
|
||||||
|
int (*get_error)(struct conn_interface *intf);
|
||||||
|
int (*error_is_recoverable)(struct conn_interface *intf, int err);
|
||||||
|
xmpp_conn_t *conn;
|
||||||
|
};
|
||||||
|
|
||||||
|
int conn_interface_write(struct conn_interface *intf,
|
||||||
|
const void *buff,
|
||||||
|
size_t len);
|
||||||
|
int conn_int_nop(struct conn_interface *intf);
|
||||||
|
|
||||||
|
int compression_init(xmpp_conn_t *conn);
|
||||||
|
void compression_free(xmpp_conn_t *conn);
|
||||||
|
void compression_handle_feature_children(xmpp_conn_t *conn, const char *text);
|
||||||
|
|
||||||
struct _xmpp_conn_t {
|
struct _xmpp_conn_t {
|
||||||
|
struct conn_interface intf;
|
||||||
|
|
||||||
unsigned int ref;
|
unsigned int ref;
|
||||||
xmpp_ctx_t *ctx;
|
xmpp_ctx_t *ctx;
|
||||||
xmpp_conn_type_t type;
|
xmpp_conn_type_t type;
|
||||||
@@ -235,6 +283,11 @@ struct _xmpp_conn_t {
|
|||||||
int sm_disable;
|
int sm_disable;
|
||||||
xmpp_sm_state_t *sm_state;
|
xmpp_sm_state_t *sm_state;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
struct xmpp_compression *state;
|
||||||
|
int allowed, supported, dont_reset;
|
||||||
|
} compression;
|
||||||
|
|
||||||
char *lang;
|
char *lang;
|
||||||
char *domain;
|
char *domain;
|
||||||
char *jid;
|
char *jid;
|
||||||
@@ -262,8 +315,9 @@ struct _xmpp_conn_t {
|
|||||||
/* stream open handler */
|
/* stream open handler */
|
||||||
xmpp_open_handler open_handler;
|
xmpp_open_handler open_handler;
|
||||||
|
|
||||||
/* user handlers only get called after authentication */
|
/* user handlers only get called after the stream negotiation has completed
|
||||||
int authenticated;
|
*/
|
||||||
|
int stream_negotiation_completed;
|
||||||
|
|
||||||
/* connection events handler */
|
/* connection events handler */
|
||||||
xmpp_conn_handler conn_handler;
|
xmpp_conn_handler conn_handler;
|
||||||
@@ -274,6 +328,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);
|
||||||
@@ -327,6 +383,8 @@ 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 disconnect_mem_error(xmpp_conn_t *conn);
|
void disconnect_mem_error(xmpp_conn_t *conn);
|
||||||
|
|
||||||
/* auth functions */
|
/* auth functions */
|
||||||
@@ -337,6 +395,7 @@ void auth_handle_open_stub(xmpp_conn_t *conn);
|
|||||||
|
|
||||||
/* queue functions */
|
/* queue functions */
|
||||||
void add_queue_back(xmpp_queue_t *queue, xmpp_send_queue_t *item);
|
void add_queue_back(xmpp_queue_t *queue, xmpp_send_queue_t *item);
|
||||||
|
xmpp_send_queue_t *peek_queue_front(xmpp_queue_t *queue);
|
||||||
xmpp_send_queue_t *pop_queue_front(xmpp_queue_t *queue);
|
xmpp_send_queue_t *pop_queue_front(xmpp_queue_t *queue);
|
||||||
char *queue_element_free(xmpp_ctx_t *ctx, xmpp_send_queue_t *e);
|
char *queue_element_free(xmpp_ctx_t *ctx, xmpp_send_queue_t *e);
|
||||||
|
|
||||||
|
|||||||
270
src/compression.c
Normal file
270
src/compression.c
Normal file
@@ -0,0 +1,270 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
|
||||||
|
/* compression.c
|
||||||
|
** strophe XMPP client library -- XEP-0138 Stream Compression
|
||||||
|
**
|
||||||
|
** Copyright (C) 2024 Steffen Jaeckel <jaeckel-floss@eyet-services.de>
|
||||||
|
**
|
||||||
|
** This software is provided AS-IS with no warranty, either express
|
||||||
|
** or implied.
|
||||||
|
**
|
||||||
|
** This program is dual licensed under the MIT or GPLv3 licenses.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file
|
||||||
|
* XEP-0138 Stream Compression.
|
||||||
|
*/
|
||||||
|
#include <zlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
#ifndef STROPHE_COMPRESSION_BUFFER_SIZE
|
||||||
|
/** Max buffer size for compressed data (send & receive). */
|
||||||
|
#define STROPHE_COMPRESSION_BUFFER_SIZE 4096
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct zlib_compression {
|
||||||
|
void *buffer, *buffer_end;
|
||||||
|
z_stream stream;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct xmpp_compression {
|
||||||
|
xmpp_conn_t *conn;
|
||||||
|
struct zlib_compression compression, decompression;
|
||||||
|
struct conn_interface next;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int _conn_decompress(struct xmpp_compression *comp,
|
||||||
|
size_t c_len,
|
||||||
|
void *buff,
|
||||||
|
size_t len)
|
||||||
|
{
|
||||||
|
if (comp->decompression.stream.next_in == NULL) {
|
||||||
|
comp->decompression.stream.next_in = comp->decompression.buffer;
|
||||||
|
comp->decompression.buffer_end =
|
||||||
|
comp->decompression.stream.next_in + c_len;
|
||||||
|
comp->decompression.stream.avail_in = c_len;
|
||||||
|
} else if (c_len) {
|
||||||
|
strophe_error(comp->conn->ctx, "zlib",
|
||||||
|
"_conn_decompress() called with c_len=%zu", c_len);
|
||||||
|
}
|
||||||
|
comp->decompression.stream.next_out = buff;
|
||||||
|
comp->decompression.stream.avail_out = len;
|
||||||
|
int ret = inflate(&comp->decompression.stream, Z_SYNC_FLUSH);
|
||||||
|
switch (ret) {
|
||||||
|
case Z_STREAM_END:
|
||||||
|
case Z_OK:
|
||||||
|
if (comp->decompression.buffer_end ==
|
||||||
|
comp->decompression.stream.next_in)
|
||||||
|
comp->decompression.stream.next_in = NULL;
|
||||||
|
return comp->decompression.stream.next_out - (Bytef *)buff;
|
||||||
|
case Z_BUF_ERROR:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
strophe_error(comp->conn->ctx, "zlib", "inflate error %d", ret);
|
||||||
|
comp->conn->error = ret;
|
||||||
|
conn_disconnect(comp->conn);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int compression_read(struct conn_interface *intf, void *buff, size_t len)
|
||||||
|
{
|
||||||
|
xmpp_conn_t *conn = intf->conn;
|
||||||
|
struct xmpp_compression *comp = conn->compression.state;
|
||||||
|
void *dbuff = buff;
|
||||||
|
size_t dlen = len;
|
||||||
|
if (comp->decompression.stream.next_in != NULL) {
|
||||||
|
return _conn_decompress(comp, 0, buff, len);
|
||||||
|
}
|
||||||
|
dbuff = comp->decompression.buffer;
|
||||||
|
dlen = STROPHE_COMPRESSION_BUFFER_SIZE;
|
||||||
|
int ret = comp->next.read(intf, dbuff, dlen);
|
||||||
|
if (ret > 0) {
|
||||||
|
return _conn_decompress(comp, ret, buff, len);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _try_compressed_write_to_network(xmpp_conn_t *conn, int force)
|
||||||
|
{
|
||||||
|
struct xmpp_compression *comp = conn->compression.state;
|
||||||
|
int ret = 0;
|
||||||
|
ptrdiff_t len =
|
||||||
|
comp->compression.stream.next_out - (Bytef *)comp->compression.buffer;
|
||||||
|
int buffer_full =
|
||||||
|
comp->compression.stream.next_out == comp->compression.buffer_end;
|
||||||
|
if ((buffer_full || force) && len > 0) {
|
||||||
|
ret = conn_interface_write(&comp->next, comp->compression.buffer, len);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
comp->compression.stream.next_out = comp->compression.buffer;
|
||||||
|
comp->compression.stream.avail_out = STROPHE_COMPRESSION_BUFFER_SIZE;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
_compression_write(xmpp_conn_t *conn, const void *buff, size_t len, int flush)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
const void *buff_end = buff + len;
|
||||||
|
struct xmpp_compression *comp = conn->compression.state;
|
||||||
|
comp->compression.stream.next_in = (Bytef *)buff;
|
||||||
|
comp->compression.stream.avail_in = len;
|
||||||
|
do {
|
||||||
|
ret = _try_compressed_write_to_network(conn, 0);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = deflate(&comp->compression.stream, flush);
|
||||||
|
if (ret == Z_STREAM_END) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (flush && ret == Z_BUF_ERROR) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (ret != Z_OK) {
|
||||||
|
strophe_error(conn->ctx, "zlib", "deflate error %d", ret);
|
||||||
|
conn->error = ret;
|
||||||
|
conn_disconnect(conn);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
ret = comp->compression.stream.next_in - (Bytef *)buff;
|
||||||
|
} while (comp->compression.stream.next_in < (Bytef *)buff_end);
|
||||||
|
if (flush) {
|
||||||
|
ret = _try_compressed_write_to_network(conn, 1);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
compression_write(struct conn_interface *intf, const void *buff, size_t len)
|
||||||
|
{
|
||||||
|
return _compression_write(intf->conn, buff, len, Z_NO_FLUSH);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int compression_flush(struct conn_interface *intf)
|
||||||
|
{
|
||||||
|
xmpp_conn_t *conn = intf->conn;
|
||||||
|
struct xmpp_compression *comp = conn->compression.state;
|
||||||
|
return _compression_write(conn, comp->compression.buffer, 0,
|
||||||
|
conn->compression.dont_reset ? Z_SYNC_FLUSH
|
||||||
|
: Z_FULL_FLUSH);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int compression_pending(struct conn_interface *intf)
|
||||||
|
{
|
||||||
|
xmpp_conn_t *conn = intf->conn;
|
||||||
|
struct xmpp_compression *comp = conn->compression.state;
|
||||||
|
return comp->decompression.stream.next_in != NULL ||
|
||||||
|
comp->next.pending(intf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int compression_get_error(struct conn_interface *intf)
|
||||||
|
{
|
||||||
|
struct conn_interface *next = &intf->conn->compression.state->next;
|
||||||
|
return next->get_error(next);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int compression_is_recoverable(struct conn_interface *intf, int err)
|
||||||
|
{
|
||||||
|
struct conn_interface *next = &intf->conn->compression.state->next;
|
||||||
|
return next->error_is_recoverable(next, err);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct conn_interface compression_intf = {
|
||||||
|
compression_read,
|
||||||
|
compression_write,
|
||||||
|
compression_flush,
|
||||||
|
compression_pending,
|
||||||
|
compression_get_error,
|
||||||
|
compression_is_recoverable,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void *_zlib_alloc(void *opaque, unsigned int items, unsigned int size)
|
||||||
|
{
|
||||||
|
size_t sz = items * size;
|
||||||
|
/* Poor man's multiplication overflow check */
|
||||||
|
if (sz < items || sz < size)
|
||||||
|
return NULL;
|
||||||
|
return strophe_alloc(opaque, sz);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _init_zlib_compression(xmpp_ctx_t *ctx, struct zlib_compression *s)
|
||||||
|
{
|
||||||
|
s->buffer = strophe_alloc(ctx, STROPHE_COMPRESSION_BUFFER_SIZE);
|
||||||
|
s->buffer_end = s->buffer + STROPHE_COMPRESSION_BUFFER_SIZE;
|
||||||
|
|
||||||
|
s->stream.opaque = ctx;
|
||||||
|
s->stream.zalloc = _zlib_alloc;
|
||||||
|
s->stream.zfree = (free_func)strophe_free;
|
||||||
|
}
|
||||||
|
|
||||||
|
int compression_init(xmpp_conn_t *conn)
|
||||||
|
{
|
||||||
|
if (!conn->compression.allowed || !conn->compression.supported)
|
||||||
|
return -1;
|
||||||
|
conn->compression.state =
|
||||||
|
strophe_alloc(conn->ctx, sizeof(*conn->compression.state));
|
||||||
|
struct xmpp_compression *comp = conn->compression.state;
|
||||||
|
memset(comp, 0, sizeof(*comp));
|
||||||
|
|
||||||
|
comp->conn = conn;
|
||||||
|
|
||||||
|
comp->next = conn->intf;
|
||||||
|
conn->intf = compression_intf;
|
||||||
|
conn->intf.conn = conn;
|
||||||
|
|
||||||
|
_init_zlib_compression(conn->ctx, &comp->compression);
|
||||||
|
|
||||||
|
comp->compression.stream.next_out = comp->compression.buffer;
|
||||||
|
comp->compression.stream.avail_out = STROPHE_COMPRESSION_BUFFER_SIZE;
|
||||||
|
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;
|
||||||
|
conn_disconnect(conn);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
_init_zlib_compression(conn->ctx, &comp->decompression);
|
||||||
|
|
||||||
|
ret = inflateInit(&comp->decompression.stream);
|
||||||
|
if (ret != Z_OK) {
|
||||||
|
strophe_free_and_null(conn->ctx, comp->decompression.buffer);
|
||||||
|
conn->error = ret;
|
||||||
|
conn_disconnect(conn);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void compression_free(xmpp_conn_t *conn)
|
||||||
|
{
|
||||||
|
struct xmpp_compression *comp = conn->compression.state;
|
||||||
|
if (!comp)
|
||||||
|
return;
|
||||||
|
if (comp->compression.buffer) {
|
||||||
|
deflateEnd(&comp->compression.stream);
|
||||||
|
strophe_free_and_null(conn->ctx, comp->compression.buffer);
|
||||||
|
}
|
||||||
|
if (comp->decompression.buffer) {
|
||||||
|
inflateEnd(&comp->decompression.stream);
|
||||||
|
strophe_free_and_null(conn->ctx, comp->decompression.buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void compression_handle_feature_children(xmpp_conn_t *conn, const char *text)
|
||||||
|
{
|
||||||
|
if (strcasecmp(text, "zlib") == 0) {
|
||||||
|
conn->compression.supported = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
36
src/compression_dummy.c
Normal file
36
src/compression_dummy.c
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
|
||||||
|
/* compression_dummy.c
|
||||||
|
** strophe XMPP client library -- Dummy Compression
|
||||||
|
**
|
||||||
|
** Copyright (C) 2024 Steffen Jaeckel <jaeckel-floss@eyet-services.de>
|
||||||
|
**
|
||||||
|
** This software is provided AS-IS with no warranty, either express
|
||||||
|
** or implied.
|
||||||
|
**
|
||||||
|
** This program is dual licensed under the MIT or GPLv3 licenses.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file
|
||||||
|
* Dummy Compression.
|
||||||
|
*/
|
||||||
|
#include <strings.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
int compression_init(xmpp_conn_t *conn)
|
||||||
|
{
|
||||||
|
conn->compression.supported = 0;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void compression_free(xmpp_conn_t *conn)
|
||||||
|
{
|
||||||
|
UNUSED(conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
void compression_handle_feature_children(xmpp_conn_t *conn, const char *text)
|
||||||
|
{
|
||||||
|
UNUSED(text);
|
||||||
|
conn->compression.supported = 0;
|
||||||
|
}
|
||||||
641
src/conn.c
641
src/conn.c
@@ -1,3 +1,4 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
|
||||||
/* conn.c
|
/* conn.c
|
||||||
** strophe XMPP client library -- connection object functions
|
** strophe XMPP client library -- connection object functions
|
||||||
**
|
**
|
||||||
@@ -6,7 +7,7 @@
|
|||||||
** This software is provided AS-IS with no warranty, either express
|
** This software is provided AS-IS with no warranty, either express
|
||||||
** or implied.
|
** or implied.
|
||||||
**
|
**
|
||||||
** This program is dual licensed under the MIT and GPLv3 licenses.
|
** This program is dual licensed under the MIT or GPLv3 licenses.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @file
|
/** @file
|
||||||
@@ -20,6 +21,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
@@ -77,6 +79,7 @@
|
|||||||
#define KEEPALIVE_COUNT 3
|
#define KEEPALIVE_COUNT 3
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static int _is_connected(xmpp_conn_t *conn, xmpp_send_queue_owner_t owner);
|
||||||
static int _disconnect_cleanup(xmpp_conn_t *conn, void *userdata);
|
static int _disconnect_cleanup(xmpp_conn_t *conn, void *userdata);
|
||||||
static void _reset_sm_state_for_reconnect(xmpp_conn_t *conn);
|
static void _reset_sm_state_for_reconnect(xmpp_conn_t *conn);
|
||||||
static char *_conn_build_stream_tag(xmpp_conn_t *conn,
|
static char *_conn_build_stream_tag(xmpp_conn_t *conn,
|
||||||
@@ -140,28 +143,19 @@ xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t *ctx)
|
|||||||
|
|
||||||
conn = strophe_alloc(ctx, sizeof(xmpp_conn_t));
|
conn = strophe_alloc(ctx, sizeof(xmpp_conn_t));
|
||||||
if (conn != NULL) {
|
if (conn != NULL) {
|
||||||
|
memset(conn, 0, sizeof(xmpp_conn_t));
|
||||||
conn->ctx = ctx;
|
conn->ctx = ctx;
|
||||||
|
|
||||||
conn->type = XMPP_UNKNOWN;
|
conn->type = XMPP_UNKNOWN;
|
||||||
conn->state = XMPP_STATE_DISCONNECTED;
|
conn->state = XMPP_STATE_DISCONNECTED;
|
||||||
|
|
||||||
conn->xsock = NULL;
|
|
||||||
conn->sock = INVALID_SOCKET;
|
conn->sock = INVALID_SOCKET;
|
||||||
conn->ka_timeout = KEEPALIVE_TIMEOUT;
|
conn->ka_timeout = KEEPALIVE_TIMEOUT;
|
||||||
conn->ka_interval = KEEPALIVE_INTERVAL;
|
conn->ka_interval = KEEPALIVE_INTERVAL;
|
||||||
conn->ka_count = KEEPALIVE_COUNT;
|
conn->ka_count = KEEPALIVE_COUNT;
|
||||||
conn->tls = NULL;
|
|
||||||
conn->timeout_stamp = 0;
|
|
||||||
conn->error = 0;
|
|
||||||
conn->stream_error = NULL;
|
|
||||||
|
|
||||||
/* default send parameters */
|
/* default send parameters */
|
||||||
conn->blocking_send = 0;
|
|
||||||
conn->send_queue_max = DEFAULT_SEND_QUEUE_MAX;
|
conn->send_queue_max = DEFAULT_SEND_QUEUE_MAX;
|
||||||
conn->send_queue_len = 0;
|
|
||||||
conn->send_queue_user_len = 0;
|
|
||||||
conn->send_queue_head = NULL;
|
|
||||||
conn->send_queue_tail = NULL;
|
|
||||||
|
|
||||||
/* default timeouts */
|
/* default timeouts */
|
||||||
conn->connect_timeout = CONNECT_TIMEOUT;
|
conn->connect_timeout = CONNECT_TIMEOUT;
|
||||||
@@ -171,49 +165,14 @@ xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t *ctx)
|
|||||||
strophe_free(conn->ctx, conn);
|
strophe_free(conn->ctx, conn);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
conn->domain = NULL;
|
|
||||||
conn->jid = NULL;
|
|
||||||
conn->pass = NULL;
|
|
||||||
conn->stream_id = NULL;
|
|
||||||
conn->bound_jid = NULL;
|
|
||||||
|
|
||||||
conn->is_raw = 0;
|
|
||||||
conn->tls_support = 0;
|
|
||||||
conn->tls_disabled = 0;
|
|
||||||
conn->tls_mandatory = 0;
|
|
||||||
conn->tls_legacy_ssl = 0;
|
|
||||||
conn->tls_trust = 0;
|
|
||||||
conn->tls_failed = 0;
|
|
||||||
conn->tls_cafile = NULL;
|
|
||||||
conn->tls_capath = NULL;
|
|
||||||
conn->tls_client_cert = NULL;
|
|
||||||
conn->tls_client_key = NULL;
|
|
||||||
conn->sasl_support = 0;
|
|
||||||
conn->auth_legacy_enabled = 0;
|
|
||||||
conn->secured = 0;
|
|
||||||
conn->certfail_handler = NULL;
|
|
||||||
conn->password_callback = NULL;
|
|
||||||
conn->password_callback_userdata = NULL;
|
|
||||||
tls_clear_password_cache(conn);
|
tls_clear_password_cache(conn);
|
||||||
conn->password_retries = 1;
|
conn->password_retries = 1;
|
||||||
|
|
||||||
conn->bind_required = 0;
|
|
||||||
conn->session_required = 0;
|
|
||||||
conn->sm_state = NULL;
|
|
||||||
|
|
||||||
conn->parser =
|
conn->parser =
|
||||||
parser_new(conn->ctx, _handle_stream_start, _handle_stream_end,
|
parser_new(conn->ctx, _handle_stream_start, _handle_stream_end,
|
||||||
_handle_stream_stanza, conn);
|
_handle_stream_stanza, conn);
|
||||||
conn->reset_parser = 0;
|
|
||||||
|
|
||||||
conn->authenticated = 0;
|
|
||||||
conn->conn_handler = NULL;
|
|
||||||
conn->userdata = NULL;
|
|
||||||
conn->timed_handlers = NULL;
|
|
||||||
/* we own (and will free) the hash values */
|
/* we own (and will free) the hash values */
|
||||||
conn->id_handlers = hash_new(conn->ctx, 32, NULL);
|
conn->id_handlers = hash_new(conn->ctx, 32, NULL);
|
||||||
conn->handlers = NULL;
|
|
||||||
conn->sockopt_cb = NULL;
|
|
||||||
|
|
||||||
/* give the caller a reference to connection */
|
/* give the caller a reference to connection */
|
||||||
conn->ref = 1;
|
conn->ref = 1;
|
||||||
@@ -798,7 +757,8 @@ int xmpp_connect_component(xmpp_conn_t *conn,
|
|||||||
return XMPP_EINVOP;
|
return XMPP_EINVOP;
|
||||||
|
|
||||||
/* XEP-0114 does not support TLS */
|
/* XEP-0114 does not support TLS */
|
||||||
xmpp_conn_disable_tls(conn);
|
(void)xmpp_conn_set_flags(conn, xmpp_conn_get_flags(conn) |
|
||||||
|
XMPP_CONN_FLAG_DISABLE_TLS);
|
||||||
if (!conn->tls_disabled) {
|
if (!conn->tls_disabled) {
|
||||||
strophe_error(conn->ctx, "conn",
|
strophe_error(conn->ctx, "conn",
|
||||||
"Failed to disable TLS. "
|
"Failed to disable TLS. "
|
||||||
@@ -862,9 +822,10 @@ void conn_established(xmpp_conn_t *conn)
|
|||||||
|
|
||||||
if (conn->is_raw) {
|
if (conn->is_raw) {
|
||||||
handler_reset_timed(conn, 0);
|
handler_reset_timed(conn, 0);
|
||||||
/* we skip authentication for a "raw" connection, but the event loop
|
/* we skip all the mandatory steps of the stream negotiation for a "raw"
|
||||||
ignores user's handlers when conn->authenticated is not set. */
|
connection, but the event loop ignores user's handlers when
|
||||||
conn->authenticated = 1;
|
conn->stream_negotiation_completed is not set. */
|
||||||
|
conn->stream_negotiation_completed = 1;
|
||||||
conn->conn_handler(conn, XMPP_CONN_RAW_CONNECT, 0, NULL,
|
conn->conn_handler(conn, XMPP_CONN_RAW_CONNECT, 0, NULL,
|
||||||
conn->userdata);
|
conn->userdata);
|
||||||
} else {
|
} else {
|
||||||
@@ -958,6 +919,7 @@ void conn_disconnect(xmpp_conn_t *conn)
|
|||||||
{
|
{
|
||||||
strophe_debug(conn->ctx, "xmpp", "Closing socket.");
|
strophe_debug(conn->ctx, "xmpp", "Closing socket.");
|
||||||
conn->state = XMPP_STATE_DISCONNECTED;
|
conn->state = XMPP_STATE_DISCONNECTED;
|
||||||
|
conn->stream_negotiation_completed = 0;
|
||||||
if (conn->tls) {
|
if (conn->tls) {
|
||||||
tls_stop(conn->tls);
|
tls_stop(conn->tls);
|
||||||
tls_free(conn->tls);
|
tls_free(conn->tls);
|
||||||
@@ -1026,7 +988,7 @@ void xmpp_send_raw_string(xmpp_conn_t *conn, const char *fmt, ...)
|
|||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
|
|
||||||
if (conn->state != XMPP_STATE_CONNECTED)
|
if (!_is_connected(conn, XMPP_QUEUE_USER))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
@@ -1101,6 +1063,23 @@ void conn_open_stream(xmpp_conn_t *conn)
|
|||||||
strophe_free(conn->ctx, from);
|
strophe_free(conn->ctx, from);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int conn_interface_write(struct conn_interface *intf,
|
||||||
|
const void *buff,
|
||||||
|
size_t len)
|
||||||
|
{
|
||||||
|
int ret = intf->write(intf, buff, len);
|
||||||
|
if (ret < 0 && !intf->error_is_recoverable(intf, intf->get_error(intf))) {
|
||||||
|
intf->conn->error = intf->get_error(intf);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int conn_int_nop(struct conn_interface *intf)
|
||||||
|
{
|
||||||
|
UNUSED(intf);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int conn_tls_start(xmpp_conn_t *conn)
|
int conn_tls_start(xmpp_conn_t *conn)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
@@ -1114,14 +1093,18 @@ 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.conn = conn;
|
||||||
if (tls_start(conn->tls)) {
|
if (tls_start(conn->tls)) {
|
||||||
conn->secured = 1;
|
conn->secured = 1;
|
||||||
} else {
|
} else {
|
||||||
rc = XMPP_EINT;
|
rc = XMPP_EINT;
|
||||||
conn->error = tls_error(conn->tls);
|
conn->error = tls_error(&conn->intf);
|
||||||
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) {
|
||||||
@@ -1145,11 +1128,15 @@ long xmpp_conn_get_flags(const xmpp_conn_t *conn)
|
|||||||
{
|
{
|
||||||
long flags;
|
long flags;
|
||||||
|
|
||||||
flags = XMPP_CONN_FLAG_DISABLE_TLS * conn->tls_disabled |
|
flags =
|
||||||
XMPP_CONN_FLAG_MANDATORY_TLS * conn->tls_mandatory |
|
XMPP_CONN_FLAG_DISABLE_TLS * conn->tls_disabled |
|
||||||
XMPP_CONN_FLAG_LEGACY_SSL * conn->tls_legacy_ssl |
|
XMPP_CONN_FLAG_MANDATORY_TLS * conn->tls_mandatory |
|
||||||
XMPP_CONN_FLAG_TRUST_TLS * conn->tls_trust |
|
XMPP_CONN_FLAG_LEGACY_SSL * conn->tls_legacy_ssl |
|
||||||
XMPP_CONN_FLAG_LEGACY_AUTH * conn->auth_legacy_enabled;
|
XMPP_CONN_FLAG_TRUST_TLS * conn->tls_trust |
|
||||||
|
XMPP_CONN_FLAG_DISABLE_SM * conn->sm_disable |
|
||||||
|
XMPP_CONN_FLAG_ENABLE_COMPRESSION * conn->compression.allowed |
|
||||||
|
XMPP_CONN_FLAG_COMPRESSION_DONT_RESET * conn->compression.dont_reset |
|
||||||
|
XMPP_CONN_FLAG_LEGACY_AUTH * conn->auth_legacy_enabled;
|
||||||
|
|
||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
@@ -1163,12 +1150,14 @@ long xmpp_conn_get_flags(const xmpp_conn_t *conn)
|
|||||||
*
|
*
|
||||||
* Supported flags are:
|
* Supported flags are:
|
||||||
*
|
*
|
||||||
* - XMPP_CONN_FLAG_DISABLE_TLS
|
* - \ref XMPP_CONN_FLAG_DISABLE_TLS
|
||||||
* - XMPP_CONN_FLAG_MANDATORY_TLS
|
* - \ref XMPP_CONN_FLAG_MANDATORY_TLS
|
||||||
* - XMPP_CONN_FLAG_LEGACY_SSL
|
* - \ref XMPP_CONN_FLAG_LEGACY_SSL
|
||||||
* - XMPP_CONN_FLAG_TRUST_TLS
|
* - \ref XMPP_CONN_FLAG_TRUST_TLS
|
||||||
* - XMPP_CONN_FLAG_LEGACY_AUTH
|
* - \ref XMPP_CONN_FLAG_LEGACY_AUTH
|
||||||
* - XMPP_CONN_FLAG_DISABLE_SM
|
* - \ref XMPP_CONN_FLAG_DISABLE_SM
|
||||||
|
* - \ref XMPP_CONN_FLAG_ENABLE_COMPRESSION
|
||||||
|
* - \ref XMPP_CONN_FLAG_COMPRESSION_DONT_RESET
|
||||||
*
|
*
|
||||||
* @param conn a Strophe connection object
|
* @param conn a Strophe connection object
|
||||||
* @param flags ORed connection flags
|
* @param flags ORed connection flags
|
||||||
@@ -1198,29 +1187,23 @@ int xmpp_conn_set_flags(xmpp_conn_t *conn, long flags)
|
|||||||
conn->tls_trust = (flags & XMPP_CONN_FLAG_TRUST_TLS) ? 1 : 0;
|
conn->tls_trust = (flags & XMPP_CONN_FLAG_TRUST_TLS) ? 1 : 0;
|
||||||
conn->auth_legacy_enabled = (flags & XMPP_CONN_FLAG_LEGACY_AUTH) ? 1 : 0;
|
conn->auth_legacy_enabled = (flags & XMPP_CONN_FLAG_LEGACY_AUTH) ? 1 : 0;
|
||||||
conn->sm_disable = (flags & XMPP_CONN_FLAG_DISABLE_SM) ? 1 : 0;
|
conn->sm_disable = (flags & XMPP_CONN_FLAG_DISABLE_SM) ? 1 : 0;
|
||||||
|
conn->compression.allowed =
|
||||||
|
(flags & XMPP_CONN_FLAG_ENABLE_COMPRESSION) ? 1 : 0;
|
||||||
|
conn->compression.dont_reset =
|
||||||
|
(flags & XMPP_CONN_FLAG_COMPRESSION_DONT_RESET) ? 1 : 0;
|
||||||
|
flags &= ~(XMPP_CONN_FLAG_DISABLE_TLS | XMPP_CONN_FLAG_MANDATORY_TLS |
|
||||||
|
XMPP_CONN_FLAG_LEGACY_SSL | XMPP_CONN_FLAG_TRUST_TLS |
|
||||||
|
XMPP_CONN_FLAG_LEGACY_AUTH | XMPP_CONN_FLAG_DISABLE_SM |
|
||||||
|
XMPP_CONN_FLAG_ENABLE_COMPRESSION |
|
||||||
|
XMPP_CONN_FLAG_COMPRESSION_DONT_RESET);
|
||||||
|
if (flags) {
|
||||||
|
strophe_error(conn->ctx, "conn", "Flags 0x%04lx unknown", flags);
|
||||||
|
return XMPP_EINVOP;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Disable TLS for this connection, called by users of the library.
|
|
||||||
* Occasionally a server will be misconfigured to send the starttls
|
|
||||||
* feature, but will not support the handshake.
|
|
||||||
*
|
|
||||||
* @param conn a Strophe connection object
|
|
||||||
*
|
|
||||||
* @note this function is deprecated
|
|
||||||
* @see xmpp_conn_set_flags()
|
|
||||||
*
|
|
||||||
* @ingroup Connections
|
|
||||||
*/
|
|
||||||
void xmpp_conn_disable_tls(xmpp_conn_t *conn)
|
|
||||||
{
|
|
||||||
long flags = xmpp_conn_get_flags(conn);
|
|
||||||
|
|
||||||
flags |= XMPP_CONN_FLAG_DISABLE_TLS;
|
|
||||||
(void)xmpp_conn_set_flags(conn, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Return whether TLS session is established or not.
|
/** Return whether TLS session is established or not.
|
||||||
*
|
*
|
||||||
* @return TRUE if TLS session is established and FALSE otherwise
|
* @return TRUE if TLS session is established and FALSE otherwise
|
||||||
@@ -1239,17 +1222,26 @@ int xmpp_conn_is_secured(xmpp_conn_t *conn)
|
|||||||
*/
|
*/
|
||||||
int xmpp_conn_is_connecting(xmpp_conn_t *conn)
|
int xmpp_conn_is_connecting(xmpp_conn_t *conn)
|
||||||
{
|
{
|
||||||
return conn->state == XMPP_STATE_CONNECTING;
|
return conn->state == XMPP_STATE_CONNECTING ||
|
||||||
|
(conn->state == XMPP_STATE_CONNECTED &&
|
||||||
|
conn->stream_negotiation_completed == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _is_connected(xmpp_conn_t *conn, xmpp_send_queue_owner_t owner)
|
||||||
|
{
|
||||||
|
return conn->state == XMPP_STATE_CONNECTED &&
|
||||||
|
(owner != XMPP_QUEUE_USER ||
|
||||||
|
conn->stream_negotiation_completed == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return TRUE if connection is in connected state and FALSE otherwise
|
* @return TRUE if connection is established and FALSE otherwise
|
||||||
*
|
*
|
||||||
* @ingroup Connections
|
* @ingroup Connections
|
||||||
*/
|
*/
|
||||||
int xmpp_conn_is_connected(xmpp_conn_t *conn)
|
int xmpp_conn_is_connected(xmpp_conn_t *conn)
|
||||||
{
|
{
|
||||||
return conn->state == XMPP_STATE_CONNECTED;
|
return _is_connected(conn, XMPP_QUEUE_USER);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1262,6 +1254,365 @@ int xmpp_conn_is_disconnected(xmpp_conn_t *conn)
|
|||||||
return conn->state == XMPP_STATE_DISCONNECTED;
|
return conn->state == XMPP_STATE_DISCONNECTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This sets the Stream Management callback function
|
||||||
|
*
|
||||||
|
* After setting this API, the library will call the given callback function
|
||||||
|
* each time when the internal SM state is updated.
|
||||||
|
*
|
||||||
|
* This can be used in conjunction with \ref xmpp_conn_restore_sm_state to
|
||||||
|
* e.g. implement a mechanism that retains an SM state over potential
|
||||||
|
* application terminations.
|
||||||
|
*
|
||||||
|
* @param conn a Strophe connection object
|
||||||
|
* @param cb a callback function or NULL to disable
|
||||||
|
* @param ctx a context that will be passed on invocation of the callback
|
||||||
|
* function
|
||||||
|
*
|
||||||
|
* @ingroup Connections
|
||||||
|
*/
|
||||||
|
void xmpp_conn_set_sm_callback(xmpp_conn_t *conn,
|
||||||
|
xmpp_sm_callback cb,
|
||||||
|
void *ctx)
|
||||||
|
{
|
||||||
|
conn->sm_callback = cb;
|
||||||
|
conn->sm_callback_ctx = ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sm_restore {
|
||||||
|
xmpp_conn_t *conn;
|
||||||
|
const unsigned char *state;
|
||||||
|
const unsigned char *const state_end, *const orig;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int sm_load_u32(struct sm_restore *sm, uint8_t type, uint32_t *val)
|
||||||
|
{
|
||||||
|
if (*sm->state != type) {
|
||||||
|
strophe_error(
|
||||||
|
sm->conn->ctx, "conn",
|
||||||
|
"Invalid CBOR type at position %u: 0x%02x, expected: 0x%02x",
|
||||||
|
sm->state - sm->orig, *sm->state, type);
|
||||||
|
return XMPP_EINVOP;
|
||||||
|
}
|
||||||
|
sm->state++;
|
||||||
|
if ((sm->state + 4) > sm->state_end) {
|
||||||
|
strophe_error(sm->conn->ctx, "conn",
|
||||||
|
"Provided sm_state data is too short");
|
||||||
|
return XMPP_EINVOP;
|
||||||
|
}
|
||||||
|
uint32_t v;
|
||||||
|
memcpy(&v, sm->state, 4);
|
||||||
|
sm->state += 4;
|
||||||
|
*val = ntohl(v);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sm_load_string(struct sm_restore *sm, char **val, size_t *len)
|
||||||
|
{
|
||||||
|
uint32_t l;
|
||||||
|
int ret = sm_load_u32(sm, 0x7a, &l);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
if ((sm->state + l) > sm->state_end) {
|
||||||
|
strophe_error(sm->conn->ctx, "conn",
|
||||||
|
"Provided sm_state data is too short");
|
||||||
|
return XMPP_EINVOP;
|
||||||
|
}
|
||||||
|
*val = strophe_alloc(sm->conn->ctx, l + 1);
|
||||||
|
if (!*val)
|
||||||
|
return XMPP_EMEM;
|
||||||
|
memcpy(*val, sm->state, l);
|
||||||
|
(*val)[l] = '\0';
|
||||||
|
sm->state += l;
|
||||||
|
*len = l;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This restores the serialized Stream Management state
|
||||||
|
*
|
||||||
|
* After setting this API, the library will call the given callback function
|
||||||
|
* each time when the internal SM state is updated.
|
||||||
|
*
|
||||||
|
* This can be used in conjunction with \ref xmpp_conn_restore_sm_state to
|
||||||
|
* e.g. implement a mechanism that retains an SM state over potential
|
||||||
|
* application terminations.
|
||||||
|
*
|
||||||
|
* @param conn a Strophe connection object
|
||||||
|
* @param sm_state a buffer as passed to the SM callback
|
||||||
|
* @param sm_state_len the length of `sm_state`
|
||||||
|
*
|
||||||
|
* @ingroup Connections
|
||||||
|
*/
|
||||||
|
int xmpp_conn_restore_sm_state(xmpp_conn_t *conn,
|
||||||
|
const unsigned char *sm_state,
|
||||||
|
size_t sm_state_len)
|
||||||
|
{
|
||||||
|
/* We can only set the SM state when we're disconnected */
|
||||||
|
if (conn->state != XMPP_STATE_DISCONNECTED) {
|
||||||
|
strophe_error(conn->ctx, "conn",
|
||||||
|
"SM state can only be set the when we're disconnected");
|
||||||
|
return XMPP_EINVOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (conn->sm_state) {
|
||||||
|
strophe_error(conn->ctx, "conn", "SM state is already set!");
|
||||||
|
return XMPP_EINVOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sm_state_len < 5 * 6) {
|
||||||
|
strophe_error(conn->ctx, "conn", "Provided sm_state data is too short");
|
||||||
|
return XMPP_EINVOP;
|
||||||
|
}
|
||||||
|
struct sm_restore sm = {.conn = conn,
|
||||||
|
.state = sm_state,
|
||||||
|
.state_end = sm_state + sm_state_len,
|
||||||
|
.orig = sm_state};
|
||||||
|
/* Check for pointer wrap-around, which should never happen */
|
||||||
|
if (sm.state_end < sm.state) {
|
||||||
|
strophe_error(conn->ctx, "conn",
|
||||||
|
"Internal error, pointer wrapped around");
|
||||||
|
return XMPP_EINVOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memcmp(sm.state, "\x1a\x00\x00\x00\x00", 5) != 0) {
|
||||||
|
strophe_error(conn->ctx, "conn", "Unknown sm_state version");
|
||||||
|
return XMPP_EINVOP;
|
||||||
|
}
|
||||||
|
sm.state += 5;
|
||||||
|
|
||||||
|
conn->sm_state = strophe_alloc(conn->ctx, sizeof(*conn->sm_state));
|
||||||
|
if (!conn->sm_state)
|
||||||
|
return XMPP_EMEM;
|
||||||
|
|
||||||
|
memset(conn->sm_state, 0, sizeof(*conn->sm_state));
|
||||||
|
conn->sm_state->ctx = conn->ctx;
|
||||||
|
|
||||||
|
conn->sm_state->sm_support = 1;
|
||||||
|
conn->sm_state->sm_enabled = 1;
|
||||||
|
conn->sm_state->can_resume = 1;
|
||||||
|
conn->sm_state->resume = 1;
|
||||||
|
|
||||||
|
int ret;
|
||||||
|
ret = sm_load_u32(&sm, 0x1a, &conn->sm_state->sm_sent_nr);
|
||||||
|
if (ret)
|
||||||
|
goto err_reload;
|
||||||
|
|
||||||
|
ret = sm_load_u32(&sm, 0x1a, &conn->sm_state->sm_handled_nr);
|
||||||
|
if (ret)
|
||||||
|
goto err_reload;
|
||||||
|
|
||||||
|
size_t id_len;
|
||||||
|
ret = sm_load_string(&sm, &conn->sm_state->id, &id_len);
|
||||||
|
if (ret)
|
||||||
|
goto err_reload;
|
||||||
|
|
||||||
|
uint32_t len, i;
|
||||||
|
ret = sm_load_u32(&sm, 0x9a, &len);
|
||||||
|
if (ret)
|
||||||
|
goto err_reload;
|
||||||
|
conn->send_queue_user_len = conn->send_queue_len = len;
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
xmpp_send_queue_t *item = strophe_alloc(conn->ctx, sizeof(*item));
|
||||||
|
if (!item) {
|
||||||
|
ret = XMPP_EMEM;
|
||||||
|
goto err_reload;
|
||||||
|
}
|
||||||
|
memset(item, 0, sizeof(*item));
|
||||||
|
|
||||||
|
if (!conn->send_queue_tail) {
|
||||||
|
conn->send_queue_head = item;
|
||||||
|
conn->send_queue_tail = item;
|
||||||
|
} else {
|
||||||
|
conn->send_queue_tail->next = item;
|
||||||
|
conn->send_queue_tail = item;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = sm_load_string(&sm, &item->data, &item->len);
|
||||||
|
if (ret)
|
||||||
|
goto err_reload;
|
||||||
|
|
||||||
|
item->owner = XMPP_QUEUE_USER;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = sm_load_u32(&sm, 0xba, &len);
|
||||||
|
if (ret)
|
||||||
|
goto err_reload;
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
xmpp_send_queue_t *item = strophe_alloc(conn->ctx, sizeof(*item));
|
||||||
|
if (!item) {
|
||||||
|
ret = XMPP_EMEM;
|
||||||
|
goto err_reload;
|
||||||
|
}
|
||||||
|
memset(item, 0, sizeof(*item));
|
||||||
|
|
||||||
|
add_queue_back(&conn->sm_state->sm_queue, item);
|
||||||
|
|
||||||
|
ret = sm_load_u32(&sm, 0x1a, &item->sm_h);
|
||||||
|
if (ret)
|
||||||
|
goto err_reload;
|
||||||
|
ret = sm_load_string(&sm, &item->data, &item->len);
|
||||||
|
if (ret)
|
||||||
|
goto err_reload;
|
||||||
|
|
||||||
|
item->owner = XMPP_QUEUE_USER;
|
||||||
|
}
|
||||||
|
|
||||||
|
return XMPP_EOK;
|
||||||
|
|
||||||
|
err_reload:
|
||||||
|
xmpp_free_sm_state(conn->sm_state);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sm_store_u32(unsigned char **next_,
|
||||||
|
const unsigned char *const end,
|
||||||
|
uint8_t type,
|
||||||
|
uint32_t val)
|
||||||
|
{
|
||||||
|
unsigned char *next = *next_;
|
||||||
|
if (next + 5 > end)
|
||||||
|
return 1;
|
||||||
|
*next++ = type;
|
||||||
|
uint32_t v = htonl(val);
|
||||||
|
memcpy(next, &v, 4);
|
||||||
|
next += 4;
|
||||||
|
*next_ = next;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t sm_state_serialize(xmpp_conn_t *conn, unsigned char **buf)
|
||||||
|
{
|
||||||
|
if (!conn->sm_state->sm_support || !conn->sm_state->sm_enabled ||
|
||||||
|
!conn->sm_state->can_resume) {
|
||||||
|
*buf = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t id_len = strlen(conn->sm_state->id);
|
||||||
|
xmpp_send_queue_t *peek = conn->sm_state->sm_queue.head;
|
||||||
|
size_t sm_queue_len = 0;
|
||||||
|
size_t sm_queue_size = 0;
|
||||||
|
while (peek) {
|
||||||
|
sm_queue_len++;
|
||||||
|
sm_queue_size += 10 + peek->len;
|
||||||
|
peek = peek->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t send_queue_len = 0;
|
||||||
|
size_t send_queue_size = 0;
|
||||||
|
peek = conn->send_queue_head;
|
||||||
|
while (peek) {
|
||||||
|
send_queue_len++;
|
||||||
|
send_queue_size += 5 + peek->len;
|
||||||
|
peek = peek->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t buf_size =
|
||||||
|
5 + 5 + 5 + 5 + id_len + 5 + send_queue_size + 5 + sm_queue_size;
|
||||||
|
*buf = strophe_alloc(conn->ctx, buf_size);
|
||||||
|
if (*buf == NULL)
|
||||||
|
return 0;
|
||||||
|
unsigned char *next = *buf;
|
||||||
|
const unsigned char *const end = next + buf_size;
|
||||||
|
/* Check for pointer wrap-around, which should never happen */
|
||||||
|
if (end < next) {
|
||||||
|
strophe_error(conn->ctx, "conn",
|
||||||
|
"Internal error, pointer wrapped around");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(next, "\x1a\x00\x00\x00\x00", 5); // Version
|
||||||
|
next += 5;
|
||||||
|
|
||||||
|
if (sm_store_u32(&next, end, 0x1a, conn->sm_state->sm_sent_nr))
|
||||||
|
goto err_serialize;
|
||||||
|
if (sm_store_u32(&next, end, 0x1a, conn->sm_state->sm_handled_nr))
|
||||||
|
goto err_serialize;
|
||||||
|
|
||||||
|
if (sm_store_u32(&next, end, 0x7a, id_len))
|
||||||
|
goto err_serialize;
|
||||||
|
memcpy(next, conn->sm_state->id, id_len);
|
||||||
|
next += id_len;
|
||||||
|
|
||||||
|
if (sm_store_u32(&next, end, 0x9a, send_queue_len))
|
||||||
|
goto err_serialize;
|
||||||
|
|
||||||
|
peek = conn->send_queue_head;
|
||||||
|
while (peek) {
|
||||||
|
if (sm_store_u32(&next, end, 0x7a, (uint32_t)peek->len))
|
||||||
|
goto err_serialize;
|
||||||
|
if (next + peek->len > end)
|
||||||
|
goto err_serialize;
|
||||||
|
memcpy(next, peek->data, peek->len);
|
||||||
|
next += peek->len;
|
||||||
|
peek = peek->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sm_store_u32(&next, end, 0xba, sm_queue_len))
|
||||||
|
goto err_serialize;
|
||||||
|
|
||||||
|
peek = conn->sm_state->sm_queue.head;
|
||||||
|
while (peek) {
|
||||||
|
if (sm_store_u32(&next, end, 0x1a, peek->sm_h))
|
||||||
|
goto err_serialize;
|
||||||
|
|
||||||
|
if (sm_store_u32(&next, end, 0x7a, (uint32_t)peek->len))
|
||||||
|
goto err_serialize;
|
||||||
|
if (next + peek->len > end)
|
||||||
|
goto err_serialize;
|
||||||
|
memcpy(next, peek->data, peek->len);
|
||||||
|
next += peek->len;
|
||||||
|
peek = peek->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf_size;
|
||||||
|
|
||||||
|
err_serialize:
|
||||||
|
strophe_error(conn->ctx, "conn", "Can't serialize more data, buffer full");
|
||||||
|
strophe_free(conn->ctx, buf);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void trigger_sm_callback(xmpp_conn_t *conn)
|
||||||
|
{
|
||||||
|
if (!conn || !conn->sm_callback)
|
||||||
|
return;
|
||||||
|
|
||||||
|
unsigned char *buf;
|
||||||
|
size_t size = sm_state_serialize(conn, &buf);
|
||||||
|
conn->sm_callback(conn, conn->sm_callback_ctx, buf, size);
|
||||||
|
strophe_free(conn->ctx, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _reset_sm_state_for_reconnect(xmpp_conn_t *conn)
|
||||||
|
{
|
||||||
|
xmpp_sm_state_t *s = conn->sm_state;
|
||||||
|
|
||||||
|
if (s->previd) {
|
||||||
|
strophe_free(conn->ctx, s->previd);
|
||||||
|
s->previd = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s->can_resume) {
|
||||||
|
s->previd = s->id;
|
||||||
|
s->id = NULL;
|
||||||
|
|
||||||
|
s->bound_jid = conn->bound_jid;
|
||||||
|
conn->bound_jid = NULL;
|
||||||
|
} else if (s->id) {
|
||||||
|
strophe_free(conn->ctx, s->id);
|
||||||
|
s->id = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
s->r_sent = s->sm_enabled = s->sm_support = s->resume = 0;
|
||||||
|
|
||||||
|
if (s->bind) {
|
||||||
|
xmpp_stanza_release(s->bind);
|
||||||
|
s->bind = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This returns the Stream Management state of a connection object after
|
* This returns the Stream Management state of a connection object after
|
||||||
* it has been disconnected.
|
* it has been disconnected.
|
||||||
@@ -1293,34 +1644,6 @@ xmpp_sm_state_t *xmpp_conn_get_sm_state(xmpp_conn_t *conn)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _reset_sm_state_for_reconnect(xmpp_conn_t *conn)
|
|
||||||
{
|
|
||||||
xmpp_sm_state_t *s = conn->sm_state;
|
|
||||||
|
|
||||||
if (s->previd) {
|
|
||||||
strophe_free(conn->ctx, s->previd);
|
|
||||||
s->previd = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (s->can_resume) {
|
|
||||||
s->previd = s->id;
|
|
||||||
s->id = NULL;
|
|
||||||
|
|
||||||
s->bound_jid = conn->bound_jid;
|
|
||||||
conn->bound_jid = NULL;
|
|
||||||
} else if (s->id) {
|
|
||||||
strophe_free(conn->ctx, s->id);
|
|
||||||
s->id = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
s->sm_enabled = s->sm_support = s->resume = 0;
|
|
||||||
|
|
||||||
if (s->bind) {
|
|
||||||
xmpp_stanza_release(s->bind);
|
|
||||||
s->bind = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param conn a Strophe connection object
|
* @param conn a Strophe connection object
|
||||||
* @param sm_state A Stream Management state returned from a call to
|
* @param sm_state A Stream Management state returned from a call to
|
||||||
@@ -1333,8 +1656,11 @@ static void _reset_sm_state_for_reconnect(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)
|
||||||
{
|
{
|
||||||
/* We can only set the SM state when we're disconnected */
|
/* We can only set the SM state when we're disconnected */
|
||||||
if (conn->state != XMPP_STATE_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;
|
return XMPP_EINVOP;
|
||||||
|
}
|
||||||
|
|
||||||
if (conn->sm_state) {
|
if (conn->sm_state) {
|
||||||
strophe_error(conn->ctx, "conn", "SM state is already set!");
|
strophe_error(conn->ctx, "conn", "SM state is already set!");
|
||||||
@@ -1353,6 +1679,21 @@ int xmpp_conn_set_sm_state(xmpp_conn_t *conn, xmpp_sm_state_t *sm_state)
|
|||||||
return XMPP_EOK;
|
return XMPP_EOK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void reset_sm_state(xmpp_sm_state_t *sm_state)
|
||||||
|
{
|
||||||
|
xmpp_ctx_t *ctx = sm_state->ctx;
|
||||||
|
|
||||||
|
strophe_free_and_null(ctx, sm_state->id);
|
||||||
|
strophe_free_and_null(ctx, sm_state->previd);
|
||||||
|
strophe_free_and_null(ctx, sm_state->bound_jid);
|
||||||
|
if (sm_state->bind)
|
||||||
|
xmpp_stanza_release(sm_state->bind);
|
||||||
|
sm_state->bind = NULL;
|
||||||
|
sm_state->sm_handled_nr = 0;
|
||||||
|
sm_state->sm_sent_nr = 0;
|
||||||
|
sm_state->r_sent = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/** c.f. \ref xmpp_conn_get_sm_state for usage documentation
|
/** c.f. \ref xmpp_conn_get_sm_state for usage documentation
|
||||||
*
|
*
|
||||||
* @param sm_state A Stream Management state returned from a call to
|
* @param sm_state A Stream Management state returned from a call to
|
||||||
@@ -1362,8 +1703,8 @@ int xmpp_conn_set_sm_state(xmpp_conn_t *conn, xmpp_sm_state_t *sm_state)
|
|||||||
*/
|
*/
|
||||||
void xmpp_free_sm_state(xmpp_sm_state_t *sm_state)
|
void xmpp_free_sm_state(xmpp_sm_state_t *sm_state)
|
||||||
{
|
{
|
||||||
xmpp_ctx_t *ctx;
|
|
||||||
xmpp_send_queue_t *smq;
|
xmpp_send_queue_t *smq;
|
||||||
|
xmpp_ctx_t *ctx;
|
||||||
|
|
||||||
if (!sm_state || !sm_state->ctx)
|
if (!sm_state || !sm_state->ctx)
|
||||||
return;
|
return;
|
||||||
@@ -1374,15 +1715,7 @@ void xmpp_free_sm_state(xmpp_sm_state_t *sm_state)
|
|||||||
strophe_free(ctx, queue_element_free(ctx, smq));
|
strophe_free(ctx, queue_element_free(ctx, smq));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sm_state->bind)
|
reset_sm_state(sm_state);
|
||||||
xmpp_stanza_release(sm_state->bind);
|
|
||||||
if (sm_state->id)
|
|
||||||
strophe_free(ctx, sm_state->id);
|
|
||||||
if (sm_state->previd)
|
|
||||||
strophe_free(ctx, sm_state->previd);
|
|
||||||
if (sm_state->bound_jid)
|
|
||||||
strophe_free(ctx, sm_state->bound_jid);
|
|
||||||
memset(sm_state, 0, sizeof(*sm_state));
|
|
||||||
strophe_free(ctx, sm_state);
|
strophe_free(ctx, sm_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1436,6 +1769,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 */
|
||||||
@@ -1444,7 +1778,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)
|
||||||
@@ -1468,7 +1802,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 */
|
||||||
@@ -1482,10 +1816,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 */
|
||||||
@@ -1679,6 +2018,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1746,12 +2086,15 @@ static void _conn_sm_handle_stanza(xmpp_conn_t *const conn,
|
|||||||
while (conn->sm_state->sm_queue.head &&
|
while (conn->sm_state->sm_queue.head &&
|
||||||
conn->sm_state->sm_queue.head->sm_h < ul_h) {
|
conn->sm_state->sm_queue.head->sm_h < ul_h) {
|
||||||
e = pop_queue_front(&conn->sm_state->sm_queue);
|
e = pop_queue_front(&conn->sm_state->sm_queue);
|
||||||
strophe_debug_verbose(2, conn->ctx, "conn", "SM_Q_DROP: %p", e);
|
strophe_debug_verbose(2, conn->ctx, "conn",
|
||||||
|
"SM_Q_DROP: %p, h=%lu", e, e->sm_h);
|
||||||
c = queue_element_free(conn->ctx, e);
|
c = queue_element_free(conn->ctx, e);
|
||||||
strophe_free(conn->ctx, c);
|
strophe_free(conn->ctx, c);
|
||||||
}
|
}
|
||||||
|
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,
|
||||||
@@ -1788,6 +2131,11 @@ static void _conn_reset(xmpp_conn_t *conn)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
compression_free(conn);
|
||||||
|
|
||||||
|
conn->intf = sock_intf;
|
||||||
|
conn->intf.conn = conn;
|
||||||
|
|
||||||
/* free queued */
|
/* free queued */
|
||||||
sq = conn->send_queue_head;
|
sq = conn->send_queue_head;
|
||||||
while (sq) {
|
while (sq) {
|
||||||
@@ -1802,22 +2150,14 @@ static void _conn_reset(xmpp_conn_t *conn)
|
|||||||
|
|
||||||
if (conn->stream_error) {
|
if (conn->stream_error) {
|
||||||
xmpp_stanza_release(conn->stream_error->stanza);
|
xmpp_stanza_release(conn->stream_error->stanza);
|
||||||
if (conn->stream_error->text)
|
strophe_free_and_null(ctx, conn->stream_error->text);
|
||||||
strophe_free(ctx, conn->stream_error->text);
|
strophe_free_and_null(ctx, conn->stream_error);
|
||||||
strophe_free(ctx, conn->stream_error);
|
|
||||||
conn->stream_error = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (conn->domain)
|
strophe_free_and_null(ctx, conn->domain);
|
||||||
strophe_free(ctx, conn->domain);
|
strophe_free_and_null(ctx, conn->bound_jid);
|
||||||
if (conn->bound_jid)
|
strophe_free_and_null(ctx, conn->stream_id);
|
||||||
strophe_free(ctx, conn->bound_jid);
|
conn->stream_negotiation_completed = 0;
|
||||||
if (conn->stream_id)
|
|
||||||
strophe_free(ctx, conn->stream_id);
|
|
||||||
conn->domain = NULL;
|
|
||||||
conn->bound_jid = NULL;
|
|
||||||
conn->stream_id = NULL;
|
|
||||||
conn->authenticated = 0;
|
|
||||||
conn->secured = 0;
|
conn->secured = 0;
|
||||||
conn->tls_failed = 0;
|
conn->tls_failed = 0;
|
||||||
conn->error = 0;
|
conn->error = 0;
|
||||||
@@ -1904,7 +2244,7 @@ static void _send_valist(xmpp_conn_t *conn,
|
|||||||
char buf[1024]; /* small buffer for common case */
|
char buf[1024]; /* small buffer for common case */
|
||||||
char *bigbuf;
|
char *bigbuf;
|
||||||
|
|
||||||
if (conn->state != XMPP_STATE_CONNECTED)
|
if (!_is_connected(conn, owner))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
va_copy(apdup, ap);
|
va_copy(apdup, ap);
|
||||||
@@ -1952,7 +2292,7 @@ void send_stanza(xmpp_conn_t *conn,
|
|||||||
char *buf = NULL;
|
char *buf = NULL;
|
||||||
size_t len;
|
size_t len;
|
||||||
|
|
||||||
if (conn->state != XMPP_STATE_CONNECTED)
|
if (!_is_connected(conn, owner))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (xmpp_stanza_to_text(stanza, &buf, &len) != 0) {
|
if (xmpp_stanza_to_text(stanza, &buf, &len) != 0) {
|
||||||
@@ -1979,6 +2319,11 @@ void add_queue_back(xmpp_queue_t *queue, xmpp_send_queue_t *item)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
xmpp_send_queue_t *peek_queue_front(xmpp_queue_t *queue)
|
||||||
|
{
|
||||||
|
return queue->head;
|
||||||
|
}
|
||||||
|
|
||||||
xmpp_send_queue_t *pop_queue_front(xmpp_queue_t *queue)
|
xmpp_send_queue_t *pop_queue_front(xmpp_queue_t *queue)
|
||||||
{
|
{
|
||||||
xmpp_send_queue_t *ret = queue->head;
|
xmpp_send_queue_t *ret = queue->head;
|
||||||
@@ -2034,8 +2379,12 @@ static int _send_raw(xmpp_conn_t *conn,
|
|||||||
conn->send_queue_user_len++;
|
conn->send_queue_user_len++;
|
||||||
strophe_debug_verbose(3, conn->ctx, "conn", "QUEUED: %s", data);
|
strophe_debug_verbose(3, conn->ctx, "conn", "QUEUED: %s", data);
|
||||||
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 = 1;
|
||||||
send_raw(conn, req_ack, strlen(req_ack), XMPP_QUEUE_SM_STROPHE, item);
|
send_raw(conn, req_ack, strlen(req_ack), XMPP_QUEUE_SM_STROPHE, item);
|
||||||
|
} else {
|
||||||
|
trigger_sm_callback(conn);
|
||||||
}
|
}
|
||||||
return XMPP_EOK;
|
return XMPP_EOK;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
|
||||||
/* crypto.c
|
/* crypto.c
|
||||||
* strophe XMPP client library -- public interface for digests, encodings
|
* strophe XMPP client library -- public interface for digests, encodings
|
||||||
*
|
*
|
||||||
@@ -6,7 +7,7 @@
|
|||||||
* This software is provided AS-IS with no warranty, either express
|
* This software is provided AS-IS with no warranty, either express
|
||||||
* or implied.
|
* or implied.
|
||||||
*
|
*
|
||||||
* This program is dual licensed under the MIT and GPLv3 licenses.
|
* This program is dual licensed under the MIT or GPLv3 licenses.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @file
|
/** @file
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
|
||||||
/* ctx.c
|
/* ctx.c
|
||||||
** strophe XMPP client library -- run-time context implementation
|
** strophe XMPP client library -- run-time context implementation
|
||||||
**
|
**
|
||||||
@@ -6,7 +7,7 @@
|
|||||||
** This software is provided AS-IS with no warranty, either express
|
** This software is provided AS-IS with no warranty, either express
|
||||||
** or implied.
|
** or implied.
|
||||||
**
|
**
|
||||||
** This program is dual licensed under the MIT and GPLv3 licenses.
|
** This program is dual licensed under the MIT or GPLv3 licenses.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @file
|
/** @file
|
||||||
@@ -464,6 +465,8 @@ xmpp_ctx_t *xmpp_ctx_new(const xmpp_mem_t *mem, const xmpp_log_t *log)
|
|||||||
ctx = mem->alloc(sizeof(xmpp_ctx_t), mem->userdata);
|
ctx = mem->alloc(sizeof(xmpp_ctx_t), mem->userdata);
|
||||||
|
|
||||||
if (ctx != NULL) {
|
if (ctx != NULL) {
|
||||||
|
memset(ctx, 0, sizeof(xmpp_ctx_t));
|
||||||
|
|
||||||
if (mem != NULL)
|
if (mem != NULL)
|
||||||
ctx->mem = mem;
|
ctx->mem = mem;
|
||||||
else
|
else
|
||||||
@@ -474,12 +477,9 @@ xmpp_ctx_t *xmpp_ctx_new(const xmpp_mem_t *mem, const xmpp_log_t *log)
|
|||||||
else
|
else
|
||||||
ctx->log = log;
|
ctx->log = log;
|
||||||
|
|
||||||
ctx->connlist = NULL;
|
|
||||||
ctx->timed_handlers = NULL;
|
|
||||||
ctx->loop_status = XMPP_LOOP_NOTSTARTED;
|
ctx->loop_status = XMPP_LOOP_NOTSTARTED;
|
||||||
ctx->rand = xmpp_rand_new(ctx);
|
ctx->rand = xmpp_rand_new(ctx);
|
||||||
ctx->timeout = EVENT_LOOP_DEFAULT_TIMEOUT;
|
ctx->timeout = EVENT_LOOP_DEFAULT_TIMEOUT;
|
||||||
ctx->verbosity = 0;
|
|
||||||
if (ctx->rand == NULL) {
|
if (ctx->rand == NULL) {
|
||||||
strophe_free(ctx, ctx);
|
strophe_free(ctx, ctx);
|
||||||
ctx = NULL;
|
ctx = NULL;
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
|
||||||
/* deprecated.c
|
/* deprecated.c
|
||||||
** strophe XMPP client library -- File with deprecated API functions.
|
** strophe XMPP client library -- File with deprecated API functions.
|
||||||
**
|
**
|
||||||
@@ -6,7 +7,7 @@
|
|||||||
** This software is provided AS-IS with no warranty, either express
|
** This software is provided AS-IS with no warranty, either express
|
||||||
** or implied.
|
** or implied.
|
||||||
**
|
**
|
||||||
** This program is dual licensed under the MIT and GPLv3 licenses.
|
** This program is dual licensed under the MIT or GPLv3 licenses.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @file
|
/** @file
|
||||||
@@ -254,3 +255,22 @@ void xmpp_conn_set_keepalive(xmpp_conn_t *conn, int timeout, int interval)
|
|||||||
conn->ka_count = 0;
|
conn->ka_count = 0;
|
||||||
xmpp_conn_set_sockopt_callback(conn, 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.
|
||||||
|
* Occasionally a server will be misconfigured to send the starttls
|
||||||
|
* feature, but will not support the handshake.
|
||||||
|
*
|
||||||
|
* @param conn a Strophe connection object
|
||||||
|
*
|
||||||
|
* @note this function is deprecated
|
||||||
|
* @see xmpp_conn_set_flags()
|
||||||
|
*
|
||||||
|
* @ingroup Deprecated
|
||||||
|
*/
|
||||||
|
void xmpp_conn_disable_tls(xmpp_conn_t *conn)
|
||||||
|
{
|
||||||
|
long flags = xmpp_conn_get_flags(conn);
|
||||||
|
|
||||||
|
flags |= XMPP_CONN_FLAG_DISABLE_TLS;
|
||||||
|
(void)xmpp_conn_set_flags(conn, flags);
|
||||||
|
}
|
||||||
|
|||||||
72
src/event.c
72
src/event.c
@@ -1,3 +1,4 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
|
||||||
/* event.c
|
/* event.c
|
||||||
** strophe XMPP client library -- event loop and management
|
** strophe XMPP client library -- event loop and management
|
||||||
**
|
**
|
||||||
@@ -6,7 +7,7 @@
|
|||||||
** This software is provided AS-IS with no warranty, either express
|
** This software is provided AS-IS with no warranty, either express
|
||||||
** or implied.
|
** or implied.
|
||||||
**
|
**
|
||||||
** This program is dual licensed under the MIT and GPLv3 licenses.
|
** This program is dual licensed under the MIT or GPLv3 licenses.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @file
|
/** @file
|
||||||
@@ -38,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
|
||||||
@@ -57,8 +58,10 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
|
|
||||||
|
#ifndef STROPHE_MESSAGE_BUFFER_SIZE
|
||||||
/** Max buffer size for receiving messages. */
|
/** Max buffer size for receiving messages. */
|
||||||
#define STROPE_MESSAGE_BUFFER_SIZE 4096
|
#define STROPHE_MESSAGE_BUFFER_SIZE 4096
|
||||||
|
#endif
|
||||||
|
|
||||||
static int _connect_next(xmpp_conn_t *conn)
|
static int _connect_next(xmpp_conn_t *conn)
|
||||||
{
|
{
|
||||||
@@ -89,13 +92,14 @@ void xmpp_run_once(xmpp_ctx_t *ctx, unsigned long timeout)
|
|||||||
{
|
{
|
||||||
xmpp_connlist_t *connitem;
|
xmpp_connlist_t *connitem;
|
||||||
xmpp_conn_t *conn;
|
xmpp_conn_t *conn;
|
||||||
|
struct conn_interface *intf;
|
||||||
fd_set rfds, wfds;
|
fd_set rfds, wfds;
|
||||||
sock_t max = 0;
|
sock_t max = 0;
|
||||||
int ret;
|
int ret;
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
xmpp_send_queue_t *sq, *tsq;
|
xmpp_send_queue_t *sq, *tsq;
|
||||||
int towrite;
|
int towrite;
|
||||||
char buf[STROPE_MESSAGE_BUFFER_SIZE];
|
char buf[STROPHE_MESSAGE_BUFFER_SIZE];
|
||||||
uint64_t next;
|
uint64_t next;
|
||||||
uint64_t usec;
|
uint64_t usec;
|
||||||
int tls_read_bytes = 0;
|
int tls_read_bytes = 0;
|
||||||
@@ -111,16 +115,18 @@ void xmpp_run_once(xmpp_ctx_t *ctx, unsigned long timeout)
|
|||||||
connitem = connitem->next;
|
connitem = connitem->next;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
intf = &conn->intf;
|
||||||
|
|
||||||
/* if we're running tls, there may be some remaining data waiting to
|
/* if we're running tls, there may be some remaining data waiting to
|
||||||
* be sent, so push that out */
|
* be sent, so push that out */
|
||||||
if (conn->tls) {
|
if (conn->tls) {
|
||||||
ret = tls_clear_pending_write(conn->tls);
|
ret = tls_clear_pending_write(intf);
|
||||||
|
|
||||||
if (ret < 0 && !tls_is_recoverable(tls_error(conn->tls))) {
|
if (ret < 0 && !tls_is_recoverable(intf, tls_error(intf))) {
|
||||||
/* an error occurred */
|
/* an error occurred */
|
||||||
strophe_debug(ctx, "xmpp",
|
strophe_debug(
|
||||||
"Send error occurred, disconnecting.");
|
ctx, "xmpp",
|
||||||
|
"Send error of pending data occurred, disconnecting.");
|
||||||
conn->error = ECONNABORTED;
|
conn->error = ECONNABORTED;
|
||||||
conn_disconnect(conn);
|
conn_disconnect(conn);
|
||||||
goto next_item;
|
goto next_item;
|
||||||
@@ -132,15 +138,7 @@ void xmpp_run_once(xmpp_ctx_t *ctx, unsigned long timeout)
|
|||||||
while (sq) {
|
while (sq) {
|
||||||
towrite = sq->len - sq->written;
|
towrite = sq->len - sq->written;
|
||||||
|
|
||||||
if (conn->tls) {
|
ret = conn_interface_write(intf, &sq->data[sq->written], towrite);
|
||||||
ret = tls_write(conn->tls, &sq->data[sq->written], towrite);
|
|
||||||
if (ret < 0 && !tls_is_recoverable(tls_error(conn->tls)))
|
|
||||||
conn->error = tls_error(conn->tls);
|
|
||||||
} else {
|
|
||||||
ret = sock_write(conn->sock, &sq->data[sq->written], towrite);
|
|
||||||
if (ret < 0 && !sock_is_recoverable(sock_error()))
|
|
||||||
conn->error = sock_error();
|
|
||||||
}
|
|
||||||
if (ret > 0 && ret < towrite)
|
if (ret > 0 && ret < towrite)
|
||||||
sq->written += ret; /* not all data could be sent now */
|
sq->written += ret; /* not all data could be sent now */
|
||||||
sq->wip = 1;
|
sq->wip = 1;
|
||||||
@@ -158,7 +156,8 @@ void xmpp_run_once(xmpp_ctx_t *ctx, unsigned long timeout)
|
|||||||
if (!(tsq->owner & XMPP_QUEUE_SM) && conn->sm_state->sm_enabled) {
|
if (!(tsq->owner & XMPP_QUEUE_SM) && conn->sm_state->sm_enabled) {
|
||||||
tsq->sm_h = conn->sm_state->sm_sent_nr;
|
tsq->sm_h = conn->sm_state->sm_sent_nr;
|
||||||
conn->sm_state->sm_sent_nr++;
|
conn->sm_state->sm_sent_nr++;
|
||||||
strophe_debug_verbose(1, ctx, "xmpp", "SM_Q_MOVE: %p", tsq);
|
strophe_debug_verbose(1, ctx, "xmpp", "SM_Q_MOVE: %p, h=%lu",
|
||||||
|
tsq, tsq->sm_h);
|
||||||
add_queue_back(&conn->sm_state->sm_queue, tsq);
|
add_queue_back(&conn->sm_state->sm_queue, tsq);
|
||||||
tsq = NULL;
|
tsq = NULL;
|
||||||
}
|
}
|
||||||
@@ -175,7 +174,9 @@ 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);
|
||||||
|
|
||||||
/* tear down connection on error */
|
/* tear down connection on error */
|
||||||
if (conn->error) {
|
if (conn->error) {
|
||||||
@@ -210,6 +211,7 @@ next_item:
|
|||||||
connitem = ctx->connlist;
|
connitem = ctx->connlist;
|
||||||
while (connitem) {
|
while (connitem) {
|
||||||
conn = connitem->conn;
|
conn = connitem->conn;
|
||||||
|
intf = &conn->intf;
|
||||||
|
|
||||||
switch (conn->state) {
|
switch (conn->state) {
|
||||||
case XMPP_STATE_CONNECTING:
|
case XMPP_STATE_CONNECTING:
|
||||||
@@ -244,7 +246,7 @@ next_item:
|
|||||||
|
|
||||||
/* Check if there is something in the SSL buffer. */
|
/* Check if there is something in the SSL buffer. */
|
||||||
if (conn->tls)
|
if (conn->tls)
|
||||||
tls_read_bytes += tls_pending(conn->tls);
|
tls_read_bytes += tls_pending(intf);
|
||||||
|
|
||||||
if (conn->state != XMPP_STATE_DISCONNECTED && conn->sock > max)
|
if (conn->state != XMPP_STATE_DISCONNECTED && conn->sock > max)
|
||||||
max = conn->sock;
|
max = conn->sock;
|
||||||
@@ -263,9 +265,9 @@ next_item:
|
|||||||
|
|
||||||
/* select errored */
|
/* select errored */
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
if (!sock_is_recoverable(sock_error()))
|
if (!sock_is_recoverable(NULL, sock_error(NULL)))
|
||||||
strophe_error(ctx, "xmpp", "event watcher internal error %d",
|
strophe_error(ctx, "xmpp", "event watcher internal error %d",
|
||||||
sock_error());
|
sock_error(NULL));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -277,6 +279,7 @@ next_item:
|
|||||||
connitem = ctx->connlist;
|
connitem = ctx->connlist;
|
||||||
while (connitem) {
|
while (connitem) {
|
||||||
conn = connitem->conn;
|
conn = connitem->conn;
|
||||||
|
intf = &conn->intf;
|
||||||
|
|
||||||
switch (conn->state) {
|
switch (conn->state) {
|
||||||
case XMPP_STATE_CONNECTING:
|
case XMPP_STATE_CONNECTING:
|
||||||
@@ -304,14 +307,9 @@ next_item:
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
case XMPP_STATE_CONNECTED:
|
case XMPP_STATE_CONNECTED:
|
||||||
if (FD_ISSET(conn->sock, &rfds) ||
|
if (FD_ISSET(conn->sock, &rfds) || intf->pending(intf)) {
|
||||||
(conn->tls && tls_pending(conn->tls))) {
|
|
||||||
if (conn->tls) {
|
ret = intf->read(intf, buf, STROPHE_MESSAGE_BUFFER_SIZE);
|
||||||
ret = tls_read(conn->tls, buf, STROPE_MESSAGE_BUFFER_SIZE);
|
|
||||||
} else {
|
|
||||||
ret =
|
|
||||||
sock_read(conn->sock, buf, STROPE_MESSAGE_BUFFER_SIZE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ret > 0) {
|
if (ret > 0) {
|
||||||
ret = parser_feed(conn->parser, buf, ret);
|
ret = parser_feed(conn->parser, buf, ret);
|
||||||
@@ -321,15 +319,13 @@ next_item:
|
|||||||
"parse error");
|
"parse error");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (conn->tls) {
|
int err = intf->get_error(intf);
|
||||||
if (!tls_is_recoverable(tls_error(conn->tls))) {
|
if (!intf->error_is_recoverable(intf, err)) {
|
||||||
strophe_debug(ctx, "xmpp",
|
strophe_debug(ctx, "xmpp", "Unrecoverable error: %d.",
|
||||||
"Unrecoverable TLS error, %d.",
|
err);
|
||||||
tls_error(conn->tls));
|
conn->error = err;
|
||||||
conn->error = tls_error(conn->tls);
|
conn_disconnect(conn);
|
||||||
conn_disconnect(conn);
|
} else if (!conn->tls) {
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* return of 0 means socket closed by server */
|
/* return of 0 means socket closed by server */
|
||||||
strophe_debug(ctx, "xmpp",
|
strophe_debug(ctx, "xmpp",
|
||||||
"Socket closed by remote host.");
|
"Socket closed by remote host.");
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
|
||||||
/* handler.c
|
/* handler.c
|
||||||
** strophe XMPP client library -- event handler management
|
** strophe XMPP client library -- event handler management
|
||||||
**
|
**
|
||||||
@@ -6,7 +7,7 @@
|
|||||||
** This software is provided AS-IS with no warranty, either express
|
** This software is provided AS-IS with no warranty, either express
|
||||||
** or implied.
|
** or implied.
|
||||||
**
|
**
|
||||||
** This program is dual licensed under the MIT and GPLv3 licenses.
|
** This program is dual licensed under the MIT or GPLv3 licenses.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @file
|
/** @file
|
||||||
@@ -24,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()
|
||||||
@@ -80,9 +79,9 @@ void handler_fire_stanza(xmpp_conn_t *conn, xmpp_stanza_t *stanza)
|
|||||||
|
|
||||||
item = head;
|
item = head;
|
||||||
while (item) {
|
while (item) {
|
||||||
/* don't fire user handlers until authentication succeeds and
|
/* don't fire user handlers until stream negotiation has completed
|
||||||
and skip newly added handlers */
|
and skip newly added handlers */
|
||||||
if ((item->user_handler && !conn->authenticated) ||
|
if ((item->user_handler && !conn->stream_negotiation_completed) ||
|
||||||
!item->enabled) {
|
!item->enabled) {
|
||||||
item = item->next;
|
item = item->next;
|
||||||
continue;
|
continue;
|
||||||
@@ -116,9 +115,10 @@ void handler_fire_stanza(xmpp_conn_t *conn, xmpp_stanza_t *stanza)
|
|||||||
|
|
||||||
item = conn->handlers;
|
item = conn->handlers;
|
||||||
while (item) {
|
while (item) {
|
||||||
/* don't fire user handlers until authentication succeeds and
|
/* don't fire user handlers until stream negotiation has completed and
|
||||||
skip newly added handlers */
|
skip newly added handlers */
|
||||||
if ((item->user_handler && !conn->authenticated) || !item->enabled) {
|
if ((item->user_handler && !conn->stream_negotiation_completed) ||
|
||||||
|
!item->enabled) {
|
||||||
item = item->next;
|
item = item->next;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -174,9 +174,9 @@ uint64_t handler_fire_timed(xmpp_ctx_t *ctx)
|
|||||||
|
|
||||||
item = conn->timed_handlers;
|
item = conn->timed_handlers;
|
||||||
while (item) {
|
while (item) {
|
||||||
/* don't fire user handlers until authentication succeeds and
|
/* don't fire user handlers until stream negotiation has completed
|
||||||
skip newly added handlers */
|
and skip newly added handlers */
|
||||||
if ((item->user_handler && !conn->authenticated) ||
|
if ((item->user_handler && !conn->stream_negotiation_completed) ||
|
||||||
!item->enabled) {
|
!item->enabled) {
|
||||||
item = item->next;
|
item = item->next;
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
|
||||||
/* hash.c
|
/* hash.c
|
||||||
** strophe XMPP client library -- hash table implementation
|
** strophe XMPP client library -- hash table implementation
|
||||||
**
|
**
|
||||||
@@ -6,7 +7,7 @@
|
|||||||
** This software is provided AS-IS with no warranty, either express
|
** This software is provided AS-IS with no warranty, either express
|
||||||
** or implied.
|
** or implied.
|
||||||
**
|
**
|
||||||
** This program is dual licensed under the MIT and GPLv3 licenses.
|
** This program is dual licensed under the MIT or GPLv3 licenses.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @file
|
/** @file
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
|
||||||
/* hash.h
|
/* hash.h
|
||||||
** strophe XMPP client library -- hash table interface
|
** strophe XMPP client library -- hash table interface
|
||||||
**
|
**
|
||||||
@@ -6,7 +7,7 @@
|
|||||||
** This software is provided AS-IS with no warranty, either express
|
** This software is provided AS-IS with no warranty, either express
|
||||||
** or implied.
|
** or implied.
|
||||||
**
|
**
|
||||||
** This program is dual licensed under the MIT and GPLv3 licenses.
|
** This program is dual licensed under the MIT or GPLv3 licenses.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @file
|
/** @file
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
|
||||||
/* jid.c
|
/* jid.c
|
||||||
** strophe XMPP client library -- helper functions for parsing JIDs
|
** strophe XMPP client library -- helper functions for parsing JIDs
|
||||||
**
|
**
|
||||||
@@ -6,7 +7,7 @@
|
|||||||
** This software is provided AS-IS with no warranty, either express
|
** This software is provided AS-IS with no warranty, either express
|
||||||
** or implied.
|
** or implied.
|
||||||
**
|
**
|
||||||
** This program is dual licensed under the MIT and GPLv3 licenses.
|
** This program is dual licensed under the MIT or GPLv3 licenses.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @file
|
/** @file
|
||||||
|
|||||||
@@ -37,7 +37,7 @@
|
|||||||
|
|
||||||
#define PUT_32BIT_LSB_FIRST(cp, value) \
|
#define PUT_32BIT_LSB_FIRST(cp, value) \
|
||||||
do { \
|
do { \
|
||||||
(cp)[0] = (value)&0xFF; \
|
(cp)[0] = (value) & 0xFF; \
|
||||||
(cp)[1] = ((value) >> 8) & 0xFF; \
|
(cp)[1] = ((value) >> 8) & 0xFF; \
|
||||||
(cp)[2] = ((value) >> 16) & 0xFF; \
|
(cp)[2] = ((value) >> 16) & 0xFF; \
|
||||||
(cp)[3] = ((value) >> 24) & 0xFF; \
|
(cp)[3] = ((value) >> 24) & 0xFF; \
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
|
||||||
/* ostypes.h
|
/* ostypes.h
|
||||||
** strophe XMPP client library -- type definitions for platforms
|
** strophe XMPP client library -- type definitions for platforms
|
||||||
** without stdint.h
|
** without stdint.h
|
||||||
@@ -7,7 +8,7 @@
|
|||||||
** This software is provided AS-IS with no warranty, either express
|
** This software is provided AS-IS with no warranty, either express
|
||||||
** or implied.
|
** or implied.
|
||||||
**
|
**
|
||||||
** This program is dual licensed under the MIT and GPLv3 licenses.
|
** This program is dual licensed under the MIT or GPLv3 licenses.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @file
|
/** @file
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
|
||||||
/* parser.h
|
/* parser.h
|
||||||
** strophe XMPP client library -- parser structures and functions
|
** strophe XMPP client library -- parser structures and functions
|
||||||
**
|
**
|
||||||
@@ -6,7 +7,7 @@
|
|||||||
** This software is provided AS-IS with no warranty, either express or
|
** This software is provided AS-IS with no warranty, either express or
|
||||||
** implied.
|
** implied.
|
||||||
**
|
**
|
||||||
** This program is dual licensed under the MIT and GPLv3 licenses.
|
** This program is dual licensed under the MIT or GPLv3 licenses.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @file
|
/** @file
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
|
||||||
/* parser.c
|
/* parser.c
|
||||||
** strophe XMPP client library -- xml parser handlers and utility functions
|
** strophe XMPP client library -- xml parser handlers and utility functions
|
||||||
**
|
**
|
||||||
@@ -6,7 +7,7 @@
|
|||||||
** This software is provided AS-IS with no warranty, either express
|
** This software is provided AS-IS with no warranty, either express
|
||||||
** or implied.
|
** or implied.
|
||||||
**
|
**
|
||||||
** This program is dual licensed under the MIT and GPLv3 licenses.
|
** This program is dual licensed under the MIT or GPLv3 licenses.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @file
|
/** @file
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
|
||||||
/* parser.c
|
/* parser.c
|
||||||
** strophe XMPP client library -- xml parser handlers and utility functions
|
** strophe XMPP client library -- xml parser handlers and utility functions
|
||||||
**
|
**
|
||||||
@@ -6,7 +7,7 @@
|
|||||||
** This software is provided AS-IS with no warranty, either express
|
** This software is provided AS-IS with no warranty, either express
|
||||||
** or implied.
|
** or implied.
|
||||||
**
|
**
|
||||||
** This program is dual licensed under the MIT and GPLv3 licenses.
|
** This program is dual licensed under the MIT or GPLv3 licenses.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @file
|
/** @file
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
|
||||||
/* rand.c
|
/* rand.c
|
||||||
* strophe XMPP client library -- pseudo-random number generator
|
* strophe XMPP client library -- pseudo-random number generator
|
||||||
*
|
*
|
||||||
@@ -6,7 +7,7 @@
|
|||||||
* This software is provided AS-IS with no warranty, either express
|
* This software is provided AS-IS with no warranty, either express
|
||||||
* or implied.
|
* or implied.
|
||||||
*
|
*
|
||||||
* This program is dual licensed under the MIT and GPLv3 licenses.
|
* This program is dual licensed under the MIT or GPLv3 licenses.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @file
|
/** @file
|
||||||
@@ -67,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.
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
|
||||||
/* resolver.c
|
/* resolver.c
|
||||||
* strophe XMPP client library -- DNS resolver
|
* strophe XMPP client library -- DNS resolver
|
||||||
*
|
*
|
||||||
@@ -6,7 +7,7 @@
|
|||||||
* This software is provided AS-IS with no warranty, either express
|
* This software is provided AS-IS with no warranty, either express
|
||||||
* or implied.
|
* or implied.
|
||||||
*
|
*
|
||||||
* This program is dual licensed under the MIT and GPLv3 licenses.
|
* This program is dual licensed under the MIT or GPLv3 licenses.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @file
|
/** @file
|
||||||
@@ -629,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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
|
||||||
/* resolver.h
|
/* resolver.h
|
||||||
* strophe XMPP client library -- DNS resolver
|
* strophe XMPP client library -- DNS resolver
|
||||||
*
|
*
|
||||||
@@ -6,7 +7,7 @@
|
|||||||
* This software is provided AS-IS with no warranty, either express
|
* This software is provided AS-IS with no warranty, either express
|
||||||
* or implied.
|
* or implied.
|
||||||
*
|
*
|
||||||
* This program is dual licensed under the MIT and GPLv3 licenses.
|
* This program is dual licensed under the MIT or GPLv3 licenses.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @file
|
/** @file
|
||||||
|
|||||||
46
src/sasl.c
46
src/sasl.c
@@ -1,3 +1,4 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
|
||||||
/* sasl.c
|
/* sasl.c
|
||||||
** strophe XMPP client library -- SASL authentication helpers
|
** strophe XMPP client library -- SASL authentication helpers
|
||||||
**
|
**
|
||||||
@@ -6,7 +7,7 @@
|
|||||||
** This software is provided AS-IS with no warranty, either express
|
** This software is provided AS-IS with no warranty, either express
|
||||||
** or implied.
|
** or implied.
|
||||||
**
|
**
|
||||||
** This program is dual licensed under the MIT and GPLv3 licenses.
|
** This program is dual licensed under the MIT or GPLv3 licenses.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @file
|
/** @file
|
||||||
@@ -374,6 +375,7 @@ char *sasl_digest_md5(xmpp_ctx_t *ctx,
|
|||||||
/** generate auth response string for the SASL SCRAM mechanism */
|
/** generate auth response string for the SASL SCRAM mechanism */
|
||||||
char *sasl_scram(xmpp_ctx_t *ctx,
|
char *sasl_scram(xmpp_ctx_t *ctx,
|
||||||
const struct hash_alg *alg,
|
const struct hash_alg *alg,
|
||||||
|
const char *channel_binding,
|
||||||
const char *challenge,
|
const char *challenge,
|
||||||
const char *first_bare,
|
const char *first_bare,
|
||||||
const char *jid,
|
const char *jid,
|
||||||
@@ -397,6 +399,7 @@ char *sasl_scram(xmpp_ctx_t *ctx,
|
|||||||
char *result = NULL;
|
char *result = NULL;
|
||||||
size_t response_len;
|
size_t response_len;
|
||||||
size_t auth_len;
|
size_t auth_len;
|
||||||
|
int l;
|
||||||
|
|
||||||
UNUSED(jid);
|
UNUSED(jid);
|
||||||
|
|
||||||
@@ -427,37 +430,44 @@ char *sasl_scram(xmpp_ctx_t *ctx,
|
|||||||
}
|
}
|
||||||
ival = strtol(i, &saveptr, 10);
|
ival = strtol(i, &saveptr, 10);
|
||||||
|
|
||||||
auth_len = 10 + strlen(r) + strlen(first_bare) + strlen(challenge);
|
/* "c=<channel_binding>," + r + ",p=" + sign_b64 + '\0' */
|
||||||
auth = strophe_alloc(ctx, auth_len);
|
response_len = 3 + strlen(channel_binding) + strlen(r) + 3 +
|
||||||
if (!auth) {
|
((alg->digest_size + 2) / 3 * 4) + 1;
|
||||||
|
response = strophe_alloc(ctx, response_len);
|
||||||
|
if (!response) {
|
||||||
goto out_sval;
|
goto out_sval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* "c=biws," + r + ",p=" + sign_b64 + '\0' */
|
auth_len = 3 + response_len + strlen(first_bare) + strlen(challenge);
|
||||||
response_len = 7 + strlen(r) + 3 + ((alg->digest_size + 2) / 3 * 4) + 1;
|
auth = strophe_alloc(ctx, auth_len);
|
||||||
response = strophe_alloc(ctx, response_len);
|
if (!auth) {
|
||||||
if (!response) {
|
goto out_response;
|
||||||
goto out_auth;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
strophe_snprintf(response, response_len, "c=biws,%s", r);
|
l = strophe_snprintf(response, response_len, "c=%s,%s", channel_binding, r);
|
||||||
strophe_snprintf(auth, auth_len, "%s,%s,%s", first_bare + 3, challenge,
|
if (l < 0 || (size_t)l >= response_len) {
|
||||||
response);
|
goto out_auth;
|
||||||
|
}
|
||||||
|
l = strophe_snprintf(auth, auth_len, "%s,%s,%s", first_bare, challenge,
|
||||||
|
response);
|
||||||
|
if (l < 0 || (size_t)l >= auth_len) {
|
||||||
|
goto out_auth;
|
||||||
|
}
|
||||||
|
|
||||||
SCRAM_ClientKey(alg, (uint8_t *)password, strlen(password), (uint8_t *)sval,
|
SCRAM_ClientKey(alg, (uint8_t *)password, strlen(password), (uint8_t *)sval,
|
||||||
sval_len, (uint32_t)ival, key);
|
sval_len, (uint32_t)ival, key);
|
||||||
SCRAM_ClientSignature(alg, key, (uint8_t *)auth, strlen(auth), sign);
|
SCRAM_ClientSignature(alg, key, (uint8_t *)auth, strlen(auth), sign);
|
||||||
SCRAM_ClientProof(alg, sign, key, sign);
|
SCRAM_ClientProof(alg, key, sign, sign);
|
||||||
|
|
||||||
sign_b64 = xmpp_base64_encode(ctx, sign, alg->digest_size);
|
sign_b64 = xmpp_base64_encode(ctx, sign, alg->digest_size);
|
||||||
if (!sign_b64) {
|
if (!sign_b64) {
|
||||||
goto out_response;
|
goto out_auth;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check for buffer overflow */
|
/* Check for buffer overflow */
|
||||||
if (strlen(response) + strlen(sign_b64) + 3 + 1 > response_len) {
|
if (strlen(response) + strlen(sign_b64) + 3 + 1 > response_len) {
|
||||||
strophe_free(ctx, sign_b64);
|
strophe_free(ctx, sign_b64);
|
||||||
goto out_response;
|
goto out_auth;
|
||||||
}
|
}
|
||||||
strcat(response, ",p=");
|
strcat(response, ",p=");
|
||||||
strcat(response, sign_b64);
|
strcat(response, sign_b64);
|
||||||
@@ -466,14 +476,14 @@ char *sasl_scram(xmpp_ctx_t *ctx,
|
|||||||
response_b64 =
|
response_b64 =
|
||||||
xmpp_base64_encode(ctx, (unsigned char *)response, strlen(response));
|
xmpp_base64_encode(ctx, (unsigned char *)response, strlen(response));
|
||||||
if (!response_b64) {
|
if (!response_b64) {
|
||||||
goto out_response;
|
goto out_auth;
|
||||||
}
|
}
|
||||||
result = response_b64;
|
result = response_b64;
|
||||||
|
|
||||||
out_response:
|
|
||||||
strophe_free(ctx, response);
|
|
||||||
out_auth:
|
out_auth:
|
||||||
strophe_free(ctx, auth);
|
strophe_free(ctx, auth);
|
||||||
|
out_response:
|
||||||
|
strophe_free(ctx, response);
|
||||||
out_sval:
|
out_sval:
|
||||||
strophe_free(ctx, sval);
|
strophe_free(ctx, sval);
|
||||||
out:
|
out:
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
|
||||||
/* sasl.h
|
/* sasl.h
|
||||||
** strophe XMPP client library -- SASL authentication helpers
|
** strophe XMPP client library -- SASL authentication helpers
|
||||||
**
|
**
|
||||||
@@ -6,7 +7,7 @@
|
|||||||
** This software is provided AS-IS with no warranty, either express
|
** This software is provided AS-IS with no warranty, either express
|
||||||
** or implied.
|
** or implied.
|
||||||
**
|
**
|
||||||
** This program is dual licensed under the MIT and GPLv3 licenses.
|
** This program is dual licensed under the MIT or GPLv3 licenses.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @file
|
/** @file
|
||||||
@@ -28,6 +29,7 @@ char *sasl_digest_md5(xmpp_ctx_t *ctx,
|
|||||||
const char *password);
|
const char *password);
|
||||||
char *sasl_scram(xmpp_ctx_t *ctx,
|
char *sasl_scram(xmpp_ctx_t *ctx,
|
||||||
const struct hash_alg *alg,
|
const struct hash_alg *alg,
|
||||||
|
const char *channel_binding,
|
||||||
const char *challenge,
|
const char *challenge,
|
||||||
const char *first_bare,
|
const char *first_bare,
|
||||||
const char *jid,
|
const char *jid,
|
||||||
|
|||||||
58
src/scram.c
58
src/scram.c
@@ -1,3 +1,4 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
|
||||||
/* scram.c
|
/* scram.c
|
||||||
* strophe XMPP client library
|
* strophe XMPP client library
|
||||||
*
|
*
|
||||||
@@ -9,7 +10,7 @@
|
|||||||
* This software is provided AS-IS with no warranty, either express
|
* This software is provided AS-IS with no warranty, either express
|
||||||
* or implied.
|
* or implied.
|
||||||
*
|
*
|
||||||
* This program is dual licensed under the MIT and GPLv3 licenses.
|
* This program is dual licensed under the MIT or GPLv3 licenses.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @file
|
/** @file
|
||||||
@@ -41,6 +42,15 @@ const struct hash_alg scram_sha1 = {
|
|||||||
(void (*)(void *, const uint8_t *, size_t))crypto_SHA1_Update,
|
(void (*)(void *, const uint8_t *, size_t))crypto_SHA1_Update,
|
||||||
(void (*)(void *, uint8_t *))crypto_SHA1_Final};
|
(void (*)(void *, uint8_t *))crypto_SHA1_Final};
|
||||||
|
|
||||||
|
const struct hash_alg scram_sha1_plus = {
|
||||||
|
"SCRAM-SHA-1-PLUS",
|
||||||
|
SASL_MASK_SCRAMSHA1_PLUS,
|
||||||
|
SHA1_DIGEST_SIZE,
|
||||||
|
(void (*)(const uint8_t *, size_t, uint8_t *))crypto_SHA1,
|
||||||
|
(void (*)(void *))crypto_SHA1_Init,
|
||||||
|
(void (*)(void *, const uint8_t *, size_t))crypto_SHA1_Update,
|
||||||
|
(void (*)(void *, uint8_t *))crypto_SHA1_Final};
|
||||||
|
|
||||||
const struct hash_alg scram_sha256 = {
|
const struct hash_alg scram_sha256 = {
|
||||||
"SCRAM-SHA-256",
|
"SCRAM-SHA-256",
|
||||||
SASL_MASK_SCRAMSHA256,
|
SASL_MASK_SCRAMSHA256,
|
||||||
@@ -50,6 +60,15 @@ const struct hash_alg scram_sha256 = {
|
|||||||
(void (*)(void *, const uint8_t *, size_t))sha256_process,
|
(void (*)(void *, const uint8_t *, size_t))sha256_process,
|
||||||
(void (*)(void *, uint8_t *))sha256_done};
|
(void (*)(void *, uint8_t *))sha256_done};
|
||||||
|
|
||||||
|
const struct hash_alg scram_sha256_plus = {
|
||||||
|
"SCRAM-SHA-256-PLUS",
|
||||||
|
SASL_MASK_SCRAMSHA256_PLUS,
|
||||||
|
SHA256_DIGEST_SIZE,
|
||||||
|
(void (*)(const uint8_t *, size_t, uint8_t *))sha256_hash,
|
||||||
|
(void (*)(void *))sha256_init,
|
||||||
|
(void (*)(void *, const uint8_t *, size_t))sha256_process,
|
||||||
|
(void (*)(void *, uint8_t *))sha256_done};
|
||||||
|
|
||||||
const struct hash_alg scram_sha512 = {
|
const struct hash_alg scram_sha512 = {
|
||||||
"SCRAM-SHA-512",
|
"SCRAM-SHA-512",
|
||||||
SASL_MASK_SCRAMSHA512,
|
SASL_MASK_SCRAMSHA512,
|
||||||
@@ -59,6 +78,43 @@ 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
|
||||||
|
* tried if the server supports them.
|
||||||
|
* Their order is derived from
|
||||||
|
* https://datatracker.ietf.org/doc/html/draft-ietf-kitten-password-storage
|
||||||
|
*/
|
||||||
|
const struct hash_alg *scram_algs[] = {
|
||||||
|
/* *1 */
|
||||||
|
&scram_sha512_plus,
|
||||||
|
/* *1 */
|
||||||
|
&scram_sha256_plus,
|
||||||
|
/* *1 */
|
||||||
|
&scram_sha1_plus,
|
||||||
|
/* *1 */
|
||||||
|
&scram_sha512,
|
||||||
|
/* *1 */
|
||||||
|
&scram_sha256,
|
||||||
|
/* *1 */
|
||||||
|
&scram_sha1,
|
||||||
|
};
|
||||||
|
/* *1 - I want to use clang-format here, but by default it will put multiple
|
||||||
|
* elements per line if there's no comment. Currently clang-format also doesn't
|
||||||
|
* have an option to enforce it to behave like that, besides by putting comments
|
||||||
|
* between each element (or I couldn't find a way to do it). In order to prevent
|
||||||
|
* clang-format from re-formatting the array I added the comments above and
|
||||||
|
* wrote this lengthy description.
|
||||||
|
*/
|
||||||
|
const size_t scram_algs_num = sizeof(scram_algs) / sizeof(scram_algs[0]);
|
||||||
|
|
||||||
union common_hash_ctx {
|
union common_hash_ctx {
|
||||||
SHA1_CTX sha1;
|
SHA1_CTX sha1;
|
||||||
sha256_context sha256;
|
sha256_context sha256;
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
|
||||||
/* scram.h
|
/* scram.h
|
||||||
* strophe XMPP client library -- SCRAM helper functions
|
* strophe XMPP client library -- SCRAM helper functions
|
||||||
*
|
*
|
||||||
@@ -6,7 +7,7 @@
|
|||||||
* This software is provided AS-IS with no warranty, either express
|
* This software is provided AS-IS with no warranty, either express
|
||||||
* or implied.
|
* or implied.
|
||||||
*
|
*
|
||||||
* This program is dual licensed under the MIT and GPLv3 licenses.
|
* This program is dual licensed under the MIT or GPLv3 licenses.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @file
|
/** @file
|
||||||
@@ -33,9 +34,8 @@ struct hash_alg {
|
|||||||
void (*final)(void *, uint8_t *);
|
void (*final)(void *, uint8_t *);
|
||||||
};
|
};
|
||||||
|
|
||||||
extern const struct hash_alg scram_sha1;
|
extern const struct hash_alg *scram_algs[];
|
||||||
extern const struct hash_alg scram_sha256;
|
extern const size_t scram_algs_num;
|
||||||
extern const struct hash_alg scram_sha512;
|
|
||||||
|
|
||||||
void SCRAM_ClientKey(const struct hash_alg *alg,
|
void SCRAM_ClientKey(const struct hash_alg *alg,
|
||||||
const uint8_t *password,
|
const uint8_t *password,
|
||||||
|
|||||||
16
src/sha.h
16
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) \
|
||||||
@@ -96,13 +96,13 @@ extern "C" {
|
|||||||
#define CONST64(n) n##ULL
|
#define CONST64(n) n##ULL
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define RORc(x, y) \
|
#define RORc(x, y) \
|
||||||
(((((uint32_t)(x)&0xFFFFFFFFUL) >> (uint32_t)((y)&31)) | \
|
(((((uint32_t)(x) & 0xFFFFFFFFUL) >> (uint32_t)((y) & 31)) | \
|
||||||
((uint32_t)(x) << (uint32_t)((32 - ((y)&31)) & 31))) & \
|
((uint32_t)(x) << (uint32_t)((32 - ((y) & 31)) & 31))) & \
|
||||||
0xFFFFFFFFUL)
|
0xFFFFFFFFUL)
|
||||||
#define ROR64c(x, y) \
|
#define ROR64c(x, y) \
|
||||||
(((((x)&CONST64(0xFFFFFFFFFFFFFFFF)) >> ((uint64_t)(y)&CONST64(63))) | \
|
(((((x) & CONST64(0xFFFFFFFFFFFFFFFF)) >> ((uint64_t)(y) & CONST64(63))) | \
|
||||||
((x) << (((uint64_t)64 - ((y)&63)) & 63))) & \
|
((x) << (((uint64_t)64 - ((y) & 63)) & 63))) & \
|
||||||
CONST64(0xFFFFFFFFFFFFFFFF))
|
CONST64(0xFFFFFFFFFFFFFFFF))
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|||||||
@@ -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))
|
||||||
|
|||||||
49
src/sock.c
49
src/sock.c
@@ -1,3 +1,4 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
|
||||||
/* sock.c
|
/* sock.c
|
||||||
** strophe XMPP client library -- socket abstraction implementation
|
** strophe XMPP client library -- socket abstraction implementation
|
||||||
**
|
**
|
||||||
@@ -6,7 +7,7 @@
|
|||||||
** This software is provided AS-IS with no warranty, either express
|
** This software is provided AS-IS with no warranty, either express
|
||||||
** or implied.
|
** or implied.
|
||||||
**
|
**
|
||||||
** This program is dual licensed under the MIT and GPLv3 licenses.
|
** This program is dual licensed under the MIT or GPLv3 licenses.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @file
|
/** @file
|
||||||
@@ -37,6 +38,18 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "resolver.h"
|
#include "resolver.h"
|
||||||
|
|
||||||
|
const struct conn_interface sock_intf = {
|
||||||
|
sock_read,
|
||||||
|
sock_write,
|
||||||
|
/* no flush */
|
||||||
|
conn_int_nop,
|
||||||
|
/* no pending */
|
||||||
|
conn_int_nop,
|
||||||
|
sock_error,
|
||||||
|
sock_is_recoverable,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
struct _xmpp_sock_t {
|
struct _xmpp_sock_t {
|
||||||
xmpp_ctx_t *ctx;
|
xmpp_ctx_t *ctx;
|
||||||
xmpp_conn_t *conn;
|
xmpp_conn_t *conn;
|
||||||
@@ -63,8 +76,9 @@ void sock_shutdown(void)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int sock_error(void)
|
int sock_error(struct conn_interface *intf)
|
||||||
{
|
{
|
||||||
|
UNUSED(intf);
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
return WSAGetLastError();
|
return WSAGetLastError();
|
||||||
#else
|
#else
|
||||||
@@ -109,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;
|
||||||
}
|
}
|
||||||
@@ -193,7 +208,7 @@ sock_t sock_connect(xmpp_sock_t *xsock)
|
|||||||
{
|
{
|
||||||
struct addrinfo *ainfo;
|
struct addrinfo *ainfo;
|
||||||
sock_t sock;
|
sock_t sock;
|
||||||
int rc = 0;
|
int rc;
|
||||||
char buf[64];
|
char buf[64];
|
||||||
|
|
||||||
do {
|
do {
|
||||||
@@ -214,6 +229,7 @@ sock_t sock_connect(xmpp_sock_t *xsock)
|
|||||||
|
|
||||||
sock = socket(ainfo->ai_family, ainfo->ai_socktype, ainfo->ai_protocol);
|
sock = socket(ainfo->ai_family, ainfo->ai_socktype, ainfo->ai_protocol);
|
||||||
if (sock != INVALID_SOCKET) {
|
if (sock != INVALID_SOCKET) {
|
||||||
|
rc = 0;
|
||||||
if (xsock->conn->sockopt_cb) {
|
if (xsock->conn->sockopt_cb) {
|
||||||
/* Don't allow user to overwrite sockfd value. */
|
/* Don't allow user to overwrite sockfd value. */
|
||||||
sock_t sock_copy = sock;
|
sock_t sock_copy = sock;
|
||||||
@@ -221,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -230,7 +246,7 @@ sock_t sock_connect(xmpp_sock_t *xsock)
|
|||||||
if (rc == 0)
|
if (rc == 0)
|
||||||
rc = connect(sock, ainfo->ai_addr, ainfo->ai_addrlen);
|
rc = connect(sock, ainfo->ai_addr, ainfo->ai_addrlen);
|
||||||
/* Assume only connect() can cause "in progress" error. */
|
/* Assume only connect() can cause "in progress" error. */
|
||||||
if (rc != 0 && !_in_progress(sock_error())) {
|
if (rc != 0 && !_in_progress(sock_error(NULL))) {
|
||||||
sock_close(sock);
|
sock_close(sock);
|
||||||
sock = INVALID_SOCKET;
|
sock = INVALID_SOCKET;
|
||||||
}
|
}
|
||||||
@@ -375,18 +391,19 @@ int sock_set_nonblocking(sock_t sock)
|
|||||||
return _sock_set_blocking_mode(sock, 0);
|
return _sock_set_blocking_mode(sock, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int sock_read(sock_t sock, void *buff, size_t len)
|
int sock_read(struct conn_interface *intf, void *buff, size_t len)
|
||||||
{
|
{
|
||||||
return recv(sock, buff, len, 0);
|
return recv(intf->conn->sock, buff, len, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int sock_write(sock_t sock, const void *buff, size_t len)
|
int sock_write(struct conn_interface *intf, const void *buff, size_t len)
|
||||||
{
|
{
|
||||||
return send(sock, buff, len, 0);
|
return send(intf->conn->sock, buff, len, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int sock_is_recoverable(int error)
|
int sock_is_recoverable(struct conn_interface *intf, int error)
|
||||||
{
|
{
|
||||||
|
UNUSED(intf);
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
return (error == WSAEINTR || error == WSAEWOULDBLOCK ||
|
return (error == WSAEINTR || error == WSAEWOULDBLOCK ||
|
||||||
error == WSAEINPROGRESS);
|
error == WSAEINPROGRESS);
|
||||||
@@ -415,15 +432,15 @@ int sock_connect_error(sock_t sock)
|
|||||||
/* it's possible that the error wasn't ENOTCONN, so if it wasn't,
|
/* it's possible that the error wasn't ENOTCONN, so if it wasn't,
|
||||||
* return that */
|
* return that */
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
if (sock_error() != WSAENOTCONN)
|
if (sock_error(NULL) != WSAENOTCONN)
|
||||||
return sock_error();
|
return sock_error(NULL);
|
||||||
#else
|
#else
|
||||||
if (sock_error() != ENOTCONN)
|
if (sock_error(NULL) != ENOTCONN)
|
||||||
return sock_error();
|
return sock_error(NULL);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* load the correct error into errno through error slippage */
|
/* load the correct error into errno through error slippage */
|
||||||
recv(sock, &temp, 1, 0);
|
recv(sock, &temp, 1, 0);
|
||||||
|
|
||||||
return sock_error();
|
return sock_error(NULL);
|
||||||
}
|
}
|
||||||
|
|||||||
13
src/sock.h
13
src/sock.h
@@ -1,3 +1,4 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
|
||||||
/* sock.h
|
/* sock.h
|
||||||
** strophe XMPP client library -- socket abstraction header
|
** strophe XMPP client library -- socket abstraction header
|
||||||
**
|
**
|
||||||
@@ -6,7 +7,7 @@
|
|||||||
** This software is provided AS-IS with no warranty, either express
|
** This software is provided AS-IS with no warranty, either express
|
||||||
** or implied.
|
** or implied.
|
||||||
**
|
**
|
||||||
** This program is dual licensed under the MIT and GPLv3 licenses.
|
** This program is dual licensed under the MIT or GPLv3 licenses.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @file
|
/** @file
|
||||||
@@ -29,12 +30,14 @@ typedef int sock_t;
|
|||||||
typedef SOCKET sock_t;
|
typedef SOCKET sock_t;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
extern const struct conn_interface sock_intf;
|
||||||
|
|
||||||
typedef struct _xmpp_sock_t xmpp_sock_t;
|
typedef struct _xmpp_sock_t xmpp_sock_t;
|
||||||
|
|
||||||
void sock_initialize(void);
|
void sock_initialize(void);
|
||||||
void sock_shutdown(void);
|
void sock_shutdown(void);
|
||||||
|
|
||||||
int sock_error(void);
|
int sock_error(struct conn_interface *intf);
|
||||||
|
|
||||||
xmpp_sock_t *sock_new(xmpp_conn_t *conn,
|
xmpp_sock_t *sock_new(xmpp_conn_t *conn,
|
||||||
const char *domain,
|
const char *domain,
|
||||||
@@ -46,9 +49,9 @@ int sock_close(sock_t sock);
|
|||||||
|
|
||||||
int sock_set_blocking(sock_t sock);
|
int sock_set_blocking(sock_t sock);
|
||||||
int sock_set_nonblocking(sock_t sock);
|
int sock_set_nonblocking(sock_t sock);
|
||||||
int sock_read(sock_t sock, void *buff, size_t len);
|
int sock_read(struct conn_interface *intf, void *buff, size_t len);
|
||||||
int sock_write(sock_t sock, const void *buff, size_t len);
|
int sock_write(struct conn_interface *intf, const void *buff, size_t len);
|
||||||
int sock_is_recoverable(int error);
|
int sock_is_recoverable(struct conn_interface *intf, int error);
|
||||||
/* checks for an error after connect, return 0 if connect successful */
|
/* checks for an error after connect, return 0 if connect successful */
|
||||||
int sock_connect_error(sock_t sock);
|
int sock_connect_error(sock_t sock);
|
||||||
int sock_set_keepalive(sock_t sock,
|
int sock_set_keepalive(sock_t sock,
|
||||||
|
|||||||
10
src/stanza.c
10
src/stanza.c
@@ -1,3 +1,4 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
|
||||||
/* stanza.c
|
/* stanza.c
|
||||||
** strophe XMPP client library -- XMPP stanza object and utilities
|
** strophe XMPP client library -- XMPP stanza object and utilities
|
||||||
**
|
**
|
||||||
@@ -6,7 +7,7 @@
|
|||||||
** This software is provided AS-IS with no warranty, either express
|
** This software is provided AS-IS with no warranty, either express
|
||||||
** or implied.
|
** or implied.
|
||||||
**
|
**
|
||||||
** This program is dual licensed under the MIT and GPLv3 licenses.
|
** This program is dual licensed under the MIT or GPLv3 licenses.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @file
|
/** @file
|
||||||
@@ -41,15 +42,10 @@ xmpp_stanza_t *xmpp_stanza_new(xmpp_ctx_t *ctx)
|
|||||||
|
|
||||||
stanza = strophe_alloc(ctx, sizeof(xmpp_stanza_t));
|
stanza = strophe_alloc(ctx, sizeof(xmpp_stanza_t));
|
||||||
if (stanza != NULL) {
|
if (stanza != NULL) {
|
||||||
|
memset(stanza, 0, sizeof(xmpp_stanza_t));
|
||||||
stanza->ref = 1;
|
stanza->ref = 1;
|
||||||
stanza->ctx = ctx;
|
stanza->ctx = ctx;
|
||||||
stanza->type = XMPP_STANZA_UNKNOWN;
|
stanza->type = XMPP_STANZA_UNKNOWN;
|
||||||
stanza->prev = NULL;
|
|
||||||
stanza->next = NULL;
|
|
||||||
stanza->children = NULL;
|
|
||||||
stanza->parent = NULL;
|
|
||||||
stanza->data = NULL;
|
|
||||||
stanza->attributes = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return stanza;
|
return stanza;
|
||||||
|
|||||||
31
src/tls.c
31
src/tls.c
@@ -1,3 +1,4 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
|
||||||
/* tls.c
|
/* tls.c
|
||||||
** strophe XMPP client library -- generic TLS functions
|
** strophe XMPP client library -- generic TLS functions
|
||||||
**
|
**
|
||||||
@@ -6,7 +7,7 @@
|
|||||||
** This software is provided AS-IS with no warranty, either express
|
** This software is provided AS-IS with no warranty, either express
|
||||||
** or implied.
|
** or implied.
|
||||||
**
|
**
|
||||||
** This program is dual licensed under the MIT and GPLv3 licenses.
|
** This program is dual licensed under the MIT or GPLv3 licenses.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @file
|
/** @file
|
||||||
@@ -29,6 +30,17 @@
|
|||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
|
const struct conn_interface tls_intf = {
|
||||||
|
tls_read,
|
||||||
|
tls_write,
|
||||||
|
tls_clear_pending_write,
|
||||||
|
tls_pending,
|
||||||
|
tls_error,
|
||||||
|
tls_is_recoverable,
|
||||||
|
/* init conn */
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
struct _dnsname_t {
|
struct _dnsname_t {
|
||||||
char **data;
|
char **data;
|
||||||
size_t cur, max;
|
size_t cur, max;
|
||||||
@@ -62,6 +74,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
|
||||||
|
|||||||
21
src/tls.h
21
src/tls.h
@@ -1,3 +1,4 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
|
||||||
/* tls.h
|
/* tls.h
|
||||||
** strophe XMPP client library -- TLS abstraction header
|
** strophe XMPP client library -- TLS abstraction header
|
||||||
**
|
**
|
||||||
@@ -6,7 +7,7 @@
|
|||||||
** This software is provided AS-IS with no warranty, either express
|
** This software is provided AS-IS with no warranty, either express
|
||||||
** or implied.
|
** or implied.
|
||||||
**
|
**
|
||||||
** This program is dual licensed under the MIT and GPLv3 licenses.
|
** This program is dual licensed under the MIT or GPLv3 licenses.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @file
|
/** @file
|
||||||
@@ -44,20 +45,24 @@ unsigned int tls_id_on_xmppaddr_num(xmpp_conn_t *conn);
|
|||||||
|
|
||||||
xmpp_tlscert_t *tls_peer_cert(xmpp_conn_t *conn);
|
xmpp_tlscert_t *tls_peer_cert(xmpp_conn_t *conn);
|
||||||
int tls_set_credentials(tls_t *tls, const char *cafilename);
|
int tls_set_credentials(tls_t *tls, const char *cafilename);
|
||||||
|
int tls_init_channel_binding(tls_t *tls,
|
||||||
|
const char **binding_prefix,
|
||||||
|
size_t *binding_prefix_len);
|
||||||
|
const void *tls_get_channel_binding_data(tls_t *tls, size_t *size);
|
||||||
|
|
||||||
int tls_start(tls_t *tls);
|
int tls_start(tls_t *tls);
|
||||||
int tls_stop(tls_t *tls);
|
int tls_stop(tls_t *tls);
|
||||||
|
|
||||||
int tls_error(tls_t *tls);
|
int tls_pending(struct conn_interface *intf);
|
||||||
|
int tls_read(struct conn_interface *intf, void *buff, size_t len);
|
||||||
|
int tls_write(struct conn_interface *intf, const void *buff, size_t len);
|
||||||
|
int tls_clear_pending_write(struct conn_interface *intf);
|
||||||
|
|
||||||
int tls_pending(tls_t *tls);
|
int tls_error(struct conn_interface *intf);
|
||||||
int tls_read(tls_t *tls, void *buff, size_t len);
|
int tls_is_recoverable(struct conn_interface *intf, int error);
|
||||||
int tls_write(tls_t *tls, const void *buff, size_t len);
|
|
||||||
|
|
||||||
int tls_clear_pending_write(tls_t *tls);
|
|
||||||
int tls_is_recoverable(int error);
|
|
||||||
|
|
||||||
/* provided by tls.c */
|
/* provided by tls.c */
|
||||||
|
extern const struct conn_interface tls_intf;
|
||||||
|
|
||||||
xmpp_tlscert_t *tlscert_new(xmpp_ctx_t *ctx);
|
xmpp_tlscert_t *tlscert_new(xmpp_ctx_t *ctx);
|
||||||
int tlscert_add_dnsname(xmpp_tlscert_t *cert, const char *dnsname);
|
int tlscert_add_dnsname(xmpp_tlscert_t *cert, const char *dnsname);
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
|
||||||
/* tls_dummy.c
|
/* tls_dummy.c
|
||||||
** strophe XMPP client library -- TLS abstraction dummy impl.
|
** strophe XMPP client library -- TLS abstraction dummy impl.
|
||||||
**
|
**
|
||||||
@@ -6,7 +7,7 @@
|
|||||||
** This software is provided AS-IS with no warranty, either express
|
** This software is provided AS-IS with no warranty, either express
|
||||||
** or implied.
|
** or implied.
|
||||||
**
|
**
|
||||||
** This program is dual licensed under the MIT and GPLv3 licenses.
|
** This program is dual licensed under the MIT or GPLv3 licenses.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @file
|
/** @file
|
||||||
@@ -74,6 +75,23 @@ int tls_set_credentials(tls_t *tls, const char *cafilename)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int tls_init_channel_binding(tls_t *tls,
|
||||||
|
const char **binding_prefix,
|
||||||
|
size_t *binding_prefix_len)
|
||||||
|
{
|
||||||
|
UNUSED(tls);
|
||||||
|
UNUSED(binding_prefix);
|
||||||
|
UNUSED(binding_prefix_len);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const void *tls_get_channel_binding_data(tls_t *tls, size_t *size)
|
||||||
|
{
|
||||||
|
UNUSED(tls);
|
||||||
|
UNUSED(size);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
int tls_start(tls_t *tls)
|
int tls_start(tls_t *tls)
|
||||||
{
|
{
|
||||||
UNUSED(tls);
|
UNUSED(tls);
|
||||||
@@ -86,43 +104,43 @@ int tls_stop(tls_t *tls)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tls_error(tls_t *tls)
|
int tls_error(struct conn_interface *intf)
|
||||||
{
|
{
|
||||||
UNUSED(tls);
|
UNUSED(intf);
|
||||||
/* todo: some kind of error polling/dump */
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tls_pending(tls_t *tls)
|
int tls_pending(struct conn_interface *intf)
|
||||||
{
|
{
|
||||||
UNUSED(tls);
|
UNUSED(intf);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tls_read(tls_t *tls, void *buff, size_t len)
|
int tls_read(struct conn_interface *intf, void *buff, size_t len)
|
||||||
{
|
{
|
||||||
UNUSED(tls);
|
UNUSED(intf);
|
||||||
UNUSED(buff);
|
UNUSED(buff);
|
||||||
UNUSED(len);
|
UNUSED(len);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tls_write(tls_t *tls, const void *buff, size_t len)
|
int tls_write(struct conn_interface *intf, const void *buff, size_t len)
|
||||||
{
|
{
|
||||||
UNUSED(tls);
|
UNUSED(intf);
|
||||||
UNUSED(buff);
|
UNUSED(buff);
|
||||||
UNUSED(len);
|
UNUSED(len);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tls_clear_pending_write(tls_t *tls)
|
int tls_clear_pending_write(struct conn_interface *intf)
|
||||||
{
|
{
|
||||||
UNUSED(tls);
|
UNUSED(intf);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tls_is_recoverable(int error)
|
int tls_is_recoverable(struct conn_interface *intf, int error)
|
||||||
{
|
{
|
||||||
|
UNUSED(intf);
|
||||||
UNUSED(error);
|
UNUSED(error);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
|
||||||
/* tls.c
|
/* tls.c
|
||||||
** strophe XMPP client library -- TLS abstraction header
|
** strophe XMPP client library -- TLS abstraction header
|
||||||
**
|
**
|
||||||
@@ -6,7 +7,7 @@
|
|||||||
** This software is provided AS-IS with no warranty, either express
|
** This software is provided AS-IS with no warranty, either express
|
||||||
** or implied.
|
** or implied.
|
||||||
**
|
**
|
||||||
** This program is dual licensed under the MIT and GPLv3 licenses.
|
** This program is dual licensed under the MIT or GPLv3 licenses.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @file
|
/** @file
|
||||||
@@ -24,12 +25,26 @@
|
|||||||
#include "tls.h"
|
#include "tls.h"
|
||||||
#include "sock.h"
|
#include "sock.h"
|
||||||
|
|
||||||
|
#if GNUTLS_VERSION_NUMBER < 0x030702
|
||||||
|
/* This is a very dirty workaround to make this file compile on older GnuTLS
|
||||||
|
* We simply define our own value for the later introduced
|
||||||
|
* `GNUTLS_CB_TLS_EXPORTER` which makes it compile, but it will fail on runtime
|
||||||
|
* when the combination of the following options happen:
|
||||||
|
* * GnuTLS < 3.7.2
|
||||||
|
* * TLS 1.3
|
||||||
|
* * A SCRAM PLUS variant to authenticate
|
||||||
|
* We will think about fixing this once a user pops up who has that problem.
|
||||||
|
*/
|
||||||
|
#define GNUTLS_CB_TLS_EXPORTER 3
|
||||||
|
#endif
|
||||||
|
|
||||||
struct _tls {
|
struct _tls {
|
||||||
xmpp_ctx_t *ctx; /* do we need this? */
|
xmpp_ctx_t *ctx; /* do we need this? */
|
||||||
xmpp_conn_t *conn;
|
xmpp_conn_t *conn;
|
||||||
gnutls_session_t session;
|
gnutls_session_t session;
|
||||||
gnutls_certificate_credentials_t cred;
|
gnutls_certificate_credentials_t cred;
|
||||||
gnutls_x509_crt_t client_cert;
|
gnutls_x509_crt_t client_cert;
|
||||||
|
gnutls_datum_t channel_binding;
|
||||||
int lasterror;
|
int lasterror;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -407,6 +422,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);
|
||||||
@@ -506,8 +523,8 @@ error_out:
|
|||||||
|
|
||||||
void tls_free(tls_t *tls)
|
void tls_free(tls_t *tls)
|
||||||
{
|
{
|
||||||
if (tls->client_cert)
|
gnutls_free(tls->channel_binding.data);
|
||||||
gnutls_x509_crt_deinit(tls->client_cert);
|
gnutls_x509_crt_deinit(tls->client_cert);
|
||||||
gnutls_deinit(tls->session);
|
gnutls_deinit(tls->session);
|
||||||
gnutls_certificate_free_credentials(tls->cred);
|
gnutls_certificate_free_credentials(tls->cred);
|
||||||
strophe_free(tls->ctx, tls);
|
strophe_free(tls->ctx, tls);
|
||||||
@@ -554,6 +571,55 @@ int tls_set_credentials(tls_t *tls, const char *cafilename)
|
|||||||
return err == GNUTLS_E_SUCCESS;
|
return err == GNUTLS_E_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int tls_init_channel_binding(tls_t *tls,
|
||||||
|
const char **binding_prefix,
|
||||||
|
size_t *binding_prefix_len)
|
||||||
|
{
|
||||||
|
gnutls_channel_binding_t binding_type;
|
||||||
|
gnutls_protocol_t tls_version = gnutls_protocol_get_version(tls->session);
|
||||||
|
|
||||||
|
switch (tls_version) {
|
||||||
|
case GNUTLS_SSL3:
|
||||||
|
case GNUTLS_TLS1_0:
|
||||||
|
case GNUTLS_TLS1_1:
|
||||||
|
case GNUTLS_TLS1_2:
|
||||||
|
*binding_prefix = "tls-unique";
|
||||||
|
*binding_prefix_len = strlen("tls-unique");
|
||||||
|
binding_type = GNUTLS_CB_TLS_UNIQUE;
|
||||||
|
break;
|
||||||
|
case GNUTLS_TLS1_3:
|
||||||
|
*binding_prefix = "tls-exporter";
|
||||||
|
*binding_prefix_len = strlen("tls-exporter");
|
||||||
|
binding_type = GNUTLS_CB_TLS_EXPORTER;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
strophe_error(tls->ctx, "tls", "Unsupported TLS Version: %s",
|
||||||
|
gnutls_protocol_get_name(tls_version));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tls->channel_binding.data) {
|
||||||
|
gnutls_free(tls->channel_binding.data);
|
||||||
|
tls->channel_binding.data = NULL;
|
||||||
|
}
|
||||||
|
int ret = gnutls_session_channel_binding(tls->session, binding_type,
|
||||||
|
&tls->channel_binding);
|
||||||
|
if (ret) {
|
||||||
|
strophe_error(tls->ctx, "tls", "could not get channel binding: %s",
|
||||||
|
gnutls_strerror(ret));
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
const void *tls_get_channel_binding_data(tls_t *tls, size_t *size)
|
||||||
|
{
|
||||||
|
if (!tls->channel_binding.data || !tls->channel_binding.size) {
|
||||||
|
strophe_error(tls->ctx, "tls", "No channel binding data available");
|
||||||
|
}
|
||||||
|
*size = tls->channel_binding.size;
|
||||||
|
return tls->channel_binding.data;
|
||||||
|
}
|
||||||
|
|
||||||
int tls_start(tls_t *tls)
|
int tls_start(tls_t *tls)
|
||||||
{
|
{
|
||||||
sock_set_blocking(tls->conn->sock);
|
sock_set_blocking(tls->conn->sock);
|
||||||
@@ -569,24 +635,26 @@ int tls_stop(tls_t *tls)
|
|||||||
return tls->lasterror == GNUTLS_E_SUCCESS;
|
return tls->lasterror == GNUTLS_E_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tls_error(tls_t *tls)
|
int tls_error(struct conn_interface *intf)
|
||||||
{
|
{
|
||||||
return tls->lasterror;
|
return intf->conn->tls->lasterror;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tls_is_recoverable(int error)
|
int tls_is_recoverable(struct conn_interface *intf, int error)
|
||||||
{
|
{
|
||||||
|
UNUSED(intf);
|
||||||
return !gnutls_error_is_fatal(error);
|
return !gnutls_error_is_fatal(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
int tls_pending(tls_t *tls)
|
int tls_pending(struct conn_interface *intf)
|
||||||
{
|
{
|
||||||
return gnutls_record_check_pending(tls->session);
|
return gnutls_record_check_pending(intf->conn->tls->session);
|
||||||
}
|
}
|
||||||
|
|
||||||
int tls_read(tls_t *tls, void *buff, size_t len)
|
int tls_read(struct conn_interface *intf, void *buff, size_t len)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
tls_t *tls = intf->conn->tls;
|
||||||
|
|
||||||
ret = gnutls_record_recv(tls->session, buff, len);
|
ret = gnutls_record_recv(tls->session, buff, len);
|
||||||
tls->lasterror = ret < 0 ? ret : 0;
|
tls->lasterror = ret < 0 ? ret : 0;
|
||||||
@@ -594,9 +662,10 @@ int tls_read(tls_t *tls, void *buff, size_t len)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tls_write(tls_t *tls, const void *buff, size_t len)
|
int tls_write(struct conn_interface *intf, const void *buff, size_t len)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
tls_t *tls = intf->conn->tls;
|
||||||
|
|
||||||
ret = gnutls_record_send(tls->session, buff, len);
|
ret = gnutls_record_send(tls->session, buff, len);
|
||||||
tls->lasterror = ret < 0 ? ret : 0;
|
tls->lasterror = ret < 0 ? ret : 0;
|
||||||
@@ -604,8 +673,8 @@ int tls_write(tls_t *tls, const void *buff, size_t len)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tls_clear_pending_write(tls_t *tls)
|
int tls_clear_pending_write(struct conn_interface *intf)
|
||||||
{
|
{
|
||||||
UNUSED(tls);
|
UNUSED(intf);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
|
||||||
/* tls_openssl.c
|
/* tls_openssl.c
|
||||||
** strophe XMPP client library -- TLS abstraction openssl impl.
|
** strophe XMPP client library -- TLS abstraction openssl impl.
|
||||||
**
|
**
|
||||||
@@ -6,7 +7,7 @@
|
|||||||
** This software is provided AS-IS with no warranty, either express
|
** This software is provided AS-IS with no warranty, either express
|
||||||
** or implied.
|
** or implied.
|
||||||
**
|
**
|
||||||
** This program is dual licensed under the MIT and GPLv3 licenses.
|
** This program is dual licensed under the MIT or GPLv3 licenses.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @file
|
/** @file
|
||||||
@@ -50,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
|
||||||
@@ -106,6 +109,9 @@ struct _tls {
|
|||||||
SSL_CTX *ssl_ctx;
|
SSL_CTX *ssl_ctx;
|
||||||
SSL *ssl;
|
SSL *ssl;
|
||||||
X509 *client_cert;
|
X509 *client_cert;
|
||||||
|
void *channel_binding_data;
|
||||||
|
size_t channel_binding_size;
|
||||||
|
FILE *keylogfile;
|
||||||
int lasterror;
|
int lasterror;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -280,9 +286,9 @@ void tls_shutdown(void)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int tls_error(tls_t *tls)
|
int tls_error(struct conn_interface *intf)
|
||||||
{
|
{
|
||||||
return tls->lasterror;
|
return intf->conn->tls->lasterror;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Search through the SubjectAlternativeNames and return the next
|
/** Search through the SubjectAlternativeNames and return the next
|
||||||
@@ -411,8 +417,10 @@ _get_alg(const xmpp_ctx_t *ctx, X509 *err_cert, xmpp_cert_element_t el)
|
|||||||
alg_nid = OBJ_obj2nid(err_cert->sig_alg->algorithm);
|
alg_nid = OBJ_obj2nid(err_cert->sig_alg->algorithm);
|
||||||
#else
|
#else
|
||||||
const X509_ALGOR *palg;
|
const X509_ALGOR *palg;
|
||||||
|
const ASN1_OBJECT *obj;
|
||||||
X509_get0_signature(NULL, &palg, err_cert);
|
X509_get0_signature(NULL, &palg, err_cert);
|
||||||
alg_nid = OBJ_obj2nid(palg->algorithm);
|
X509_ALGOR_get0(&obj, NULL, NULL, palg);
|
||||||
|
alg_nid = OBJ_obj2nid(obj);
|
||||||
#endif
|
#endif
|
||||||
} break;
|
} break;
|
||||||
default:
|
default:
|
||||||
@@ -532,6 +540,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]);
|
||||||
@@ -551,6 +561,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));
|
||||||
@@ -694,6 +734,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;
|
||||||
@@ -712,6 +754,9 @@ 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);
|
||||||
SSL_free(tls->ssl);
|
SSL_free(tls->ssl);
|
||||||
X509_free(tls->client_cert);
|
X509_free(tls->client_cert);
|
||||||
SSL_CTX_free(tls->ssl_ctx);
|
SSL_CTX_free(tls->ssl_ctx);
|
||||||
@@ -721,7 +766,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);
|
||||||
@@ -738,6 +783,83 @@ int tls_set_credentials(tls_t *tls, const char *cafilename)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int tls_init_channel_binding(tls_t *tls,
|
||||||
|
const char **binding_prefix,
|
||||||
|
size_t *binding_prefix_len)
|
||||||
|
{
|
||||||
|
const char *label = NULL;
|
||||||
|
size_t labellen = 0;
|
||||||
|
int ssl_version = SSL_version(tls->ssl);
|
||||||
|
|
||||||
|
switch (ssl_version) {
|
||||||
|
case SSL3_VERSION:
|
||||||
|
*binding_prefix = "tls-unique";
|
||||||
|
*binding_prefix_len = strlen("tls-unique");
|
||||||
|
tls->channel_binding_size = 36;
|
||||||
|
break;
|
||||||
|
case TLS1_VERSION:
|
||||||
|
case TLS1_1_VERSION:
|
||||||
|
case TLS1_2_VERSION:
|
||||||
|
*binding_prefix = "tls-unique";
|
||||||
|
*binding_prefix_len = strlen("tls-unique");
|
||||||
|
tls->channel_binding_size = 12;
|
||||||
|
break;
|
||||||
|
#ifdef TLS1_3_VERSION
|
||||||
|
case TLS1_3_VERSION:
|
||||||
|
label = "EXPORTER-Channel-Binding";
|
||||||
|
labellen = 24;
|
||||||
|
*binding_prefix = "tls-exporter";
|
||||||
|
*binding_prefix_len = strlen("tls-exporter");
|
||||||
|
tls->channel_binding_size = 32;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
strophe_error(tls->ctx, "tls", "Unsupported TLS/SSL Version: %s",
|
||||||
|
SSL_get_version(tls->ssl));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
strophe_free_and_null(tls->ctx, tls->channel_binding_data);
|
||||||
|
tls->channel_binding_data =
|
||||||
|
strophe_alloc(tls->ctx, tls->channel_binding_size);
|
||||||
|
if (!tls->channel_binding_data)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (ssl_version <= TLS1_2_VERSION) {
|
||||||
|
size_t len;
|
||||||
|
if (SSL_session_reused(tls->ssl)) {
|
||||||
|
len = SSL_get_peer_finished(tls->ssl, tls->channel_binding_data,
|
||||||
|
tls->channel_binding_size);
|
||||||
|
} else {
|
||||||
|
len = SSL_get_finished(tls->ssl, tls->channel_binding_data,
|
||||||
|
tls->channel_binding_size);
|
||||||
|
}
|
||||||
|
if (len != tls->channel_binding_size) {
|
||||||
|
strophe_error(tls->ctx, "tls",
|
||||||
|
"Got channel binding data of wrong size %zu", len);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (SSL_export_keying_material(tls->ssl, tls->channel_binding_data,
|
||||||
|
tls->channel_binding_size, label,
|
||||||
|
labellen, NULL, 0, 0) != 1) {
|
||||||
|
strophe_error(tls->ctx, "tls",
|
||||||
|
"Could not get channel binding data");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const void *tls_get_channel_binding_data(tls_t *tls, size_t *size)
|
||||||
|
{
|
||||||
|
if (!tls->channel_binding_data || !tls->channel_binding_size) {
|
||||||
|
strophe_error(tls->ctx, "tls", "No channel binding data available");
|
||||||
|
}
|
||||||
|
*size = tls->channel_binding_size;
|
||||||
|
return tls->channel_binding_data;
|
||||||
|
}
|
||||||
|
|
||||||
int tls_start(tls_t *tls)
|
int tls_start(tls_t *tls)
|
||||||
{
|
{
|
||||||
int error;
|
int error;
|
||||||
@@ -750,7 +872,7 @@ int tls_start(tls_t *tls)
|
|||||||
ret = SSL_connect(tls->ssl);
|
ret = SSL_connect(tls->ssl);
|
||||||
error = ret <= 0 ? SSL_get_error(tls->ssl, ret) : 0;
|
error = ret <= 0 ? SSL_get_error(tls->ssl, ret) : 0;
|
||||||
|
|
||||||
if (ret == -1 && tls_is_recoverable(error)) {
|
if (ret == -1 && tls_is_recoverable(NULL, error)) {
|
||||||
/* wait for something to happen on the sock before looping back */
|
/* wait for something to happen on the sock before looping back */
|
||||||
_tls_sock_wait(tls, error);
|
_tls_sock_wait(tls, error);
|
||||||
continue;
|
continue;
|
||||||
@@ -791,7 +913,7 @@ int tls_stop(tls_t *tls)
|
|||||||
++retries;
|
++retries;
|
||||||
ret = SSL_shutdown(tls->ssl);
|
ret = SSL_shutdown(tls->ssl);
|
||||||
error = ret < 0 ? SSL_get_error(tls->ssl, ret) : 0;
|
error = ret < 0 ? SSL_get_error(tls->ssl, ret) : 0;
|
||||||
if (ret == 1 || !tls_is_recoverable(error) ||
|
if (ret == 1 || !tls_is_recoverable(NULL, error) ||
|
||||||
retries >= TLS_SHUTDOWN_MAX_RETRIES) {
|
retries >= TLS_SHUTDOWN_MAX_RETRIES) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -810,21 +932,23 @@ int tls_stop(tls_t *tls)
|
|||||||
return ret <= 0 ? 0 : 1;
|
return ret <= 0 ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tls_is_recoverable(int error)
|
int tls_is_recoverable(struct conn_interface *intf, int error)
|
||||||
{
|
{
|
||||||
|
UNUSED(intf);
|
||||||
return (error == SSL_ERROR_NONE || error == SSL_ERROR_WANT_READ ||
|
return (error == SSL_ERROR_NONE || error == SSL_ERROR_WANT_READ ||
|
||||||
error == SSL_ERROR_WANT_WRITE || error == SSL_ERROR_WANT_CONNECT ||
|
error == SSL_ERROR_WANT_WRITE || error == SSL_ERROR_WANT_CONNECT ||
|
||||||
error == SSL_ERROR_WANT_ACCEPT);
|
error == SSL_ERROR_WANT_ACCEPT);
|
||||||
}
|
}
|
||||||
|
|
||||||
int tls_pending(tls_t *tls)
|
int tls_pending(struct conn_interface *intf)
|
||||||
{
|
{
|
||||||
return SSL_pending(tls->ssl);
|
return SSL_pending(intf->conn->tls->ssl);
|
||||||
}
|
}
|
||||||
|
|
||||||
int tls_read(tls_t *tls, void *buff, size_t len)
|
int tls_read(struct conn_interface *intf, void *buff, size_t len)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
tls_t *tls = intf->conn->tls;
|
||||||
|
|
||||||
ret = SSL_read(tls->ssl, buff, len);
|
ret = SSL_read(tls->ssl, buff, len);
|
||||||
_tls_set_error(tls, ret <= 0 ? SSL_get_error(tls->ssl, ret) : 0);
|
_tls_set_error(tls, ret <= 0 ? SSL_get_error(tls->ssl, ret) : 0);
|
||||||
@@ -832,9 +956,10 @@ int tls_read(tls_t *tls, void *buff, size_t len)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tls_write(tls_t *tls, const void *buff, size_t len)
|
int tls_write(struct conn_interface *intf, const void *buff, size_t len)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
tls_t *tls = intf->conn->tls;
|
||||||
|
|
||||||
ret = SSL_write(tls->ssl, buff, len);
|
ret = SSL_write(tls->ssl, buff, len);
|
||||||
_tls_set_error(tls, ret <= 0 ? SSL_get_error(tls->ssl, ret) : 0);
|
_tls_set_error(tls, ret <= 0 ? SSL_get_error(tls->ssl, ret) : 0);
|
||||||
@@ -842,9 +967,9 @@ int tls_write(tls_t *tls, const void *buff, size_t len)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tls_clear_pending_write(tls_t *tls)
|
int tls_clear_pending_write(struct conn_interface *intf)
|
||||||
{
|
{
|
||||||
UNUSED(tls);
|
UNUSED(intf);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -882,7 +1007,7 @@ static const char *_tls_error_str(int error, const char **tbl, size_t tbl_size)
|
|||||||
|
|
||||||
static void _tls_set_error(tls_t *tls, int error)
|
static void _tls_set_error(tls_t *tls, int error)
|
||||||
{
|
{
|
||||||
if (error != 0 && !tls_is_recoverable(error)) {
|
if (error != 0 && !tls_is_recoverable(NULL, error)) {
|
||||||
strophe_debug(tls->ctx, "tls", "error=%s(%d) errno=%d lasterror=%d",
|
strophe_debug(tls->ctx, "tls", "error=%s(%d) errno=%d lasterror=%d",
|
||||||
TLS_ERROR_STR(error, tls_errors), error, errno,
|
TLS_ERROR_STR(error, tls_errors), error, errno,
|
||||||
tls->lasterror);
|
tls->lasterror);
|
||||||
@@ -913,7 +1038,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 {
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
|
||||||
/* tls_schannel.c
|
/* tls_schannel.c
|
||||||
** strophe XMPP client library -- TLS abstraction schannel impl.
|
** strophe XMPP client library -- TLS abstraction schannel impl.
|
||||||
**
|
**
|
||||||
@@ -6,7 +7,7 @@
|
|||||||
** This software is provided AS-IS with no warranty, either express
|
** This software is provided AS-IS with no warranty, either express
|
||||||
** or implied.
|
** or implied.
|
||||||
**
|
**
|
||||||
** This program is dual licensed under the MIT and GPLv3 licenses.
|
** This program is dual licensed under the MIT or GPLv3 licenses.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @file
|
/** @file
|
||||||
@@ -236,6 +237,23 @@ int tls_set_credentials(tls_t *tls, const char *cafilename)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int tls_init_channel_binding(tls_t *tls,
|
||||||
|
const char **binding_prefix,
|
||||||
|
size_t *binding_prefix_len)
|
||||||
|
{
|
||||||
|
UNUSED(tls);
|
||||||
|
UNUSED(binding_prefix);
|
||||||
|
UNUSED(binding_prefix_len);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const void *tls_get_channel_binding_data(tls_t *tls, size_t *size)
|
||||||
|
{
|
||||||
|
UNUSED(tls);
|
||||||
|
UNUSED(size);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
int tls_start(tls_t *tls)
|
int tls_start(tls_t *tls)
|
||||||
{
|
{
|
||||||
ULONG ctxtreq = 0, ctxtattr = 0;
|
ULONG ctxtreq = 0, ctxtattr = 0;
|
||||||
@@ -244,9 +262,11 @@ int tls_start(tls_t *tls)
|
|||||||
SECURITY_STATUS ret;
|
SECURITY_STATUS ret;
|
||||||
int sent;
|
int sent;
|
||||||
char *name;
|
char *name;
|
||||||
|
struct conn_interface *intf;
|
||||||
|
|
||||||
/* 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;
|
||||||
|
|
||||||
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 |
|
||||||
@@ -295,9 +315,9 @@ int tls_start(tls_t *tls)
|
|||||||
unsigned char *writebuff = sbdout.pBuffers[0].pvBuffer;
|
unsigned char *writebuff = sbdout.pBuffers[0].pvBuffer;
|
||||||
unsigned int writelen = sbdout.pBuffers[0].cbBuffer;
|
unsigned int writelen = sbdout.pBuffers[0].cbBuffer;
|
||||||
|
|
||||||
sent = sock_write(tls->sock, writebuff, writelen);
|
sent = sock_write(intf, writebuff, writelen);
|
||||||
if (sent == -1) {
|
if (sent == -1) {
|
||||||
tls->lasterror = sock_error();
|
tls->lasterror = sock_error(intf);
|
||||||
} else {
|
} else {
|
||||||
writebuff += sent;
|
writebuff += sent;
|
||||||
writelen -= sent;
|
writelen -= sent;
|
||||||
@@ -335,13 +355,13 @@ int tls_start(tls_t *tls)
|
|||||||
|
|
||||||
select(tls->sock, &fds, NULL, NULL, &tv);
|
select(tls->sock, &fds, NULL, NULL, &tv);
|
||||||
|
|
||||||
inbytes = sock_read(tls->sock, p, tls->spi->cbMaxToken - len);
|
inbytes = sock_read(intf, p, tls->spi->cbMaxToken - len);
|
||||||
|
|
||||||
if (inbytes > 0) {
|
if (inbytes > 0) {
|
||||||
len += inbytes;
|
len += inbytes;
|
||||||
p += inbytes;
|
p += inbytes;
|
||||||
} else {
|
} else {
|
||||||
tls->lasterror = sock_error();
|
tls->lasterror = sock_error(intf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -356,9 +376,9 @@ int tls_start(tls_t *tls)
|
|||||||
if (sbdout.pBuffers[0].cbBuffer) {
|
if (sbdout.pBuffers[0].cbBuffer) {
|
||||||
unsigned char *writebuff = sbdout.pBuffers[0].pvBuffer;
|
unsigned char *writebuff = sbdout.pBuffers[0].pvBuffer;
|
||||||
unsigned int writelen = sbdout.pBuffers[0].cbBuffer;
|
unsigned int writelen = sbdout.pBuffers[0].cbBuffer;
|
||||||
sent = sock_write(tls->sock, writebuff, writelen);
|
sent = sock_write(intf, writebuff, writelen);
|
||||||
if (sent == -1) {
|
if (sent == -1) {
|
||||||
tls->lasterror = sock_error();
|
tls->lasterror = sock_error(intf);
|
||||||
} else {
|
} else {
|
||||||
writebuff += sent;
|
writebuff += sent;
|
||||||
writelen -= sent;
|
writelen -= sent;
|
||||||
@@ -405,20 +425,22 @@ int tls_stop(tls_t *tls)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tls_error(tls_t *tls)
|
int tls_error(struct conn_interface *intf)
|
||||||
{
|
{
|
||||||
return tls->lasterror;
|
return intf->conn->tls->lasterror;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tls_is_recoverable(int error)
|
int tls_is_recoverable(struct conn_interface *intf, int error)
|
||||||
{
|
{
|
||||||
|
UNUSED(intf);
|
||||||
return (error == SEC_E_OK || error == SEC_E_INCOMPLETE_MESSAGE ||
|
return (error == SEC_E_OK || error == SEC_E_INCOMPLETE_MESSAGE ||
|
||||||
error == WSAEWOULDBLOCK || error == WSAEMSGSIZE ||
|
error == WSAEWOULDBLOCK || error == WSAEMSGSIZE ||
|
||||||
error == WSAEINPROGRESS);
|
error == WSAEINPROGRESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
int tls_pending(tls_t *tls)
|
int tls_pending(struct conn_interface *intf)
|
||||||
{
|
{
|
||||||
|
tls_t *tls = intf->conn->tls;
|
||||||
// There are 3 cases:
|
// There are 3 cases:
|
||||||
// - there is data in ready buffer, so it is by default pending
|
// - there is data in ready buffer, so it is by default pending
|
||||||
// - there is data in recv buffer. If it is not decrypted yet, means it
|
// - there is data in recv buffer. If it is not decrypted yet, means it
|
||||||
@@ -434,9 +456,10 @@ int tls_pending(tls_t *tls)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tls_read(tls_t *tls, void *buff, size_t len)
|
int tls_read(struct conn_interface *intf, void *buff, size_t len)
|
||||||
{
|
{
|
||||||
int bytes;
|
int bytes;
|
||||||
|
tls_t *tls = intf->conn->tls;
|
||||||
|
|
||||||
/* first, if we've got some ready data, put that in the buffer */
|
/* first, if we've got some ready data, put that in the buffer */
|
||||||
if (tls->readybufferpos < tls->readybufferlen) {
|
if (tls->readybufferpos < tls->readybufferlen) {
|
||||||
@@ -459,7 +482,7 @@ int tls_read(tls_t *tls, void *buff, size_t len)
|
|||||||
read = tls_read(tls, newbuff, len - bytes);
|
read = tls_read(tls, newbuff, len - bytes);
|
||||||
|
|
||||||
if (read == -1) {
|
if (read == -1) {
|
||||||
if (tls_is_recoverable(tls->lasterror)) {
|
if (tls_is_recoverable(intf, tls->lasterror)) {
|
||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -471,7 +494,7 @@ int tls_read(tls_t *tls, void *buff, size_t len)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* next, top up our recv buffer */
|
/* next, top up our recv buffer */
|
||||||
bytes = sock_read(tls->sock, tls->recvbuffer + tls->recvbufferpos,
|
bytes = sock_read(intf, tls->recvbuffer + tls->recvbufferpos,
|
||||||
tls->recvbuffermaxlen - tls->recvbufferpos);
|
tls->recvbuffermaxlen - tls->recvbufferpos);
|
||||||
|
|
||||||
if (bytes == 0) {
|
if (bytes == 0) {
|
||||||
@@ -480,8 +503,8 @@ int tls_read(tls_t *tls, void *buff, size_t len)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (bytes == -1) {
|
if (bytes == -1) {
|
||||||
if (!tls_is_recoverable(sock_error())) {
|
if (!tls_is_recoverable(intf, sock_error(intf))) {
|
||||||
tls->lasterror = sock_error();
|
tls->lasterror = sock_error(intf);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -556,16 +579,17 @@ int tls_read(tls_t *tls, void *buff, size_t len)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tls_clear_pending_write(tls_t *tls)
|
int tls_clear_pending_write(struct conn_interface *intf)
|
||||||
{
|
{
|
||||||
|
tls_t *tls = intf->conn->tls;
|
||||||
if (tls->sendbufferpos < tls->sendbufferlen) {
|
if (tls->sendbufferpos < tls->sendbufferlen) {
|
||||||
int bytes;
|
int bytes;
|
||||||
|
|
||||||
bytes = sock_write(tls->sock, tls->sendbuffer + tls->sendbufferpos,
|
bytes = sock_write(intf, tls->sendbuffer + tls->sendbufferpos,
|
||||||
tls->sendbufferlen - tls->sendbufferpos);
|
tls->sendbufferlen - tls->sendbufferpos);
|
||||||
|
|
||||||
if (bytes == -1) {
|
if (bytes == -1) {
|
||||||
tls->lasterror = sock_error();
|
tls->lasterror = sock_error(intf);
|
||||||
return -1;
|
return -1;
|
||||||
} else if (bytes > 0) {
|
} else if (bytes > 0) {
|
||||||
tls->sendbufferpos += bytes;
|
tls->sendbufferpos += bytes;
|
||||||
@@ -579,12 +603,13 @@ int tls_clear_pending_write(tls_t *tls)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tls_write(tls_t *tls, const void *buff, size_t len)
|
int tls_write(struct conn_interface *intf, const void *buff, size_t len)
|
||||||
{
|
{
|
||||||
SecBufferDesc sbdenc;
|
SecBufferDesc sbdenc;
|
||||||
SecBuffer sbenc[4];
|
SecBuffer sbenc[4];
|
||||||
const unsigned char *p = buff;
|
const unsigned char *p = buff;
|
||||||
int sent = 0, ret, remain = len;
|
int sent = 0, ret, remain = len;
|
||||||
|
tls_t *tls = intf->conn->tls;
|
||||||
|
|
||||||
ret = tls_clear_pending_write(tls);
|
ret = tls_clear_pending_write(tls);
|
||||||
if (ret <= 0) {
|
if (ret <= 0) {
|
||||||
@@ -644,7 +669,7 @@ int tls_write(tls_t *tls, const void *buff, size_t len)
|
|||||||
|
|
||||||
ret = tls_clear_pending_write(tls);
|
ret = tls_clear_pending_write(tls);
|
||||||
|
|
||||||
if (ret == -1 && !tls_is_recoverable(tls_error(tls))) {
|
if (ret == -1 && !tls_is_recoverable(intf, tls_error(tls))) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -656,7 +681,8 @@ int tls_write(tls_t *tls, const void *buff, size_t len)
|
|||||||
remain = 0;
|
remain = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret == 0 || (ret == -1 && tls_is_recoverable(tls_error(tls)))) {
|
if (ret == 0 ||
|
||||||
|
(ret == -1 && tls_is_recoverable(intf, tls_error(tls)))) {
|
||||||
return sent;
|
return sent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
|
||||||
/* util.c
|
/* util.c
|
||||||
** strophe XMPP client library -- various utility functions
|
** strophe XMPP client library -- various utility functions
|
||||||
**
|
**
|
||||||
@@ -6,7 +7,7 @@
|
|||||||
** This software is provided AS-IS with no warranty, either express
|
** This software is provided AS-IS with no warranty, either express
|
||||||
** or implied.
|
** or implied.
|
||||||
**
|
**
|
||||||
** This program is dual licensed under the MIT and GPLv3 licenses.
|
** This program is dual licensed under the MIT or GPLv3 licenses.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @file
|
/** @file
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
|
||||||
/* util.h
|
/* util.h
|
||||||
** strophe XMPP client library -- various utility functions
|
** strophe XMPP client library -- various utility functions
|
||||||
**
|
**
|
||||||
@@ -6,7 +7,7 @@
|
|||||||
** This software is provided AS-IS with no warranty, either express
|
** This software is provided AS-IS with no warranty, either express
|
||||||
** or implied.
|
** or implied.
|
||||||
**
|
**
|
||||||
** This program is dual licensed under the MIT and GPLv3 licenses.
|
** This program is dual licensed under the MIT or GPLv3 licenses.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @file
|
/** @file
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
|
||||||
/* uuid.c
|
/* uuid.c
|
||||||
* strophe XMPP client library -- UUID generation
|
* strophe XMPP client library -- UUID generation
|
||||||
*
|
*
|
||||||
@@ -6,7 +7,7 @@
|
|||||||
* This software is provided AS-IS with no warranty, either express
|
* This software is provided AS-IS with no warranty, either express
|
||||||
* or implied.
|
* or implied.
|
||||||
*
|
*
|
||||||
* This program is dual licensed under the MIT and GPLv3 licenses.
|
* This program is dual licensed under the MIT or GPLv3 licenses.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @file
|
/** @file
|
||||||
|
|||||||
66
strophe.h
66
strophe.h
@@ -1,3 +1,4 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
|
||||||
/* strophe.h
|
/* strophe.h
|
||||||
** strophe XMPP client library C API
|
** strophe XMPP client library C API
|
||||||
**
|
**
|
||||||
@@ -6,7 +7,7 @@
|
|||||||
** This software is provided AS-IS with no warranty, either express or
|
** This software is provided AS-IS with no warranty, either express or
|
||||||
** implied.
|
** implied.
|
||||||
**
|
**
|
||||||
** This software is dual licensed under the MIT and GPLv3 licenses.
|
** This software is dual licensed under the MIT or GPLv3 licenses.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @file
|
/** @file
|
||||||
@@ -17,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" {
|
||||||
@@ -83,6 +85,14 @@ extern "C" {
|
|||||||
* Namespace definition for Stream Management.
|
* Namespace definition for Stream Management.
|
||||||
*/
|
*/
|
||||||
#define XMPP_NS_SM "urn:xmpp:sm:3"
|
#define XMPP_NS_SM "urn:xmpp:sm:3"
|
||||||
|
/** @def XMPP_NS_COMPRESSION
|
||||||
|
* Namespace definition for Stream Compression.
|
||||||
|
*/
|
||||||
|
#define XMPP_NS_COMPRESSION "http://jabber.org/protocol/compress"
|
||||||
|
/** @def XMPP_NS_FEATURE_COMPRESSION
|
||||||
|
* Namespace definition for Stream Compression.
|
||||||
|
*/
|
||||||
|
#define XMPP_NS_FEATURE_COMPRESSION "http://jabber.org/features/compress"
|
||||||
|
|
||||||
/* error defines */
|
/* error defines */
|
||||||
/** @def XMPP_EOK
|
/** @def XMPP_EOK
|
||||||
@@ -190,6 +200,15 @@ typedef struct _xmpp_sm_t xmpp_sm_state_t;
|
|||||||
* Disable Stream-Management XEP-0198.
|
* Disable Stream-Management XEP-0198.
|
||||||
*/
|
*/
|
||||||
#define XMPP_CONN_FLAG_DISABLE_SM (1UL << 5)
|
#define XMPP_CONN_FLAG_DISABLE_SM (1UL << 5)
|
||||||
|
/** @def XMPP_CONN_FLAG_ENABLE_COMPRESSION
|
||||||
|
* Enable Stream-Compression XEP-0138.
|
||||||
|
*/
|
||||||
|
#define XMPP_CONN_FLAG_ENABLE_COMPRESSION (1UL << 6)
|
||||||
|
/** @def XMPP_CONN_FLAG_COMPRESSION_DONT_RESET
|
||||||
|
* Don't reset the compressed stream after each stanza.
|
||||||
|
* Only enable this flag if you know what you're doing.
|
||||||
|
*/
|
||||||
|
#define XMPP_CONN_FLAG_COMPRESSION_DONT_RESET (1UL << 7)
|
||||||
|
|
||||||
/* connect callback */
|
/* connect callback */
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@@ -381,7 +400,6 @@ char *xmpp_conn_cert_xmppaddr(xmpp_conn_t *conn, unsigned int n);
|
|||||||
const char *xmpp_conn_get_pass(const xmpp_conn_t *conn);
|
const char *xmpp_conn_get_pass(const xmpp_conn_t *conn);
|
||||||
void xmpp_conn_set_pass(xmpp_conn_t *conn, const char *pass);
|
void xmpp_conn_set_pass(xmpp_conn_t *conn, const char *pass);
|
||||||
xmpp_ctx_t *xmpp_conn_get_context(xmpp_conn_t *conn);
|
xmpp_ctx_t *xmpp_conn_get_context(xmpp_conn_t *conn);
|
||||||
void xmpp_conn_disable_tls(xmpp_conn_t *conn);
|
|
||||||
int xmpp_conn_is_secured(xmpp_conn_t *conn);
|
int xmpp_conn_is_secured(xmpp_conn_t *conn);
|
||||||
void xmpp_conn_set_sockopt_callback(xmpp_conn_t *conn,
|
void xmpp_conn_set_sockopt_callback(xmpp_conn_t *conn,
|
||||||
xmpp_sockopt_callback callback);
|
xmpp_sockopt_callback callback);
|
||||||
@@ -397,8 +415,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);
|
||||||
|
|
||||||
@@ -594,6 +642,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,
|
||||||
@@ -690,11 +739,18 @@ void xmpp_rand_bytes(xmpp_rand_t *rand, unsigned char *output, size_t len);
|
|||||||
*/
|
*/
|
||||||
void xmpp_rand_nonce(xmpp_rand_t *rand, char *output, size_t len);
|
void xmpp_rand_nonce(xmpp_rand_t *rand, char *output, size_t len);
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* Formerly "private but exported" functions made public for now to announce
|
* Formerly "private but exported" functions made public for now to announce
|
||||||
* deprecation */
|
* deprecation */
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* XMPP_DEPRECATED(x) macro to show a compiler warning for deprecated API
|
||||||
|
* functions
|
||||||
|
*
|
||||||
|
* @param x The function that can be used as a replacement or 'internal' if
|
||||||
|
* there is no replacement
|
||||||
|
*/
|
||||||
#if defined(__GNUC__)
|
#if defined(__GNUC__)
|
||||||
#if (__GNUC__ * 100 + __GNUC_MINOR__ >= 405)
|
#if (__GNUC__ * 100 + __GNUC_MINOR__ >= 405)
|
||||||
#define XMPP_DEPRECATED(x) __attribute__((deprecated("replaced by " #x)))
|
#define XMPP_DEPRECATED(x) __attribute__((deprecated("replaced by " #x)))
|
||||||
@@ -742,6 +798,8 @@ void xmpp_debug_verbose(
|
|||||||
|
|
||||||
XMPP_DEPRECATED(xmpp_conn_set_sockopt_callback)
|
XMPP_DEPRECATED(xmpp_conn_set_sockopt_callback)
|
||||||
void xmpp_conn_set_keepalive(xmpp_conn_t *conn, int timeout, int interval);
|
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);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@@ -1,16 +1,19 @@
|
|||||||
-----BEGIN CERTIFICATE-----
|
-----BEGIN CERTIFICATE-----
|
||||||
MIICfjCCAjSgAwIBAgIIW5u5Vwn2Mv0wCgYIKoZIzj0EAwIwSzFJMEcGA1UEAwxA
|
MIIDIDCCAqagAwIBAgIIddFxfQ2VcRIwCgYIKoZIzj0EAwQwSzFJMEcGA1UEAwxA
|
||||||
dmVyeS5sb25nLnVzZXJuYW1lQHNvLnRoZS5hc24xLmxlbmd0aC5pcy5hLnZhbGlk
|
dmVyeS5sb25nLnVzZXJuYW1lQHNvLnRoZS5hc24xLmxlbmd0aC5pcy5hLnZhbGlk
|
||||||
LmFzY2lpLmNoYXJhY3RlcjAgFw0yMTAzMDExOTExMDBaGA8yMTIxMDMwMTE5MTEw
|
LmFzY2lpLmNoYXJhY3RlcjAgFw0yMzA4MDkxMzI3MDBaGA8yMTI0MDgwOTEzMjcw
|
||||||
MFowSzFJMEcGA1UEAwxAdmVyeS5sb25nLnVzZXJuYW1lQHNvLnRoZS5hc24xLmxl
|
MFowSzFJMEcGA1UEAwxAdmVyeS5sb25nLnVzZXJuYW1lQHNvLnRoZS5hc24xLmxl
|
||||||
bmd0aC5pcy5hLnZhbGlkLmFzY2lpLmNoYXJhY3RlcjBJMBMGByqGSM49AgEGCCqG
|
bmd0aC5pcy5hLnZhbGlkLmFzY2lpLmNoYXJhY3RlcjB2MBAGByqGSM49AgEGBSuB
|
||||||
SM49AwEBAzIABI/tSR5cZ9iHCVw0JwmKLvV3TbxPg3kDdouB0R2WKEdEWwXMIHkE
|
BAAiA2IABHfN9a5xAEPYWz+0O6Jfe95WGUeuq6Eca5po4UGcJgs78L6d4KT+FR/a
|
||||||
85RReISg+9/JDaOCAQ4wggEKMAkGA1UdEwQCMAAwHQYDVR0OBBYEFPjLGyHxqlOV
|
yDSi/BmS0ZAksXbshkSjQA6XmAwWkNInJF/buAwh/hFVAOXwx3eKtguPskxg1xYj
|
||||||
nXJQ9YBrnureO8LiMB8GA1UdIwQYMBaAFPjLGyHxqlOVnXJQ9YBrnureO8LiMAsG
|
0WZ3WrY9oKOCAVMwggFPMAkGA1UdEwQCMAAwHQYDVR0OBBYEFNeonZqrLTGCm3Vk
|
||||||
A1UdDwQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAjCBmgYDVR0RBIGSMIGPoE4G
|
+X3TtMfDQVf4MGQGA1UdIwRdMFuhT6RNMEsxSTBHBgNVBAMMQHZlcnkubG9uZy51
|
||||||
CCsGAQUFBwgFoEIMQHZlcnkubG9uZy51c2VybmFtZUBzby50aGUuYXNuMS5sZW5n
|
c2VybmFtZUBzby50aGUuYXNuMS5sZW5ndGguaXMuYS52YWxpZC5hc2NpaS5jaGFy
|
||||||
dGguaXMuYS52YWxpZC5hc2NpaS5jaGFyYWN0ZXKBDnlldEBub3RoZXIuc2Fugg53
|
YWN0ZXKCCHXRcX0NlXESMAsGA1UdDwQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcD
|
||||||
d3cuc3Ryb3BoZS5pbaAdBggrBgEFBQcIBaARDA9zZWNvbmRAeG1wcC5qaWQwCgYI
|
AjCBmgYDVR0RBIGSMIGPoE4GCCsGAQUFBwgFoEIMQHZlcnkubG9uZy51c2VybmFt
|
||||||
KoZIzj0EAwIDOAAwNQIZAJmfqBhBMdaKCiWEuXu84K4+lznfzlRfmwIYCGRD1xk0
|
ZUBzby50aGUuYXNuMS5sZW5ndGguaXMuYS52YWxpZC5hc2NpaS5jaGFyYWN0ZXKB
|
||||||
9cRa3V6PVwYWz6HcdRdMUBUj
|
DnlldEBub3RoZXIuc2Fugg53d3cuc3Ryb3BoZS5pbaAdBggrBgEFBQcIBaARDA9z
|
||||||
|
ZWNvbmRAeG1wcC5qaWQwCgYIKoZIzj0EAwQDaAAwZQIxAJTzJY/q/zFws0FPPfVI
|
||||||
|
VXc+kaGdxwzM1FKlVMwxl+PzXAoeL0Z7FtGSkaCWyaokaAIwLaYxuQhgisetYxbU
|
||||||
|
qTyv0MdS2uUy6NNcVNztWCMS350TuuVm3f9wmwOjfaeoHft3
|
||||||
-----END CERTIFICATE-----
|
-----END CERTIFICATE-----
|
||||||
|
|||||||
BIN
tests/cert.pfx
BIN
tests/cert.pfx
Binary file not shown.
@@ -1,3 +1,4 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
|
||||||
/* check_parser.h
|
/* check_parser.h
|
||||||
** strophe XMPP client library -- parser tests
|
** strophe XMPP client library -- parser tests
|
||||||
**
|
**
|
||||||
@@ -6,7 +7,7 @@
|
|||||||
** This software is provided AS-IS with no warranty, either express or
|
** This software is provided AS-IS with no warranty, either express or
|
||||||
** implied.
|
** implied.
|
||||||
**
|
**
|
||||||
** This program is dual licensed under the MIT and GPLv3 licenses.
|
** This program is dual licensed under the MIT or GPLv3 licenses.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
-----BEGIN EC PRIVATE KEY-----
|
-----BEGIN EC PRIVATE KEY-----
|
||||||
MF8CAQEEGF7SsbTSOjzb97nFc7Qbt4sic+1nZk+ETqAKBggqhkjOPQMBAaE0AzIA
|
MIGkAgEBBDBZ90AXrC5n1ZxFGq4WpqMgvH7qw2YddaUzzPFtf9qDRDrRe3xW6nTr
|
||||||
BI/tSR5cZ9iHCVw0JwmKLvV3TbxPg3kDdouB0R2WKEdEWwXMIHkE85RReISg+9/J
|
Iywpxdh26GWgBwYFK4EEACKhZANiAAR3zfWucQBD2Fs/tDuiX3veVhlHrquhHGua
|
||||||
DQ==
|
aOFBnCYLO/C+neCk/hUf2sg0ovwZktGQJLF27IZEo0AOl5gMFpDSJyRf27gMIf4R
|
||||||
|
VQDl8Md3irYLj7JMYNcWI9Fmd1q2PaA=
|
||||||
-----END EC PRIVATE KEY-----
|
-----END EC PRIVATE KEY-----
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
-----BEGIN EC PRIVATE KEY-----
|
-----BEGIN EC PRIVATE KEY-----
|
||||||
Proc-Type: 4,ENCRYPTED
|
Proc-Type: 4,ENCRYPTED
|
||||||
DEK-Info: AES-256-CBC,30B7F2152A39184AEEF290ED2B1DBC0E
|
DEK-Info: AES-256-CBC,D1537075EE9323A68A08B79257D87D53
|
||||||
|
|
||||||
IojJAF1hGHL9qnu5MCzl5l1PzsnxLj38JjLBLPXaNekiAbag5H9Tzr7y5nfyviPM
|
faIortcMN9tCcmwidAJlFDOS68OJlAH1Bzjh2sqhZDhFJEU/w3bOihTDk1cV0yg1
|
||||||
hi6syrkXgLOBF+mZWJouOxCNx7+t6eWVfsDZcnzsw6HrTN/2xwkYP/3lYfzlnt6q
|
JHSxolcX7aYLaBfhSdbnUDaeNhyvfF97O6lMHXbiSdkWBMKrOjSwpW5BcemQgbpI
|
||||||
/AKYQIUUPc/31J6xg3kGRQ==
|
gjCi7KYWb2Z3CqcELR9624u4vRgytJQliqLW1jjnGMELcuq7HaoB2wP0XmXp9/BV
|
||||||
|
QMQU504S6V8JbogFZeNGCOq+EW5C8tEBCz82y1PRUr0=
|
||||||
-----END EC PRIVATE KEY-----
|
-----END EC PRIVATE KEY-----
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
|
||||||
/* res_query_dump.c
|
/* res_query_dump.c
|
||||||
* Simple program to dump res_query(3) response
|
* Simple program to dump res_query(3) response
|
||||||
*
|
*
|
||||||
@@ -6,7 +7,7 @@
|
|||||||
* This software is provided AS-IS with no warranty, either express
|
* This software is provided AS-IS with no warranty, either express
|
||||||
* or implied.
|
* or implied.
|
||||||
*
|
*
|
||||||
* This program is dual licensed under the MIT and GPLv3 licenses.
|
* This program is dual licensed under the MIT or GPLv3 licenses.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Linux and OSX:
|
/* Linux and OSX:
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
|
||||||
/* test.c
|
/* test.c
|
||||||
* strophe XMPP client library -- common routines for tests
|
* strophe XMPP client library -- common routines for tests
|
||||||
*
|
*
|
||||||
@@ -6,7 +7,7 @@
|
|||||||
* This software is provided AS-IS with no warranty, either express
|
* This software is provided AS-IS with no warranty, either express
|
||||||
* or implied.
|
* or implied.
|
||||||
*
|
*
|
||||||
* This program is dual licensed under the MIT and GPLv3 licenses.
|
* This program is dual licensed under the MIT or GPLv3 licenses.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|||||||
77
tests/test.h
77
tests/test.h
@@ -1,3 +1,4 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
|
||||||
/* test.h
|
/* test.h
|
||||||
** libstrophe XMPP client library -- common routines for tests
|
** libstrophe XMPP client library -- common routines for tests
|
||||||
**
|
**
|
||||||
@@ -6,7 +7,7 @@
|
|||||||
** This software is provided AS-IS with no warranty, either express
|
** This software is provided AS-IS with no warranty, either express
|
||||||
** or implied.
|
** or implied.
|
||||||
**
|
**
|
||||||
** This program is dual licensed under the MIT and GPLv3 licenses.
|
** This program is dual licensed under the MIT or GPLv3 licenses.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __LIBSTROPHE_TEST_H__
|
#ifndef __LIBSTROPHE_TEST_H__
|
||||||
@@ -34,46 +35,48 @@
|
|||||||
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
|
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define COMPARE(v1, v2) \
|
#define COMPARE(should, is) \
|
||||||
do { \
|
do { \
|
||||||
const char *__v1 = v1; \
|
const char *__should = should; \
|
||||||
const char *__v2 = v2; \
|
const char *__is = is; \
|
||||||
if ((__v1 == NULL) && (__v2 == NULL)) { \
|
if ((__should == NULL) && (__is == NULL)) { \
|
||||||
/* noop */ \
|
/* noop */ \
|
||||||
} else if (!__v1 || !__v2 || strcmp(__v1, __v2) != 0) { \
|
} else if (!__should || !__is || strcmp(__should, __is) != 0) { \
|
||||||
printf("Error: %s\n" \
|
printf("Error: %s\n" \
|
||||||
"Expected: %s\n" \
|
"Expected: %s\n" \
|
||||||
"Got: %s\n", \
|
"Got: %s\n", \
|
||||||
#v1 " != " #v2, __v1, __v2); \
|
#should " != " #is, __should, __is); \
|
||||||
exit(1); \
|
exit(1); \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define COMPARE_BUF(v1, len1, v2, len2) \
|
#define COMPARE_BUF(should, should_len, is, is_len) \
|
||||||
do { \
|
do { \
|
||||||
const uint8_t *__v1 = (uint8_t *)(v1); \
|
const uint8_t *__should = (uint8_t *)(should); \
|
||||||
const uint8_t *__v2 = (uint8_t *)(v2); \
|
const uint8_t *__is = (uint8_t *)(is); \
|
||||||
size_t __len1 = len1; \
|
size_t __should_len = should_len; \
|
||||||
size_t __len2 = len2; \
|
size_t __is_len = is_len; \
|
||||||
if (__len1 != __len2 || memcmp(__v1, __v2, __len1) != 0) { \
|
if (__should_len != __is_len || \
|
||||||
printf("Error: %s\n", #v1 " != " #v2); \
|
memcmp(__should, __is, __should_len) != 0) { \
|
||||||
printf("Expected: 0x%s\n", test_bin_to_hex(__v1, __len1)); \
|
printf("Error: %s\n", #should " != " #is); \
|
||||||
printf("Got: 0x%s\n", test_bin_to_hex(__v2, __len2)); \
|
printf("Expected: 0x%s\n", \
|
||||||
exit(1); \
|
test_bin_to_hex(__should, __should_len)); \
|
||||||
} \
|
printf("Got: 0x%s\n", test_bin_to_hex(__is, __is_len)); \
|
||||||
|
exit(1); \
|
||||||
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define ENSURE_EQ(v1, v2) \
|
#define ENSURE_EQ(should, is) \
|
||||||
do { \
|
do { \
|
||||||
int __v1 = v1; \
|
int __should = should; \
|
||||||
int __v2 = v2; \
|
int __is = is; \
|
||||||
if (__v1 != __v2) { \
|
if (__should != __is) { \
|
||||||
printf("Error: %s\n" \
|
printf("Error: %s\n" \
|
||||||
"Expected: %d\n" \
|
"Expected: %d\n" \
|
||||||
"Got: %d\n", \
|
"Got: %d\n", \
|
||||||
#v1 " != " #v2, __v2, __v1); \
|
#should " != " #is, __is, __should); \
|
||||||
exit(1); \
|
exit(1); \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
void test_hex_to_bin(const char *hex, uint8_t *bin, size_t *bin_len);
|
void test_hex_to_bin(const char *hex, uint8_t *bin, size_t *bin_len);
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
|
||||||
/* test_base64.c
|
/* test_base64.c
|
||||||
** libstrophe XMPP client library -- test routines for the base64 codec
|
** libstrophe XMPP client library -- test routines for the base64 codec
|
||||||
**
|
**
|
||||||
@@ -6,7 +7,7 @@
|
|||||||
** This software is provided AS-IS with no warranty, either express
|
** This software is provided AS-IS with no warranty, either express
|
||||||
** or implied.
|
** or implied.
|
||||||
**
|
**
|
||||||
** This program is dual licensed under the MIT and GPLv3 licenses.
|
** This program is dual licensed under the MIT or GPLv3 licenses.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
|
||||||
/* test_ctx.c
|
/* test_ctx.c
|
||||||
** libstrophe XMPP client library -- test routines for the library run-time
|
** libstrophe XMPP client library -- test routines for the library run-time
|
||||||
*context
|
*context
|
||||||
@@ -7,7 +8,7 @@
|
|||||||
** This software is provided AS-IS with no warranty, either express
|
** This software is provided AS-IS with no warranty, either express
|
||||||
** or implied.
|
** or implied.
|
||||||
**
|
**
|
||||||
** This program is dual licensed under the MIT and GPLv3 licenses.
|
** This program is dual licensed under the MIT or GPLv3 licenses.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
|
||||||
/* test_hash.c
|
/* test_hash.c
|
||||||
** libstrophe XMPP client library -- self-test for the hash-table implementation
|
** libstrophe XMPP client library -- self-test for the hash-table implementation
|
||||||
**
|
**
|
||||||
@@ -6,7 +7,7 @@
|
|||||||
** This software is provided AS-IS with no warranty, either express
|
** This software is provided AS-IS with no warranty, either express
|
||||||
** or implied.
|
** or implied.
|
||||||
**
|
**
|
||||||
** This program is dual licensed under the MIT and GPLv3 licenses.
|
** This program is dual licensed under the MIT or GPLv3 licenses.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
|
||||||
/* test_jid.c
|
/* test_jid.c
|
||||||
** libstrophe XMPP client library -- test routines for the jid utils
|
** libstrophe XMPP client library -- test routines for the jid utils
|
||||||
**
|
**
|
||||||
@@ -6,7 +7,7 @@
|
|||||||
** This software is provided AS-IS with no warranty, either express
|
** This software is provided AS-IS with no warranty, either express
|
||||||
** or implied.
|
** or implied.
|
||||||
**
|
**
|
||||||
** This program is dual licensed under the MIT and GPLv3 licenses.
|
** This program is dual licensed under the MIT or GPLv3 licenses.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
|
||||||
/* test_md5.c
|
/* test_md5.c
|
||||||
* strophe XMPP client library -- test vectors for MD5
|
* strophe XMPP client library -- test vectors for MD5
|
||||||
*
|
*
|
||||||
@@ -6,7 +7,7 @@
|
|||||||
* This software is provided AS-IS with no warranty, either express
|
* This software is provided AS-IS with no warranty, either express
|
||||||
* or implied.
|
* or implied.
|
||||||
*
|
*
|
||||||
* This program is dual licensed under the MIT and GPLv3 licenses.
|
* This program is dual licensed under the MIT or GPLv3 licenses.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* gcc -o test_md5 -I./src tests/test_md5.c tests/test.c src/md5.c */
|
/* gcc -o test_md5 -I./src tests/test_md5.c tests/test.c src/md5.c */
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
|
||||||
/* check_rand.c
|
/* check_rand.c
|
||||||
* strophe XMPP client library -- test vectors for Hash_DRBG
|
* strophe XMPP client library -- test vectors for Hash_DRBG
|
||||||
*
|
*
|
||||||
@@ -6,7 +7,7 @@
|
|||||||
* This software is provided AS-IS with no warranty, either express
|
* This software is provided AS-IS with no warranty, either express
|
||||||
* or implied.
|
* or implied.
|
||||||
*
|
*
|
||||||
* This program is dual licensed under the MIT and GPLv3 licenses.
|
* This program is dual licensed under the MIT or GPLv3 licenses.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* gcc -o test_rand -I./src tests/test_rand.c tests/test.c src/sha1.c */
|
/* gcc -o test_rand -I./src tests/test_rand.c tests/test.c src/sha1.c */
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
|
||||||
/* test_resolver.c
|
/* test_resolver.c
|
||||||
* strophe XMPP client library -- tests for resolver
|
* strophe XMPP client library -- tests for resolver
|
||||||
*
|
*
|
||||||
@@ -6,7 +7,7 @@
|
|||||||
* This software is provided AS-IS with no warranty, either express
|
* This software is provided AS-IS with no warranty, either express
|
||||||
* or implied.
|
* or implied.
|
||||||
*
|
*
|
||||||
* This program is dual licensed under the MIT and GPLv3 licenses.
|
* This program is dual licensed under the MIT or GPLv3 licenses.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
|
||||||
/* test_sasl.c
|
/* test_sasl.c
|
||||||
** libstrophe XMPP client library -- test routines for the SASL implementation
|
** libstrophe XMPP client library -- test routines for the SASL implementation
|
||||||
**
|
**
|
||||||
@@ -6,7 +7,7 @@
|
|||||||
** This software is provided AS-IS with no warranty, either express
|
** This software is provided AS-IS with no warranty, either express
|
||||||
** or implied.
|
** or implied.
|
||||||
**
|
**
|
||||||
** This program is dual licensed under the MIT and GPLv3 licenses.
|
** This program is dual licensed under the MIT or GPLv3 licenses.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
|
||||||
/* test_scram.c
|
/* test_scram.c
|
||||||
* strophe XMPP client library -- test vectors for SCRAM-SHA1
|
* strophe XMPP client library -- test vectors for SCRAM-SHA1
|
||||||
*
|
*
|
||||||
@@ -6,7 +7,7 @@
|
|||||||
* This software is provided AS-IS with no warranty, either express
|
* This software is provided AS-IS with no warranty, either express
|
||||||
* or implied.
|
* or implied.
|
||||||
*
|
*
|
||||||
* This program is dual licensed under the MIT and GPLv3 licenses.
|
* This program is dual licensed under the MIT or GPLv3 licenses.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* gcc -o test_scram -I./src tests/test_scram.c tests/test.c src/sha1.c */
|
/* gcc -o test_scram -I./src tests/test_scram.c tests/test.c src/sha1.c */
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
|
||||||
/* test_send_queue.c
|
/* test_send_queue.c
|
||||||
** libstrophe XMPP client library -- test routines for the send queue
|
** libstrophe XMPP client library -- test routines for the send queue
|
||||||
**
|
**
|
||||||
@@ -6,7 +7,7 @@
|
|||||||
** This software is provided AS-IS with no warranty, either express
|
** This software is provided AS-IS with no warranty, either express
|
||||||
** or implied.
|
** or implied.
|
||||||
**
|
**
|
||||||
** This program is dual licensed under the MIT and GPLv3 licenses.
|
** This program is dual licensed under the MIT or GPLv3 licenses.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
@@ -39,48 +40,48 @@ int main()
|
|||||||
|
|
||||||
xmpp_conn_set_sm_state(conn, sm_state);
|
xmpp_conn_set_sm_state(conn, sm_state);
|
||||||
|
|
||||||
ENSURE_EQ(xmpp_conn_send_queue_len(conn), 0);
|
ENSURE_EQ(0, xmpp_conn_send_queue_len(conn));
|
||||||
|
|
||||||
state = conn->state;
|
state = conn->state;
|
||||||
conn->state = XMPP_STATE_CONNECTED;
|
conn->state = XMPP_STATE_CONNECTED;
|
||||||
|
|
||||||
xmpp_send_raw(conn, "foo", 3);
|
xmpp_send_raw(conn, "foo", 3);
|
||||||
ENSURE_EQ(xmpp_conn_send_queue_len(conn), 1);
|
ENSURE_EQ(1, xmpp_conn_send_queue_len(conn));
|
||||||
|
|
||||||
xmpp_send_raw(conn, "bar", 3);
|
xmpp_send_raw(conn, "bar", 3);
|
||||||
ENSURE_EQ(xmpp_conn_send_queue_len(conn), 2);
|
ENSURE_EQ(2, xmpp_conn_send_queue_len(conn));
|
||||||
|
|
||||||
xmpp_send_raw(conn, "baz", 3);
|
xmpp_send_raw(conn, "baz", 3);
|
||||||
ENSURE_EQ(xmpp_conn_send_queue_len(conn), 3);
|
ENSURE_EQ(3, xmpp_conn_send_queue_len(conn));
|
||||||
|
|
||||||
xmpp_send_raw(conn, "baan", 4);
|
xmpp_send_raw(conn, "baan", 4);
|
||||||
ENSURE_EQ(xmpp_conn_send_queue_len(conn), 4);
|
ENSURE_EQ(4, xmpp_conn_send_queue_len(conn));
|
||||||
|
|
||||||
conn->send_queue_head->wip = 1;
|
conn->send_queue_head->wip = 1;
|
||||||
ENSURE_EQ(xmpp_conn_send_queue_len(conn), 3);
|
ENSURE_EQ(3, xmpp_conn_send_queue_len(conn));
|
||||||
|
|
||||||
ret = xmpp_conn_send_queue_drop_element(conn, XMPP_QUEUE_OLDEST);
|
ret = xmpp_conn_send_queue_drop_element(conn, XMPP_QUEUE_OLDEST);
|
||||||
COMPARE("bar", ret);
|
COMPARE("bar", ret);
|
||||||
xmpp_free(ctx, ret);
|
xmpp_free(ctx, ret);
|
||||||
ENSURE_EQ(xmpp_conn_send_queue_len(conn), 2);
|
ENSURE_EQ(2, xmpp_conn_send_queue_len(conn));
|
||||||
|
|
||||||
conn->send_queue_head->wip = 0;
|
conn->send_queue_head->wip = 0;
|
||||||
ENSURE_EQ(xmpp_conn_send_queue_len(conn), 3);
|
ENSURE_EQ(3, xmpp_conn_send_queue_len(conn));
|
||||||
|
|
||||||
ret = xmpp_conn_send_queue_drop_element(conn, XMPP_QUEUE_OLDEST);
|
ret = xmpp_conn_send_queue_drop_element(conn, XMPP_QUEUE_OLDEST);
|
||||||
COMPARE("foo", ret);
|
COMPARE("foo", ret);
|
||||||
xmpp_free(ctx, ret);
|
xmpp_free(ctx, ret);
|
||||||
ENSURE_EQ(xmpp_conn_send_queue_len(conn), 2);
|
ENSURE_EQ(2, xmpp_conn_send_queue_len(conn));
|
||||||
|
|
||||||
ret = xmpp_conn_send_queue_drop_element(conn, XMPP_QUEUE_YOUNGEST);
|
ret = xmpp_conn_send_queue_drop_element(conn, XMPP_QUEUE_YOUNGEST);
|
||||||
COMPARE("baan", ret);
|
COMPARE("baan", ret);
|
||||||
xmpp_free(ctx, ret);
|
xmpp_free(ctx, ret);
|
||||||
ENSURE_EQ(xmpp_conn_send_queue_len(conn), 1);
|
ENSURE_EQ(1, xmpp_conn_send_queue_len(conn));
|
||||||
|
|
||||||
ret = xmpp_conn_send_queue_drop_element(conn, XMPP_QUEUE_YOUNGEST);
|
ret = xmpp_conn_send_queue_drop_element(conn, XMPP_QUEUE_YOUNGEST);
|
||||||
COMPARE("baz", ret);
|
COMPARE("baz", ret);
|
||||||
xmpp_free(ctx, ret);
|
xmpp_free(ctx, ret);
|
||||||
ENSURE_EQ(xmpp_conn_send_queue_len(conn), 0);
|
ENSURE_EQ(0, xmpp_conn_send_queue_len(conn));
|
||||||
|
|
||||||
conn->state = state;
|
conn->state = state;
|
||||||
|
|
||||||
|
|||||||
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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
|
||||||
/* test_sock.c
|
/* test_sock.c
|
||||||
** libstrophe XMPP client library -- test routines for the socket abstraction
|
** libstrophe XMPP client library -- test routines for the socket abstraction
|
||||||
**
|
**
|
||||||
@@ -6,7 +7,7 @@
|
|||||||
** This software is provided AS-IS with no warranty, either express
|
** This software is provided AS-IS with no warranty, either express
|
||||||
** or implied.
|
** or implied.
|
||||||
**
|
**
|
||||||
** This program is dual licensed under the MIT and GPLv3 licenses.
|
** This program is dual licensed under the MIT or GPLv3 licenses.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
|
||||||
/* test_stanza.c
|
/* test_stanza.c
|
||||||
* libstrophe XMPP client library -- test routines for stanza functions
|
* libstrophe XMPP client library -- test routines for stanza functions
|
||||||
*
|
*
|
||||||
@@ -6,7 +7,7 @@
|
|||||||
* This software is provided AS-IS with no warranty, either express
|
* This software is provided AS-IS with no warranty, either express
|
||||||
* or implied.
|
* or implied.
|
||||||
*
|
*
|
||||||
* This program is dual licensed under the MIT and GPLv3 licenses.
|
* This program is dual licensed under the MIT or GPLv3 licenses.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* gcc -o test_stanza -I./src tests/test_stanza.c -lstrophe */
|
/* gcc -o test_stanza -I./src tests/test_stanza.c -lstrophe */
|
||||||
@@ -174,7 +175,7 @@ static void test_stanza_error(xmpp_ctx_t *ctx)
|
|||||||
xmpp_stanza_reply_error(stanza, "cancel", "service-unavailable", NULL);
|
xmpp_stanza_reply_error(stanza, "cancel", "service-unavailable", NULL);
|
||||||
assert(error != NULL);
|
assert(error != NULL);
|
||||||
mood = xmpp_stanza_new_from_string(ctx, str_mood);
|
mood = xmpp_stanza_new_from_string(ctx, str_mood);
|
||||||
assert(stanza != NULL);
|
assert(mood != NULL);
|
||||||
|
|
||||||
assert(xmpp_stanza_get_to(error) != 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));
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
|
||||||
/* test_string.c
|
/* test_string.c
|
||||||
* strophe XMPP client library -- tests for re-implemented string functions
|
* strophe XMPP client library -- tests for re-implemented string functions
|
||||||
*
|
*
|
||||||
@@ -6,7 +7,7 @@
|
|||||||
* This software is provided AS-IS with no warranty, either express
|
* This software is provided AS-IS with no warranty, either express
|
||||||
* or implied.
|
* or implied.
|
||||||
*
|
*
|
||||||
* This program is dual licensed under the MIT and GPLv3 licenses.
|
* This program is dual licensed under the MIT or GPLv3 licenses.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
|
||||||
/* test_xmppaddr.c
|
/* test_xmppaddr.c
|
||||||
** libstrophe XMPP client library -- test routines for the xmppaddr
|
** libstrophe XMPP client library -- test routines for the xmppaddr
|
||||||
** certificate API's
|
** certificate API's
|
||||||
@@ -7,7 +8,7 @@
|
|||||||
** This software is provided AS-IS with no warranty, either express
|
** This software is provided AS-IS with no warranty, either express
|
||||||
** or implied.
|
** or implied.
|
||||||
**
|
**
|
||||||
** This program is dual licensed under the MIT and GPLv3 licenses.
|
** This program is dual licensed under the MIT or GPLv3 licenses.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|||||||
Reference in New Issue
Block a user