mirror of
https://github.com/strophe/libstrophe.git
synced 2026-08-05 11:26:22 +00:00
Compare commits
136 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d20957a98d | ||
|
|
8cfb2d2a03 | ||
|
|
1b10e8f987 | ||
|
|
178f566ae2 | ||
|
|
0326e5c5e2 | ||
|
|
212df6d036 | ||
|
|
4b04db6b2d | ||
|
|
fb327d4bd1 | ||
|
|
a811c868ff | ||
|
|
3f05bafffb | ||
|
|
133abd096d | ||
|
|
cecd6b20e8 | ||
|
|
2272681ea2 | ||
|
|
17f79cbbb8 | ||
|
|
2570084cae | ||
|
|
b2e6458736 | ||
|
|
c192a2b181 | ||
|
|
2e325e5e68 | ||
|
|
f0436490b0 | ||
|
|
243664926f | ||
|
|
466fa2adbf | ||
|
|
284e8f4421 | ||
|
|
6852da97ae | ||
|
|
35f37e8c23 | ||
|
|
cbe6701c14 | ||
|
|
296df2fca9 | ||
|
|
7caf88a6a8 | ||
|
|
ebaad72a35 | ||
|
|
962bf4de5e | ||
|
|
884dace400 | ||
|
|
234bef4025 | ||
|
|
45cbd51633 | ||
|
|
484e971323 | ||
|
|
038404cb99 | ||
|
|
6f075bfc71 | ||
|
|
7aed036896 | ||
|
|
0e8c88a5e4 | ||
|
|
a13847d994 | ||
|
|
18b67d6eaf | ||
|
|
886f45584c | ||
|
|
4f915d7515 | ||
|
|
e25ca7719f | ||
|
|
2bf5cc0e41 | ||
|
|
30f3cc9263 | ||
|
|
e120109644 | ||
|
|
b4f13205d8 | ||
|
|
4797522d88 | ||
|
|
5ee06776ee | ||
|
|
c40b4c12c1 | ||
|
|
d8329960c5 | ||
|
|
94ece33f16 | ||
|
|
b179c2d277 | ||
|
|
ab568a2666 | ||
|
|
c10c930e8f | ||
|
|
6ddf424192 | ||
|
|
6aff44184e | ||
|
|
9cc9ea86bb | ||
|
|
13a0bc463c | ||
|
|
8ff510a3af | ||
|
|
633d1e9b52 | ||
|
|
a13ba65cfb | ||
|
|
0e6b0ef84d | ||
|
|
9a86efabe5 | ||
|
|
a4b05cf156 | ||
|
|
06da6d5125 | ||
|
|
1bcf77608d | ||
|
|
aab0cc3e3e | ||
|
|
822f95071a | ||
|
|
27f613bc84 | ||
|
|
af1ef3855b | ||
|
|
7ede9c6d03 | ||
|
|
20c6f225b9 | ||
|
|
5b204b0938 | ||
|
|
6e6093ee7b | ||
|
|
f12d43989f | ||
|
|
032e8ec89d | ||
|
|
d0644c5e95 | ||
|
|
b1b827cde6 | ||
|
|
e73b577e0b | ||
|
|
8d2d59e914 | ||
|
|
212f3ea760 | ||
|
|
4aa7ea7e5b | ||
|
|
5f9c0399c3 | ||
|
|
b83347b464 | ||
|
|
d8a86a54d5 | ||
|
|
49289a9c05 | ||
|
|
456083d878 | ||
|
|
15e7032f0d | ||
|
|
cd2cf6eb23 | ||
|
|
666995531a | ||
|
|
9269d6b0d5 | ||
|
|
c319ee6583 | ||
|
|
cc53012cfa | ||
|
|
cc297eff45 | ||
|
|
e151096834 | ||
|
|
82040403bf | ||
|
|
a845c7ec3d | ||
|
|
5ecb0c5d0c | ||
|
|
da8dc2d3cb | ||
|
|
182695d1ca | ||
|
|
0d039f7192 | ||
|
|
ebe97e8f2a | ||
|
|
9505cace5e | ||
|
|
8ef027c54a | ||
|
|
0bdb5f1d5b | ||
|
|
49e7572059 | ||
|
|
c074a6166c | ||
|
|
4c504ee42b | ||
|
|
f226891520 | ||
|
|
43a68479ad | ||
|
|
1e422a70dd | ||
|
|
2a474bd809 | ||
|
|
704c157d24 | ||
|
|
d8528b597c | ||
|
|
c149caa32a | ||
|
|
fa63aac731 | ||
|
|
ba40bf1040 | ||
|
|
2f9bcfe145 | ||
|
|
b957213fdc | ||
|
|
f51b01a5b3 | ||
|
|
d2efc85ce3 | ||
|
|
940d76e9e2 | ||
|
|
59eb8d67ed | ||
|
|
78592650e5 | ||
|
|
92d006a41b | ||
|
|
0741820711 | ||
|
|
c9ddc2b7ef | ||
|
|
f776b34d8c | ||
|
|
f47609c1f0 | ||
|
|
443b4d3116 | ||
|
|
4cf7a0cb79 | ||
|
|
9a5fe8b96d | ||
|
|
80a7ea0b7c | ||
|
|
1092447edf | ||
|
|
d2c1daf4d5 | ||
|
|
d1a41c9d7d |
5
.gitignore
vendored
5
.gitignore
vendored
@@ -34,8 +34,10 @@ examples/active
|
|||||||
examples/basic
|
examples/basic
|
||||||
examples/bot
|
examples/bot
|
||||||
examples/component
|
examples/component
|
||||||
|
examples/register
|
||||||
examples/roster
|
examples/roster
|
||||||
examples/uuid
|
examples/uuid
|
||||||
|
examples/vcard
|
||||||
test_stamp
|
test_stamp
|
||||||
test-suite.log
|
test-suite.log
|
||||||
tests/*.o
|
tests/*.o
|
||||||
@@ -53,8 +55,9 @@ tests/test_sasl
|
|||||||
tests/test_scram
|
tests/test_scram
|
||||||
tests/test_sha1
|
tests/test_sha1
|
||||||
tests/test_snprintf
|
tests/test_snprintf
|
||||||
tests/test_string
|
|
||||||
tests/test_sock
|
tests/test_sock
|
||||||
|
tests/test_stanza
|
||||||
|
tests/test_string
|
||||||
m4/
|
m4/
|
||||||
libstrophe.project
|
libstrophe.project
|
||||||
libs/
|
libs/
|
||||||
|
|||||||
18
.travis.yml
18
.travis.yml
@@ -1,11 +1,15 @@
|
|||||||
language: c
|
language: c
|
||||||
install:
|
install:
|
||||||
- sudo apt-get update
|
- sudo apt-get update
|
||||||
- sudo apt-get -y install libtool pkg-config libexpat1-dev libxml2-dev libssl-dev check
|
- sudo apt-get -y install libtool pkg-config libexpat1-dev libxml2-dev libssl-dev libc-ares-dev
|
||||||
script:
|
before_script:
|
||||||
- ./bootstrap.sh
|
- ./bootstrap.sh
|
||||||
- ./configure --without-libxml2 && make CFLAGS="-Wall -Werror" && make CFLAGS="-Wall -Werror" check-TESTS
|
script:
|
||||||
- make clean
|
- ./configure ${CONFIGURE_OPT} CFLAGS="-Werror" && make && make check
|
||||||
- ./configure --with-libxml2 && make CFLAGS="-Wall -Werror" && make CFLAGS="-Wall -Werror" check-TESTS
|
env:
|
||||||
- make clean
|
- CONFIGURE_OPT="--without-libxml2"
|
||||||
- ./configure --disable-tls && make CFLAGS="-Wall -Werror" && make CFLAGS="-Wall -Werror" check-TESTS
|
- CONFIGURE_OPT="--with-libxml2"
|
||||||
|
- CONFIGURE_OPT="--disable-tls"
|
||||||
|
- CONFIGURE_OPT="--enable-cares"
|
||||||
|
matrix:
|
||||||
|
fast_finish: true
|
||||||
|
|||||||
40
ChangeLog
40
ChangeLog
@@ -1,3 +1,43 @@
|
|||||||
|
0.10.0
|
||||||
|
- c-ares support
|
||||||
|
- LibreSSL support
|
||||||
|
- examples/register implements XEP-0077
|
||||||
|
- New API:
|
||||||
|
- xmpp_stanza_get_child_by_name_and_ns()
|
||||||
|
- xmpp_conn_is_connecting()
|
||||||
|
- xmpp_conn_is_connected()
|
||||||
|
- xmpp_conn_is_disconnected()
|
||||||
|
- xmpp_stanza_add_child_ex()
|
||||||
|
- xmpp_stanza_get_context()
|
||||||
|
|
||||||
|
0.9.3
|
||||||
|
- PLAIN mechanism is used only when no other mechanisms are supported
|
||||||
|
- Legacy authentication is disabled by default, can be enabled with
|
||||||
|
connection flag XMPP_CONN_FLAG_LEGACY_AUTH
|
||||||
|
- Session is not established if it is optional
|
||||||
|
- Fixed a bug causing a reused connection not to cleanup properly
|
||||||
|
- Improved debug logging in OpenSSL module
|
||||||
|
- Few memory leaks fixed
|
||||||
|
|
||||||
|
0.9.2
|
||||||
|
- OpenSSL tls module verifies certificate by default. Set flag
|
||||||
|
XMPP_CONN_FLAG_TRUST_TLS to ignore result of the verification
|
||||||
|
- Certificate hostname verification is forced for openssl-1.0.2 and
|
||||||
|
newer
|
||||||
|
- OpenSSL tls module disables insecure SSLv2 SSLv3 and TLSv1
|
||||||
|
- Support of handlers with the same callback function, but different
|
||||||
|
userdata
|
||||||
|
- System handlers are deleted on xmpp_conn_t reconnection. Old system
|
||||||
|
handlers could cause problems
|
||||||
|
- Default timeout for xmpp_run() is increased from 1 millisecond to 1
|
||||||
|
second in order to reduce CPU consumption
|
||||||
|
- Reduced memory usage in expat module
|
||||||
|
- New functions:
|
||||||
|
- xmpp_error_new()
|
||||||
|
- xmpp_send_error()
|
||||||
|
- xmpp_ctx_set_timeout()
|
||||||
|
- xmpp_sha1_digest()
|
||||||
|
|
||||||
0.9.1
|
0.9.1
|
||||||
- Fixed bug #95 (DNS lookup failing on Cygwin)
|
- Fixed bug #95 (DNS lookup failing on Cygwin)
|
||||||
- Removed dependency on the check package
|
- Removed dependency on the check package
|
||||||
|
|||||||
122
Makefile.am
122
Makefile.am
@@ -1,7 +1,6 @@
|
|||||||
AUTOMAKE_OPTIONS = subdir-objects
|
AUTOMAKE_OPTIONS = subdir-objects
|
||||||
|
|
||||||
ACLOCAL_AMFLAGS = -I m4
|
ACLOCAL_AMFLAGS = -I m4
|
||||||
AM_CFLAGS = -g -Wall
|
|
||||||
|
|
||||||
PARSER_CFLAGS=@PARSER_CFLAGS@
|
PARSER_CFLAGS=@PARSER_CFLAGS@
|
||||||
PARSER_LIBS=@PARSER_LIBS@
|
PARSER_LIBS=@PARSER_LIBS@
|
||||||
@@ -9,26 +8,56 @@ PARSER_LIBS=@PARSER_LIBS@
|
|||||||
SSL_CFLAGS = @openssl_CFLAGS@
|
SSL_CFLAGS = @openssl_CFLAGS@
|
||||||
SSL_LIBS = @openssl_LIBS@
|
SSL_LIBS = @openssl_LIBS@
|
||||||
|
|
||||||
|
RESOLV_CFLAGS = @RESOLV_CFLAGS@
|
||||||
RESOLV_LIBS = @RESOLV_LIBS@
|
RESOLV_LIBS = @RESOLV_LIBS@
|
||||||
|
|
||||||
STROPHE_FLAGS = -I$(top_srcdir)
|
WARNING_FLAGS = @WARNING_FLAGS@
|
||||||
|
STROPHE_FLAGS = -I$(top_srcdir) $(WARNING_FLAGS)
|
||||||
STROPHE_LIBS = libstrophe.la
|
STROPHE_LIBS = libstrophe.la
|
||||||
|
|
||||||
## Main build targets
|
## Main build targets
|
||||||
lib_LTLIBRARIES = libstrophe.la
|
lib_LTLIBRARIES = libstrophe.la
|
||||||
|
|
||||||
libstrophe_la_CFLAGS = $(SSL_CFLAGS) $(STROPHE_FLAGS) $(PARSER_CFLAGS)
|
libstrophe_la_CFLAGS = $(SSL_CFLAGS) $(STROPHE_FLAGS) $(PARSER_CFLAGS) $(RESOLV_CFLAGS)
|
||||||
libstrophe_la_LDFLAGS = $(SSL_LIBS) $(PARSER_LIBS) $(RESOLV_LIBS) -no-undefined
|
libstrophe_la_LDFLAGS = $(SSL_LIBS) $(PARSER_LIBS) $(RESOLV_LIBS) -no-undefined
|
||||||
# Export only public API
|
# Export only public API
|
||||||
libstrophe_la_LDFLAGS += -export-symbols-regex '^xmpp_'
|
libstrophe_la_LDFLAGS += -export-symbols-regex '^xmpp_'
|
||||||
libstrophe_la_SOURCES = src/auth.c src/conn.c src/crypto.c src/ctx.c \
|
|
||||||
src/event.c src/handler.c src/hash.c src/jid.c src/md5.c \
|
libstrophe_la_SOURCES = \
|
||||||
src/resolver.c src/sasl.c src/scram.c src/sha1.c \
|
src/auth.c \
|
||||||
src/snprintf.c src/sock.c src/stanza.c src/util.c \
|
src/conn.c \
|
||||||
src/rand.c src/uuid.c \
|
src/crypto.c \
|
||||||
src/common.h src/hash.h src/md5.h src/ostypes.h src/parser.h \
|
src/ctx.c \
|
||||||
src/resolver.h src/sasl.h src/scram.h src/sha1.h src/snprintf.h \
|
src/event.c \
|
||||||
src/sock.h src/tls.h src/util.h src/rand.h
|
src/handler.c \
|
||||||
|
src/hash.c \
|
||||||
|
src/jid.c \
|
||||||
|
src/md5.c \
|
||||||
|
src/rand.c \
|
||||||
|
src/resolver.c \
|
||||||
|
src/sasl.c \
|
||||||
|
src/scram.c \
|
||||||
|
src/sha1.c \
|
||||||
|
src/snprintf.c \
|
||||||
|
src/sock.c \
|
||||||
|
src/stanza.c \
|
||||||
|
src/util.c \
|
||||||
|
src/uuid.c
|
||||||
|
libstrophe_la_SOURCES += \
|
||||||
|
src/common.h \
|
||||||
|
src/hash.h \
|
||||||
|
src/md5.h \
|
||||||
|
src/ostypes.h \
|
||||||
|
src/parser.h \
|
||||||
|
src/rand.h \
|
||||||
|
src/resolver.h \
|
||||||
|
src/sasl.h \
|
||||||
|
src/scram.h \
|
||||||
|
src/sha1.h \
|
||||||
|
src/snprintf.h \
|
||||||
|
src/sock.h \
|
||||||
|
src/tls.h \
|
||||||
|
src/util.h
|
||||||
|
|
||||||
if DISABLE_TLS
|
if DISABLE_TLS
|
||||||
libstrophe_la_SOURCES += src/tls_dummy.c
|
libstrophe_la_SOURCES += src/tls_dummy.c
|
||||||
@@ -47,19 +76,37 @@ noinst_HEADERS = strophepp.h
|
|||||||
|
|
||||||
pkgconfig_DATA = libstrophe.pc
|
pkgconfig_DATA = libstrophe.pc
|
||||||
|
|
||||||
EXTRA_DIST = docs rpm Doxyfile LICENSE.txt GPL-LICENSE.txt MIT-LICENSE.txt \
|
EXTRA_DIST = \
|
||||||
src/tls_dummy.c src/tls_gnutls.c src/tls_schannel.c \
|
Doxyfile \
|
||||||
examples/README.md
|
GPL-LICENSE.txt \
|
||||||
|
LICENSE.txt \
|
||||||
|
MIT-LICENSE.txt \
|
||||||
|
bootstrap.sh \
|
||||||
|
build-android.sh \
|
||||||
|
docs/footer.html \
|
||||||
|
examples/README.md \
|
||||||
|
jni/Android.mk \
|
||||||
|
jni/Application.mk \
|
||||||
|
rpm/README \
|
||||||
|
rpm/libstrophe.spec \
|
||||||
|
src/tls_gnutls.c \
|
||||||
|
src/tls_schannel.c \
|
||||||
|
tests/res_query_dump.c
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
noinst_PROGRAMS = examples/active examples/roster examples/basic examples/bot \
|
noinst_PROGRAMS = \
|
||||||
examples/component examples/uuid
|
examples/active \
|
||||||
|
examples/basic \
|
||||||
|
examples/bot \
|
||||||
|
examples/component \
|
||||||
|
examples/roster \
|
||||||
|
examples/uuid \
|
||||||
|
examples/vcard \
|
||||||
|
examples/register
|
||||||
|
|
||||||
examples_active_SOURCES = examples/active.c
|
examples_active_SOURCES = examples/active.c
|
||||||
examples_active_CFLAGS = $(STROPHE_FLAGS)
|
examples_active_CFLAGS = $(STROPHE_FLAGS)
|
||||||
examples_active_LDADD = $(STROPHE_LIBS)
|
examples_active_LDADD = $(STROPHE_LIBS)
|
||||||
examples_roster_SOURCES = examples/roster.c
|
|
||||||
examples_roster_CFLAGS = $(STROPHE_FLAGS)
|
|
||||||
examples_roster_LDADD = $(STROPHE_LIBS)
|
|
||||||
examples_basic_SOURCES = examples/basic.c
|
examples_basic_SOURCES = examples/basic.c
|
||||||
examples_basic_CFLAGS = $(STROPHE_FLAGS)
|
examples_basic_CFLAGS = $(STROPHE_FLAGS)
|
||||||
examples_basic_LDADD = $(STROPHE_LIBS)
|
examples_basic_LDADD = $(STROPHE_LIBS)
|
||||||
@@ -69,15 +116,36 @@ examples_bot_LDADD = $(STROPHE_LIBS)
|
|||||||
examples_component_SOURCES = examples/component.c
|
examples_component_SOURCES = examples/component.c
|
||||||
examples_component_CFLAGS = $(STROPHE_FLAGS)
|
examples_component_CFLAGS = $(STROPHE_FLAGS)
|
||||||
examples_component_LDADD = $(STROPHE_LIBS)
|
examples_component_LDADD = $(STROPHE_LIBS)
|
||||||
|
examples_roster_SOURCES = examples/roster.c
|
||||||
|
examples_roster_CFLAGS = $(STROPHE_FLAGS)
|
||||||
|
examples_roster_LDADD = $(STROPHE_LIBS)
|
||||||
examples_uuid_SOURCES = examples/uuid.c
|
examples_uuid_SOURCES = examples/uuid.c
|
||||||
examples_uuid_CFLAGS = $(STROPHE_FLAGS)
|
examples_uuid_CFLAGS = $(STROPHE_FLAGS)
|
||||||
examples_uuid_LDADD = $(STROPHE_LIBS)
|
examples_uuid_LDADD = $(STROPHE_LIBS)
|
||||||
|
examples_vcard_SOURCES = examples/vcard.c
|
||||||
|
examples_vcard_CFLAGS = $(STROPHE_FLAGS)
|
||||||
|
examples_vcard_LDADD = $(STROPHE_LIBS)
|
||||||
|
examples_register_SOURCES = examples/register.c
|
||||||
|
examples_register_CFLAGS = $(STROPHE_FLAGS)
|
||||||
|
examples_register_LDADD = $(STROPHE_LIBS)
|
||||||
|
|
||||||
|
|
||||||
## Tests
|
## Tests
|
||||||
TESTS = tests/check_parser tests/test_sha1 tests/test_md5 tests/test_rand \
|
TESTS = \
|
||||||
tests/test_scram tests/test_ctx tests/test_base64 tests/test_jid \
|
tests/check_parser \
|
||||||
tests/test_snprintf tests/test_string tests/test_resolver
|
tests/test_sha1 \
|
||||||
|
tests/test_md5 \
|
||||||
|
tests/test_rand \
|
||||||
|
tests/test_scram \
|
||||||
|
tests/test_ctx \
|
||||||
|
tests/test_base64 \
|
||||||
|
tests/test_hash \
|
||||||
|
tests/test_jid \
|
||||||
|
tests/test_snprintf \
|
||||||
|
tests/test_string \
|
||||||
|
tests/test_stanza \
|
||||||
|
tests/test_resolver
|
||||||
|
|
||||||
check_PROGRAMS = $(TESTS)
|
check_PROGRAMS = $(TESTS)
|
||||||
|
|
||||||
tests_check_parser_SOURCES = tests/check_parser.c tests/test.h
|
tests_check_parser_SOURCES = tests/check_parser.c tests/test.h
|
||||||
@@ -96,6 +164,11 @@ tests_test_base64_CFLAGS = $(STROPHE_FLAGS) -I$(top_srcdir)/src
|
|||||||
tests_test_base64_LDADD = $(STROPHE_LIBS)
|
tests_test_base64_LDADD = $(STROPHE_LIBS)
|
||||||
tests_test_base64_LDFLAGS = -static
|
tests_test_base64_LDFLAGS = -static
|
||||||
|
|
||||||
|
tests_test_hash_SOURCES = tests/test_hash.c
|
||||||
|
tests_test_hash_CFLAGS = $(STROPHE_FLAGS) -I$(top_srcdir)/src
|
||||||
|
tests_test_hash_LDADD = $(STROPHE_LIBS)
|
||||||
|
tests_test_hash_LDFLAGS = -static
|
||||||
|
|
||||||
tests_test_jid_SOURCES = tests/test_jid.c
|
tests_test_jid_SOURCES = tests/test_jid.c
|
||||||
tests_test_jid_CFLAGS = $(STROPHE_FLAGS) -I$(top_srcdir)/src
|
tests_test_jid_CFLAGS = $(STROPHE_FLAGS) -I$(top_srcdir)/src
|
||||||
tests_test_jid_LDADD = $(STROPHE_LIBS)
|
tests_test_jid_LDADD = $(STROPHE_LIBS)
|
||||||
@@ -125,3 +198,8 @@ tests_test_string_SOURCES = tests/test_string.c tests/test.h
|
|||||||
tests_test_string_CFLAGS = $(STROPHE_FLAGS) -I$(top_srcdir)/src
|
tests_test_string_CFLAGS = $(STROPHE_FLAGS) -I$(top_srcdir)/src
|
||||||
tests_test_string_LDADD = $(STROPHE_LIBS)
|
tests_test_string_LDADD = $(STROPHE_LIBS)
|
||||||
tests_test_string_LDFLAGS = -static
|
tests_test_string_LDFLAGS = -static
|
||||||
|
|
||||||
|
tests_test_stanza_SOURCES = tests/test_stanza.c
|
||||||
|
tests_test_stanza_CFLAGS = $(STROPHE_FLAGS)
|
||||||
|
tests_test_stanza_LDADD = $(STROPHE_LIBS)
|
||||||
|
tests_test_stanza_LDFLAGS = -static
|
||||||
|
|||||||
33
configure.ac
33
configure.ac
@@ -1,4 +1,4 @@
|
|||||||
AC_INIT([libstrophe], [0.9.1], [jack@metajack.im])
|
AC_INIT([libstrophe], [0.9.3], [jack@metajack.im])
|
||||||
AC_CONFIG_MACRO_DIR([m4])
|
AC_CONFIG_MACRO_DIR([m4])
|
||||||
AM_INIT_AUTOMAKE([foreign])
|
AM_INIT_AUTOMAKE([foreign])
|
||||||
LT_INIT([dlopen])
|
LT_INIT([dlopen])
|
||||||
@@ -15,12 +15,24 @@ AS_CASE([$host_os],
|
|||||||
[*nto*|*qnx*], [PLATFORM="qnx"],
|
[*nto*|*qnx*], [PLATFORM="qnx"],
|
||||||
[*solaris*], [PLATFORM="solaris"],
|
[*solaris*], [PLATFORM="solaris"],
|
||||||
[*android*], [PLATFORM="android"],
|
[*android*], [PLATFORM="android"],
|
||||||
|
[*haiku*], [PLATFORM="haiku"],
|
||||||
[PLATFORM="nix"])
|
[PLATFORM="nix"])
|
||||||
|
|
||||||
|
WARNING_FLAGS="-Wall"
|
||||||
|
|
||||||
|
AS_CASE([$PLATFORM],
|
||||||
|
[haiku], [],
|
||||||
|
[WARNING_FLAGS="$WARNING_FLAGS -Wextra -Wno-unused-parameter"])
|
||||||
|
|
||||||
AC_ARG_WITH([libxml2],
|
AC_ARG_WITH([libxml2],
|
||||||
[AS_HELP_STRING([--with-libxml2], [use libxml2 for XML parsing, expat is the default])])
|
[AS_HELP_STRING([--with-libxml2], [use libxml2 for XML parsing, expat is the default])])
|
||||||
AC_ARG_ENABLE([tls],
|
AC_ARG_ENABLE([tls],
|
||||||
[AS_HELP_STRING([--disable-tls], [disable TLS support])])
|
[AS_HELP_STRING([--disable-tls], [disable TLS support])])
|
||||||
|
AC_ARG_ENABLE([cares],
|
||||||
|
[AS_HELP_STRING([--enable-cares], [use c-ares for DNS resolution])])
|
||||||
|
|
||||||
|
AC_SEARCH_LIBS([socket], [network socket])
|
||||||
|
#AC_CHECK_FUNCS([snprintf vsnprintf])
|
||||||
|
|
||||||
if test "x$enable_tls" != xno; then
|
if test "x$enable_tls" != xno; then
|
||||||
PKG_CHECK_MODULES([openssl], [openssl],
|
PKG_CHECK_MODULES([openssl], [openssl],
|
||||||
@@ -62,7 +74,7 @@ if test "x$with_libxml2" != xno -a "x$with_parser" = x; then
|
|||||||
[
|
[
|
||||||
with_parser="libxml2"
|
with_parser="libxml2"
|
||||||
libxml2_CFLAGS="-I${includedir}/libxml2"
|
libxml2_CFLAGS="-I${includedir}/libxml2"
|
||||||
libxml2_LIBS="-lxml2"
|
libxml2_LIBS="-lxml2 -lm"
|
||||||
PC_LIBS="${libxml2_LIBS} ${PC_LIBS}"
|
PC_LIBS="${libxml2_LIBS} ${PC_LIBS}"
|
||||||
PC_CFLAGS="${libxml2_CFLAGS} ${PC_CFLAGS}"
|
PC_CFLAGS="${libxml2_CFLAGS} ${PC_CFLAGS}"
|
||||||
])
|
])
|
||||||
@@ -82,13 +94,24 @@ fi
|
|||||||
|
|
||||||
AC_MSG_NOTICE([libstrophe will use the $with_parser XML parser])
|
AC_MSG_NOTICE([libstrophe will use the $with_parser XML parser])
|
||||||
|
|
||||||
AC_SEARCH_LIBS([socket], [socket])
|
if test "x$enable_cares" = xyes; then
|
||||||
|
PKG_CHECK_MODULES([libcares], [libcares >= 1.7.0],
|
||||||
|
[
|
||||||
|
PC_REQUIRES="libcares ${PC_REQUIRES}"
|
||||||
|
RESOLV_CFLAGS=$libcares_CFLAGS
|
||||||
|
RESOLV_LIBS=$libcares_LIBS
|
||||||
|
AC_DEFINE([HAVE_CARES])
|
||||||
|
],
|
||||||
|
[AC_MSG_ERROR([libcares not found])])
|
||||||
|
# TODO: if pkg-config doesn't find, check the library manually
|
||||||
|
else
|
||||||
|
|
||||||
AS_CASE([$PLATFORM],
|
AS_CASE([$PLATFORM],
|
||||||
[bsd], [RESOLV_LIBS=""],
|
[bsd], [RESOLV_LIBS=""],
|
||||||
[qnx], [RESOLV_LIBS="-lsocket"],
|
[qnx], [RESOLV_LIBS="-lsocket"],
|
||||||
[solaris], [RESOLV_LIBS="-lresolv -lsocket -lnsl"],
|
[solaris], [RESOLV_LIBS="-lresolv -lsocket -lnsl"],
|
||||||
[android], [RESOLV_LIBS=""],
|
[android], [RESOLV_LIBS=""],
|
||||||
|
[haiku], [RESOLV_LIBS="-lnetwork"],
|
||||||
[RESOLV_LIBS="-lresolv"])
|
[RESOLV_LIBS="-lresolv"])
|
||||||
|
|
||||||
LIBS_TMP="${LIBS}"
|
LIBS_TMP="${LIBS}"
|
||||||
@@ -110,6 +133,8 @@ AC_LINK_IFELSE([AC_LANG_SOURCE([
|
|||||||
LIBS="${LIBS_TMP}"
|
LIBS="${LIBS_TMP}"
|
||||||
PC_LIBS="${RESOLV_LIBS} ${PC_LIBS}"
|
PC_LIBS="${RESOLV_LIBS} ${PC_LIBS}"
|
||||||
|
|
||||||
|
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],
|
||||||
@@ -126,6 +151,8 @@ AC_SUBST([PC_LIBS], [${PC_LIBS}])
|
|||||||
|
|
||||||
AC_SUBST(PARSER_CFLAGS)
|
AC_SUBST(PARSER_CFLAGS)
|
||||||
AC_SUBST(PARSER_LIBS)
|
AC_SUBST(PARSER_LIBS)
|
||||||
|
AC_SUBST(RESOLV_CFLAGS)
|
||||||
AC_SUBST(RESOLV_LIBS)
|
AC_SUBST(RESOLV_LIBS)
|
||||||
|
AC_SUBST(WARNING_FLAGS)
|
||||||
AC_CONFIG_FILES([Makefile libstrophe.pc])
|
AC_CONFIG_FILES([Makefile libstrophe.pc])
|
||||||
AC_OUTPUT
|
AC_OUTPUT
|
||||||
|
|||||||
@@ -55,10 +55,7 @@ void conn_handler(xmpp_conn_t * const conn, const xmpp_conn_event_t status,
|
|||||||
fprintf(stderr, "DEBUG: connected\n");
|
fprintf(stderr, "DEBUG: connected\n");
|
||||||
|
|
||||||
/* create iq stanza for request */
|
/* create iq stanza for request */
|
||||||
iq = xmpp_stanza_new(ctx);
|
iq = xmpp_iq_new(ctx, "get", "active1");
|
||||||
xmpp_stanza_set_name(iq, "iq");
|
|
||||||
xmpp_stanza_set_type(iq, "get");
|
|
||||||
xmpp_stanza_set_id(iq, "active1");
|
|
||||||
xmpp_stanza_set_to(iq, "xxxxxxxxx.com");
|
xmpp_stanza_set_to(iq, "xxxxxxxxx.com");
|
||||||
|
|
||||||
query = xmpp_stanza_new(ctx);
|
query = xmpp_stanza_new(ctx);
|
||||||
|
|||||||
@@ -73,15 +73,19 @@ int version_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void
|
|||||||
int message_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata)
|
int message_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata)
|
||||||
{
|
{
|
||||||
xmpp_ctx_t *ctx = (xmpp_ctx_t*)userdata;
|
xmpp_ctx_t *ctx = (xmpp_ctx_t*)userdata;
|
||||||
xmpp_stanza_t *reply;
|
xmpp_stanza_t *body, *reply;
|
||||||
|
const char *type;
|
||||||
char *intext, *replytext;
|
char *intext, *replytext;
|
||||||
|
int quit = 0;
|
||||||
|
|
||||||
if (!xmpp_stanza_get_child_by_name(stanza, "body"))
|
body = xmpp_stanza_get_child_by_name(stanza, "body");
|
||||||
|
if (body == NULL)
|
||||||
return 1;
|
return 1;
|
||||||
if (xmpp_stanza_get_type(stanza) != NULL && !strcmp(xmpp_stanza_get_type(stanza), "error"))
|
type = xmpp_stanza_get_type(stanza);
|
||||||
|
if (type != NULL && strcmp(type, "error") == 0)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
intext = xmpp_stanza_get_text(xmpp_stanza_get_child_by_name(stanza, "body"));
|
intext = xmpp_stanza_get_text(body);
|
||||||
|
|
||||||
printf("Incoming message from %s: %s\n", xmpp_stanza_get_from(stanza), intext);
|
printf("Incoming message from %s: %s\n", xmpp_stanza_get_from(stanza), intext);
|
||||||
|
|
||||||
@@ -89,15 +93,24 @@ int message_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void
|
|||||||
if (xmpp_stanza_get_type(reply) == NULL)
|
if (xmpp_stanza_get_type(reply) == NULL)
|
||||||
xmpp_stanza_set_type(reply, "chat");
|
xmpp_stanza_set_type(reply, "chat");
|
||||||
|
|
||||||
|
if (strcmp(intext, "quit") == 0) {
|
||||||
|
replytext = strdup("bye!");
|
||||||
|
quit = 1;
|
||||||
|
} 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);
|
||||||
strcat(replytext, " to you too!");
|
strcat(replytext, " to you too!");
|
||||||
|
}
|
||||||
xmpp_free(ctx, intext);
|
xmpp_free(ctx, intext);
|
||||||
xmpp_message_set_body(reply, replytext);
|
xmpp_message_set_body(reply, replytext);
|
||||||
|
|
||||||
xmpp_send(conn, reply);
|
xmpp_send(conn, reply);
|
||||||
xmpp_stanza_release(reply);
|
xmpp_stanza_release(reply);
|
||||||
free(replytext);
|
free(replytext);
|
||||||
|
|
||||||
|
if (quit)
|
||||||
|
xmpp_disconnect(conn);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
357
examples/register.c
Normal file
357
examples/register.c
Normal file
@@ -0,0 +1,357 @@
|
|||||||
|
/* register.c
|
||||||
|
* strophe XMPP client library -- In-band registration (XEP-0077)
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020 Dmitry Podgorny <pasis.ua@gmail.com>
|
||||||
|
*
|
||||||
|
* This software is provided AS-IS with no warranty, either express
|
||||||
|
* or implied.
|
||||||
|
*
|
||||||
|
* This program is dual licensed under the MIT and GPLv3 licenses.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This example uses a "raw" connection to establish connection to a server
|
||||||
|
* without account. Then it queries server to register new account according
|
||||||
|
* to XEP-0077.
|
||||||
|
*
|
||||||
|
* How to use it. After the application connects and receives instructions
|
||||||
|
* from the server, user will be prompted to type information such as
|
||||||
|
* username, password, etc. Press enter without typing if you want to skip
|
||||||
|
* a field and not to send it to the server.
|
||||||
|
*
|
||||||
|
* Notice, the example doesn't implement forms. Therefore, it won't work
|
||||||
|
* in complicated scenarios.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <strophe.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
xmpp_ctx_t *ctx;
|
||||||
|
const char *jid;
|
||||||
|
} xmpp_reg_t;
|
||||||
|
|
||||||
|
#define FEATURES_TIMEOUT 5000 /* 5 seconds */
|
||||||
|
|
||||||
|
static void iq_reg_send_form(xmpp_reg_t *reg,
|
||||||
|
xmpp_conn_t *conn,
|
||||||
|
xmpp_stanza_t *stanza)
|
||||||
|
{
|
||||||
|
xmpp_ctx_t *ctx = reg->ctx;
|
||||||
|
xmpp_stanza_t *query;
|
||||||
|
xmpp_stanza_t *next;
|
||||||
|
xmpp_stanza_t *elem;
|
||||||
|
xmpp_stanza_t *text;
|
||||||
|
xmpp_stanza_t *iq;
|
||||||
|
const char *name;
|
||||||
|
ssize_t rc;
|
||||||
|
size_t size;
|
||||||
|
char *s;
|
||||||
|
|
||||||
|
query = xmpp_stanza_get_child_by_name(stanza, "query");
|
||||||
|
if (!query) {
|
||||||
|
xmpp_disconnect(conn);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
next = xmpp_stanza_get_children(query);
|
||||||
|
query = xmpp_stanza_new(ctx);
|
||||||
|
xmpp_stanza_set_name(query, "query");
|
||||||
|
xmpp_stanza_set_ns(query, XMPP_NS_REGISTER);
|
||||||
|
while (next) {
|
||||||
|
name = xmpp_stanza_get_name(next);
|
||||||
|
if (name && strcmp(name, "instructions") == 0) {
|
||||||
|
s = xmpp_stanza_get_text(next);
|
||||||
|
printf("instructions: %s\n", s);
|
||||||
|
xmpp_free(ctx, s);
|
||||||
|
} else {
|
||||||
|
printf("%s: ", name);
|
||||||
|
s = NULL;
|
||||||
|
size = 0;
|
||||||
|
rc = getline(&s, &size, stdin);
|
||||||
|
if (rc > 0 && s[rc - 1] == '\n')
|
||||||
|
s[rc - 1] = '\0';
|
||||||
|
if (rc > 0 && strlen(s) > 0) {
|
||||||
|
elem = xmpp_stanza_new(ctx);
|
||||||
|
text = xmpp_stanza_new(ctx);
|
||||||
|
xmpp_stanza_set_text(text, s);
|
||||||
|
xmpp_stanza_set_name(elem, name);
|
||||||
|
xmpp_stanza_add_child(elem, text);
|
||||||
|
xmpp_stanza_add_child(query, elem);
|
||||||
|
xmpp_stanza_release(text);
|
||||||
|
xmpp_stanza_release(elem);
|
||||||
|
}
|
||||||
|
free(s);
|
||||||
|
}
|
||||||
|
next = xmpp_stanza_get_next(next);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xmpp_stanza_get_children(query) == NULL) {
|
||||||
|
fprintf(stderr, "DEBUG: nothing to send\n");
|
||||||
|
xmpp_disconnect(conn);
|
||||||
|
} else {
|
||||||
|
iq = xmpp_iq_new(ctx, "set", "reg2");
|
||||||
|
xmpp_stanza_add_child(iq, query);
|
||||||
|
xmpp_stanza_release(query);
|
||||||
|
xmpp_send(conn, iq);
|
||||||
|
xmpp_stanza_release(iq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int iq_reg2_cb(xmpp_conn_t * const conn,
|
||||||
|
xmpp_stanza_t * const stanza,
|
||||||
|
void * const userdata)
|
||||||
|
{
|
||||||
|
const char *type;
|
||||||
|
|
||||||
|
type = xmpp_stanza_get_type(stanza);
|
||||||
|
if (!type || strcmp(type, "error") == 0) {
|
||||||
|
fprintf(stderr, "DEBUG: error during registration\n");
|
||||||
|
goto quit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(type, "result") != 0) {
|
||||||
|
fprintf(stderr, "DEBUG: expected type 'result', but got %s\n", type);
|
||||||
|
goto quit;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "DEBUG: successful registration\n");
|
||||||
|
|
||||||
|
quit:
|
||||||
|
xmpp_disconnect(conn);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int iq_reg_cb(xmpp_conn_t * const conn,
|
||||||
|
xmpp_stanza_t * const stanza,
|
||||||
|
void * const userdata)
|
||||||
|
{
|
||||||
|
xmpp_reg_t *reg = (xmpp_reg_t *)userdata;
|
||||||
|
xmpp_stanza_t *registered = NULL;
|
||||||
|
xmpp_stanza_t *query;
|
||||||
|
const char *type;
|
||||||
|
|
||||||
|
type = xmpp_stanza_get_type(stanza);
|
||||||
|
if (!type || strcmp(type, "error") == 0) {
|
||||||
|
fprintf(stderr, "DEBUG: error during registration\n");
|
||||||
|
xmpp_disconnect(conn);
|
||||||
|
goto quit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(type, "result") != 0) {
|
||||||
|
fprintf(stderr, "DEBUG: expected type 'result', but got %s\n", type);
|
||||||
|
xmpp_disconnect(conn);
|
||||||
|
goto quit;
|
||||||
|
}
|
||||||
|
|
||||||
|
query = xmpp_stanza_get_child_by_name(stanza, "query");
|
||||||
|
if (query)
|
||||||
|
registered = xmpp_stanza_get_child_by_name(query, "registered");
|
||||||
|
if (registered != NULL) {
|
||||||
|
fprintf(stderr, "DEBUG: already registered\n");
|
||||||
|
xmpp_disconnect(conn);
|
||||||
|
goto quit;
|
||||||
|
}
|
||||||
|
xmpp_id_handler_add(conn, iq_reg2_cb, "reg2", reg);
|
||||||
|
iq_reg_send_form(reg, conn, stanza);
|
||||||
|
|
||||||
|
quit:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _handle_error(xmpp_conn_t * const conn,
|
||||||
|
xmpp_stanza_t * const stanza,
|
||||||
|
void * const userdata)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "DEBUG: received stream error\n");
|
||||||
|
xmpp_disconnect(conn);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _handle_proceedtls_default(xmpp_conn_t * const conn,
|
||||||
|
xmpp_stanza_t * const stanza,
|
||||||
|
void * const userdata)
|
||||||
|
{
|
||||||
|
const char *name = xmpp_stanza_get_name(stanza);
|
||||||
|
|
||||||
|
if (strcmp(name, "proceed") == 0) {
|
||||||
|
fprintf(stderr, "DEBUG: proceeding with TLS\n");
|
||||||
|
if (xmpp_conn_tls_start(conn) == 0) {
|
||||||
|
xmpp_handler_delete(conn, _handle_error);
|
||||||
|
xmpp_conn_open_stream_default(conn);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "DEBUG: TLS failed\n");
|
||||||
|
/* failed tls spoils the connection, so disconnect */
|
||||||
|
xmpp_disconnect(conn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _handle_missing_features(xmpp_conn_t * const conn,
|
||||||
|
void * const userdata)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "DEBUG: timeout\n");
|
||||||
|
xmpp_disconnect(conn);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _handle_features(xmpp_conn_t * const conn,
|
||||||
|
xmpp_stanza_t * const stanza,
|
||||||
|
void * const userdata)
|
||||||
|
{
|
||||||
|
xmpp_reg_t *reg = (xmpp_reg_t *)userdata;
|
||||||
|
xmpp_ctx_t *ctx = reg->ctx;
|
||||||
|
xmpp_stanza_t *child;
|
||||||
|
xmpp_stanza_t *iq;
|
||||||
|
char *domain;
|
||||||
|
|
||||||
|
xmpp_timed_handler_delete(conn, _handle_missing_features);
|
||||||
|
|
||||||
|
/* secure connection if possible */
|
||||||
|
child = xmpp_stanza_get_child_by_name(stanza, "starttls");
|
||||||
|
if (child && (strcmp(xmpp_stanza_get_ns(child), XMPP_NS_TLS) == 0)) {
|
||||||
|
fprintf(stderr, "DEBUG: server supports TLS, try to establish\n");
|
||||||
|
child = xmpp_stanza_new(ctx);
|
||||||
|
xmpp_stanza_set_name(child, "starttls");
|
||||||
|
xmpp_stanza_set_ns(child, XMPP_NS_TLS);
|
||||||
|
xmpp_handler_add(conn, _handle_proceedtls_default,
|
||||||
|
XMPP_NS_TLS, NULL, NULL, NULL);
|
||||||
|
xmpp_send(conn, child);
|
||||||
|
xmpp_stanza_release(child);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check whether server supports in-band registration */
|
||||||
|
child = xmpp_stanza_get_child_by_name(stanza, "register");
|
||||||
|
if (child && strcmp(xmpp_stanza_get_ns(child), XMPP_NS_REGISTER) == 0) {
|
||||||
|
fprintf(stderr, "DEBUG: server doesn't support in-band registration\n");
|
||||||
|
xmpp_disconnect(conn);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "DEBUG: server supports in-band registration\n");
|
||||||
|
domain = xmpp_jid_domain(ctx, reg->jid);
|
||||||
|
iq = xmpp_iq_new(ctx, "get", "reg1");
|
||||||
|
xmpp_stanza_set_to(iq, domain);
|
||||||
|
child = xmpp_stanza_new(ctx);
|
||||||
|
xmpp_stanza_set_name(child, "query");
|
||||||
|
xmpp_stanza_set_ns(child, XMPP_NS_REGISTER);
|
||||||
|
xmpp_stanza_add_child(iq, child);
|
||||||
|
|
||||||
|
xmpp_handler_add(conn, iq_reg_cb, XMPP_NS_REGISTER, "iq", NULL, reg);
|
||||||
|
xmpp_send(conn, iq);
|
||||||
|
|
||||||
|
xmpp_free(ctx, domain);
|
||||||
|
xmpp_stanza_release(child);
|
||||||
|
xmpp_stanza_release(iq);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void conn_handler(xmpp_conn_t * const conn,
|
||||||
|
const xmpp_conn_event_t status,
|
||||||
|
const int error,
|
||||||
|
xmpp_stream_error_t * const stream_error,
|
||||||
|
void * const userdata)
|
||||||
|
{
|
||||||
|
xmpp_reg_t *reg = (xmpp_reg_t *)userdata;
|
||||||
|
int secured;
|
||||||
|
|
||||||
|
if (status == XMPP_CONN_RAW_CONNECT) {
|
||||||
|
fprintf(stderr, "DEBUG: raw connection established\n");
|
||||||
|
xmpp_conn_open_stream_default(conn);
|
||||||
|
} else if (status == XMPP_CONN_CONNECT) {
|
||||||
|
fprintf(stderr, "DEBUG: stream opened\n");
|
||||||
|
secured = xmpp_conn_is_secured(conn);
|
||||||
|
fprintf(stderr, "DEBUG: connection is %s.\n",
|
||||||
|
secured ? "secured" : "NOT secured");
|
||||||
|
|
||||||
|
/* setup handler for stream:error */
|
||||||
|
xmpp_handler_add(conn, _handle_error, XMPP_NS_STREAMS,
|
||||||
|
"error", NULL, NULL);
|
||||||
|
|
||||||
|
/* setup handlers for incoming <stream:features> */
|
||||||
|
xmpp_handler_add(conn, _handle_features, XMPP_NS_STREAMS,
|
||||||
|
"features", NULL, reg);
|
||||||
|
xmpp_timed_handler_add(conn, _handle_missing_features,
|
||||||
|
FEATURES_TIMEOUT, NULL);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "DEBUG: disconnected\n");
|
||||||
|
xmpp_stop(reg->ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
xmpp_reg_t *xmpp_reg_new(void)
|
||||||
|
{
|
||||||
|
xmpp_reg_t *reg;
|
||||||
|
|
||||||
|
reg = malloc(sizeof(*reg));
|
||||||
|
if (reg != NULL) {
|
||||||
|
memset(reg, 0, sizeof(*reg));
|
||||||
|
}
|
||||||
|
return reg;
|
||||||
|
}
|
||||||
|
|
||||||
|
void xmpp_reg_release(xmpp_reg_t *reg)
|
||||||
|
{
|
||||||
|
free(reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
xmpp_ctx_t *ctx;
|
||||||
|
xmpp_conn_t *conn;
|
||||||
|
xmpp_log_t *log;
|
||||||
|
xmpp_reg_t *reg;
|
||||||
|
const char *jid;
|
||||||
|
const char *host = NULL;
|
||||||
|
char *domain;
|
||||||
|
|
||||||
|
if (argc < 2 || argc > 3) {
|
||||||
|
fprintf(stderr, "Usage: %s <jid> [<host>]\n", argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
jid = argv[1];
|
||||||
|
if (argc > 2)
|
||||||
|
host = argv[2];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note, this example doesn't handle errors. Applications should check
|
||||||
|
* return values of non-void functions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
xmpp_initialize();
|
||||||
|
log = xmpp_get_default_logger(XMPP_LEVEL_DEBUG);
|
||||||
|
ctx = xmpp_ctx_new(NULL, log);
|
||||||
|
conn = xmpp_conn_new(ctx);
|
||||||
|
|
||||||
|
/* jid can be a jid or domain for "raw" connection */
|
||||||
|
domain = xmpp_jid_domain(ctx, jid);
|
||||||
|
xmpp_conn_set_jid(conn, domain);
|
||||||
|
xmpp_free(ctx, domain);
|
||||||
|
|
||||||
|
/* private data */
|
||||||
|
reg = xmpp_reg_new();
|
||||||
|
reg->ctx = ctx;
|
||||||
|
reg->jid = jid;
|
||||||
|
|
||||||
|
xmpp_connect_raw(conn, host, 0, conn_handler, reg);
|
||||||
|
xmpp_run(ctx);
|
||||||
|
|
||||||
|
/* release private data */
|
||||||
|
xmpp_reg_release(reg);
|
||||||
|
|
||||||
|
xmpp_conn_release(conn);
|
||||||
|
xmpp_ctx_free(ctx);
|
||||||
|
xmpp_shutdown();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -62,10 +62,7 @@ void conn_handler(xmpp_conn_t * const conn, const xmpp_conn_event_t status,
|
|||||||
fprintf(stderr, "DEBUG: connected\n");
|
fprintf(stderr, "DEBUG: connected\n");
|
||||||
|
|
||||||
/* create iq stanza for request */
|
/* create iq stanza for request */
|
||||||
iq = xmpp_stanza_new(ctx);
|
iq = xmpp_iq_new(ctx, "get", "roster1");
|
||||||
xmpp_stanza_set_name(iq, "iq");
|
|
||||||
xmpp_stanza_set_type(iq, "get");
|
|
||||||
xmpp_stanza_set_id(iq, "roster1");
|
|
||||||
|
|
||||||
query = xmpp_stanza_new(ctx);
|
query = xmpp_stanza_new(ctx);
|
||||||
xmpp_stanza_set_name(query, "query");
|
xmpp_stanza_set_name(query, "query");
|
||||||
|
|||||||
284
examples/vcard.c
Normal file
284
examples/vcard.c
Normal file
@@ -0,0 +1,284 @@
|
|||||||
|
/* vcard.c
|
||||||
|
* strophe XMPP client library -- vCard example
|
||||||
|
*
|
||||||
|
* Copyright (C) 2016 Dmitry Podgorny <pasis.ua@gmail.com>
|
||||||
|
*
|
||||||
|
* This software is provided AS-IS with no warranty, either express
|
||||||
|
* or implied.
|
||||||
|
*
|
||||||
|
* This program is dual licensed under the MIT and GPLv3 licenses.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <libgen.h> /* basename */
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <strophe.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
xmpp_ctx_t *ctx;
|
||||||
|
const char *recipient;
|
||||||
|
const char *img_path;
|
||||||
|
} vcard_t;
|
||||||
|
|
||||||
|
typedef void (*vcard_cb_t)(vcard_t *, xmpp_stanza_t *);
|
||||||
|
|
||||||
|
#define REQ_TIMEOUT 5000
|
||||||
|
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
|
||||||
|
|
||||||
|
static void vcard_photo(vcard_t *vc, xmpp_stanza_t *stanza)
|
||||||
|
{
|
||||||
|
xmpp_stanza_t *tmp;
|
||||||
|
char *s;
|
||||||
|
char *tok;
|
||||||
|
char *saveptr = NULL;
|
||||||
|
char *copy;
|
||||||
|
unsigned char *img;
|
||||||
|
size_t img_size;
|
||||||
|
size_t written;
|
||||||
|
FILE *fd;
|
||||||
|
|
||||||
|
tmp = xmpp_stanza_get_child_by_name(stanza, "TYPE");
|
||||||
|
assert(tmp != NULL);
|
||||||
|
s = xmpp_stanza_get_text(tmp);
|
||||||
|
assert(s != NULL);
|
||||||
|
printf("PHOTO: %s, saving to file %s\n", s, vc->img_path);
|
||||||
|
xmpp_free(vc->ctx, s);
|
||||||
|
|
||||||
|
tmp = xmpp_stanza_get_child_by_name(stanza, "BINVAL");
|
||||||
|
assert(tmp != NULL);
|
||||||
|
s = xmpp_stanza_get_text(tmp);
|
||||||
|
assert(s != NULL);
|
||||||
|
|
||||||
|
/* remove \n and \r */
|
||||||
|
copy = (char *)malloc(strlen(s) + 1);
|
||||||
|
assert(copy != NULL);
|
||||||
|
copy[0] = '\0';
|
||||||
|
tok = strtok_r(s, "\n\r", &saveptr);
|
||||||
|
while (tok != NULL) {
|
||||||
|
strcat(copy, tok);
|
||||||
|
tok = strtok_r(NULL, "\n\r", &saveptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
xmpp_base64_decode_bin(vc->ctx, copy, strlen(copy), &img, &img_size);
|
||||||
|
assert(img != NULL);
|
||||||
|
|
||||||
|
fd = fopen(vc->img_path, "w");
|
||||||
|
assert(fd != NULL);
|
||||||
|
written = fwrite(img, 1, img_size, fd);
|
||||||
|
if (written < img_size)
|
||||||
|
printf("Saving photo failed\n");
|
||||||
|
fclose(fd);
|
||||||
|
|
||||||
|
free(copy);
|
||||||
|
xmpp_free(vc->ctx, s);
|
||||||
|
xmpp_free(vc->ctx, img);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void vcard_print_string(vcard_t *vc, xmpp_stanza_t *stanza,
|
||||||
|
const char *info)
|
||||||
|
{
|
||||||
|
char *s = xmpp_stanza_get_text(stanza);
|
||||||
|
|
||||||
|
assert(s != NULL);
|
||||||
|
printf("%s: %s\n", info, s);
|
||||||
|
xmpp_free(vc->ctx, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void vcard_bday(vcard_t *vc, xmpp_stanza_t *stanza)
|
||||||
|
{
|
||||||
|
vcard_print_string(vc, stanza, "Birthday");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void vcard_desc(vcard_t *vc, xmpp_stanza_t *stanza)
|
||||||
|
{
|
||||||
|
vcard_print_string(vc, stanza, "Description");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void vcard_email(vcard_t *vc, xmpp_stanza_t *stanza)
|
||||||
|
{
|
||||||
|
xmpp_stanza_t *userid = xmpp_stanza_get_child_by_name(stanza, "USERID");
|
||||||
|
|
||||||
|
if (userid != NULL)
|
||||||
|
vcard_print_string(vc, userid, "E-mail");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void vcard_fn(vcard_t *vc, xmpp_stanza_t *stanza)
|
||||||
|
{
|
||||||
|
vcard_print_string(vc, stanza, "Full name");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void vcard_name(vcard_t *vc, xmpp_stanza_t *stanza)
|
||||||
|
{
|
||||||
|
xmpp_stanza_t *name = xmpp_stanza_get_child_by_name(stanza, "GIVEN");
|
||||||
|
xmpp_stanza_t *family = xmpp_stanza_get_child_by_name(stanza, "FAMILY");
|
||||||
|
|
||||||
|
if (name != NULL)
|
||||||
|
vcard_print_string(vc, name, "Given name");
|
||||||
|
if (family != NULL)
|
||||||
|
vcard_print_string(vc, family, "Family name");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void vcard_nick(vcard_t *vc, xmpp_stanza_t *stanza)
|
||||||
|
{
|
||||||
|
vcard_print_string(vc, stanza, "Nickname");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void vcard_url(vcard_t *vc, xmpp_stanza_t *stanza)
|
||||||
|
{
|
||||||
|
vcard_print_string(vc, stanza, "URL");
|
||||||
|
}
|
||||||
|
|
||||||
|
static vcard_cb_t vcard_cb_get(xmpp_stanza_t *stanza)
|
||||||
|
{
|
||||||
|
vcard_cb_t cb = NULL;
|
||||||
|
const char *tag;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
const char *tag;
|
||||||
|
vcard_cb_t cb;
|
||||||
|
} vcard_tbl[] = {
|
||||||
|
{ "PHOTO", vcard_photo },
|
||||||
|
{ "BDAY", vcard_bday },
|
||||||
|
{ "DESC", vcard_desc },
|
||||||
|
{ "EMAIL", vcard_email },
|
||||||
|
{ "FN", vcard_fn },
|
||||||
|
{ "N", vcard_name },
|
||||||
|
{ "NICKNAME", vcard_nick },
|
||||||
|
{ "URL", vcard_url },
|
||||||
|
};
|
||||||
|
|
||||||
|
tag = xmpp_stanza_get_name(stanza);
|
||||||
|
if (tag == NULL)
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(vcard_tbl); ++i) {
|
||||||
|
if (strcmp(tag, vcard_tbl[i].tag) == 0) {
|
||||||
|
cb = vcard_tbl[i].cb;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exit:
|
||||||
|
return cb;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int timedout(xmpp_conn_t * const conn, void * const userdata)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Timeout reached.\n");
|
||||||
|
xmpp_disconnect(conn);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int recv_vcard(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza,
|
||||||
|
void * const userdata)
|
||||||
|
{
|
||||||
|
vcard_t *vc = userdata;
|
||||||
|
vcard_cb_t cb;
|
||||||
|
xmpp_stanza_t *child;
|
||||||
|
char *s;
|
||||||
|
size_t s_size;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
printf("Received vCard.\n\n");
|
||||||
|
|
||||||
|
child = xmpp_stanza_get_child_by_name(stanza, "error");
|
||||||
|
if (child != NULL) {
|
||||||
|
rc = xmpp_stanza_to_text(child, &s, &s_size);
|
||||||
|
assert(rc == XMPP_EOK);
|
||||||
|
printf("Error returned: %s.\n", s);
|
||||||
|
xmpp_free(vc->ctx, s);
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
child = xmpp_stanza_get_child_by_name(stanza, "vCard");
|
||||||
|
assert(child != NULL);
|
||||||
|
child = xmpp_stanza_get_children(child);
|
||||||
|
while (child != NULL) {
|
||||||
|
cb = vcard_cb_get(child);
|
||||||
|
if (cb != NULL)
|
||||||
|
cb(vc, child);
|
||||||
|
child = xmpp_stanza_get_next(child);
|
||||||
|
}
|
||||||
|
|
||||||
|
exit:
|
||||||
|
xmpp_disconnect(conn);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void send_vcard_req(xmpp_conn_t *conn, const char *to, const char *id)
|
||||||
|
{
|
||||||
|
printf("Requesting vCard from %s.\n", to);
|
||||||
|
xmpp_send_raw_string(conn, "<iq from='%s' to='%s' type='get' id='%s'>"
|
||||||
|
"<vCard xmlns='vcard-temp'/></iq>",
|
||||||
|
xmpp_conn_get_bound_jid(conn), to, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void conn_handler(xmpp_conn_t * const conn,
|
||||||
|
const xmpp_conn_event_t status,
|
||||||
|
const int error,
|
||||||
|
xmpp_stream_error_t * const stream_error,
|
||||||
|
void * const userdata)
|
||||||
|
{
|
||||||
|
vcard_t *vc = userdata;
|
||||||
|
|
||||||
|
if (status == XMPP_CONN_CONNECT) {
|
||||||
|
send_vcard_req(conn, vc->recipient, "vc1");
|
||||||
|
xmpp_id_handler_add(conn, recv_vcard, "vc1", vc);
|
||||||
|
xmpp_timed_handler_add(conn, timedout, REQ_TIMEOUT, NULL);
|
||||||
|
} else {
|
||||||
|
if (error != 0)
|
||||||
|
fprintf(stderr, "Disconnected with error=%d.\n", error);
|
||||||
|
if (stream_error != NULL)
|
||||||
|
fprintf(stderr, "Stream error type=%d text=%s.\n",
|
||||||
|
stream_error->type, stream_error->text);
|
||||||
|
xmpp_stop(vc->ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
xmpp_log_t *log;
|
||||||
|
xmpp_ctx_t *ctx;
|
||||||
|
xmpp_conn_t *conn;
|
||||||
|
const char *jid;
|
||||||
|
const char *pass;
|
||||||
|
char *prog;
|
||||||
|
vcard_t vcard;
|
||||||
|
|
||||||
|
if (argc < 4 || argc > 5) {
|
||||||
|
prog = argc > 0 ? strdup(argv[0]) : NULL;
|
||||||
|
printf("Usage: %s <login-jid> <password> <recipient-jid> "
|
||||||
|
"[image-file]\n\n", prog == NULL ? "vcard" : basename(prog));
|
||||||
|
printf("If vCard contains a photo it will be stored to "
|
||||||
|
"image-file. If you don't provide the image-file "
|
||||||
|
"default filename will be generated.\n");
|
||||||
|
free(prog);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
jid = argv[1];
|
||||||
|
pass = argv[2];
|
||||||
|
vcard.recipient = argv[3];
|
||||||
|
vcard.img_path = argc > 4 ? argv[4] : "vcard.jpg";
|
||||||
|
|
||||||
|
xmpp_initialize();
|
||||||
|
log = xmpp_get_default_logger(XMPP_LEVEL_INFO);
|
||||||
|
ctx = xmpp_ctx_new(NULL, log);
|
||||||
|
conn = xmpp_conn_new(ctx);
|
||||||
|
xmpp_conn_set_jid(conn, jid);
|
||||||
|
xmpp_conn_set_pass(conn, pass);
|
||||||
|
vcard.ctx = ctx;
|
||||||
|
xmpp_connect_client(conn, NULL, 0, conn_handler, &vcard);
|
||||||
|
xmpp_run(ctx);
|
||||||
|
xmpp_conn_release(conn);
|
||||||
|
xmpp_ctx_free(ctx);
|
||||||
|
xmpp_shutdown();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -62,7 +62,7 @@ include $(BUILD_STATIC_LIBRARY)
|
|||||||
|
|
||||||
include $(CLEAR_VARS)
|
include $(CLEAR_VARS)
|
||||||
LOCAL_MODULE := libexpat
|
LOCAL_MODULE := libexpat
|
||||||
LOCAL_CFLAGS := -DHAVE_MEMMOVE
|
LOCAL_CFLAGS := -DHAVE_MEMMOVE -DXML_DEV_URANDOM
|
||||||
#LOCAL_C_INCLUDES := \
|
#LOCAL_C_INCLUDES := \
|
||||||
# $(LOCAL_PATH)/expat
|
# $(LOCAL_PATH)/expat
|
||||||
|
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
APP_ABI := armeabi armeabi-v7a mips x86
|
APP_ABI := armeabi-v7a arm64-v8a
|
||||||
APP_PLATFORM := android-19
|
APP_PLATFORM := android-19
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
1. Setup
|
1. Setup
|
||||||
|
|
||||||
yum install gcc make expat-devel libstrophe
|
yum install gcc make autoconf automake expat-devel openssl-devel
|
||||||
|
|
||||||
Fedora:
|
Fedora:
|
||||||
|
|
||||||
|
|||||||
@@ -8,10 +8,12 @@ License: MIT/GPLv3
|
|||||||
URL: http://strophe.im/libstrophe/
|
URL: http://strophe.im/libstrophe/
|
||||||
Source0: libstrophe_git.tar.gz
|
Source0: libstrophe_git.tar.gz
|
||||||
|
|
||||||
|
BuildRequires: autoconf
|
||||||
BuildRequires: automake
|
BuildRequires: automake
|
||||||
BuildRequires: libtool
|
BuildRequires: libtool
|
||||||
BuildRequires: openssl-devel
|
BuildRequires: openssl-devel
|
||||||
BuildRequires: expat-devel
|
BuildRequires: expat-devel
|
||||||
|
Requires: openssl
|
||||||
Requires: expat
|
Requires: expat
|
||||||
|
|
||||||
%description
|
%description
|
||||||
|
|||||||
345
src/auth.c
345
src/auth.c
@@ -24,7 +24,7 @@
|
|||||||
#include "rand.h"
|
#include "rand.h"
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#define strcasecmp stricmp
|
#define strcasecmp _stricmp
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* TODO: these should configurable at runtime on a per connection basis */
|
/* TODO: these should configurable at runtime on a per connection basis */
|
||||||
@@ -61,18 +61,15 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void _auth(xmpp_conn_t * const conn);
|
static void _auth(xmpp_conn_t * const conn);
|
||||||
|
static void _auth_legacy(xmpp_conn_t *conn);
|
||||||
static void _handle_open_sasl(xmpp_conn_t * const conn);
|
static void _handle_open_sasl(xmpp_conn_t * const conn);
|
||||||
|
static void _handle_open_tls(xmpp_conn_t * const conn);
|
||||||
|
|
||||||
static int _handle_component_auth(xmpp_conn_t * const conn);
|
static int _handle_component_auth(xmpp_conn_t * const conn);
|
||||||
static int _handle_component_hs_response(xmpp_conn_t * const conn,
|
static int _handle_component_hs_response(xmpp_conn_t * const conn,
|
||||||
xmpp_stanza_t * const stanza,
|
xmpp_stanza_t * const stanza,
|
||||||
void * const userdata);
|
void * const userdata);
|
||||||
|
|
||||||
static int _handle_missing_legacy(xmpp_conn_t * const conn,
|
|
||||||
void * const userdata);
|
|
||||||
static int _handle_legacy(xmpp_conn_t * const conn,
|
|
||||||
xmpp_stanza_t * const stanza,
|
|
||||||
void * const userdata);
|
|
||||||
static int _handle_features_sasl(xmpp_conn_t * const conn,
|
static int _handle_features_sasl(xmpp_conn_t * const conn,
|
||||||
xmpp_stanza_t * const stanza,
|
xmpp_stanza_t * const stanza,
|
||||||
void * const userdata);
|
void * const userdata);
|
||||||
@@ -102,6 +99,9 @@ static int _handle_session(xmpp_conn_t * const conn,
|
|||||||
void * const userdata);
|
void * const userdata);
|
||||||
static int _handle_missing_session(xmpp_conn_t * const conn,
|
static int _handle_missing_session(xmpp_conn_t * const conn,
|
||||||
void * const userdata);
|
void * const userdata);
|
||||||
|
static int _handle_sm(xmpp_conn_t * const conn,
|
||||||
|
xmpp_stanza_t * const stanza,
|
||||||
|
void * const userdata);
|
||||||
static int _handle_missing_handshake(xmpp_conn_t * const conn,
|
static int _handle_missing_handshake(xmpp_conn_t * const conn,
|
||||||
void * const userdata);
|
void * const userdata);
|
||||||
|
|
||||||
@@ -218,6 +218,7 @@ static int _handle_features(xmpp_conn_t * const conn,
|
|||||||
void * const userdata)
|
void * const userdata)
|
||||||
{
|
{
|
||||||
xmpp_stanza_t *child, *mech;
|
xmpp_stanza_t *child, *mech;
|
||||||
|
const char *ns;
|
||||||
char *text;
|
char *text;
|
||||||
|
|
||||||
/* remove the handler that detects missing stream:features */
|
/* remove the handler that detects missing stream:features */
|
||||||
@@ -227,8 +228,10 @@ static int _handle_features(xmpp_conn_t * const conn,
|
|||||||
if (!conn->secured) {
|
if (!conn->secured) {
|
||||||
if (!conn->tls_disabled) {
|
if (!conn->tls_disabled) {
|
||||||
child = xmpp_stanza_get_child_by_name(stanza, "starttls");
|
child = xmpp_stanza_get_child_by_name(stanza, "starttls");
|
||||||
if (child && (strcmp(xmpp_stanza_get_ns(child), XMPP_NS_TLS) == 0))
|
if (child) {
|
||||||
conn->tls_support = 1;
|
ns = xmpp_stanza_get_ns(child);
|
||||||
|
conn->tls_support = ns != NULL && strcmp(ns, XMPP_NS_TLS) == 0;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
conn->tls_support = 0;
|
conn->tls_support = 0;
|
||||||
}
|
}
|
||||||
@@ -236,11 +239,15 @@ static int _handle_features(xmpp_conn_t * const conn,
|
|||||||
|
|
||||||
/* check for SASL */
|
/* check for SASL */
|
||||||
child = xmpp_stanza_get_child_by_name(stanza, "mechanisms");
|
child = xmpp_stanza_get_child_by_name(stanza, "mechanisms");
|
||||||
if (child && (strcmp(xmpp_stanza_get_ns(child), XMPP_NS_SASL) == 0)) {
|
ns = child ? xmpp_stanza_get_ns(child) : NULL;
|
||||||
|
if (child && ns && strcmp(ns, XMPP_NS_SASL) == 0) {
|
||||||
for (mech = xmpp_stanza_get_children(child); mech;
|
for (mech = xmpp_stanza_get_children(child); mech;
|
||||||
mech = xmpp_stanza_get_next(mech)) {
|
mech = xmpp_stanza_get_next(mech)) {
|
||||||
if (xmpp_stanza_get_name(mech) && strcmp(xmpp_stanza_get_name(mech), "mechanism") == 0) {
|
if (xmpp_stanza_get_name(mech) && strcmp(xmpp_stanza_get_name(mech), "mechanism") == 0) {
|
||||||
text = xmpp_stanza_get_text(mech);
|
text = xmpp_stanza_get_text(mech);
|
||||||
|
if (text == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
if (strcasecmp(text, "PLAIN") == 0)
|
if (strcasecmp(text, "PLAIN") == 0)
|
||||||
conn->sasl_support |= SASL_MASK_PLAIN;
|
conn->sasl_support |= SASL_MASK_PLAIN;
|
||||||
else if (strcasecmp(text, "DIGEST-MD5") == 0)
|
else if (strcasecmp(text, "DIGEST-MD5") == 0)
|
||||||
@@ -255,6 +262,10 @@ static int _handle_features(xmpp_conn_t * const conn,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Disable PLAIN when other secure mechanisms are supported */
|
||||||
|
if (conn->sasl_support & ~(SASL_MASK_PLAIN | SASL_MASK_ANONYMOUS))
|
||||||
|
conn->sasl_support &= ~SASL_MASK_PLAIN;
|
||||||
|
|
||||||
_auth(conn);
|
_auth(conn);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -288,7 +299,7 @@ static int _handle_proceedtls_default(xmpp_conn_t * const conn,
|
|||||||
xmpp_debug(conn->ctx, "xmpp", "proceeding with TLS");
|
xmpp_debug(conn->ctx, "xmpp", "proceeding with TLS");
|
||||||
|
|
||||||
if (conn_tls_start(conn) == 0) {
|
if (conn_tls_start(conn) == 0) {
|
||||||
conn_prepare_reset(conn, auth_handle_open);
|
conn_prepare_reset(conn, _handle_open_tls);
|
||||||
conn_open_stream(conn);
|
conn_open_stream(conn);
|
||||||
} else {
|
} else {
|
||||||
/* failed tls spoils the connection, so disconnect */
|
/* failed tls spoils the connection, so disconnect */
|
||||||
@@ -315,7 +326,7 @@ static int _handle_sasl_result(xmpp_conn_t * const conn,
|
|||||||
/* fall back to next auth method */
|
/* fall back to next auth method */
|
||||||
_auth(conn);
|
_auth(conn);
|
||||||
} else if (strcmp(name, "success") == 0) {
|
} else if (strcmp(name, "success") == 0) {
|
||||||
/* SASL PLAIN auth successful, we need to restart the stream */
|
/* SASL auth successful, we need to restart the stream */
|
||||||
xmpp_debug(conn->ctx, "xmpp", "SASL %s auth successful",
|
xmpp_debug(conn->ctx, "xmpp", "SASL %s auth successful",
|
||||||
(char *)userdata);
|
(char *)userdata);
|
||||||
|
|
||||||
@@ -549,9 +560,11 @@ static xmpp_stanza_t *_make_sasl_auth(xmpp_conn_t * const conn,
|
|||||||
*/
|
*/
|
||||||
static void _auth(xmpp_conn_t * const conn)
|
static void _auth(xmpp_conn_t * const conn)
|
||||||
{
|
{
|
||||||
xmpp_stanza_t *auth, *authdata, *query, *child, *iq;
|
xmpp_stanza_t *auth;
|
||||||
char *str, *authid;
|
xmpp_stanza_t *authdata;
|
||||||
|
char *authid;
|
||||||
char *scram_init;
|
char *scram_init;
|
||||||
|
char *str;
|
||||||
int anonjid;
|
int anonjid;
|
||||||
|
|
||||||
/* if there is no node in conn->jid, we assume anonymous connect */
|
/* if there is no node in conn->jid, we assume anonymous connect */
|
||||||
@@ -564,7 +577,7 @@ static void _auth(xmpp_conn_t * const conn)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (conn->tls_support) {
|
if (conn->tls_support) {
|
||||||
tls_t *tls = tls_new(conn->ctx, conn->sock);
|
tls_t *tls = tls_new(conn);
|
||||||
|
|
||||||
/* If we couldn't init tls, it isn't there, so go on */
|
/* If we couldn't init tls, it isn't there, so go on */
|
||||||
if (!tls) {
|
if (!tls) {
|
||||||
@@ -718,108 +731,12 @@ static void _auth(xmpp_conn_t * const conn)
|
|||||||
|
|
||||||
/* SASL PLAIN was tried */
|
/* SASL PLAIN was tried */
|
||||||
conn->sasl_support &= ~SASL_MASK_PLAIN;
|
conn->sasl_support &= ~SASL_MASK_PLAIN;
|
||||||
} else if (conn->type == XMPP_CLIENT) {
|
} else if (conn->type == XMPP_CLIENT && conn->auth_legacy_enabled) {
|
||||||
/* legacy client authentication */
|
/* legacy client authentication */
|
||||||
|
_auth_legacy(conn);
|
||||||
iq = xmpp_stanza_new(conn->ctx);
|
|
||||||
if (!iq) {
|
|
||||||
disconnect_mem_error(conn);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
xmpp_stanza_set_name(iq, "iq");
|
|
||||||
xmpp_stanza_set_type(iq, "set");
|
|
||||||
xmpp_stanza_set_id(iq, "_xmpp_auth1");
|
|
||||||
|
|
||||||
query = xmpp_stanza_new(conn->ctx);
|
|
||||||
if (!query) {
|
|
||||||
xmpp_stanza_release(iq);
|
|
||||||
disconnect_mem_error(conn);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
xmpp_stanza_set_name(query, "query");
|
|
||||||
xmpp_stanza_set_ns(query, XMPP_NS_AUTH);
|
|
||||||
xmpp_stanza_add_child(iq, query);
|
|
||||||
xmpp_stanza_release(query);
|
|
||||||
|
|
||||||
child = xmpp_stanza_new(conn->ctx);
|
|
||||||
if (!child) {
|
|
||||||
xmpp_stanza_release(iq);
|
|
||||||
disconnect_mem_error(conn);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
xmpp_stanza_set_name(child, "username");
|
|
||||||
xmpp_stanza_add_child(query, child);
|
|
||||||
xmpp_stanza_release(child);
|
|
||||||
|
|
||||||
authdata = xmpp_stanza_new(conn->ctx);
|
|
||||||
if (!authdata) {
|
|
||||||
xmpp_stanza_release(iq);
|
|
||||||
disconnect_mem_error(conn);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
str = xmpp_jid_node(conn->ctx, conn->jid);
|
|
||||||
xmpp_stanza_set_text(authdata, str);
|
|
||||||
xmpp_free(conn->ctx, str);
|
|
||||||
xmpp_stanza_add_child(child, authdata);
|
|
||||||
xmpp_stanza_release(authdata);
|
|
||||||
|
|
||||||
child = xmpp_stanza_new(conn->ctx);
|
|
||||||
if (!child) {
|
|
||||||
xmpp_stanza_release(iq);
|
|
||||||
disconnect_mem_error(conn);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
xmpp_stanza_set_name(child, "password");
|
|
||||||
xmpp_stanza_add_child(query, child);
|
|
||||||
xmpp_stanza_release(child);
|
|
||||||
|
|
||||||
authdata = xmpp_stanza_new(conn->ctx);
|
|
||||||
if (!authdata) {
|
|
||||||
xmpp_stanza_release(iq);
|
|
||||||
disconnect_mem_error(conn);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
xmpp_stanza_set_text(authdata, conn->pass);
|
|
||||||
xmpp_stanza_add_child(child, authdata);
|
|
||||||
xmpp_stanza_release(authdata);
|
|
||||||
|
|
||||||
child = xmpp_stanza_new(conn->ctx);
|
|
||||||
if (!child) {
|
|
||||||
xmpp_stanza_release(iq);
|
|
||||||
disconnect_mem_error(conn);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
xmpp_stanza_set_name(child, "resource");
|
|
||||||
xmpp_stanza_add_child(query, child);
|
|
||||||
xmpp_stanza_release(child);
|
|
||||||
|
|
||||||
authdata = xmpp_stanza_new(conn->ctx);
|
|
||||||
if (!authdata) {
|
|
||||||
xmpp_stanza_release(iq);
|
|
||||||
disconnect_mem_error(conn);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
str = xmpp_jid_resource(conn->ctx, conn->jid);
|
|
||||||
if (str) {
|
|
||||||
xmpp_stanza_set_text(authdata, str);
|
|
||||||
xmpp_free(conn->ctx, str);
|
|
||||||
} else {
|
} else {
|
||||||
xmpp_stanza_release(authdata);
|
xmpp_error(conn->ctx, "auth", "Cannot authenticate with known methods");
|
||||||
xmpp_stanza_release(iq);
|
|
||||||
xmpp_error(conn->ctx, "auth",
|
|
||||||
"Cannot authenticate without resource");
|
|
||||||
xmpp_disconnect(conn);
|
xmpp_disconnect(conn);
|
||||||
return;
|
|
||||||
}
|
|
||||||
xmpp_stanza_add_child(child, authdata);
|
|
||||||
xmpp_stanza_release(authdata);
|
|
||||||
|
|
||||||
handler_add_id(conn, _handle_legacy, "_xmpp_auth1", NULL);
|
|
||||||
handler_add_timed(conn, _handle_missing_legacy,
|
|
||||||
LEGACY_TIMEOUT, NULL);
|
|
||||||
|
|
||||||
xmpp_send(conn, iq);
|
|
||||||
xmpp_stanza_release(iq);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -838,15 +755,23 @@ void auth_handle_open(xmpp_conn_t * const conn)
|
|||||||
/* reset all timed handlers */
|
/* reset all timed handlers */
|
||||||
handler_reset_timed(conn, 0);
|
handler_reset_timed(conn, 0);
|
||||||
|
|
||||||
/* setup handler for stream:error */
|
/* setup handler for stream:error, we will keep this handler
|
||||||
handler_add(conn, _handle_error,
|
* for reopened streams until connection is disconnected */
|
||||||
XMPP_NS_STREAMS, "error", NULL, NULL);
|
handler_add(conn, _handle_error, XMPP_NS_STREAMS, "error", NULL, NULL);
|
||||||
|
|
||||||
/* setup handlers for incoming <stream:features> */
|
/* setup handlers for incoming <stream:features> */
|
||||||
handler_add(conn, _handle_features,
|
handler_add(conn, _handle_features,
|
||||||
XMPP_NS_STREAMS, "features", NULL, NULL);
|
XMPP_NS_STREAMS, "features", NULL, NULL);
|
||||||
handler_add_timed(conn, _handle_missing_features,
|
handler_add_timed(conn, _handle_missing_features, FEATURES_TIMEOUT, NULL);
|
||||||
FEATURES_TIMEOUT, NULL);
|
}
|
||||||
|
|
||||||
|
/* called when stream:stream tag received after TLS establishment */
|
||||||
|
static void _handle_open_tls(xmpp_conn_t * const conn)
|
||||||
|
{
|
||||||
|
/* setup handlers for incoming <stream:features> */
|
||||||
|
handler_add(conn, _handle_features,
|
||||||
|
XMPP_NS_STREAMS, "features", NULL, NULL);
|
||||||
|
handler_add_timed(conn, _handle_missing_features, FEATURES_TIMEOUT, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* called when stream:stream tag received after SASL auth */
|
/* called when stream:stream tag received after SASL auth */
|
||||||
@@ -865,7 +790,8 @@ static int _handle_features_sasl(xmpp_conn_t * const conn,
|
|||||||
xmpp_stanza_t * const stanza,
|
xmpp_stanza_t * const stanza,
|
||||||
void * const userdata)
|
void * const userdata)
|
||||||
{
|
{
|
||||||
xmpp_stanza_t *bind, *session, *iq, *res, *text;
|
xmpp_stanza_t *bind, *session, *iq, *res, *text, *opt;
|
||||||
|
const char *ns;
|
||||||
char *resource;
|
char *resource;
|
||||||
|
|
||||||
/* remove missing features handler */
|
/* remove missing features handler */
|
||||||
@@ -874,16 +800,27 @@ static int _handle_features_sasl(xmpp_conn_t * const conn,
|
|||||||
/* we are expecting <bind/> and <session/> since this is a
|
/* we are expecting <bind/> and <session/> since this is a
|
||||||
XMPP style connection */
|
XMPP style connection */
|
||||||
|
|
||||||
|
/* check whether resource binding is required */
|
||||||
bind = xmpp_stanza_get_child_by_name(stanza, "bind");
|
bind = xmpp_stanza_get_child_by_name(stanza, "bind");
|
||||||
if (bind && strcmp(xmpp_stanza_get_ns(bind), XMPP_NS_BIND) == 0) {
|
if (bind) {
|
||||||
/* resource binding is required */
|
ns = xmpp_stanza_get_ns(bind);
|
||||||
conn->bind_required = 1;
|
conn->bind_required = ns != NULL && strcmp(ns, XMPP_NS_BIND) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* check whether session establishment is required */
|
||||||
session = xmpp_stanza_get_child_by_name(stanza, "session");
|
session = xmpp_stanza_get_child_by_name(stanza, "session");
|
||||||
if (session && strcmp(xmpp_stanza_get_ns(session), XMPP_NS_SESSION) == 0) {
|
if (session) {
|
||||||
/* session establishment required */
|
ns = xmpp_stanza_get_ns(session);
|
||||||
conn->session_required = 1;
|
opt = xmpp_stanza_get_child_by_name(session, "optional");
|
||||||
|
if (!opt)
|
||||||
|
conn->session_required = ns != NULL &&
|
||||||
|
strcmp(ns, XMPP_NS_SESSION) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
opt = xmpp_stanza_get_child_by_ns(stanza, XMPP_NS_SM);
|
||||||
|
if (opt && strcmp(xmpp_stanza_get_name(opt), "sm") == 0) {
|
||||||
|
/* stream management supported */
|
||||||
|
conn->sm_support = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if bind is required, go ahead and start it */
|
/* if bind is required, go ahead and start it */
|
||||||
@@ -896,16 +833,12 @@ static int _handle_features_sasl(xmpp_conn_t * const conn,
|
|||||||
BIND_TIMEOUT, NULL);
|
BIND_TIMEOUT, NULL);
|
||||||
|
|
||||||
/* send bind request */
|
/* send bind request */
|
||||||
iq = xmpp_stanza_new(conn->ctx);
|
iq = xmpp_iq_new(conn->ctx, "set", "_xmpp_bind1");
|
||||||
if (!iq) {
|
if (!iq) {
|
||||||
disconnect_mem_error(conn);
|
disconnect_mem_error(conn);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
xmpp_stanza_set_name(iq, "iq");
|
|
||||||
xmpp_stanza_set_type(iq, "set");
|
|
||||||
xmpp_stanza_set_id(iq, "_xmpp_bind1");
|
|
||||||
|
|
||||||
bind = xmpp_stanza_copy(bind);
|
bind = xmpp_stanza_copy(bind);
|
||||||
if (!bind) {
|
if (!bind) {
|
||||||
xmpp_stanza_release(iq);
|
xmpp_stanza_release(iq);
|
||||||
@@ -978,7 +911,7 @@ static int _handle_bind(xmpp_conn_t * const conn,
|
|||||||
void * const userdata)
|
void * const userdata)
|
||||||
{
|
{
|
||||||
const char *type;
|
const char *type;
|
||||||
xmpp_stanza_t *iq, *session;
|
xmpp_stanza_t *iq, *enable, *session, *binding, *jid_stanza;
|
||||||
|
|
||||||
/* delete missing bind handler */
|
/* delete missing bind handler */
|
||||||
xmpp_timed_handler_delete(conn, _handle_missing_bind);
|
xmpp_timed_handler_delete(conn, _handle_missing_bind);
|
||||||
@@ -989,12 +922,11 @@ static int _handle_bind(xmpp_conn_t * const conn,
|
|||||||
xmpp_error(conn->ctx, "xmpp", "Binding failed.");
|
xmpp_error(conn->ctx, "xmpp", "Binding failed.");
|
||||||
xmpp_disconnect(conn);
|
xmpp_disconnect(conn);
|
||||||
} else if (type && strcmp(type, "result") == 0) {
|
} else if (type && strcmp(type, "result") == 0) {
|
||||||
xmpp_stanza_t *binding = xmpp_stanza_get_child_by_name(stanza, "bind");
|
binding = xmpp_stanza_get_child_by_name(stanza, "bind");
|
||||||
xmpp_debug(conn->ctx, "xmpp", "Bind successful.");
|
xmpp_debug(conn->ctx, "xmpp", "Bind successful.");
|
||||||
|
|
||||||
if (binding) {
|
if (binding) {
|
||||||
xmpp_stanza_t *jid_stanza = xmpp_stanza_get_child_by_name(binding,
|
jid_stanza = xmpp_stanza_get_child_by_name(binding, "jid");
|
||||||
"jid");
|
|
||||||
if (jid_stanza) {
|
if (jid_stanza) {
|
||||||
conn->bound_jid = xmpp_stanza_get_text(jid_stanza);
|
conn->bound_jid = xmpp_stanza_get_text(jid_stanza);
|
||||||
}
|
}
|
||||||
@@ -1008,20 +940,17 @@ static int _handle_bind(xmpp_conn_t * const conn,
|
|||||||
SESSION_TIMEOUT, NULL);
|
SESSION_TIMEOUT, NULL);
|
||||||
|
|
||||||
/* send session request */
|
/* send session request */
|
||||||
iq = xmpp_stanza_new(conn->ctx);
|
iq = xmpp_iq_new(conn->ctx, "set", "_xmpp_session1");
|
||||||
if (!iq) {
|
if (!iq) {
|
||||||
disconnect_mem_error(conn);
|
disconnect_mem_error(conn);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
xmpp_stanza_set_name(iq, "iq");
|
|
||||||
xmpp_stanza_set_type(iq, "set");
|
|
||||||
xmpp_stanza_set_id(iq, "_xmpp_session1");
|
|
||||||
|
|
||||||
session = xmpp_stanza_new(conn->ctx);
|
session = xmpp_stanza_new(conn->ctx);
|
||||||
if (!session) {
|
if (!session) {
|
||||||
xmpp_stanza_release(iq);
|
xmpp_stanza_release(iq);
|
||||||
disconnect_mem_error(conn);
|
disconnect_mem_error(conn);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
xmpp_stanza_set_name(session, "session");
|
xmpp_stanza_set_name(session, "session");
|
||||||
@@ -1033,7 +962,23 @@ static int _handle_bind(xmpp_conn_t * const conn,
|
|||||||
/* send session establishment request */
|
/* send session establishment request */
|
||||||
xmpp_send(conn, iq);
|
xmpp_send(conn, iq);
|
||||||
xmpp_stanza_release(iq);
|
xmpp_stanza_release(iq);
|
||||||
} else {
|
}
|
||||||
|
|
||||||
|
if (conn->sm_support) {
|
||||||
|
enable = xmpp_stanza_new(conn->ctx);
|
||||||
|
if (!enable) {
|
||||||
|
disconnect_mem_error(conn);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
xmpp_stanza_set_name(enable, "enable");
|
||||||
|
xmpp_stanza_set_ns(enable, XMPP_NS_SM);
|
||||||
|
handler_add(conn, _handle_sm, XMPP_NS_SM, NULL, NULL, NULL);
|
||||||
|
xmpp_send(conn, enable);
|
||||||
|
xmpp_stanza_release(enable);
|
||||||
|
conn->sm_sent_nr = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!conn->session_required) {
|
||||||
conn->authenticated = 1;
|
conn->authenticated = 1;
|
||||||
|
|
||||||
/* call connection handler */
|
/* call connection handler */
|
||||||
@@ -1093,6 +1038,32 @@ static int _handle_missing_session(xmpp_conn_t * const conn,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int _handle_missing_legacy(xmpp_conn_t * const conn,
|
||||||
|
void * const userdata)
|
||||||
|
{
|
||||||
|
xmpp_error(conn->ctx, "xmpp", "Server did not reply to legacy "\
|
||||||
|
"authentication request.");
|
||||||
|
xmpp_disconnect(conn);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _handle_sm(xmpp_conn_t * const conn,
|
||||||
|
xmpp_stanza_t * const stanza,
|
||||||
|
void * const userdata)
|
||||||
|
{
|
||||||
|
const char *name;
|
||||||
|
|
||||||
|
name = xmpp_stanza_get_name(stanza);
|
||||||
|
if (name && strcmp(name, "enabled") == 0) {
|
||||||
|
conn->sm_enabled = 1;
|
||||||
|
conn->sm_handled_nr = 0;
|
||||||
|
} else {
|
||||||
|
conn->sm_enabled = 0;
|
||||||
|
xmpp_warn(conn->ctx, "auth", "Stream management failed.");
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int _handle_legacy(xmpp_conn_t * const conn,
|
static int _handle_legacy(xmpp_conn_t * const conn,
|
||||||
xmpp_stanza_t * const stanza,
|
xmpp_stanza_t * const stanza,
|
||||||
void * const userdata)
|
void * const userdata)
|
||||||
@@ -1129,13 +1100,97 @@ static int _handle_legacy(xmpp_conn_t * const conn,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _handle_missing_legacy(xmpp_conn_t * const conn,
|
static void _auth_legacy(xmpp_conn_t *conn)
|
||||||
void * const userdata)
|
|
||||||
{
|
{
|
||||||
xmpp_error(conn->ctx, "xmpp", "Server did not reply to legacy "\
|
xmpp_stanza_t *iq;
|
||||||
"authentication request.");
|
xmpp_stanza_t *authdata;
|
||||||
|
xmpp_stanza_t *query;
|
||||||
|
xmpp_stanza_t *child;
|
||||||
|
char *str;
|
||||||
|
|
||||||
|
xmpp_debug(conn->ctx, "auth", "Legacy authentication request");
|
||||||
|
|
||||||
|
iq = xmpp_iq_new(conn->ctx, "set", "_xmpp_auth1");
|
||||||
|
if (!iq)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
query = xmpp_stanza_new(conn->ctx);
|
||||||
|
if (!query)
|
||||||
|
goto err_free;
|
||||||
|
xmpp_stanza_set_name(query, "query");
|
||||||
|
xmpp_stanza_set_ns(query, XMPP_NS_AUTH);
|
||||||
|
xmpp_stanza_add_child(iq, query);
|
||||||
|
xmpp_stanza_release(query);
|
||||||
|
|
||||||
|
child = xmpp_stanza_new(conn->ctx);
|
||||||
|
if (!child)
|
||||||
|
goto err_free;
|
||||||
|
xmpp_stanza_set_name(child, "username");
|
||||||
|
xmpp_stanza_add_child(query, child);
|
||||||
|
xmpp_stanza_release(child);
|
||||||
|
|
||||||
|
authdata = xmpp_stanza_new(conn->ctx);
|
||||||
|
if (!authdata)
|
||||||
|
goto err_free;
|
||||||
|
str = xmpp_jid_node(conn->ctx, conn->jid);
|
||||||
|
if (!str) {
|
||||||
|
xmpp_stanza_release(authdata);
|
||||||
|
goto err_free;
|
||||||
|
}
|
||||||
|
xmpp_stanza_set_text(authdata, str);
|
||||||
|
xmpp_free(conn->ctx, str);
|
||||||
|
xmpp_stanza_add_child(child, authdata);
|
||||||
|
xmpp_stanza_release(authdata);
|
||||||
|
|
||||||
|
child = xmpp_stanza_new(conn->ctx);
|
||||||
|
if (!child)
|
||||||
|
goto err_free;
|
||||||
|
xmpp_stanza_set_name(child, "password");
|
||||||
|
xmpp_stanza_add_child(query, child);
|
||||||
|
xmpp_stanza_release(child);
|
||||||
|
|
||||||
|
authdata = xmpp_stanza_new(conn->ctx);
|
||||||
|
if (!authdata)
|
||||||
|
goto err_free;
|
||||||
|
xmpp_stanza_set_text(authdata, conn->pass);
|
||||||
|
xmpp_stanza_add_child(child, authdata);
|
||||||
|
xmpp_stanza_release(authdata);
|
||||||
|
|
||||||
|
child = xmpp_stanza_new(conn->ctx);
|
||||||
|
if (!child)
|
||||||
|
goto err_free;
|
||||||
|
xmpp_stanza_set_name(child, "resource");
|
||||||
|
xmpp_stanza_add_child(query, child);
|
||||||
|
xmpp_stanza_release(child);
|
||||||
|
|
||||||
|
authdata = xmpp_stanza_new(conn->ctx);
|
||||||
|
if (!authdata)
|
||||||
|
goto err_free;
|
||||||
|
str = xmpp_jid_resource(conn->ctx, conn->jid);
|
||||||
|
if (str) {
|
||||||
|
xmpp_stanza_set_text(authdata, str);
|
||||||
|
xmpp_free(conn->ctx, str);
|
||||||
|
} else {
|
||||||
|
xmpp_stanza_release(authdata);
|
||||||
|
xmpp_stanza_release(iq);
|
||||||
|
xmpp_error(conn->ctx, "auth", "Cannot authenticate without resource");
|
||||||
xmpp_disconnect(conn);
|
xmpp_disconnect(conn);
|
||||||
return 0;
|
return;
|
||||||
|
}
|
||||||
|
xmpp_stanza_add_child(child, authdata);
|
||||||
|
xmpp_stanza_release(authdata);
|
||||||
|
|
||||||
|
handler_add_id(conn, _handle_legacy, "_xmpp_auth1", NULL);
|
||||||
|
handler_add_timed(conn, _handle_missing_legacy, LEGACY_TIMEOUT, NULL);
|
||||||
|
|
||||||
|
xmpp_send(conn, iq);
|
||||||
|
xmpp_stanza_release(iq);
|
||||||
|
return;
|
||||||
|
|
||||||
|
err_free:
|
||||||
|
xmpp_stanza_release(iq);
|
||||||
|
err:
|
||||||
|
disconnect_mem_error(conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
void auth_handle_component_open(xmpp_conn_t * const conn)
|
void auth_handle_component_open(xmpp_conn_t * const conn)
|
||||||
|
|||||||
13
src/common.h
13
src/common.h
@@ -50,6 +50,8 @@ struct _xmpp_ctx_t {
|
|||||||
xmpp_rand_t *rand;
|
xmpp_rand_t *rand;
|
||||||
xmpp_loop_status_t loop_status;
|
xmpp_loop_status_t loop_status;
|
||||||
xmpp_connlist_t *connlist;
|
xmpp_connlist_t *connlist;
|
||||||
|
|
||||||
|
unsigned long timeout;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -105,7 +107,7 @@ 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;
|
||||||
void *handler;
|
int (*handler)();
|
||||||
void *userdata;
|
void *userdata;
|
||||||
int enabled; /* handlers are added disabled and enabled after the
|
int enabled; /* handlers are added disabled and enabled after the
|
||||||
* handler chain is processed to prevent stanzas from
|
* handler chain is processed to prevent stanzas from
|
||||||
@@ -128,7 +130,7 @@ struct _xmpp_handlist_t {
|
|||||||
char *name;
|
char *name;
|
||||||
char *type;
|
char *type;
|
||||||
};
|
};
|
||||||
};
|
} u;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define MAX_DOMAIN_LEN 256
|
#define MAX_DOMAIN_LEN 256
|
||||||
@@ -166,14 +168,20 @@ struct _xmpp_conn_t {
|
|||||||
int tls_disabled;
|
int tls_disabled;
|
||||||
int tls_mandatory;
|
int tls_mandatory;
|
||||||
int tls_legacy_ssl;
|
int tls_legacy_ssl;
|
||||||
|
int tls_trust;
|
||||||
int tls_failed; /* set when tls fails, so we don't try again */
|
int tls_failed; /* set when tls fails, so we don't try again */
|
||||||
int sasl_support; /* if true, field is a bitfield of supported
|
int sasl_support; /* if true, field is a bitfield of supported
|
||||||
mechanisms */
|
mechanisms */
|
||||||
|
int auth_legacy_enabled;
|
||||||
int secured; /* set when stream is secured with TLS */
|
int secured; /* set when stream is secured with TLS */
|
||||||
|
|
||||||
/* if server returns <bind/> or <session/> we must do them */
|
/* if server returns <bind/> or <session/> we must do them */
|
||||||
int bind_required;
|
int bind_required;
|
||||||
int session_required;
|
int session_required;
|
||||||
|
int sm_support;
|
||||||
|
int sm_enabled;
|
||||||
|
uint32_t sm_handled_nr;
|
||||||
|
uint32_t sm_sent_nr;
|
||||||
|
|
||||||
char *lang;
|
char *lang;
|
||||||
char *domain;
|
char *domain;
|
||||||
@@ -264,6 +272,7 @@ void handler_add(xmpp_conn_t * const conn,
|
|||||||
const char * const name,
|
const char * const name,
|
||||||
const char * const type,
|
const char * const type,
|
||||||
void * const userdata);
|
void * const userdata);
|
||||||
|
void handler_system_delete_all(xmpp_conn_t *conn);
|
||||||
|
|
||||||
/* utility functions */
|
/* utility functions */
|
||||||
void disconnect_mem_error(xmpp_conn_t * const conn);
|
void disconnect_mem_error(xmpp_conn_t * const conn);
|
||||||
|
|||||||
129
src/conn.c
129
src/conn.c
@@ -62,6 +62,8 @@ static void _handle_stream_end(char *name,
|
|||||||
void * const userdata);
|
void * const userdata);
|
||||||
static void _handle_stream_stanza(xmpp_stanza_t *stanza,
|
static void _handle_stream_stanza(xmpp_stanza_t *stanza,
|
||||||
void * const userdata);
|
void * const userdata);
|
||||||
|
static void _conn_sm_handle_stanza(xmpp_conn_t * const conn,
|
||||||
|
xmpp_stanza_t *stanza);
|
||||||
static unsigned short _conn_default_port(xmpp_conn_t * const conn,
|
static unsigned short _conn_default_port(xmpp_conn_t * const conn,
|
||||||
xmpp_conn_type_t type);
|
xmpp_conn_type_t type);
|
||||||
static void _conn_reset(xmpp_conn_t * const conn);
|
static void _conn_reset(xmpp_conn_t * const conn);
|
||||||
@@ -73,6 +75,15 @@ static int _conn_connect(xmpp_conn_t * const conn,
|
|||||||
xmpp_conn_handler callback,
|
xmpp_conn_handler callback,
|
||||||
void * const userdata);
|
void * const userdata);
|
||||||
|
|
||||||
|
void xmpp_send_error(xmpp_conn_t * const conn, xmpp_error_type_t const type, char * const text)
|
||||||
|
{
|
||||||
|
xmpp_stanza_t *error = xmpp_error_new(conn->ctx, type, text);
|
||||||
|
|
||||||
|
xmpp_send(conn, error);
|
||||||
|
|
||||||
|
xmpp_stanza_release(error);
|
||||||
|
}
|
||||||
|
|
||||||
/** Create a new Strophe connection object.
|
/** Create a new Strophe connection object.
|
||||||
*
|
*
|
||||||
* @param ctx a Strophe context object
|
* @param ctx a Strophe context object
|
||||||
@@ -128,12 +139,18 @@ xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t * const ctx)
|
|||||||
conn->tls_disabled = 0;
|
conn->tls_disabled = 0;
|
||||||
conn->tls_mandatory = 0;
|
conn->tls_mandatory = 0;
|
||||||
conn->tls_legacy_ssl = 0;
|
conn->tls_legacy_ssl = 0;
|
||||||
|
conn->tls_trust = 0;
|
||||||
conn->tls_failed = 0;
|
conn->tls_failed = 0;
|
||||||
conn->sasl_support = 0;
|
conn->sasl_support = 0;
|
||||||
|
conn->auth_legacy_enabled = 0;
|
||||||
conn->secured = 0;
|
conn->secured = 0;
|
||||||
|
|
||||||
conn->bind_required = 0;
|
conn->bind_required = 0;
|
||||||
conn->session_required = 0;
|
conn->session_required = 0;
|
||||||
|
conn->sm_support = 0;
|
||||||
|
conn->sm_enabled = 0;
|
||||||
|
conn->sm_handled_nr = 0;
|
||||||
|
conn->sm_sent_nr = 0;
|
||||||
|
|
||||||
conn->parser = parser_new(conn->ctx,
|
conn->parser = parser_new(conn->ctx,
|
||||||
_handle_stream_start,
|
_handle_stream_start,
|
||||||
@@ -243,6 +260,12 @@ int xmpp_conn_release(xmpp_conn_t * const conn)
|
|||||||
else {
|
else {
|
||||||
ctx = conn->ctx;
|
ctx = conn->ctx;
|
||||||
|
|
||||||
|
if (conn->state == XMPP_STATE_CONNECTING ||
|
||||||
|
conn->state == XMPP_STATE_CONNECTED)
|
||||||
|
{
|
||||||
|
conn_disconnect(conn);
|
||||||
|
}
|
||||||
|
|
||||||
/* remove connection from context's connlist */
|
/* remove connection from context's connlist */
|
||||||
if (ctx->connlist->conn == conn) {
|
if (ctx->connlist->conn == conn) {
|
||||||
item = ctx->connlist;
|
item = ctx->connlist;
|
||||||
@@ -264,6 +287,8 @@ int xmpp_conn_release(xmpp_conn_t * const conn)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_conn_reset(conn);
|
||||||
|
|
||||||
/* free handler stuff
|
/* free handler stuff
|
||||||
* note that userdata is the responsibility of the client
|
* note that userdata is the responsibility of the client
|
||||||
* and the handler pointers don't need to be freed since they
|
* and the handler pointers don't need to be freed since they
|
||||||
@@ -286,7 +311,7 @@ int xmpp_conn_release(xmpp_conn_t * const conn)
|
|||||||
while (hlitem) {
|
while (hlitem) {
|
||||||
thli = hlitem;
|
thli = hlitem;
|
||||||
hlitem = hlitem->next;
|
hlitem = hlitem->next;
|
||||||
xmpp_free(conn->ctx, thli->id);
|
xmpp_free(conn->ctx, thli->u.id);
|
||||||
xmpp_free(conn->ctx, thli);
|
xmpp_free(conn->ctx, thli);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -298,14 +323,13 @@ int xmpp_conn_release(xmpp_conn_t * const conn)
|
|||||||
thli = hlitem;
|
thli = hlitem;
|
||||||
hlitem = hlitem->next;
|
hlitem = hlitem->next;
|
||||||
|
|
||||||
if (thli->ns) xmpp_free(ctx, thli->ns);
|
if (thli->u.ns) xmpp_free(ctx, thli->u.ns);
|
||||||
if (thli->name) xmpp_free(ctx, thli->name);
|
if (thli->u.name) xmpp_free(ctx, thli->u.name);
|
||||||
if (thli->type) xmpp_free(ctx, thli->type);
|
if (thli->u.type) xmpp_free(ctx, thli->u.type);
|
||||||
xmpp_free(ctx, thli);
|
xmpp_free(ctx, thli);
|
||||||
}
|
}
|
||||||
|
|
||||||
parser_free(conn->parser);
|
parser_free(conn->parser);
|
||||||
_conn_reset(conn);
|
|
||||||
|
|
||||||
if (conn->jid) xmpp_free(ctx, conn->jid);
|
if (conn->jid) xmpp_free(ctx, conn->jid);
|
||||||
if (conn->pass) xmpp_free(ctx, conn->pass);
|
if (conn->pass) xmpp_free(ctx, conn->pass);
|
||||||
@@ -702,7 +726,7 @@ void conn_parser_reset(xmpp_conn_t * const conn)
|
|||||||
/** Initiate termination of the connection to the XMPP server.
|
/** Initiate termination of the connection to the XMPP server.
|
||||||
* This function starts the disconnection sequence by sending
|
* This function starts the disconnection sequence by sending
|
||||||
* </stream:stream> to the XMPP server. This function will do nothing
|
* </stream:stream> to the XMPP server. This function will do nothing
|
||||||
* if the connection state is CONNECTING or CONNECTED.
|
* if the connection state is different from CONNECTING or CONNECTED.
|
||||||
*
|
*
|
||||||
* @param conn a Strophe connection object
|
* @param conn a Strophe connection object
|
||||||
*
|
*
|
||||||
@@ -744,10 +768,10 @@ void xmpp_send_raw_string(xmpp_conn_t * const conn,
|
|||||||
char *bigbuf;
|
char *bigbuf;
|
||||||
|
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
len = xmpp_vsnprintf(buf, 1024, fmt, ap);
|
len = xmpp_vsnprintf(buf, sizeof(buf), fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|
||||||
if (len >= 1024) {
|
if (len >= sizeof(buf)) {
|
||||||
/* we need more space for this data, so we allocate a big
|
/* we need more space for this data, so we allocate a big
|
||||||
* enough buffer and print to that */
|
* enough buffer and print to that */
|
||||||
len++; /* account for trailing \0 */
|
len++; /* account for trailing \0 */
|
||||||
@@ -768,7 +792,6 @@ void xmpp_send_raw_string(xmpp_conn_t * const conn,
|
|||||||
xmpp_free(conn->ctx, bigbuf);
|
xmpp_free(conn->ctx, bigbuf);
|
||||||
} else {
|
} else {
|
||||||
xmpp_debug(conn->ctx, "conn", "SENT: %s", buf);
|
xmpp_debug(conn->ctx, "conn", "SENT: %s", buf);
|
||||||
|
|
||||||
xmpp_send_raw(conn, buf, len);
|
xmpp_send_raw(conn, buf, len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -833,10 +856,9 @@ void xmpp_send(xmpp_conn_t * const conn,
|
|||||||
{
|
{
|
||||||
char *buf;
|
char *buf;
|
||||||
size_t len;
|
size_t len;
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (conn->state == XMPP_STATE_CONNECTED) {
|
if (conn->state == XMPP_STATE_CONNECTED) {
|
||||||
if ((ret = xmpp_stanza_to_text(stanza, &buf, &len)) == 0) {
|
if (xmpp_stanza_to_text(stanza, &buf, &len) == 0) {
|
||||||
xmpp_send_raw(conn, buf, len);
|
xmpp_send_raw(conn, buf, len);
|
||||||
xmpp_debug(conn->ctx, "conn", "SENT: %s", buf);
|
xmpp_debug(conn->ctx, "conn", "SENT: %s", buf);
|
||||||
xmpp_free(conn->ctx, buf);
|
xmpp_free(conn->ctx, buf);
|
||||||
@@ -874,7 +896,7 @@ int conn_tls_start(xmpp_conn_t * const conn)
|
|||||||
conn->tls = NULL;
|
conn->tls = NULL;
|
||||||
rc = XMPP_EINVOP;
|
rc = XMPP_EINVOP;
|
||||||
} else {
|
} else {
|
||||||
conn->tls = tls_new(conn->ctx, conn->sock);
|
conn->tls = tls_new(conn);
|
||||||
rc = conn->tls == NULL ? XMPP_EMEM : 0;
|
rc = conn->tls == NULL ? XMPP_EMEM : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -910,7 +932,9 @@ long xmpp_conn_get_flags(const xmpp_conn_t * const conn)
|
|||||||
|
|
||||||
flags = XMPP_CONN_FLAG_DISABLE_TLS * conn->tls_disabled |
|
flags = XMPP_CONN_FLAG_DISABLE_TLS * conn->tls_disabled |
|
||||||
XMPP_CONN_FLAG_MANDATORY_TLS * conn->tls_mandatory |
|
XMPP_CONN_FLAG_MANDATORY_TLS * conn->tls_mandatory |
|
||||||
XMPP_CONN_FLAG_LEGACY_SSL * conn->tls_legacy_ssl;
|
XMPP_CONN_FLAG_LEGACY_SSL * conn->tls_legacy_ssl |
|
||||||
|
XMPP_CONN_FLAG_TRUST_TLS * conn->tls_trust |
|
||||||
|
XMPP_CONN_FLAG_LEGACY_AUTH * conn->auth_legacy_enabled;;
|
||||||
|
|
||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
@@ -927,6 +951,8 @@ long xmpp_conn_get_flags(const xmpp_conn_t * const conn)
|
|||||||
* - XMPP_CONN_FLAG_DISABLE_TLS
|
* - XMPP_CONN_FLAG_DISABLE_TLS
|
||||||
* - XMPP_CONN_FLAG_MANDATORY_TLS
|
* - XMPP_CONN_FLAG_MANDATORY_TLS
|
||||||
* - XMPP_CONN_FLAG_LEGACY_SSL
|
* - XMPP_CONN_FLAG_LEGACY_SSL
|
||||||
|
* - XMPP_CONN_FLAG_TRUST_TLS
|
||||||
|
* - XMPP_CONN_FLAG_LEGACY_AUTH
|
||||||
*
|
*
|
||||||
* @param conn a Strophe connection object
|
* @param conn a Strophe connection object
|
||||||
* @param flags ORed connection flags
|
* @param flags ORed connection flags
|
||||||
@@ -943,7 +969,8 @@ int xmpp_conn_set_flags(xmpp_conn_t * const conn, long flags)
|
|||||||
return XMPP_EINVOP;
|
return XMPP_EINVOP;
|
||||||
}
|
}
|
||||||
if (flags & XMPP_CONN_FLAG_DISABLE_TLS &&
|
if (flags & XMPP_CONN_FLAG_DISABLE_TLS &&
|
||||||
flags & (XMPP_CONN_FLAG_MANDATORY_TLS | XMPP_CONN_FLAG_LEGACY_SSL)) {
|
flags & (XMPP_CONN_FLAG_MANDATORY_TLS | XMPP_CONN_FLAG_LEGACY_SSL |
|
||||||
|
XMPP_CONN_FLAG_TRUST_TLS)) {
|
||||||
xmpp_error(conn->ctx, "conn", "Flags 0x%04lx conflict", flags);
|
xmpp_error(conn->ctx, "conn", "Flags 0x%04lx conflict", flags);
|
||||||
return XMPP_EINVOP;
|
return XMPP_EINVOP;
|
||||||
}
|
}
|
||||||
@@ -951,6 +978,8 @@ int xmpp_conn_set_flags(xmpp_conn_t * const conn, long flags)
|
|||||||
conn->tls_disabled = (flags & XMPP_CONN_FLAG_DISABLE_TLS) ? 1 : 0;
|
conn->tls_disabled = (flags & XMPP_CONN_FLAG_DISABLE_TLS) ? 1 : 0;
|
||||||
conn->tls_mandatory = (flags & XMPP_CONN_FLAG_MANDATORY_TLS) ? 1 : 0;
|
conn->tls_mandatory = (flags & XMPP_CONN_FLAG_MANDATORY_TLS) ? 1 : 0;
|
||||||
conn->tls_legacy_ssl = (flags & XMPP_CONN_FLAG_LEGACY_SSL) ? 1 : 0;
|
conn->tls_legacy_ssl = (flags & XMPP_CONN_FLAG_LEGACY_SSL) ? 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;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -985,6 +1014,37 @@ int xmpp_conn_is_secured(xmpp_conn_t * const conn)
|
|||||||
return conn->secured && !conn->tls_failed && conn->tls != NULL ? 1 : 0;
|
return conn->secured && !conn->tls_failed && conn->tls != NULL ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return TRUE if connection is in connecting state and FALSE otherwise
|
||||||
|
*
|
||||||
|
* @ingroup Connections
|
||||||
|
*/
|
||||||
|
int xmpp_conn_is_connecting(xmpp_conn_t * const conn)
|
||||||
|
{
|
||||||
|
return conn->state == XMPP_STATE_CONNECTING ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return TRUE if connection is in connected state and FALSE otherwise
|
||||||
|
*
|
||||||
|
* @ingroup Connections
|
||||||
|
*/
|
||||||
|
int xmpp_conn_is_connected(xmpp_conn_t * const conn)
|
||||||
|
{
|
||||||
|
return conn->state == XMPP_STATE_CONNECTED ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return TRUE if connection is in disconnected state and FALSE otherwise
|
||||||
|
*
|
||||||
|
* @ingroup Connections
|
||||||
|
*/
|
||||||
|
int xmpp_conn_is_disconnected(xmpp_conn_t * const conn)
|
||||||
|
{
|
||||||
|
return conn->state == XMPP_STATE_DISCONNECTED ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* timed handler for cleanup if normal disconnect procedure takes too long */
|
/* timed handler for cleanup if normal disconnect procedure takes too long */
|
||||||
static int _disconnect_cleanup(xmpp_conn_t * const conn,
|
static int _disconnect_cleanup(xmpp_conn_t * const conn,
|
||||||
void * const userdata)
|
void * const userdata)
|
||||||
@@ -1162,6 +1222,36 @@ static void _handle_stream_stanza(xmpp_stanza_t *stanza,
|
|||||||
}
|
}
|
||||||
|
|
||||||
handler_fire_stanza(conn, stanza);
|
handler_fire_stanza(conn, stanza);
|
||||||
|
if (conn->sm_enabled)
|
||||||
|
_conn_sm_handle_stanza(conn, stanza);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* XEP-0198 stream management */
|
||||||
|
static void _conn_sm_handle_stanza(xmpp_conn_t * const conn,
|
||||||
|
xmpp_stanza_t *stanza)
|
||||||
|
{
|
||||||
|
xmpp_stanza_t *a;
|
||||||
|
const char *name;
|
||||||
|
const char *ns;
|
||||||
|
char h[11];
|
||||||
|
|
||||||
|
ns = xmpp_stanza_get_ns(stanza);
|
||||||
|
if (ns && strcmp(ns, XMPP_NS_SM) != 0)
|
||||||
|
++conn->sm_handled_nr;
|
||||||
|
else {
|
||||||
|
name = xmpp_stanza_get_name(stanza);
|
||||||
|
if (name && strcmp(name, "r") == 0) {
|
||||||
|
a = xmpp_stanza_new(conn->ctx);
|
||||||
|
if (!a)
|
||||||
|
return; /* XXX */
|
||||||
|
xmpp_stanza_set_name(a, "a");
|
||||||
|
xmpp_stanza_set_ns(a, XMPP_NS_SM);
|
||||||
|
xmpp_snprintf(h, sizeof(h), "%u", conn->sm_handled_nr);
|
||||||
|
xmpp_stanza_set_attribute(a, "h", h);
|
||||||
|
xmpp_send(conn, a);
|
||||||
|
xmpp_stanza_release(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned short _conn_default_port(xmpp_conn_t * const conn,
|
static unsigned short _conn_default_port(xmpp_conn_t * const conn,
|
||||||
@@ -1196,6 +1286,9 @@ static void _conn_reset(xmpp_conn_t * const conn)
|
|||||||
xmpp_free(ctx, tsq->data);
|
xmpp_free(ctx, tsq->data);
|
||||||
xmpp_free(ctx, tsq);
|
xmpp_free(ctx, tsq);
|
||||||
}
|
}
|
||||||
|
conn->send_queue_head = NULL;
|
||||||
|
conn->send_queue_tail = NULL;
|
||||||
|
conn->send_queue_len = 0;
|
||||||
|
|
||||||
if (conn->stream_error) {
|
if (conn->stream_error) {
|
||||||
xmpp_stanza_release(conn->stream_error->stanza);
|
xmpp_stanza_release(conn->stream_error->stanza);
|
||||||
@@ -1215,6 +1308,14 @@ static void _conn_reset(xmpp_conn_t * const conn)
|
|||||||
conn->secured = 0;
|
conn->secured = 0;
|
||||||
conn->tls_failed = 0;
|
conn->tls_failed = 0;
|
||||||
conn->error = 0;
|
conn->error = 0;
|
||||||
|
|
||||||
|
conn->tls_support = 0;
|
||||||
|
conn->sm_support = 0;
|
||||||
|
conn->sm_enabled = 0;
|
||||||
|
conn->bind_required = 0;
|
||||||
|
conn->session_required = 0;
|
||||||
|
|
||||||
|
handler_system_delete_all(conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _conn_connect(xmpp_conn_t * const conn,
|
static int _conn_connect(xmpp_conn_t * const conn,
|
||||||
|
|||||||
52
src/crypto.c
52
src/crypto.c
@@ -61,7 +61,7 @@ static char *digest_to_string_alloc(xmpp_ctx_t *ctx, const uint8_t *digest)
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Compute SHA1 message digest
|
/** Compute SHA1 message digest.
|
||||||
* Returns an allocated string which represents SHA1 message digest in
|
* Returns an allocated string which represents SHA1 message digest in
|
||||||
* hexadecimal notation. The string must be freed with xmpp_free().
|
* hexadecimal notation. The string must be freed with xmpp_free().
|
||||||
*
|
*
|
||||||
@@ -81,9 +81,37 @@ char *xmpp_sha1(xmpp_ctx_t *ctx, const unsigned char *data, size_t len)
|
|||||||
return digest_to_string_alloc(ctx, digest);
|
return digest_to_string_alloc(ctx, digest);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Create new SHA1 object
|
/** Compute SHA1 message digest.
|
||||||
|
* Stores digest in user's buffer which must be at least XMPP_SHA1_DIGEST_SIZE
|
||||||
|
* bytes long.
|
||||||
*
|
*
|
||||||
* @param ctx a Strophe context onject
|
* @param data buffer for digest computation
|
||||||
|
* @param len size of the data buffer
|
||||||
|
* @param digest output buffer of XMPP_SHA1_DIGEST_SIZE bytes
|
||||||
|
*
|
||||||
|
* @ingroup Digests
|
||||||
|
*/
|
||||||
|
void xmpp_sha1_digest(const unsigned char *data, size_t len,
|
||||||
|
unsigned char *digest)
|
||||||
|
{
|
||||||
|
crypto_SHA1((const uint8_t *)data, len, digest);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Create new SHA1 object.
|
||||||
|
* SHA1 object is used to compute SHA1 digest of a buffer that is split
|
||||||
|
* in multiple chunks or provided in stream mode. A single buffer can be
|
||||||
|
* processed by short functions xmpp_sha1() and xmpp_sha1_digest().
|
||||||
|
* Follow the next use-case for xmpp_sha1_t object:
|
||||||
|
* @code
|
||||||
|
* xmpp_sha1_t *sha1 = xmpp_sha1_new(ctx);
|
||||||
|
* // Repeat update for all chunks of data
|
||||||
|
* xmpp_sha1_update(sha1, data, len);
|
||||||
|
* xmpp_sha1_final(sha1);
|
||||||
|
* char *digest = xmpp_sha1_to_string_alloc(sha1);
|
||||||
|
* xmpp_sha1_free(sha1);
|
||||||
|
* @endcode
|
||||||
|
*
|
||||||
|
* @param ctx a Strophe context object
|
||||||
*
|
*
|
||||||
* @return new SHA1 object
|
* @return new SHA1 object
|
||||||
*
|
*
|
||||||
@@ -102,7 +130,7 @@ xmpp_sha1_t *xmpp_sha1_new(xmpp_ctx_t *ctx)
|
|||||||
return sha1;
|
return sha1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Destroy SHA1 object
|
/** Destroy SHA1 object.
|
||||||
*
|
*
|
||||||
* @param sha1 a SHA1 object
|
* @param sha1 a SHA1 object
|
||||||
*
|
*
|
||||||
@@ -113,7 +141,7 @@ void xmpp_sha1_free(xmpp_sha1_t *sha1)
|
|||||||
xmpp_free(sha1->xmpp_ctx, sha1);
|
xmpp_free(sha1->xmpp_ctx, sha1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Update SHA1 context with the next portion of data
|
/** Update SHA1 context with the next portion of data.
|
||||||
* Can be called repeatedly.
|
* Can be called repeatedly.
|
||||||
*
|
*
|
||||||
* @param sha1 a SHA1 object
|
* @param sha1 a SHA1 object
|
||||||
@@ -127,7 +155,7 @@ void xmpp_sha1_update(xmpp_sha1_t *sha1, const unsigned char *data, size_t len)
|
|||||||
crypto_SHA1_Update(&sha1->ctx, data, len);
|
crypto_SHA1_Update(&sha1->ctx, data, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Finish SHA1 computation
|
/** Finish SHA1 computation.
|
||||||
* Don't call xmpp_sha1_update() after this function. Retrieve resulting
|
* Don't call xmpp_sha1_update() after this function. Retrieve resulting
|
||||||
* message digest with xmpp_sha1_to_string() or xmpp_sha1_to_digest().
|
* message digest with xmpp_sha1_to_string() or xmpp_sha1_to_digest().
|
||||||
*
|
*
|
||||||
@@ -140,7 +168,7 @@ void xmpp_sha1_final(xmpp_sha1_t *sha1)
|
|||||||
crypto_SHA1_Final(&sha1->ctx, sha1->digest);
|
crypto_SHA1_Final(&sha1->ctx, sha1->digest);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Return message digest rendered as a string
|
/** Return message digest rendered as a string.
|
||||||
* Stores the string to a user's buffer and returns the buffer. Call this
|
* Stores the string to a user's buffer and returns the buffer. Call this
|
||||||
* function after xmpp_sha1_final().
|
* function after xmpp_sha1_final().
|
||||||
*
|
*
|
||||||
@@ -157,7 +185,7 @@ char *xmpp_sha1_to_string(xmpp_sha1_t *sha1, char *s, size_t slen)
|
|||||||
return digest_to_string(sha1->digest, s, slen);
|
return digest_to_string(sha1->digest, s, slen);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Return message digest rendered as a string
|
/** Return message digest rendered as a string.
|
||||||
* Returns an allocated string. Free the string using the Strophe context
|
* Returns an allocated string. Free the string using the Strophe context
|
||||||
* which is passed to xmpp_sha1_new(). Call this function after
|
* which is passed to xmpp_sha1_new(). Call this function after
|
||||||
* xmpp_sha1_final().
|
* xmpp_sha1_final().
|
||||||
@@ -173,7 +201,7 @@ char *xmpp_sha1_to_string_alloc(xmpp_sha1_t *sha1)
|
|||||||
return digest_to_string_alloc(sha1->xmpp_ctx, sha1->digest);
|
return digest_to_string_alloc(sha1->xmpp_ctx, sha1->digest);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Stores message digest to a user's buffer
|
/** Stores message digest to a user's buffer.
|
||||||
*
|
*
|
||||||
* @param sha1 a SHA1 object
|
* @param sha1 a SHA1 object
|
||||||
* @param digest output buffer of XMPP_SHA1_DIGEST_SIZE bytes
|
* @param digest output buffer of XMPP_SHA1_DIGEST_SIZE bytes
|
||||||
@@ -391,7 +419,7 @@ _base64_error:
|
|||||||
*outlen = 0;
|
*outlen = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Base64 encoding routine
|
/** Base64 encoding routine.
|
||||||
* Returns an allocated string which must be freed with xmpp_free().
|
* Returns an allocated string which must be freed with xmpp_free().
|
||||||
*
|
*
|
||||||
* @param ctx a Strophe context
|
* @param ctx a Strophe context
|
||||||
@@ -407,7 +435,7 @@ char *xmpp_base64_encode(xmpp_ctx_t *ctx, const unsigned char *data, size_t len)
|
|||||||
return base64_encode(ctx, data, len);
|
return base64_encode(ctx, data, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Base64 decoding routine
|
/** Base64 decoding routine.
|
||||||
* Returns an allocated string which must be freed with xmpp_free(). User
|
* Returns an allocated string which must be freed with xmpp_free(). User
|
||||||
* calls this function when the result must be a string. When decoded buffer
|
* calls this function when the result must be a string. When decoded buffer
|
||||||
* contains '\0' NULL is returned.
|
* contains '\0' NULL is returned.
|
||||||
@@ -443,7 +471,7 @@ char *xmpp_base64_decode_str(xmpp_ctx_t *ctx, const char *base64, size_t len)
|
|||||||
return (char *)buf;
|
return (char *)buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Base64 decoding routine
|
/** Base64 decoding routine.
|
||||||
* Returns an allocated buffer which must be freed with xmpp_free().
|
* Returns an allocated buffer which must be freed with xmpp_free().
|
||||||
*
|
*
|
||||||
* @param ctx a Strophe context
|
* @param ctx a Strophe context
|
||||||
|
|||||||
26
src/ctx.c
26
src/ctx.c
@@ -47,10 +47,11 @@
|
|||||||
|
|
||||||
#include "strophe.h"
|
#include "strophe.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
#include "resolver.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
/* Workaround for visual studio without va_copy support. */
|
/* Workaround for visual studio without va_copy support. */
|
||||||
#if defined(_MSC_VER) && _MSC_VER < 1800
|
#if defined(_MSC_VER) && _MSC_VER < 1800 || defined(__HAIKU__)
|
||||||
#define va_copy(d,s) ((d) = (s))
|
#define va_copy(d,s) ((d) = (s))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -63,6 +64,7 @@
|
|||||||
void xmpp_initialize(void)
|
void xmpp_initialize(void)
|
||||||
{
|
{
|
||||||
sock_initialize();
|
sock_initialize();
|
||||||
|
resolver_initialize();
|
||||||
tls_initialize();
|
tls_initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,6 +75,7 @@
|
|||||||
void xmpp_shutdown(void)
|
void xmpp_shutdown(void)
|
||||||
{
|
{
|
||||||
tls_shutdown();
|
tls_shutdown();
|
||||||
|
resolver_shutdown();
|
||||||
sock_shutdown();
|
sock_shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,6 +94,14 @@ void xmpp_shutdown(void)
|
|||||||
#define LIBXMPP_VERSION_MINOR (0)
|
#define LIBXMPP_VERSION_MINOR (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef EVENT_LOOP_DEFAULT_TIMEOUT
|
||||||
|
/** @def EVENT_LOOP_DEFAULT_TIMEOUT
|
||||||
|
* The default timeout in milliseconds for the event loop.
|
||||||
|
* This is set to 1 second.
|
||||||
|
*/
|
||||||
|
#define EVENT_LOOP_DEFAULT_TIMEOUT 1000
|
||||||
|
#endif
|
||||||
|
|
||||||
/** Check that Strophe supports a specific API version.
|
/** Check that Strophe supports a specific API version.
|
||||||
*
|
*
|
||||||
* @param major the major version number
|
* @param major the major version number
|
||||||
@@ -182,7 +193,6 @@ xmpp_log_t *xmpp_get_default_logger(xmpp_log_level_t level)
|
|||||||
{
|
{
|
||||||
/* clamp to the known range */
|
/* clamp to the known range */
|
||||||
if (level > XMPP_LEVEL_ERROR) level = XMPP_LEVEL_ERROR;
|
if (level > XMPP_LEVEL_ERROR) level = XMPP_LEVEL_ERROR;
|
||||||
if (level < XMPP_LEVEL_DEBUG) level = XMPP_LEVEL_DEBUG;
|
|
||||||
|
|
||||||
return (xmpp_log_t*)&_xmpp_default_loggers[level];
|
return (xmpp_log_t*)&_xmpp_default_loggers[level];
|
||||||
}
|
}
|
||||||
@@ -410,6 +420,7 @@ xmpp_ctx_t *xmpp_ctx_new(const xmpp_mem_t * const mem,
|
|||||||
ctx->connlist = NULL;
|
ctx->connlist = 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;
|
||||||
if (ctx->rand == NULL) {
|
if (ctx->rand == NULL) {
|
||||||
xmpp_free(ctx, ctx);
|
xmpp_free(ctx, ctx);
|
||||||
ctx = NULL;
|
ctx = NULL;
|
||||||
@@ -432,3 +443,14 @@ void xmpp_ctx_free(xmpp_ctx_t * const ctx)
|
|||||||
xmpp_free(ctx, ctx); /* pull the hole in after us */
|
xmpp_free(ctx, ctx); /* pull the hole in after us */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Set the timeout to use when calling xmpp_run().
|
||||||
|
*
|
||||||
|
* @param ctx a Strophe context object
|
||||||
|
* @param timeout the time to wait for events in milliseconds
|
||||||
|
*
|
||||||
|
* @ingroup Context
|
||||||
|
*/
|
||||||
|
void xmpp_ctx_set_timeout(xmpp_ctx_t * const ctx, const unsigned long timeout)
|
||||||
|
{
|
||||||
|
ctx->timeout = timeout;
|
||||||
|
}
|
||||||
|
|||||||
75
src/event.c
75
src/event.c
@@ -41,23 +41,24 @@
|
|||||||
#define _sleep(x) usleep((x) * 1000)
|
#define _sleep(x) usleep((x) * 1000)
|
||||||
#else
|
#else
|
||||||
#include <winsock2.h>
|
#include <winsock2.h>
|
||||||
|
#ifndef ETIMEDOUT
|
||||||
#define ETIMEDOUT WSAETIMEDOUT
|
#define ETIMEDOUT WSAETIMEDOUT
|
||||||
|
#endif
|
||||||
|
#ifndef ECONNRESET
|
||||||
#define ECONNRESET WSAECONNRESET
|
#define ECONNRESET WSAECONNRESET
|
||||||
|
#endif
|
||||||
|
#ifndef ECONNABORTED
|
||||||
#define ECONNABORTED WSAECONNABORTED
|
#define ECONNABORTED WSAECONNABORTED
|
||||||
|
#endif
|
||||||
#define _sleep(x) Sleep(x)
|
#define _sleep(x) Sleep(x)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <strophe.h>
|
#include "strophe.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
|
|
||||||
#ifndef DEFAULT_TIMEOUT
|
/** Max buffer size for receiving messages. */
|
||||||
/** @def DEFAULT_TIMEOUT
|
#define STROPE_MESSAGE_BUFFER_SIZE 4096
|
||||||
* The default timeout in milliseconds for the event loop.
|
|
||||||
* This is set to 1 millisecond.
|
|
||||||
*/
|
|
||||||
#define DEFAULT_TIMEOUT 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/** Run the event loop once.
|
/** Run the event loop once.
|
||||||
* This function will run send any data that has been queued by
|
* This function will run send any data that has been queued by
|
||||||
@@ -82,7 +83,7 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
|
|||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
xmpp_send_queue_t *sq, *tsq;
|
xmpp_send_queue_t *sq, *tsq;
|
||||||
int towrite;
|
int towrite;
|
||||||
char buf[4096];
|
char buf[STROPE_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;
|
||||||
@@ -104,8 +105,8 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
|
|||||||
ret = tls_clear_pending_write(conn->tls);
|
ret = tls_clear_pending_write(conn->tls);
|
||||||
|
|
||||||
if (ret < 0 && !tls_is_recoverable(tls_error(conn->tls))) {
|
if (ret < 0 && !tls_is_recoverable(tls_error(conn->tls))) {
|
||||||
/* an error occured */
|
/* an error occurred */
|
||||||
xmpp_debug(ctx, "xmpp", "Send error occured, disconnecting.");
|
xmpp_debug(ctx, "xmpp", "Send error occurred, disconnecting.");
|
||||||
conn->error = ECONNABORTED;
|
conn->error = ECONNABORTED;
|
||||||
conn_disconnect(conn);
|
conn_disconnect(conn);
|
||||||
}
|
}
|
||||||
@@ -118,30 +119,17 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
|
|||||||
|
|
||||||
if (conn->tls) {
|
if (conn->tls) {
|
||||||
ret = tls_write(conn->tls, &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)))
|
||||||
if (ret < 0 && !tls_is_recoverable(tls_error(conn->tls))) {
|
|
||||||
/* an error occured */
|
|
||||||
conn->error = tls_error(conn->tls);
|
conn->error = tls_error(conn->tls);
|
||||||
break;
|
|
||||||
} else if (ret < towrite) {
|
|
||||||
/* not all data could be sent now */
|
|
||||||
if (ret >= 0) sq->written += ret;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
ret = sock_write(conn->sock, &sq->data[sq->written], towrite);
|
ret = sock_write(conn->sock, &sq->data[sq->written], towrite);
|
||||||
|
if (ret < 0 && !sock_is_recoverable(sock_error()))
|
||||||
if (ret < 0 && !sock_is_recoverable(sock_error())) {
|
|
||||||
/* an error occured */
|
|
||||||
conn->error = sock_error();
|
conn->error = sock_error();
|
||||||
break;
|
|
||||||
} else if (ret < towrite) {
|
|
||||||
/* not all data could be sent now */
|
|
||||||
if (ret >= 0) sq->written += ret;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if (ret > 0 && ret < towrite)
|
||||||
|
sq->written += ret; /* not all data could be sent now */
|
||||||
|
if (ret != towrite)
|
||||||
|
break; /* partial write or an error */
|
||||||
|
|
||||||
/* all data for this queue item written, delete and move on */
|
/* all data for this queue item written, delete and move on */
|
||||||
xmpp_free(ctx, sq->data);
|
xmpp_free(ctx, sq->data);
|
||||||
@@ -160,7 +148,7 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
|
|||||||
if (conn->error) {
|
if (conn->error) {
|
||||||
/* FIXME: need to tear down send queues and random other things
|
/* FIXME: need to tear down send queues and random other things
|
||||||
* maybe this should be abstracted */
|
* maybe this should be abstracted */
|
||||||
xmpp_debug(ctx, "xmpp", "Send error occured, disconnecting.");
|
xmpp_debug(ctx, "xmpp", "Send error occurred, disconnecting.");
|
||||||
conn->error = ECONNABORTED;
|
conn->error = ECONNABORTED;
|
||||||
conn_disconnect(conn);
|
conn_disconnect(conn);
|
||||||
}
|
}
|
||||||
@@ -175,9 +163,8 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* fire any ready timed handlers, then
|
/* fire any ready timed handlers, then make sure we don't wait past
|
||||||
make sure we don't wait past the time when timed handlers need
|
the time when timed handlers need to be called */
|
||||||
to be called */
|
|
||||||
next = handler_fire_timed(ctx);
|
next = handler_fire_timed(ctx);
|
||||||
|
|
||||||
usec = ((next < timeout) ? next : timeout) * 1000;
|
usec = ((next < timeout) ? next : timeout) * 1000;
|
||||||
@@ -209,6 +196,8 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
|
|||||||
break;
|
break;
|
||||||
case XMPP_STATE_CONNECTED:
|
case XMPP_STATE_CONNECTED:
|
||||||
FD_SET(conn->sock, &rfds);
|
FD_SET(conn->sock, &rfds);
|
||||||
|
if (conn->send_queue_len > 0)
|
||||||
|
FD_SET(conn->sock, &wfds);
|
||||||
break;
|
break;
|
||||||
case XMPP_STATE_DISCONNECTED:
|
case XMPP_STATE_DISCONNECTED:
|
||||||
/* do nothing */
|
/* do nothing */
|
||||||
@@ -217,9 +206,8 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* 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(conn->tls);
|
||||||
}
|
|
||||||
|
|
||||||
if (conn->state != XMPP_STATE_DISCONNECTED && conn->sock > max)
|
if (conn->state != XMPP_STATE_DISCONNECTED && conn->sock > max)
|
||||||
max = conn->sock;
|
max = conn->sock;
|
||||||
@@ -275,23 +263,20 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
|
|||||||
case XMPP_STATE_CONNECTED:
|
case XMPP_STATE_CONNECTED:
|
||||||
if (FD_ISSET(conn->sock, &rfds) || (conn->tls && tls_pending(conn->tls))) {
|
if (FD_ISSET(conn->sock, &rfds) || (conn->tls && tls_pending(conn->tls))) {
|
||||||
if (conn->tls) {
|
if (conn->tls) {
|
||||||
ret = tls_read(conn->tls, buf, 4096);
|
ret = tls_read(conn->tls, buf, STROPE_MESSAGE_BUFFER_SIZE);
|
||||||
} else {
|
} else {
|
||||||
ret = sock_read(conn->sock, buf, 4096);
|
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);
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
/* parse error, we need to shut down */
|
xmpp_debug(ctx, "xmpp", "parse error [%s]", buf);
|
||||||
/* FIXME */
|
xmpp_send_error(conn, XMPP_SE_INVALID_XML, "parse error");
|
||||||
xmpp_debug(ctx, "xmpp", "parse error, disconnecting");
|
|
||||||
conn_disconnect(conn);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (conn->tls) {
|
if (conn->tls) {
|
||||||
if (!tls_is_recoverable(tls_error(conn->tls)))
|
if (!tls_is_recoverable(tls_error(conn->tls))) {
|
||||||
{
|
|
||||||
xmpp_debug(ctx, "xmpp", "Unrecoverable TLS error, %d.", tls_error(conn->tls));
|
xmpp_debug(ctx, "xmpp", "Unrecoverable TLS error, %d.", tls_error(conn->tls));
|
||||||
conn->error = tls_error(conn->tls);
|
conn->error = tls_error(conn->tls);
|
||||||
conn_disconnect(conn);
|
conn_disconnect(conn);
|
||||||
@@ -333,7 +318,7 @@ void xmpp_run(xmpp_ctx_t *ctx)
|
|||||||
|
|
||||||
ctx->loop_status = XMPP_LOOP_RUNNING;
|
ctx->loop_status = XMPP_LOOP_RUNNING;
|
||||||
while (ctx->loop_status == XMPP_LOOP_RUNNING) {
|
while (ctx->loop_status == XMPP_LOOP_RUNNING) {
|
||||||
xmpp_run_once(ctx, DEFAULT_TIMEOUT);
|
xmpp_run_once(ctx, ctx->timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* make it possible to start event loop again */
|
/* make it possible to start event loop again */
|
||||||
|
|||||||
355
src/handler.c
355
src/handler.c
@@ -24,6 +24,31 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "ostypes.h"
|
#include "ostypes.h"
|
||||||
|
|
||||||
|
/* Remove item from the list pointed by head, but don't free it.
|
||||||
|
* There can be a situation when user's handler deletes another handler which
|
||||||
|
* is the previous in the list. handler_fire_stanza() and handler_fire_timed()
|
||||||
|
* must handle this situation correctly. Current function helps to avoid
|
||||||
|
* list corruption in described scenario.
|
||||||
|
*
|
||||||
|
* TODO Convert handler lists to double-linked lists. Current implementation
|
||||||
|
* works for O(n).
|
||||||
|
*/
|
||||||
|
static void _handler_item_remove(xmpp_handlist_t **head,
|
||||||
|
xmpp_handlist_t *item)
|
||||||
|
{
|
||||||
|
xmpp_handlist_t *i = *head;
|
||||||
|
|
||||||
|
if (i == item)
|
||||||
|
*head = item->next;
|
||||||
|
else if (i != NULL) {
|
||||||
|
while (i->next != NULL && i->next != item)
|
||||||
|
i = i->next;
|
||||||
|
if (i->next == item) {
|
||||||
|
i->next = item->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Fire off all stanza handlers that match.
|
/** Fire off all stanza handlers that match.
|
||||||
* This function is called internally by the event loop whenever stanzas
|
* This function is called internally by the event loop whenever stanzas
|
||||||
* are received from the XMPP server.
|
* are received from the XMPP server.
|
||||||
@@ -34,36 +59,40 @@
|
|||||||
void handler_fire_stanza(xmpp_conn_t * const conn,
|
void handler_fire_stanza(xmpp_conn_t * const conn,
|
||||||
xmpp_stanza_t * const stanza)
|
xmpp_stanza_t * const stanza)
|
||||||
{
|
{
|
||||||
xmpp_handlist_t *item, *prev;
|
xmpp_handlist_t *item, *next, *head, *head_old;
|
||||||
const char *id, *ns, *name, *type;
|
const char *id, *ns, *name, *type;
|
||||||
|
int ret;
|
||||||
|
|
||||||
/* call id handlers */
|
/* call id handlers */
|
||||||
id = xmpp_stanza_get_id(stanza);
|
id = xmpp_stanza_get_id(stanza);
|
||||||
if (id) {
|
if (id) {
|
||||||
prev = NULL;
|
head = (xmpp_handlist_t *)hash_get(conn->id_handlers, id);
|
||||||
item = (xmpp_handlist_t *)hash_get(conn->id_handlers, id);
|
/* enable all added handlers */
|
||||||
while (item) {
|
for (item = head; item; item = item->next)
|
||||||
xmpp_handlist_t *next = item->next;
|
item->enabled = 1;
|
||||||
|
|
||||||
if (item->user_handler && !conn->authenticated) {
|
item = head;
|
||||||
item = next;
|
while (item) {
|
||||||
|
/* don't fire user handlers until authentication succeeds and
|
||||||
|
and skip newly added handlers */
|
||||||
|
if ((item->user_handler && !conn->authenticated) || !item->enabled) {
|
||||||
|
item = item->next;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!((xmpp_handler)(item->handler))(conn, stanza, item->userdata)) {
|
ret = ((xmpp_handler)(item->handler))(conn, stanza, item->userdata);
|
||||||
|
next = item->next;
|
||||||
|
if (!ret) {
|
||||||
/* handler is one-shot, so delete it */
|
/* handler is one-shot, so delete it */
|
||||||
if (prev)
|
head_old = head;
|
||||||
prev->next = next;
|
_handler_item_remove(&head, item);
|
||||||
else {
|
if (head != head_old) {
|
||||||
hash_drop(conn->id_handlers, id);
|
/* replace old value */
|
||||||
hash_add(conn->id_handlers, id, next);
|
hash_add(conn->id_handlers, id, head);
|
||||||
}
|
}
|
||||||
xmpp_free(conn->ctx, item->id);
|
xmpp_free(conn->ctx, item->u.id);
|
||||||
xmpp_free(conn->ctx, item);
|
xmpp_free(conn->ctx, item);
|
||||||
item = NULL;
|
|
||||||
}
|
}
|
||||||
if (item)
|
|
||||||
prev = item;
|
|
||||||
item = next;
|
item = next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -77,47 +106,34 @@ void handler_fire_stanza(xmpp_conn_t * const conn,
|
|||||||
for (item = conn->handlers; item; item = item->next)
|
for (item = conn->handlers; item; item = item->next)
|
||||||
item->enabled = 1;
|
item->enabled = 1;
|
||||||
|
|
||||||
prev = NULL;
|
|
||||||
item = conn->handlers;
|
item = conn->handlers;
|
||||||
while (item) {
|
while (item) {
|
||||||
/* skip newly added handlers */
|
/* don't fire user handlers until authentication succeeds and
|
||||||
if (!item->enabled) {
|
skip newly added handlers */
|
||||||
prev = item;
|
if ((item->user_handler && !conn->authenticated) || !item->enabled) {
|
||||||
item = item->next;
|
item = item->next;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* don't call user handlers until authentication succeeds */
|
next = item->next;
|
||||||
if (item->user_handler && !conn->authenticated) {
|
if ((!item->u.ns || (ns && strcmp(ns, item->u.ns) == 0) ||
|
||||||
prev = item;
|
xmpp_stanza_get_child_by_ns(stanza, item->u.ns)) &&
|
||||||
item = item->next;
|
(!item->u.name || (name && strcmp(name, item->u.name) == 0)) &&
|
||||||
continue;
|
(!item->u.type || (type && strcmp(type, item->u.type) == 0))) {
|
||||||
}
|
|
||||||
|
|
||||||
if ((!item->ns || (ns && strcmp(ns, item->ns) == 0) ||
|
ret = ((xmpp_handler)(item->handler))(conn, stanza, item->userdata);
|
||||||
xmpp_stanza_get_child_by_ns(stanza, item->ns)) &&
|
/* list may be changed during execution of a handler */
|
||||||
(!item->name || (name && strcmp(name, item->name) == 0)) &&
|
next = item->next;
|
||||||
(!item->type || (type && strcmp(type, item->type) == 0)))
|
if (!ret) {
|
||||||
if (!((xmpp_handler)(item->handler))(conn, stanza, item->userdata)) {
|
|
||||||
/* handler is one-shot, so delete it */
|
/* handler is one-shot, so delete it */
|
||||||
if (prev)
|
_handler_item_remove(&conn->handlers, item);
|
||||||
prev->next = item->next;
|
if (item->u.ns) xmpp_free(conn->ctx, item->u.ns);
|
||||||
else
|
if (item->u.name) xmpp_free(conn->ctx, item->u.name);
|
||||||
conn->handlers = item->next;
|
if (item->u.type) xmpp_free(conn->ctx, item->u.type);
|
||||||
if (item->ns) xmpp_free(conn->ctx, item->ns);
|
|
||||||
if (item->name) xmpp_free(conn->ctx, item->name);
|
|
||||||
if (item->type) xmpp_free(conn->ctx, item->type);
|
|
||||||
xmpp_free(conn->ctx, item);
|
xmpp_free(conn->ctx, item);
|
||||||
item = NULL;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (item) {
|
item = next;
|
||||||
prev = item;
|
|
||||||
item = item->next;
|
|
||||||
} else if (prev)
|
|
||||||
item = prev->next;
|
|
||||||
else
|
|
||||||
item = conn->handlers;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,54 +147,53 @@ void handler_fire_stanza(xmpp_conn_t * const conn,
|
|||||||
uint64_t handler_fire_timed(xmpp_ctx_t * const ctx)
|
uint64_t handler_fire_timed(xmpp_ctx_t * const ctx)
|
||||||
{
|
{
|
||||||
xmpp_connlist_t *connitem;
|
xmpp_connlist_t *connitem;
|
||||||
xmpp_handlist_t *handitem, *temp;
|
xmpp_handlist_t *item, *next;
|
||||||
int ret, fired;
|
xmpp_conn_t *conn;
|
||||||
uint64_t elapsed, min;
|
uint64_t elapsed, min;
|
||||||
|
uint64_t timestamp;
|
||||||
|
int ret;
|
||||||
|
|
||||||
min = (uint64_t)(-1);
|
min = (uint64_t)(-1);
|
||||||
|
|
||||||
connitem = ctx->connlist;
|
connitem = ctx->connlist;
|
||||||
while (connitem) {
|
while (connitem) {
|
||||||
if (connitem->conn->state != XMPP_STATE_CONNECTED) {
|
conn = connitem->conn;
|
||||||
|
if (conn->state != XMPP_STATE_CONNECTED) {
|
||||||
connitem = connitem->next;
|
connitem = connitem->next;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* enable all handlers that were added */
|
/* enable all handlers that were added */
|
||||||
for (handitem = connitem->conn->timed_handlers; handitem;
|
for (item = conn->timed_handlers; item; item = item->next)
|
||||||
handitem = handitem->next)
|
item->enabled = 1;
|
||||||
handitem->enabled = 1;
|
|
||||||
|
|
||||||
handitem = connitem->conn->timed_handlers;
|
item = conn->timed_handlers;
|
||||||
while (handitem) {
|
while (item) {
|
||||||
/* skip newly added handlers */
|
/* don't fire user handlers until authentication succeeds and
|
||||||
if (!handitem->enabled) {
|
skip newly added handlers */
|
||||||
handitem = handitem->next;
|
if ((item->user_handler && !conn->authenticated) || !item->enabled) {
|
||||||
|
item = item->next;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* only fire user handlers after authentication */
|
next = item->next;
|
||||||
if (handitem->user_handler && !connitem->conn->authenticated) {
|
timestamp = time_stamp();
|
||||||
handitem = handitem->next;
|
elapsed = time_elapsed(item->u.last_stamp, timestamp);
|
||||||
continue;
|
if (elapsed >= item->u.period) {
|
||||||
}
|
|
||||||
|
|
||||||
fired = 0;
|
|
||||||
elapsed = time_elapsed(handitem->last_stamp, time_stamp());
|
|
||||||
if (elapsed >= handitem->period) {
|
|
||||||
/* fire! */
|
/* fire! */
|
||||||
fired = 1;
|
item->u.last_stamp = timestamp;
|
||||||
handitem->last_stamp = time_stamp();
|
ret = ((xmpp_timed_handler)item->handler)(conn, item->userdata);
|
||||||
ret = ((xmpp_timed_handler)handitem->handler)(connitem->conn, handitem->userdata);
|
/* list may be changed during execution of a handler */
|
||||||
} else if (min > (handitem->period - elapsed))
|
next = item->next;
|
||||||
min = handitem->period - elapsed;
|
if (!ret) {
|
||||||
|
|
||||||
temp = handitem;
|
|
||||||
handitem = handitem->next;
|
|
||||||
|
|
||||||
/* delete handler if it returned false */
|
/* delete handler if it returned false */
|
||||||
if (fired && !ret)
|
_handler_item_remove(&conn->timed_handlers, item);
|
||||||
xmpp_timed_handler_delete(connitem->conn, temp->handler);
|
xmpp_free(conn->ctx, item);
|
||||||
|
}
|
||||||
|
} else if (min > (item->u.period - elapsed))
|
||||||
|
min = item->u.period - elapsed;
|
||||||
|
|
||||||
|
item = next;
|
||||||
}
|
}
|
||||||
|
|
||||||
connitem = connitem->next;
|
connitem = connitem->next;
|
||||||
@@ -200,7 +215,7 @@ void handler_reset_timed(xmpp_conn_t *conn, int user_only)
|
|||||||
handitem = conn->timed_handlers;
|
handitem = conn->timed_handlers;
|
||||||
while (handitem) {
|
while (handitem) {
|
||||||
if ((user_only && handitem->user_handler) || !user_only)
|
if ((user_only && handitem->user_handler) || !user_only)
|
||||||
handitem->last_stamp = time_stamp();
|
handitem->u.last_stamp = time_stamp();
|
||||||
|
|
||||||
handitem = handitem->next;
|
handitem = handitem->next;
|
||||||
}
|
}
|
||||||
@@ -216,9 +231,11 @@ static void _timed_handler_add(xmpp_conn_t * const conn,
|
|||||||
|
|
||||||
/* check if handler is already in the list */
|
/* check if handler is already in the list */
|
||||||
for (item = conn->timed_handlers; item; item = item->next) {
|
for (item = conn->timed_handlers; item; item = item->next) {
|
||||||
if (item->handler == (void *)handler)
|
if (item->handler == handler && item->userdata == userdata) {
|
||||||
|
xmpp_warn(conn->ctx, "xmpp", "Timed handler already exists.");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (item) return;
|
if (item) return;
|
||||||
|
|
||||||
/* build new item */
|
/* build new item */
|
||||||
@@ -226,13 +243,13 @@ static void _timed_handler_add(xmpp_conn_t * const conn,
|
|||||||
if (!item) return;
|
if (!item) return;
|
||||||
|
|
||||||
item->user_handler = user_handler;
|
item->user_handler = user_handler;
|
||||||
item->handler = (void *)handler;
|
item->handler = handler;
|
||||||
item->userdata = userdata;
|
item->userdata = userdata;
|
||||||
item->enabled = 0;
|
item->enabled = 0;
|
||||||
item->next = NULL;
|
item->next = NULL;
|
||||||
|
|
||||||
item->period = period;
|
item->u.period = period;
|
||||||
item->last_stamp = time_stamp();
|
item->u.last_stamp = time_stamp();
|
||||||
|
|
||||||
/* append item to list */
|
/* append item to list */
|
||||||
if (!conn->timed_handlers)
|
if (!conn->timed_handlers)
|
||||||
@@ -262,19 +279,18 @@ void xmpp_timed_handler_delete(xmpp_conn_t * const conn,
|
|||||||
prev = NULL;
|
prev = NULL;
|
||||||
item = conn->timed_handlers;
|
item = conn->timed_handlers;
|
||||||
while (item) {
|
while (item) {
|
||||||
if (item->handler == (void *)handler)
|
if (item->handler == handler) {
|
||||||
break;
|
|
||||||
prev = item;
|
|
||||||
item = item->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item) {
|
|
||||||
if (prev)
|
if (prev)
|
||||||
prev->next = item->next;
|
prev->next = item->next;
|
||||||
else
|
else
|
||||||
conn->timed_handlers = item->next;
|
conn->timed_handlers = item->next;
|
||||||
|
|
||||||
xmpp_free(conn->ctx, item);
|
xmpp_free(conn->ctx, item);
|
||||||
|
item = prev ? prev->next : conn->timed_handlers;
|
||||||
|
} else {
|
||||||
|
prev = item;
|
||||||
|
item = item->next;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -288,8 +304,10 @@ static void _id_handler_add(xmpp_conn_t * const conn,
|
|||||||
/* check if handler is already in the list */
|
/* check if handler is already in the list */
|
||||||
item = (xmpp_handlist_t *)hash_get(conn->id_handlers, id);
|
item = (xmpp_handlist_t *)hash_get(conn->id_handlers, id);
|
||||||
while (item) {
|
while (item) {
|
||||||
if (item->handler == (void *)handler)
|
if (item->handler == handler && item->userdata == userdata) {
|
||||||
|
xmpp_warn(conn->ctx, "xmpp", "Id handler already exists.");
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
item = item->next;
|
item = item->next;
|
||||||
}
|
}
|
||||||
if (item) return;
|
if (item) return;
|
||||||
@@ -299,13 +317,13 @@ static void _id_handler_add(xmpp_conn_t * const conn,
|
|||||||
if (!item) return;
|
if (!item) return;
|
||||||
|
|
||||||
item->user_handler = user_handler;
|
item->user_handler = user_handler;
|
||||||
item->handler = (void *)handler;
|
item->handler = handler;
|
||||||
item->userdata = userdata;
|
item->userdata = userdata;
|
||||||
item->enabled = 0;
|
item->enabled = 0;
|
||||||
item->next = NULL;
|
item->next = NULL;
|
||||||
|
|
||||||
item->id = xmpp_strdup(conn->ctx, id);
|
item->u.id = xmpp_strdup(conn->ctx, id);
|
||||||
if (!item->id) {
|
if (!item->u.id) {
|
||||||
xmpp_free(conn->ctx, item);
|
xmpp_free(conn->ctx, item);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -333,29 +351,30 @@ void xmpp_id_handler_delete(xmpp_conn_t * const conn,
|
|||||||
xmpp_handler handler,
|
xmpp_handler handler,
|
||||||
const char * const id)
|
const char * const id)
|
||||||
{
|
{
|
||||||
xmpp_handlist_t *item, *prev;
|
xmpp_handlist_t *item, *prev, *next;
|
||||||
|
|
||||||
prev = NULL;
|
prev = NULL;
|
||||||
item = (xmpp_handlist_t *)hash_get(conn->id_handlers, id);
|
item = (xmpp_handlist_t *)hash_get(conn->id_handlers, id);
|
||||||
if (!item) return;
|
if (!item) return;
|
||||||
|
|
||||||
while (item) {
|
while (item) {
|
||||||
if (item->handler == (void *)handler)
|
next = item->next;
|
||||||
break;
|
|
||||||
|
|
||||||
prev = item;
|
if (item->handler == handler) {
|
||||||
item = item->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item) {
|
|
||||||
if (prev)
|
if (prev)
|
||||||
prev->next = item->next;
|
prev->next = next;
|
||||||
else {
|
else {
|
||||||
hash_drop(conn->id_handlers, id);
|
hash_drop(conn->id_handlers, id);
|
||||||
hash_add(conn->id_handlers, id, item->next);
|
hash_add(conn->id_handlers, id, next);
|
||||||
}
|
}
|
||||||
xmpp_free(conn->ctx, item->id);
|
|
||||||
|
xmpp_free(conn->ctx, item->u.id);
|
||||||
xmpp_free(conn->ctx, item);
|
xmpp_free(conn->ctx, item);
|
||||||
|
item = next;
|
||||||
|
} else {
|
||||||
|
prev = item;
|
||||||
|
item = next;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -371,9 +390,13 @@ static void _handler_add(xmpp_conn_t * const conn,
|
|||||||
|
|
||||||
/* check if handler already in list */
|
/* check if handler already in list */
|
||||||
for (item = conn->handlers; item; item = item->next) {
|
for (item = conn->handlers; item; item = item->next) {
|
||||||
if (item->handler == (void *)handler)
|
/* same handler function can process different stanzas and
|
||||||
|
distinguish them according to userdata. */
|
||||||
|
if (item->handler == handler && item->userdata == userdata) {
|
||||||
|
xmpp_warn(conn->ctx, "xmpp", "Stanza handler already exists.");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (item) return;
|
if (item) return;
|
||||||
|
|
||||||
/* build new item */
|
/* build new item */
|
||||||
@@ -381,37 +404,37 @@ static void _handler_add(xmpp_conn_t * const conn,
|
|||||||
if (!item) return;
|
if (!item) return;
|
||||||
|
|
||||||
item->user_handler = user_handler;
|
item->user_handler = user_handler;
|
||||||
item->handler = (void *)handler;
|
item->handler = handler;
|
||||||
item->userdata = userdata;
|
item->userdata = userdata;
|
||||||
item->enabled = 0;
|
item->enabled = 0;
|
||||||
item->next = NULL;
|
item->next = NULL;
|
||||||
|
|
||||||
if (ns) {
|
if (ns) {
|
||||||
item->ns = xmpp_strdup(conn->ctx, ns);
|
item->u.ns = xmpp_strdup(conn->ctx, ns);
|
||||||
if (!item->ns) {
|
if (!item->u.ns) {
|
||||||
xmpp_free(conn->ctx, item);
|
xmpp_free(conn->ctx, item);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
item->ns = NULL;
|
item->u.ns = NULL;
|
||||||
if (name) {
|
if (name) {
|
||||||
item->name = xmpp_strdup(conn->ctx, name);
|
item->u.name = xmpp_strdup(conn->ctx, name);
|
||||||
if (!item->name) {
|
if (!item->u.name) {
|
||||||
if (item->ns) xmpp_free(conn->ctx, item->ns);
|
if (item->u.ns) xmpp_free(conn->ctx, item->u.ns);
|
||||||
xmpp_free(conn->ctx, item);
|
xmpp_free(conn->ctx, item);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
item->name = NULL;
|
item->u.name = NULL;
|
||||||
if (type) {
|
if (type) {
|
||||||
item->type = xmpp_strdup(conn->ctx, type);
|
item->u.type = xmpp_strdup(conn->ctx, type);
|
||||||
if (!item->type) {
|
if (!item->u.type) {
|
||||||
if (item->ns) xmpp_free(conn->ctx, item->ns);
|
if (item->u.ns) xmpp_free(conn->ctx, item->u.ns);
|
||||||
if (item->name) xmpp_free(conn->ctx, item->name);
|
if (item->u.name) xmpp_free(conn->ctx, item->u.name);
|
||||||
xmpp_free(conn->ctx, item);
|
xmpp_free(conn->ctx, item);
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
item->type = NULL;
|
item->u.type = NULL;
|
||||||
|
|
||||||
/* append to list */
|
/* append to list */
|
||||||
if (!conn->handlers)
|
if (!conn->handlers)
|
||||||
@@ -441,23 +464,21 @@ void xmpp_handler_delete(xmpp_conn_t * const conn,
|
|||||||
prev = NULL;
|
prev = NULL;
|
||||||
item = conn->handlers;
|
item = conn->handlers;
|
||||||
while (item) {
|
while (item) {
|
||||||
if (item->handler == (void *)handler)
|
if (item->handler == handler) {
|
||||||
break;
|
|
||||||
|
|
||||||
prev = item;
|
|
||||||
item = item->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item) {
|
|
||||||
if (prev)
|
if (prev)
|
||||||
prev->next = item->next;
|
prev->next = item->next;
|
||||||
else
|
else
|
||||||
conn->handlers = item->next;
|
conn->handlers = item->next;
|
||||||
|
|
||||||
if (item->ns) xmpp_free(conn->ctx, item->ns);
|
if (item->u.ns) xmpp_free(conn->ctx, item->u.ns);
|
||||||
if (item->name) xmpp_free(conn->ctx, item->name);
|
if (item->u.name) xmpp_free(conn->ctx, item->u.name);
|
||||||
if (item->type) xmpp_free(conn->ctx, item->type);
|
if (item->u.type) xmpp_free(conn->ctx, item->u.type);
|
||||||
xmpp_free(conn->ctx, item);
|
xmpp_free(conn->ctx, item);
|
||||||
|
item = prev ? prev->next : conn->handlers;
|
||||||
|
} else {
|
||||||
|
prev = item;
|
||||||
|
item = item->next;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -595,3 +616,75 @@ void handler_add(xmpp_conn_t * const conn,
|
|||||||
{
|
{
|
||||||
_handler_add(conn, handler, ns, name, type, userdata, 0);
|
_handler_add(conn, handler, ns, name, type, userdata, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Delete all system handlers.
|
||||||
|
* This function is used to reset conn object before re-connecting.
|
||||||
|
*
|
||||||
|
* @param conn a Strophe connection object
|
||||||
|
*/
|
||||||
|
void handler_system_delete_all(xmpp_conn_t *conn)
|
||||||
|
{
|
||||||
|
xmpp_handlist_t *item, *next, *head, *head_old;
|
||||||
|
hash_iterator_t *iter;
|
||||||
|
const char *key;
|
||||||
|
char *key2 = NULL;
|
||||||
|
|
||||||
|
/* TODO unify all kinds of handlers and avoid copy-paste below */
|
||||||
|
|
||||||
|
item = conn->handlers;
|
||||||
|
while (item) {
|
||||||
|
if (!item->user_handler) {
|
||||||
|
next = item->next;
|
||||||
|
_handler_item_remove(&conn->handlers, item);
|
||||||
|
if (item->u.ns) xmpp_free(conn->ctx, item->u.ns);
|
||||||
|
if (item->u.name) xmpp_free(conn->ctx, item->u.name);
|
||||||
|
if (item->u.type) xmpp_free(conn->ctx, item->u.type);
|
||||||
|
xmpp_free(conn->ctx, item);
|
||||||
|
item = next;
|
||||||
|
} else
|
||||||
|
item = item->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
item = conn->timed_handlers;
|
||||||
|
while (item) {
|
||||||
|
if (!item->user_handler) {
|
||||||
|
next = item->next;
|
||||||
|
_handler_item_remove(&conn->timed_handlers, item);
|
||||||
|
xmpp_free(conn->ctx, item);
|
||||||
|
item = next;
|
||||||
|
} else
|
||||||
|
item = item->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
iter = hash_iter_new(conn->id_handlers);
|
||||||
|
key = iter == NULL ? NULL : hash_iter_next(iter);
|
||||||
|
while (key != NULL) {
|
||||||
|
head = head_old = (xmpp_handlist_t *)hash_get(conn->id_handlers, key);
|
||||||
|
item = head;
|
||||||
|
while (item) {
|
||||||
|
if (!item->user_handler) {
|
||||||
|
next = item->next;
|
||||||
|
_handler_item_remove(&head, item);
|
||||||
|
xmpp_free(conn->ctx, item->u.id);
|
||||||
|
xmpp_free(conn->ctx, item);
|
||||||
|
item = next;
|
||||||
|
} else
|
||||||
|
item = item->next;
|
||||||
|
}
|
||||||
|
if (head != head_old)
|
||||||
|
key2 = xmpp_strdup(conn->ctx, key);
|
||||||
|
/* Hash table implementation is not perfect, so we need to find next
|
||||||
|
key before dropping current one. Otherwise, we will get access to
|
||||||
|
freed memory. */
|
||||||
|
key = hash_iter_next(iter);
|
||||||
|
if (head != head_old) {
|
||||||
|
/* hash_add() replaces value if the key exists */
|
||||||
|
if (head != NULL)
|
||||||
|
hash_add(conn->id_handlers, key2, head);
|
||||||
|
else
|
||||||
|
hash_drop(conn->id_handlers, key2);
|
||||||
|
xmpp_free(conn->ctx, key2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (iter) hash_iter_release(iter);
|
||||||
|
}
|
||||||
|
|||||||
61
src/hash.c
61
src/hash.c
@@ -106,18 +106,35 @@ void hash_release(hash_t * const table)
|
|||||||
/** hash a key for our table lookup */
|
/** hash a key for our table lookup */
|
||||||
static int _hash_key(hash_t *table, const char *key)
|
static int _hash_key(hash_t *table, const char *key)
|
||||||
{
|
{
|
||||||
int hash = 0;
|
unsigned hash = 0;
|
||||||
int shift = 0;
|
unsigned shift = 0;
|
||||||
const char *c = key;
|
const unsigned char *c = (const unsigned char *)key;
|
||||||
|
|
||||||
while (*c != '\0') {
|
while (*c != 0) {
|
||||||
/* assume 32 bit ints */
|
/* assume 32 bit ints */
|
||||||
hash ^= ((int)*c++ << shift);
|
hash ^= ((unsigned)*c++ << shift);
|
||||||
shift += 8;
|
shift += 8;
|
||||||
if (shift > 24) shift = 0;
|
if (shift > 24) shift = 0;
|
||||||
}
|
}
|
||||||
|
return hash % (unsigned)table->length;
|
||||||
|
}
|
||||||
|
|
||||||
return hash % table->length;
|
hashentry_t *_hash_entry_find(hash_t *table, const char *key)
|
||||||
|
{
|
||||||
|
hashentry_t *entry;
|
||||||
|
int table_index = _hash_key(table, key);
|
||||||
|
|
||||||
|
/* look up the hash entry */
|
||||||
|
entry = table->entries[table_index];
|
||||||
|
while (entry != NULL) {
|
||||||
|
/* traverse the linked list looking for the key */
|
||||||
|
if (!strcmp(key, entry->key)) {
|
||||||
|
/* match */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
entry = entry->next;
|
||||||
|
}
|
||||||
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** add a key, value pair to a hash table.
|
/** add a key, value pair to a hash table.
|
||||||
@@ -130,9 +147,10 @@ int hash_add(hash_t *table, const char * const key, void *data)
|
|||||||
hashentry_t *entry = NULL;
|
hashentry_t *entry = NULL;
|
||||||
int table_index = _hash_key(table, key);
|
int table_index = _hash_key(table, key);
|
||||||
|
|
||||||
/* drop existing entry, if any */
|
/* find and replace existing entry, if any */
|
||||||
hash_drop(table, key);
|
entry = _hash_entry_find(table, key);
|
||||||
|
|
||||||
|
if (entry == NULL) {
|
||||||
/* allocate and fill a new entry */
|
/* allocate and fill a new entry */
|
||||||
entry = xmpp_alloc(ctx, sizeof(hashentry_t));
|
entry = xmpp_alloc(ctx, sizeof(hashentry_t));
|
||||||
if (!entry) return -1;
|
if (!entry) return -1;
|
||||||
@@ -141,12 +159,15 @@ int hash_add(hash_t *table, const char * const key, void *data)
|
|||||||
xmpp_free(ctx, entry);
|
xmpp_free(ctx, entry);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
entry->value = data;
|
|
||||||
/* insert ourselves in the linked list */
|
/* insert ourselves in the linked list */
|
||||||
/* TODO: this leaks duplicate keys */
|
|
||||||
entry->next = table->entries[table_index];
|
entry->next = table->entries[table_index];
|
||||||
table->entries[table_index] = entry;
|
table->entries[table_index] = entry;
|
||||||
table->num_keys++;
|
table->num_keys++;
|
||||||
|
} else {
|
||||||
|
if (table->free) table->free(ctx, entry->value);
|
||||||
|
}
|
||||||
|
|
||||||
|
entry->value = data;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -155,22 +176,9 @@ int hash_add(hash_t *table, const char * const key, void *data)
|
|||||||
void *hash_get(hash_t *table, const char *key)
|
void *hash_get(hash_t *table, const char *key)
|
||||||
{
|
{
|
||||||
hashentry_t *entry;
|
hashentry_t *entry;
|
||||||
int table_index = _hash_key(table, key);
|
|
||||||
void *result = NULL;
|
|
||||||
|
|
||||||
/* look up the hash entry */
|
entry = _hash_entry_find(table, key);
|
||||||
entry = table->entries[table_index];
|
return entry == NULL ? NULL : entry->value;
|
||||||
while (entry != NULL) {
|
|
||||||
/* traverse the linked list looking for the key */
|
|
||||||
if (!strcmp(key, entry->key)) {
|
|
||||||
/* match */
|
|
||||||
result = entry->value;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
entry = entry->next;
|
|
||||||
}
|
|
||||||
/* no match */
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** delete a key from a hash table */
|
/** delete a key from a hash table */
|
||||||
@@ -235,7 +243,7 @@ void hash_iter_release(hash_iterator_t *iter)
|
|||||||
|
|
||||||
iter->ref--;
|
iter->ref--;
|
||||||
|
|
||||||
if (iter->ref <= 0) {
|
if (iter->ref == 0) { // ref is unsigned!!!
|
||||||
hash_release(iter->table);
|
hash_release(iter->table);
|
||||||
xmpp_free(ctx, iter);
|
xmpp_free(ctx, iter);
|
||||||
}
|
}
|
||||||
@@ -273,4 +281,3 @@ const char * hash_iter_next(hash_iterator_t *iter)
|
|||||||
iter->entry = entry;
|
iter->entry = entry;
|
||||||
return entry->key;
|
return entry->key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
41
src/jid.c
41
src/jid.c
@@ -72,15 +72,13 @@ char *xmpp_jid_new(xmpp_ctx_t *ctx, const char *node,
|
|||||||
char *xmpp_jid_bare(xmpp_ctx_t *ctx, const char *jid)
|
char *xmpp_jid_bare(xmpp_ctx_t *ctx, const char *jid)
|
||||||
{
|
{
|
||||||
char *result;
|
char *result;
|
||||||
const char *c;
|
size_t len;
|
||||||
|
|
||||||
c = strchr(jid, '/');
|
len = strcspn(jid, "/");
|
||||||
if (c == NULL) return xmpp_strdup(ctx, jid);
|
result = xmpp_alloc(ctx, len + 1);
|
||||||
|
|
||||||
result = xmpp_alloc(ctx, c-jid+1);
|
|
||||||
if (result != NULL) {
|
if (result != NULL) {
|
||||||
memcpy(result, jid, c-jid);
|
memcpy(result, jid, len);
|
||||||
result[c-jid] = '\0';
|
result[len] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@@ -121,7 +119,8 @@ char *xmpp_jid_node(xmpp_ctx_t *ctx, const char *jid)
|
|||||||
char *xmpp_jid_domain(xmpp_ctx_t *ctx, const char *jid)
|
char *xmpp_jid_domain(xmpp_ctx_t *ctx, const char *jid)
|
||||||
{
|
{
|
||||||
char *result = NULL;
|
char *result = NULL;
|
||||||
const char *c,*s;
|
const char *c;
|
||||||
|
size_t dlen;
|
||||||
|
|
||||||
c = strchr(jid, '@');
|
c = strchr(jid, '@');
|
||||||
if (c == NULL) {
|
if (c == NULL) {
|
||||||
@@ -131,15 +130,11 @@ char *xmpp_jid_domain(xmpp_ctx_t *ctx, const char *jid)
|
|||||||
/* advance past the separator */
|
/* advance past the separator */
|
||||||
c++;
|
c++;
|
||||||
}
|
}
|
||||||
s = strchr(c, '/');
|
dlen = strcspn(c, "/"); /* do not include resource */
|
||||||
if (s == NULL) {
|
result = xmpp_alloc(ctx, dlen + 1);
|
||||||
/* no resource */
|
|
||||||
s = c + strlen(c);
|
|
||||||
}
|
|
||||||
result = xmpp_alloc(ctx, (s-c) + 1);
|
|
||||||
if (result != NULL) {
|
if (result != NULL) {
|
||||||
memcpy(result, c, (s-c));
|
memcpy(result, c, dlen);
|
||||||
result[s-c] = '\0';
|
result[dlen] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@@ -155,20 +150,8 @@ char *xmpp_jid_domain(xmpp_ctx_t *ctx, const char *jid)
|
|||||||
*/
|
*/
|
||||||
char *xmpp_jid_resource(xmpp_ctx_t *ctx, const char *jid)
|
char *xmpp_jid_resource(xmpp_ctx_t *ctx, const char *jid)
|
||||||
{
|
{
|
||||||
char *result = NULL;
|
|
||||||
const char *c;
|
const char *c;
|
||||||
size_t len;
|
|
||||||
|
|
||||||
c = strchr(jid, '/');
|
c = strchr(jid, '/');
|
||||||
if (c != NULL) {
|
return c != NULL ? xmpp_strdup(ctx, c + 1) : NULL;
|
||||||
c++;
|
|
||||||
len = strlen(c);
|
|
||||||
result = xmpp_alloc(ctx, len + 1);
|
|
||||||
if (result != NULL) {
|
|
||||||
memcpy(result, c, len);
|
|
||||||
result[len] = '\0';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|||||||
14
src/md5.c
14
src/md5.c
@@ -43,8 +43,7 @@
|
|||||||
(cp)[3] = ((value) >> 24) & 0xFF; \
|
(cp)[3] = ((value) >> 24) & 0xFF; \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
static void MD5Transform(uint32_t buf[4], const unsigned char inext[64],
|
static void MD5Transform(uint32_t buf[4], const unsigned char inext[64]);
|
||||||
struct MD5Context *ctx);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
|
* Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
|
||||||
@@ -91,7 +90,7 @@ void MD5Update(struct MD5Context *ctx, unsigned char const *buf, uint32_t len)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
memcpy(p, buf, t);
|
memcpy(p, buf, t);
|
||||||
MD5Transform(ctx->buf, ctx->in, ctx);
|
MD5Transform(ctx->buf, ctx->in);
|
||||||
buf += t;
|
buf += t;
|
||||||
len -= t;
|
len -= t;
|
||||||
}
|
}
|
||||||
@@ -99,7 +98,7 @@ void MD5Update(struct MD5Context *ctx, unsigned char const *buf, uint32_t len)
|
|||||||
|
|
||||||
while (len >= 64) {
|
while (len >= 64) {
|
||||||
memcpy(ctx->in, buf, 64);
|
memcpy(ctx->in, buf, 64);
|
||||||
MD5Transform(ctx->buf, ctx->in, ctx);
|
MD5Transform(ctx->buf, ctx->in);
|
||||||
buf += 64;
|
buf += 64;
|
||||||
len -= 64;
|
len -= 64;
|
||||||
}
|
}
|
||||||
@@ -133,7 +132,7 @@ void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
|
|||||||
if (count < 8) {
|
if (count < 8) {
|
||||||
/* Two lots of padding: Pad the first block to 64 bytes */
|
/* Two lots of padding: Pad the first block to 64 bytes */
|
||||||
memset(p, 0, count);
|
memset(p, 0, count);
|
||||||
MD5Transform(ctx->buf, ctx->in, ctx);
|
MD5Transform(ctx->buf, ctx->in);
|
||||||
|
|
||||||
/* Now fill the next block with 56 bytes */
|
/* Now fill the next block with 56 bytes */
|
||||||
memset(ctx->in, 0, 56);
|
memset(ctx->in, 0, 56);
|
||||||
@@ -146,7 +145,7 @@ void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
|
|||||||
PUT_32BIT_LSB_FIRST(ctx->in + 56, ctx->bits[0]);
|
PUT_32BIT_LSB_FIRST(ctx->in + 56, ctx->bits[0]);
|
||||||
PUT_32BIT_LSB_FIRST(ctx->in + 60, ctx->bits[1]);
|
PUT_32BIT_LSB_FIRST(ctx->in + 60, ctx->bits[1]);
|
||||||
|
|
||||||
MD5Transform(ctx->buf, ctx->in, ctx);
|
MD5Transform(ctx->buf, ctx->in);
|
||||||
PUT_32BIT_LSB_FIRST(digest, ctx->buf[0]);
|
PUT_32BIT_LSB_FIRST(digest, ctx->buf[0]);
|
||||||
PUT_32BIT_LSB_FIRST(digest + 4, ctx->buf[1]);
|
PUT_32BIT_LSB_FIRST(digest + 4, ctx->buf[1]);
|
||||||
PUT_32BIT_LSB_FIRST(digest + 8, ctx->buf[2]);
|
PUT_32BIT_LSB_FIRST(digest + 8, ctx->buf[2]);
|
||||||
@@ -180,8 +179,7 @@ void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
|
|||||||
* reflect the addition of 16 longwords of new data. MD5Update blocks
|
* reflect the addition of 16 longwords of new data. MD5Update blocks
|
||||||
* the data and converts bytes into longwords for this routine.
|
* the data and converts bytes into longwords for this routine.
|
||||||
*/
|
*/
|
||||||
static void MD5Transform(uint32_t buf[4], const unsigned char inext[64],
|
static void MD5Transform(uint32_t buf[4], const unsigned char inext[64])
|
||||||
struct MD5Context *ctx)
|
|
||||||
{
|
{
|
||||||
register uint32_t a, b, c, d, i;
|
register uint32_t a, b, c, d, i;
|
||||||
uint32_t in[16];
|
uint32_t in[16];
|
||||||
|
|||||||
@@ -82,4 +82,3 @@ void XMPP::Context::callLog(void * const userdata,
|
|||||||
{
|
{
|
||||||
reinterpret_cast<Context *>(userdata)->log(level, area, msg);
|
reinterpret_cast<Context *>(userdata)->log(level, area, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -75,5 +75,3 @@ Stanza *Stanza::copy()
|
|||||||
// TODO
|
// TODO
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -19,12 +19,15 @@
|
|||||||
|
|
||||||
#include <expat.h>
|
#include <expat.h>
|
||||||
|
|
||||||
#include <strophe.h>
|
#include "strophe.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
|
|
||||||
/* Use the Unit Separator to delimit namespace and name in our XML*/
|
/* Allocate inner text by this number bytes more. Expat splits string
|
||||||
#define NAMESPACE_SEP ('\x1F')
|
* "new\nline" into 3 strings: "new" "\n" "line". Expecting this pattern,
|
||||||
|
* we can leave few bytes in the inner_text for "\n". It should reduce
|
||||||
|
* number of re-allocations in 2 times for multi-line texts. */
|
||||||
|
#define INNER_TEXT_PADDING 2
|
||||||
|
|
||||||
struct _parser_t {
|
struct _parser_t {
|
||||||
xmpp_ctx_t *ctx;
|
xmpp_ctx_t *ctx;
|
||||||
@@ -35,6 +38,51 @@ struct _parser_t {
|
|||||||
void *userdata;
|
void *userdata;
|
||||||
int depth;
|
int depth;
|
||||||
xmpp_stanza_t *stanza;
|
xmpp_stanza_t *stanza;
|
||||||
|
char* inner_text;
|
||||||
|
/* number of allocated bytes */
|
||||||
|
int inner_text_size;
|
||||||
|
/* excluding terminal '\0' */
|
||||||
|
int inner_text_used;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Use the Unit Separator to delimit namespace and name in our XML */
|
||||||
|
const XML_Char namespace_sep = '\x1F';
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Cached strophe ctx. It is used for memory suite.
|
||||||
|
* Note, expat doesn't support userdata in memory suite, therefore,
|
||||||
|
* we can support only one strophe context. If user creates more than one
|
||||||
|
* context, this module will fallback to default library allocator for all
|
||||||
|
* contexts other than mem_ctx.
|
||||||
|
*/
|
||||||
|
static xmpp_ctx_t *mem_ctx = NULL;
|
||||||
|
|
||||||
|
static void *parser_mem_malloc(size_t size)
|
||||||
|
{
|
||||||
|
if (mem_ctx != NULL)
|
||||||
|
return xmpp_alloc(mem_ctx, size);
|
||||||
|
else
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *parser_mem_realloc(void *ptr, size_t size)
|
||||||
|
{
|
||||||
|
if (mem_ctx != NULL)
|
||||||
|
return xmpp_realloc(mem_ctx, ptr, size);
|
||||||
|
else
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parser_mem_free(void *ptr)
|
||||||
|
{
|
||||||
|
if (mem_ctx != NULL)
|
||||||
|
xmpp_free(mem_ctx, ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const XML_Memory_Handling_Suite parser_mem_suite = {
|
||||||
|
.malloc_fcn = &parser_mem_malloc,
|
||||||
|
.realloc_fcn = &parser_mem_realloc,
|
||||||
|
.free_fcn = &parser_mem_free,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* return allocated string with the name from a delimited
|
/* return allocated string with the name from a delimited
|
||||||
@@ -45,7 +93,7 @@ static char *_xml_name(xmpp_ctx_t *ctx, const char *nsname)
|
|||||||
const char *c;
|
const char *c;
|
||||||
size_t len;
|
size_t len;
|
||||||
|
|
||||||
c = strchr(nsname, NAMESPACE_SEP);
|
c = strchr(nsname, namespace_sep);
|
||||||
if (c == NULL) return xmpp_strdup(ctx, nsname);
|
if (c == NULL) return xmpp_strdup(ctx, nsname);
|
||||||
|
|
||||||
c++;
|
c++;
|
||||||
@@ -65,7 +113,7 @@ static char *_xml_namespace(xmpp_ctx_t *ctx, const char *nsname)
|
|||||||
char *result = NULL;
|
char *result = NULL;
|
||||||
const char *c;
|
const char *c;
|
||||||
|
|
||||||
c = strchr(nsname, NAMESPACE_SEP);
|
c = strchr(nsname, namespace_sep);
|
||||||
if (c != NULL) {
|
if (c != NULL) {
|
||||||
result = xmpp_alloc(ctx, (c-nsname) + 1);
|
result = xmpp_alloc(ctx, (c-nsname) + 1);
|
||||||
if (result != NULL) {
|
if (result != NULL) {
|
||||||
@@ -92,6 +140,26 @@ static void _set_attributes(xmpp_stanza_t *stanza, const XML_Char **attrs)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void complete_inner_text(parser_t *parser)
|
||||||
|
{
|
||||||
|
xmpp_stanza_t *stanza;
|
||||||
|
|
||||||
|
if (parser->inner_text) {
|
||||||
|
/* create and populate stanza */
|
||||||
|
stanza = xmpp_stanza_new(parser->ctx);
|
||||||
|
/* FIXME: disconnect on allocation error */
|
||||||
|
if (stanza) {
|
||||||
|
xmpp_stanza_set_text(stanza, parser->inner_text);
|
||||||
|
xmpp_stanza_add_child(parser->stanza, stanza);
|
||||||
|
xmpp_stanza_release(stanza);
|
||||||
|
}
|
||||||
|
xmpp_free(parser->ctx, parser->inner_text);
|
||||||
|
parser->inner_text = NULL;
|
||||||
|
parser->inner_text_size = 0;
|
||||||
|
parser->inner_text_used = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void _start_element(void *userdata,
|
static void _start_element(void *userdata,
|
||||||
const XML_Char *nsname,
|
const XML_Char *nsname,
|
||||||
const XML_Char **attrs)
|
const XML_Char **attrs)
|
||||||
@@ -106,7 +174,7 @@ static void _start_element(void *userdata,
|
|||||||
if (parser->depth == 0) {
|
if (parser->depth == 0) {
|
||||||
/* notify the owner */
|
/* notify the owner */
|
||||||
if (parser->startcb)
|
if (parser->startcb)
|
||||||
parser->startcb((char *)name, (char **)attrs,
|
parser->startcb(name, (char **)attrs,
|
||||||
parser->userdata);
|
parser->userdata);
|
||||||
} else {
|
} else {
|
||||||
/* build stanzas at depth 1 */
|
/* build stanzas at depth 1 */
|
||||||
@@ -125,6 +193,7 @@ static void _start_element(void *userdata,
|
|||||||
xmpp_stanza_set_ns(child, ns);
|
xmpp_stanza_set_ns(child, ns);
|
||||||
|
|
||||||
if (parser->stanza != NULL) {
|
if (parser->stanza != NULL) {
|
||||||
|
complete_inner_text(parser);
|
||||||
xmpp_stanza_add_child(parser->stanza, child);
|
xmpp_stanza_add_child(parser->stanza, child);
|
||||||
xmpp_stanza_release(child);
|
xmpp_stanza_release(child);
|
||||||
}
|
}
|
||||||
@@ -149,6 +218,7 @@ static void _end_element(void *userdata, const XML_Char *name)
|
|||||||
if (parser->endcb)
|
if (parser->endcb)
|
||||||
parser->endcb((char *)name, parser->userdata);
|
parser->endcb((char *)name, parser->userdata);
|
||||||
} else {
|
} else {
|
||||||
|
complete_inner_text(parser);
|
||||||
if (parser->stanza->parent) {
|
if (parser->stanza->parent) {
|
||||||
/* we're finishing a child stanza, so set current to the parent */
|
/* we're finishing a child stanza, so set current to the parent */
|
||||||
parser->stanza = parser->stanza->parent;
|
parser->stanza = parser->stanza->parent;
|
||||||
@@ -165,20 +235,29 @@ static void _end_element(void *userdata, const XML_Char *name)
|
|||||||
static void _characters(void *userdata, const XML_Char *s, int len)
|
static void _characters(void *userdata, const XML_Char *s, int len)
|
||||||
{
|
{
|
||||||
parser_t *parser = (parser_t *)userdata;
|
parser_t *parser = (parser_t *)userdata;
|
||||||
xmpp_stanza_t *stanza;
|
char *p;
|
||||||
|
|
||||||
if (parser->depth < 2) return;
|
if (parser->depth < 2) return;
|
||||||
|
|
||||||
/* create and populate stanza */
|
/* Join all parts to a single resulting string. Stanza is created in
|
||||||
stanza = xmpp_stanza_new(parser->ctx);
|
* _start_element() and _end_element(). */
|
||||||
if (!stanza) {
|
if (parser->inner_text_used + len >= parser->inner_text_size) {
|
||||||
/* FIXME: allocation error, disconnect */
|
parser->inner_text_size = parser->inner_text_used + len + 1 +
|
||||||
|
INNER_TEXT_PADDING;
|
||||||
|
p = xmpp_realloc(parser->ctx, parser->inner_text,
|
||||||
|
parser->inner_text_size);
|
||||||
|
if (p == NULL) {
|
||||||
|
xmpp_free(parser->ctx, parser->inner_text);
|
||||||
|
parser->inner_text = NULL;
|
||||||
|
parser->inner_text_used = 0;
|
||||||
|
parser->inner_text_size = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
xmpp_stanza_set_text_with_size(stanza, s, len);
|
parser->inner_text = p;
|
||||||
|
parser->inner_text[parser->inner_text_used] = '\0';
|
||||||
xmpp_stanza_add_child(parser->stanza, stanza);
|
}
|
||||||
xmpp_stanza_release(stanza);
|
parser->inner_text_used += len;
|
||||||
|
strncat(parser->inner_text, s, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
parser_t *parser_new(xmpp_ctx_t *ctx,
|
parser_t *parser_new(xmpp_ctx_t *ctx,
|
||||||
@@ -199,6 +278,9 @@ parser_t *parser_new(xmpp_ctx_t *ctx,
|
|||||||
parser->userdata = userdata;
|
parser->userdata = userdata;
|
||||||
parser->depth = 0;
|
parser->depth = 0;
|
||||||
parser->stanza = NULL;
|
parser->stanza = NULL;
|
||||||
|
parser->inner_text = NULL;
|
||||||
|
parser->inner_text_size = 0;
|
||||||
|
parser->inner_text_used = 0;
|
||||||
|
|
||||||
parser_reset(parser);
|
parser_reset(parser);
|
||||||
}
|
}
|
||||||
@@ -217,23 +299,48 @@ void parser_free(parser_t *parser)
|
|||||||
if (parser->expat)
|
if (parser->expat)
|
||||||
XML_ParserFree(parser->expat);
|
XML_ParserFree(parser->expat);
|
||||||
|
|
||||||
|
if (parser->inner_text) {
|
||||||
|
xmpp_free (parser->ctx, parser->inner_text);
|
||||||
|
parser->inner_text = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
xmpp_free(parser->ctx, parser);
|
xmpp_free(parser->ctx, parser);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* shuts down and restarts XML parser. true on success */
|
/* shuts down and restarts XML parser. true on success */
|
||||||
int parser_reset(parser_t *parser)
|
int parser_reset(parser_t *parser)
|
||||||
{
|
{
|
||||||
if (parser->expat)
|
XML_Bool ret;
|
||||||
|
const XML_Memory_Handling_Suite *mem = NULL;
|
||||||
|
|
||||||
|
if (parser->expat) {
|
||||||
|
ret = XML_ParserReset(parser->expat, NULL);
|
||||||
|
if (ret != XML_TRUE) {
|
||||||
XML_ParserFree(parser->expat);
|
XML_ParserFree(parser->expat);
|
||||||
|
parser->expat = NULL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (mem_ctx == NULL)
|
||||||
|
mem_ctx = parser->ctx;
|
||||||
|
if (parser->ctx == mem_ctx)
|
||||||
|
mem = &parser_mem_suite;
|
||||||
|
parser->expat = XML_ParserCreate_MM(NULL, mem, &namespace_sep);
|
||||||
|
}
|
||||||
|
|
||||||
if (parser->stanza)
|
if (parser->stanza) {
|
||||||
xmpp_stanza_release(parser->stanza);
|
xmpp_stanza_release(parser->stanza);
|
||||||
|
parser->stanza = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
parser->expat = XML_ParserCreateNS(NULL, NAMESPACE_SEP);
|
if (parser->inner_text) {
|
||||||
if (!parser->expat) return 0;
|
xmpp_free(parser->ctx, parser->inner_text);
|
||||||
|
parser->inner_text = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!parser->expat)
|
||||||
|
return 0;
|
||||||
|
|
||||||
parser->depth = 0;
|
parser->depth = 0;
|
||||||
parser->stanza = NULL;
|
|
||||||
|
|
||||||
XML_SetUserData(parser->expat, parser);
|
XML_SetUserData(parser->expat, parser);
|
||||||
XML_SetElementHandler(parser->expat, _start_element, _end_element);
|
XML_SetElementHandler(parser->expat, _start_element, _end_element);
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
#include <libxml/parser.h>
|
#include <libxml/parser.h>
|
||||||
#include <libxml/tree.h>
|
#include <libxml/tree.h>
|
||||||
|
|
||||||
#include <strophe.h>
|
#include "strophe.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
|
|
||||||
@@ -116,11 +116,12 @@ static void _start_element(void *userdata,
|
|||||||
|
|
||||||
if (parser->depth == 0) {
|
if (parser->depth == 0) {
|
||||||
/* notify the owner */
|
/* notify the owner */
|
||||||
if (parser->startcb)
|
if (parser->startcb) {
|
||||||
cbattrs = _convert_attrs(parser, nattrs, attrs);
|
cbattrs = _convert_attrs(parser, nattrs, attrs);
|
||||||
parser->startcb((char *)name, cbattrs,
|
parser->startcb((char *)name, cbattrs,
|
||||||
parser->userdata);
|
parser->userdata);
|
||||||
_free_cbattrs(parser, cbattrs);
|
_free_cbattrs(parser, cbattrs);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
/* build stanzas at depth 1 */
|
/* build stanzas at depth 1 */
|
||||||
if (!parser->stanza && parser->depth != 1) {
|
if (!parser->stanza && parser->depth != 1) {
|
||||||
@@ -248,6 +249,8 @@ void parser_free(parser_t *parser)
|
|||||||
{
|
{
|
||||||
if (parser->xmlctx)
|
if (parser->xmlctx)
|
||||||
xmlFreeParserCtxt(parser->xmlctx);
|
xmlFreeParserCtxt(parser->xmlctx);
|
||||||
|
if (parser->stanza)
|
||||||
|
xmpp_stanza_release(parser->stanza);
|
||||||
xmpp_free(parser->ctx, parser);
|
xmpp_free(parser->ctx, parser);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -256,18 +259,16 @@ int parser_reset(parser_t *parser)
|
|||||||
{
|
{
|
||||||
if (parser->xmlctx)
|
if (parser->xmlctx)
|
||||||
xmlFreeParserCtxt(parser->xmlctx);
|
xmlFreeParserCtxt(parser->xmlctx);
|
||||||
|
|
||||||
if (parser->stanza)
|
if (parser->stanza)
|
||||||
xmpp_stanza_release(parser->stanza);
|
xmpp_stanza_release(parser->stanza);
|
||||||
|
|
||||||
|
parser->stanza = NULL;
|
||||||
|
parser->depth = 0;
|
||||||
|
|
||||||
parser->xmlctx = xmlCreatePushParserCtxt(&parser->handlers,
|
parser->xmlctx = xmlCreatePushParserCtxt(&parser->handlers,
|
||||||
parser, NULL, 0, NULL);
|
parser, NULL, 0, NULL);
|
||||||
if (!parser->xmlctx) return 0;
|
|
||||||
|
|
||||||
parser->depth = 0;
|
return parser->xmlctx ? 1 : 0;
|
||||||
parser->stanza = NULL;
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* feed a chunk of data to the parser */
|
/* feed a chunk of data to the parser */
|
||||||
@@ -275,9 +276,5 @@ int parser_feed(parser_t *parser, char *chunk, int len)
|
|||||||
{
|
{
|
||||||
/* xmlParseChunk API returns 0 on success which is opposite logic to
|
/* xmlParseChunk API returns 0 on success which is opposite logic to
|
||||||
the status returned by parser_feed */
|
the status returned by parser_feed */
|
||||||
if(!xmlParseChunk(parser->xmlctx, chunk, len, 0)) {
|
return !xmlParseChunk(parser->xmlctx, chunk, len, 0);
|
||||||
return 1;
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
37
src/rand.c
37
src/rand.c
@@ -127,8 +127,10 @@ static void Hash_DRBG_Instantiate(Hash_DRBG_CTX *ctx,
|
|||||||
|
|
||||||
assert(entropy_input_len <= ENTROPY_MAX);
|
assert(entropy_input_len <= ENTROPY_MAX);
|
||||||
assert(nonce_len <= NONCE_MAX);
|
assert(nonce_len <= NONCE_MAX);
|
||||||
|
assert(nonce != NULL || nonce_len == 0);
|
||||||
|
|
||||||
memcpy(seed_material, entropy_input, entropy_input_len);
|
memcpy(seed_material, entropy_input, entropy_input_len);
|
||||||
|
if (nonce != NULL)
|
||||||
memcpy(seed_material + entropy_input_len, nonce, nonce_len);
|
memcpy(seed_material + entropy_input_len, nonce, nonce_len);
|
||||||
Hash_df(seed_material, entropy_input_len + nonce_len, seed, seedlen);
|
Hash_df(seed_material, entropy_input_len + nonce_len, seed, seedlen);
|
||||||
seed0[0] = 0;
|
seed0[0] = 0;
|
||||||
@@ -287,25 +289,32 @@ int xmpp_rand(xmpp_rand_t *rand)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void rand_byte2hex(unsigned char byte, char *hex)
|
||||||
|
{
|
||||||
|
static const char hex_tbl[16] = { '0', '1', '2', '3', '4', '5', '6', '7',
|
||||||
|
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
|
||||||
|
|
||||||
|
hex[0] = hex_tbl[(byte >> 4) & 0x0f];
|
||||||
|
hex[1] = hex_tbl[byte & 0x0f];
|
||||||
|
}
|
||||||
|
|
||||||
void xmpp_rand_nonce(xmpp_rand_t *rand, char *output, size_t len)
|
void xmpp_rand_nonce(xmpp_rand_t *rand, char *output, size_t len)
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
size_t rand_len = len / 2;
|
const size_t rand_len = len / 2;
|
||||||
#ifndef _MSC_VER
|
|
||||||
unsigned char rand_buf[rand_len];
|
|
||||||
#else
|
|
||||||
unsigned char *rand_buf = (unsigned char *)_alloca(rand_len);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* current implementation returns printable HEX representation of
|
/*
|
||||||
* a random buffer, however base64 encoding can be used instead;
|
* We don't want to use any allocation here, because this function
|
||||||
* the only problem is that base64_encode() allocates memory and
|
* can't fail. Also we want to avoid VLA.
|
||||||
* as result can fail.
|
* Current implementation uses half of the output buffer for random buffer
|
||||||
|
* generation and then converts it to HEX representation.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
xmpp_rand_bytes(rand, rand_buf, rand_len);
|
if (rand_len > 0) {
|
||||||
for (i = 0; i < rand_len; ++i) {
|
xmpp_rand_bytes(rand, (unsigned char *)output, rand_len);
|
||||||
xmpp_snprintf(output + i * 2, len, "%02x", rand_buf[i]);
|
for (i = rand_len; i > 0; --i)
|
||||||
len -= 2;
|
rand_byte2hex(output[i - 1], &output[(i - 1) * 2]);
|
||||||
}
|
}
|
||||||
|
if (len > 0)
|
||||||
|
output[len - 1] = '\0';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ xmpp_rand_t *xmpp_rand_new(xmpp_ctx_t *ctx);
|
|||||||
*/
|
*/
|
||||||
void xmpp_rand_free(xmpp_ctx_t *ctx, xmpp_rand_t *rand);
|
void xmpp_rand_free(xmpp_ctx_t *ctx, xmpp_rand_t *rand);
|
||||||
|
|
||||||
/** Generate random integer
|
/** Generate random integer.
|
||||||
* Analogue of rand(3).
|
* Analogue of rand(3).
|
||||||
*
|
*
|
||||||
* @ingroup Random
|
* @ingroup Random
|
||||||
|
|||||||
407
src/resolver.c
407
src/resolver.c
@@ -1,4 +1,4 @@
|
|||||||
/* resolver.h
|
/* resolver.c
|
||||||
* strophe XMPP client library -- DNS resolver
|
* strophe XMPP client library -- DNS resolver
|
||||||
*
|
*
|
||||||
* Copyright (C) 2015 Dmitry Podgorny <pasis.ua@gmail.com>
|
* Copyright (C) 2015 Dmitry Podgorny <pasis.ua@gmail.com>
|
||||||
@@ -13,11 +13,23 @@
|
|||||||
* DNS resolver.
|
* DNS resolver.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _WIN32
|
#if !defined(_WIN32) && !defined(HAVE_CARES)
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <arpa/nameser.h>
|
#include <arpa/nameser.h>
|
||||||
#include <resolv.h> /* res_query */
|
#include <resolv.h> /* res_query */
|
||||||
#endif /* _WIN32 */
|
#endif /* _WIN32 && HAVE_CARES */
|
||||||
|
|
||||||
|
#ifdef HAVE_CARES
|
||||||
|
#include <ares.h>
|
||||||
|
/* for select(2) */
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <winsock2.h>
|
||||||
|
#else /* _WIN32 */
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif /* !_WIN32 */
|
||||||
|
#endif /* HAVE_CARES */
|
||||||
|
|
||||||
#include <string.h> /* strncpy */
|
#include <string.h> /* strncpy */
|
||||||
|
|
||||||
@@ -31,6 +43,189 @@
|
|||||||
#define MESSAGE_T_SRV 33
|
#define MESSAGE_T_SRV 33
|
||||||
#define MESSAGE_C_IN 1
|
#define MESSAGE_C_IN 1
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Forward declarations.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#ifdef HAVE_CARES
|
||||||
|
static int resolver_ares_srv_lookup_buf(xmpp_ctx_t *ctx,
|
||||||
|
const unsigned char *buf,
|
||||||
|
size_t len,
|
||||||
|
resolver_srv_rr_t **srv_rr_list);
|
||||||
|
static int resolver_ares_srv_lookup(xmpp_ctx_t *ctx, const char *fulldomain,
|
||||||
|
resolver_srv_rr_t **srv_rr_list);
|
||||||
|
#endif /* HAVE_CARES */
|
||||||
|
|
||||||
|
#ifndef HAVE_CARES
|
||||||
|
static int resolver_raw_srv_lookup_buf(xmpp_ctx_t *ctx,
|
||||||
|
const unsigned char *buf,
|
||||||
|
size_t len,
|
||||||
|
resolver_srv_rr_t **srv_rr_list);
|
||||||
|
#endif /* !HAVE_CARES */
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
static int resolver_win32_srv_lookup(xmpp_ctx_t *ctx, const char *fulldomain,
|
||||||
|
resolver_srv_rr_t **srv_rr_list);
|
||||||
|
static int resolver_win32_srv_query(const char *fulldomain,
|
||||||
|
unsigned char *buf, size_t len);
|
||||||
|
#endif /* _WIN32 */
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Implementation.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
void resolver_initialize(void)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_CARES
|
||||||
|
ares_library_init(ARES_LIB_INIT_ALL);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void resolver_shutdown(void)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_CARES
|
||||||
|
ares_library_cleanup();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void resolver_srv_list_sort(resolver_srv_rr_t **srv_rr_list)
|
||||||
|
{
|
||||||
|
resolver_srv_rr_t *rr_head;
|
||||||
|
resolver_srv_rr_t *rr_current;
|
||||||
|
resolver_srv_rr_t *rr_next;
|
||||||
|
resolver_srv_rr_t *rr_prev;
|
||||||
|
int swap;
|
||||||
|
|
||||||
|
rr_head = *srv_rr_list;
|
||||||
|
|
||||||
|
if ((rr_head == NULL) || (rr_head->next == NULL)) {
|
||||||
|
/* Empty or single record list */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
rr_prev = NULL;
|
||||||
|
rr_current = rr_head;
|
||||||
|
rr_next = rr_head->next;
|
||||||
|
swap = 0;
|
||||||
|
while (rr_next != NULL) {
|
||||||
|
/*
|
||||||
|
* RFC2052: A client MUST attempt to contact the target host
|
||||||
|
* with the lowest-numbered priority it can reach.
|
||||||
|
* RFC2052: When selecting a target host among the
|
||||||
|
* those that have the same priority, the chance of trying
|
||||||
|
* this one first SHOULD be proportional to its weight.
|
||||||
|
*/
|
||||||
|
if ((rr_current->priority > rr_next->priority) ||
|
||||||
|
(rr_current->priority == rr_next->priority &&
|
||||||
|
rr_current->weight < rr_next->weight))
|
||||||
|
{
|
||||||
|
/* Swap node */
|
||||||
|
swap = 1;
|
||||||
|
if (rr_prev != NULL) {
|
||||||
|
rr_prev->next = rr_next;
|
||||||
|
} else {
|
||||||
|
/* Swap head node */
|
||||||
|
rr_head = rr_next;
|
||||||
|
}
|
||||||
|
rr_current->next = rr_next->next;
|
||||||
|
rr_next->next = rr_current;
|
||||||
|
|
||||||
|
rr_prev = rr_next;
|
||||||
|
rr_next = rr_current->next;
|
||||||
|
} else {
|
||||||
|
/* Next node */
|
||||||
|
rr_prev = rr_current;
|
||||||
|
rr_current = rr_next;
|
||||||
|
rr_next = rr_next->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (swap != 0);
|
||||||
|
|
||||||
|
*srv_rr_list = rr_head;
|
||||||
|
}
|
||||||
|
|
||||||
|
int resolver_srv_lookup_buf(xmpp_ctx_t *ctx, const unsigned char *buf,
|
||||||
|
size_t len, resolver_srv_rr_t **srv_rr_list)
|
||||||
|
{
|
||||||
|
int set;
|
||||||
|
|
||||||
|
#ifdef HAVE_CARES
|
||||||
|
set = resolver_ares_srv_lookup_buf(ctx, buf, len, srv_rr_list);
|
||||||
|
#else
|
||||||
|
set = resolver_raw_srv_lookup_buf(ctx, buf, len, srv_rr_list);
|
||||||
|
#endif
|
||||||
|
resolver_srv_list_sort(srv_rr_list);
|
||||||
|
|
||||||
|
return set;
|
||||||
|
}
|
||||||
|
|
||||||
|
int resolver_srv_lookup(xmpp_ctx_t *ctx, const char *service, const char *proto,
|
||||||
|
const char *domain, resolver_srv_rr_t **srv_rr_list)
|
||||||
|
{
|
||||||
|
#define RESOLVER_BUF_MAX 65536
|
||||||
|
unsigned char *buf;
|
||||||
|
char fulldomain[2048];
|
||||||
|
int len;
|
||||||
|
int set = XMPP_DOMAIN_NOT_FOUND;
|
||||||
|
|
||||||
|
(void)buf;
|
||||||
|
(void)len;
|
||||||
|
|
||||||
|
xmpp_snprintf(fulldomain, sizeof(fulldomain),
|
||||||
|
"_%s._%s.%s", service, proto, domain);
|
||||||
|
|
||||||
|
*srv_rr_list = NULL;
|
||||||
|
|
||||||
|
#ifdef HAVE_CARES
|
||||||
|
set = resolver_ares_srv_lookup(ctx, fulldomain, srv_rr_list);
|
||||||
|
#else /* HAVE_CARES */
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
set = resolver_win32_srv_lookup(ctx, fulldomain, srv_rr_list);
|
||||||
|
if (set == XMPP_DOMAIN_FOUND)
|
||||||
|
return set;
|
||||||
|
#endif /* _WIN32 */
|
||||||
|
|
||||||
|
buf = xmpp_alloc(ctx, RESOLVER_BUF_MAX);
|
||||||
|
if (buf == NULL)
|
||||||
|
return XMPP_DOMAIN_NOT_FOUND;
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
len = resolver_win32_srv_query(fulldomain, buf, RESOLVER_BUF_MAX);
|
||||||
|
#else /* _WIN32 */
|
||||||
|
len = res_query(fulldomain, MESSAGE_C_IN, MESSAGE_T_SRV, buf,
|
||||||
|
RESOLVER_BUF_MAX);
|
||||||
|
#endif /* _WIN32 */
|
||||||
|
|
||||||
|
if (len > 0)
|
||||||
|
set = resolver_srv_lookup_buf(ctx, buf, (size_t)len, srv_rr_list);
|
||||||
|
|
||||||
|
xmpp_free(ctx, buf);
|
||||||
|
|
||||||
|
#endif /* HAVE_CARES */
|
||||||
|
|
||||||
|
return set;
|
||||||
|
}
|
||||||
|
|
||||||
|
void resolver_srv_free(xmpp_ctx_t *ctx, resolver_srv_rr_t *srv_rr_list)
|
||||||
|
{
|
||||||
|
resolver_srv_rr_t *rr;
|
||||||
|
|
||||||
|
while (srv_rr_list != NULL) {
|
||||||
|
rr = srv_rr_list->next;
|
||||||
|
xmpp_free(ctx, srv_rr_list);
|
||||||
|
srv_rr_list = rr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef HAVE_CARES
|
||||||
|
/*******************************************************************************
|
||||||
|
* Resolver raw implementation.
|
||||||
|
*
|
||||||
|
* This code is common for both unix and win32.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
struct message_header {
|
struct message_header {
|
||||||
uint16_t id;
|
uint16_t id;
|
||||||
uint8_t octet2;
|
uint8_t octet2;
|
||||||
@@ -41,13 +236,6 @@ struct message_header {
|
|||||||
uint16_t arcount;
|
uint16_t arcount;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
static int resolver_win32_srv_lookup(xmpp_ctx_t *ctx, const char *fulldomain,
|
|
||||||
resolver_srv_rr_t **srv_rr_list);
|
|
||||||
static int resolver_win32_srv_query(const char *fulldomain,
|
|
||||||
unsigned char *buf, size_t len);
|
|
||||||
#endif /* _WIN32 */
|
|
||||||
|
|
||||||
/* the same as ntohs(), but receives pointer to the value */
|
/* the same as ntohs(), but receives pointer to the value */
|
||||||
static uint16_t xmpp_ntohs_ptr(const void *ptr)
|
static uint16_t xmpp_ntohs_ptr(const void *ptr)
|
||||||
{
|
{
|
||||||
@@ -80,7 +268,7 @@ static size_t message_name_append_safe(char *name, size_t name_len,
|
|||||||
copy_len = name_max > name_len ? name_max - name_len : 0;
|
copy_len = name_max > name_len ? name_max - name_len : 0;
|
||||||
copy_len = xmpp_min(tail_len, copy_len);
|
copy_len = xmpp_min(tail_len, copy_len);
|
||||||
if (copy_len > 0)
|
if (copy_len > 0)
|
||||||
strncpy(&name[name_len], tail, copy_len);
|
memcpy(&name[name_len], tail, copy_len);
|
||||||
|
|
||||||
return name_len + tail_len;
|
return name_len + tail_len;
|
||||||
}
|
}
|
||||||
@@ -160,63 +348,6 @@ static unsigned message_name_len(const unsigned char *buf, size_t buf_len,
|
|||||||
return message_name_get(buf, buf_len, buf_offset, NULL, SIZE_MAX);
|
return message_name_get(buf, buf_len, buf_offset, NULL, SIZE_MAX);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void resolver_srv_list_sort(resolver_srv_rr_t **srv_rr_list)
|
|
||||||
{
|
|
||||||
resolver_srv_rr_t * rr_head;
|
|
||||||
resolver_srv_rr_t * rr_current;
|
|
||||||
resolver_srv_rr_t * rr_next;
|
|
||||||
resolver_srv_rr_t * rr_prev;
|
|
||||||
int swap;
|
|
||||||
|
|
||||||
rr_head = *srv_rr_list;
|
|
||||||
|
|
||||||
if ((rr_head == NULL) || (rr_head->next == NULL)) {
|
|
||||||
/* Empty or single record list */
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
do {
|
|
||||||
rr_prev = NULL;
|
|
||||||
rr_current = rr_head;
|
|
||||||
rr_next = rr_head->next;
|
|
||||||
swap = 0;
|
|
||||||
while (rr_next != NULL) {
|
|
||||||
/*
|
|
||||||
* RFC2052: A client MUST attempt to contact the target host
|
|
||||||
* with the lowest-numbered priority it can reach.
|
|
||||||
* RFC2052: When selecting a target host among the
|
|
||||||
* those that have the same priority, the chance of trying
|
|
||||||
* this one first SHOULD be proportional to its weight.
|
|
||||||
*/
|
|
||||||
if ((rr_current->priority > rr_next->priority) ||
|
|
||||||
(rr_current->priority == rr_next->priority &&
|
|
||||||
rr_current->weight < rr_next->weight))
|
|
||||||
{
|
|
||||||
/* Swap node */
|
|
||||||
swap = 1;
|
|
||||||
if (rr_prev != NULL) {
|
|
||||||
rr_prev->next = rr_next;
|
|
||||||
} else {
|
|
||||||
/* Swap head node */
|
|
||||||
rr_head = rr_next;
|
|
||||||
}
|
|
||||||
rr_current->next = rr_next->next;
|
|
||||||
rr_next->next = rr_current;
|
|
||||||
|
|
||||||
rr_prev = rr_next;
|
|
||||||
rr_next = rr_current->next;
|
|
||||||
} else {
|
|
||||||
/* Next node */
|
|
||||||
rr_prev = rr_current;
|
|
||||||
rr_current = rr_next;
|
|
||||||
rr_next = rr_next->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while (swap != 0);
|
|
||||||
|
|
||||||
*srv_rr_list = rr_head;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define BUF_OVERFLOW_CHECK(ptr, len) do { \
|
#define BUF_OVERFLOW_CHECK(ptr, len) do { \
|
||||||
if ((ptr) >= (len)) { \
|
if ((ptr) >= (len)) { \
|
||||||
if (*srv_rr_list != NULL) \
|
if (*srv_rr_list != NULL) \
|
||||||
@@ -226,8 +357,10 @@ static void resolver_srv_list_sort(resolver_srv_rr_t **srv_rr_list)
|
|||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
int resolver_srv_lookup_buf(xmpp_ctx_t *ctx, const unsigned char *buf,
|
static int resolver_raw_srv_lookup_buf(xmpp_ctx_t *ctx,
|
||||||
size_t len, resolver_srv_rr_t **srv_rr_list)
|
const unsigned char *buf,
|
||||||
|
size_t len,
|
||||||
|
resolver_srv_rr_t **srv_rr_list)
|
||||||
{
|
{
|
||||||
unsigned i;
|
unsigned i;
|
||||||
unsigned j;
|
unsigned j;
|
||||||
@@ -292,52 +425,110 @@ int resolver_srv_lookup_buf(xmpp_ctx_t *ctx, const unsigned char *buf,
|
|||||||
}
|
}
|
||||||
j += rdlength;
|
j += rdlength;
|
||||||
}
|
}
|
||||||
resolver_srv_list_sort(srv_rr_list);
|
|
||||||
|
|
||||||
return *srv_rr_list != NULL ? XMPP_DOMAIN_FOUND : XMPP_DOMAIN_NOT_FOUND;
|
return *srv_rr_list != NULL ? XMPP_DOMAIN_FOUND : XMPP_DOMAIN_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
int resolver_srv_lookup(xmpp_ctx_t *ctx, const char *service, const char *proto,
|
#endif /* !HAVE_CARES */
|
||||||
const char *domain, resolver_srv_rr_t **srv_rr_list)
|
|
||||||
{
|
|
||||||
char fulldomain[2048];
|
|
||||||
unsigned char buf[65535];
|
|
||||||
int len;
|
|
||||||
int set = XMPP_DOMAIN_NOT_FOUND;
|
|
||||||
|
|
||||||
xmpp_snprintf(fulldomain, sizeof(fulldomain),
|
#ifdef HAVE_CARES
|
||||||
"_%s._%s.%s", service, proto, domain);
|
/*******************************************************************************
|
||||||
|
* Resolver implementation using c-ares library.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
struct resolver_ares_ctx {
|
||||||
|
xmpp_ctx_t *ctx;
|
||||||
|
int result;
|
||||||
|
resolver_srv_rr_t *srv_rr_list;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int resolver_ares_srv_lookup_buf(xmpp_ctx_t *ctx,
|
||||||
|
const unsigned char *buf,
|
||||||
|
size_t len,
|
||||||
|
resolver_srv_rr_t **srv_rr_list)
|
||||||
|
{
|
||||||
|
struct ares_srv_reply *srv;
|
||||||
|
struct ares_srv_reply *item;
|
||||||
|
resolver_srv_rr_t *rr;
|
||||||
|
int rc;
|
||||||
|
|
||||||
*srv_rr_list = NULL;
|
*srv_rr_list = NULL;
|
||||||
|
|
||||||
#ifdef _WIN32
|
rc = ares_parse_srv_reply(buf, len, &srv);
|
||||||
set = resolver_win32_srv_lookup(ctx, fulldomain, srv_rr_list);
|
if (rc != ARES_SUCCESS)
|
||||||
if (set == XMPP_DOMAIN_FOUND)
|
return XMPP_DOMAIN_NOT_FOUND;
|
||||||
return set;
|
|
||||||
len = resolver_win32_srv_query(fulldomain, buf, sizeof(buf));
|
|
||||||
#else /* _WIN32 */
|
|
||||||
len = res_query(fulldomain, MESSAGE_C_IN, MESSAGE_T_SRV, buf, sizeof(buf));
|
|
||||||
#endif /* _WIN32 */
|
|
||||||
|
|
||||||
if (len > 0)
|
item = srv;
|
||||||
set = resolver_srv_lookup_buf(ctx, buf, (size_t)len, srv_rr_list);
|
while (item != NULL) {
|
||||||
|
rr = xmpp_alloc(ctx, sizeof(*rr));
|
||||||
|
if (rr == NULL)
|
||||||
|
break;
|
||||||
|
rr->next = *srv_rr_list;
|
||||||
|
rr->priority = item->priority;
|
||||||
|
rr->weight = item->weight;
|
||||||
|
rr->port = item->port;
|
||||||
|
strncpy(rr->target, item->host, sizeof(rr->target) - 1);
|
||||||
|
rr->target[sizeof(rr->target) - 1] = '\0';
|
||||||
|
*srv_rr_list = rr;
|
||||||
|
item = item->next;
|
||||||
|
}
|
||||||
|
ares_free_data(srv);
|
||||||
|
|
||||||
return set;
|
return *srv_rr_list == NULL ? XMPP_DOMAIN_NOT_FOUND : XMPP_DOMAIN_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
void resolver_srv_free(xmpp_ctx_t *ctx, resolver_srv_rr_t *srv_rr_list)
|
static void ares_srv_lookup_callback(void *arg, int status, int timeouts,
|
||||||
|
unsigned char *buf, int len)
|
||||||
{
|
{
|
||||||
resolver_srv_rr_t *rr;
|
struct resolver_ares_ctx *actx = arg;
|
||||||
|
|
||||||
while (srv_rr_list != NULL) {
|
if (status != ARES_SUCCESS)
|
||||||
rr = srv_rr_list->next;
|
actx->result = XMPP_DOMAIN_NOT_FOUND;
|
||||||
xmpp_free(ctx, srv_rr_list);
|
else
|
||||||
srv_rr_list = rr;
|
actx->result = resolver_ares_srv_lookup_buf(actx->ctx, buf, len,
|
||||||
|
&actx->srv_rr_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int resolver_ares_srv_lookup(xmpp_ctx_t *ctx, const char *fulldomain,
|
||||||
|
resolver_srv_rr_t **srv_rr_list)
|
||||||
|
{
|
||||||
|
struct resolver_ares_ctx actx;
|
||||||
|
ares_channel chan;
|
||||||
|
struct timeval tv;
|
||||||
|
struct timeval *tvp;
|
||||||
|
fd_set rfds;
|
||||||
|
fd_set wfds;
|
||||||
|
int nfds;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
actx.ctx = ctx;
|
||||||
|
actx.result = XMPP_DOMAIN_NOT_FOUND;
|
||||||
|
actx.srv_rr_list = NULL;
|
||||||
|
|
||||||
|
rc = ares_init(&chan);
|
||||||
|
if (rc == ARES_SUCCESS) {
|
||||||
|
ares_query(chan, fulldomain, MESSAGE_C_IN, MESSAGE_T_SRV,
|
||||||
|
ares_srv_lookup_callback, &actx);
|
||||||
|
while (1) {
|
||||||
|
FD_ZERO(&rfds);
|
||||||
|
FD_ZERO(&wfds);
|
||||||
|
nfds = ares_fds(chan, &rfds, &wfds);
|
||||||
|
if (nfds == 0)
|
||||||
|
break;
|
||||||
|
tvp = ares_timeout(chan, NULL, &tv);
|
||||||
|
select(nfds, &rfds, &wfds, NULL, tvp);
|
||||||
|
ares_process(chan, &rfds, &wfds);
|
||||||
}
|
}
|
||||||
|
ares_destroy(chan);
|
||||||
|
}
|
||||||
|
|
||||||
|
*srv_rr_list = actx.srv_rr_list;
|
||||||
|
return actx.result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* HAVE_CARES */
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Next part was copied from sock.c and contains old win32 code.
|
* Next part was copied from sock.c and contains old win32 code.
|
||||||
*
|
*
|
||||||
@@ -431,7 +622,7 @@ static void netbuf_add_domain_name(unsigned char *buf, int buflen, int *offset,
|
|||||||
|
|
||||||
*p++ = '\0';
|
*p++ = '\0';
|
||||||
|
|
||||||
*offset += p - start;
|
*offset += (int)(p - start);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void netbuf_add_dnsquery_header(unsigned char *buf, int buflen, int *offset, struct dnsquery_header *header)
|
static void netbuf_add_dnsquery_header(unsigned char *buf, int buflen, int *offset, struct dnsquery_header *header)
|
||||||
@@ -470,21 +661,21 @@ static int resolver_win32_srv_lookup(xmpp_ctx_t *ctx, const char *fulldomain,
|
|||||||
resolver_srv_rr_t *rr;
|
resolver_srv_rr_t *rr;
|
||||||
HINSTANCE hdnsapi = NULL;
|
HINSTANCE hdnsapi = NULL;
|
||||||
|
|
||||||
DNS_STATUS (WINAPI * pDnsQuery_A)(PCSTR, WORD, DWORD, PIP4_ARRAY, PDNS_RECORD*, PVOID*);
|
DNS_STATUS (WINAPI * pDnsQuery_A)(PCSTR, WORD, DWORD, PIP4_ARRAY, DNS_RECORDA**, PVOID*);
|
||||||
void (WINAPI * pDnsRecordListFree)(PDNS_RECORD, DNS_FREE_TYPE);
|
void (WINAPI * pDnsRecordListFree)(DNS_RECORDA*, DNS_FREE_TYPE);
|
||||||
|
|
||||||
if (hdnsapi = LoadLibrary("dnsapi.dll")) {
|
if (hdnsapi = LoadLibrary("dnsapi.dll")) {
|
||||||
pDnsQuery_A = (void *)GetProcAddress(hdnsapi, "DnsQuery_A");
|
pDnsQuery_A = (void *)GetProcAddress(hdnsapi, "DnsQuery_A");
|
||||||
pDnsRecordListFree = (void *)GetProcAddress(hdnsapi, "DnsRecordListFree");
|
pDnsRecordListFree = (void *)GetProcAddress(hdnsapi, "DnsRecordListFree");
|
||||||
|
|
||||||
if (pDnsQuery_A && pDnsRecordListFree) {
|
if (pDnsQuery_A && pDnsRecordListFree) {
|
||||||
PDNS_RECORD dnsrecords = NULL;
|
DNS_RECORDA *dnsrecords = NULL;
|
||||||
DNS_STATUS error;
|
DNS_STATUS error;
|
||||||
|
|
||||||
error = pDnsQuery_A(fulldomain, DNS_TYPE_SRV, DNS_QUERY_STANDARD, NULL, &dnsrecords, NULL);
|
error = pDnsQuery_A(fulldomain, DNS_TYPE_SRV, DNS_QUERY_STANDARD, NULL, &dnsrecords, NULL);
|
||||||
|
|
||||||
if (error == 0) {
|
if (error == 0) {
|
||||||
PDNS_RECORD current = dnsrecords;
|
DNS_RECORDA *current = dnsrecords;
|
||||||
|
|
||||||
while (current) {
|
while (current) {
|
||||||
if (current->wType == DNS_TYPE_SRV) {
|
if (current->wType == DNS_TYPE_SRV) {
|
||||||
@@ -517,7 +708,7 @@ static int resolver_win32_srv_query(const char *fulldomain,
|
|||||||
unsigned char *buf, size_t len)
|
unsigned char *buf, size_t len)
|
||||||
{
|
{
|
||||||
int set = 0;
|
int set = 0;
|
||||||
int insize;
|
int insize = 0;
|
||||||
|
|
||||||
/* if dnsapi didn't work/isn't there, try querying the dns server manually */
|
/* if dnsapi didn't work/isn't there, try querying the dns server manually */
|
||||||
if (!set)
|
if (!set)
|
||||||
@@ -550,7 +741,7 @@ static int resolver_win32_srv_query(const char *fulldomain,
|
|||||||
char buffer[65535];
|
char buffer[65535];
|
||||||
|
|
||||||
len = 65535;
|
len = 65535;
|
||||||
fi = buffer;
|
fi = (FIXED_INFO *)buffer;
|
||||||
|
|
||||||
if ((error = pGetNetworkParams(fi, &len)) == ERROR_SUCCESS)
|
if ((error = pGetNetworkParams(fi, &len)) == ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
@@ -711,14 +902,14 @@ static int resolver_win32_srv_query(const char *fulldomain,
|
|||||||
header.rd = 1;
|
header.rd = 1;
|
||||||
header.qdcount = 1;
|
header.qdcount = 1;
|
||||||
|
|
||||||
netbuf_add_dnsquery_header(buf, len, &offset, &header);
|
netbuf_add_dnsquery_header(buf, (int)len, &offset, &header);
|
||||||
|
|
||||||
memset(&question, 0, sizeof(question));
|
memset(&question, 0, sizeof(question));
|
||||||
strncpy(question.qname, fulldomain, 1024);
|
strncpy(question.qname, fulldomain, 1024);
|
||||||
question.qtype = 33; /* SRV */
|
question.qtype = 33; /* SRV */
|
||||||
question.qclass = 1; /* INTERNET! */
|
question.qclass = 1; /* INTERNET! */
|
||||||
|
|
||||||
netbuf_add_dnsquery_question(buf, len, &offset, &question);
|
netbuf_add_dnsquery_question(buf, (int)len, &offset, &question);
|
||||||
|
|
||||||
insize = 0;
|
insize = 0;
|
||||||
for (i = 0; i < numdnsservers && insize <= 0; i++)
|
for (i = 0; i < numdnsservers && insize <= 0; i++)
|
||||||
@@ -736,7 +927,7 @@ static int resolver_win32_srv_query(const char *fulldomain,
|
|||||||
sendto(sock, (char *)buf, offset, 0, (struct sockaddr *)&dnsaddr, addrlen);
|
sendto(sock, (char *)buf, offset, 0, (struct sockaddr *)&dnsaddr, addrlen);
|
||||||
for (j = 0; j < 50; j++)
|
for (j = 0; j < 50; j++)
|
||||||
{
|
{
|
||||||
insize = recvfrom(sock, (char *)buf, len, 0, (struct sockaddr *)&dnsaddr, &addrlen);
|
insize = recvfrom(sock, (char *)buf, (int)len, 0, (struct sockaddr *)&dnsaddr, &addrlen);
|
||||||
if (insize == SOCKET_ERROR)
|
if (insize == SOCKET_ERROR)
|
||||||
{
|
{
|
||||||
if (sock_error() == WSAEWOULDBLOCK)
|
if (sock_error() == WSAEWOULDBLOCK)
|
||||||
|
|||||||
@@ -33,6 +33,9 @@ typedef struct resolver_srv_rr_struc {
|
|||||||
struct resolver_srv_rr_struc *next;
|
struct resolver_srv_rr_struc *next;
|
||||||
} resolver_srv_rr_t;
|
} resolver_srv_rr_t;
|
||||||
|
|
||||||
|
void resolver_initialize(void);
|
||||||
|
void resolver_shutdown(void);
|
||||||
|
|
||||||
/** Perform lookup for RFC1035 message format.
|
/** Perform lookup for RFC1035 message format.
|
||||||
* This function allocates all elements.
|
* This function allocates all elements.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -264,6 +264,7 @@ char *sasl_digest_md5(xmpp_ctx_t *ctx, const char *challenge,
|
|||||||
xmpp_rand_nonce(ctx->rand, cnonce, sizeof(cnonce));
|
xmpp_rand_nonce(ctx->rand, cnonce, sizeof(cnonce));
|
||||||
hash_add(table, "cnonce", xmpp_strdup(ctx, cnonce));
|
hash_add(table, "cnonce", xmpp_strdup(ctx, cnonce));
|
||||||
hash_add(table, "nc", xmpp_strdup(ctx, "00000001"));
|
hash_add(table, "nc", xmpp_strdup(ctx, "00000001"));
|
||||||
|
if (hash_get(table, "qop") == NULL)
|
||||||
hash_add(table, "qop", xmpp_strdup(ctx, "auth"));
|
hash_add(table, "qop", xmpp_strdup(ctx, "auth"));
|
||||||
value = xmpp_alloc(ctx, 5 + strlen(domain) + 1);
|
value = xmpp_alloc(ctx, 5 + strlen(domain) + 1);
|
||||||
memcpy(value, "xmpp/", 5);
|
memcpy(value, "xmpp/", 5);
|
||||||
|
|||||||
@@ -197,8 +197,9 @@ void crypto_SHA1_Update(SHA1_CTX* context, const uint8_t* data,
|
|||||||
size_t i, j;
|
size_t i, j;
|
||||||
|
|
||||||
j = (context->count[0] >> 3) & 63;
|
j = (context->count[0] >> 3) & 63;
|
||||||
if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++;
|
if ((context->count[0] += (uint32_t)len << 3) < ((uint32_t)len << 3))
|
||||||
context->count[1] += (len >> 29);
|
context->count[1]++;
|
||||||
|
context->count[1] += (uint32_t)(len >> 29);
|
||||||
if ((j + len) > 63) {
|
if ((j + len) > 63) {
|
||||||
memcpy(&context->buffer[j], data, (i = 64-j));
|
memcpy(&context->buffer[j], data, (i = 64-j));
|
||||||
SHA1_Transform(context->state, context->buffer);
|
SHA1_Transform(context->state, context->buffer);
|
||||||
@@ -233,7 +234,6 @@ void crypto_SHA1_Final(SHA1_CTX* context, uint8_t* digest)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Wipe variables */
|
/* Wipe variables */
|
||||||
i = 0;
|
|
||||||
memset(context->buffer, 0, 64);
|
memset(context->buffer, 0, 64);
|
||||||
memset(context->state, 0, 20);
|
memset(context->state, 0, 20);
|
||||||
memset(context->count, 0, 8);
|
memset(context->count, 0, 8);
|
||||||
|
|||||||
@@ -286,6 +286,7 @@ static int dopr (char *buffer, size_t maxlen, const char *format, va_list args)
|
|||||||
break;
|
break;
|
||||||
case 'X':
|
case 'X':
|
||||||
flags |= DP_F_UP;
|
flags |= DP_F_UP;
|
||||||
|
//-fallthrough
|
||||||
case 'x':
|
case 'x':
|
||||||
flags |= DP_F_UNSIGNED;
|
flags |= DP_F_UNSIGNED;
|
||||||
if (cflags == DP_C_SHORT)
|
if (cflags == DP_C_SHORT)
|
||||||
@@ -306,6 +307,7 @@ static int dopr (char *buffer, size_t maxlen, const char *format, va_list args)
|
|||||||
break;
|
break;
|
||||||
case 'E':
|
case 'E':
|
||||||
flags |= DP_F_UP;
|
flags |= DP_F_UP;
|
||||||
|
//-fallthrough
|
||||||
case 'e':
|
case 'e':
|
||||||
if (cflags == DP_C_LDOUBLE)
|
if (cflags == DP_C_LDOUBLE)
|
||||||
fvalue = va_arg (args, LDOUBLE);
|
fvalue = va_arg (args, LDOUBLE);
|
||||||
@@ -314,6 +316,7 @@ static int dopr (char *buffer, size_t maxlen, const char *format, va_list args)
|
|||||||
break;
|
break;
|
||||||
case 'G':
|
case 'G':
|
||||||
flags |= DP_F_UP;
|
flags |= DP_F_UP;
|
||||||
|
//-fallthrough
|
||||||
case 'g':
|
case 'g':
|
||||||
if (cflags == DP_C_LDOUBLE)
|
if (cflags == DP_C_LDOUBLE)
|
||||||
fvalue = va_arg (args, LDOUBLE);
|
fvalue = va_arg (args, LDOUBLE);
|
||||||
|
|||||||
33
src/sock.c
33
src/sock.c
@@ -158,38 +158,33 @@ int sock_close(const sock_t sock)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int sock_set_blocking(const sock_t sock)
|
static int _sock_set_blocking_mode(sock_t sock, int blocking)
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
u_long block = 0;
|
u_long nonblock = blocking ? 0 : 1;
|
||||||
return ioctlsocket(sock, FIONBIO, &block);
|
|
||||||
#else
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
rc = fcntl(sock, F_GETFL, NULL);
|
|
||||||
if (rc >= 0) {
|
|
||||||
rc = fcntl(sock, F_SETFL, rc & (~O_NONBLOCK));
|
|
||||||
}
|
|
||||||
return rc;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
int sock_set_nonblocking(const sock_t sock)
|
|
||||||
{
|
|
||||||
#ifdef _WIN32
|
|
||||||
u_long nonblock = 1;
|
|
||||||
return ioctlsocket(sock, FIONBIO, &nonblock);
|
return ioctlsocket(sock, FIONBIO, &nonblock);
|
||||||
#else
|
#else
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
rc = fcntl(sock, F_GETFL, NULL);
|
rc = fcntl(sock, F_GETFL, NULL);
|
||||||
if (rc >= 0) {
|
if (rc >= 0) {
|
||||||
rc = fcntl(sock, F_SETFL, rc | O_NONBLOCK);
|
rc = blocking ? rc & (~O_NONBLOCK) : rc | O_NONBLOCK;
|
||||||
|
rc = fcntl(sock, F_SETFL, rc);
|
||||||
}
|
}
|
||||||
return rc;
|
return rc;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int sock_set_blocking(const sock_t sock)
|
||||||
|
{
|
||||||
|
return _sock_set_blocking_mode(sock, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int sock_set_nonblocking(const sock_t sock)
|
||||||
|
{
|
||||||
|
return _sock_set_blocking_mode(sock, 0);
|
||||||
|
}
|
||||||
|
|
||||||
int sock_read(const sock_t sock, void * const buff, const size_t len)
|
int sock_read(const sock_t sock, void * const buff, const size_t len)
|
||||||
{
|
{
|
||||||
return recv(sock, buff, len, 0);
|
return recv(sock, buff, len, 0);
|
||||||
|
|||||||
280
src/stanza.c
280
src/stanza.c
@@ -76,35 +76,27 @@ xmpp_stanza_t *xmpp_stanza_clone(xmpp_stanza_t * const stanza)
|
|||||||
static int _stanza_copy_attributes(xmpp_stanza_t * dst,
|
static int _stanza_copy_attributes(xmpp_stanza_t * dst,
|
||||||
const xmpp_stanza_t * const src)
|
const xmpp_stanza_t * const src)
|
||||||
{
|
{
|
||||||
hash_iterator_t *iter = NULL;
|
hash_iterator_t *iter;
|
||||||
const char *key;
|
const char *key;
|
||||||
void *val;
|
const char *val;
|
||||||
|
int rc = XMPP_EOK;
|
||||||
|
|
||||||
dst->attributes = hash_new(src->ctx, 8, xmpp_free);
|
|
||||||
if (!dst->attributes)
|
|
||||||
return -1;
|
|
||||||
iter = hash_iter_new(src->attributes);
|
iter = hash_iter_new(src->attributes);
|
||||||
if (!iter)
|
if (!iter) rc = XMPP_EMEM;
|
||||||
goto error;
|
|
||||||
while ((key = hash_iter_next(iter))) {
|
|
||||||
val = xmpp_strdup(src->ctx,
|
|
||||||
(char *)hash_get(src->attributes, key));
|
|
||||||
if (!val)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
if (hash_add(dst->attributes, key, val)) {
|
while (rc == XMPP_EOK && (key = hash_iter_next(iter))) {
|
||||||
xmpp_free(src->ctx, val);
|
val = hash_get(src->attributes, key);
|
||||||
goto error;
|
if (!val) rc = XMPP_EINT;
|
||||||
}
|
if (rc == XMPP_EOK)
|
||||||
|
rc = xmpp_stanza_set_attribute(dst, key, val);
|
||||||
}
|
}
|
||||||
hash_iter_release(iter);
|
hash_iter_release(iter);
|
||||||
return 0;
|
|
||||||
|
|
||||||
error:
|
if (rc != XMPP_EOK && dst->attributes) {
|
||||||
if (iter != NULL)
|
|
||||||
hash_iter_release(iter);
|
|
||||||
hash_release(dst->attributes);
|
hash_release(dst->attributes);
|
||||||
return -1;
|
dst->attributes = NULL;
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Copy a stanza and its children.
|
/** Copy a stanza and its children.
|
||||||
@@ -196,6 +188,19 @@ int xmpp_stanza_release(xmpp_stanza_t * const stanza)
|
|||||||
return released;
|
return released;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Get the strophe context that the stanza is associated with.
|
||||||
|
*
|
||||||
|
* @param stanza a Strophe stanza object
|
||||||
|
*
|
||||||
|
* @return a Strophe context
|
||||||
|
*
|
||||||
|
* @ingroup Stanza
|
||||||
|
*/
|
||||||
|
xmpp_ctx_t *xmpp_stanza_get_context(const xmpp_stanza_t * const stanza)
|
||||||
|
{
|
||||||
|
return stanza->ctx;
|
||||||
|
}
|
||||||
|
|
||||||
/** Determine if a stanza is a text node.
|
/** Determine if a stanza is a text node.
|
||||||
*
|
*
|
||||||
* @param stanza a Strophe stanza object
|
* @param stanza a Strophe stanza object
|
||||||
@@ -352,10 +357,16 @@ static int _render_stanza_recursive(xmpp_stanza_t *stanza,
|
|||||||
}
|
}
|
||||||
tmp = _escape_xml(stanza->ctx,
|
tmp = _escape_xml(stanza->ctx,
|
||||||
(char *)hash_get(stanza->attributes, key));
|
(char *)hash_get(stanza->attributes, key));
|
||||||
if (tmp == NULL) return XMPP_EMEM;
|
if (tmp == NULL) {
|
||||||
|
hash_iter_release(iter);
|
||||||
|
return XMPP_EMEM;
|
||||||
|
}
|
||||||
ret = xmpp_snprintf(ptr, left, " %s=\"%s\"", key, tmp);
|
ret = xmpp_snprintf(ptr, left, " %s=\"%s\"", key, tmp);
|
||||||
xmpp_free(stanza->ctx, tmp);
|
xmpp_free(stanza->ctx, tmp);
|
||||||
if (ret < 0) return XMPP_EMEM;
|
if (ret < 0) {
|
||||||
|
hash_iter_release(iter);
|
||||||
|
return XMPP_EMEM;
|
||||||
|
}
|
||||||
_render_update(&written, buflen, ret, &left, &ptr);
|
_render_update(&written, buflen, ret, &left, &ptr);
|
||||||
}
|
}
|
||||||
hash_iter_release(iter);
|
hash_iter_release(iter);
|
||||||
@@ -429,9 +440,14 @@ int xmpp_stanza_to_text(xmpp_stanza_t *stanza,
|
|||||||
}
|
}
|
||||||
|
|
||||||
ret = _render_stanza_recursive(stanza, buffer, length);
|
ret = _render_stanza_recursive(stanza, buffer, length);
|
||||||
if (ret < 0) return ret;
|
if (ret < 0) {
|
||||||
|
xmpp_free(stanza->ctx, buffer);
|
||||||
|
*buf = NULL;
|
||||||
|
*buflen = 0;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
if (ret > length - 1) {
|
if ((size_t)ret > length - 1) {
|
||||||
tmp = xmpp_realloc(stanza->ctx, buffer, ret + 1);
|
tmp = xmpp_realloc(stanza->ctx, buffer, ret + 1);
|
||||||
if (!tmp) {
|
if (!tmp) {
|
||||||
xmpp_free(stanza->ctx, buffer);
|
xmpp_free(stanza->ctx, buffer);
|
||||||
@@ -443,7 +459,12 @@ int xmpp_stanza_to_text(xmpp_stanza_t *stanza,
|
|||||||
buffer = tmp;
|
buffer = tmp;
|
||||||
|
|
||||||
ret = _render_stanza_recursive(stanza, buffer, length);
|
ret = _render_stanza_recursive(stanza, buffer, length);
|
||||||
if (ret > length - 1) return XMPP_EMEM;
|
if ((size_t)ret > length - 1) {
|
||||||
|
xmpp_free(stanza->ctx, buffer);
|
||||||
|
*buf = NULL;
|
||||||
|
*buflen = 0;
|
||||||
|
return XMPP_EMEM;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer[length - 1] = 0;
|
buffer[length - 1] = 0;
|
||||||
@@ -570,6 +591,7 @@ int xmpp_stanza_set_attribute(xmpp_stanza_t * const stanza,
|
|||||||
const char * const value)
|
const char * const value)
|
||||||
{
|
{
|
||||||
char *val;
|
char *val;
|
||||||
|
int rc;
|
||||||
|
|
||||||
if (stanza->type != XMPP_STANZA_TAG) return XMPP_EINVOP;
|
if (stanza->type != XMPP_STANZA_TAG) return XMPP_EINVOP;
|
||||||
|
|
||||||
@@ -580,11 +602,14 @@ int xmpp_stanza_set_attribute(xmpp_stanza_t * const stanza,
|
|||||||
|
|
||||||
val = xmpp_strdup(stanza->ctx, value);
|
val = xmpp_strdup(stanza->ctx, value);
|
||||||
if (!val) {
|
if (!val) {
|
||||||
hash_release(stanza->attributes);
|
|
||||||
return XMPP_EMEM;
|
return XMPP_EMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
hash_add(stanza->attributes, key, val);
|
rc = hash_add(stanza->attributes, key, val);
|
||||||
|
if (rc < 0) {
|
||||||
|
xmpp_free(stanza->ctx, val);
|
||||||
|
return XMPP_EMEM;
|
||||||
|
}
|
||||||
|
|
||||||
return XMPP_EOK;
|
return XMPP_EOK;
|
||||||
}
|
}
|
||||||
@@ -607,22 +632,29 @@ int xmpp_stanza_set_ns(xmpp_stanza_t * const stanza,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Add a child stanza to a stanza object.
|
/** Add a child stanza to a stanza object.
|
||||||
* This function clones the child and appends it to the stanza object's
|
* If do_clone is TRUE, user keeps reference to the child stanza and must call
|
||||||
* children.
|
* xmpp_stanza_release() to release the reference. If do_clone is FALSE, user
|
||||||
|
* transfers ownership and must not neither call xmpp_stanza_release() for
|
||||||
|
* the child stanza nor use it.
|
||||||
*
|
*
|
||||||
* @param stanza a Strophe stanza object
|
* @param stanza a Strophe stanza object
|
||||||
* @param child the child stanza object
|
* @param child the child stanza object
|
||||||
|
* @param do_clone TRUE to increase ref count of child (default for
|
||||||
|
* xmpp_stanza_add_child())
|
||||||
*
|
*
|
||||||
* @return XMPP_EOK (0) on success or a number less than 0 on failure
|
* @return XMPP_EOK (0) on success or a number less than 0 on failure
|
||||||
*
|
*
|
||||||
* @ingroup Stanza
|
* @ingroup Stanza
|
||||||
*/
|
*/
|
||||||
int xmpp_stanza_add_child(xmpp_stanza_t *stanza, xmpp_stanza_t *child)
|
int xmpp_stanza_add_child_ex(xmpp_stanza_t *stanza, xmpp_stanza_t *child,
|
||||||
|
int do_clone)
|
||||||
{
|
{
|
||||||
xmpp_stanza_t *s;
|
xmpp_stanza_t *s;
|
||||||
|
|
||||||
|
if (do_clone) {
|
||||||
/* get a reference to the child */
|
/* get a reference to the child */
|
||||||
xmpp_stanza_clone(child);
|
xmpp_stanza_clone(child);
|
||||||
|
}
|
||||||
|
|
||||||
child->parent = stanza;
|
child->parent = stanza;
|
||||||
|
|
||||||
@@ -638,6 +670,22 @@ int xmpp_stanza_add_child(xmpp_stanza_t *stanza, xmpp_stanza_t *child)
|
|||||||
return XMPP_EOK;
|
return XMPP_EOK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Add a child stanza to a stanza object.
|
||||||
|
* This function clones the child and appends it to the stanza object's
|
||||||
|
* children.
|
||||||
|
*
|
||||||
|
* @param stanza a Strophe stanza object
|
||||||
|
* @param child the child stanza object
|
||||||
|
*
|
||||||
|
* @return XMPP_EOK (0) on success or a number less than 0 on failure
|
||||||
|
*
|
||||||
|
* @ingroup Stanza
|
||||||
|
*/
|
||||||
|
int xmpp_stanza_add_child(xmpp_stanza_t *stanza, xmpp_stanza_t *child)
|
||||||
|
{
|
||||||
|
return xmpp_stanza_add_child_ex(stanza, child, 1);
|
||||||
|
}
|
||||||
|
|
||||||
/** Set the text data for a text stanza.
|
/** Set the text data for a text stanza.
|
||||||
* This function copies the text given and sets the stanza object's text to
|
* This function copies the text given and sets the stanza object's text to
|
||||||
* it. Attempting to use this function on a stanza that has a name will
|
* it. Attempting to use this function on a stanza that has a name will
|
||||||
@@ -812,16 +860,50 @@ xmpp_stanza_t *xmpp_stanza_get_child_by_ns(xmpp_stanza_t * const stanza,
|
|||||||
const char * const ns)
|
const char * const ns)
|
||||||
{
|
{
|
||||||
xmpp_stanza_t *child;
|
xmpp_stanza_t *child;
|
||||||
|
const char *child_ns;
|
||||||
|
|
||||||
for (child = stanza->children; child; child = child->next) {
|
for (child = stanza->children; child; child = child->next) {
|
||||||
if (xmpp_stanza_get_ns(child) &&
|
child_ns = xmpp_stanza_get_ns(child);
|
||||||
strcmp(ns, xmpp_stanza_get_ns(child)) == 0)
|
if (child_ns && strcmp(ns, child_ns) == 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return child;
|
return child;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Get the first child of stanza with name and a given namespace.
|
||||||
|
* This function searches all the immediate children of stanza for a child
|
||||||
|
* stanza that matches the name and namespace provided.
|
||||||
|
* The first matching child is returned.
|
||||||
|
*
|
||||||
|
* @param stanza a Strophe stanza object
|
||||||
|
* @param name a string with the name to match
|
||||||
|
* @param ns a string with the namespace to match
|
||||||
|
*
|
||||||
|
* @return the matching child stanza object or NULL if no match was found
|
||||||
|
*
|
||||||
|
* @ingroup Stanza
|
||||||
|
*/
|
||||||
|
xmpp_stanza_t *xmpp_stanza_get_child_by_name_and_ns(xmpp_stanza_t * const stanza,
|
||||||
|
const char * const name,
|
||||||
|
const char * const ns)
|
||||||
|
{
|
||||||
|
xmpp_stanza_t *child;
|
||||||
|
const char *child_ns;
|
||||||
|
|
||||||
|
for (child = stanza->children; child; child = child->next) {
|
||||||
|
if (child->type == XMPP_STANZA_TAG &&
|
||||||
|
(strcmp(name, xmpp_stanza_get_name(child)) == 0)) {
|
||||||
|
child_ns = xmpp_stanza_get_ns(child);
|
||||||
|
if (child_ns && strcmp(ns, child_ns) == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return child;
|
||||||
|
}
|
||||||
|
|
||||||
/** Get the list of children.
|
/** Get the list of children.
|
||||||
* This function returns the first child of the stanza object. The rest
|
* This function returns the first child of the stanza object. The rest
|
||||||
* of the children can be obtained by calling xmpp_stanza_get_next() to
|
* of the children can be obtained by calling xmpp_stanza_get_next() to
|
||||||
@@ -1047,7 +1129,12 @@ int xmpp_stanza_del_attribute(xmpp_stanza_t * const stanza,
|
|||||||
*/
|
*/
|
||||||
xmpp_stanza_t *xmpp_stanza_reply(xmpp_stanza_t * const stanza)
|
xmpp_stanza_t *xmpp_stanza_reply(xmpp_stanza_t * const stanza)
|
||||||
{
|
{
|
||||||
xmpp_stanza_t *copy;
|
xmpp_stanza_t *copy = NULL;
|
||||||
|
const char *from;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
from = xmpp_stanza_get_from(stanza);
|
||||||
|
if (!from) goto copy_error;
|
||||||
|
|
||||||
copy = xmpp_stanza_new(stanza->ctx);
|
copy = xmpp_stanza_new(stanza->ctx);
|
||||||
if (!copy) goto copy_error;
|
if (!copy) goto copy_error;
|
||||||
@@ -1060,12 +1147,14 @@ xmpp_stanza_t *xmpp_stanza_reply(xmpp_stanza_t * const stanza)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (stanza->attributes) {
|
if (stanza->attributes) {
|
||||||
if (_stanza_copy_attributes(copy, stanza) == -1)
|
if (_stanza_copy_attributes(copy, stanza) < 0)
|
||||||
goto copy_error;
|
goto copy_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
xmpp_stanza_set_to(copy, xmpp_stanza_get_from(stanza));
|
xmpp_stanza_del_attribute(copy, "to");
|
||||||
xmpp_stanza_del_attribute(copy, "from");
|
xmpp_stanza_del_attribute(copy, "from");
|
||||||
|
rc = xmpp_stanza_set_to(copy, from);
|
||||||
|
if (rc != XMPP_EOK) goto copy_error;
|
||||||
|
|
||||||
return copy;
|
return copy;
|
||||||
|
|
||||||
@@ -1214,3 +1303,122 @@ xmpp_stanza_t *xmpp_presence_new(xmpp_ctx_t *ctx)
|
|||||||
{
|
{
|
||||||
return _stanza_new_with_attrs(ctx, "presence", NULL, NULL, NULL);
|
return _stanza_new_with_attrs(ctx, "presence", NULL, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Create an <stream:error/> stanza object with given type and error text.
|
||||||
|
* The error text is optional and may be NULL.
|
||||||
|
*
|
||||||
|
* @param ctx a Strophe context object
|
||||||
|
* @param type enum of xmpp_error_type_t
|
||||||
|
* @param text content of a 'text'
|
||||||
|
*
|
||||||
|
* @return a new Strophe stanza object
|
||||||
|
*
|
||||||
|
* @todo Handle errors in this function
|
||||||
|
*
|
||||||
|
* @ingroup Stanza
|
||||||
|
*/
|
||||||
|
xmpp_stanza_t *xmpp_error_new(xmpp_ctx_t *ctx, xmpp_error_type_t const type,
|
||||||
|
const char * const text)
|
||||||
|
{
|
||||||
|
xmpp_stanza_t *error = _stanza_new_with_attrs(ctx, "stream:error", NULL, NULL, NULL);
|
||||||
|
xmpp_stanza_t *error_type = xmpp_stanza_new(ctx);
|
||||||
|
|
||||||
|
switch(type) {
|
||||||
|
case XMPP_SE_BAD_FORMAT:
|
||||||
|
xmpp_stanza_set_name(error_type, "bad-format");
|
||||||
|
break;
|
||||||
|
case XMPP_SE_BAD_NS_PREFIX:
|
||||||
|
xmpp_stanza_set_name(error_type, "bad-namespace-prefix");
|
||||||
|
break;
|
||||||
|
case XMPP_SE_CONFLICT:
|
||||||
|
xmpp_stanza_set_name(error_type, "conflict");
|
||||||
|
break;
|
||||||
|
case XMPP_SE_CONN_TIMEOUT:
|
||||||
|
xmpp_stanza_set_name(error_type, "connection-timeout");
|
||||||
|
break;
|
||||||
|
case XMPP_SE_HOST_GONE:
|
||||||
|
xmpp_stanza_set_name(error_type, "host-gone");
|
||||||
|
break;
|
||||||
|
case XMPP_SE_HOST_UNKNOWN:
|
||||||
|
xmpp_stanza_set_name(error_type, "host-unknown");
|
||||||
|
break;
|
||||||
|
case XMPP_SE_IMPROPER_ADDR:
|
||||||
|
xmpp_stanza_set_name(error_type, "improper-addressing");
|
||||||
|
break;
|
||||||
|
case XMPP_SE_INTERNAL_SERVER_ERROR:
|
||||||
|
xmpp_stanza_set_name(error_type, "internal-server-error");
|
||||||
|
break;
|
||||||
|
case XMPP_SE_INVALID_FROM:
|
||||||
|
xmpp_stanza_set_name(error_type, "invalid-from");
|
||||||
|
break;
|
||||||
|
case XMPP_SE_INVALID_ID:
|
||||||
|
xmpp_stanza_set_name(error_type, "invalid-id");
|
||||||
|
break;
|
||||||
|
case XMPP_SE_INVALID_NS:
|
||||||
|
xmpp_stanza_set_name(error_type, "invalid-namespace");
|
||||||
|
break;
|
||||||
|
case XMPP_SE_INVALID_XML:
|
||||||
|
xmpp_stanza_set_name(error_type, "invalid-xml");
|
||||||
|
break;
|
||||||
|
case XMPP_SE_NOT_AUTHORIZED:
|
||||||
|
xmpp_stanza_set_name(error_type, "not-authorized");
|
||||||
|
break;
|
||||||
|
case XMPP_SE_POLICY_VIOLATION:
|
||||||
|
xmpp_stanza_set_name(error_type, "policy-violation");
|
||||||
|
break;
|
||||||
|
case XMPP_SE_REMOTE_CONN_FAILED:
|
||||||
|
xmpp_stanza_set_name(error_type, "remote-connection-failed");
|
||||||
|
break;
|
||||||
|
case XMPP_SE_RESOURCE_CONSTRAINT:
|
||||||
|
xmpp_stanza_set_name(error_type, "resource-constraint");
|
||||||
|
break;
|
||||||
|
case XMPP_SE_RESTRICTED_XML:
|
||||||
|
xmpp_stanza_set_name(error_type, "restricted-xml");
|
||||||
|
break;
|
||||||
|
case XMPP_SE_SEE_OTHER_HOST:
|
||||||
|
xmpp_stanza_set_name(error_type, "see-other-host");
|
||||||
|
break;
|
||||||
|
case XMPP_SE_SYSTEM_SHUTDOWN:
|
||||||
|
xmpp_stanza_set_name(error_type, "system-shutdown");
|
||||||
|
break;
|
||||||
|
case XMPP_SE_UNDEFINED_CONDITION:
|
||||||
|
xmpp_stanza_set_name(error_type, "undefined-condition");
|
||||||
|
break;
|
||||||
|
case XMPP_SE_UNSUPPORTED_ENCODING:
|
||||||
|
xmpp_stanza_set_name(error_type, "unsupported-encoding");
|
||||||
|
break;
|
||||||
|
case XMPP_SE_UNSUPPORTED_STANZA_TYPE:
|
||||||
|
xmpp_stanza_set_name(error_type, "unsupported-stanza-type");
|
||||||
|
break;
|
||||||
|
case XMPP_SE_UNSUPPORTED_VERSION:
|
||||||
|
xmpp_stanza_set_name(error_type, "unsupported-version");
|
||||||
|
break;
|
||||||
|
case XMPP_SE_XML_NOT_WELL_FORMED:
|
||||||
|
xmpp_stanza_set_name(error_type, "xml-not-well-formed");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
xmpp_stanza_set_name(error_type, "internal-server-error");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
xmpp_stanza_set_ns(error_type, XMPP_NS_STREAMS_IETF);
|
||||||
|
xmpp_stanza_add_child(error, error_type);
|
||||||
|
xmpp_stanza_release(error_type);
|
||||||
|
|
||||||
|
if (text) {
|
||||||
|
xmpp_stanza_t *error_text = xmpp_stanza_new(ctx);
|
||||||
|
xmpp_stanza_t *content = xmpp_stanza_new(ctx);
|
||||||
|
|
||||||
|
xmpp_stanza_set_name(error_text, "text");
|
||||||
|
xmpp_stanza_set_ns(error_text, XMPP_NS_STREAMS_IETF);
|
||||||
|
|
||||||
|
xmpp_stanza_set_text(content, text);
|
||||||
|
xmpp_stanza_add_child(error_text, content);
|
||||||
|
xmpp_stanza_release(content);
|
||||||
|
|
||||||
|
xmpp_stanza_add_child(error, error_text);
|
||||||
|
xmpp_stanza_release(error_text);
|
||||||
|
}
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|||||||
116
src/thread.c
116
src/thread.c
@@ -1,116 +0,0 @@
|
|||||||
/* thread.c
|
|
||||||
** strophe XMPP client library -- thread abstraction
|
|
||||||
**
|
|
||||||
** Copyright (C) 2005-2009 Collecta, Inc.
|
|
||||||
**
|
|
||||||
** This software is provided AS-IS with no warranty, either express
|
|
||||||
** or implied.
|
|
||||||
**
|
|
||||||
** This program is dual licensed under the MIT and GPLv3 licenses.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** @file
|
|
||||||
* Thread absraction.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
#define WIN32_LEAN_AND_MEAN
|
|
||||||
#include <windows.h>
|
|
||||||
#else
|
|
||||||
#include <pthread.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "strophe.h"
|
|
||||||
#include "common.h"
|
|
||||||
#include "thread.h"
|
|
||||||
|
|
||||||
struct _mutex_t {
|
|
||||||
const xmpp_ctx_t *ctx;
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
HANDLE mutex;
|
|
||||||
#else
|
|
||||||
pthread_mutex_t *mutex;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
/* mutex functions */
|
|
||||||
|
|
||||||
mutex_t *mutex_create(const xmpp_ctx_t * ctx)
|
|
||||||
{
|
|
||||||
mutex_t *mutex;
|
|
||||||
|
|
||||||
mutex = xmpp_alloc(ctx, sizeof(mutex_t));
|
|
||||||
if (mutex) {
|
|
||||||
mutex->ctx = ctx;
|
|
||||||
#ifdef _WIN32
|
|
||||||
mutex->mutex = CreateMutex(NULL, FALSE, NULL);
|
|
||||||
#else
|
|
||||||
mutex->mutex = xmpp_alloc(ctx, sizeof(pthread_mutex_t));
|
|
||||||
if (mutex->mutex)
|
|
||||||
if (pthread_mutex_init(mutex->mutex, NULL) != 0) {
|
|
||||||
xmpp_free(ctx, mutex->mutex);
|
|
||||||
mutex->mutex = NULL;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (!mutex->mutex) {
|
|
||||||
xmpp_free(ctx, mutex);
|
|
||||||
mutex = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return mutex;
|
|
||||||
}
|
|
||||||
|
|
||||||
int mutex_destroy(mutex_t *mutex)
|
|
||||||
{
|
|
||||||
int ret = 1;
|
|
||||||
const xmpp_ctx_t *ctx;
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
if (mutex->mutex)
|
|
||||||
ret = CloseHandle(mutex->mutex);
|
|
||||||
#else
|
|
||||||
if (mutex->mutex)
|
|
||||||
ret = pthread_mutex_destroy(mutex->mutex) == 0;
|
|
||||||
#endif
|
|
||||||
ctx = mutex->ctx;
|
|
||||||
xmpp_free(ctx, mutex);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int mutex_lock(mutex_t *mutex)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
ret = WaitForSingleObject(mutex->mutex, INFINITE) == 0;
|
|
||||||
#else
|
|
||||||
ret = pthread_mutex_lock(mutex->mutex) == 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int mutex_trylock(mutex_t *mutex)
|
|
||||||
{
|
|
||||||
/* TODO */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int mutex_unlock(mutex_t *mutex)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
ret = ReleaseMutex(mutex->mutex);
|
|
||||||
#else
|
|
||||||
ret = pthread_mutex_unlock(mutex->mutex) == 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
40
src/thread.h
40
src/thread.h
@@ -1,40 +0,0 @@
|
|||||||
/* thread.h
|
|
||||||
** strophe XMPP client library -- thread abstraction header
|
|
||||||
**
|
|
||||||
** Copyright (C) 2005-2009 Collecta, Inc.
|
|
||||||
**
|
|
||||||
** This software is provided AS-IS with no warranty, either express
|
|
||||||
** or implied.
|
|
||||||
**
|
|
||||||
** This program is dual licensed under the MIT and GPLv3 licenses.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** @file
|
|
||||||
* Threading abstraction API.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __LIBSTROPHE_THREAD_H__
|
|
||||||
#define __LIBSTROPHE_THREAD_H__
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
#include <windows.h>
|
|
||||||
#else
|
|
||||||
#include <pthread.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "strophe.h"
|
|
||||||
|
|
||||||
typedef struct _mutex_t mutex_t;
|
|
||||||
|
|
||||||
/* mutex functions */
|
|
||||||
|
|
||||||
mutex_t *mutex_create(const xmpp_ctx_t *ctx);
|
|
||||||
int mutex_destroy(mutex_t *mutex);
|
|
||||||
int mutex_lock(mutex_t *mutex);
|
|
||||||
int mutex_trylock(mutex_t *mutex);
|
|
||||||
int mutex_unlock(mutex_t *mutex);
|
|
||||||
|
|
||||||
#endif /* __LIBSTROPHE_THREAD_H__ */
|
|
||||||
@@ -24,7 +24,7 @@ typedef struct _tls tls_t;
|
|||||||
void tls_initialize(void);
|
void tls_initialize(void);
|
||||||
void tls_shutdown(void);
|
void tls_shutdown(void);
|
||||||
|
|
||||||
tls_t *tls_new(xmpp_ctx_t *ctx, sock_t sock);
|
tls_t *tls_new(xmpp_conn_t *conn);
|
||||||
void tls_free(tls_t *tls);
|
void tls_free(tls_t *tls);
|
||||||
|
|
||||||
int tls_set_credentials(tls_t *tls, const char *cafilename);
|
int tls_set_credentials(tls_t *tls, const char *cafilename);
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ void tls_shutdown(void)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
tls_t *tls_new(xmpp_ctx_t *ctx, sock_t sock)
|
tls_t *tls_new(xmpp_conn_t *conn)
|
||||||
{
|
{
|
||||||
/* always fail */
|
/* always fail */
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|||||||
@@ -46,13 +46,13 @@ void tls_shutdown(void)
|
|||||||
gnutls_global_deinit();
|
gnutls_global_deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
tls_t *tls_new(xmpp_ctx_t *ctx, sock_t sock)
|
tls_t *tls_new(xmpp_conn_t *conn)
|
||||||
{
|
{
|
||||||
tls_t *tls = xmpp_alloc(ctx, sizeof(tls_t));
|
tls_t *tls = xmpp_alloc(conn->ctx, sizeof(tls_t));
|
||||||
|
|
||||||
if (tls) {
|
if (tls) {
|
||||||
tls->ctx = ctx;
|
tls->ctx = conn->ctx;
|
||||||
tls->sock = sock;
|
tls->sock = conn->sock;
|
||||||
gnutls_init(&tls->session, GNUTLS_CLIENT);
|
gnutls_init(&tls->session, GNUTLS_CLIENT);
|
||||||
|
|
||||||
gnutls_certificate_allocate_credentials(&tls->cred);
|
gnutls_certificate_allocate_credentials(&tls->cred);
|
||||||
@@ -61,7 +61,7 @@ tls_t *tls_new(xmpp_ctx_t *ctx, sock_t sock)
|
|||||||
gnutls_set_default_priority(tls->session);
|
gnutls_set_default_priority(tls->session);
|
||||||
|
|
||||||
/* fixme: this may require setting a callback on win32? */
|
/* fixme: this may require setting a callback on win32? */
|
||||||
gnutls_transport_set_int(tls->session, sock);
|
gnutls_transport_set_int(tls->session, conn->sock);
|
||||||
}
|
}
|
||||||
|
|
||||||
return tls;
|
return tls;
|
||||||
|
|||||||
@@ -24,11 +24,29 @@
|
|||||||
|
|
||||||
#include <openssl/ssl.h>
|
#include <openssl/ssl.h>
|
||||||
#include <openssl/err.h>
|
#include <openssl/err.h>
|
||||||
|
#include <openssl/opensslv.h>
|
||||||
|
#include <openssl/x509v3.h>
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "tls.h"
|
#include "tls.h"
|
||||||
#include "sock.h"
|
#include "sock.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Redefine OPENSSL_VERSION_NUMBER for LibreSSL.
|
||||||
|
* LibreSSL and OpenSSL use different and incompatible version schemes. Solve
|
||||||
|
* this issue in the way how nginx project did.
|
||||||
|
*/
|
||||||
|
#if (defined LIBRESSL_VERSION_NUMBER && OPENSSL_VERSION_NUMBER == 0x20000000L)
|
||||||
|
#undef OPENSSL_VERSION_NUMBER
|
||||||
|
#if (LIBRESSL_VERSION_NUMBER >= 0x2080000fL)
|
||||||
|
#define OPENSSL_VERSION_NUMBER 0x1010000fL
|
||||||
|
#elif (LIBRESSL_VERSION_NUMBER >= 0x2070000fL)
|
||||||
|
#define OPENSSL_VERSION_NUMBER 0x1000200fL
|
||||||
|
#else
|
||||||
|
#define OPENSSL_VERSION_NUMBER 0x1000107fL
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
struct _tls {
|
struct _tls {
|
||||||
xmpp_ctx_t *ctx;
|
xmpp_ctx_t *ctx;
|
||||||
sock_t sock;
|
sock_t sock;
|
||||||
@@ -46,16 +64,38 @@ enum {
|
|||||||
static void _tls_sock_wait(tls_t *tls, int error);
|
static void _tls_sock_wait(tls_t *tls, int error);
|
||||||
static void _tls_set_error(tls_t *tls, int error);
|
static void _tls_set_error(tls_t *tls, int error);
|
||||||
static void _tls_log_error(xmpp_ctx_t *ctx);
|
static void _tls_log_error(xmpp_ctx_t *ctx);
|
||||||
|
static void _tls_dump_cert_info(tls_t *tls);
|
||||||
|
|
||||||
void tls_initialize(void)
|
void tls_initialize(void)
|
||||||
{
|
{
|
||||||
|
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||||
SSL_library_init();
|
SSL_library_init();
|
||||||
SSL_load_error_strings();
|
SSL_load_error_strings();
|
||||||
|
#else
|
||||||
|
OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void tls_shutdown(void)
|
void tls_shutdown(void)
|
||||||
{
|
{
|
||||||
return;
|
/*
|
||||||
|
* FIXME: Don't free global tables, program or other libraries may use
|
||||||
|
* openssl after libstrophe finalization. Maybe better leak some fixed
|
||||||
|
* memory rather than cause random crashes of the main program.
|
||||||
|
*/
|
||||||
|
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||||
|
ERR_free_strings();
|
||||||
|
EVP_cleanup();
|
||||||
|
CRYPTO_cleanup_all_ex_data();
|
||||||
|
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
|
||||||
|
SSL_COMP_free_compression_methods();
|
||||||
|
#endif
|
||||||
|
#if OPENSSL_VERSION_NUMBER < 0x10000000L
|
||||||
|
ERR_remove_state(0);
|
||||||
|
#else
|
||||||
|
ERR_remove_thread_state(NULL);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int tls_error(tls_t *tls)
|
int tls_error(tls_t *tls)
|
||||||
@@ -63,29 +103,79 @@ int tls_error(tls_t *tls)
|
|||||||
return tls->lasterror;
|
return tls->lasterror;
|
||||||
}
|
}
|
||||||
|
|
||||||
tls_t *tls_new(xmpp_ctx_t *ctx, sock_t sock)
|
tls_t *tls_new(xmpp_conn_t *conn)
|
||||||
{
|
{
|
||||||
tls_t *tls = xmpp_alloc(ctx, sizeof(*tls));
|
tls_t *tls = xmpp_alloc(conn->ctx, sizeof(*tls));
|
||||||
|
int mode;
|
||||||
|
|
||||||
if (tls) {
|
if (tls) {
|
||||||
int ret;
|
int ret;
|
||||||
|
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
|
||||||
|
/* Hostname verification is supported in OpenSSL 1.0.2 and newer. */
|
||||||
|
X509_VERIFY_PARAM *param;
|
||||||
|
#endif
|
||||||
memset(tls, 0, sizeof(*tls));
|
memset(tls, 0, sizeof(*tls));
|
||||||
|
|
||||||
tls->ctx = ctx;
|
tls->ctx = conn->ctx;
|
||||||
tls->sock = sock;
|
tls->sock = conn->sock;
|
||||||
|
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||||
tls->ssl_ctx = SSL_CTX_new(SSLv23_client_method());
|
tls->ssl_ctx = SSL_CTX_new(SSLv23_client_method());
|
||||||
|
#else
|
||||||
|
tls->ssl_ctx = SSL_CTX_new(TLS_client_method());
|
||||||
|
#endif
|
||||||
if (tls->ssl_ctx == NULL)
|
if (tls->ssl_ctx == NULL)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
|
/* Enable bug workarounds. */
|
||||||
|
SSL_CTX_set_options(tls->ssl_ctx, SSL_OP_ALL);
|
||||||
|
|
||||||
|
/* Disable insecure SSL/TLS versions. */
|
||||||
|
SSL_CTX_set_options(tls->ssl_ctx, SSL_OP_NO_SSLv2); /* DROWN */
|
||||||
|
SSL_CTX_set_options(tls->ssl_ctx, SSL_OP_NO_SSLv3); /* POODLE */
|
||||||
|
SSL_CTX_set_options(tls->ssl_ctx, SSL_OP_NO_TLSv1); /* BEAST */
|
||||||
|
|
||||||
SSL_CTX_set_client_cert_cb(tls->ssl_ctx, NULL);
|
SSL_CTX_set_client_cert_cb(tls->ssl_ctx, NULL);
|
||||||
SSL_CTX_set_mode(tls->ssl_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE);
|
SSL_CTX_set_mode(tls->ssl_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE);
|
||||||
SSL_CTX_set_verify(tls->ssl_ctx, SSL_VERIFY_NONE, NULL);
|
|
||||||
|
ret = SSL_CTX_set_default_verify_paths(tls->ssl_ctx);
|
||||||
|
if (ret == 0 && !conn->tls_trust) {
|
||||||
|
/*
|
||||||
|
* Returns 1 on success and 0 on failure. A missing default
|
||||||
|
* location is still treated as a success.
|
||||||
|
* Ignore errors when XMPP_CONN_FLAG_TRUST_TLS is set.
|
||||||
|
*/
|
||||||
|
xmpp_error(tls->ctx, "tls",
|
||||||
|
"SSL_CTX_set_default_verify_paths() failed");
|
||||||
|
goto err_free_ctx;
|
||||||
|
}
|
||||||
|
|
||||||
tls->ssl = SSL_new(tls->ssl_ctx);
|
tls->ssl = SSL_new(tls->ssl_ctx);
|
||||||
if (tls->ssl == NULL)
|
if (tls->ssl == NULL)
|
||||||
goto err_free_ctx;
|
goto err_free_ctx;
|
||||||
|
|
||||||
ret = SSL_set_fd(tls->ssl, sock);
|
#if OPENSSL_VERSION_NUMBER >= 0x0908060L && !defined(OPENSSL_NO_TLSEXT)
|
||||||
|
/* Enable SNI. */
|
||||||
|
SSL_set_tlsext_host_name(tls->ssl, conn->domain);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Trust server's certificate when user sets the flag explicitly. */
|
||||||
|
mode = conn->tls_trust ? SSL_VERIFY_NONE : SSL_VERIFY_PEER;
|
||||||
|
SSL_set_verify(tls->ssl, mode, 0);
|
||||||
|
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
|
||||||
|
/* Hostname verification is supported in OpenSSL 1.0.2 and newer. */
|
||||||
|
param = SSL_get0_param(tls->ssl);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allow only complete wildcards. RFC 6125 discourages wildcard usage
|
||||||
|
* completely, and lists internationalized domain names as a reason
|
||||||
|
* against partial wildcards.
|
||||||
|
* See https://tools.ietf.org/html/rfc6125#section-7.2 for more information.
|
||||||
|
*/
|
||||||
|
X509_VERIFY_PARAM_set_hostflags(param, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
|
||||||
|
X509_VERIFY_PARAM_set1_host(param, conn->domain, 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ret = SSL_set_fd(tls->ssl, conn->sock);
|
||||||
if (ret <= 0)
|
if (ret <= 0)
|
||||||
goto err_free_ssl;
|
goto err_free_ssl;
|
||||||
}
|
}
|
||||||
@@ -97,8 +187,8 @@ err_free_ssl:
|
|||||||
err_free_ctx:
|
err_free_ctx:
|
||||||
SSL_CTX_free(tls->ssl_ctx);
|
SSL_CTX_free(tls->ssl_ctx);
|
||||||
err:
|
err:
|
||||||
xmpp_free(ctx, tls);
|
xmpp_free(conn->ctx, tls);
|
||||||
_tls_log_error(ctx);
|
_tls_log_error(conn->ctx);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,6 +208,7 @@ int tls_start(tls_t *tls)
|
|||||||
{
|
{
|
||||||
int error;
|
int error;
|
||||||
int ret;
|
int ret;
|
||||||
|
long x509_res;
|
||||||
|
|
||||||
/* Since we're non-blocking, loop the connect call until it
|
/* Since we're non-blocking, loop the connect call until it
|
||||||
succeeds or fails */
|
succeeds or fails */
|
||||||
@@ -134,8 +225,13 @@ int tls_start(tls_t *tls)
|
|||||||
/* success or fatal error */
|
/* success or fatal error */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
_tls_set_error(tls, error);
|
|
||||||
|
|
||||||
|
x509_res = SSL_get_verify_result(tls->ssl);
|
||||||
|
xmpp_debug(tls->ctx, "tls", "Certificate verification %s",
|
||||||
|
x509_res == X509_V_OK ? "passed" : "FAILED");
|
||||||
|
_tls_dump_cert_info(tls);
|
||||||
|
|
||||||
|
_tls_set_error(tls, error);
|
||||||
return ret <= 0 ? 0 : 1;
|
return ret <= 0 ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,6 +241,11 @@ int tls_stop(tls_t *tls)
|
|||||||
int error;
|
int error;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
/* According to OpenSSL.org, we must not call SSL_shutdown(3)
|
||||||
|
if a previous fatal error has occurred on a connection. */
|
||||||
|
if (tls->lasterror == SSL_ERROR_SYSCALL || tls->lasterror == SSL_ERROR_SSL)
|
||||||
|
return 1;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
++retries;
|
++retries;
|
||||||
ret = SSL_shutdown(tls->ssl);
|
ret = SSL_shutdown(tls->ssl);
|
||||||
@@ -155,6 +256,14 @@ int tls_stop(tls_t *tls)
|
|||||||
}
|
}
|
||||||
_tls_sock_wait(tls, error);
|
_tls_sock_wait(tls, error);
|
||||||
}
|
}
|
||||||
|
if (error == SSL_ERROR_SYSCALL && errno == 0) {
|
||||||
|
/*
|
||||||
|
* Handle special case when peer closes connection instead of
|
||||||
|
* proper shutdown.
|
||||||
|
*/
|
||||||
|
error = 0;
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
_tls_set_error(tls, error);
|
_tls_set_error(tls, error);
|
||||||
|
|
||||||
return ret <= 0 ? 0 : 1;
|
return ret <= 0 ? 0 : 1;
|
||||||
@@ -206,6 +315,8 @@ static void _tls_sock_wait(tls_t *tls, int error)
|
|||||||
int nfds;
|
int nfds;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
if (error == SSL_ERROR_NONE) return;
|
||||||
|
|
||||||
FD_ZERO(&rfds);
|
FD_ZERO(&rfds);
|
||||||
FD_ZERO(&wfds);
|
FD_ZERO(&wfds);
|
||||||
if (error == SSL_ERROR_WANT_READ)
|
if (error == SSL_ERROR_WANT_READ)
|
||||||
@@ -224,6 +335,7 @@ static void _tls_sock_wait(tls_t *tls, int error)
|
|||||||
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(error)) {
|
||||||
|
xmpp_debug(tls->ctx, "tls", "error=%d errno=%d", error, errno);
|
||||||
_tls_log_error(tls->ctx);
|
_tls_log_error(tls->ctx);
|
||||||
}
|
}
|
||||||
tls->lasterror = error;
|
tls->lasterror = error;
|
||||||
@@ -242,3 +354,26 @@ static void _tls_log_error(xmpp_ctx_t *ctx)
|
|||||||
}
|
}
|
||||||
} while (e != 0);
|
} while (e != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void _tls_dump_cert_info(tls_t *tls)
|
||||||
|
{
|
||||||
|
X509 *cert;
|
||||||
|
char *name;
|
||||||
|
|
||||||
|
cert = SSL_get_peer_certificate(tls->ssl);
|
||||||
|
if (cert == NULL)
|
||||||
|
xmpp_debug(tls->ctx, "tls", "Certificate was not presented by peer");
|
||||||
|
else {
|
||||||
|
name = X509_NAME_oneline(X509_get_subject_name(cert), NULL, 0);
|
||||||
|
if (name != NULL) {
|
||||||
|
xmpp_debug(tls->ctx, "tls", "Subject=%s", name);
|
||||||
|
OPENSSL_free(name);
|
||||||
|
}
|
||||||
|
name = X509_NAME_oneline(X509_get_issuer_name(cert), NULL, 0);
|
||||||
|
if (name != NULL) {
|
||||||
|
xmpp_debug(tls->ctx, "tls", "Issuer=%s", name);
|
||||||
|
OPENSSL_free(name);
|
||||||
|
}
|
||||||
|
X509_free(cert);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
|
|
||||||
struct _tls {
|
struct _tls {
|
||||||
xmpp_ctx_t *ctx;
|
xmpp_ctx_t *ctx;
|
||||||
|
xmpp_conn_t *conn;
|
||||||
sock_t sock;
|
sock_t sock;
|
||||||
|
|
||||||
HANDLE hsec32;
|
HANDLE hsec32;
|
||||||
@@ -60,8 +61,10 @@ void tls_shutdown(void)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
tls_t *tls_new(xmpp_ctx_t *ctx, sock_t sock)
|
tls_t *tls_new(xmpp_conn_t *conn)
|
||||||
{
|
{
|
||||||
|
xmpp_ctx_t *ctx = conn->ctx;
|
||||||
|
sock_t sock = conn->sock;
|
||||||
tls_t *tls;
|
tls_t *tls;
|
||||||
PSecurityFunctionTable (*pInitSecurityInterface)(void);
|
PSecurityFunctionTable (*pInitSecurityInterface)(void);
|
||||||
SCHANNEL_CRED scred;
|
SCHANNEL_CRED scred;
|
||||||
@@ -92,6 +95,7 @@ tls_t *tls_new(xmpp_ctx_t *ctx, sock_t sock)
|
|||||||
|
|
||||||
memset(tls, 0, sizeof(*tls));
|
memset(tls, 0, sizeof(*tls));
|
||||||
tls->ctx = ctx;
|
tls->ctx = ctx;
|
||||||
|
tls->conn = conn;
|
||||||
tls->sock = sock;
|
tls->sock = sock;
|
||||||
|
|
||||||
if (!(tls->hsec32 = LoadLibrary ("secur32.dll"))) {
|
if (!(tls->hsec32 = LoadLibrary ("secur32.dll"))) {
|
||||||
@@ -216,24 +220,10 @@ int tls_start(tls_t *tls)
|
|||||||
SecBuffer sbin[2], sbout[1];
|
SecBuffer sbin[2], sbout[1];
|
||||||
SECURITY_STATUS ret;
|
SECURITY_STATUS ret;
|
||||||
int sent;
|
int sent;
|
||||||
char *name = NULL;
|
char *name;
|
||||||
|
|
||||||
/* search the ctx's conns for our sock, and use the domain there as our
|
/* use the domain there as our name */
|
||||||
* name */
|
name = tls->conn->domain;
|
||||||
{
|
|
||||||
xmpp_connlist_t *listentry = tls->ctx->connlist;
|
|
||||||
|
|
||||||
while (listentry) {
|
|
||||||
xmpp_conn_t *conn = listentry->conn;
|
|
||||||
|
|
||||||
if (conn->sock == tls->sock) {
|
|
||||||
name = strdup(conn->domain);
|
|
||||||
listentry = NULL;
|
|
||||||
} else {
|
|
||||||
listentry = listentry->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
||||||
@@ -265,10 +255,18 @@ int tls_start(tls_t *tls)
|
|||||||
NULL, 0, &(tls->hctxt), &sbdout,
|
NULL, 0, &(tls->hctxt), &sbdout,
|
||||||
&ctxtattr, NULL);
|
&ctxtattr, NULL);
|
||||||
|
|
||||||
while (ret == SEC_I_CONTINUE_NEEDED
|
|
||||||
|| ret == SEC_I_INCOMPLETE_CREDENTIALS) {
|
|
||||||
unsigned char *p = sbin[0].pvBuffer;
|
unsigned char *p = sbin[0].pvBuffer;
|
||||||
int len = 0, inbytes = 0;
|
int len = 0;
|
||||||
|
|
||||||
|
while (ret == SEC_I_CONTINUE_NEEDED
|
||||||
|
|| ret == SEC_I_INCOMPLETE_CREDENTIALS
|
||||||
|
|| ret == SEC_E_INCOMPLETE_MESSAGE) {
|
||||||
|
int inbytes = 0;
|
||||||
|
|
||||||
|
if (ret != SEC_E_INCOMPLETE_MESSAGE) {
|
||||||
|
len = 0;
|
||||||
|
p = sbin[0].pvBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
if (sbdout.pBuffers[0].cbBuffer) {
|
if (sbdout.pBuffers[0].cbBuffer) {
|
||||||
unsigned char *writebuff = sbdout.pBuffers[0].pvBuffer;
|
unsigned char *writebuff = sbdout.pBuffers[0].pvBuffer;
|
||||||
|
|||||||
@@ -86,7 +86,12 @@ char *xmpp_strtok_r(char *s, const char *delim, char **saveptr)
|
|||||||
*/
|
*/
|
||||||
uint64_t time_stamp(void)
|
uint64_t time_stamp(void)
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#if defined(_XBOX_ONE)
|
||||||
|
uint64_t SystemTime;
|
||||||
|
GetSystemTimeAsFileTime((FILETIME*)&SystemTime);
|
||||||
|
/* Convert 100 nanosec ticks to milliseconds */
|
||||||
|
return (SystemTime / 10000);
|
||||||
|
#elif defined(_WIN32)
|
||||||
return timeGetTime();
|
return timeGetTime();
|
||||||
#else
|
#else
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
|
|||||||
32
strophe.h
32
strophe.h
@@ -71,6 +71,14 @@ extern "C" {
|
|||||||
* Namespace definition for 'jabber:iq:roster'.
|
* Namespace definition for 'jabber:iq:roster'.
|
||||||
*/
|
*/
|
||||||
#define XMPP_NS_ROSTER "jabber:iq:roster"
|
#define XMPP_NS_ROSTER "jabber:iq:roster"
|
||||||
|
/** @def XMPP_NS_REGISTER
|
||||||
|
* Namespace definition for 'jabber:iq:register'.
|
||||||
|
*/
|
||||||
|
#define XMPP_NS_REGISTER "jabber:iq:register"
|
||||||
|
/** @def XMPP_NS_SM
|
||||||
|
* Namespace definition for Stream Management.
|
||||||
|
*/
|
||||||
|
#define XMPP_NS_SM "urn:xmpp:sm:3"
|
||||||
|
|
||||||
/* error defines */
|
/* error defines */
|
||||||
/** @def XMPP_EOK
|
/** @def XMPP_EOK
|
||||||
@@ -165,6 +173,14 @@ typedef struct _xmpp_stanza_t xmpp_stanza_t;
|
|||||||
#define XMPP_CONN_FLAG_DISABLE_TLS (1UL << 0)
|
#define XMPP_CONN_FLAG_DISABLE_TLS (1UL << 0)
|
||||||
#define XMPP_CONN_FLAG_MANDATORY_TLS (1UL << 1)
|
#define XMPP_CONN_FLAG_MANDATORY_TLS (1UL << 1)
|
||||||
#define XMPP_CONN_FLAG_LEGACY_SSL (1UL << 2)
|
#define XMPP_CONN_FLAG_LEGACY_SSL (1UL << 2)
|
||||||
|
/** @def XMPP_CONN_FLAG_TRUST_TLS
|
||||||
|
* Trust server's certificate even if it is invalid.
|
||||||
|
*/
|
||||||
|
#define XMPP_CONN_FLAG_TRUST_TLS (1UL << 3)
|
||||||
|
/** @def XMPP_CONN_FLAG_LEGACY_AUTH
|
||||||
|
* Enable legacy authentication support.
|
||||||
|
*/
|
||||||
|
#define XMPP_CONN_FLAG_LEGACY_AUTH (1UL << 4)
|
||||||
|
|
||||||
/* connect callback */
|
/* connect callback */
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@@ -213,6 +229,7 @@ typedef void (*xmpp_conn_handler)(xmpp_conn_t * const conn,
|
|||||||
xmpp_stream_error_t * const stream_error,
|
xmpp_stream_error_t * const stream_error,
|
||||||
void * const userdata);
|
void * const userdata);
|
||||||
|
|
||||||
|
void xmpp_send_error(xmpp_conn_t * const conn, xmpp_error_type_t const type, char * const text);
|
||||||
xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t * const ctx);
|
xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t * const ctx);
|
||||||
xmpp_conn_t *xmpp_conn_clone(xmpp_conn_t * const conn);
|
xmpp_conn_t *xmpp_conn_clone(xmpp_conn_t * const conn);
|
||||||
int xmpp_conn_release(xmpp_conn_t * const conn);
|
int xmpp_conn_release(xmpp_conn_t * const conn);
|
||||||
@@ -228,6 +245,9 @@ xmpp_ctx_t *xmpp_conn_get_context(xmpp_conn_t * const conn);
|
|||||||
void xmpp_conn_disable_tls(xmpp_conn_t * const conn);
|
void xmpp_conn_disable_tls(xmpp_conn_t * const conn);
|
||||||
int xmpp_conn_is_secured(xmpp_conn_t * const conn);
|
int xmpp_conn_is_secured(xmpp_conn_t * const conn);
|
||||||
void xmpp_conn_set_keepalive(xmpp_conn_t * const conn, int timeout, int interval);
|
void xmpp_conn_set_keepalive(xmpp_conn_t * const conn, int timeout, int interval);
|
||||||
|
int xmpp_conn_is_connecting(xmpp_conn_t * const conn);
|
||||||
|
int xmpp_conn_is_connected(xmpp_conn_t * const conn);
|
||||||
|
int xmpp_conn_is_disconnected(xmpp_conn_t * const conn);
|
||||||
|
|
||||||
int xmpp_connect_client(xmpp_conn_t * const conn,
|
int xmpp_connect_client(xmpp_conn_t * const conn,
|
||||||
const char * const altdomain,
|
const char * const altdomain,
|
||||||
@@ -314,6 +334,8 @@ xmpp_stanza_t *xmpp_stanza_copy(const xmpp_stanza_t * const stanza);
|
|||||||
/* free a stanza object and it's contents */
|
/* free a stanza object and it's contents */
|
||||||
int xmpp_stanza_release(xmpp_stanza_t * const stanza);
|
int xmpp_stanza_release(xmpp_stanza_t * const stanza);
|
||||||
|
|
||||||
|
xmpp_ctx_t *xmpp_stanza_get_context(const xmpp_stanza_t * const stanza);
|
||||||
|
|
||||||
int xmpp_stanza_is_text(xmpp_stanza_t * const stanza);
|
int xmpp_stanza_is_text(xmpp_stanza_t * const stanza);
|
||||||
int xmpp_stanza_is_tag(xmpp_stanza_t * const stanza);
|
int xmpp_stanza_is_tag(xmpp_stanza_t * const stanza);
|
||||||
|
|
||||||
@@ -326,8 +348,13 @@ xmpp_stanza_t *xmpp_stanza_get_child_by_name(xmpp_stanza_t * const stanza,
|
|||||||
const char * const name);
|
const char * const name);
|
||||||
xmpp_stanza_t *xmpp_stanza_get_child_by_ns(xmpp_stanza_t * const stanza,
|
xmpp_stanza_t *xmpp_stanza_get_child_by_ns(xmpp_stanza_t * const stanza,
|
||||||
const char * const ns);
|
const char * const ns);
|
||||||
|
xmpp_stanza_t *xmpp_stanza_get_child_by_name_and_ns(xmpp_stanza_t * const stanza,
|
||||||
|
const char * const name,
|
||||||
|
const char * const ns);
|
||||||
xmpp_stanza_t *xmpp_stanza_get_next(xmpp_stanza_t * const stanza);
|
xmpp_stanza_t *xmpp_stanza_get_next(xmpp_stanza_t * const stanza);
|
||||||
int xmpp_stanza_add_child(xmpp_stanza_t *stanza, xmpp_stanza_t *child);
|
int xmpp_stanza_add_child(xmpp_stanza_t *stanza, xmpp_stanza_t *child);
|
||||||
|
int xmpp_stanza_add_child_ex(xmpp_stanza_t *stanza, xmpp_stanza_t *child,
|
||||||
|
int do_clone);
|
||||||
|
|
||||||
const char *xmpp_stanza_get_attribute(xmpp_stanza_t * const stanza,
|
const char *xmpp_stanza_get_attribute(xmpp_stanza_t * const stanza,
|
||||||
const char * const name);
|
const char * const name);
|
||||||
@@ -377,6 +404,8 @@ int xmpp_message_set_body(xmpp_stanza_t *msg, const char * const text);
|
|||||||
xmpp_stanza_t *xmpp_iq_new(xmpp_ctx_t *ctx, const char * const type,
|
xmpp_stanza_t *xmpp_iq_new(xmpp_ctx_t *ctx, const char * const type,
|
||||||
const char * const id);
|
const char * const id);
|
||||||
xmpp_stanza_t *xmpp_presence_new(xmpp_ctx_t *ctx);
|
xmpp_stanza_t *xmpp_presence_new(xmpp_ctx_t *ctx);
|
||||||
|
xmpp_stanza_t *xmpp_error_new(xmpp_ctx_t *ctx, xmpp_error_type_t const type,
|
||||||
|
const char * const text);
|
||||||
|
|
||||||
/* jid */
|
/* jid */
|
||||||
|
|
||||||
@@ -394,6 +423,7 @@ char *xmpp_jid_resource(xmpp_ctx_t *ctx, const char *jid);
|
|||||||
void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout);
|
void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout);
|
||||||
void xmpp_run(xmpp_ctx_t *ctx);
|
void xmpp_run(xmpp_ctx_t *ctx);
|
||||||
void xmpp_stop(xmpp_ctx_t *ctx);
|
void xmpp_stop(xmpp_ctx_t *ctx);
|
||||||
|
void xmpp_ctx_set_timeout(xmpp_ctx_t * const ctx, const unsigned long timeout);
|
||||||
|
|
||||||
/* UUID */
|
/* UUID */
|
||||||
|
|
||||||
@@ -409,6 +439,8 @@ char *xmpp_uuid_gen(xmpp_ctx_t *ctx);
|
|||||||
typedef struct _xmpp_sha1_t xmpp_sha1_t;
|
typedef struct _xmpp_sha1_t xmpp_sha1_t;
|
||||||
|
|
||||||
char *xmpp_sha1(xmpp_ctx_t *ctx, const unsigned char *data, size_t len);
|
char *xmpp_sha1(xmpp_ctx_t *ctx, const unsigned char *data, size_t len);
|
||||||
|
void xmpp_sha1_digest(const unsigned char *data, size_t len,
|
||||||
|
unsigned char *digest);
|
||||||
|
|
||||||
xmpp_sha1_t *xmpp_sha1_new(xmpp_ctx_t *ctx);
|
xmpp_sha1_t *xmpp_sha1_new(xmpp_ctx_t *ctx);
|
||||||
void xmpp_sha1_free(xmpp_sha1_t *sha1);
|
void xmpp_sha1_free(xmpp_sha1_t *sha1);
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ int main(int argc, char **argv)
|
|||||||
len = res_query(fulldomain, C_IN, T_SRV, buf, sizeof(buf));
|
len = res_query(fulldomain, C_IN, T_SRV, buf, sizeof(buf));
|
||||||
|
|
||||||
if (len < 0) {
|
if (len < 0) {
|
||||||
fprintf(stderr, "res_query(): Error occured (errno=%d)\n", errno);
|
fprintf(stderr, "res_query(): Error occurred (errno=%d)\n", errno);
|
||||||
}
|
}
|
||||||
if (len == 0) {
|
if (len == 0) {
|
||||||
fprintf(stderr, "res_query(): Empty result\n");
|
fprintf(stderr, "res_query(): Empty result\n");
|
||||||
|
|||||||
@@ -134,8 +134,7 @@ int main(int argc, char *argv[])
|
|||||||
unsigned char *udec;
|
unsigned char *udec;
|
||||||
char *dec;
|
char *dec;
|
||||||
char *enc;
|
char *enc;
|
||||||
size_t len;
|
size_t len, i;
|
||||||
int i;
|
|
||||||
|
|
||||||
printf("BASE64 tests.\n");
|
printf("BASE64 tests.\n");
|
||||||
|
|
||||||
|
|||||||
@@ -16,18 +16,19 @@
|
|||||||
#include "strophe.h"
|
#include "strophe.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "hash.h"
|
#include "hash.h"
|
||||||
|
#include "test.h"
|
||||||
|
|
||||||
#define TABLESIZE 100
|
#define TABLESIZE 100
|
||||||
#define TESTSIZE 500
|
#define TESTSIZE 500
|
||||||
|
|
||||||
/* static test data */
|
/* static test data */
|
||||||
const int nkeys = 5;
|
|
||||||
const char *keys[] = {
|
const char *keys[] = {
|
||||||
"foo", "bar", "baz", "quux", "xyzzy"
|
"foo", "bar", "baz", "quux", "xyzzy"
|
||||||
};
|
};
|
||||||
const char *values[] = {
|
const char *values[] = {
|
||||||
"wuzzle", "mug", "canonical", "rosebud", "lottery"
|
"wuzzle", "mug", "canonical", "rosebud", "lottery"
|
||||||
};
|
};
|
||||||
|
const int nkeys = ARRAY_SIZE(keys);
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
@@ -58,7 +59,7 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* allocate a hash table */
|
/* allocate a hash table */
|
||||||
table = hash_new(ctx, TABLESIZE, NULL);
|
table = hash_new(ctx, TABLESIZE, xmpp_free);
|
||||||
if (table == NULL) {
|
if (table == NULL) {
|
||||||
/* table allocation failed! */
|
/* table allocation failed! */
|
||||||
return 1;
|
return 1;
|
||||||
@@ -66,7 +67,7 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
/* test insertion */
|
/* test insertion */
|
||||||
for (i = 0; i < nkeys; i++) {
|
for (i = 0; i < nkeys; i++) {
|
||||||
err = hash_add(table, keys[i], (void*)values[i]);
|
err = hash_add(table, keys[i], xmpp_strdup(ctx, values[i]));
|
||||||
if (err) return err;
|
if (err) return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,6 +77,18 @@ int main(int argc, char **argv)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* test replacing old values */
|
||||||
|
for (i = 0; i < nkeys; i++) {
|
||||||
|
err = hash_add(table, keys[0], xmpp_strdup(ctx, values[i]));
|
||||||
|
if (err) return err;
|
||||||
|
if (hash_num_keys(table) != nkeys) return 1;
|
||||||
|
result = hash_get(table, keys[0]);
|
||||||
|
if (result == NULL) return 1;
|
||||||
|
if (strcmp(result, values[i]) != 0) return 1;
|
||||||
|
}
|
||||||
|
/* restore value for the 1st key */
|
||||||
|
hash_add(table, keys[0], xmpp_strdup(ctx, values[0]));
|
||||||
|
|
||||||
/* test cloning */
|
/* test cloning */
|
||||||
clone = hash_clone(table);
|
clone = hash_clone(table);
|
||||||
|
|
||||||
|
|||||||
@@ -27,54 +27,67 @@ static const char *_s(const char *s)
|
|||||||
|
|
||||||
int test_jid(xmpp_ctx_t *ctx)
|
int test_jid(xmpp_ctx_t *ctx)
|
||||||
{
|
{
|
||||||
|
char *bare;
|
||||||
char *node;
|
char *node;
|
||||||
char *domain;
|
char *domain;
|
||||||
char *resource;
|
char *resource;
|
||||||
|
|
||||||
|
bare = xmpp_jid_bare(ctx, jid1);
|
||||||
node = xmpp_jid_node(ctx, jid1);
|
node = xmpp_jid_node(ctx, jid1);
|
||||||
domain = xmpp_jid_domain(ctx, jid1);
|
domain = xmpp_jid_domain(ctx, jid1);
|
||||||
resource = xmpp_jid_resource(ctx, jid1);
|
resource = xmpp_jid_resource(ctx, jid1);
|
||||||
printf("jid '%s' parsed to %s, %s, %s\n",
|
printf("jid '%s' parsed to %s, %s, %s\n",
|
||||||
jid1, _s(node), _s(domain), _s(resource));
|
jid1, _s(node), _s(domain), _s(resource));
|
||||||
|
if (bare == NULL || strcmp(bare, "foo@bar.com")) return 1;
|
||||||
if (node == NULL || strcmp(node, "foo")) return 1;
|
if (node == NULL || strcmp(node, "foo")) return 1;
|
||||||
if (domain == NULL || strcmp(domain, "bar.com")) return 1;
|
if (domain == NULL || strcmp(domain, "bar.com")) return 1;
|
||||||
if (resource != NULL) return 1;
|
if (resource != NULL) return 1;
|
||||||
|
if (bare) xmpp_free(ctx, bare);
|
||||||
if (node) xmpp_free(ctx, node);
|
if (node) xmpp_free(ctx, node);
|
||||||
if (domain) xmpp_free(ctx, domain);
|
if (domain) xmpp_free(ctx, domain);
|
||||||
if (resource) xmpp_free(ctx, resource);
|
if (resource) xmpp_free(ctx, resource);
|
||||||
|
|
||||||
|
bare = xmpp_jid_bare(ctx, jid2);
|
||||||
node = xmpp_jid_node(ctx, jid2);
|
node = xmpp_jid_node(ctx, jid2);
|
||||||
domain = xmpp_jid_domain(ctx, jid2);
|
domain = xmpp_jid_domain(ctx, jid2);
|
||||||
resource = xmpp_jid_resource(ctx, jid2);
|
resource = xmpp_jid_resource(ctx, jid2);
|
||||||
printf("jid '%s' parsed to %s, %s, %s\n",
|
printf("jid '%s' parsed to %s, %s, %s\n",
|
||||||
jid2, _s(node), _s(domain), _s(resource));
|
jid2, _s(node), _s(domain), _s(resource));
|
||||||
|
if (bare == NULL || strcmp(bare, "anyone@example.com")) return 1;
|
||||||
if (node == NULL || strcmp(node, "anyone")) return 1;
|
if (node == NULL || strcmp(node, "anyone")) return 1;
|
||||||
if (domain == NULL || strcmp(domain, "example.com")) return 1;
|
if (domain == NULL || strcmp(domain, "example.com")) return 1;
|
||||||
if (resource == NULL || strcmp(resource, "hullo")) return 1;
|
if (resource == NULL || strcmp(resource, "hullo")) return 1;
|
||||||
|
if (bare) xmpp_free(ctx, bare);
|
||||||
if (node) xmpp_free(ctx, node);
|
if (node) xmpp_free(ctx, node);
|
||||||
if (domain) xmpp_free(ctx, domain);
|
if (domain) xmpp_free(ctx, domain);
|
||||||
if (resource) xmpp_free(ctx, resource);
|
if (resource) xmpp_free(ctx, resource);
|
||||||
|
|
||||||
|
bare = xmpp_jid_bare(ctx, jid3);
|
||||||
node = xmpp_jid_node(ctx, jid3);
|
node = xmpp_jid_node(ctx, jid3);
|
||||||
domain = xmpp_jid_domain(ctx, jid3);
|
domain = xmpp_jid_domain(ctx, jid3);
|
||||||
resource = xmpp_jid_resource(ctx, jid3);
|
resource = xmpp_jid_resource(ctx, jid3);
|
||||||
printf("jid '%s' parsed to %s, %s, %s\n",
|
printf("jid '%s' parsed to %s, %s, %s\n",
|
||||||
jid3, _s(node), _s(domain), _s(resource));
|
jid3, _s(node), _s(domain), _s(resource));
|
||||||
|
if (bare == NULL || strcmp(bare, "manic.porter@xyz.net")) return 1;
|
||||||
if (node == NULL || strcmp(node, "manic.porter")) return 1;
|
if (node == NULL || strcmp(node, "manic.porter")) return 1;
|
||||||
if (domain == NULL || strcmp(domain, "xyz.net")) return 1;
|
if (domain == NULL || strcmp(domain, "xyz.net")) return 1;
|
||||||
if (resource == NULL || strcmp(resource, "frob")) return 1;
|
if (resource == NULL || strcmp(resource, "frob")) return 1;
|
||||||
|
if (bare) xmpp_free(ctx, bare);
|
||||||
if (node) xmpp_free(ctx, node);
|
if (node) xmpp_free(ctx, node);
|
||||||
if (domain) xmpp_free(ctx, domain);
|
if (domain) xmpp_free(ctx, domain);
|
||||||
if (resource) xmpp_free(ctx, resource);
|
if (resource) xmpp_free(ctx, resource);
|
||||||
|
|
||||||
|
bare = xmpp_jid_bare(ctx, jid4);
|
||||||
node = xmpp_jid_node(ctx, jid4);
|
node = xmpp_jid_node(ctx, jid4);
|
||||||
domain = xmpp_jid_domain(ctx, jid4);
|
domain = xmpp_jid_domain(ctx, jid4);
|
||||||
resource = xmpp_jid_resource(ctx, jid4);
|
resource = xmpp_jid_resource(ctx, jid4);
|
||||||
printf("jid '%s' parsed to %s, %s, %s\n",
|
printf("jid '%s' parsed to %s, %s, %s\n",
|
||||||
jid4, _s(node), _s(domain), _s(resource));
|
jid4, _s(node), _s(domain), _s(resource));
|
||||||
|
if (bare == NULL || strcmp(bare, "domain.tld")) return 1;
|
||||||
if (node != NULL) return 1;
|
if (node != NULL) return 1;
|
||||||
if (domain == NULL || strcmp(domain, "domain.tld")) return 1;
|
if (domain == NULL || strcmp(domain, "domain.tld")) return 1;
|
||||||
if (resource != NULL) return 1;
|
if (resource != NULL) return 1;
|
||||||
|
if (bare) xmpp_free(ctx, bare);
|
||||||
if (node) xmpp_free(ctx, node);
|
if (node) xmpp_free(ctx, node);
|
||||||
if (domain) xmpp_free(ctx, domain);
|
if (domain) xmpp_free(ctx, domain);
|
||||||
if (resource) xmpp_free(ctx, resource);
|
if (resource) xmpp_free(ctx, resource);
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ static void digest_to_hex(const uint8_t *digest, char *output)
|
|||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
int k;
|
size_t k;
|
||||||
SHA1_CTX context;
|
SHA1_CTX context;
|
||||||
uint8_t digest[20];
|
uint8_t digest[20];
|
||||||
char output[80];
|
char output[80];
|
||||||
|
|||||||
96
tests/test_stanza.c
Normal file
96
tests/test_stanza.c
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
/* test_stanza.c
|
||||||
|
* libstrophe XMPP client library -- test routines for stanza functions
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020 Dmitry Podgorny <pasis.ua@gmail.com>
|
||||||
|
*
|
||||||
|
* This software is provided AS-IS with no warranty, either express
|
||||||
|
* or implied.
|
||||||
|
*
|
||||||
|
* This program is dual licensed under the MIT and GPLv3 licenses.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* gcc -o test_stanza -I./src tests/test_stanza.c -lstrophe */
|
||||||
|
|
||||||
|
#include <strophe.h>
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#define MAGICPTR ((void *)0xfeedbeef)
|
||||||
|
static unsigned long used_blocks = 0;
|
||||||
|
|
||||||
|
static void *stanza_alloc(size_t size, void *userdata)
|
||||||
|
{
|
||||||
|
assert(userdata == MAGICPTR);
|
||||||
|
|
||||||
|
++used_blocks;
|
||||||
|
return malloc(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void stanza_free(void *ptr, void *userdata)
|
||||||
|
{
|
||||||
|
assert(userdata == MAGICPTR);
|
||||||
|
|
||||||
|
--used_blocks;
|
||||||
|
free(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *stanza_realloc(void *ptr, size_t size, void *userdata)
|
||||||
|
{
|
||||||
|
assert(userdata == MAGICPTR);
|
||||||
|
|
||||||
|
return realloc(ptr, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const xmpp_mem_t stanza_mem = {
|
||||||
|
.alloc = &stanza_alloc,
|
||||||
|
.free = &stanza_free,
|
||||||
|
.realloc = &stanza_realloc,
|
||||||
|
.userdata = MAGICPTR,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void test_stanza_add_child(xmpp_ctx_t *ctx)
|
||||||
|
{
|
||||||
|
xmpp_stanza_t *stanza;
|
||||||
|
xmpp_stanza_t *child;
|
||||||
|
unsigned long baseline = used_blocks;
|
||||||
|
|
||||||
|
/* xmpp_stanza_add_child */
|
||||||
|
|
||||||
|
stanza = xmpp_stanza_new(ctx);
|
||||||
|
child = xmpp_stanza_new(ctx);
|
||||||
|
assert(stanza != NULL);
|
||||||
|
assert(child != NULL);
|
||||||
|
xmpp_stanza_add_child(stanza, child);
|
||||||
|
xmpp_stanza_release(stanza);
|
||||||
|
assert(used_blocks > baseline);
|
||||||
|
xmpp_stanza_release(child);
|
||||||
|
assert(used_blocks == baseline);
|
||||||
|
|
||||||
|
/* xmpp_stanza_add_child_ex */
|
||||||
|
|
||||||
|
stanza = xmpp_stanza_new(ctx);
|
||||||
|
child = xmpp_stanza_new(ctx);
|
||||||
|
assert(stanza != NULL);
|
||||||
|
assert(child != NULL);
|
||||||
|
xmpp_stanza_add_child_ex(stanza, child, 0);
|
||||||
|
xmpp_stanza_release(stanza);
|
||||||
|
assert(used_blocks == baseline);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
xmpp_ctx_t *ctx;
|
||||||
|
|
||||||
|
xmpp_initialize();
|
||||||
|
ctx = xmpp_ctx_new(&stanza_mem, NULL);
|
||||||
|
assert(ctx != NULL);
|
||||||
|
|
||||||
|
test_stanza_add_child(ctx);
|
||||||
|
|
||||||
|
xmpp_ctx_free(ctx);
|
||||||
|
xmpp_shutdown();
|
||||||
|
|
||||||
|
/* All allocated blocks must be freed. */
|
||||||
|
assert(used_blocks == 0);
|
||||||
|
}
|
||||||
@@ -20,6 +20,16 @@
|
|||||||
|
|
||||||
#include "test.h" /* ARRAY_SIZE */
|
#include "test.h" /* ARRAY_SIZE */
|
||||||
|
|
||||||
|
/* strtok_s() has appeared in visual studio 2005.
|
||||||
|
Use own implementation for older versions. */
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
# if (_MSC_VER >= 1400)
|
||||||
|
# define strtok_r strtok_s
|
||||||
|
# else
|
||||||
|
# define strtok_r xmpp_strtok_r
|
||||||
|
# endif
|
||||||
|
#endif /* _MSC_VER */
|
||||||
|
|
||||||
static int test_strtok_r(void)
|
static int test_strtok_r(void)
|
||||||
{
|
{
|
||||||
const char *test = "-abc-=-def--";
|
const char *test = "-abc-=-def--";
|
||||||
@@ -79,7 +89,7 @@ static int test_strdup_one(xmpp_ctx_t *ctx, const char *s)
|
|||||||
static int test_strdup(void)
|
static int test_strdup(void)
|
||||||
{
|
{
|
||||||
xmpp_ctx_t *ctx;
|
xmpp_ctx_t *ctx;
|
||||||
int i;
|
size_t i;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
static const char *tests[] = { "", "\0", "test", "s p a c e", "\n\r" };
|
static const char *tests[] = { "", "\0", "test", "s p a c e", "\n\r" };
|
||||||
|
|||||||
Reference in New Issue
Block a user