Compare commits
180 Commits
0.9.1
...
unify-erro
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
070a64d9d5 | ||
|
|
9ee08f8f2a | ||
|
|
7c1061ccbb | ||
|
|
7eab7c3f5e | ||
|
|
4d93b6c0d6 | ||
|
|
65b3a0996f | ||
|
|
4dd78be10d | ||
|
|
8c076ac969 | ||
|
|
7c68aced35 | ||
|
|
197896ba1b | ||
|
|
bef411f319 | ||
|
|
7f5ce7d2ae | ||
|
|
47e27c837a | ||
|
|
50a4a983cd | ||
|
|
428681a185 | ||
|
|
3dcc5a60f2 | ||
|
|
cba21b5598 | ||
|
|
a65dd1059d | ||
|
|
7c83eb0efa | ||
|
|
f2c658723f | ||
|
|
7ac4b1cc12 | ||
|
|
1c4cb66f5a | ||
|
|
6a50c9cea6 | ||
|
|
37b12ad788 | ||
|
|
5530ac690f | ||
|
|
3063d886bd | ||
|
|
198bdd77d0 | ||
|
|
20c039fdb8 | ||
|
|
c92fc849e7 | ||
|
|
6fdac3ae72 | ||
|
|
623ff164de | ||
|
|
faa46d28a5 | ||
|
|
1ca10fd167 | ||
|
|
709e41fd10 | ||
|
|
771d5865ae | ||
|
|
fc064bc883 | ||
|
|
2ca2fcfedd | ||
|
|
d78b02ee24 | ||
|
|
2a94a49cef | ||
|
|
562a06425b | ||
|
|
eef07cef36 | ||
|
|
2e21d5a021 | ||
|
|
abd1b08a97 | ||
|
|
3feed16e2e | ||
|
|
6b38216124 | ||
|
|
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 |
11
.gitignore
vendored
11
.gitignore
vendored
@@ -1,4 +1,5 @@
|
|||||||
*.swp
|
*.swp
|
||||||
|
*.orig
|
||||||
Makefile
|
Makefile
|
||||||
test-driver
|
test-driver
|
||||||
.libs
|
.libs
|
||||||
@@ -34,8 +35,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
|
||||||
@@ -52,11 +55,17 @@ tests/test_resolver
|
|||||||
tests/test_sasl
|
tests/test_sasl
|
||||||
tests/test_scram
|
tests/test_scram
|
||||||
tests/test_sha1
|
tests/test_sha1
|
||||||
|
tests/test_sha256
|
||||||
|
tests/test_sha512
|
||||||
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/
|
||||||
obj/
|
obj/
|
||||||
expat/
|
expat/
|
||||||
|
.settings/
|
||||||
|
.project
|
||||||
|
.cproject
|
||||||
|
|||||||
27
.travis.yml
27
.travis.yml
@@ -1,11 +1,24 @@
|
|||||||
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 dos2unix
|
||||||
script:
|
stages:
|
||||||
|
- style
|
||||||
|
- test
|
||||||
|
before_script:
|
||||||
- ./bootstrap.sh
|
- ./bootstrap.sh
|
||||||
- ./configure --without-libxml2 && make CFLAGS="-Wall -Werror" && make CFLAGS="-Wall -Werror" check-TESTS
|
env:
|
||||||
- make clean
|
- CONFIGURE_OPT="--without-libxml2"
|
||||||
- ./configure --with-libxml2 && make CFLAGS="-Wall -Werror" && make CFLAGS="-Wall -Werror" check-TESTS
|
- CONFIGURE_OPT="--with-libxml2"
|
||||||
- make clean
|
- CONFIGURE_OPT="--disable-tls"
|
||||||
- ./configure --disable-tls && make CFLAGS="-Wall -Werror" && make CFLAGS="-Wall -Werror" check-TESTS
|
- CONFIGURE_OPT="--enable-cares"
|
||||||
|
script: ./configure ${CONFIGURE_OPT} CFLAGS="-Werror" && make && make check
|
||||||
|
jobs:
|
||||||
|
include:
|
||||||
|
- stage: style
|
||||||
|
name: "Check code style"
|
||||||
|
script: ./configure && make format && git diff --exit-code
|
||||||
|
env:
|
||||||
|
- CONFIGURE_OPT=""
|
||||||
|
matrix:
|
||||||
|
fast_finish: true
|
||||||
|
|||||||
51
ChangeLog
51
ChangeLog
@@ -1,3 +1,54 @@
|
|||||||
|
0.10.0
|
||||||
|
- Coding style has been unified
|
||||||
|
- SCRAM-SHA-256 and SCRAM-SHA-512 support
|
||||||
|
- c-ares support
|
||||||
|
- LibreSSL support
|
||||||
|
- Introduced global timed handlers that fire periodically regardless of
|
||||||
|
connections status, such a handler can be used to implement deferred
|
||||||
|
re-connection
|
||||||
|
- examples/register implements XEP-0077
|
||||||
|
- Fixed issue with IPv6 on Windows (#153)
|
||||||
|
- Improved portability across systems such as Haiku, Windows
|
||||||
|
- New API:
|
||||||
|
- xmpp_stanza_get_child_by_name_and_ns()
|
||||||
|
- xmpp_conn_is_connecting()
|
||||||
|
- xmpp_conn_is_connected()
|
||||||
|
- xmpp_conn_is_disconnected()
|
||||||
|
- xmpp_stanza_new_from_string()
|
||||||
|
- xmpp_stanza_add_child_ex()
|
||||||
|
- xmpp_stanza_get_context()
|
||||||
|
- xmpp_stanza_reply_error()
|
||||||
|
- xmpp_global_timed_handler_add()
|
||||||
|
- xmpp_global_timed_handler_delete()
|
||||||
|
|
||||||
|
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
|
||||||
|
|||||||
143
Makefile.am
143
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,61 @@ 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/sha256.c \
|
||||||
|
src/sha512.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/sha.h \
|
||||||
|
src/sha1.h \
|
||||||
|
src/sha256.h \
|
||||||
|
src/sha512.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
|
||||||
@@ -43,23 +77,39 @@ libstrophe_la_SOURCES += src/parser_libxml2.c
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
include_HEADERS = strophe.h
|
include_HEADERS = strophe.h
|
||||||
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 \
|
_clang-format \
|
||||||
examples/README.md
|
Doxyfile \
|
||||||
|
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 \
|
||||||
|
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 +119,38 @@ 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_sha256 \
|
||||||
|
tests/test_sha512 \
|
||||||
|
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 +169,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)
|
||||||
@@ -109,12 +187,19 @@ tests_test_resolver_LDFLAGS = -static
|
|||||||
tests_test_rand_SOURCES = tests/test_rand.c tests/test.c src/sha1.c
|
tests_test_rand_SOURCES = tests/test_rand.c tests/test.c src/sha1.c
|
||||||
tests_test_rand_CFLAGS = $(STROPHE_FLAGS) -I$(top_srcdir)/src
|
tests_test_rand_CFLAGS = $(STROPHE_FLAGS) -I$(top_srcdir)/src
|
||||||
|
|
||||||
tests_test_scram_SOURCES = tests/test_scram.c tests/test.c src/sha1.c
|
tests_test_scram_SOURCES = tests/test_scram.c tests/test.c src/sha1.c \
|
||||||
|
src/sha256.c src/sha512.c
|
||||||
tests_test_scram_CFLAGS = $(STROPHE_FLAGS) -I$(top_srcdir)/src
|
tests_test_scram_CFLAGS = $(STROPHE_FLAGS) -I$(top_srcdir)/src
|
||||||
|
|
||||||
tests_test_sha1_SOURCES = tests/test_sha1.c src/sha1.c
|
tests_test_sha1_SOURCES = tests/test_sha1.c src/sha1.c
|
||||||
tests_test_sha1_CFLAGS = -I$(top_srcdir)/src
|
tests_test_sha1_CFLAGS = -I$(top_srcdir)/src
|
||||||
|
|
||||||
|
tests_test_sha256_SOURCES = tests/test_sha256.c tests/test.c src/sha256.c
|
||||||
|
tests_test_sha256_CFLAGS = -I$(top_srcdir)/src
|
||||||
|
|
||||||
|
tests_test_sha512_SOURCES = tests/test_sha512.c tests/test.c src/sha512.c
|
||||||
|
tests_test_sha512_CFLAGS = -I$(top_srcdir)/src
|
||||||
|
|
||||||
tests_test_md5_SOURCES = tests/test_md5.c tests/test.c src/md5.c
|
tests_test_md5_SOURCES = tests/test_md5.c tests/test.c src/md5.c
|
||||||
tests_test_md5_CFLAGS = -I$(top_srcdir)/src
|
tests_test_md5_CFLAGS = -I$(top_srcdir)/src
|
||||||
|
|
||||||
@@ -125,3 +210,13 @@ 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
|
||||||
|
|
||||||
|
format:
|
||||||
|
@echo " * run clang-format on all sources"
|
||||||
|
@dos2unix -q src/*.[ch] *.h tests/*.[ch] examples/*.c
|
||||||
|
@clang-format -i src/*.[ch] *.h tests/*.[ch] examples/*.c
|
||||||
|
|||||||
@@ -5,11 +5,7 @@ libstrophe is a lightweight XMPP client library written in C. It has
|
|||||||
minimal dependencies and is configurable for various environments. It
|
minimal dependencies and is configurable for various environments. It
|
||||||
runs well on Linux, Unix and Windows based platforms.
|
runs well on Linux, Unix and Windows based platforms.
|
||||||
|
|
||||||
Its goals are:
|
libstrophe is dual licensed under MIT and GPLv3.
|
||||||
|
|
||||||
- usable quickly
|
|
||||||
- well documented
|
|
||||||
- reliable
|
|
||||||
|
|
||||||
Build Instructions
|
Build Instructions
|
||||||
------------------
|
------------------
|
||||||
|
|||||||
17
_clang-format
Normal file
17
_clang-format
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
---
|
||||||
|
AlignConsecutiveAssignments: 'false'
|
||||||
|
AlignEscapedNewlines: Left
|
||||||
|
AllowShortBlocksOnASingleLine: 'true'
|
||||||
|
AllowShortFunctionsOnASingleLine: Empty
|
||||||
|
AllowShortIfStatementsOnASingleLine: 'false'
|
||||||
|
BinPackParameters: 'false'
|
||||||
|
BreakBeforeBraces: Linux
|
||||||
|
ColumnLimit: '80'
|
||||||
|
DerivePointerAlignment: 'false'
|
||||||
|
IndentWidth: '4'
|
||||||
|
PointerAlignment: Right
|
||||||
|
SortIncludes: 'false'
|
||||||
|
TabWidth: '4'
|
||||||
|
UseTab: Never
|
||||||
|
|
||||||
|
...
|
||||||
34
configure.ac
34
configure.ac
@@ -1,4 +1,4 @@
|
|||||||
AC_INIT([libstrophe], [0.9.1], [jack@metajack.im])
|
AC_INIT([libstrophe], [0.10.0], [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,25 @@ 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"])
|
||||||
|
|
||||||
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])
|
||||||
|
AC_CHECK_DECLS([va_copy], [], [], [#include <stdarg.h>])
|
||||||
|
|
||||||
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 +75,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 +95,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 +134,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 +152,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
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ int handle_reply(xmpp_conn_t * const conn,
|
|||||||
xmpp_stanza_t *query, *item;
|
xmpp_stanza_t *query, *item;
|
||||||
const char *type;
|
const char *type;
|
||||||
|
|
||||||
|
(void)userdata;
|
||||||
|
|
||||||
type = xmpp_stanza_get_type(stanza);
|
type = xmpp_stanza_get_type(stanza);
|
||||||
if (strcmp(type, "error") == 0)
|
if (strcmp(type, "error") == 0)
|
||||||
fprintf(stderr, "ERROR: query failed\n");
|
fprintf(stderr, "ERROR: query failed\n");
|
||||||
@@ -44,21 +46,23 @@ int handle_reply(xmpp_conn_t * const conn,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void conn_handler(xmpp_conn_t * const conn, const xmpp_conn_event_t status,
|
void conn_handler(xmpp_conn_t *const conn,
|
||||||
const int error, xmpp_stream_error_t * const stream_error,
|
const xmpp_conn_event_t status,
|
||||||
|
const int error,
|
||||||
|
xmpp_stream_error_t *const stream_error,
|
||||||
void *const userdata)
|
void *const userdata)
|
||||||
{
|
{
|
||||||
xmpp_ctx_t *ctx = (xmpp_ctx_t *)userdata;
|
xmpp_ctx_t *ctx = (xmpp_ctx_t *)userdata;
|
||||||
xmpp_stanza_t *iq, *query;
|
xmpp_stanza_t *iq, *query;
|
||||||
|
|
||||||
|
(void)error;
|
||||||
|
(void)stream_error;
|
||||||
|
|
||||||
if (status == XMPP_CONN_CONNECT) {
|
if (status == XMPP_CONN_CONNECT) {
|
||||||
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);
|
||||||
|
|||||||
@@ -19,22 +19,44 @@
|
|||||||
#define KA_INTERVAL 1
|
#define KA_INTERVAL 1
|
||||||
|
|
||||||
/* define a handler for connection events */
|
/* define a handler for connection events */
|
||||||
void conn_handler(xmpp_conn_t * const conn, const xmpp_conn_event_t status,
|
void conn_handler(xmpp_conn_t *const conn,
|
||||||
const int error, xmpp_stream_error_t * const stream_error,
|
const xmpp_conn_event_t status,
|
||||||
|
const int error,
|
||||||
|
xmpp_stream_error_t *const stream_error,
|
||||||
void *const userdata)
|
void *const userdata)
|
||||||
{
|
{
|
||||||
xmpp_ctx_t *ctx = (xmpp_ctx_t *)userdata;
|
xmpp_ctx_t *ctx = (xmpp_ctx_t *)userdata;
|
||||||
int secured;
|
int secured;
|
||||||
|
|
||||||
|
(void)error;
|
||||||
|
(void)stream_error;
|
||||||
|
|
||||||
if (status == XMPP_CONN_CONNECT) {
|
if (status == XMPP_CONN_CONNECT) {
|
||||||
fprintf(stderr, "DEBUG: connected\n");
|
fprintf(stderr, "DEBUG: connected\n");
|
||||||
secured = xmpp_conn_is_secured(conn);
|
secured = xmpp_conn_is_secured(conn);
|
||||||
fprintf(stderr, "DEBUG: connection is %s.\n",
|
fprintf(stderr, "DEBUG: connection is %s.\n",
|
||||||
secured ? "secured" : "NOT secured");
|
secured ? "secured" : "NOT secured");
|
||||||
xmpp_disconnect(conn);
|
xmpp_disconnect(conn);
|
||||||
|
} else {
|
||||||
|
switch (error) {
|
||||||
|
case XMPP_EOK:
|
||||||
|
fprintf(stderr, "DEBUG: disconnected successfully.\n");
|
||||||
|
break;
|
||||||
|
case XMPP_EINVOP:
|
||||||
|
/*
|
||||||
|
* This may happen when the requested functionality is not
|
||||||
|
* supported or some data is not provided when it is required (e.g.
|
||||||
|
* resource part).
|
||||||
|
*/
|
||||||
|
fprintf(stderr, "DEBUG: disconnected, invalid operation.\n");
|
||||||
|
break;
|
||||||
|
case XMPP_ECERT:
|
||||||
|
/*
|
||||||
|
* In this case, application can reconnect with
|
||||||
|
* XMPP_CONN_FLAG_TRUST_TLS if user permits.
|
||||||
|
*/
|
||||||
|
fprintf(stderr, "DEBUG: disconnected, invalid TLS certificate.\n");
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
fprintf(stderr, "DEBUG: disconnected\n");
|
|
||||||
xmpp_stop(ctx);
|
xmpp_stop(ctx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -55,8 +77,12 @@ int main(int argc, char **argv)
|
|||||||
flags |= XMPP_CONN_FLAG_DISABLE_TLS;
|
flags |= XMPP_CONN_FLAG_DISABLE_TLS;
|
||||||
else if (strcmp(argv[i], "--mandatory-tls") == 0)
|
else if (strcmp(argv[i], "--mandatory-tls") == 0)
|
||||||
flags |= XMPP_CONN_FLAG_MANDATORY_TLS;
|
flags |= XMPP_CONN_FLAG_MANDATORY_TLS;
|
||||||
|
else if (strcmp(argv[i], "--trust-tls") == 0)
|
||||||
|
flags |= XMPP_CONN_FLAG_TRUST_TLS;
|
||||||
else if (strcmp(argv[i], "--legacy-ssl") == 0)
|
else if (strcmp(argv[i], "--legacy-ssl") == 0)
|
||||||
flags |= XMPP_CONN_FLAG_LEGACY_SSL;
|
flags |= XMPP_CONN_FLAG_LEGACY_SSL;
|
||||||
|
else if (strcmp(argv[i], "--legacy-auth") == 0)
|
||||||
|
flags |= XMPP_CONN_FLAG_LEGACY_AUTH;
|
||||||
else if (strcmp(argv[i], "--tcp-keepalive") == 0)
|
else if (strcmp(argv[i], "--tcp-keepalive") == 0)
|
||||||
tcp_keepalive = 1;
|
tcp_keepalive = 1;
|
||||||
else
|
else
|
||||||
@@ -67,7 +93,9 @@ int main(int argc, char **argv)
|
|||||||
"Options:\n"
|
"Options:\n"
|
||||||
" --disable-tls Disable TLS.\n"
|
" --disable-tls Disable TLS.\n"
|
||||||
" --mandatory-tls Deny plaintext connection.\n"
|
" --mandatory-tls Deny plaintext connection.\n"
|
||||||
|
" --trust-tls Trust TLS certificate.\n"
|
||||||
" --legacy-ssl Use old style SSL.\n"
|
" --legacy-ssl Use old style SSL.\n"
|
||||||
|
" --legacy-auth Allow legacy authentication.\n"
|
||||||
" --tcp-keepalive Configure TCP keepalive.\n\n"
|
" --tcp-keepalive Configure TCP keepalive.\n\n"
|
||||||
"Note: --disable-tls conflicts with --mandatory-tls or "
|
"Note: --disable-tls conflicts with --mandatory-tls or "
|
||||||
"--legacy-ssl\n");
|
"--legacy-ssl\n");
|
||||||
@@ -87,8 +115,9 @@ int main(int argc, char **argv)
|
|||||||
/* init library */
|
/* init library */
|
||||||
xmpp_initialize();
|
xmpp_initialize();
|
||||||
|
|
||||||
|
/* pass NULL instead to silence output */
|
||||||
|
log = xmpp_get_default_logger(XMPP_LEVEL_DEBUG);
|
||||||
/* create a context */
|
/* create a context */
|
||||||
log = xmpp_get_default_logger(XMPP_LEVEL_DEBUG); /* pass NULL instead to silence output */
|
|
||||||
ctx = xmpp_ctx_new(NULL, log);
|
ctx = xmpp_ctx_new(NULL, log);
|
||||||
|
|
||||||
/* create a connection */
|
/* create a connection */
|
||||||
@@ -97,7 +126,8 @@ int main(int argc, char **argv)
|
|||||||
/* configure connection properties (optional) */
|
/* configure connection properties (optional) */
|
||||||
xmpp_conn_set_flags(conn, flags);
|
xmpp_conn_set_flags(conn, flags);
|
||||||
/* configure TCP keepalive (optional) */
|
/* configure TCP keepalive (optional) */
|
||||||
if (tcp_keepalive) xmpp_conn_set_keepalive(conn, KA_TIMEOUT, KA_INTERVAL);
|
if (tcp_keepalive)
|
||||||
|
xmpp_conn_set_keepalive(conn, KA_TIMEOUT, KA_INTERVAL);
|
||||||
|
|
||||||
/* setup authentication information */
|
/* setup authentication information */
|
||||||
xmpp_conn_set_jid(conn, jid);
|
xmpp_conn_set_jid(conn, jid);
|
||||||
|
|||||||
@@ -22,8 +22,9 @@
|
|||||||
|
|
||||||
#include <strophe.h>
|
#include <strophe.h>
|
||||||
|
|
||||||
|
int version_handler(xmpp_conn_t *const conn,
|
||||||
int version_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata)
|
xmpp_stanza_t *const stanza,
|
||||||
|
void *const userdata)
|
||||||
{
|
{
|
||||||
xmpp_stanza_t *reply, *query, *name, *version, *text;
|
xmpp_stanza_t *reply, *query, *name, *version, *text;
|
||||||
const char *ns;
|
const char *ns;
|
||||||
@@ -69,57 +70,77 @@ int version_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int message_handler(xmpp_conn_t *const conn,
|
||||||
int message_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata)
|
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);
|
||||||
|
|
||||||
reply = xmpp_stanza_reply(stanza);
|
reply = xmpp_stanza_reply(stanza);
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* define a handler for connection events */
|
/* define a handler for connection events */
|
||||||
void conn_handler(xmpp_conn_t * const conn, const xmpp_conn_event_t status,
|
void conn_handler(xmpp_conn_t *const conn,
|
||||||
const int error, xmpp_stream_error_t * const stream_error,
|
const xmpp_conn_event_t status,
|
||||||
|
const int error,
|
||||||
|
xmpp_stream_error_t *const stream_error,
|
||||||
void *const userdata)
|
void *const userdata)
|
||||||
{
|
{
|
||||||
xmpp_ctx_t *ctx = (xmpp_ctx_t *)userdata;
|
xmpp_ctx_t *ctx = (xmpp_ctx_t *)userdata;
|
||||||
|
|
||||||
|
(void)error;
|
||||||
|
(void)stream_error;
|
||||||
|
|
||||||
if (status == XMPP_CONN_CONNECT) {
|
if (status == XMPP_CONN_CONNECT) {
|
||||||
xmpp_stanza_t *pres;
|
xmpp_stanza_t *pres;
|
||||||
fprintf(stderr, "DEBUG: connected\n");
|
fprintf(stderr, "DEBUG: connected\n");
|
||||||
xmpp_handler_add(conn, version_handler, "jabber:iq:version", "iq", NULL, ctx);
|
xmpp_handler_add(conn, version_handler, "jabber:iq:version", "iq", NULL,
|
||||||
|
ctx);
|
||||||
xmpp_handler_add(conn, message_handler, NULL, "message", NULL, ctx);
|
xmpp_handler_add(conn, message_handler, NULL, "message", NULL, ctx);
|
||||||
|
|
||||||
/* Send initial <presence/> so that we appear online to contacts */
|
/* Send initial <presence/> so that we appear online to contacts */
|
||||||
pres = xmpp_presence_new(ctx);
|
pres = xmpp_presence_new(ctx);
|
||||||
xmpp_send(conn, pres);
|
xmpp_send(conn, pres);
|
||||||
xmpp_stanza_release(pres);
|
xmpp_stanza_release(pres);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
fprintf(stderr, "DEBUG: disconnected\n");
|
fprintf(stderr, "DEBUG: disconnected\n");
|
||||||
xmpp_stop(ctx);
|
xmpp_stop(ctx);
|
||||||
}
|
}
|
||||||
@@ -144,8 +165,9 @@ int main(int argc, char **argv)
|
|||||||
/* init library */
|
/* init library */
|
||||||
xmpp_initialize();
|
xmpp_initialize();
|
||||||
|
|
||||||
|
/* pass NULL instead to silence output */
|
||||||
|
log = xmpp_get_default_logger(XMPP_LEVEL_DEBUG);
|
||||||
/* create a context */
|
/* create a context */
|
||||||
log = xmpp_get_default_logger(XMPP_LEVEL_DEBUG); /* pass NULL instead to silence output */
|
|
||||||
ctx = xmpp_ctx_new(NULL, log);
|
ctx = xmpp_ctx_new(NULL, log);
|
||||||
|
|
||||||
/* create a connection */
|
/* create a connection */
|
||||||
|
|||||||
@@ -19,19 +19,22 @@
|
|||||||
|
|
||||||
#include <strophe.h>
|
#include <strophe.h>
|
||||||
|
|
||||||
|
|
||||||
/* define a handler for connection events */
|
/* define a handler for connection events */
|
||||||
void conn_handler(xmpp_conn_t * const conn, const xmpp_conn_event_t status,
|
void conn_handler(xmpp_conn_t *const conn,
|
||||||
const int error, xmpp_stream_error_t * const stream_error,
|
const xmpp_conn_event_t status,
|
||||||
|
const int error,
|
||||||
|
xmpp_stream_error_t *const stream_error,
|
||||||
void *const userdata)
|
void *const userdata)
|
||||||
{
|
{
|
||||||
xmpp_ctx_t *ctx = (xmpp_ctx_t *)userdata;
|
xmpp_ctx_t *ctx = (xmpp_ctx_t *)userdata;
|
||||||
|
|
||||||
|
(void)error;
|
||||||
|
(void)stream_error;
|
||||||
|
|
||||||
if (status == XMPP_CONN_CONNECT) {
|
if (status == XMPP_CONN_CONNECT) {
|
||||||
fprintf(stderr, "DEBUG: connected\n");
|
fprintf(stderr, "DEBUG: connected\n");
|
||||||
xmpp_disconnect(conn);
|
xmpp_disconnect(conn);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
fprintf(stderr, "DEBUG: disconnected\n");
|
fprintf(stderr, "DEBUG: disconnected\n");
|
||||||
xmpp_stop(ctx);
|
xmpp_stop(ctx);
|
||||||
}
|
}
|
||||||
@@ -67,8 +70,9 @@ int main(int argc, char **argv)
|
|||||||
/* init library */
|
/* init library */
|
||||||
xmpp_initialize();
|
xmpp_initialize();
|
||||||
|
|
||||||
|
/* pass NULL instead to silence output */
|
||||||
|
log = xmpp_get_default_logger(XMPP_LEVEL_DEBUG);
|
||||||
/* create a context */
|
/* create a context */
|
||||||
log = xmpp_get_default_logger(XMPP_LEVEL_DEBUG); /* pass NULL instead to silence output */
|
|
||||||
ctx = xmpp_ctx_new(NULL, log);
|
ctx = xmpp_ctx_new(NULL, log);
|
||||||
|
|
||||||
/* create a connection */
|
/* create a connection */
|
||||||
@@ -94,4 +98,3 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
370
examples/register.c
Normal file
370
examples/register.c
Normal file
@@ -0,0 +1,370 @@
|
|||||||
|
/* 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;
|
||||||
|
size_t len;
|
||||||
|
char buf[256];
|
||||||
|
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 = fgets(buf, sizeof(buf), stdin);
|
||||||
|
if (s != NULL) {
|
||||||
|
len = strlen(s);
|
||||||
|
if (len > 0 && s[len - 1] == '\n') {
|
||||||
|
s[len - 1] = '\0';
|
||||||
|
--len;
|
||||||
|
}
|
||||||
|
if (len > 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
|
||||||
|
(void)userdata;
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
(void)stanza;
|
||||||
|
(void)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);
|
||||||
|
|
||||||
|
(void)userdata;
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
(void)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;
|
||||||
|
|
||||||
|
(void)error;
|
||||||
|
(void)stream_error;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
@@ -25,6 +25,8 @@ int handle_reply(xmpp_conn_t * const conn,
|
|||||||
xmpp_stanza_t *query, *item;
|
xmpp_stanza_t *query, *item;
|
||||||
const char *type, *name;
|
const char *type, *name;
|
||||||
|
|
||||||
|
(void)userdata;
|
||||||
|
|
||||||
type = xmpp_stanza_get_type(stanza);
|
type = xmpp_stanza_get_type(stanza);
|
||||||
if (strcmp(type, "error") == 0)
|
if (strcmp(type, "error") == 0)
|
||||||
fprintf(stderr, "ERROR: query failed\n");
|
fprintf(stderr, "ERROR: query failed\n");
|
||||||
@@ -34,13 +36,11 @@ int handle_reply(xmpp_conn_t * const conn,
|
|||||||
for (item = xmpp_stanza_get_children(query); item;
|
for (item = xmpp_stanza_get_children(query); item;
|
||||||
item = xmpp_stanza_get_next(item))
|
item = xmpp_stanza_get_next(item))
|
||||||
if ((name = xmpp_stanza_get_attribute(item, "name")))
|
if ((name = xmpp_stanza_get_attribute(item, "name")))
|
||||||
printf("\t %s (%s) sub=%s\n",
|
printf("\t %s (%s) sub=%s\n", name,
|
||||||
name,
|
|
||||||
xmpp_stanza_get_attribute(item, "jid"),
|
xmpp_stanza_get_attribute(item, "jid"),
|
||||||
xmpp_stanza_get_attribute(item, "subscription"));
|
xmpp_stanza_get_attribute(item, "subscription"));
|
||||||
else
|
else
|
||||||
printf("\t %s sub=%s\n",
|
printf("\t %s sub=%s\n", xmpp_stanza_get_attribute(item, "jid"),
|
||||||
xmpp_stanza_get_attribute(item, "jid"),
|
|
||||||
xmpp_stanza_get_attribute(item, "subscription"));
|
xmpp_stanza_get_attribute(item, "subscription"));
|
||||||
printf("END OF LIST\n");
|
printf("END OF LIST\n");
|
||||||
}
|
}
|
||||||
@@ -51,21 +51,23 @@ int handle_reply(xmpp_conn_t * const conn,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void conn_handler(xmpp_conn_t * const conn, const xmpp_conn_event_t status,
|
void conn_handler(xmpp_conn_t *const conn,
|
||||||
const int error, xmpp_stream_error_t * const stream_error,
|
const xmpp_conn_event_t status,
|
||||||
|
const int error,
|
||||||
|
xmpp_stream_error_t *const stream_error,
|
||||||
void *const userdata)
|
void *const userdata)
|
||||||
{
|
{
|
||||||
xmpp_ctx_t *ctx = (xmpp_ctx_t *)userdata;
|
xmpp_ctx_t *ctx = (xmpp_ctx_t *)userdata;
|
||||||
xmpp_stanza_t *iq, *query;
|
xmpp_stanza_t *iq, *query;
|
||||||
|
|
||||||
|
(void)error;
|
||||||
|
(void)stream_error;
|
||||||
|
|
||||||
if (status == XMPP_CONN_CONNECT) {
|
if (status == XMPP_CONN_CONNECT) {
|
||||||
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");
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <strophe.h>
|
#include <strophe.h>
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main()
|
||||||
{
|
{
|
||||||
xmpp_ctx_t *ctx;
|
xmpp_ctx_t *ctx;
|
||||||
char *uuid;
|
char *uuid;
|
||||||
|
|||||||
283
examples/vcard.c
Normal file
283
examples/vcard.c
Normal file
@@ -0,0 +1,283 @@
|
|||||||
|
/* 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)
|
||||||
|
{
|
||||||
|
(void)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;
|
||||||
|
}
|
||||||
@@ -23,7 +23,7 @@ include $(BUILD_EXECUTABLE)
|
|||||||
|
|
||||||
include $(CLEAR_VARS)
|
include $(CLEAR_VARS)
|
||||||
LOCAL_MODULE := libstrophe
|
LOCAL_MODULE := libstrophe
|
||||||
LOCAL_CFLAGS :=
|
LOCAL_CFLAGS := -DHAVE_DECL_VA_COPY
|
||||||
LOCAL_C_INCLUDES := \
|
LOCAL_C_INCLUDES := \
|
||||||
$(LOCAL_PATH)/.. \
|
$(LOCAL_PATH)/.. \
|
||||||
$(LOCAL_PATH)/../src \
|
$(LOCAL_PATH)/../src \
|
||||||
@@ -45,6 +45,8 @@ LOCAL_SRC_FILES := \
|
|||||||
../src/sasl.c \
|
../src/sasl.c \
|
||||||
../src/scram.c \
|
../src/scram.c \
|
||||||
../src/sha1.c \
|
../src/sha1.c \
|
||||||
|
../src/sha256.c \
|
||||||
|
../src/sha512.c \
|
||||||
../src/snprintf.c \
|
../src/snprintf.c \
|
||||||
../src/sock.c \
|
../src/sock.c \
|
||||||
../src/stanza.c \
|
../src/stanza.c \
|
||||||
@@ -62,7 +64,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
|
||||||
|
|||||||
31
rpm/README
31
rpm/README
@@ -1,31 +0,0 @@
|
|||||||
1. Setup
|
|
||||||
|
|
||||||
yum install gcc make expat-devel libstrophe
|
|
||||||
|
|
||||||
Fedora:
|
|
||||||
|
|
||||||
yum install fedora-packager
|
|
||||||
cd ~
|
|
||||||
rpmdev-setuptree
|
|
||||||
|
|
||||||
CentOS:
|
|
||||||
|
|
||||||
mkdir -p ~/rpmbuild/{BUILD,RPMS,SOURCES,SPECS,SRPMS}
|
|
||||||
|
|
||||||
Then make a tarball of sources:
|
|
||||||
|
|
||||||
tar czf libstrophe_git.tar.gz libstrophe
|
|
||||||
|
|
||||||
2. Build
|
|
||||||
|
|
||||||
cp libstrophe.spec ~/rpmbuild/SPECS
|
|
||||||
cp libstrophe_git.tar.gz ~/rpmbuild/SOURCES
|
|
||||||
rpmbuild -bb ~/rpmbuild/SPECS/libstrophe.spec
|
|
||||||
|
|
||||||
3. Install
|
|
||||||
|
|
||||||
yum localinstall ~/rpmbuild/RPMS/<arch>/libstrophe-1.1<dist>.<arch>.rpm
|
|
||||||
|
|
||||||
Or, if localinstall is not recognised:
|
|
||||||
|
|
||||||
rpm -i ~/rpmbuild/RPMS/<arch>/libstrophe-1.1<dist>.<arch>.rpm
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
Name: libstrophe
|
|
||||||
Version: 1
|
|
||||||
Release: 1%{?dist}_git
|
|
||||||
Summary: xmpp library in C
|
|
||||||
|
|
||||||
Group: Application/System
|
|
||||||
License: MIT/GPLv3
|
|
||||||
URL: http://strophe.im/libstrophe/
|
|
||||||
Source0: libstrophe_git.tar.gz
|
|
||||||
|
|
||||||
BuildRequires: automake
|
|
||||||
BuildRequires: libtool
|
|
||||||
BuildRequires: openssl-devel
|
|
||||||
BuildRequires: expat-devel
|
|
||||||
Requires: expat
|
|
||||||
|
|
||||||
%description
|
|
||||||
XMPP library in C
|
|
||||||
|
|
||||||
%package devel
|
|
||||||
Summary: Headers and libraries for building apps that use libstrophe
|
|
||||||
Group: Development/Libraries
|
|
||||||
Requires: %{name} = %{version}-%{release}
|
|
||||||
|
|
||||||
%description devel
|
|
||||||
This package contains headers and libraries required to build applications that
|
|
||||||
use the strophe XMPP library.
|
|
||||||
|
|
||||||
%prep
|
|
||||||
%setup -n libstrophe
|
|
||||||
./bootstrap.sh
|
|
||||||
|
|
||||||
%build
|
|
||||||
%configure
|
|
||||||
make %{?_smp_mflags}
|
|
||||||
|
|
||||||
%install
|
|
||||||
make install DESTDIR=%{buildroot}
|
|
||||||
|
|
||||||
%post -p /sbin/ldconfig
|
|
||||||
|
|
||||||
%postun -p /sbin/ldconfig
|
|
||||||
|
|
||||||
%files
|
|
||||||
%defattr(-,root,root,-)
|
|
||||||
%{_libdir}/libstrophe.so*
|
|
||||||
%doc
|
|
||||||
|
|
||||||
%files devel
|
|
||||||
%defattr(-,root,root,-)
|
|
||||||
%{_libdir}/libstrophe.a
|
|
||||||
%{_libdir}/libstrophe.la
|
|
||||||
%{_libdir}/pkgconfig/libstrophe.pc
|
|
||||||
%{_includedir}/strophe.h
|
|
||||||
%doc
|
|
||||||
|
|
||||||
%changelog
|
|
||||||
569
src/auth.c
569
src/auth.c
File diff suppressed because it is too large
Load Diff
83
src/common.h
83
src/common.h
@@ -19,7 +19,6 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
|
||||||
#include "strophe.h"
|
#include "strophe.h"
|
||||||
#include "ostypes.h"
|
#include "ostypes.h"
|
||||||
#include "sock.h"
|
#include "sock.h"
|
||||||
@@ -30,6 +29,38 @@
|
|||||||
#include "rand.h"
|
#include "rand.h"
|
||||||
#include "snprintf.h"
|
#include "snprintf.h"
|
||||||
|
|
||||||
|
/** handlers **/
|
||||||
|
|
||||||
|
typedef struct _xmpp_handlist_t xmpp_handlist_t;
|
||||||
|
struct _xmpp_handlist_t {
|
||||||
|
/* common members */
|
||||||
|
int user_handler;
|
||||||
|
int (*handler)();
|
||||||
|
void *userdata;
|
||||||
|
int enabled; /* handlers are added disabled and enabled after the
|
||||||
|
* handler chain is processed to prevent stanzas from
|
||||||
|
* getting processed by newly added handlers */
|
||||||
|
xmpp_handlist_t *next;
|
||||||
|
|
||||||
|
union {
|
||||||
|
/* timed handlers */
|
||||||
|
struct {
|
||||||
|
unsigned long period;
|
||||||
|
uint64_t last_stamp;
|
||||||
|
};
|
||||||
|
/* id handlers */
|
||||||
|
struct {
|
||||||
|
char *id;
|
||||||
|
};
|
||||||
|
/* normal handlers */
|
||||||
|
struct {
|
||||||
|
char *ns;
|
||||||
|
char *name;
|
||||||
|
char *type;
|
||||||
|
};
|
||||||
|
} u;
|
||||||
|
};
|
||||||
|
|
||||||
/** run-time context **/
|
/** run-time context **/
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@@ -50,13 +81,14 @@ 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;
|
||||||
};
|
xmpp_handlist_t *timed_handlers;
|
||||||
|
|
||||||
|
unsigned long timeout;
|
||||||
|
};
|
||||||
|
|
||||||
/* convenience functions for accessing the context */
|
/* convenience functions for accessing the context */
|
||||||
void *xmpp_alloc(const xmpp_ctx_t *const ctx, const size_t size);
|
void *xmpp_alloc(const xmpp_ctx_t *const ctx, const size_t size);
|
||||||
void *xmpp_realloc(const xmpp_ctx_t * const ctx, void *p,
|
void *xmpp_realloc(const xmpp_ctx_t *const ctx, void *p, const size_t size);
|
||||||
const size_t size);
|
|
||||||
char *xmpp_strdup(const xmpp_ctx_t *const ctx, const char *const s);
|
char *xmpp_strdup(const xmpp_ctx_t *const ctx, const char *const s);
|
||||||
|
|
||||||
void xmpp_log(const xmpp_ctx_t *const ctx,
|
void xmpp_log(const xmpp_ctx_t *const ctx,
|
||||||
@@ -101,35 +133,7 @@ struct _xmpp_send_queue_t {
|
|||||||
xmpp_send_queue_t *next;
|
xmpp_send_queue_t *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct _xmpp_handlist_t xmpp_handlist_t;
|
#define UNUSED(x) ((void)(x))
|
||||||
struct _xmpp_handlist_t {
|
|
||||||
/* common members */
|
|
||||||
int user_handler;
|
|
||||||
void *handler;
|
|
||||||
void *userdata;
|
|
||||||
int enabled; /* handlers are added disabled and enabled after the
|
|
||||||
* handler chain is processed to prevent stanzas from
|
|
||||||
* getting processed by newly added handlers */
|
|
||||||
xmpp_handlist_t *next;
|
|
||||||
|
|
||||||
union {
|
|
||||||
/* timed handlers */
|
|
||||||
struct {
|
|
||||||
unsigned long period;
|
|
||||||
uint64_t last_stamp;
|
|
||||||
};
|
|
||||||
/* id handlers */
|
|
||||||
struct {
|
|
||||||
char *id;
|
|
||||||
};
|
|
||||||
/* normal handlers */
|
|
||||||
struct {
|
|
||||||
char *ns;
|
|
||||||
char *name;
|
|
||||||
char *type;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
#define MAX_DOMAIN_LEN 256
|
#define MAX_DOMAIN_LEN 256
|
||||||
|
|
||||||
@@ -137,6 +141,11 @@ struct _xmpp_handlist_t {
|
|||||||
#define SASL_MASK_DIGESTMD5 (1 << 1)
|
#define SASL_MASK_DIGESTMD5 (1 << 1)
|
||||||
#define SASL_MASK_ANONYMOUS (1 << 2)
|
#define SASL_MASK_ANONYMOUS (1 << 2)
|
||||||
#define SASL_MASK_SCRAMSHA1 (1 << 3)
|
#define SASL_MASK_SCRAMSHA1 (1 << 3)
|
||||||
|
#define SASL_MASK_SCRAMSHA256 (1 << 4)
|
||||||
|
#define SASL_MASK_SCRAMSHA512 (1 << 5)
|
||||||
|
|
||||||
|
#define SASL_MASK_SCRAM \
|
||||||
|
(SASL_MASK_SCRAMSHA1 | SASL_MASK_SCRAMSHA256 | SASL_MASK_SCRAMSHA512)
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
XMPP_PORT_CLIENT = 5222,
|
XMPP_PORT_CLIENT = 5222,
|
||||||
@@ -166,9 +175,11 @@ 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 */
|
||||||
@@ -222,7 +233,6 @@ int conn_tls_start(xmpp_conn_t * const conn);
|
|||||||
void conn_prepare_reset(xmpp_conn_t *const conn, xmpp_open_handler handler);
|
void conn_prepare_reset(xmpp_conn_t *const conn, xmpp_open_handler handler);
|
||||||
void conn_parser_reset(xmpp_conn_t *const conn);
|
void conn_parser_reset(xmpp_conn_t *const conn);
|
||||||
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
XMPP_STANZA_UNKNOWN,
|
XMPP_STANZA_UNKNOWN,
|
||||||
XMPP_STANZA_TEXT,
|
XMPP_STANZA_TEXT,
|
||||||
@@ -246,8 +256,7 @@ struct _xmpp_stanza_t {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* handler management */
|
/* handler management */
|
||||||
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);
|
|
||||||
uint64_t handler_fire_timed(xmpp_ctx_t *const ctx);
|
uint64_t handler_fire_timed(xmpp_ctx_t *const ctx);
|
||||||
void handler_reset_timed(xmpp_conn_t *conn, int user_only);
|
void handler_reset_timed(xmpp_conn_t *conn, int user_only);
|
||||||
void handler_add_timed(xmpp_conn_t *const conn,
|
void handler_add_timed(xmpp_conn_t *const conn,
|
||||||
@@ -264,8 +273,10 @@ 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_with_error(xmpp_conn_t *const conn, int error);
|
||||||
void disconnect_mem_error(xmpp_conn_t *const conn);
|
void disconnect_mem_error(xmpp_conn_t *const conn);
|
||||||
|
|
||||||
/* auth functions */
|
/* auth functions */
|
||||||
|
|||||||
340
src/conn.c
340
src/conn.c
@@ -48,20 +48,21 @@
|
|||||||
#define CONNECT_TIMEOUT 5000 /* 5 seconds */
|
#define CONNECT_TIMEOUT 5000 /* 5 seconds */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int _disconnect_cleanup(xmpp_conn_t * const conn,
|
static int _disconnect_cleanup(xmpp_conn_t *const conn, void *const userdata);
|
||||||
void * const userdata);
|
|
||||||
static char *_conn_build_stream_tag(xmpp_conn_t *const conn,
|
static char *_conn_build_stream_tag(xmpp_conn_t *const conn,
|
||||||
char **attributes, size_t attributes_len);
|
char **attributes,
|
||||||
static void _conn_attributes_new(xmpp_conn_t *conn, char **attrs,
|
|
||||||
char ***attributes, size_t *attributes_len);
|
|
||||||
static void _conn_attributes_destroy(xmpp_conn_t *conn, char **attributes,
|
|
||||||
size_t attributes_len);
|
size_t attributes_len);
|
||||||
static void _handle_stream_start(char *name, char **attrs,
|
static void _conn_attributes_new(xmpp_conn_t *conn,
|
||||||
void * const userdata);
|
char **attrs,
|
||||||
static void _handle_stream_end(char *name,
|
char ***attributes,
|
||||||
void * const userdata);
|
size_t *attributes_len);
|
||||||
static void _handle_stream_stanza(xmpp_stanza_t *stanza,
|
static void _conn_attributes_destroy(xmpp_conn_t *conn,
|
||||||
void * const userdata);
|
char **attributes,
|
||||||
|
size_t attributes_len);
|
||||||
|
static void
|
||||||
|
_handle_stream_start(char *name, char **attrs, void *const userdata);
|
||||||
|
static void _handle_stream_end(char *name, void *const userdata);
|
||||||
|
static void _handle_stream_stanza(xmpp_stanza_t *stanza, void *const userdata);
|
||||||
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 +74,17 @@ 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
|
||||||
@@ -86,7 +98,8 @@ xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t * const ctx)
|
|||||||
xmpp_conn_t *conn = NULL;
|
xmpp_conn_t *conn = NULL;
|
||||||
xmpp_connlist_t *tail, *item;
|
xmpp_connlist_t *tail, *item;
|
||||||
|
|
||||||
if (ctx == NULL) return NULL;
|
if (ctx == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
conn = xmpp_alloc(ctx, sizeof(xmpp_conn_t));
|
conn = xmpp_alloc(ctx, sizeof(xmpp_conn_t));
|
||||||
if (conn != NULL) {
|
if (conn != NULL) {
|
||||||
@@ -128,18 +141,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->parser = parser_new(conn->ctx,
|
conn->parser =
|
||||||
_handle_stream_start,
|
parser_new(conn->ctx, _handle_stream_start, _handle_stream_end,
|
||||||
_handle_stream_end,
|
_handle_stream_stanza, conn);
|
||||||
_handle_stream_stanza,
|
|
||||||
conn);
|
|
||||||
conn->reset_parser = 0;
|
conn->reset_parser = 0;
|
||||||
|
|
||||||
conn->authenticated = 0;
|
conn->authenticated = 0;
|
||||||
@@ -155,7 +168,8 @@ xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t * const ctx)
|
|||||||
|
|
||||||
/* add connection to ctx->connlist */
|
/* add connection to ctx->connlist */
|
||||||
tail = conn->ctx->connlist;
|
tail = conn->ctx->connlist;
|
||||||
while (tail && tail->next) tail = tail->next;
|
while (tail && tail->next)
|
||||||
|
tail = tail->next;
|
||||||
|
|
||||||
item = xmpp_alloc(conn->ctx, sizeof(xmpp_connlist_t));
|
item = xmpp_alloc(conn->ctx, sizeof(xmpp_connlist_t));
|
||||||
if (!item) {
|
if (!item) {
|
||||||
@@ -168,8 +182,10 @@ xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t * const ctx)
|
|||||||
item->conn = conn;
|
item->conn = conn;
|
||||||
item->next = NULL;
|
item->next = NULL;
|
||||||
|
|
||||||
if (tail) tail->next = item;
|
if (tail)
|
||||||
else conn->ctx->connlist = item;
|
tail->next = item;
|
||||||
|
else
|
||||||
|
conn->ctx->connlist = item;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -243,6 +259,11 @@ 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 +285,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 +309,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,18 +321,23 @@ 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)
|
||||||
if (thli->name) xmpp_free(ctx, thli->name);
|
xmpp_free(ctx, thli->u.ns);
|
||||||
if (thli->type) xmpp_free(ctx, thli->type);
|
if (thli->u.name)
|
||||||
|
xmpp_free(ctx, thli->u.name);
|
||||||
|
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)
|
||||||
if (conn->pass) xmpp_free(ctx, conn->pass);
|
xmpp_free(ctx, conn->jid);
|
||||||
if (conn->lang) xmpp_free(ctx, conn->lang);
|
if (conn->pass)
|
||||||
|
xmpp_free(ctx, conn->pass);
|
||||||
|
if (conn->lang)
|
||||||
|
xmpp_free(ctx, conn->lang);
|
||||||
xmpp_free(ctx, conn);
|
xmpp_free(ctx, conn);
|
||||||
released = 1;
|
released = 1;
|
||||||
}
|
}
|
||||||
@@ -361,7 +389,8 @@ const char *xmpp_conn_get_bound_jid(const xmpp_conn_t * const conn)
|
|||||||
*/
|
*/
|
||||||
void xmpp_conn_set_jid(xmpp_conn_t *const conn, const char *const jid)
|
void xmpp_conn_set_jid(xmpp_conn_t *const conn, const char *const jid)
|
||||||
{
|
{
|
||||||
if (conn->jid) xmpp_free(conn->ctx, conn->jid);
|
if (conn->jid)
|
||||||
|
xmpp_free(conn->ctx, conn->jid);
|
||||||
conn->jid = xmpp_strdup(conn->ctx, jid);
|
conn->jid = xmpp_strdup(conn->ctx, jid);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -389,7 +418,8 @@ const char *xmpp_conn_get_pass(const xmpp_conn_t * const conn)
|
|||||||
*/
|
*/
|
||||||
void xmpp_conn_set_pass(xmpp_conn_t *const conn, const char *const pass)
|
void xmpp_conn_set_pass(xmpp_conn_t *const conn, const char *const pass)
|
||||||
{
|
{
|
||||||
if (conn->pass) xmpp_free(conn->ctx, conn->pass);
|
if (conn->pass)
|
||||||
|
xmpp_free(conn->ctx, conn->pass);
|
||||||
conn->pass = xmpp_strdup(conn->ctx, pass);
|
conn->pass = xmpp_strdup(conn->ctx, pass);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -441,7 +471,8 @@ int xmpp_connect_client(xmpp_conn_t * const conn,
|
|||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
domain = xmpp_jid_domain(conn->ctx, conn->jid);
|
domain = xmpp_jid_domain(conn->ctx, conn->jid);
|
||||||
if (!domain) return XMPP_EMEM;
|
if (!domain)
|
||||||
|
return XMPP_EMEM;
|
||||||
|
|
||||||
if (altdomain != NULL) {
|
if (altdomain != NULL) {
|
||||||
xmpp_debug(conn->ctx, "xmpp", "Connecting via altdomain.");
|
xmpp_debug(conn->ctx, "xmpp", "Connecting via altdomain.");
|
||||||
@@ -457,7 +488,8 @@ int xmpp_connect_client(xmpp_conn_t * const conn,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (XMPP_DOMAIN_NOT_FOUND == found) {
|
if (XMPP_DOMAIN_NOT_FOUND == found) {
|
||||||
xmpp_debug(conn->ctx, "xmpp", "SRV lookup failed, "
|
xmpp_debug(conn->ctx, "xmpp",
|
||||||
|
"SRV lookup failed, "
|
||||||
"connecting via domain.");
|
"connecting via domain.");
|
||||||
host = domain;
|
host = domain;
|
||||||
port = altport ? altport : _conn_default_port(conn, XMPP_CLIENT);
|
port = altport ? altport : _conn_default_port(conn, XMPP_CLIENT);
|
||||||
@@ -471,8 +503,8 @@ int xmpp_connect_client(xmpp_conn_t * const conn,
|
|||||||
port = rr->port;
|
port = rr->port;
|
||||||
rr = rr->next;
|
rr = rr->next;
|
||||||
}
|
}
|
||||||
rc = _conn_connect(conn, domain, host, port, XMPP_CLIENT,
|
rc = _conn_connect(conn, domain, host, port, XMPP_CLIENT, callback,
|
||||||
callback, userdata);
|
userdata);
|
||||||
} while (rc != 0 && rr != NULL);
|
} while (rc != 0 && rr != NULL);
|
||||||
|
|
||||||
xmpp_free(conn->ctx, domain);
|
xmpp_free(conn->ctx, domain);
|
||||||
@@ -504,17 +536,21 @@ int xmpp_connect_client(xmpp_conn_t * const conn,
|
|||||||
*
|
*
|
||||||
* @ingroup Connections
|
* @ingroup Connections
|
||||||
*/
|
*/
|
||||||
int xmpp_connect_component(xmpp_conn_t * const conn, const char * const server,
|
int xmpp_connect_component(xmpp_conn_t *const conn,
|
||||||
unsigned short port, xmpp_conn_handler callback,
|
const char *const server,
|
||||||
|
unsigned short port,
|
||||||
|
xmpp_conn_handler callback,
|
||||||
void *const userdata)
|
void *const userdata)
|
||||||
{
|
{
|
||||||
/* The server domain, jid and password MUST be specified. */
|
/* The server domain, jid and password MUST be specified. */
|
||||||
if (!(server && conn->jid && conn->pass)) return XMPP_EINVOP;
|
if (!(server && conn->jid && conn->pass))
|
||||||
|
return XMPP_EINVOP;
|
||||||
|
|
||||||
/* XEP-0114 does not support TLS */
|
/* XEP-0114 does not support TLS */
|
||||||
xmpp_conn_disable_tls(conn);
|
xmpp_conn_disable_tls(conn);
|
||||||
if (!conn->tls_disabled) {
|
if (!conn->tls_disabled) {
|
||||||
xmpp_error(conn->ctx, "conn", "Failed to disable TLS. "
|
xmpp_error(conn->ctx, "conn",
|
||||||
|
"Failed to disable TLS. "
|
||||||
"XEP-0114 does not support TLS");
|
"XEP-0114 does not support TLS");
|
||||||
return XMPP_EINT;
|
return XMPP_EINT;
|
||||||
}
|
}
|
||||||
@@ -573,7 +609,8 @@ void conn_established(xmpp_conn_t * const conn)
|
|||||||
/* we skip authentication for a "raw" connection, but the event loop
|
/* we skip authentication for a "raw" connection, but the event loop
|
||||||
ignores user's handlers when conn->authenticated is not set. */
|
ignores user's handlers when conn->authenticated is not set. */
|
||||||
conn->authenticated = 1;
|
conn->authenticated = 1;
|
||||||
conn->conn_handler(conn, XMPP_CONN_RAW_CONNECT, 0, NULL, conn->userdata);
|
conn->conn_handler(conn, XMPP_CONN_RAW_CONNECT, 0, NULL,
|
||||||
|
conn->userdata);
|
||||||
} else {
|
} else {
|
||||||
/* send stream init */
|
/* send stream init */
|
||||||
conn_open_stream(conn);
|
conn_open_stream(conn);
|
||||||
@@ -618,7 +655,8 @@ int xmpp_conn_open_stream_default(xmpp_conn_t * const conn)
|
|||||||
*
|
*
|
||||||
* @ingroup Connections
|
* @ingroup Connections
|
||||||
*/
|
*/
|
||||||
int xmpp_conn_open_stream(xmpp_conn_t * const conn, char **attributes,
|
int xmpp_conn_open_stream(xmpp_conn_t *const conn,
|
||||||
|
char **attributes,
|
||||||
size_t attributes_len)
|
size_t attributes_len)
|
||||||
{
|
{
|
||||||
char *tag;
|
char *tag;
|
||||||
@@ -702,7 +740,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
|
||||||
*
|
*
|
||||||
@@ -718,8 +756,7 @@ void xmpp_disconnect(xmpp_conn_t * const conn)
|
|||||||
xmpp_send_raw_string(conn, "</stream:stream>");
|
xmpp_send_raw_string(conn, "</stream:stream>");
|
||||||
|
|
||||||
/* setup timed handler in case disconnect takes too long */
|
/* setup timed handler in case disconnect takes too long */
|
||||||
handler_add_timed(conn, _disconnect_cleanup,
|
handler_add_timed(conn, _disconnect_cleanup, DISCONNECT_TIMEOUT, NULL);
|
||||||
DISCONNECT_TIMEOUT, NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Send a raw string to the XMPP server.
|
/** Send a raw string to the XMPP server.
|
||||||
@@ -735,8 +772,7 @@ void xmpp_disconnect(xmpp_conn_t * const conn)
|
|||||||
*
|
*
|
||||||
* @ingroup Connections
|
* @ingroup Connections
|
||||||
*/
|
*/
|
||||||
void xmpp_send_raw_string(xmpp_conn_t * const conn,
|
void xmpp_send_raw_string(xmpp_conn_t *const conn, const char *const fmt, ...)
|
||||||
const char * const fmt, ...)
|
|
||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
size_t len;
|
size_t len;
|
||||||
@@ -744,16 +780,17 @@ 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 */
|
||||||
bigbuf = xmpp_alloc(conn->ctx, len);
|
bigbuf = xmpp_alloc(conn->ctx, len);
|
||||||
if (!bigbuf) {
|
if (!bigbuf) {
|
||||||
xmpp_debug(conn->ctx, "xmpp", "Could not allocate memory for send_raw_string");
|
xmpp_debug(conn->ctx, "xmpp",
|
||||||
|
"Could not allocate memory for send_raw_string");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
@@ -768,7 +805,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -786,15 +822,18 @@ void xmpp_send_raw_string(xmpp_conn_t * const conn,
|
|||||||
* @ingroup Connections
|
* @ingroup Connections
|
||||||
*/
|
*/
|
||||||
void xmpp_send_raw(xmpp_conn_t *const conn,
|
void xmpp_send_raw(xmpp_conn_t *const conn,
|
||||||
const char * const data, const size_t len)
|
const char *const data,
|
||||||
|
const size_t len)
|
||||||
{
|
{
|
||||||
xmpp_send_queue_t *item;
|
xmpp_send_queue_t *item;
|
||||||
|
|
||||||
if (conn->state != XMPP_STATE_CONNECTED) return;
|
if (conn->state != XMPP_STATE_CONNECTED)
|
||||||
|
return;
|
||||||
|
|
||||||
/* create send queue item for queue */
|
/* create send queue item for queue */
|
||||||
item = xmpp_alloc(conn->ctx, sizeof(xmpp_send_queue_t));
|
item = xmpp_alloc(conn->ctx, sizeof(xmpp_send_queue_t));
|
||||||
if (!item) return;
|
if (!item)
|
||||||
|
return;
|
||||||
|
|
||||||
item->data = xmpp_alloc(conn->ctx, len);
|
item->data = xmpp_alloc(conn->ctx, len);
|
||||||
if (!item->data) {
|
if (!item->data) {
|
||||||
@@ -828,15 +867,13 @@ void xmpp_send_raw(xmpp_conn_t * const conn,
|
|||||||
*
|
*
|
||||||
* @ingroup Connections
|
* @ingroup Connections
|
||||||
*/
|
*/
|
||||||
void xmpp_send(xmpp_conn_t * const conn,
|
void xmpp_send(xmpp_conn_t *const conn, xmpp_stanza_t *const stanza)
|
||||||
xmpp_stanza_t * const stanza)
|
|
||||||
{
|
{
|
||||||
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);
|
||||||
@@ -853,16 +890,15 @@ void xmpp_send(xmpp_conn_t * const conn,
|
|||||||
void conn_open_stream(xmpp_conn_t *const conn)
|
void conn_open_stream(xmpp_conn_t *const conn)
|
||||||
{
|
{
|
||||||
xmpp_send_raw_string(conn,
|
xmpp_send_raw_string(conn,
|
||||||
"<?xml version=\"1.0\"?>" \
|
"<?xml version=\"1.0\"?>"
|
||||||
"<stream:stream to=\"%s\" " \
|
"<stream:stream to=\"%s\" "
|
||||||
"xml:lang=\"%s\" " \
|
"xml:lang=\"%s\" "
|
||||||
"version=\"1.0\" " \
|
"version=\"1.0\" "
|
||||||
"xmlns=\"%s\" " \
|
"xmlns=\"%s\" "
|
||||||
"xmlns:stream=\"%s\">",
|
"xmlns:stream=\"%s\">",
|
||||||
conn->domain,
|
conn->domain, conn->lang,
|
||||||
conn->lang,
|
conn->type == XMPP_CLIENT ? XMPP_NS_CLIENT
|
||||||
conn->type == XMPP_CLIENT ? XMPP_NS_CLIENT :
|
: XMPP_NS_COMPONENT,
|
||||||
XMPP_NS_COMPONENT,
|
|
||||||
XMPP_NS_STREAMS);
|
XMPP_NS_STREAMS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -874,7 +910,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -882,16 +918,18 @@ int conn_tls_start(xmpp_conn_t * const conn)
|
|||||||
if (tls_start(conn->tls)) {
|
if (tls_start(conn->tls)) {
|
||||||
conn->secured = 1;
|
conn->secured = 1;
|
||||||
} else {
|
} else {
|
||||||
rc = XMPP_EINT;
|
/* TODO: distinguish invalid certificates and other errors */
|
||||||
conn->error = tls_error(conn->tls);
|
rc = XMPP_ECERT;
|
||||||
tls_free(conn->tls);
|
tls_free(conn->tls);
|
||||||
conn->tls = NULL;
|
conn->tls = NULL;
|
||||||
conn->tls_failed = 1;
|
conn->tls_failed = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
xmpp_debug(conn->ctx, "conn", "Couldn't start TLS! "
|
xmpp_debug(conn->ctx, "conn",
|
||||||
"error %d tls_error %d", rc, conn->error);
|
"Couldn't start TLS! error %d tls_error %d", rc,
|
||||||
|
conn->tls == NULL ? 0 : tls_error(conn->tls));
|
||||||
|
conn->error = rc;
|
||||||
}
|
}
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@@ -910,7 +948,10 @@ 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 +968,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
|
||||||
@@ -938,12 +981,14 @@ long xmpp_conn_get_flags(const xmpp_conn_t * const conn)
|
|||||||
int xmpp_conn_set_flags(xmpp_conn_t *const conn, long flags)
|
int xmpp_conn_set_flags(xmpp_conn_t *const conn, long flags)
|
||||||
{
|
{
|
||||||
if (conn->state != XMPP_STATE_DISCONNECTED) {
|
if (conn->state != XMPP_STATE_DISCONNECTED) {
|
||||||
xmpp_error(conn->ctx, "conn", "Flags can be set only "
|
xmpp_error(conn->ctx, "conn",
|
||||||
|
"Flags can be set only "
|
||||||
"for disconnected connection");
|
"for disconnected connection");
|
||||||
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 +996,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;
|
||||||
}
|
}
|
||||||
@@ -982,23 +1029,55 @@ 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)
|
||||||
{
|
{
|
||||||
return conn->secured && !conn->tls_failed && conn->tls != NULL ? 1 : 0;
|
return conn->secured && !conn->tls_failed && conn->tls != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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)
|
|
||||||
{
|
{
|
||||||
xmpp_debug(conn->ctx, "xmpp",
|
UNUSED(userdata);
|
||||||
"disconnection forced by cleanup timeout");
|
|
||||||
|
|
||||||
|
xmpp_debug(conn->ctx, "xmpp", "disconnection forced by cleanup timeout");
|
||||||
|
|
||||||
|
conn->error = conn->error ?: XMPP_ETIMEDOUT;
|
||||||
conn_disconnect(conn);
|
conn_disconnect(conn);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *_conn_build_stream_tag(xmpp_conn_t *const conn,
|
static char *_conn_build_stream_tag(xmpp_conn_t *const conn,
|
||||||
char **attributes, size_t attributes_len)
|
char **attributes,
|
||||||
|
size_t attributes_len)
|
||||||
{
|
{
|
||||||
char *tag;
|
char *tag;
|
||||||
size_t len;
|
size_t len;
|
||||||
@@ -1014,7 +1093,8 @@ static char *_conn_build_stream_tag(xmpp_conn_t * const conn,
|
|||||||
for (i = 0; i < attributes_len; ++i)
|
for (i = 0; i < attributes_len; ++i)
|
||||||
len += strlen(attributes[i]) + 2;
|
len += strlen(attributes[i]) + 2;
|
||||||
tag = xmpp_alloc(conn->ctx, len + 1);
|
tag = xmpp_alloc(conn->ctx, len + 1);
|
||||||
if (!tag) return NULL;
|
if (!tag)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
strcpy(tag, tag_head);
|
strcpy(tag, tag_head);
|
||||||
for (i = 0; i < attributes_len; ++i) {
|
for (i = 0; i < attributes_len; ++i) {
|
||||||
@@ -1030,7 +1110,8 @@ static char *_conn_build_stream_tag(xmpp_conn_t * const conn,
|
|||||||
strcat(tag, tag_tail);
|
strcat(tag, tag_tail);
|
||||||
|
|
||||||
if (strlen(tag) != len) {
|
if (strlen(tag) != len) {
|
||||||
xmpp_error(conn->ctx, "xmpp", "Internal error in "
|
xmpp_error(conn->ctx, "xmpp",
|
||||||
|
"Internal error in "
|
||||||
"_conn_build_stream_tag().");
|
"_conn_build_stream_tag().");
|
||||||
xmpp_free(conn->ctx, tag);
|
xmpp_free(conn->ctx, tag);
|
||||||
tag = NULL;
|
tag = NULL;
|
||||||
@@ -1039,20 +1120,24 @@ static char *_conn_build_stream_tag(xmpp_conn_t * const conn,
|
|||||||
return tag;
|
return tag;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _conn_attributes_new(xmpp_conn_t *conn, char **attrs,
|
static void _conn_attributes_new(xmpp_conn_t *conn,
|
||||||
char ***attributes, size_t *attributes_len)
|
char **attrs,
|
||||||
|
char ***attributes,
|
||||||
|
size_t *attributes_len)
|
||||||
{
|
{
|
||||||
char **array = NULL;
|
char **array = NULL;
|
||||||
size_t nr = 0;
|
size_t nr = 0;
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
if (attrs) {
|
if (attrs) {
|
||||||
for (; attrs[nr]; ++nr);
|
for (; attrs[nr]; ++nr)
|
||||||
|
;
|
||||||
array = xmpp_alloc(conn->ctx, sizeof(*array) * nr);
|
array = xmpp_alloc(conn->ctx, sizeof(*array) * nr);
|
||||||
for (i = 0; array && i < nr; ++i) {
|
for (i = 0; array && i < nr; ++i) {
|
||||||
array[i] = (i & 1) == 0 ? parser_attr_name(conn->ctx, attrs[i])
|
array[i] = (i & 1) == 0 ? parser_attr_name(conn->ctx, attrs[i])
|
||||||
: xmpp_strdup(conn->ctx, attrs[i]);
|
: xmpp_strdup(conn->ctx, attrs[i]);
|
||||||
if (array[i] == NULL) break;
|
if (array[i] == NULL)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (!array || i < nr) {
|
if (!array || i < nr) {
|
||||||
xmpp_error(conn->ctx, "xmpp", "Memory allocation error.");
|
xmpp_error(conn->ctx, "xmpp", "Memory allocation error.");
|
||||||
@@ -1065,7 +1150,8 @@ static void _conn_attributes_new(xmpp_conn_t *conn, char **attrs,
|
|||||||
*attributes_len = nr;
|
*attributes_len = nr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _conn_attributes_destroy(xmpp_conn_t *conn, char **attributes,
|
static void _conn_attributes_destroy(xmpp_conn_t *conn,
|
||||||
|
char **attributes,
|
||||||
size_t attributes_len)
|
size_t attributes_len)
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
@@ -1096,7 +1182,8 @@ static char *_get_stream_attribute(char **attrs, char *name)
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (!attrs) return NULL;
|
if (!attrs)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
for (i = 0; attrs[i]; i += 2)
|
for (i = 0; attrs[i]; i += 2)
|
||||||
if (strcmp(name, attrs[i]) == 0)
|
if (strcmp(name, attrs[i]) == 0)
|
||||||
@@ -1105,14 +1192,14 @@ static char *_get_stream_attribute(char **attrs, char *name)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _handle_stream_start(char *name, char **attrs,
|
static void _handle_stream_start(char *name, char **attrs, void *const userdata)
|
||||||
void * const userdata)
|
|
||||||
{
|
{
|
||||||
xmpp_conn_t *conn = (xmpp_conn_t *)userdata;
|
xmpp_conn_t *conn = (xmpp_conn_t *)userdata;
|
||||||
char *id;
|
char *id;
|
||||||
int failed = 0;
|
int ret = 0;
|
||||||
|
|
||||||
if (conn->stream_id) xmpp_free(conn->ctx, conn->stream_id);
|
if (conn->stream_id)
|
||||||
|
xmpp_free(conn->ctx, conn->stream_id);
|
||||||
conn->stream_id = NULL;
|
conn->stream_id = NULL;
|
||||||
|
|
||||||
if (strcmp(name, "stream") == 0) {
|
if (strcmp(name, "stream") == 0) {
|
||||||
@@ -1123,34 +1210,37 @@ static void _handle_stream_start(char *name, char **attrs,
|
|||||||
|
|
||||||
if (id && !conn->stream_id) {
|
if (id && !conn->stream_id) {
|
||||||
xmpp_error(conn->ctx, "conn", "Memory allocation failed.");
|
xmpp_error(conn->ctx, "conn", "Memory allocation failed.");
|
||||||
failed = 1;
|
ret = XMPP_EMEM;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
xmpp_error(conn->ctx, "conn", "Server did not open valid stream."
|
xmpp_error(conn->ctx, "conn",
|
||||||
" name = %s.", name);
|
"Server did not open valid stream."
|
||||||
failed = 1;
|
" name = %s.",
|
||||||
|
name);
|
||||||
|
ret = XMPP_EINT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!failed) {
|
if (ret == 0) {
|
||||||
/* call stream open handler */
|
/* call stream open handler */
|
||||||
conn->open_handler(conn);
|
conn->open_handler(conn);
|
||||||
} else {
|
} else {
|
||||||
|
conn->error = ret;
|
||||||
conn_disconnect(conn);
|
conn_disconnect(conn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _handle_stream_end(char *name,
|
static void _handle_stream_end(char *name, void *const userdata)
|
||||||
void * const userdata)
|
|
||||||
{
|
{
|
||||||
xmpp_conn_t *conn = (xmpp_conn_t *)userdata;
|
xmpp_conn_t *conn = (xmpp_conn_t *)userdata;
|
||||||
|
|
||||||
|
UNUSED(name);
|
||||||
|
|
||||||
/* stream is over */
|
/* stream is over */
|
||||||
xmpp_debug(conn->ctx, "xmpp", "RECV: </stream:stream>");
|
xmpp_debug(conn->ctx, "xmpp", "RECV: </stream:stream>");
|
||||||
conn_disconnect_clean(conn);
|
conn_disconnect_clean(conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _handle_stream_stanza(xmpp_stanza_t *stanza,
|
static void _handle_stream_stanza(xmpp_stanza_t *stanza, void *const userdata)
|
||||||
void * const userdata)
|
|
||||||
{
|
{
|
||||||
xmpp_conn_t *conn = (xmpp_conn_t *)userdata;
|
xmpp_conn_t *conn = (xmpp_conn_t *)userdata;
|
||||||
char *buf;
|
char *buf;
|
||||||
@@ -1169,8 +1259,8 @@ static unsigned short _conn_default_port(xmpp_conn_t * const conn,
|
|||||||
{
|
{
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case XMPP_CLIENT:
|
case XMPP_CLIENT:
|
||||||
return conn->tls_legacy_ssl ? XMPP_PORT_CLIENT_LEGACY_SSL :
|
return conn->tls_legacy_ssl ? XMPP_PORT_CLIENT_LEGACY_SSL
|
||||||
XMPP_PORT_CLIENT;
|
: XMPP_PORT_CLIENT;
|
||||||
case XMPP_COMPONENT:
|
case XMPP_COMPONENT:
|
||||||
return XMPP_PORT_COMPONENT;
|
return XMPP_PORT_COMPONENT;
|
||||||
default:
|
default:
|
||||||
@@ -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);
|
||||||
@@ -1205,9 +1298,12 @@ static void _conn_reset(xmpp_conn_t * const conn)
|
|||||||
conn->stream_error = NULL;
|
conn->stream_error = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (conn->domain) xmpp_free(ctx, conn->domain);
|
if (conn->domain)
|
||||||
if (conn->bound_jid) xmpp_free(ctx, conn->bound_jid);
|
xmpp_free(ctx, conn->domain);
|
||||||
if (conn->stream_id) xmpp_free(ctx, conn->stream_id);
|
if (conn->bound_jid)
|
||||||
|
xmpp_free(ctx, conn->bound_jid);
|
||||||
|
if (conn->stream_id)
|
||||||
|
xmpp_free(ctx, conn->stream_id);
|
||||||
conn->domain = NULL;
|
conn->domain = NULL;
|
||||||
conn->bound_jid = NULL;
|
conn->bound_jid = NULL;
|
||||||
conn->stream_id = NULL;
|
conn->stream_id = NULL;
|
||||||
@@ -1215,6 +1311,12 @@ 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->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,
|
||||||
@@ -1227,20 +1329,25 @@ static int _conn_connect(xmpp_conn_t * const conn,
|
|||||||
{
|
{
|
||||||
xmpp_open_handler open_handler;
|
xmpp_open_handler open_handler;
|
||||||
|
|
||||||
if (conn->state != XMPP_STATE_DISCONNECTED) return XMPP_EINVOP;
|
if (conn->state != XMPP_STATE_DISCONNECTED)
|
||||||
if (type != XMPP_CLIENT && type != XMPP_COMPONENT) return XMPP_EINVOP;
|
return XMPP_EINVOP;
|
||||||
if (host == NULL || port == 0) return XMPP_EINT;
|
if (type != XMPP_CLIENT && type != XMPP_COMPONENT)
|
||||||
|
return XMPP_EINVOP;
|
||||||
|
if (host == NULL || port == 0)
|
||||||
|
return XMPP_EINT;
|
||||||
|
|
||||||
_conn_reset(conn);
|
_conn_reset(conn);
|
||||||
|
|
||||||
conn->type = type;
|
conn->type = type;
|
||||||
conn->domain = xmpp_strdup(conn->ctx, domain);
|
conn->domain = xmpp_strdup(conn->ctx, domain);
|
||||||
if (!conn->domain) return XMPP_EMEM;
|
if (!conn->domain)
|
||||||
|
return XMPP_EMEM;
|
||||||
|
|
||||||
conn->sock = sock_connect(host, port);
|
conn->sock = sock_connect(host, port);
|
||||||
xmpp_debug(conn->ctx, "xmpp", "sock_connect() to %s:%u returned %d",
|
xmpp_debug(conn->ctx, "xmpp", "sock_connect() to %s:%u returned %d", host,
|
||||||
host, port, conn->sock);
|
port, conn->sock);
|
||||||
if (conn->sock == -1) return XMPP_EINT;
|
if (conn->sock == -1)
|
||||||
|
return XMPP_EINT;
|
||||||
if (conn->ka_timeout || conn->ka_interval)
|
if (conn->ka_timeout || conn->ka_interval)
|
||||||
sock_set_keepalive(conn->sock, conn->ka_timeout, conn->ka_interval);
|
sock_set_keepalive(conn->sock, conn->ka_timeout, conn->ka_interval);
|
||||||
|
|
||||||
@@ -1248,9 +1355,10 @@ static int _conn_connect(xmpp_conn_t * const conn,
|
|||||||
conn->conn_handler = callback;
|
conn->conn_handler = callback;
|
||||||
conn->userdata = userdata;
|
conn->userdata = userdata;
|
||||||
|
|
||||||
open_handler = conn->is_raw ? auth_handle_open_stub :
|
open_handler = conn->is_raw
|
||||||
type == XMPP_CLIENT ? auth_handle_open :
|
? auth_handle_open_stub
|
||||||
auth_handle_component_open;
|
: type == XMPP_CLIENT ? auth_handle_open
|
||||||
|
: auth_handle_component_open;
|
||||||
conn_prepare_reset(conn, open_handler);
|
conn_prepare_reset(conn, open_handler);
|
||||||
|
|
||||||
/* FIXME: it could happen that the connect returns immediately as
|
/* FIXME: it could happen that the connect returns immediately as
|
||||||
|
|||||||
176
src/crypto.c
176
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,38 @@ 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 +131,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 +142,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 +156,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 +169,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 +186,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 +202,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
|
||||||
@@ -186,43 +215,34 @@ void xmpp_sha1_to_digest(xmpp_sha1_t *sha1, unsigned char *digest)
|
|||||||
memcpy(digest, sha1->digest, SHA1_DIGEST_SIZE);
|
memcpy(digest, sha1->digest, SHA1_DIGEST_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Base64 encoding routines. Implemented according to RFC 3548. */
|
/* Base64 encoding routines. Implemented according to RFC 3548. */
|
||||||
|
|
||||||
/* map of all byte values to the base64 values, or to
|
/* map of all byte values to the base64 values, or to
|
||||||
'65' which indicates an invalid character. '=' is '64' */
|
'65' which indicates an invalid character. '=' is '64' */
|
||||||
static const unsigned char _base64_invcharmap[256] = {
|
static const unsigned char _base64_invcharmap[256] = {
|
||||||
65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65,
|
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
|
||||||
65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65,
|
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
|
||||||
65,65,65,65, 65,65,65,65, 65,65,65,62, 65,65,65,63,
|
65, 65, 65, 65, 65, 62, 65, 65, 65, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60,
|
||||||
52,53,54,55, 56,57,58,59, 60,61,65,65, 65,64,65,65,
|
61, 65, 65, 65, 64, 65, 65, 65, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
|
||||||
65, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14,
|
11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 65, 65, 65, 65,
|
||||||
15,16,17,18, 19,20,21,22, 23,24,25,65, 65,65,65,65,
|
65, 65, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42,
|
||||||
65,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
|
43, 44, 45, 46, 47, 48, 49, 50, 51, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
|
||||||
41,42,43,44, 45,46,47,48, 49,50,51,65, 65,65,65,65,
|
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
|
||||||
65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65,
|
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
|
||||||
65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65,
|
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
|
||||||
65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65,
|
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
|
||||||
65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65,
|
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
|
||||||
65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65,
|
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
|
||||||
65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65,
|
65, 65, 65, 65, 65, 65, 65, 65, 65};
|
||||||
65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65,
|
|
||||||
65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65
|
|
||||||
};
|
|
||||||
|
|
||||||
/* map of all 6-bit values to their corresponding byte
|
/* map of all 6-bit values to their corresponding byte
|
||||||
in the base64 alphabet. Padding char is the value '64' */
|
in the base64 alphabet. Padding char is the value '64' */
|
||||||
static const char _base64_charmap[65] = {
|
static const char _base64_charmap[65] = {
|
||||||
'A','B','C','D', 'E','F','G','H',
|
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
|
||||||
'I','J','K','L', 'M','N','O','P',
|
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
|
||||||
'Q','R','S','T', 'U','V','W','X',
|
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
|
||||||
'Y','Z','a','b', 'c','d','e','f',
|
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
|
||||||
'g','h','i','j', 'k','l','m','n',
|
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', '='};
|
||||||
'o','p','q','r', 's','t','u','v',
|
|
||||||
'w','x','y','z', '0','1','2','3',
|
|
||||||
'4','5','6','7', '8','9','+','/',
|
|
||||||
'='
|
|
||||||
};
|
|
||||||
|
|
||||||
static size_t base64_encoded_len(const size_t len)
|
static size_t base64_encoded_len(const size_t len)
|
||||||
{
|
{
|
||||||
@@ -231,7 +251,8 @@ static size_t base64_encoded_len(const size_t len)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static char *base64_encode(xmpp_ctx_t *ctx,
|
static char *base64_encode(xmpp_ctx_t *ctx,
|
||||||
const unsigned char * const buffer, const size_t len)
|
const unsigned char *const buffer,
|
||||||
|
const size_t len)
|
||||||
{
|
{
|
||||||
size_t clen;
|
size_t clen;
|
||||||
char *cbuf, *c;
|
char *cbuf, *c;
|
||||||
@@ -289,24 +310,31 @@ static size_t base64_decoded_len(const char * const buffer, const size_t len)
|
|||||||
unsigned char c;
|
unsigned char c;
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
if (len < 4) return 0;
|
if (len < 4)
|
||||||
|
return 0;
|
||||||
|
|
||||||
/* count the padding characters for the remainder */
|
/* count the padding characters for the remainder */
|
||||||
for (i = len; i > 0; --i) {
|
for (i = len; i > 0; --i) {
|
||||||
c = _base64_invcharmap[(unsigned char)buffer[i - 1]];
|
c = _base64_invcharmap[(unsigned char)buffer[i - 1]];
|
||||||
if (c < 64) break;
|
if (c < 64)
|
||||||
if (c == 64) ++nudge;
|
break;
|
||||||
if (c > 64) return 0;
|
if (c == 64)
|
||||||
|
++nudge;
|
||||||
|
if (c > 64)
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
if (nudge > 2) return 0;
|
if (nudge > 2)
|
||||||
|
return 0;
|
||||||
|
|
||||||
/* decoded steam is 3 bytes for every four */
|
/* decoded steam is 3 bytes for every four */
|
||||||
return 3 * (len >> 2) - nudge;
|
return 3 * (len >> 2) - nudge;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void base64_decode(xmpp_ctx_t *ctx,
|
static void base64_decode(xmpp_ctx_t *ctx,
|
||||||
const char * const buffer, const size_t len,
|
const char *const buffer,
|
||||||
unsigned char **out, size_t *outlen)
|
const size_t len,
|
||||||
|
unsigned char **out,
|
||||||
|
size_t *outlen)
|
||||||
{
|
{
|
||||||
size_t dlen;
|
size_t dlen;
|
||||||
unsigned char *dbuf, *d;
|
unsigned char *dbuf, *d;
|
||||||
@@ -314,10 +342,12 @@ static void base64_decode(xmpp_ctx_t *ctx,
|
|||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
/* len must be a multiple of 4 */
|
/* len must be a multiple of 4 */
|
||||||
if (len & 0x03) goto _base64_error;
|
if (len & 0x03)
|
||||||
|
goto _base64_error;
|
||||||
|
|
||||||
dlen = base64_decoded_len(buffer, len);
|
dlen = base64_decoded_len(buffer, len);
|
||||||
if (dlen == 0) goto _base64_error;
|
if (dlen == 0)
|
||||||
|
goto _base64_error;
|
||||||
|
|
||||||
dbuf = xmpp_alloc(ctx, dlen + 1);
|
dbuf = xmpp_alloc(ctx, dlen + 1);
|
||||||
if (dbuf != NULL) {
|
if (dbuf != NULL) {
|
||||||
@@ -325,22 +355,27 @@ static void base64_decode(xmpp_ctx_t *ctx,
|
|||||||
/* loop over each set of 4 characters, decoding 3 bytes */
|
/* loop over each set of 4 characters, decoding 3 bytes */
|
||||||
for (i = 0; i + 3 < len; i += 4) {
|
for (i = 0; i + 3 < len; i += 4) {
|
||||||
hextet = _base64_invcharmap[(unsigned char)buffer[i]];
|
hextet = _base64_invcharmap[(unsigned char)buffer[i]];
|
||||||
if (hextet & 0xC0) break;
|
if (hextet & 0xC0)
|
||||||
|
break;
|
||||||
word = hextet << 18;
|
word = hextet << 18;
|
||||||
hextet = _base64_invcharmap[(unsigned char)buffer[i + 1]];
|
hextet = _base64_invcharmap[(unsigned char)buffer[i + 1]];
|
||||||
if (hextet & 0xC0) break;
|
if (hextet & 0xC0)
|
||||||
|
break;
|
||||||
word |= hextet << 12;
|
word |= hextet << 12;
|
||||||
hextet = _base64_invcharmap[(unsigned char)buffer[i + 2]];
|
hextet = _base64_invcharmap[(unsigned char)buffer[i + 2]];
|
||||||
if (hextet & 0xC0) break;
|
if (hextet & 0xC0)
|
||||||
|
break;
|
||||||
word |= hextet << 6;
|
word |= hextet << 6;
|
||||||
hextet = _base64_invcharmap[(unsigned char)buffer[i + 3]];
|
hextet = _base64_invcharmap[(unsigned char)buffer[i + 3]];
|
||||||
if (hextet & 0xC0) break;
|
if (hextet & 0xC0)
|
||||||
|
break;
|
||||||
word |= hextet;
|
word |= hextet;
|
||||||
*d++ = (word & 0x00FF0000) >> 16;
|
*d++ = (word & 0x00FF0000) >> 16;
|
||||||
*d++ = (word & 0x0000FF00) >> 8;
|
*d++ = (word & 0x0000FF00) >> 8;
|
||||||
*d++ = (word & 0x000000FF);
|
*d++ = (word & 0x000000FF);
|
||||||
}
|
}
|
||||||
if (hextet > 64) goto _base64_decode_error;
|
if (hextet > 64)
|
||||||
|
goto _base64_decode_error;
|
||||||
/* handle the remainder */
|
/* handle the remainder */
|
||||||
switch (dlen % 3) {
|
switch (dlen % 3) {
|
||||||
case 0:
|
case 0:
|
||||||
@@ -349,32 +384,40 @@ static void base64_decode(xmpp_ctx_t *ctx,
|
|||||||
case 1:
|
case 1:
|
||||||
/* redo the last quartet, checking for correctness */
|
/* redo the last quartet, checking for correctness */
|
||||||
hextet = _base64_invcharmap[(unsigned char)buffer[len - 4]];
|
hextet = _base64_invcharmap[(unsigned char)buffer[len - 4]];
|
||||||
if (hextet & 0xC0) goto _base64_decode_error;
|
if (hextet & 0xC0)
|
||||||
|
goto _base64_decode_error;
|
||||||
word = hextet << 2;
|
word = hextet << 2;
|
||||||
hextet = _base64_invcharmap[(unsigned char)buffer[len - 3]];
|
hextet = _base64_invcharmap[(unsigned char)buffer[len - 3]];
|
||||||
if (hextet & 0xC0) goto _base64_decode_error;
|
if (hextet & 0xC0)
|
||||||
|
goto _base64_decode_error;
|
||||||
word |= hextet >> 4;
|
word |= hextet >> 4;
|
||||||
*d++ = word & 0xFF;
|
*d++ = word & 0xFF;
|
||||||
hextet = _base64_invcharmap[(unsigned char)buffer[len - 2]];
|
hextet = _base64_invcharmap[(unsigned char)buffer[len - 2]];
|
||||||
if (hextet != 64) goto _base64_decode_error;
|
if (hextet != 64)
|
||||||
|
goto _base64_decode_error;
|
||||||
hextet = _base64_invcharmap[(unsigned char)buffer[len - 1]];
|
hextet = _base64_invcharmap[(unsigned char)buffer[len - 1]];
|
||||||
if (hextet != 64) goto _base64_decode_error;
|
if (hextet != 64)
|
||||||
|
goto _base64_decode_error;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
/* redo the last quartet, checking for correctness */
|
/* redo the last quartet, checking for correctness */
|
||||||
hextet = _base64_invcharmap[(unsigned char)buffer[len - 4]];
|
hextet = _base64_invcharmap[(unsigned char)buffer[len - 4]];
|
||||||
if (hextet & 0xC0) goto _base64_decode_error;
|
if (hextet & 0xC0)
|
||||||
|
goto _base64_decode_error;
|
||||||
word = hextet << 10;
|
word = hextet << 10;
|
||||||
hextet = _base64_invcharmap[(unsigned char)buffer[len - 3]];
|
hextet = _base64_invcharmap[(unsigned char)buffer[len - 3]];
|
||||||
if (hextet & 0xC0) goto _base64_decode_error;
|
if (hextet & 0xC0)
|
||||||
|
goto _base64_decode_error;
|
||||||
word |= hextet << 4;
|
word |= hextet << 4;
|
||||||
hextet = _base64_invcharmap[(unsigned char)buffer[len - 2]];
|
hextet = _base64_invcharmap[(unsigned char)buffer[len - 2]];
|
||||||
if (hextet & 0xC0) goto _base64_decode_error;
|
if (hextet & 0xC0)
|
||||||
|
goto _base64_decode_error;
|
||||||
word |= hextet >> 2;
|
word |= hextet >> 2;
|
||||||
*d++ = (word & 0xFF00) >> 8;
|
*d++ = (word & 0xFF00) >> 8;
|
||||||
*d++ = (word & 0x00FF);
|
*d++ = (word & 0x00FF);
|
||||||
hextet = _base64_invcharmap[(unsigned char)buffer[len - 1]];
|
hextet = _base64_invcharmap[(unsigned char)buffer[len - 1]];
|
||||||
if (hextet != 64) goto _base64_decode_error;
|
if (hextet != 64)
|
||||||
|
goto _base64_decode_error;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
*d = '\0';
|
*d = '\0';
|
||||||
@@ -391,7 +434,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 +450,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 +486,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
|
||||||
@@ -456,8 +499,11 @@ char *xmpp_base64_decode_str(xmpp_ctx_t *ctx, const char *base64, size_t len)
|
|||||||
*
|
*
|
||||||
* @ingroup Encodings
|
* @ingroup Encodings
|
||||||
*/
|
*/
|
||||||
void xmpp_base64_decode_bin(xmpp_ctx_t *ctx, const char *base64, size_t len,
|
void xmpp_base64_decode_bin(xmpp_ctx_t *ctx,
|
||||||
unsigned char **out, size_t *outlen)
|
const char *base64,
|
||||||
|
size_t len,
|
||||||
|
unsigned char **out,
|
||||||
|
size_t *outlen)
|
||||||
{
|
{
|
||||||
base64_decode(ctx, base64, len, out, outlen);
|
base64_decode(ctx, base64, len, out, outlen);
|
||||||
}
|
}
|
||||||
|
|||||||
71
src/ctx.c
71
src/ctx.c
@@ -47,11 +47,13 @@
|
|||||||
|
|
||||||
#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 systems without va_copy support. */
|
||||||
#if defined(_MSC_VER) && _MSC_VER < 1800
|
#if defined(_MSC_VER) && _MSC_VER < 1800 || \
|
||||||
#define va_copy(d,s) ((d) = (s))
|
!defined(_MSC_VER) && !defined(HAVE_DECL_VA_COPY)
|
||||||
|
#define va_copy(d, s) (memcpy(&d, &s, sizeof(va_list)))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/** Initialize the Strophe library.
|
/** Initialize the Strophe library.
|
||||||
@@ -63,6 +65,7 @@
|
|||||||
void xmpp_initialize(void)
|
void xmpp_initialize(void)
|
||||||
{
|
{
|
||||||
sock_initialize();
|
sock_initialize();
|
||||||
|
resolver_initialize();
|
||||||
tls_initialize();
|
tls_initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,6 +76,7 @@
|
|||||||
void xmpp_shutdown(void)
|
void xmpp_shutdown(void)
|
||||||
{
|
{
|
||||||
tls_shutdown();
|
tls_shutdown();
|
||||||
|
resolver_shutdown();
|
||||||
sock_shutdown();
|
sock_shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,6 +95,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
|
||||||
@@ -102,8 +114,7 @@ void xmpp_shutdown(void)
|
|||||||
*/
|
*/
|
||||||
int xmpp_version_check(int major, int minor)
|
int xmpp_version_check(int major, int minor)
|
||||||
{
|
{
|
||||||
return (major == LIBXMPP_VERSION_MAJOR) &&
|
return (major == LIBXMPP_VERSION_MAJOR) && (minor >= LIBXMPP_VERSION_MINOR);
|
||||||
(minor >= LIBXMPP_VERSION_MINOR);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We define the global default allocator, logger, and context here. */
|
/* We define the global default allocator, logger, and context here. */
|
||||||
@@ -113,33 +124,32 @@ int xmpp_version_check(int major, int minor)
|
|||||||
*/
|
*/
|
||||||
static void *_malloc(const size_t size, void *const userdata)
|
static void *_malloc(const size_t size, void *const userdata)
|
||||||
{
|
{
|
||||||
|
UNUSED(userdata);
|
||||||
return malloc(size);
|
return malloc(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _free(void *p, void *const userdata)
|
static void _free(void *p, void *const userdata)
|
||||||
{
|
{
|
||||||
|
UNUSED(userdata);
|
||||||
free(p);
|
free(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *_realloc(void *p, const size_t size, void *const userdata)
|
static void *_realloc(void *p, const size_t size, void *const userdata)
|
||||||
{
|
{
|
||||||
|
UNUSED(userdata);
|
||||||
return realloc(p, size);
|
return realloc(p, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* default memory function map */
|
/* default memory function map */
|
||||||
static xmpp_mem_t xmpp_default_mem = {
|
static xmpp_mem_t xmpp_default_mem = {
|
||||||
_malloc, /* use the thinly wrapped stdlib routines by default */
|
_malloc, /* use the thinly wrapped stdlib routines by default */
|
||||||
_free,
|
_free, _realloc, NULL};
|
||||||
_realloc,
|
|
||||||
NULL
|
|
||||||
};
|
|
||||||
|
|
||||||
/* log levels and names */
|
/* log levels and names */
|
||||||
static const char * const _xmpp_log_level_name[4] = {"DEBUG", "INFO", "WARN", "ERROR"};
|
static const char *const _xmpp_log_level_name[4] = {"DEBUG", "INFO", "WARN",
|
||||||
static const xmpp_log_level_t _xmpp_default_logger_levels[] = {XMPP_LEVEL_DEBUG,
|
"ERROR"};
|
||||||
XMPP_LEVEL_INFO,
|
static const xmpp_log_level_t _xmpp_default_logger_levels[] = {
|
||||||
XMPP_LEVEL_WARN,
|
XMPP_LEVEL_DEBUG, XMPP_LEVEL_INFO, XMPP_LEVEL_WARN, XMPP_LEVEL_ERROR};
|
||||||
XMPP_LEVEL_ERROR};
|
|
||||||
|
|
||||||
/** Log a message.
|
/** Log a message.
|
||||||
* The default logger writes to stderr.
|
* The default logger writes to stderr.
|
||||||
@@ -161,11 +171,14 @@ static void xmpp_default_logger(void * const userdata,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const xmpp_log_t _xmpp_default_loggers[] = {
|
static const xmpp_log_t _xmpp_default_loggers[] = {
|
||||||
{&xmpp_default_logger, (void*)&_xmpp_default_logger_levels[XMPP_LEVEL_DEBUG]},
|
{&xmpp_default_logger,
|
||||||
{&xmpp_default_logger, (void*)&_xmpp_default_logger_levels[XMPP_LEVEL_INFO]},
|
(void *)&_xmpp_default_logger_levels[XMPP_LEVEL_DEBUG]},
|
||||||
{&xmpp_default_logger, (void*)&_xmpp_default_logger_levels[XMPP_LEVEL_WARN]},
|
{&xmpp_default_logger,
|
||||||
{&xmpp_default_logger, (void*)&_xmpp_default_logger_levels[XMPP_LEVEL_ERROR]}
|
(void *)&_xmpp_default_logger_levels[XMPP_LEVEL_INFO]},
|
||||||
};
|
{&xmpp_default_logger,
|
||||||
|
(void *)&_xmpp_default_logger_levels[XMPP_LEVEL_WARN]},
|
||||||
|
{&xmpp_default_logger,
|
||||||
|
(void *)&_xmpp_default_logger_levels[XMPP_LEVEL_ERROR]}};
|
||||||
|
|
||||||
/** Get a default logger with filtering.
|
/** Get a default logger with filtering.
|
||||||
* The default logger provides a basic logging setup which writes log
|
* The default logger provides a basic logging setup which writes log
|
||||||
@@ -181,8 +194,8 @@ static const xmpp_log_t _xmpp_default_loggers[] = {
|
|||||||
xmpp_log_t *xmpp_get_default_logger(xmpp_log_level_t level)
|
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)
|
||||||
if (level < XMPP_LEVEL_DEBUG) level = XMPP_LEVEL_DEBUG;
|
level = XMPP_LEVEL_ERROR;
|
||||||
|
|
||||||
return (xmpp_log_t *)&_xmpp_default_loggers[level];
|
return (xmpp_log_t *)&_xmpp_default_loggers[level];
|
||||||
}
|
}
|
||||||
@@ -224,8 +237,7 @@ void xmpp_free(const xmpp_ctx_t * const ctx, void *p)
|
|||||||
*
|
*
|
||||||
* @return a pointer to the reallocated memory or NULL on an error
|
* @return a pointer to the reallocated memory or NULL on an error
|
||||||
*/
|
*/
|
||||||
void *xmpp_realloc(const xmpp_ctx_t * const ctx, void *p,
|
void *xmpp_realloc(const xmpp_ctx_t *const ctx, void *p, const size_t size)
|
||||||
const size_t size)
|
|
||||||
{
|
{
|
||||||
return ctx->mem->realloc(p, size, ctx->mem->userdata);
|
return ctx->mem->realloc(p, size, ctx->mem->userdata);
|
||||||
}
|
}
|
||||||
@@ -408,8 +420,10 @@ xmpp_ctx_t *xmpp_ctx_new(const xmpp_mem_t * const mem,
|
|||||||
ctx->log = log;
|
ctx->log = log;
|
||||||
|
|
||||||
ctx->connlist = NULL;
|
ctx->connlist = NULL;
|
||||||
|
ctx->timed_handlers = NULL;
|
||||||
ctx->loop_status = XMPP_LOOP_NOTSTARTED;
|
ctx->loop_status = XMPP_LOOP_NOTSTARTED;
|
||||||
ctx->rand = xmpp_rand_new(ctx);
|
ctx->rand = xmpp_rand_new(ctx);
|
||||||
|
ctx->timeout = EVENT_LOOP_DEFAULT_TIMEOUT;
|
||||||
if (ctx->rand == NULL) {
|
if (ctx->rand == NULL) {
|
||||||
xmpp_free(ctx, ctx);
|
xmpp_free(ctx, ctx);
|
||||||
ctx = NULL;
|
ctx = NULL;
|
||||||
@@ -432,3 +446,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;
|
||||||
|
}
|
||||||
|
|||||||
113
src/event.c
113
src/event.c
@@ -41,23 +41,15 @@
|
|||||||
#define _sleep(x) usleep((x)*1000)
|
#define _sleep(x) usleep((x)*1000)
|
||||||
#else
|
#else
|
||||||
#include <winsock2.h>
|
#include <winsock2.h>
|
||||||
#define ETIMEDOUT WSAETIMEDOUT
|
|
||||||
#define ECONNRESET WSAECONNRESET
|
|
||||||
#define ECONNABORTED WSAECONNABORTED
|
|
||||||
#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,12 +74,13 @@ 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;
|
||||||
|
|
||||||
if (ctx->loop_status == XMPP_LOOP_QUIT) return;
|
if (ctx->loop_status == XMPP_LOOP_QUIT)
|
||||||
|
return;
|
||||||
|
|
||||||
/* send queued data */
|
/* send queued data */
|
||||||
connitem = ctx->connlist;
|
connitem = ctx->connlist;
|
||||||
@@ -104,44 +97,29 @@ 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.");
|
conn->error = XMPP_EIO;
|
||||||
conn->error = ECONNABORTED;
|
|
||||||
conn_disconnect(conn);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* write all data from the send queue to the socket */
|
/* write all data from the send queue to the socket */
|
||||||
sq = conn->send_queue_head;
|
sq = conn->send_queue_head;
|
||||||
while (sq) {
|
while (!conn->error && sq) {
|
||||||
towrite = sq->len - sq->written;
|
towrite = sq->len - sq->written;
|
||||||
|
|
||||||
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))) {
|
conn->error = XMPP_EIO;
|
||||||
/* an error occured */
|
|
||||||
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())) {
|
conn->error = XMPP_EIO;
|
||||||
/* an error occured */
|
|
||||||
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);
|
||||||
@@ -153,15 +131,15 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
|
|||||||
/* pop the top item */
|
/* pop the top item */
|
||||||
conn->send_queue_head = sq;
|
conn->send_queue_head = sq;
|
||||||
/* if we've sent everything update the tail */
|
/* if we've sent everything update the tail */
|
||||||
if (!sq) conn->send_queue_tail = NULL;
|
if (!sq)
|
||||||
|
conn->send_queue_tail = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* tear down connection on error */
|
/* tear down connection on error */
|
||||||
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_disconnect(conn);
|
conn_disconnect(conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -174,10 +152,8 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
|
|||||||
conn_parser_reset(connitem->conn);
|
conn_parser_reset(connitem->conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* fire any ready timed handlers, then make sure we don't wait past
|
||||||
/* fire any ready timed handlers, then
|
the time when timed handlers need to be called */
|
||||||
make sure we don't wait past the time when timed handlers need
|
|
||||||
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;
|
||||||
@@ -202,13 +178,15 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
|
|||||||
conn->connect_timeout)
|
conn->connect_timeout)
|
||||||
FD_SET(conn->sock, &wfds);
|
FD_SET(conn->sock, &wfds);
|
||||||
else {
|
else {
|
||||||
conn->error = ETIMEDOUT;
|
|
||||||
xmpp_info(ctx, "xmpp", "Connection attempt timed out.");
|
xmpp_info(ctx, "xmpp", "Connection attempt timed out.");
|
||||||
|
conn->error = XMPP_ETIMEDOUT;
|
||||||
conn_disconnect(conn);
|
conn_disconnect(conn);
|
||||||
}
|
}
|
||||||
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 +195,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;
|
||||||
@@ -245,7 +222,8 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* no events happened */
|
/* no events happened */
|
||||||
if (ret == 0 && tls_read_bytes == 0) return;
|
if (ret == 0 && tls_read_bytes == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
/* process events */
|
/* process events */
|
||||||
connitem = ctx->connlist;
|
connitem = ctx->connlist;
|
||||||
@@ -262,6 +240,7 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
|
|||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
/* connection failed */
|
/* connection failed */
|
||||||
xmpp_debug(ctx, "xmpp", "connection failed, error %d", ret);
|
xmpp_debug(ctx, "xmpp", "connection failed, error %d", ret);
|
||||||
|
conn->error = XMPP_EIO;
|
||||||
conn_disconnect(conn);
|
conn_disconnect(conn);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -273,33 +252,36 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
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,
|
||||||
xmpp_debug(ctx, "xmpp", "parse error, disconnecting");
|
"parse error");
|
||||||
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",
|
||||||
xmpp_debug(ctx, "xmpp", "Unrecoverable TLS error, %d.", tls_error(conn->tls));
|
"Unrecoverable TLS error, %d.",
|
||||||
conn->error = tls_error(conn->tls);
|
tls_error(conn->tls));
|
||||||
|
conn->error = XMPP_EIO;
|
||||||
conn_disconnect(conn);
|
conn_disconnect(conn);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* return of 0 means socket closed by server */
|
/* return of 0 means socket closed by server */
|
||||||
xmpp_debug(ctx, "xmpp", "Socket closed by remote host.");
|
xmpp_debug(ctx, "xmpp",
|
||||||
conn->error = ECONNRESET;
|
"Socket closed by remote host.");
|
||||||
|
conn->error = ret == 0 ? XMPP_ERESET : XMPP_EIO;
|
||||||
conn_disconnect(conn);
|
conn_disconnect(conn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -329,11 +311,12 @@ 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)
|
||||||
{
|
{
|
||||||
if (ctx->loop_status != XMPP_LOOP_NOTSTARTED) return;
|
if (ctx->loop_status != XMPP_LOOP_NOTSTARTED)
|
||||||
|
return;
|
||||||
|
|
||||||
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 */
|
||||||
|
|||||||
535
src/handler.c
535
src/handler.c
@@ -24,6 +24,28 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "ostypes.h"
|
#include "ostypes.h"
|
||||||
|
|
||||||
|
typedef int (*xmpp_void_handler)();
|
||||||
|
|
||||||
|
/* Remove item from the list pointed by head, but don't free it.
|
||||||
|
* 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)
|
||||||
|
{
|
||||||
|
while (*head) {
|
||||||
|
if (*head == item) {
|
||||||
|
*head = item->next;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
head = &(*head)->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.
|
||||||
@@ -31,39 +53,43 @@
|
|||||||
* @param conn a Strophe connection object
|
* @param conn a Strophe connection object
|
||||||
* @param stanza a Strophe stanza object
|
* @param stanza a Strophe stanza object
|
||||||
*/
|
*/
|
||||||
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 +103,37 @@ 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)
|
||||||
else
|
xmpp_free(conn->ctx, item->u.ns);
|
||||||
conn->handlers = item->next;
|
if (item->u.name)
|
||||||
if (item->ns) xmpp_free(conn->ctx, item->ns);
|
xmpp_free(conn->ctx, item->u.name);
|
||||||
if (item->name) xmpp_free(conn->ctx, item->name);
|
if (item->u.type)
|
||||||
if (item->type) xmpp_free(conn->ctx, item->type);
|
xmpp_free(conn->ctx, item->u.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,59 +147,87 @@ 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(ctx, item);
|
||||||
|
}
|
||||||
|
} else if (min > (item->u.period - elapsed))
|
||||||
|
min = item->u.period - elapsed;
|
||||||
|
|
||||||
|
item = next;
|
||||||
}
|
}
|
||||||
|
|
||||||
connitem = connitem->next;
|
connitem = connitem->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check timed handlers in context. These handlers fire periodically
|
||||||
|
* regardless of connections state.
|
||||||
|
* TODO Reduce copy-paste.
|
||||||
|
*/
|
||||||
|
item = ctx->timed_handlers;
|
||||||
|
while (item) {
|
||||||
|
next = item->next;
|
||||||
|
timestamp = time_stamp();
|
||||||
|
elapsed = time_elapsed(item->u.last_stamp, timestamp);
|
||||||
|
if (elapsed >= item->u.period) {
|
||||||
|
/* fire! */
|
||||||
|
item->u.last_stamp = timestamp;
|
||||||
|
ret =
|
||||||
|
((xmpp_global_timed_handler)item->handler)(ctx, item->userdata);
|
||||||
|
/* list may be changed during execution of a handler */
|
||||||
|
next = item->next;
|
||||||
|
if (!ret) {
|
||||||
|
/* delete handler if it returned false */
|
||||||
|
_handler_item_remove(&ctx->timed_handlers, item);
|
||||||
|
xmpp_free(ctx, item);
|
||||||
|
}
|
||||||
|
} else if (min > (item->u.period - elapsed))
|
||||||
|
min = item->u.period - elapsed;
|
||||||
|
|
||||||
|
item = next;
|
||||||
|
}
|
||||||
|
|
||||||
return min;
|
return min;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -200,48 +244,63 @@ 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _timed_handler_add(xmpp_conn_t * const conn,
|
static void _timed_handler_add(xmpp_ctx_t *ctx,
|
||||||
xmpp_timed_handler handler,
|
xmpp_handlist_t **handlers_list,
|
||||||
|
xmpp_void_handler handler,
|
||||||
const unsigned long period,
|
const unsigned long period,
|
||||||
void *const userdata,
|
void *const userdata,
|
||||||
const int user_handler)
|
const int user_handler)
|
||||||
{
|
{
|
||||||
xmpp_handlist_t *item, *tail;
|
xmpp_handlist_t *item;
|
||||||
|
|
||||||
/* 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 = *handlers_list; item; item = item->next) {
|
||||||
if (item->handler == (void *)handler)
|
if (item->handler == handler && item->userdata == userdata) {
|
||||||
|
xmpp_warn(ctx, "xmpp", "Timed handler already exists.");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (item) return;
|
}
|
||||||
|
if (item)
|
||||||
|
return;
|
||||||
|
|
||||||
/* build new item */
|
/* build new item */
|
||||||
item = xmpp_alloc(conn->ctx, sizeof(xmpp_handlist_t));
|
item = xmpp_alloc(ctx, sizeof(xmpp_handlist_t));
|
||||||
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->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)
|
item->next = *handlers_list;
|
||||||
conn->timed_handlers = item;
|
*handlers_list = item;
|
||||||
else {
|
}
|
||||||
tail = conn->timed_handlers;
|
|
||||||
while (tail->next)
|
static void _timed_handler_delete(xmpp_ctx_t *ctx,
|
||||||
tail = tail->next;
|
xmpp_handlist_t **handlers_list,
|
||||||
tail->next = item;
|
xmpp_void_handler handler)
|
||||||
|
{
|
||||||
|
xmpp_handlist_t *item;
|
||||||
|
|
||||||
|
while (*handlers_list) {
|
||||||
|
item = *handlers_list;
|
||||||
|
if (item->handler == handler) {
|
||||||
|
*handlers_list = item->next;
|
||||||
|
xmpp_free(ctx, item);
|
||||||
|
} else {
|
||||||
|
handlers_list = &item->next;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -255,57 +314,42 @@ static void _timed_handler_add(xmpp_conn_t * const conn,
|
|||||||
void xmpp_timed_handler_delete(xmpp_conn_t *const conn,
|
void xmpp_timed_handler_delete(xmpp_conn_t *const conn,
|
||||||
xmpp_timed_handler handler)
|
xmpp_timed_handler handler)
|
||||||
{
|
{
|
||||||
xmpp_handlist_t *item, *prev;
|
_timed_handler_delete(conn->ctx, &conn->timed_handlers, handler);
|
||||||
|
|
||||||
if (!conn->timed_handlers) return;
|
|
||||||
|
|
||||||
prev = NULL;
|
|
||||||
item = conn->timed_handlers;
|
|
||||||
while (item) {
|
|
||||||
if (item->handler == (void *)handler)
|
|
||||||
break;
|
|
||||||
prev = item;
|
|
||||||
item = item->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item) {
|
|
||||||
if (prev)
|
|
||||||
prev->next = item->next;
|
|
||||||
else
|
|
||||||
conn->timed_handlers = item->next;
|
|
||||||
|
|
||||||
xmpp_free(conn->ctx, item);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _id_handler_add(xmpp_conn_t *const conn,
|
static void _id_handler_add(xmpp_conn_t *const conn,
|
||||||
xmpp_handler handler,
|
xmpp_handler handler,
|
||||||
const char *const id,
|
const char *const id,
|
||||||
void * const userdata, int user_handler)
|
void *const userdata,
|
||||||
|
int user_handler)
|
||||||
{
|
{
|
||||||
xmpp_handlist_t *item, *tail;
|
xmpp_handlist_t *item, *tail;
|
||||||
|
|
||||||
/* 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;
|
||||||
|
|
||||||
/* build new item */
|
/* build new item */
|
||||||
item = xmpp_alloc(conn->ctx, sizeof(xmpp_handlist_t));
|
item = xmpp_alloc(conn->ctx, sizeof(xmpp_handlist_t));
|
||||||
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 +377,31 @@ 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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -365,53 +411,65 @@ static void _handler_add(xmpp_conn_t * const conn,
|
|||||||
const char *const ns,
|
const char *const ns,
|
||||||
const char *const name,
|
const char *const name,
|
||||||
const char *const type,
|
const char *const type,
|
||||||
void * const userdata, int user_handler)
|
void *const userdata,
|
||||||
|
int user_handler)
|
||||||
{
|
{
|
||||||
xmpp_handlist_t *item, *tail;
|
xmpp_handlist_t *item, *tail;
|
||||||
|
|
||||||
/* 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 */
|
||||||
item = (xmpp_handlist_t *)xmpp_alloc(conn->ctx, sizeof(xmpp_handlist_t));
|
item = (xmpp_handlist_t *)xmpp_alloc(conn->ctx, sizeof(xmpp_handlist_t));
|
||||||
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)
|
||||||
if (item->name) xmpp_free(conn->ctx, item->name);
|
xmpp_free(conn->ctx, item->u.ns);
|
||||||
|
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)
|
||||||
@@ -431,33 +489,34 @@ static void _handler_add(xmpp_conn_t * const conn,
|
|||||||
*
|
*
|
||||||
* @ingroup Handlers
|
* @ingroup Handlers
|
||||||
*/
|
*/
|
||||||
void xmpp_handler_delete(xmpp_conn_t * const conn,
|
void xmpp_handler_delete(xmpp_conn_t *const conn, xmpp_handler handler)
|
||||||
xmpp_handler handler)
|
|
||||||
{
|
{
|
||||||
xmpp_handlist_t *prev, *item;
|
xmpp_handlist_t *prev, *item;
|
||||||
|
|
||||||
if (!conn->handlers) return;
|
if (!conn->handlers)
|
||||||
|
return;
|
||||||
|
|
||||||
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)
|
||||||
if (item->name) xmpp_free(conn->ctx, item->name);
|
xmpp_free(conn->ctx, item->u.ns);
|
||||||
if (item->type) xmpp_free(conn->ctx, item->type);
|
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);
|
xmpp_free(conn->ctx, item);
|
||||||
|
item = prev ? prev->next : conn->handlers;
|
||||||
|
} else {
|
||||||
|
prev = item;
|
||||||
|
item = item->next;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -482,7 +541,8 @@ void xmpp_timed_handler_add(xmpp_conn_t * const conn,
|
|||||||
const unsigned long period,
|
const unsigned long period,
|
||||||
void *const userdata)
|
void *const userdata)
|
||||||
{
|
{
|
||||||
_timed_handler_add(conn, handler, period, userdata, 1);
|
_timed_handler_add(conn->ctx, &conn->timed_handlers, handler, period,
|
||||||
|
userdata, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Add a timed system handler.
|
/** Add a timed system handler.
|
||||||
@@ -499,7 +559,8 @@ void handler_add_timed(xmpp_conn_t * const conn,
|
|||||||
const unsigned long period,
|
const unsigned long period,
|
||||||
void *const userdata)
|
void *const userdata)
|
||||||
{
|
{
|
||||||
_timed_handler_add(conn, handler, period, userdata, 0);
|
_timed_handler_add(conn->ctx, &conn->timed_handlers, handler, period,
|
||||||
|
userdata, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Add an id based stanza handler.
|
/** Add an id based stanza handler.
|
||||||
@@ -595,3 +656,129 @@ 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Add a global timed handler.
|
||||||
|
* The handler will fire for the first time once the period has elapsed,
|
||||||
|
* and continue firing regularly after that. Strophe will try its best
|
||||||
|
* to fire handlers as close to the period times as it can, but accuracy
|
||||||
|
* will vary depending on the resolution of the event loop.
|
||||||
|
*
|
||||||
|
* The main difference between global and ordinary handlers:
|
||||||
|
* - Ordinary handler is related to a connection, fires only when the
|
||||||
|
* connection is in connected state and is removed once the connection is
|
||||||
|
* destroyed.
|
||||||
|
* - Global handler fires regardless of connections state and is related to
|
||||||
|
* a Strophe context.
|
||||||
|
*
|
||||||
|
* The handler is executed in context of the respective event loop.
|
||||||
|
*
|
||||||
|
* If the handler function returns true, it will be kept, and if it
|
||||||
|
* returns false, it will be deleted from the list of handlers.
|
||||||
|
*
|
||||||
|
* Notice, the same handler pointer may be added multiple times with different
|
||||||
|
* userdata pointers. However, xmpp_global_timed_handler_delete() deletes
|
||||||
|
* all occurrences.
|
||||||
|
*
|
||||||
|
* @param ctx a Strophe context object
|
||||||
|
* @param handler a function pointer to a timed handler
|
||||||
|
* @param period the time in milliseconds between firings
|
||||||
|
* @param userdata an opaque data pointer that will be passed to the handler
|
||||||
|
*
|
||||||
|
* @ingroup Handlers
|
||||||
|
*/
|
||||||
|
void xmpp_global_timed_handler_add(xmpp_ctx_t *const ctx,
|
||||||
|
xmpp_global_timed_handler handler,
|
||||||
|
const unsigned long period,
|
||||||
|
void *const userdata)
|
||||||
|
{
|
||||||
|
_timed_handler_add(ctx, &ctx->timed_handlers, handler, period, userdata, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Delete a global timed handler.
|
||||||
|
*
|
||||||
|
* @param ctx a Strophe context object
|
||||||
|
* @param handler function pointer to the handler
|
||||||
|
*
|
||||||
|
* @ingroup Handlers
|
||||||
|
*/
|
||||||
|
void xmpp_global_timed_handler_delete(xmpp_ctx_t *const ctx,
|
||||||
|
xmpp_global_timed_handler handler)
|
||||||
|
{
|
||||||
|
_timed_handler_delete(ctx, &ctx->timed_handlers, handler);
|
||||||
|
}
|
||||||
|
|||||||
82
src/hash.c
82
src/hash.c
@@ -46,8 +46,8 @@ struct _hash_iterator_t {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/** allocate and initialize a new hash table */
|
/** allocate and initialize a new hash table */
|
||||||
hash_t *hash_new(xmpp_ctx_t * const ctx, const int size,
|
hash_t *
|
||||||
hash_free_func free_func)
|
hash_new(xmpp_ctx_t *const ctx, const int size, hash_free_func free_func)
|
||||||
{
|
{
|
||||||
hash_t *result = NULL;
|
hash_t *result = NULL;
|
||||||
|
|
||||||
@@ -93,7 +93,8 @@ void hash_release(hash_t * const table)
|
|||||||
while (entry != NULL) {
|
while (entry != NULL) {
|
||||||
next = entry->next;
|
next = entry->next;
|
||||||
xmpp_free(ctx, entry->key);
|
xmpp_free(ctx, entry->key);
|
||||||
if (table->free) table->free(ctx, entry->value);
|
if (table->free)
|
||||||
|
table->free(ctx, entry->value);
|
||||||
xmpp_free(ctx, entry);
|
xmpp_free(ctx, entry);
|
||||||
entry = next;
|
entry = next;
|
||||||
}
|
}
|
||||||
@@ -106,18 +107,36 @@ 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,23 +149,29 @@ 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;
|
||||||
entry->key = xmpp_strdup(ctx, key);
|
entry->key = xmpp_strdup(ctx, key);
|
||||||
if (!entry->key) {
|
if (!entry->key) {
|
||||||
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 +180,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 */
|
||||||
@@ -188,7 +200,8 @@ int hash_drop(hash_t *table, const char *key)
|
|||||||
if (!strcmp(key, entry->key)) {
|
if (!strcmp(key, entry->key)) {
|
||||||
/* match, remove the entry */
|
/* match, remove the entry */
|
||||||
xmpp_free(ctx, entry->key);
|
xmpp_free(ctx, entry->key);
|
||||||
if (table->free) table->free(ctx, entry->value);
|
if (table->free)
|
||||||
|
table->free(ctx, entry->value);
|
||||||
if (prev == NULL) {
|
if (prev == NULL) {
|
||||||
table->entries[table_index] = entry->next;
|
table->entries[table_index] = entry->next;
|
||||||
} else {
|
} else {
|
||||||
@@ -227,7 +240,6 @@ hash_iterator_t *hash_iter_new(hash_t *table)
|
|||||||
return iter;
|
return iter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** release an iterator that is no longer needed */
|
/** release an iterator that is no longer needed */
|
||||||
void hash_iter_release(hash_iterator_t *iter)
|
void hash_iter_release(hash_iterator_t *iter)
|
||||||
{
|
{
|
||||||
@@ -235,7 +247,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);
|
||||||
}
|
}
|
||||||
@@ -250,7 +262,8 @@ const char * hash_iter_next(hash_iterator_t *iter)
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* advance until we find the next entry */
|
/* advance until we find the next entry */
|
||||||
if (entry != NULL) entry = entry->next;
|
if (entry != NULL)
|
||||||
|
entry = entry->next;
|
||||||
if (entry == NULL) {
|
if (entry == NULL) {
|
||||||
/* we're off the end of list, search for a new entry */
|
/* we're off the end of list, search for a new entry */
|
||||||
i = iter->index + 1;
|
i = iter->index + 1;
|
||||||
@@ -273,4 +286,3 @@ const char * hash_iter_next(hash_iterator_t *iter)
|
|||||||
iter->entry = entry;
|
iter->entry = entry;
|
||||||
return entry->key;
|
return entry->key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,8 +21,8 @@ typedef struct _hash_t hash_t;
|
|||||||
typedef void (*hash_free_func)(const xmpp_ctx_t *const ctx, void *p);
|
typedef void (*hash_free_func)(const xmpp_ctx_t *const ctx, void *p);
|
||||||
|
|
||||||
/** allocate and initialize a new hash table */
|
/** allocate and initialize a new hash table */
|
||||||
hash_t *hash_new(xmpp_ctx_t * const ctx, const int size,
|
hash_t *
|
||||||
hash_free_func free_func);
|
hash_new(xmpp_ctx_t *const ctx, const int size, hash_free_func free_func);
|
||||||
|
|
||||||
/** allocate a new reference to an existing hash table */
|
/** allocate a new reference to an existing hash table */
|
||||||
hash_t *hash_clone(hash_t *const table);
|
hash_t *hash_clone(hash_t *const table);
|
||||||
|
|||||||
47
src/jid.c
47
src/jid.c
@@ -28,7 +28,8 @@
|
|||||||
* @return an allocated string with the full JID or NULL if no domain
|
* @return an allocated string with the full JID or NULL if no domain
|
||||||
* is specified
|
* is specified
|
||||||
*/
|
*/
|
||||||
char *xmpp_jid_new(xmpp_ctx_t *ctx, const char *node,
|
char *xmpp_jid_new(xmpp_ctx_t *ctx,
|
||||||
|
const char *node,
|
||||||
const char *domain,
|
const char *domain,
|
||||||
const char *resource)
|
const char *resource)
|
||||||
{
|
{
|
||||||
@@ -36,7 +37,8 @@ char *xmpp_jid_new(xmpp_ctx_t *ctx, const char *node,
|
|||||||
size_t len, nlen, dlen, rlen;
|
size_t len, nlen, dlen, rlen;
|
||||||
|
|
||||||
/* jid must at least have a domain */
|
/* jid must at least have a domain */
|
||||||
if (domain == NULL) return NULL;
|
if (domain == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
/* accumulate lengths */
|
/* accumulate lengths */
|
||||||
dlen = strlen(domain);
|
dlen = strlen(domain);
|
||||||
@@ -72,15 +74,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 +121,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 +132,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 +152,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];
|
||||||
|
|||||||
@@ -21,7 +21,8 @@ struct MD5Context {
|
|||||||
};
|
};
|
||||||
|
|
||||||
void MD5Init(struct MD5Context *context);
|
void MD5Init(struct MD5Context *context);
|
||||||
void MD5Update(struct MD5Context *context, unsigned char const *buf,
|
void MD5Update(struct MD5Context *context,
|
||||||
|
unsigned char const *buf,
|
||||||
uint32_t len);
|
uint32_t len);
|
||||||
void MD5Final(unsigned char digest[16], struct MD5Context *context);
|
void MD5Final(unsigned char digest[16], struct MD5Context *context);
|
||||||
|
|
||||||
|
|||||||
@@ -1,85 +0,0 @@
|
|||||||
/* oocontext.cpp
|
|
||||||
** strophe XMPP client library -- C++ context implementation
|
|
||||||
**
|
|
||||||
** 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#include "strophe.h"
|
|
||||||
#include "strophepp.h"
|
|
||||||
|
|
||||||
XMPP::Context::Context()
|
|
||||||
{
|
|
||||||
m_mem.alloc = callAlloc;
|
|
||||||
m_mem.realloc = callRealloc;
|
|
||||||
m_mem.free = callFree;
|
|
||||||
m_mem.userdata = (void *)this;
|
|
||||||
|
|
||||||
m_log.handler = callLog;
|
|
||||||
m_log.userdata = (void *)this;
|
|
||||||
|
|
||||||
m_ctx = ::xmpp_ctx_new(&m_mem, &m_log);
|
|
||||||
}
|
|
||||||
|
|
||||||
XMPP::Context::~Context()
|
|
||||||
{
|
|
||||||
::xmpp_ctx_free(m_ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
void *XMPP::Context::alloc(const size_t size)
|
|
||||||
{
|
|
||||||
return ::malloc(size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void *XMPP::Context::realloc(void *p, const size_t size)
|
|
||||||
{
|
|
||||||
return ::realloc(p, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void XMPP::Context::free(void *p)
|
|
||||||
{
|
|
||||||
::free(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
void XMPP::Context::log(const xmpp_log_level_t level,
|
|
||||||
const char * const area,
|
|
||||||
const char * const msg)
|
|
||||||
{
|
|
||||||
/* do nothing by default */
|
|
||||||
}
|
|
||||||
|
|
||||||
xmpp_ctx_t *XMPP::Context::getContext()
|
|
||||||
{
|
|
||||||
return m_ctx;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *XMPP::Context::callAlloc(const size_t size, void * const userdata)
|
|
||||||
{
|
|
||||||
return reinterpret_cast<Context *>(userdata)->alloc(size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void *XMPP::Context::callRealloc(void *p, const size_t size,
|
|
||||||
void * const userdata)
|
|
||||||
{
|
|
||||||
return reinterpret_cast<Context *>(userdata)->realloc(p, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void XMPP::Context::callFree(void *p, void * const userdata)
|
|
||||||
{
|
|
||||||
reinterpret_cast<Context *>(userdata)->free(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
void XMPP::Context::callLog(void * const userdata,
|
|
||||||
const xmpp_log_level_t level,
|
|
||||||
const char * const area,
|
|
||||||
const char * const msg)
|
|
||||||
{
|
|
||||||
reinterpret_cast<Context *>(userdata)->log(level, area, msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
/* oostanza.cpp
|
|
||||||
** strophe XMPP client library -- C++ context implementation
|
|
||||||
**
|
|
||||||
** 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "strophe.h"
|
|
||||||
#include "strophepp.h"
|
|
||||||
|
|
||||||
using namespace XMPP;
|
|
||||||
|
|
||||||
void *Stanza::operator new(size_t size, Context *ctx)
|
|
||||||
{
|
|
||||||
void *p;
|
|
||||||
|
|
||||||
/* we must allocate extra room for the Context object so that the
|
|
||||||
destructor can access it to free the object. C++ does not allow
|
|
||||||
us to access normal members in the destructor, so we have to hide
|
|
||||||
it. This must be prepended as well, since C++ will add stuff to
|
|
||||||
the end in subclasses. */
|
|
||||||
|
|
||||||
p = ctx->alloc(size + sizeof(Context *));
|
|
||||||
if (!p) return p;
|
|
||||||
|
|
||||||
*reinterpret_cast<Context **>(p) = ctx;
|
|
||||||
p = reinterpret_cast<void *>(reinterpret_cast<char *>(p) +
|
|
||||||
sizeof(Context *));
|
|
||||||
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Stanza::operator delete(void *p)
|
|
||||||
{
|
|
||||||
Context *ctx;
|
|
||||||
|
|
||||||
ctx = *reinterpret_cast<Context **>(reinterpret_cast<char *>(p) - 4);
|
|
||||||
ctx->free(reinterpret_cast<char *>(p) - 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
Stanza::Stanza(Context *ctx)
|
|
||||||
{
|
|
||||||
m_ctx = ctx;
|
|
||||||
m_stanza = ::xmpp_stanza_new(ctx->getContext());
|
|
||||||
// TODO: check for errors
|
|
||||||
}
|
|
||||||
|
|
||||||
Stanza::~Stanza()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Stanza *Stanza::create(Context *ctx)
|
|
||||||
{
|
|
||||||
return new (ctx) Stanza(ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Stanza::release()
|
|
||||||
{
|
|
||||||
if (::xmpp_stanza_release(m_stanza))
|
|
||||||
delete this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Stanza *Stanza::clone()
|
|
||||||
{
|
|
||||||
::xmpp_stanza_clone(m_stanza);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Stanza *Stanza::copy()
|
|
||||||
{
|
|
||||||
// TODO
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@@ -27,7 +27,6 @@ typedef void (*parser_end_callback)(char *name, void * const userdata);
|
|||||||
typedef void (*parser_stanza_callback)(xmpp_stanza_t *stanza,
|
typedef void (*parser_stanza_callback)(xmpp_stanza_t *stanza,
|
||||||
void *const userdata);
|
void *const userdata);
|
||||||
|
|
||||||
|
|
||||||
parser_t *parser_new(xmpp_ctx_t *ctx,
|
parser_t *parser_new(xmpp_ctx_t *ctx,
|
||||||
parser_start_callback startcb,
|
parser_start_callback startcb,
|
||||||
parser_end_callback endcb,
|
parser_end_callback endcb,
|
||||||
|
|||||||
@@ -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,8 +93,9 @@ 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++;
|
||||||
len = strlen(c);
|
len = strlen(c);
|
||||||
@@ -65,7 +114,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) {
|
||||||
@@ -82,7 +131,8 @@ static void _set_attributes(xmpp_stanza_t *stanza, const XML_Char **attrs)
|
|||||||
char *attr;
|
char *attr;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (!attrs) return;
|
if (!attrs)
|
||||||
|
return;
|
||||||
|
|
||||||
for (i = 0; attrs[i]; i += 2) {
|
for (i = 0; attrs[i]; i += 2) {
|
||||||
/* namespaced attributes aren't used in xmpp, discard namespace */
|
/* namespaced attributes aren't used in xmpp, discard namespace */
|
||||||
@@ -92,9 +142,28 @@ static void _set_attributes(xmpp_stanza_t *stanza, const XML_Char **attrs)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _start_element(void *userdata,
|
static void complete_inner_text(parser_t *parser)
|
||||||
const XML_Char *nsname,
|
{
|
||||||
const XML_Char **attrs)
|
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, const XML_Char *nsname, const XML_Char **attrs)
|
||||||
{
|
{
|
||||||
parser_t *parser = (parser_t *)userdata;
|
parser_t *parser = (parser_t *)userdata;
|
||||||
xmpp_stanza_t *child;
|
xmpp_stanza_t *child;
|
||||||
@@ -106,8 +175,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 */
|
||||||
if (!parser->stanza && parser->depth != 1) {
|
if (!parser->stanza && parser->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);
|
||||||
}
|
}
|
||||||
@@ -132,8 +201,10 @@ static void _start_element(void *userdata,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ns) xmpp_free(parser->ctx, ns);
|
if (ns)
|
||||||
if (name) xmpp_free(parser->ctx, name);
|
xmpp_free(parser->ctx, ns);
|
||||||
|
if (name)
|
||||||
|
xmpp_free(parser->ctx, name);
|
||||||
|
|
||||||
parser->depth++;
|
parser->depth++;
|
||||||
}
|
}
|
||||||
@@ -149,13 +220,13 @@ 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;
|
||||||
} else {
|
} else {
|
||||||
if (parser->stanzacb)
|
if (parser->stanzacb)
|
||||||
parser->stanzacb(parser->stanza,
|
parser->stanzacb(parser->stanza, parser->userdata);
|
||||||
parser->userdata);
|
|
||||||
xmpp_stanza_release(parser->stanza);
|
xmpp_stanza_release(parser->stanza);
|
||||||
parser->stanza = NULL;
|
parser->stanza = NULL;
|
||||||
}
|
}
|
||||||
@@ -165,20 +236,30 @@ 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 +280,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 +301,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"
|
||||||
|
|
||||||
@@ -36,13 +36,14 @@ struct _parser_t {
|
|||||||
xmpp_stanza_t *stanza;
|
xmpp_stanza_t *stanza;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void _set_attributes(xmpp_stanza_t *stanza, int nattrs,
|
static void
|
||||||
const xmlChar **attrs)
|
_set_attributes(xmpp_stanza_t *stanza, int nattrs, const xmlChar **attrs)
|
||||||
{
|
{
|
||||||
int i, len;
|
int i, len;
|
||||||
char *value;
|
char *value;
|
||||||
|
|
||||||
if (!attrs) return;
|
if (!attrs)
|
||||||
|
return;
|
||||||
|
|
||||||
/* SAX2 uses array of localname/prefix/uri/value_begin/value_end */
|
/* SAX2 uses array of localname/prefix/uri/value_begin/value_end */
|
||||||
for (i = 0; i < nattrs * 5; i += 5) {
|
for (i = 0; i < nattrs * 5; i += 5) {
|
||||||
@@ -59,17 +60,19 @@ static void _set_attributes(xmpp_stanza_t *stanza, int nattrs,
|
|||||||
|
|
||||||
/* SAX2 gives us the attrs in an incredibly inconvenient array,
|
/* SAX2 gives us the attrs in an incredibly inconvenient array,
|
||||||
* convert it to what the start callback is expecting */
|
* convert it to what the start callback is expecting */
|
||||||
static char **_convert_attrs(parser_t *parser, int nattrs,
|
static char **
|
||||||
const xmlChar **attrs)
|
_convert_attrs(parser_t *parser, int nattrs, const xmlChar **attrs)
|
||||||
{
|
{
|
||||||
int c, i, o, len;
|
int c, i, o, len;
|
||||||
char *value;
|
char *value;
|
||||||
char **ret;
|
char **ret;
|
||||||
|
|
||||||
if (!attrs) return NULL;
|
if (!attrs)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
ret = xmpp_alloc(parser->ctx, (nattrs + 1) * 2 * sizeof(char *));
|
ret = xmpp_alloc(parser->ctx, (nattrs + 1) * 2 * sizeof(char *));
|
||||||
if (!ret) return NULL;
|
if (!ret)
|
||||||
|
return NULL;
|
||||||
memset(ret, 0, (nattrs + 1) * 2 * sizeof(char *));
|
memset(ret, 0, (nattrs + 1) * 2 * sizeof(char *));
|
||||||
|
|
||||||
for (c = 0; c < nattrs; c++) {
|
for (c = 0; c < nattrs; c++) {
|
||||||
@@ -97,30 +100,41 @@ static void _free_cbattrs(parser_t *parser, char **attrs)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
for (i = 0; attrs[i]; i += 2) {
|
for (i = 0; attrs[i]; i += 2) {
|
||||||
if (attrs[i]) xmpp_free(parser->ctx, attrs[i]);
|
if (attrs[i])
|
||||||
if (attrs[i+1]) xmpp_free(parser->ctx, attrs[i+1]);
|
xmpp_free(parser->ctx, attrs[i]);
|
||||||
|
if (attrs[i + 1])
|
||||||
|
xmpp_free(parser->ctx, attrs[i + 1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
xmpp_free(parser->ctx, attrs);
|
xmpp_free(parser->ctx, attrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _start_element(void *userdata,
|
static void _start_element(void *userdata,
|
||||||
const xmlChar *name, const xmlChar *prefix,
|
const xmlChar *name,
|
||||||
const xmlChar *uri, int nnamespaces,
|
const xmlChar *prefix,
|
||||||
const xmlChar **namespaces, int nattrs,
|
const xmlChar *uri,
|
||||||
int ndefaulted, const xmlChar **attrs)
|
int nnamespaces,
|
||||||
|
const xmlChar **namespaces,
|
||||||
|
int nattrs,
|
||||||
|
int ndefaulted,
|
||||||
|
const xmlChar **attrs)
|
||||||
{
|
{
|
||||||
parser_t *parser = (parser_t *)userdata;
|
parser_t *parser = (parser_t *)userdata;
|
||||||
xmpp_stanza_t *child;
|
xmpp_stanza_t *child;
|
||||||
char **cbattrs;
|
char **cbattrs;
|
||||||
|
|
||||||
|
UNUSED(prefix);
|
||||||
|
UNUSED(nnamespaces);
|
||||||
|
UNUSED(namespaces);
|
||||||
|
UNUSED(ndefaulted);
|
||||||
|
|
||||||
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) {
|
||||||
@@ -162,11 +176,16 @@ static void _start_element(void *userdata,
|
|||||||
parser->depth++;
|
parser->depth++;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _end_element(void *userdata, const xmlChar *name,
|
static void _end_element(void *userdata,
|
||||||
const xmlChar *prefix, const xmlChar *uri)
|
const xmlChar *name,
|
||||||
|
const xmlChar *prefix,
|
||||||
|
const xmlChar *uri)
|
||||||
{
|
{
|
||||||
parser_t *parser = (parser_t *)userdata;
|
parser_t *parser = (parser_t *)userdata;
|
||||||
|
|
||||||
|
UNUSED(prefix);
|
||||||
|
UNUSED(uri);
|
||||||
|
|
||||||
parser->depth--;
|
parser->depth--;
|
||||||
|
|
||||||
if (parser->depth == 0) {
|
if (parser->depth == 0) {
|
||||||
@@ -179,8 +198,7 @@ static void _end_element(void *userdata, const xmlChar *name,
|
|||||||
parser->stanza = parser->stanza->parent;
|
parser->stanza = parser->stanza->parent;
|
||||||
} else {
|
} else {
|
||||||
if (parser->stanzacb)
|
if (parser->stanzacb)
|
||||||
parser->stanzacb(parser->stanza,
|
parser->stanzacb(parser->stanza, parser->userdata);
|
||||||
parser->userdata);
|
|
||||||
xmpp_stanza_release(parser->stanza);
|
xmpp_stanza_release(parser->stanza);
|
||||||
parser->stanza = NULL;
|
parser->stanza = NULL;
|
||||||
}
|
}
|
||||||
@@ -193,7 +211,8 @@ static void _characters(void *userdata, const xmlChar *chr, int len)
|
|||||||
xmpp_stanza_t *stanza;
|
xmpp_stanza_t *stanza;
|
||||||
|
|
||||||
/* skip unimportant whitespace, etc */
|
/* skip unimportant whitespace, etc */
|
||||||
if (parser->depth < 2) return;
|
if (parser->depth < 2)
|
||||||
|
return;
|
||||||
|
|
||||||
/* create and populate stanza */
|
/* create and populate stanza */
|
||||||
stanza = xmpp_stanza_new(parser->ctx);
|
stanza = xmpp_stanza_new(parser->ctx);
|
||||||
@@ -248,6 +267,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 +277,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->xmlctx = xmlCreatePushParserCtxt(&parser->handlers,
|
|
||||||
parser, NULL, 0, NULL);
|
|
||||||
if (!parser->xmlctx) return 0;
|
|
||||||
|
|
||||||
parser->depth = 0;
|
|
||||||
parser->stanza = NULL;
|
parser->stanza = NULL;
|
||||||
|
parser->depth = 0;
|
||||||
|
|
||||||
return 1;
|
parser->xmlctx =
|
||||||
|
xmlCreatePushParserCtxt(&parser->handlers, parser, NULL, 0, NULL);
|
||||||
|
|
||||||
|
return parser->xmlctx ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* feed a chunk of data to the parser */
|
/* feed a chunk of data to the parser */
|
||||||
@@ -275,9 +294,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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
57
src/rand.c
57
src/rand.c
@@ -62,8 +62,8 @@ struct _xmpp_rand_t {
|
|||||||
/* adds two arrays as numbers in big-endian representation and stores
|
/* adds two arrays as numbers in big-endian representation and stores
|
||||||
* result in the first one.
|
* result in the first one.
|
||||||
*/
|
*/
|
||||||
static void arr_add(uint8_t *arr1, size_t arr1_len,
|
static void
|
||||||
uint8_t *arr2, size_t arr2_len)
|
arr_add(uint8_t *arr1, size_t arr1_len, uint8_t *arr2, size_t arr2_len)
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
uint32_t acc;
|
uint32_t acc;
|
||||||
@@ -89,8 +89,10 @@ static void store_be32(uint32_t val, uint8_t be[4])
|
|||||||
be[3] = (uint8_t)(val & 0xff);
|
be[3] = (uint8_t)(val & 0xff);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Hash_df(uint8_t *input_string, size_t input_string_len,
|
static void Hash_df(uint8_t *input_string,
|
||||||
uint8_t *output_string, size_t no_of_bytes_to_return)
|
size_t input_string_len,
|
||||||
|
uint8_t *output_string,
|
||||||
|
size_t no_of_bytes_to_return)
|
||||||
{
|
{
|
||||||
uint8_t counter;
|
uint8_t counter;
|
||||||
uint8_t temp[round_up(seedlen, outlen)];
|
uint8_t temp[round_up(seedlen, outlen)];
|
||||||
@@ -119,7 +121,8 @@ static void Hash_df(uint8_t *input_string, size_t input_string_len,
|
|||||||
static void Hash_DRBG_Instantiate(Hash_DRBG_CTX *ctx,
|
static void Hash_DRBG_Instantiate(Hash_DRBG_CTX *ctx,
|
||||||
uint8_t *entropy_input,
|
uint8_t *entropy_input,
|
||||||
size_t entropy_input_len,
|
size_t entropy_input_len,
|
||||||
uint8_t *nonce, size_t nonce_len)
|
uint8_t *nonce,
|
||||||
|
size_t nonce_len)
|
||||||
{
|
{
|
||||||
uint8_t seed_material[ENTROPY_MAX + NONCE_MAX];
|
uint8_t seed_material[ENTROPY_MAX + NONCE_MAX];
|
||||||
uint8_t seed0[seedlen + 1];
|
uint8_t seed0[seedlen + 1];
|
||||||
@@ -127,8 +130,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;
|
||||||
@@ -160,8 +165,8 @@ static void Hash_DRBG_Reseed(Hash_DRBG_CTX *ctx,
|
|||||||
ctx->reseed_counter = 1;
|
ctx->reseed_counter = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Hashgen(uint8_t *V, uint8_t *output,
|
static void
|
||||||
size_t requested_number_of_bytes)
|
Hashgen(uint8_t *V, uint8_t *output, size_t requested_number_of_bytes)
|
||||||
{
|
{
|
||||||
uint8_t data[seedlen];
|
uint8_t data[seedlen];
|
||||||
uint8_t W[GENERATE_MAX];
|
uint8_t W[GENERATE_MAX];
|
||||||
@@ -185,7 +190,8 @@ static void Hashgen(uint8_t *V, uint8_t *output,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* assume additional_input is zero length string */
|
/* assume additional_input is zero length string */
|
||||||
static int Hash_DRBG_Generate(Hash_DRBG_CTX *ctx, uint8_t *output,
|
static int Hash_DRBG_Generate(Hash_DRBG_CTX *ctx,
|
||||||
|
uint8_t *output,
|
||||||
size_t requested_number_of_bytes)
|
size_t requested_number_of_bytes)
|
||||||
{
|
{
|
||||||
uint8_t H[outlen];
|
uint8_t H[outlen];
|
||||||
@@ -287,25 +293,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
|
||||||
|
|||||||
792
src/resolver.c
792
src/resolver.c
File diff suppressed because it is too large
Load Diff
@@ -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.
|
||||||
*
|
*
|
||||||
@@ -43,8 +46,10 @@ typedef struct resolver_srv_rr_struc {
|
|||||||
*
|
*
|
||||||
* @return XMPP_DOMAIN_FOUND on success or XMPP_DOMAIN_NOT_FOUND on fail
|
* @return XMPP_DOMAIN_FOUND on success or XMPP_DOMAIN_NOT_FOUND on fail
|
||||||
*/
|
*/
|
||||||
int resolver_srv_lookup_buf(xmpp_ctx_t *ctx, const unsigned char *buf,
|
int resolver_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);
|
||||||
/** Resolve SRV record.
|
/** Resolve SRV record.
|
||||||
*
|
*
|
||||||
* @param ctx a Strophe context object
|
* @param ctx a Strophe context object
|
||||||
@@ -55,8 +60,11 @@ int resolver_srv_lookup_buf(xmpp_ctx_t *ctx, const unsigned char *buf,
|
|||||||
*
|
*
|
||||||
* @return XMPP_DOMAIN_FOUND on success or XMPP_DOMAIN_NOT_FOUND on fail
|
* @return XMPP_DOMAIN_FOUND on success or XMPP_DOMAIN_NOT_FOUND on fail
|
||||||
*/
|
*/
|
||||||
int resolver_srv_lookup(xmpp_ctx_t *ctx, const char *service, const char *proto,
|
int resolver_srv_lookup(xmpp_ctx_t *ctx,
|
||||||
const char *domain, resolver_srv_rr_t **srv_rr_list);
|
const char *service,
|
||||||
|
const char *proto,
|
||||||
|
const char *domain,
|
||||||
|
resolver_srv_rr_t **srv_rr_list);
|
||||||
|
|
||||||
/** Release a list returned by resolver_srv_lookup() or
|
/** Release a list returned by resolver_srv_lookup() or
|
||||||
* resolver_srv_lookup_buf().
|
* resolver_srv_lookup_buf().
|
||||||
|
|||||||
103
src/sasl.c
103
src/sasl.c
@@ -21,7 +21,6 @@
|
|||||||
#include "ostypes.h"
|
#include "ostypes.h"
|
||||||
#include "sasl.h"
|
#include "sasl.h"
|
||||||
#include "md5.h"
|
#include "md5.h"
|
||||||
#include "sha1.h"
|
|
||||||
#include "scram.h"
|
#include "scram.h"
|
||||||
#include "rand.h"
|
#include "rand.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
@@ -36,9 +35,9 @@
|
|||||||
#endif
|
#endif
|
||||||
#endif /* _MSC_VER */
|
#endif /* _MSC_VER */
|
||||||
|
|
||||||
|
|
||||||
/** generate authentication string for the SASL PLAIN mechanism */
|
/** generate authentication string for the SASL PLAIN mechanism */
|
||||||
char *sasl_plain(xmpp_ctx_t *ctx, const char *authid, const char *password) {
|
char *sasl_plain(xmpp_ctx_t *ctx, const char *authid, const char *password)
|
||||||
|
{
|
||||||
size_t idlen, passlen;
|
size_t idlen, passlen;
|
||||||
size_t msglen;
|
size_t msglen;
|
||||||
char *result = NULL;
|
char *result = NULL;
|
||||||
@@ -113,13 +112,17 @@ static hash_t *_parse_digest_challenge(xmpp_ctx_t *ctx, const char *msg)
|
|||||||
s = text;
|
s = text;
|
||||||
while (*s != '\0') {
|
while (*s != '\0') {
|
||||||
/* skip any leading commas and spaces */
|
/* skip any leading commas and spaces */
|
||||||
while ((*s == ',') || (*s == ' ')) s++;
|
while ((*s == ',') || (*s == ' '))
|
||||||
|
s++;
|
||||||
/* accumulate a key ending at '=' */
|
/* accumulate a key ending at '=' */
|
||||||
t = s;
|
t = s;
|
||||||
while ((*t != '=') && (*t != '\0')) t++;
|
while ((*t != '=') && (*t != '\0'))
|
||||||
if (*t == '\0') break; /* bad string */
|
t++;
|
||||||
|
if (*t == '\0')
|
||||||
|
break; /* bad string */
|
||||||
key = _make_string(ctx, (char *)s, (t - s));
|
key = _make_string(ctx, (char *)s, (t - s));
|
||||||
if (key == NULL) break;
|
if (key == NULL)
|
||||||
|
break;
|
||||||
/* advance our start pointer past the key */
|
/* advance our start pointer past the key */
|
||||||
s = t + 1;
|
s = t + 1;
|
||||||
t = s;
|
t = s;
|
||||||
@@ -136,7 +139,8 @@ static hash_t *_parse_digest_challenge(xmpp_ctx_t *ctx, const char *msg)
|
|||||||
}
|
}
|
||||||
/* otherwise, accumulate a value ending in ',' or '\0' */
|
/* otherwise, accumulate a value ending in ',' or '\0' */
|
||||||
} else {
|
} else {
|
||||||
while ((*t != ',') && (*t != '\0')) t++;
|
while ((*t != ',') && (*t != '\0'))
|
||||||
|
t++;
|
||||||
value = _make_string(ctx, (char *)s, (t - s));
|
value = _make_string(ctx, (char *)s, (t - s));
|
||||||
s = t;
|
s = t;
|
||||||
}
|
}
|
||||||
@@ -168,8 +172,8 @@ static void _digest_to_hex(const char *digest, char *hex)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** append 'key="value"' to a buffer, growing as necessary */
|
/** append 'key="value"' to a buffer, growing as necessary */
|
||||||
static char *_add_key(xmpp_ctx_t *ctx, hash_t *table, const char *key,
|
static char *
|
||||||
char *buf, int *len, int quote)
|
_add_key(xmpp_ctx_t *ctx, hash_t *table, const char *key, char *buf, int quote)
|
||||||
{
|
{
|
||||||
int olen, nlen;
|
int olen, nlen;
|
||||||
int keylen, valuelen;
|
int keylen, valuelen;
|
||||||
@@ -181,7 +185,8 @@ static char *_add_key(xmpp_ctx_t *ctx, hash_t *table, const char *key,
|
|||||||
buf = xmpp_alloc(ctx, 1);
|
buf = xmpp_alloc(ctx, 1);
|
||||||
buf[0] = '\0';
|
buf[0] = '\0';
|
||||||
}
|
}
|
||||||
if (buf == NULL) return NULL;
|
if (buf == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
/* get current string length */
|
/* get current string length */
|
||||||
olen = strlen(buf);
|
olen = strlen(buf);
|
||||||
@@ -204,27 +209,33 @@ static char *_add_key(xmpp_ctx_t *ctx, hash_t *table, const char *key,
|
|||||||
|
|
||||||
if (buf != NULL) {
|
if (buf != NULL) {
|
||||||
c = buf + olen;
|
c = buf + olen;
|
||||||
if (olen) *c++ = ',';
|
if (olen)
|
||||||
memcpy(c, key, keylen); c += keylen;
|
*c++ = ',';
|
||||||
|
memcpy(c, key, keylen);
|
||||||
|
c += keylen;
|
||||||
*c++ = '=';
|
*c++ = '=';
|
||||||
memcpy(c, qvalue, valuelen); c += valuelen;
|
memcpy(c, qvalue, valuelen);
|
||||||
|
c += valuelen;
|
||||||
*c++ = '\0';
|
*c++ = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (quote) xmpp_free(ctx, (char *)qvalue);
|
if (quote)
|
||||||
|
xmpp_free(ctx, (char *)qvalue);
|
||||||
|
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** generate auth response string for the SASL DIGEST-MD5 mechanism */
|
/** generate auth response string for the SASL DIGEST-MD5 mechanism */
|
||||||
char *sasl_digest_md5(xmpp_ctx_t *ctx, const char *challenge,
|
char *sasl_digest_md5(xmpp_ctx_t *ctx,
|
||||||
const char *jid, const char *password) {
|
const char *challenge,
|
||||||
|
const char *jid,
|
||||||
|
const char *password)
|
||||||
|
{
|
||||||
hash_t *table;
|
hash_t *table;
|
||||||
char *result = NULL;
|
char *result = NULL;
|
||||||
char *node, *domain, *realm;
|
char *node, *domain, *realm;
|
||||||
char *value;
|
char *value;
|
||||||
char *response;
|
char *response;
|
||||||
int rlen;
|
|
||||||
struct MD5Context MD5;
|
struct MD5Context MD5;
|
||||||
unsigned char digest[16], HA1[16], HA2[16];
|
unsigned char digest[16], HA1[16], HA2[16];
|
||||||
char hex[32];
|
char hex[32];
|
||||||
@@ -264,6 +275,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);
|
||||||
@@ -339,16 +351,15 @@ char *sasl_digest_md5(xmpp_ctx_t *ctx, const char *challenge,
|
|||||||
|
|
||||||
/* construct reply */
|
/* construct reply */
|
||||||
result = NULL;
|
result = NULL;
|
||||||
rlen = 0;
|
result = _add_key(ctx, table, "username", result, 1);
|
||||||
result = _add_key(ctx, table, "username", result, &rlen, 1);
|
result = _add_key(ctx, table, "realm", result, 1);
|
||||||
result = _add_key(ctx, table, "realm", result, &rlen, 1);
|
result = _add_key(ctx, table, "nonce", result, 1);
|
||||||
result = _add_key(ctx, table, "nonce", result, &rlen, 1);
|
result = _add_key(ctx, table, "cnonce", result, 1);
|
||||||
result = _add_key(ctx, table, "cnonce", result, &rlen, 1);
|
result = _add_key(ctx, table, "nc", result, 0);
|
||||||
result = _add_key(ctx, table, "nc", result, &rlen, 0);
|
result = _add_key(ctx, table, "qop", result, 0);
|
||||||
result = _add_key(ctx, table, "qop", result, &rlen, 0);
|
result = _add_key(ctx, table, "digest-uri", result, 1);
|
||||||
result = _add_key(ctx, table, "digest-uri", result, &rlen, 1);
|
result = _add_key(ctx, table, "response", result, 0);
|
||||||
result = _add_key(ctx, table, "response", result, &rlen, 0);
|
result = _add_key(ctx, table, "charset", result, 0);
|
||||||
result = _add_key(ctx, table, "charset", result, &rlen, 0);
|
|
||||||
|
|
||||||
xmpp_free(ctx, node);
|
xmpp_free(ctx, node);
|
||||||
xmpp_free(ctx, domain);
|
xmpp_free(ctx, domain);
|
||||||
@@ -361,13 +372,16 @@ char *sasl_digest_md5(xmpp_ctx_t *ctx, const char *challenge,
|
|||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** generate auth response string for the SASL SCRAM-SHA-1 mechanism */
|
/** generate auth response string for the SASL SCRAM mechanism */
|
||||||
char *sasl_scram_sha1(xmpp_ctx_t *ctx, const char *challenge,
|
char *sasl_scram(xmpp_ctx_t *ctx,
|
||||||
const char *first_bare, const char *jid,
|
const struct hash_alg *alg,
|
||||||
|
const char *challenge,
|
||||||
|
const char *first_bare,
|
||||||
|
const char *jid,
|
||||||
const char *password)
|
const char *password)
|
||||||
{
|
{
|
||||||
uint8_t key[SHA1_DIGEST_SIZE];
|
uint8_t key[SCRAM_DIGEST_SIZE];
|
||||||
uint8_t sign[SHA1_DIGEST_SIZE];
|
uint8_t sign[SCRAM_DIGEST_SIZE];
|
||||||
char *r = NULL;
|
char *r = NULL;
|
||||||
char *s = NULL;
|
char *s = NULL;
|
||||||
char *i = NULL;
|
char *i = NULL;
|
||||||
@@ -384,7 +398,8 @@ char *sasl_scram_sha1(xmpp_ctx_t *ctx, const char *challenge,
|
|||||||
char *result = NULL;
|
char *result = NULL;
|
||||||
size_t response_len;
|
size_t response_len;
|
||||||
size_t auth_len;
|
size_t auth_len;
|
||||||
int j;
|
|
||||||
|
UNUSED(jid);
|
||||||
|
|
||||||
tmp = xmpp_strdup(ctx, challenge);
|
tmp = xmpp_strdup(ctx, challenge);
|
||||||
if (!tmp) {
|
if (!tmp) {
|
||||||
@@ -419,7 +434,8 @@ char *sasl_scram_sha1(xmpp_ctx_t *ctx, const char *challenge,
|
|||||||
goto out_sval;
|
goto out_sval;
|
||||||
}
|
}
|
||||||
|
|
||||||
response_len = 39 + strlen(r);
|
/* "c=biws," + r + ",p=" + sign_b64 + '\0' */
|
||||||
|
response_len = 7 + strlen(r) + 3 + ((alg->digest_size + 2) / 3 * 4) + 1;
|
||||||
response = xmpp_alloc(ctx, response_len);
|
response = xmpp_alloc(ctx, response_len);
|
||||||
if (!response) {
|
if (!response) {
|
||||||
goto out_auth;
|
goto out_auth;
|
||||||
@@ -429,18 +445,17 @@ char *sasl_scram_sha1(xmpp_ctx_t *ctx, const char *challenge,
|
|||||||
xmpp_snprintf(auth, auth_len, "%s,%s,%s", first_bare + 3, challenge,
|
xmpp_snprintf(auth, auth_len, "%s,%s,%s", first_bare + 3, challenge,
|
||||||
response);
|
response);
|
||||||
|
|
||||||
SCRAM_SHA1_ClientKey((uint8_t *)password, strlen(password),
|
SCRAM_ClientKey(alg, (uint8_t *)password, strlen(password), (uint8_t *)sval,
|
||||||
(uint8_t *)sval, sval_len, (uint32_t)ival, key);
|
sval_len, (uint32_t)ival, key);
|
||||||
SCRAM_SHA1_ClientSignature(key, (uint8_t *)auth, strlen(auth), sign);
|
SCRAM_ClientSignature(alg, key, (uint8_t *)auth, strlen(auth), sign);
|
||||||
for (j = 0; j < SHA1_DIGEST_SIZE; j++) {
|
SCRAM_ClientProof(alg, sign, key, sign);
|
||||||
sign[j] ^= key[j];
|
|
||||||
}
|
|
||||||
|
|
||||||
sign_b64 = xmpp_base64_encode(ctx, sign, sizeof(sign));
|
sign_b64 = xmpp_base64_encode(ctx, sign, alg->digest_size);
|
||||||
if (!sign_b64) {
|
if (!sign_b64) {
|
||||||
goto out_response;
|
goto out_response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check for buffer overflow */
|
||||||
if (strlen(response) + strlen(sign_b64) + 3 + 1 > response_len) {
|
if (strlen(response) + strlen(sign_b64) + 3 + 1 > response_len) {
|
||||||
xmpp_free(ctx, sign_b64);
|
xmpp_free(ctx, sign_b64);
|
||||||
goto out_response;
|
goto out_response;
|
||||||
@@ -449,8 +464,8 @@ char *sasl_scram_sha1(xmpp_ctx_t *ctx, const char *challenge,
|
|||||||
strcat(response, sign_b64);
|
strcat(response, sign_b64);
|
||||||
xmpp_free(ctx, sign_b64);
|
xmpp_free(ctx, sign_b64);
|
||||||
|
|
||||||
response_b64 = xmpp_base64_encode(ctx, (unsigned char *)response,
|
response_b64 =
|
||||||
strlen(response));
|
xmpp_base64_encode(ctx, (unsigned char *)response, strlen(response));
|
||||||
if (!response_b64) {
|
if (!response_b64) {
|
||||||
goto out_response;
|
goto out_response;
|
||||||
}
|
}
|
||||||
|
|||||||
14
src/sasl.h
14
src/sasl.h
@@ -17,14 +17,20 @@
|
|||||||
#define __LIBSTROPHE_SASL_H__
|
#define __LIBSTROPHE_SASL_H__
|
||||||
|
|
||||||
#include "strophe.h"
|
#include "strophe.h"
|
||||||
|
#include "scram.h"
|
||||||
|
|
||||||
/** low-level sasl routines */
|
/** low-level sasl routines */
|
||||||
|
|
||||||
char *sasl_plain(xmpp_ctx_t *ctx, const char *authid, const char *password);
|
char *sasl_plain(xmpp_ctx_t *ctx, const char *authid, const char *password);
|
||||||
char *sasl_digest_md5(xmpp_ctx_t *ctx, const char *challenge,
|
char *sasl_digest_md5(xmpp_ctx_t *ctx,
|
||||||
const char *jid, const char *password);
|
const char *challenge,
|
||||||
char *sasl_scram_sha1(xmpp_ctx_t *ctx, const char *challenge,
|
const char *jid,
|
||||||
const char *first_bare, const char *jid,
|
const char *password);
|
||||||
|
char *sasl_scram(xmpp_ctx_t *ctx,
|
||||||
|
const struct hash_alg *alg,
|
||||||
|
const char *challenge,
|
||||||
|
const char *first_bare,
|
||||||
|
const char *jid,
|
||||||
const char *password);
|
const char *password);
|
||||||
|
|
||||||
#endif /* _LIBXMPP_SASL_H__ */
|
#endif /* _LIBXMPP_SASL_H__ */
|
||||||
|
|||||||
138
src/scram.c
138
src/scram.c
@@ -19,56 +19,103 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
#include "sha1.h"
|
#include "sha1.h"
|
||||||
|
#include "sha256.h"
|
||||||
|
#include "sha512.h"
|
||||||
#include "ostypes.h"
|
#include "ostypes.h"
|
||||||
|
|
||||||
#include "scram.h"
|
#include "scram.h"
|
||||||
|
|
||||||
#define HMAC_BLOCK_SIZE 64
|
#define HMAC_BLOCK_SIZE_MAX 128
|
||||||
|
|
||||||
static const uint8_t ipad = 0x36;
|
static const uint8_t ipad = 0x36;
|
||||||
static const uint8_t opad = 0x5C;
|
static const uint8_t opad = 0x5C;
|
||||||
|
|
||||||
static void crypto_HMAC_SHA1(const uint8_t *key, size_t key_len,
|
const struct hash_alg scram_sha1 = {
|
||||||
const uint8_t *text, size_t len,
|
"SCRAM-SHA-1",
|
||||||
|
SASL_MASK_SCRAMSHA1,
|
||||||
|
SHA1_DIGEST_SIZE,
|
||||||
|
(void (*)(const uint8_t *, size_t, uint8_t *))crypto_SHA1,
|
||||||
|
(void (*)(void *))crypto_SHA1_Init,
|
||||||
|
(void (*)(void *, const uint8_t *, size_t))crypto_SHA1_Update,
|
||||||
|
(void (*)(void *, uint8_t *))crypto_SHA1_Final};
|
||||||
|
|
||||||
|
const struct hash_alg scram_sha256 = {
|
||||||
|
"SCRAM-SHA-256",
|
||||||
|
SASL_MASK_SCRAMSHA256,
|
||||||
|
SHA256_DIGEST_SIZE,
|
||||||
|
(void (*)(const uint8_t *, size_t, uint8_t *))sha256_hash,
|
||||||
|
(void (*)(void *))sha256_init,
|
||||||
|
(void (*)(void *, const uint8_t *, size_t))sha256_process,
|
||||||
|
(void (*)(void *, uint8_t *))sha256_done};
|
||||||
|
|
||||||
|
const struct hash_alg scram_sha512 = {
|
||||||
|
"SCRAM-SHA-512",
|
||||||
|
SASL_MASK_SCRAMSHA512,
|
||||||
|
SHA512_DIGEST_SIZE,
|
||||||
|
(void (*)(const uint8_t *, size_t, uint8_t *))sha512_hash,
|
||||||
|
(void (*)(void *))sha512_init,
|
||||||
|
(void (*)(void *, const uint8_t *, size_t))sha512_process,
|
||||||
|
(void (*)(void *, uint8_t *))sha512_done};
|
||||||
|
|
||||||
|
union common_hash_ctx {
|
||||||
|
SHA1_CTX sha1;
|
||||||
|
sha256_context sha256;
|
||||||
|
sha512_context sha512;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void crypto_HMAC(const struct hash_alg *alg,
|
||||||
|
const uint8_t *key,
|
||||||
|
size_t key_len,
|
||||||
|
const uint8_t *text,
|
||||||
|
size_t len,
|
||||||
uint8_t *digest)
|
uint8_t *digest)
|
||||||
{
|
{
|
||||||
uint8_t key_pad[HMAC_BLOCK_SIZE];
|
uint8_t key_pad[HMAC_BLOCK_SIZE_MAX];
|
||||||
uint8_t key_ipad[HMAC_BLOCK_SIZE];
|
uint8_t key_ipad[HMAC_BLOCK_SIZE_MAX];
|
||||||
uint8_t key_opad[HMAC_BLOCK_SIZE];
|
uint8_t key_opad[HMAC_BLOCK_SIZE_MAX];
|
||||||
uint8_t sha_digest[SHA1_DIGEST_SIZE];
|
uint8_t sha_digest[SCRAM_DIGEST_SIZE];
|
||||||
int i;
|
size_t blocksize;
|
||||||
SHA1_CTX ctx;
|
size_t i;
|
||||||
|
union common_hash_ctx ctx;
|
||||||
|
|
||||||
memset(key_pad, 0, sizeof(key_pad));
|
assert(alg->digest_size <= HMAC_BLOCK_SIZE_MAX);
|
||||||
if (key_len <= HMAC_BLOCK_SIZE) {
|
blocksize = alg->digest_size < 48 ? 64 : 128;
|
||||||
|
|
||||||
|
memset(key_pad, 0, blocksize);
|
||||||
|
if (key_len <= blocksize) {
|
||||||
memcpy(key_pad, key, key_len);
|
memcpy(key_pad, key, key_len);
|
||||||
} else {
|
} else {
|
||||||
/* according to RFC2104 */
|
/* according to RFC2104 */
|
||||||
crypto_SHA1(key, key_len, key_pad);
|
alg->hash(key, key_len, key_pad);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < HMAC_BLOCK_SIZE; i++) {
|
for (i = 0; i < blocksize; i++) {
|
||||||
key_ipad[i] = key_pad[i] ^ ipad;
|
key_ipad[i] = key_pad[i] ^ ipad;
|
||||||
key_opad[i] = key_pad[i] ^ opad;
|
key_opad[i] = key_pad[i] ^ opad;
|
||||||
}
|
}
|
||||||
|
|
||||||
crypto_SHA1_Init(&ctx);
|
alg->init((void *)&ctx);
|
||||||
crypto_SHA1_Update(&ctx, key_ipad, HMAC_BLOCK_SIZE);
|
alg->update((void *)&ctx, key_ipad, blocksize);
|
||||||
crypto_SHA1_Update(&ctx, text, len);
|
alg->update((void *)&ctx, text, len);
|
||||||
crypto_SHA1_Final(&ctx, sha_digest);
|
alg->final((void *)&ctx, sha_digest);
|
||||||
|
|
||||||
crypto_SHA1_Init(&ctx);
|
alg->init((void *)&ctx);
|
||||||
crypto_SHA1_Update(&ctx, key_opad, HMAC_BLOCK_SIZE);
|
alg->update((void *)&ctx, key_opad, blocksize);
|
||||||
crypto_SHA1_Update(&ctx, sha_digest, SHA1_DIGEST_SIZE);
|
alg->update((void *)&ctx, sha_digest, alg->digest_size);
|
||||||
crypto_SHA1_Final(&ctx, digest);
|
alg->final((void *)&ctx, digest);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SCRAM_SHA1_Hi(const uint8_t *text, size_t len,
|
static void SCRAM_Hi(const struct hash_alg *alg,
|
||||||
const uint8_t *salt, size_t salt_len, uint32_t i,
|
const uint8_t *text,
|
||||||
|
size_t len,
|
||||||
|
const uint8_t *salt,
|
||||||
|
size_t salt_len,
|
||||||
|
uint32_t i,
|
||||||
uint8_t *digest)
|
uint8_t *digest)
|
||||||
{
|
{
|
||||||
int k;
|
size_t k;
|
||||||
uint32_t j;
|
uint32_t j;
|
||||||
uint8_t tmp[128];
|
uint8_t tmp[128];
|
||||||
|
|
||||||
@@ -77,7 +124,7 @@ static void SCRAM_SHA1_Hi(const uint8_t *text, size_t len,
|
|||||||
/* assume salt + INT(1) isn't longer than sizeof(tmp) */
|
/* assume salt + INT(1) isn't longer than sizeof(tmp) */
|
||||||
assert(salt_len <= sizeof(tmp) - sizeof(int1));
|
assert(salt_len <= sizeof(tmp) - sizeof(int1));
|
||||||
|
|
||||||
memset(digest, 0, SHA1_DIGEST_SIZE);
|
memset(digest, 0, alg->digest_size);
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -86,46 +133,53 @@ static void SCRAM_SHA1_Hi(const uint8_t *text, size_t len,
|
|||||||
memcpy(&tmp[salt_len], int1, sizeof(int1));
|
memcpy(&tmp[salt_len], int1, sizeof(int1));
|
||||||
|
|
||||||
/* 'text' for Hi is a 'key' for HMAC */
|
/* 'text' for Hi is a 'key' for HMAC */
|
||||||
crypto_HMAC_SHA1(text, len, tmp, salt_len + sizeof(int1), digest);
|
crypto_HMAC(alg, text, len, tmp, salt_len + sizeof(int1), digest);
|
||||||
memcpy(tmp, digest, SHA1_DIGEST_SIZE);
|
memcpy(tmp, digest, alg->digest_size);
|
||||||
|
|
||||||
for (j = 1; j < i; j++) {
|
for (j = 1; j < i; j++) {
|
||||||
crypto_HMAC_SHA1(text, len, tmp, SHA1_DIGEST_SIZE, tmp);
|
crypto_HMAC(alg, text, len, tmp, alg->digest_size, tmp);
|
||||||
for (k = 0; k < SHA1_DIGEST_SIZE; k++) {
|
for (k = 0; k < alg->digest_size; k++) {
|
||||||
digest[k] ^= tmp[k];
|
digest[k] ^= tmp[k];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SCRAM_SHA1_ClientKey(const uint8_t *password, size_t len,
|
void SCRAM_ClientKey(const struct hash_alg *alg,
|
||||||
const uint8_t *salt, size_t salt_len, uint32_t i,
|
const uint8_t *password,
|
||||||
|
size_t len,
|
||||||
|
const uint8_t *salt,
|
||||||
|
size_t salt_len,
|
||||||
|
uint32_t i,
|
||||||
uint8_t *key)
|
uint8_t *key)
|
||||||
{
|
{
|
||||||
uint8_t salted[SHA1_DIGEST_SIZE];
|
uint8_t salted[SCRAM_DIGEST_SIZE];
|
||||||
|
|
||||||
/* XXX: Normalize(password) is omitted */
|
/* XXX: Normalize(password) is omitted */
|
||||||
|
|
||||||
SCRAM_SHA1_Hi(password, len, salt, salt_len, i, salted);
|
SCRAM_Hi(alg, password, len, salt, salt_len, i, salted);
|
||||||
crypto_HMAC_SHA1(salted, SHA1_DIGEST_SIZE, (uint8_t *)"Client Key",
|
crypto_HMAC(alg, salted, alg->digest_size, (uint8_t *)"Client Key",
|
||||||
strlen("Client Key"), key);
|
strlen("Client Key"), key);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SCRAM_SHA1_ClientSignature(const uint8_t *ClientKey,
|
void SCRAM_ClientSignature(const struct hash_alg *alg,
|
||||||
const uint8_t *AuthMessage, size_t len,
|
const uint8_t *ClientKey,
|
||||||
|
const uint8_t *AuthMessage,
|
||||||
|
size_t len,
|
||||||
uint8_t *sign)
|
uint8_t *sign)
|
||||||
{
|
{
|
||||||
uint8_t stored[SHA1_DIGEST_SIZE];
|
uint8_t stored[SCRAM_DIGEST_SIZE];
|
||||||
|
|
||||||
crypto_SHA1(ClientKey, SHA1_DIGEST_SIZE, stored);
|
alg->hash(ClientKey, alg->digest_size, stored);
|
||||||
crypto_HMAC_SHA1(stored, SHA1_DIGEST_SIZE, AuthMessage, len, sign);
|
crypto_HMAC(alg, stored, alg->digest_size, AuthMessage, len, sign);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SCRAM_SHA1_ClientProof(const uint8_t *ClientKey,
|
void SCRAM_ClientProof(const struct hash_alg *alg,
|
||||||
|
const uint8_t *ClientKey,
|
||||||
const uint8_t *ClientSignature,
|
const uint8_t *ClientSignature,
|
||||||
uint8_t *proof)
|
uint8_t *proof)
|
||||||
{
|
{
|
||||||
int i;
|
size_t i;
|
||||||
for (i = 0; i < SHA1_DIGEST_SIZE; i++) {
|
for (i = 0; i < alg->digest_size; i++) {
|
||||||
proof[i] = ClientKey[i] ^ ClientSignature[i];
|
proof[i] = ClientKey[i] ^ ClientSignature[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
39
src/scram.h
39
src/scram.h
@@ -1,5 +1,5 @@
|
|||||||
/* scram.h
|
/* scram.h
|
||||||
* strophe XMPP client library -- SCRAM-SHA1 helper functions
|
* strophe XMPP client library -- SCRAM helper functions
|
||||||
*
|
*
|
||||||
* Copyright (C) 2013 Dmitry Podgorny <pasis.ua@gmail.com>
|
* Copyright (C) 2013 Dmitry Podgorny <pasis.ua@gmail.com>
|
||||||
*
|
*
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/** @file
|
/** @file
|
||||||
* SCRAM-SHA1 helper functions.
|
* SCRAM helper functions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __LIBSTROPHE_SCRAM_H__
|
#ifndef __LIBSTROPHE_SCRAM_H__
|
||||||
@@ -19,17 +19,40 @@
|
|||||||
/* make sure the stdint.h types are available */
|
/* make sure the stdint.h types are available */
|
||||||
#include "ostypes.h"
|
#include "ostypes.h"
|
||||||
|
|
||||||
#include "sha1.h"
|
/* Maximum possible digest size. Used for buffers allocation. */
|
||||||
|
#include "sha512.h"
|
||||||
|
#define SCRAM_DIGEST_SIZE SHA512_DIGEST_SIZE
|
||||||
|
|
||||||
void SCRAM_SHA1_ClientKey(const uint8_t *password, size_t len,
|
struct hash_alg {
|
||||||
const uint8_t *salt, size_t salt_len, uint32_t i,
|
const char *scram_name;
|
||||||
|
int mask;
|
||||||
|
size_t digest_size;
|
||||||
|
void (*hash)(const uint8_t *, size_t, uint8_t *);
|
||||||
|
void (*init)(void *);
|
||||||
|
void (*update)(void *, const uint8_t *, size_t);
|
||||||
|
void (*final)(void *, uint8_t *);
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const struct hash_alg scram_sha1;
|
||||||
|
extern const struct hash_alg scram_sha256;
|
||||||
|
extern const struct hash_alg scram_sha512;
|
||||||
|
|
||||||
|
void SCRAM_ClientKey(const struct hash_alg *alg,
|
||||||
|
const uint8_t *password,
|
||||||
|
size_t len,
|
||||||
|
const uint8_t *salt,
|
||||||
|
size_t salt_len,
|
||||||
|
uint32_t i,
|
||||||
uint8_t *key);
|
uint8_t *key);
|
||||||
|
|
||||||
void SCRAM_SHA1_ClientSignature(const uint8_t *ClientKey,
|
void SCRAM_ClientSignature(const struct hash_alg *alg,
|
||||||
const uint8_t *AuthMessage, size_t len,
|
const uint8_t *ClientKey,
|
||||||
|
const uint8_t *AuthMessage,
|
||||||
|
size_t len,
|
||||||
uint8_t *sign);
|
uint8_t *sign);
|
||||||
|
|
||||||
void SCRAM_SHA1_ClientProof(const uint8_t *ClientKey,
|
void SCRAM_ClientProof(const struct hash_alg *alg,
|
||||||
|
const uint8_t *ClientKey,
|
||||||
const uint8_t *ClientSignature,
|
const uint8_t *ClientSignature,
|
||||||
uint8_t *proof);
|
uint8_t *proof);
|
||||||
|
|
||||||
|
|||||||
112
src/sha.h
Normal file
112
src/sha.h
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
/* public api for steve reid's public domain SHA-1 implementation */
|
||||||
|
/* this file is in the public domain */
|
||||||
|
|
||||||
|
/** @file
|
||||||
|
* SHA-1 hash API.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LIBSTROPHE_SHA_H__
|
||||||
|
#define __LIBSTROPHE_SHA_H__
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* make sure the stdint.h types are available */
|
||||||
|
#include "ostypes.h"
|
||||||
|
|
||||||
|
#if defined(__BIG_ENDIAN__) || \
|
||||||
|
(defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && \
|
||||||
|
__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
|
||||||
|
|
||||||
|
#define STORE32H(x, y) \
|
||||||
|
do { \
|
||||||
|
uint32_t __t = (x); \
|
||||||
|
memcpy(y, &__t, 4); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define LOAD32H(x, y) \
|
||||||
|
do { \
|
||||||
|
memcpy(&(x), y, 4); \
|
||||||
|
x &= 0xFFFFFFFF; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define STORE64H(x, y) \
|
||||||
|
do { \
|
||||||
|
uint64_t __t = (x); \
|
||||||
|
memcpy(y, &__t, 8); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define LOAD64H(x, y) \
|
||||||
|
do { \
|
||||||
|
memcpy(&(x), y, 8); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#elif defined(__LITTLE_ENDIAN__) || \
|
||||||
|
(defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \
|
||||||
|
__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
|
||||||
|
|
||||||
|
#define STORE32H(x, y) \
|
||||||
|
do { \
|
||||||
|
(y)[0] = (uint8_t)(((x) >> 24) & 255); \
|
||||||
|
(y)[1] = (uint8_t)(((x) >> 16) & 255); \
|
||||||
|
(y)[2] = (uint8_t)(((x) >> 8) & 255); \
|
||||||
|
(y)[3] = (uint8_t)((x)&255); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define LOAD32H(x, y) \
|
||||||
|
do { \
|
||||||
|
x = ((uint32_t)((y)[0] & 255) << 24) | \
|
||||||
|
((uint32_t)((y)[1] & 255) << 16) | \
|
||||||
|
((uint32_t)((y)[2] & 255) << 8) | ((uint32_t)((y)[3] & 255)); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define STORE64H(x, y) \
|
||||||
|
do { \
|
||||||
|
(y)[0] = (uint8_t)(((x) >> 56) & 255); \
|
||||||
|
(y)[1] = (uint8_t)(((x) >> 48) & 255); \
|
||||||
|
(y)[2] = (uint8_t)(((x) >> 40) & 255); \
|
||||||
|
(y)[3] = (uint8_t)(((x) >> 32) & 255); \
|
||||||
|
(y)[4] = (uint8_t)(((x) >> 24) & 255); \
|
||||||
|
(y)[5] = (uint8_t)(((x) >> 16) & 255); \
|
||||||
|
(y)[6] = (uint8_t)(((x) >> 8) & 255); \
|
||||||
|
(y)[7] = (uint8_t)((x)&255); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define LOAD64H(x, y) \
|
||||||
|
do { \
|
||||||
|
x = (((uint64_t)((y)[0] & 255)) << 56) | \
|
||||||
|
(((uint64_t)((y)[1] & 255)) << 48) | \
|
||||||
|
(((uint64_t)((y)[2] & 255)) << 40) | \
|
||||||
|
(((uint64_t)((y)[3] & 255)) << 32) | \
|
||||||
|
(((uint64_t)((y)[4] & 255)) << 24) | \
|
||||||
|
(((uint64_t)((y)[5] & 255)) << 16) | \
|
||||||
|
(((uint64_t)((y)[6] & 255)) << 8) | (((uint64_t)((y)[7] & 255))); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#else
|
||||||
|
#error Unknown endianness not supported
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#define CONST64(n) n##ui64
|
||||||
|
#else
|
||||||
|
#define CONST64(n) n##ULL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define RORc(x, y) \
|
||||||
|
(((((uint32_t)(x)&0xFFFFFFFFUL) >> (uint32_t)((y)&31)) | \
|
||||||
|
((uint32_t)(x) << (uint32_t)((32 - ((y)&31)) & 31))) & \
|
||||||
|
0xFFFFFFFFUL)
|
||||||
|
#define ROR64c(x, y) \
|
||||||
|
(((((x)&CONST64(0xFFFFFFFFFFFFFFFF)) >> ((uint64_t)(y)&CONST64(63))) | \
|
||||||
|
((x) << (((uint64_t)64 - ((y)&63)) & 63))) & \
|
||||||
|
CONST64(0xFFFFFFFFFFFFFFFF))
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __LIBSTROPHE_SHA_H__ */
|
||||||
88
src/sha1.c
88
src/sha1.c
@@ -75,9 +75,6 @@ move public api to sha1.h
|
|||||||
#include "ostypes.h"
|
#include "ostypes.h"
|
||||||
#include "sha1.h"
|
#include "sha1.h"
|
||||||
|
|
||||||
/* Don't change user's data */
|
|
||||||
#define SHA1HANDSOFF
|
|
||||||
|
|
||||||
static uint32_t host_to_be(uint32_t i);
|
static uint32_t host_to_be(uint32_t i);
|
||||||
static void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64]);
|
static void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64]);
|
||||||
|
|
||||||
@@ -86,16 +83,27 @@ static void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64]);
|
|||||||
/* blk0() and blk() perform the initial expand. */
|
/* blk0() and blk() perform the initial expand. */
|
||||||
/* I got the idea of expanding during the round function from SSLeay */
|
/* I got the idea of expanding during the round function from SSLeay */
|
||||||
#define blk0(i) (block->l[i] = host_to_be(block->l[i]))
|
#define blk0(i) (block->l[i] = host_to_be(block->l[i]))
|
||||||
#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
|
#define blk(i) \
|
||||||
^block->l[(i+2)&15]^block->l[i&15],1))
|
(block->l[i & 15] = rol(block->l[(i + 13) & 15] ^ block->l[(i + 8) & 15] ^ \
|
||||||
|
block->l[(i + 2) & 15] ^ block->l[i & 15], \
|
||||||
|
1))
|
||||||
|
|
||||||
/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
|
/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
|
||||||
#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
|
#define R0(v, w, x, y, z, i) \
|
||||||
#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
|
z += ((w & (x ^ y)) ^ y) + blk0(i) + 0x5A827999 + rol(v, 5); \
|
||||||
#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
|
w = rol(w, 30);
|
||||||
#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
|
#define R1(v, w, x, y, z, i) \
|
||||||
#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
|
z += ((w & (x ^ y)) ^ y) + blk(i) + 0x5A827999 + rol(v, 5); \
|
||||||
|
w = rol(w, 30);
|
||||||
|
#define R2(v, w, x, y, z, i) \
|
||||||
|
z += (w ^ x ^ y) + blk(i) + 0x6ED9EBA1 + rol(v, 5); \
|
||||||
|
w = rol(w, 30);
|
||||||
|
#define R3(v, w, x, y, z, i) \
|
||||||
|
z += (((w | x) & y) | (w & x)) + blk(i) + 0x8F1BBCDC + rol(v, 5); \
|
||||||
|
w = rol(w, 30);
|
||||||
|
#define R4(v, w, x, y, z, i) \
|
||||||
|
z += (w ^ x ^ y) + blk(i) + 0xCA62C1D6 + rol(v, 5); \
|
||||||
|
w = rol(w, 30);
|
||||||
|
|
||||||
static uint32_t host_to_be(uint32_t i)
|
static uint32_t host_to_be(uint32_t i)
|
||||||
{
|
{
|
||||||
@@ -118,6 +126,13 @@ static uint32_t host_to_be(uint32_t i)
|
|||||||
#undef le_to_be
|
#undef le_to_be
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void *(*volatile SHA1_explicit_memset)(void *, int, size_t) = &memset;
|
||||||
|
|
||||||
|
static void SHA1_cleanse(void *p, size_t len)
|
||||||
|
{
|
||||||
|
SHA1_explicit_memset(p, 0, len);
|
||||||
|
}
|
||||||
|
|
||||||
/* Hash a single 512-bit block. This is the core of the algorithm. */
|
/* Hash a single 512-bit block. This is the core of the algorithm. */
|
||||||
static void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64])
|
static void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64])
|
||||||
{
|
{
|
||||||
@@ -128,13 +143,9 @@ static void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64])
|
|||||||
} CHAR64LONG16;
|
} CHAR64LONG16;
|
||||||
CHAR64LONG16 *block;
|
CHAR64LONG16 *block;
|
||||||
|
|
||||||
#ifdef SHA1HANDSOFF
|
|
||||||
static uint8_t workspace[64];
|
static uint8_t workspace[64];
|
||||||
block = (CHAR64LONG16 *)workspace;
|
block = (CHAR64LONG16 *)workspace;
|
||||||
memcpy(block, buffer, 64);
|
memcpy(block, buffer, 64);
|
||||||
#else
|
|
||||||
block = (CHAR64LONG16*)buffer;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Copy context->state[] to working vars */
|
/* Copy context->state[] to working vars */
|
||||||
a = state[0];
|
a = state[0];
|
||||||
@@ -144,6 +155,7 @@ static void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64])
|
|||||||
e = state[4];
|
e = state[4];
|
||||||
|
|
||||||
/* 4 rounds of 20 operations each. Loop unrolled. */
|
/* 4 rounds of 20 operations each. Loop unrolled. */
|
||||||
|
/* clang-format off */
|
||||||
R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
|
R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
|
||||||
R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
|
R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
|
||||||
R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
|
R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
|
||||||
@@ -164,6 +176,7 @@ static void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64])
|
|||||||
R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
|
R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
|
||||||
R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
|
R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
|
||||||
R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
|
R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
|
||||||
|
/* clang-format on */
|
||||||
|
|
||||||
/* Add the working vars back into context.state[] */
|
/* Add the working vars back into context.state[] */
|
||||||
state[0] += a;
|
state[0] += a;
|
||||||
@@ -173,10 +186,13 @@ static void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64])
|
|||||||
state[4] += e;
|
state[4] += e;
|
||||||
|
|
||||||
/* Wipe variables */
|
/* Wipe variables */
|
||||||
a = b = c = d = e = 0;
|
SHA1_cleanse(&a, sizeof(a));
|
||||||
|
SHA1_cleanse(&b, sizeof(b));
|
||||||
|
SHA1_cleanse(&c, sizeof(c));
|
||||||
|
SHA1_cleanse(&d, sizeof(d));
|
||||||
|
SHA1_cleanse(&e, sizeof(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* SHA1Init - Initialize new context */
|
/* SHA1Init - Initialize new context */
|
||||||
void crypto_SHA1_Init(SHA1_CTX *context)
|
void crypto_SHA1_Init(SHA1_CTX *context)
|
||||||
{
|
{
|
||||||
@@ -189,16 +205,17 @@ void crypto_SHA1_Init(SHA1_CTX* context)
|
|||||||
context->count[0] = context->count[1] = 0;
|
context->count[0] = context->count[1] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Run your data through this. */
|
/* Run your data through this. */
|
||||||
void crypto_SHA1_Update(SHA1_CTX* context, const uint8_t* data,
|
void crypto_SHA1_Update(SHA1_CTX *context,
|
||||||
|
const uint8_t *data,
|
||||||
const size_t len)
|
const size_t len)
|
||||||
{
|
{
|
||||||
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);
|
||||||
@@ -206,12 +223,11 @@ void crypto_SHA1_Update(SHA1_CTX* context, const uint8_t* data,
|
|||||||
SHA1_Transform(context->state, data + i);
|
SHA1_Transform(context->state, data + i);
|
||||||
}
|
}
|
||||||
j = 0;
|
j = 0;
|
||||||
}
|
} else
|
||||||
else i = 0;
|
i = 0;
|
||||||
memcpy(&context->buffer[j], &data[i], len - i);
|
memcpy(&context->buffer[j], &data[i], len - i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Add padding and return the message digest. */
|
/* Add padding and return the message digest. */
|
||||||
void crypto_SHA1_Final(SHA1_CTX *context, uint8_t *digest)
|
void crypto_SHA1_Final(SHA1_CTX *context, uint8_t *digest)
|
||||||
{
|
{
|
||||||
@@ -219,32 +235,30 @@ void crypto_SHA1_Final(SHA1_CTX* context, uint8_t* digest)
|
|||||||
uint8_t finalcount[8];
|
uint8_t finalcount[8];
|
||||||
|
|
||||||
for (i = 0; i < 8; i++) {
|
for (i = 0; i < 8; i++) {
|
||||||
finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
|
finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)] >>
|
||||||
>> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */
|
((3 - (i & 3)) * 8)) &
|
||||||
|
255); /* Endian independent */
|
||||||
}
|
}
|
||||||
crypto_SHA1_Update(context, (uint8_t *)"\200", 1);
|
crypto_SHA1_Update(context, (uint8_t *)"\200", 1);
|
||||||
while ((context->count[0] & 504) != 448) {
|
while ((context->count[0] & 504) != 448) {
|
||||||
crypto_SHA1_Update(context, (uint8_t *)"\0", 1);
|
crypto_SHA1_Update(context, (uint8_t *)"\0", 1);
|
||||||
}
|
}
|
||||||
crypto_SHA1_Update(context, finalcount, 8); /* Should cause a SHA1_Transform() */
|
/* Should cause a SHA1_Transform() */
|
||||||
|
crypto_SHA1_Update(context, finalcount, 8);
|
||||||
for (i = 0; i < SHA1_DIGEST_SIZE; i++) {
|
for (i = 0; i < SHA1_DIGEST_SIZE; i++) {
|
||||||
digest[i] = (uint8_t)
|
digest[i] =
|
||||||
((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
|
(uint8_t)((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Wipe variables */
|
/* Wipe variables */
|
||||||
i = 0;
|
SHA1_cleanse(context->buffer, 64);
|
||||||
memset(context->buffer, 0, 64);
|
SHA1_cleanse(context->state, 20);
|
||||||
memset(context->state, 0, 20);
|
SHA1_cleanse(context->count, 8);
|
||||||
memset(context->count, 0, 8);
|
SHA1_cleanse(finalcount, 8); /* SWR */
|
||||||
memset(finalcount, 0, 8); /* SWR */
|
|
||||||
|
|
||||||
#ifdef SHA1HANDSOFF /* make SHA1Transform overwrite its own static vars */
|
|
||||||
SHA1_Transform(context->state, context->buffer);
|
SHA1_Transform(context->state, context->buffer);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void crypto_SHA1(const uint8_t *data, size_t len, uint8_t *digest)
|
void crypto_SHA1(const uint8_t *data, size_t len, uint8_t *digest)
|
||||||
{
|
{
|
||||||
SHA1_CTX ctx;
|
SHA1_CTX ctx;
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ typedef struct {
|
|||||||
#define SHA1_DIGEST_SIZE 20
|
#define SHA1_DIGEST_SIZE 20
|
||||||
|
|
||||||
void crypto_SHA1_Init(SHA1_CTX *context);
|
void crypto_SHA1_Init(SHA1_CTX *context);
|
||||||
void crypto_SHA1_Update(SHA1_CTX* context, const uint8_t* data,
|
void crypto_SHA1_Update(SHA1_CTX *context,
|
||||||
|
const uint8_t *data,
|
||||||
const size_t len);
|
const size_t len);
|
||||||
void crypto_SHA1_Final(SHA1_CTX *context, uint8_t *digest);
|
void crypto_SHA1_Final(SHA1_CTX *context, uint8_t *digest);
|
||||||
void crypto_SHA1(const uint8_t *data, size_t len, uint8_t *digest);
|
void crypto_SHA1(const uint8_t *data, size_t len, uint8_t *digest);
|
||||||
|
|||||||
210
src/sha256.c
Normal file
210
src/sha256.c
Normal file
@@ -0,0 +1,210 @@
|
|||||||
|
/*
|
||||||
|
* Code originally from LibTomCrypt -- Licensed under the Public Domain/WTFPL2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "sha256.h"
|
||||||
|
#include "sha.h"
|
||||||
|
|
||||||
|
/* Various logical functions */
|
||||||
|
#define Ch(x, y, z) (z ^ (x & (y ^ z)))
|
||||||
|
#define Maj(x, y, z) (((x | y) & z) | (x & y))
|
||||||
|
#define S(x, n) RORc((x), (n))
|
||||||
|
#define R(x, n) (((x)&0xFFFFFFFFUL) >> (n))
|
||||||
|
#define Sigma0(x) (S(x, 2) ^ S(x, 13) ^ S(x, 22))
|
||||||
|
#define Sigma1(x) (S(x, 6) ^ S(x, 11) ^ S(x, 25))
|
||||||
|
#define Gamma0(x) (S(x, 7) ^ S(x, 18) ^ R(x, 3))
|
||||||
|
#define Gamma1(x) (S(x, 17) ^ S(x, 19) ^ R(x, 10))
|
||||||
|
|
||||||
|
static void sha256_compress(sha256_context *md, const uint8_t *buf)
|
||||||
|
{
|
||||||
|
uint32_t S[8], W[64], t0, t1;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* copy state into S */
|
||||||
|
for (i = 0; i < 8; i++) {
|
||||||
|
S[i] = md->state[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* copy the state into 512-bits into W[0..15] */
|
||||||
|
for (i = 0; i < 16; i++) {
|
||||||
|
LOAD32H(W[i], buf + (4 * i));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fill W[16..63] */
|
||||||
|
for (i = 16; i < 64; i++) {
|
||||||
|
W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compress */
|
||||||
|
#define RND(a, b, c, d, e, f, g, h, i, ki) \
|
||||||
|
t0 = h + Sigma1(e) + Ch(e, f, g) + ki + W[i]; \
|
||||||
|
t1 = Sigma0(a) + Maj(a, b, c); \
|
||||||
|
d += t0; \
|
||||||
|
h = t0 + t1;
|
||||||
|
|
||||||
|
RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], 0, 0x428a2f98);
|
||||||
|
RND(S[7], S[0], S[1], S[2], S[3], S[4], S[5], S[6], 1, 0x71374491);
|
||||||
|
RND(S[6], S[7], S[0], S[1], S[2], S[3], S[4], S[5], 2, 0xb5c0fbcf);
|
||||||
|
RND(S[5], S[6], S[7], S[0], S[1], S[2], S[3], S[4], 3, 0xe9b5dba5);
|
||||||
|
RND(S[4], S[5], S[6], S[7], S[0], S[1], S[2], S[3], 4, 0x3956c25b);
|
||||||
|
RND(S[3], S[4], S[5], S[6], S[7], S[0], S[1], S[2], 5, 0x59f111f1);
|
||||||
|
RND(S[2], S[3], S[4], S[5], S[6], S[7], S[0], S[1], 6, 0x923f82a4);
|
||||||
|
RND(S[1], S[2], S[3], S[4], S[5], S[6], S[7], S[0], 7, 0xab1c5ed5);
|
||||||
|
RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], 8, 0xd807aa98);
|
||||||
|
RND(S[7], S[0], S[1], S[2], S[3], S[4], S[5], S[6], 9, 0x12835b01);
|
||||||
|
RND(S[6], S[7], S[0], S[1], S[2], S[3], S[4], S[5], 10, 0x243185be);
|
||||||
|
RND(S[5], S[6], S[7], S[0], S[1], S[2], S[3], S[4], 11, 0x550c7dc3);
|
||||||
|
RND(S[4], S[5], S[6], S[7], S[0], S[1], S[2], S[3], 12, 0x72be5d74);
|
||||||
|
RND(S[3], S[4], S[5], S[6], S[7], S[0], S[1], S[2], 13, 0x80deb1fe);
|
||||||
|
RND(S[2], S[3], S[4], S[5], S[6], S[7], S[0], S[1], 14, 0x9bdc06a7);
|
||||||
|
RND(S[1], S[2], S[3], S[4], S[5], S[6], S[7], S[0], 15, 0xc19bf174);
|
||||||
|
RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], 16, 0xe49b69c1);
|
||||||
|
RND(S[7], S[0], S[1], S[2], S[3], S[4], S[5], S[6], 17, 0xefbe4786);
|
||||||
|
RND(S[6], S[7], S[0], S[1], S[2], S[3], S[4], S[5], 18, 0x0fc19dc6);
|
||||||
|
RND(S[5], S[6], S[7], S[0], S[1], S[2], S[3], S[4], 19, 0x240ca1cc);
|
||||||
|
RND(S[4], S[5], S[6], S[7], S[0], S[1], S[2], S[3], 20, 0x2de92c6f);
|
||||||
|
RND(S[3], S[4], S[5], S[6], S[7], S[0], S[1], S[2], 21, 0x4a7484aa);
|
||||||
|
RND(S[2], S[3], S[4], S[5], S[6], S[7], S[0], S[1], 22, 0x5cb0a9dc);
|
||||||
|
RND(S[1], S[2], S[3], S[4], S[5], S[6], S[7], S[0], 23, 0x76f988da);
|
||||||
|
RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], 24, 0x983e5152);
|
||||||
|
RND(S[7], S[0], S[1], S[2], S[3], S[4], S[5], S[6], 25, 0xa831c66d);
|
||||||
|
RND(S[6], S[7], S[0], S[1], S[2], S[3], S[4], S[5], 26, 0xb00327c8);
|
||||||
|
RND(S[5], S[6], S[7], S[0], S[1], S[2], S[3], S[4], 27, 0xbf597fc7);
|
||||||
|
RND(S[4], S[5], S[6], S[7], S[0], S[1], S[2], S[3], 28, 0xc6e00bf3);
|
||||||
|
RND(S[3], S[4], S[5], S[6], S[7], S[0], S[1], S[2], 29, 0xd5a79147);
|
||||||
|
RND(S[2], S[3], S[4], S[5], S[6], S[7], S[0], S[1], 30, 0x06ca6351);
|
||||||
|
RND(S[1], S[2], S[3], S[4], S[5], S[6], S[7], S[0], 31, 0x14292967);
|
||||||
|
RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], 32, 0x27b70a85);
|
||||||
|
RND(S[7], S[0], S[1], S[2], S[3], S[4], S[5], S[6], 33, 0x2e1b2138);
|
||||||
|
RND(S[6], S[7], S[0], S[1], S[2], S[3], S[4], S[5], 34, 0x4d2c6dfc);
|
||||||
|
RND(S[5], S[6], S[7], S[0], S[1], S[2], S[3], S[4], 35, 0x53380d13);
|
||||||
|
RND(S[4], S[5], S[6], S[7], S[0], S[1], S[2], S[3], 36, 0x650a7354);
|
||||||
|
RND(S[3], S[4], S[5], S[6], S[7], S[0], S[1], S[2], 37, 0x766a0abb);
|
||||||
|
RND(S[2], S[3], S[4], S[5], S[6], S[7], S[0], S[1], 38, 0x81c2c92e);
|
||||||
|
RND(S[1], S[2], S[3], S[4], S[5], S[6], S[7], S[0], 39, 0x92722c85);
|
||||||
|
RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], 40, 0xa2bfe8a1);
|
||||||
|
RND(S[7], S[0], S[1], S[2], S[3], S[4], S[5], S[6], 41, 0xa81a664b);
|
||||||
|
RND(S[6], S[7], S[0], S[1], S[2], S[3], S[4], S[5], 42, 0xc24b8b70);
|
||||||
|
RND(S[5], S[6], S[7], S[0], S[1], S[2], S[3], S[4], 43, 0xc76c51a3);
|
||||||
|
RND(S[4], S[5], S[6], S[7], S[0], S[1], S[2], S[3], 44, 0xd192e819);
|
||||||
|
RND(S[3], S[4], S[5], S[6], S[7], S[0], S[1], S[2], 45, 0xd6990624);
|
||||||
|
RND(S[2], S[3], S[4], S[5], S[6], S[7], S[0], S[1], 46, 0xf40e3585);
|
||||||
|
RND(S[1], S[2], S[3], S[4], S[5], S[6], S[7], S[0], 47, 0x106aa070);
|
||||||
|
RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], 48, 0x19a4c116);
|
||||||
|
RND(S[7], S[0], S[1], S[2], S[3], S[4], S[5], S[6], 49, 0x1e376c08);
|
||||||
|
RND(S[6], S[7], S[0], S[1], S[2], S[3], S[4], S[5], 50, 0x2748774c);
|
||||||
|
RND(S[5], S[6], S[7], S[0], S[1], S[2], S[3], S[4], 51, 0x34b0bcb5);
|
||||||
|
RND(S[4], S[5], S[6], S[7], S[0], S[1], S[2], S[3], 52, 0x391c0cb3);
|
||||||
|
RND(S[3], S[4], S[5], S[6], S[7], S[0], S[1], S[2], 53, 0x4ed8aa4a);
|
||||||
|
RND(S[2], S[3], S[4], S[5], S[6], S[7], S[0], S[1], 54, 0x5b9cca4f);
|
||||||
|
RND(S[1], S[2], S[3], S[4], S[5], S[6], S[7], S[0], 55, 0x682e6ff3);
|
||||||
|
RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], 56, 0x748f82ee);
|
||||||
|
RND(S[7], S[0], S[1], S[2], S[3], S[4], S[5], S[6], 57, 0x78a5636f);
|
||||||
|
RND(S[6], S[7], S[0], S[1], S[2], S[3], S[4], S[5], 58, 0x84c87814);
|
||||||
|
RND(S[5], S[6], S[7], S[0], S[1], S[2], S[3], S[4], 59, 0x8cc70208);
|
||||||
|
RND(S[4], S[5], S[6], S[7], S[0], S[1], S[2], S[3], 60, 0x90befffa);
|
||||||
|
RND(S[3], S[4], S[5], S[6], S[7], S[0], S[1], S[2], 61, 0xa4506ceb);
|
||||||
|
RND(S[2], S[3], S[4], S[5], S[6], S[7], S[0], S[1], 62, 0xbef9a3f7);
|
||||||
|
RND(S[1], S[2], S[3], S[4], S[5], S[6], S[7], S[0], 63, 0xc67178f2);
|
||||||
|
|
||||||
|
#undef RND
|
||||||
|
|
||||||
|
/* feedback */
|
||||||
|
for (i = 0; i < 8; i++) {
|
||||||
|
md->state[i] = md->state[i] + S[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void sha256_init(sha256_context *md)
|
||||||
|
{
|
||||||
|
md->curlen = 0;
|
||||||
|
md->length = 0;
|
||||||
|
md->state[0] = 0x6A09E667UL;
|
||||||
|
md->state[1] = 0xBB67AE85UL;
|
||||||
|
md->state[2] = 0x3C6EF372UL;
|
||||||
|
md->state[3] = 0xA54FF53AUL;
|
||||||
|
md->state[4] = 0x510E527FUL;
|
||||||
|
md->state[5] = 0x9B05688CUL;
|
||||||
|
md->state[6] = 0x1F83D9ABUL;
|
||||||
|
md->state[7] = 0x5BE0CD19UL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sha256_process(sha256_context *md, const uint8_t *in, size_t inlen)
|
||||||
|
{
|
||||||
|
size_t n;
|
||||||
|
if (md->curlen > sizeof(md->buf)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ((md->length + inlen) < md->length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
while (inlen > 0) {
|
||||||
|
if (md->curlen == 0 && inlen >= 64) {
|
||||||
|
sha256_compress(md, in);
|
||||||
|
md->length += 64 * 8;
|
||||||
|
in += 64;
|
||||||
|
inlen -= 64;
|
||||||
|
} else {
|
||||||
|
n = (((inlen) < ((64 - md->curlen))) ? (inlen)
|
||||||
|
: ((64 - md->curlen)));
|
||||||
|
memcpy(md->buf + md->curlen, in, (size_t)n);
|
||||||
|
md->curlen += n;
|
||||||
|
in += n;
|
||||||
|
inlen -= n;
|
||||||
|
if (md->curlen == 64) {
|
||||||
|
sha256_compress(md, md->buf);
|
||||||
|
md->length += 8 * 64;
|
||||||
|
md->curlen = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void sha256_done(sha256_context *md, uint8_t *out)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (md->curlen >= sizeof(md->buf)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* increase the length of the message */
|
||||||
|
md->length += md->curlen * 8;
|
||||||
|
|
||||||
|
/* append the '1' bit */
|
||||||
|
md->buf[md->curlen++] = (uint8_t)0x80;
|
||||||
|
|
||||||
|
/* if the length is currently above 56 bytes we append zeros
|
||||||
|
* then compress. Then we can fall back to padding zeros and length
|
||||||
|
* encoding like normal.
|
||||||
|
*/
|
||||||
|
if (md->curlen > 56) {
|
||||||
|
while (md->curlen < 64) {
|
||||||
|
md->buf[md->curlen++] = (uint8_t)0;
|
||||||
|
}
|
||||||
|
sha256_compress(md, md->buf);
|
||||||
|
md->curlen = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* pad upto 56 bytes of zeroes */
|
||||||
|
while (md->curlen < 56) {
|
||||||
|
md->buf[md->curlen++] = (uint8_t)0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* store length */
|
||||||
|
STORE64H(md->length, md->buf + 56);
|
||||||
|
sha256_compress(md, md->buf);
|
||||||
|
|
||||||
|
/* copy output */
|
||||||
|
for (i = 0; i < 8; i++) {
|
||||||
|
STORE32H(md->state[i], out + (4 * i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void sha256_hash(const uint8_t *data, size_t len, uint8_t *digest)
|
||||||
|
{
|
||||||
|
sha256_context md;
|
||||||
|
sha256_init(&md);
|
||||||
|
sha256_process(&md, data, len);
|
||||||
|
sha256_done(&md, digest);
|
||||||
|
}
|
||||||
34
src/sha256.h
Normal file
34
src/sha256.h
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
/* public api for LibTomCrypt SHA-256 implementation */
|
||||||
|
|
||||||
|
/** @file
|
||||||
|
* SHA-256 hash API.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LIBSTROPHE_SHA256_H__
|
||||||
|
#define __LIBSTROPHE_SHA256_H__
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* make sure the stdint.h types are available */
|
||||||
|
#include "ostypes.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint64_t length;
|
||||||
|
uint32_t state[8], curlen;
|
||||||
|
uint8_t buf[64];
|
||||||
|
} sha256_context;
|
||||||
|
|
||||||
|
#define SHA256_DIGEST_SIZE 32
|
||||||
|
|
||||||
|
void sha256_init(sha256_context *md);
|
||||||
|
void sha256_process(sha256_context *md, const uint8_t *in, size_t inlen);
|
||||||
|
void sha256_done(sha256_context *md, uint8_t *out);
|
||||||
|
|
||||||
|
void sha256_hash(const uint8_t *data, size_t len, uint8_t *digest);
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __LIBSTROPHE_SHA256_H__ */
|
||||||
201
src/sha512.c
Normal file
201
src/sha512.c
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
/*
|
||||||
|
* Code originally from LibTomCrypt -- Licensed under the Public Domain/WTFPL2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "sha512.h"
|
||||||
|
#include "sha.h"
|
||||||
|
|
||||||
|
/* the K array */
|
||||||
|
static const uint64_t K[80] = {
|
||||||
|
CONST64(0x428a2f98d728ae22), CONST64(0x7137449123ef65cd),
|
||||||
|
CONST64(0xb5c0fbcfec4d3b2f), CONST64(0xe9b5dba58189dbbc),
|
||||||
|
CONST64(0x3956c25bf348b538), CONST64(0x59f111f1b605d019),
|
||||||
|
CONST64(0x923f82a4af194f9b), CONST64(0xab1c5ed5da6d8118),
|
||||||
|
CONST64(0xd807aa98a3030242), CONST64(0x12835b0145706fbe),
|
||||||
|
CONST64(0x243185be4ee4b28c), CONST64(0x550c7dc3d5ffb4e2),
|
||||||
|
CONST64(0x72be5d74f27b896f), CONST64(0x80deb1fe3b1696b1),
|
||||||
|
CONST64(0x9bdc06a725c71235), CONST64(0xc19bf174cf692694),
|
||||||
|
CONST64(0xe49b69c19ef14ad2), CONST64(0xefbe4786384f25e3),
|
||||||
|
CONST64(0x0fc19dc68b8cd5b5), CONST64(0x240ca1cc77ac9c65),
|
||||||
|
CONST64(0x2de92c6f592b0275), CONST64(0x4a7484aa6ea6e483),
|
||||||
|
CONST64(0x5cb0a9dcbd41fbd4), CONST64(0x76f988da831153b5),
|
||||||
|
CONST64(0x983e5152ee66dfab), CONST64(0xa831c66d2db43210),
|
||||||
|
CONST64(0xb00327c898fb213f), CONST64(0xbf597fc7beef0ee4),
|
||||||
|
CONST64(0xc6e00bf33da88fc2), CONST64(0xd5a79147930aa725),
|
||||||
|
CONST64(0x06ca6351e003826f), CONST64(0x142929670a0e6e70),
|
||||||
|
CONST64(0x27b70a8546d22ffc), CONST64(0x2e1b21385c26c926),
|
||||||
|
CONST64(0x4d2c6dfc5ac42aed), CONST64(0x53380d139d95b3df),
|
||||||
|
CONST64(0x650a73548baf63de), CONST64(0x766a0abb3c77b2a8),
|
||||||
|
CONST64(0x81c2c92e47edaee6), CONST64(0x92722c851482353b),
|
||||||
|
CONST64(0xa2bfe8a14cf10364), CONST64(0xa81a664bbc423001),
|
||||||
|
CONST64(0xc24b8b70d0f89791), CONST64(0xc76c51a30654be30),
|
||||||
|
CONST64(0xd192e819d6ef5218), CONST64(0xd69906245565a910),
|
||||||
|
CONST64(0xf40e35855771202a), CONST64(0x106aa07032bbd1b8),
|
||||||
|
CONST64(0x19a4c116b8d2d0c8), CONST64(0x1e376c085141ab53),
|
||||||
|
CONST64(0x2748774cdf8eeb99), CONST64(0x34b0bcb5e19b48a8),
|
||||||
|
CONST64(0x391c0cb3c5c95a63), CONST64(0x4ed8aa4ae3418acb),
|
||||||
|
CONST64(0x5b9cca4f7763e373), CONST64(0x682e6ff3d6b2b8a3),
|
||||||
|
CONST64(0x748f82ee5defb2fc), CONST64(0x78a5636f43172f60),
|
||||||
|
CONST64(0x84c87814a1f0ab72), CONST64(0x8cc702081a6439ec),
|
||||||
|
CONST64(0x90befffa23631e28), CONST64(0xa4506cebde82bde9),
|
||||||
|
CONST64(0xbef9a3f7b2c67915), CONST64(0xc67178f2e372532b),
|
||||||
|
CONST64(0xca273eceea26619c), CONST64(0xd186b8c721c0c207),
|
||||||
|
CONST64(0xeada7dd6cde0eb1e), CONST64(0xf57d4f7fee6ed178),
|
||||||
|
CONST64(0x06f067aa72176fba), CONST64(0x0a637dc5a2c898a6),
|
||||||
|
CONST64(0x113f9804bef90dae), CONST64(0x1b710b35131c471b),
|
||||||
|
CONST64(0x28db77f523047d84), CONST64(0x32caab7b40c72493),
|
||||||
|
CONST64(0x3c9ebe0a15c9bebc), CONST64(0x431d67c49c100d4c),
|
||||||
|
CONST64(0x4cc5d4becb3e42b6), CONST64(0x597f299cfc657e2a),
|
||||||
|
CONST64(0x5fcb6fab3ad6faec), CONST64(0x6c44198c4a475817)};
|
||||||
|
|
||||||
|
/* Various logical functions */
|
||||||
|
#define Ch(x, y, z) (z ^ (x & (y ^ z)))
|
||||||
|
#define Maj(x, y, z) (((x | y) & z) | (x & y))
|
||||||
|
#define S(x, n) ROR64c(x, n)
|
||||||
|
#define R(x, n) (((x)&CONST64(0xFFFFFFFFFFFFFFFF)) >> ((uint64_t)n))
|
||||||
|
#define Sigma0(x) (S(x, 28) ^ S(x, 34) ^ S(x, 39))
|
||||||
|
#define Sigma1(x) (S(x, 14) ^ S(x, 18) ^ S(x, 41))
|
||||||
|
#define Gamma0(x) (S(x, 1) ^ S(x, 8) ^ R(x, 7))
|
||||||
|
#define Gamma1(x) (S(x, 19) ^ S(x, 61) ^ R(x, 6))
|
||||||
|
|
||||||
|
/* compress 1024-bits */
|
||||||
|
static void sha512_compress(sha512_context *md, const uint8_t *buf)
|
||||||
|
{
|
||||||
|
uint64_t S[8], W[80], t0, t1;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* copy state into S */
|
||||||
|
for (i = 0; i < 8; i++) {
|
||||||
|
S[i] = md->state[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* copy the state into 1024-bits into W[0..15] */
|
||||||
|
for (i = 0; i < 16; i++) {
|
||||||
|
LOAD64H(W[i], buf + (8 * i));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fill W[16..79] */
|
||||||
|
for (i = 16; i < 80; i++) {
|
||||||
|
W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compress */
|
||||||
|
#define RND(a, b, c, d, e, f, g, h, i) \
|
||||||
|
t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \
|
||||||
|
t1 = Sigma0(a) + Maj(a, b, c); \
|
||||||
|
d += t0; \
|
||||||
|
h = t0 + t1;
|
||||||
|
|
||||||
|
for (i = 0; i < 80; i += 8) {
|
||||||
|
RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], i + 0);
|
||||||
|
RND(S[7], S[0], S[1], S[2], S[3], S[4], S[5], S[6], i + 1);
|
||||||
|
RND(S[6], S[7], S[0], S[1], S[2], S[3], S[4], S[5], i + 2);
|
||||||
|
RND(S[5], S[6], S[7], S[0], S[1], S[2], S[3], S[4], i + 3);
|
||||||
|
RND(S[4], S[5], S[6], S[7], S[0], S[1], S[2], S[3], i + 4);
|
||||||
|
RND(S[3], S[4], S[5], S[6], S[7], S[0], S[1], S[2], i + 5);
|
||||||
|
RND(S[2], S[3], S[4], S[5], S[6], S[7], S[0], S[1], i + 6);
|
||||||
|
RND(S[1], S[2], S[3], S[4], S[5], S[6], S[7], S[0], i + 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* feedback */
|
||||||
|
for (i = 0; i < 8; i++) {
|
||||||
|
md->state[i] = md->state[i] + S[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void sha512_init(sha512_context *md)
|
||||||
|
{
|
||||||
|
md->curlen = 0;
|
||||||
|
md->length = 0;
|
||||||
|
md->state[0] = CONST64(0x6a09e667f3bcc908);
|
||||||
|
md->state[1] = CONST64(0xbb67ae8584caa73b);
|
||||||
|
md->state[2] = CONST64(0x3c6ef372fe94f82b);
|
||||||
|
md->state[3] = CONST64(0xa54ff53a5f1d36f1);
|
||||||
|
md->state[4] = CONST64(0x510e527fade682d1);
|
||||||
|
md->state[5] = CONST64(0x9b05688c2b3e6c1f);
|
||||||
|
md->state[6] = CONST64(0x1f83d9abfb41bd6b);
|
||||||
|
md->state[7] = CONST64(0x5be0cd19137e2179);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sha512_process(sha512_context *md, const uint8_t *in, size_t inlen)
|
||||||
|
{
|
||||||
|
size_t n;
|
||||||
|
if (md->curlen > sizeof(md->buf)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ((md->length + inlen) < md->length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
while (inlen > 0) {
|
||||||
|
if (md->curlen == 0 && inlen >= 128) {
|
||||||
|
sha512_compress(md, in);
|
||||||
|
md->length += 128 * 8;
|
||||||
|
in += 128;
|
||||||
|
inlen -= 128;
|
||||||
|
} else {
|
||||||
|
n = (((inlen) < ((128u - md->curlen))) ? (inlen)
|
||||||
|
: ((128u - md->curlen)));
|
||||||
|
memcpy(md->buf + md->curlen, in, (size_t)n);
|
||||||
|
md->curlen += n;
|
||||||
|
in += n;
|
||||||
|
inlen -= n;
|
||||||
|
if (md->curlen == 128) {
|
||||||
|
sha512_compress(md, md->buf);
|
||||||
|
md->length += 8 * 128;
|
||||||
|
md->curlen = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void sha512_done(sha512_context *md, uint8_t *out)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (md->curlen >= sizeof(md->buf)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* increase the length of the message */
|
||||||
|
md->length += md->curlen * CONST64(8);
|
||||||
|
|
||||||
|
/* append the '1' bit */
|
||||||
|
md->buf[md->curlen++] = (uint8_t)0x80;
|
||||||
|
|
||||||
|
/* if the length is currently above 112 bytes we append zeros
|
||||||
|
* then compress. Then we can fall back to padding zeros and length
|
||||||
|
* encoding like normal.
|
||||||
|
*/
|
||||||
|
if (md->curlen > 112) {
|
||||||
|
while (md->curlen < 128) {
|
||||||
|
md->buf[md->curlen++] = (uint8_t)0;
|
||||||
|
}
|
||||||
|
sha512_compress(md, md->buf);
|
||||||
|
md->curlen = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* pad upto 120 bytes of zeroes
|
||||||
|
* note: that from 112 to 120 is the 64 MSB of the length. We assume that
|
||||||
|
* you won't hash > 2^64 bits of data... :-)
|
||||||
|
*/
|
||||||
|
while (md->curlen < 120) {
|
||||||
|
md->buf[md->curlen++] = (uint8_t)0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* store length */
|
||||||
|
STORE64H(md->length, md->buf + 120);
|
||||||
|
sha512_compress(md, md->buf);
|
||||||
|
|
||||||
|
/* copy output */
|
||||||
|
for (i = 0; i < 8; i++) {
|
||||||
|
STORE64H(md->state[i], out + (8 * i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void sha512_hash(const uint8_t *data, size_t len, uint8_t *digest)
|
||||||
|
{
|
||||||
|
sha512_context md;
|
||||||
|
sha512_init(&md);
|
||||||
|
sha512_process(&md, data, len);
|
||||||
|
sha512_done(&md, digest);
|
||||||
|
}
|
||||||
34
src/sha512.h
Normal file
34
src/sha512.h
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
/* public api for LibTomCrypt SHA-512 implementation */
|
||||||
|
|
||||||
|
/** @file
|
||||||
|
* SHA-512 hash API.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LIBSTROPHE_SHA512_H__
|
||||||
|
#define __LIBSTROPHE_SHA512_H__
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* make sure the stdint.h types are available */
|
||||||
|
#include "ostypes.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint64_t length, state[8];
|
||||||
|
uint8_t curlen;
|
||||||
|
uint8_t buf[128];
|
||||||
|
} sha512_context;
|
||||||
|
|
||||||
|
#define SHA512_DIGEST_SIZE 64
|
||||||
|
|
||||||
|
void sha512_init(sha512_context *cc);
|
||||||
|
void sha512_process(sha512_context *cc, const uint8_t *data, size_t len);
|
||||||
|
void sha512_done(sha512_context *cc, uint8_t *dst);
|
||||||
|
|
||||||
|
void sha512_hash(const uint8_t *data, size_t len, uint8_t *digest);
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __LIBSTROPHE_SHA512_H__ */
|
||||||
235
src/snprintf.c
235
src/snprintf.c
@@ -85,14 +85,29 @@
|
|||||||
#define LDOUBLE double
|
#define LDOUBLE double
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int dopr (char *buffer, size_t maxlen, const char *format,
|
static int dopr(char *buffer, size_t maxlen, const char *format, va_list args);
|
||||||
va_list args);
|
static int fmtstr(char *buffer,
|
||||||
static int fmtstr (char *buffer, size_t *currlen, size_t maxlen,
|
size_t *currlen,
|
||||||
char *value, int flags, int min, int max);
|
size_t maxlen,
|
||||||
static int fmtint (char *buffer, size_t *currlen, size_t maxlen,
|
char *value,
|
||||||
long value, int base, int min, int max, int flags);
|
int flags,
|
||||||
static int fmtfp (char *buffer, size_t *currlen, size_t maxlen,
|
int min,
|
||||||
LDOUBLE fvalue, int min, int max, int flags);
|
int max);
|
||||||
|
static int fmtint(char *buffer,
|
||||||
|
size_t *currlen,
|
||||||
|
size_t maxlen,
|
||||||
|
long value,
|
||||||
|
int base,
|
||||||
|
int min,
|
||||||
|
int max,
|
||||||
|
int flags);
|
||||||
|
static int fmtfp(char *buffer,
|
||||||
|
size_t *currlen,
|
||||||
|
size_t maxlen,
|
||||||
|
LDOUBLE fvalue,
|
||||||
|
int min,
|
||||||
|
int max,
|
||||||
|
int flags);
|
||||||
static int dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c);
|
static int dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -147,13 +162,11 @@ static int dopr (char *buffer, size_t maxlen, const char *format, va_list args)
|
|||||||
ch = *format++;
|
ch = *format++;
|
||||||
total = 0;
|
total = 0;
|
||||||
|
|
||||||
while (state != DP_S_DONE)
|
while (state != DP_S_DONE) {
|
||||||
{
|
|
||||||
if (ch == '\0')
|
if (ch == '\0')
|
||||||
state = DP_S_DONE;
|
state = DP_S_DONE;
|
||||||
|
|
||||||
switch(state)
|
switch (state) {
|
||||||
{
|
|
||||||
case DP_S_DEFAULT:
|
case DP_S_DEFAULT:
|
||||||
if (ch == '%')
|
if (ch == '%')
|
||||||
state = DP_S_FLAGS;
|
state = DP_S_FLAGS;
|
||||||
@@ -162,8 +175,7 @@ static int dopr (char *buffer, size_t maxlen, const char *format, va_list args)
|
|||||||
ch = *format++;
|
ch = *format++;
|
||||||
break;
|
break;
|
||||||
case DP_S_FLAGS:
|
case DP_S_FLAGS:
|
||||||
switch (ch)
|
switch (ch) {
|
||||||
{
|
|
||||||
case '-':
|
case '-':
|
||||||
flags |= DP_F_MINUS;
|
flags |= DP_F_MINUS;
|
||||||
ch = *format++;
|
ch = *format++;
|
||||||
@@ -190,50 +202,39 @@ static int dopr (char *buffer, size_t maxlen, const char *format, va_list args)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case DP_S_MIN:
|
case DP_S_MIN:
|
||||||
if (isdigit(ch))
|
if (isdigit(ch)) {
|
||||||
{
|
|
||||||
min = 10 * min + char_to_int(ch);
|
min = 10 * min + char_to_int(ch);
|
||||||
ch = *format++;
|
ch = *format++;
|
||||||
}
|
} else if (ch == '*') {
|
||||||
else if (ch == '*')
|
|
||||||
{
|
|
||||||
min = va_arg(args, int);
|
min = va_arg(args, int);
|
||||||
ch = *format++;
|
ch = *format++;
|
||||||
state = DP_S_DOT;
|
state = DP_S_DOT;
|
||||||
}
|
} else
|
||||||
else
|
|
||||||
state = DP_S_DOT;
|
state = DP_S_DOT;
|
||||||
break;
|
break;
|
||||||
case DP_S_DOT:
|
case DP_S_DOT:
|
||||||
if (ch == '.')
|
if (ch == '.') {
|
||||||
{
|
|
||||||
state = DP_S_MAX;
|
state = DP_S_MAX;
|
||||||
ch = *format++;
|
ch = *format++;
|
||||||
}
|
} else
|
||||||
else
|
|
||||||
state = DP_S_MOD;
|
state = DP_S_MOD;
|
||||||
break;
|
break;
|
||||||
case DP_S_MAX:
|
case DP_S_MAX:
|
||||||
if (isdigit(ch))
|
if (isdigit(ch)) {
|
||||||
{
|
|
||||||
if (max < 0)
|
if (max < 0)
|
||||||
max = 0;
|
max = 0;
|
||||||
max = 10 * max + char_to_int(ch);
|
max = 10 * max + char_to_int(ch);
|
||||||
ch = *format++;
|
ch = *format++;
|
||||||
}
|
} else if (ch == '*') {
|
||||||
else if (ch == '*')
|
|
||||||
{
|
|
||||||
max = va_arg(args, int);
|
max = va_arg(args, int);
|
||||||
ch = *format++;
|
ch = *format++;
|
||||||
state = DP_S_MOD;
|
state = DP_S_MOD;
|
||||||
}
|
} else
|
||||||
else
|
|
||||||
state = DP_S_MOD;
|
state = DP_S_MOD;
|
||||||
break;
|
break;
|
||||||
case DP_S_MOD:
|
case DP_S_MOD:
|
||||||
/* Currently, we don't support Long Long, bummer */
|
/* Currently, we don't support Long Long, bummer */
|
||||||
switch (ch)
|
switch (ch) {
|
||||||
{
|
|
||||||
case 'h':
|
case 'h':
|
||||||
cflags = DP_C_SHORT;
|
cflags = DP_C_SHORT;
|
||||||
ch = *format++;
|
ch = *format++;
|
||||||
@@ -252,8 +253,7 @@ static int dopr (char *buffer, size_t maxlen, const char *format, va_list args)
|
|||||||
state = DP_S_CONV;
|
state = DP_S_CONV;
|
||||||
break;
|
break;
|
||||||
case DP_S_CONV:
|
case DP_S_CONV:
|
||||||
switch (ch)
|
switch (ch) {
|
||||||
{
|
|
||||||
case 'd':
|
case 'd':
|
||||||
case 'i':
|
case 'i':
|
||||||
if (cflags == DP_C_SHORT)
|
if (cflags == DP_C_SHORT)
|
||||||
@@ -262,7 +262,8 @@ static int dopr (char *buffer, size_t maxlen, const char *format, va_list args)
|
|||||||
value = va_arg(args, long int);
|
value = va_arg(args, long int);
|
||||||
else
|
else
|
||||||
value = va_arg(args, int);
|
value = va_arg(args, int);
|
||||||
total += fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
|
total += fmtint(buffer, &currlen, maxlen, value, 10, min, max,
|
||||||
|
flags);
|
||||||
break;
|
break;
|
||||||
case 'o':
|
case 'o':
|
||||||
flags |= DP_F_UNSIGNED;
|
flags |= DP_F_UNSIGNED;
|
||||||
@@ -272,7 +273,8 @@ static int dopr (char *buffer, size_t maxlen, const char *format, va_list args)
|
|||||||
value = va_arg(args, unsigned long int);
|
value = va_arg(args, unsigned long int);
|
||||||
else
|
else
|
||||||
value = va_arg(args, unsigned int);
|
value = va_arg(args, unsigned int);
|
||||||
total += fmtint (buffer, &currlen, maxlen, value, 8, min, max, flags);
|
total +=
|
||||||
|
fmtint(buffer, &currlen, maxlen, value, 8, min, max, flags);
|
||||||
break;
|
break;
|
||||||
case 'u':
|
case 'u':
|
||||||
flags |= DP_F_UNSIGNED;
|
flags |= DP_F_UNSIGNED;
|
||||||
@@ -282,10 +284,12 @@ static int dopr (char *buffer, size_t maxlen, const char *format, va_list args)
|
|||||||
value = va_arg(args, unsigned long int);
|
value = va_arg(args, unsigned long int);
|
||||||
else
|
else
|
||||||
value = va_arg(args, unsigned int);
|
value = va_arg(args, unsigned int);
|
||||||
total += fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
|
total += fmtint(buffer, &currlen, maxlen, value, 10, min, max,
|
||||||
|
flags);
|
||||||
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)
|
||||||
@@ -294,7 +298,8 @@ static int dopr (char *buffer, size_t maxlen, const char *format, va_list args)
|
|||||||
value = va_arg(args, unsigned long int);
|
value = va_arg(args, unsigned long int);
|
||||||
else
|
else
|
||||||
value = va_arg(args, unsigned int);
|
value = va_arg(args, unsigned int);
|
||||||
total += fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags);
|
total += fmtint(buffer, &currlen, maxlen, value, 16, min, max,
|
||||||
|
flags);
|
||||||
break;
|
break;
|
||||||
case 'f':
|
case 'f':
|
||||||
if (cflags == DP_C_LDOUBLE)
|
if (cflags == DP_C_LDOUBLE)
|
||||||
@@ -302,10 +307,12 @@ static int dopr (char *buffer, size_t maxlen, const char *format, va_list args)
|
|||||||
else
|
else
|
||||||
fvalue = va_arg(args, double);
|
fvalue = va_arg(args, double);
|
||||||
/* um, floating point? */
|
/* um, floating point? */
|
||||||
total += fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
|
total +=
|
||||||
|
fmtfp(buffer, &currlen, maxlen, fvalue, min, max, flags);
|
||||||
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 +321,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);
|
||||||
@@ -321,32 +329,29 @@ static int dopr (char *buffer, size_t maxlen, const char *format, va_list args)
|
|||||||
fvalue = va_arg(args, double);
|
fvalue = va_arg(args, double);
|
||||||
break;
|
break;
|
||||||
case 'c':
|
case 'c':
|
||||||
total += dopr_outch (buffer, &currlen, maxlen, va_arg (args, int));
|
total +=
|
||||||
|
dopr_outch(buffer, &currlen, maxlen, va_arg(args, int));
|
||||||
break;
|
break;
|
||||||
case 's':
|
case 's':
|
||||||
strvalue = va_arg(args, char *);
|
strvalue = va_arg(args, char *);
|
||||||
total += fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max);
|
total +=
|
||||||
|
fmtstr(buffer, &currlen, maxlen, strvalue, flags, min, max);
|
||||||
break;
|
break;
|
||||||
case 'p':
|
case 'p':
|
||||||
strvalue = va_arg(args, void *);
|
strvalue = va_arg(args, void *);
|
||||||
total += fmtint (buffer, &currlen, maxlen, (long) strvalue, 16, min,
|
total += fmtint(buffer, &currlen, maxlen, (long)strvalue, 16,
|
||||||
max, flags);
|
min, max, flags);
|
||||||
break;
|
break;
|
||||||
case 'n':
|
case 'n':
|
||||||
if (cflags == DP_C_SHORT)
|
if (cflags == DP_C_SHORT) {
|
||||||
{
|
|
||||||
short int *num;
|
short int *num;
|
||||||
num = va_arg(args, short int *);
|
num = va_arg(args, short int *);
|
||||||
*num = currlen;
|
*num = currlen;
|
||||||
}
|
} else if (cflags == DP_C_LONG) {
|
||||||
else if (cflags == DP_C_LONG)
|
|
||||||
{
|
|
||||||
long int *num;
|
long int *num;
|
||||||
num = va_arg(args, long int *);
|
num = va_arg(args, long int *);
|
||||||
*num = currlen;
|
*num = currlen;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
int *num;
|
int *num;
|
||||||
num = va_arg(args, int *);
|
num = va_arg(args, int *);
|
||||||
*num = currlen;
|
*num = currlen;
|
||||||
@@ -375,8 +380,7 @@ static int dopr (char *buffer, size_t maxlen, const char *format, va_list args)
|
|||||||
break; /* some picky compilers need this */
|
break; /* some picky compilers need this */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (buffer != NULL && maxlen > 0)
|
if (buffer != NULL && maxlen > 0) {
|
||||||
{
|
|
||||||
if (currlen < maxlen - 1)
|
if (currlen < maxlen - 1)
|
||||||
buffer[currlen] = '\0';
|
buffer[currlen] = '\0';
|
||||||
else
|
else
|
||||||
@@ -385,19 +389,24 @@ static int dopr (char *buffer, size_t maxlen, const char *format, va_list args)
|
|||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int fmtstr (char *buffer, size_t *currlen, size_t maxlen,
|
static int fmtstr(char *buffer,
|
||||||
char *value, int flags, int min, int max)
|
size_t *currlen,
|
||||||
|
size_t maxlen,
|
||||||
|
char *value,
|
||||||
|
int flags,
|
||||||
|
int min,
|
||||||
|
int max)
|
||||||
{
|
{
|
||||||
int padlen, strln; /* amount to pad */
|
int padlen, strln; /* amount to pad */
|
||||||
int cnt = 0;
|
int cnt = 0;
|
||||||
int total = 0;
|
int total = 0;
|
||||||
|
|
||||||
if (value == 0)
|
if (value == 0) {
|
||||||
{
|
|
||||||
value = "<NULL>";
|
value = "<NULL>";
|
||||||
}
|
}
|
||||||
|
|
||||||
for (strln = 0; value[strln]; ++strln); /* strlen */
|
for (strln = 0; value[strln]; ++strln)
|
||||||
|
; /* strlen */
|
||||||
if (max >= 0 && max < strln)
|
if (max >= 0 && max < strln)
|
||||||
strln = max;
|
strln = max;
|
||||||
padlen = min - strln;
|
padlen = min - strln;
|
||||||
@@ -406,18 +415,15 @@ static int fmtstr (char *buffer, size_t *currlen, size_t maxlen,
|
|||||||
if (flags & DP_F_MINUS)
|
if (flags & DP_F_MINUS)
|
||||||
padlen = -padlen; /* Left Justify */
|
padlen = -padlen; /* Left Justify */
|
||||||
|
|
||||||
while (padlen > 0)
|
while (padlen > 0) {
|
||||||
{
|
|
||||||
total += dopr_outch(buffer, currlen, maxlen, ' ');
|
total += dopr_outch(buffer, currlen, maxlen, ' ');
|
||||||
--padlen;
|
--padlen;
|
||||||
}
|
}
|
||||||
while (*value && ((max < 0) || (cnt < max)))
|
while (*value && ((max < 0) || (cnt < max))) {
|
||||||
{
|
|
||||||
total += dopr_outch(buffer, currlen, maxlen, *value++);
|
total += dopr_outch(buffer, currlen, maxlen, *value++);
|
||||||
++cnt;
|
++cnt;
|
||||||
}
|
}
|
||||||
while (padlen < 0)
|
while (padlen < 0) {
|
||||||
{
|
|
||||||
total += dopr_outch(buffer, currlen, maxlen, ' ');
|
total += dopr_outch(buffer, currlen, maxlen, ' ');
|
||||||
++padlen;
|
++padlen;
|
||||||
}
|
}
|
||||||
@@ -426,8 +432,14 @@ static int fmtstr (char *buffer, size_t *currlen, size_t maxlen,
|
|||||||
|
|
||||||
/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
|
/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
|
||||||
|
|
||||||
static int fmtint (char *buffer, size_t *currlen, size_t maxlen,
|
static int fmtint(char *buffer,
|
||||||
long value, int base, int min, int max, int flags)
|
size_t *currlen,
|
||||||
|
size_t maxlen,
|
||||||
|
long value,
|
||||||
|
int base,
|
||||||
|
int min,
|
||||||
|
int max,
|
||||||
|
int flags)
|
||||||
{
|
{
|
||||||
int signvalue = 0;
|
int signvalue = 0;
|
||||||
unsigned long uvalue;
|
unsigned long uvalue;
|
||||||
@@ -443,37 +455,35 @@ static int fmtint (char *buffer, size_t *currlen, size_t maxlen,
|
|||||||
|
|
||||||
uvalue = value;
|
uvalue = value;
|
||||||
|
|
||||||
if(!(flags & DP_F_UNSIGNED))
|
if (!(flags & DP_F_UNSIGNED)) {
|
||||||
{
|
|
||||||
if (value < 0) {
|
if (value < 0) {
|
||||||
signvalue = '-';
|
signvalue = '-';
|
||||||
uvalue = -value;
|
uvalue = -value;
|
||||||
}
|
} else if (flags & DP_F_PLUS) /* Do a sign (+/i) */
|
||||||
else
|
|
||||||
if (flags & DP_F_PLUS) /* Do a sign (+/i) */
|
|
||||||
signvalue = '+';
|
signvalue = '+';
|
||||||
else
|
else if (flags & DP_F_SPACE)
|
||||||
if (flags & DP_F_SPACE)
|
|
||||||
signvalue = ' ';
|
signvalue = ' ';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
|
if (flags & DP_F_UP)
|
||||||
|
caps = 1; /* Should characters be upper case? */
|
||||||
|
|
||||||
do {
|
do {
|
||||||
convert[place++] =
|
convert[place++] = (caps ? "0123456789ABCDEF"
|
||||||
(caps? "0123456789ABCDEF":"0123456789abcdef")
|
: "0123456789abcdef")[uvalue % (unsigned)base];
|
||||||
[uvalue % (unsigned)base ];
|
|
||||||
uvalue = (uvalue / (unsigned)base);
|
uvalue = (uvalue / (unsigned)base);
|
||||||
} while (uvalue && (place < 20));
|
} while (uvalue && (place < 20));
|
||||||
if (place == 20) place--;
|
if (place == 20)
|
||||||
|
place--;
|
||||||
convert[place] = 0;
|
convert[place] = 0;
|
||||||
|
|
||||||
zpadlen = max - place;
|
zpadlen = max - place;
|
||||||
spadlen = min - MAX(max, place) - (signvalue ? 1 : 0);
|
spadlen = min - MAX(max, place) - (signvalue ? 1 : 0);
|
||||||
if (zpadlen < 0) zpadlen = 0;
|
if (zpadlen < 0)
|
||||||
if (spadlen < 0) spadlen = 0;
|
zpadlen = 0;
|
||||||
if (flags & DP_F_ZERO)
|
if (spadlen < 0)
|
||||||
{
|
spadlen = 0;
|
||||||
|
if (flags & DP_F_ZERO) {
|
||||||
zpadlen = MAX(zpadlen, spadlen);
|
zpadlen = MAX(zpadlen, spadlen);
|
||||||
spadlen = 0;
|
spadlen = 0;
|
||||||
}
|
}
|
||||||
@@ -486,8 +496,7 @@ static int fmtint (char *buffer, size_t *currlen, size_t maxlen,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Spaces */
|
/* Spaces */
|
||||||
while (spadlen > 0)
|
while (spadlen > 0) {
|
||||||
{
|
|
||||||
total += dopr_outch(buffer, currlen, maxlen, ' ');
|
total += dopr_outch(buffer, currlen, maxlen, ' ');
|
||||||
--spadlen;
|
--spadlen;
|
||||||
}
|
}
|
||||||
@@ -497,10 +506,8 @@ static int fmtint (char *buffer, size_t *currlen, size_t maxlen,
|
|||||||
total += dopr_outch(buffer, currlen, maxlen, signvalue);
|
total += dopr_outch(buffer, currlen, maxlen, signvalue);
|
||||||
|
|
||||||
/* Zeros */
|
/* Zeros */
|
||||||
if (zpadlen > 0)
|
if (zpadlen > 0) {
|
||||||
{
|
while (zpadlen > 0) {
|
||||||
while (zpadlen > 0)
|
|
||||||
{
|
|
||||||
total += dopr_outch(buffer, currlen, maxlen, '0');
|
total += dopr_outch(buffer, currlen, maxlen, '0');
|
||||||
--zpadlen;
|
--zpadlen;
|
||||||
}
|
}
|
||||||
@@ -533,8 +540,7 @@ static LDOUBLE _snp_pow10 (int exp)
|
|||||||
{
|
{
|
||||||
LDOUBLE result = 1;
|
LDOUBLE result = 1;
|
||||||
|
|
||||||
while (exp)
|
while (exp) {
|
||||||
{
|
|
||||||
result *= 10;
|
result *= 10;
|
||||||
exp--;
|
exp--;
|
||||||
}
|
}
|
||||||
@@ -554,8 +560,13 @@ static long _snp_round (LDOUBLE value)
|
|||||||
return intpart;
|
return intpart;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int fmtfp (char *buffer, size_t *currlen, size_t maxlen,
|
static int fmtfp(char *buffer,
|
||||||
LDOUBLE fvalue, int min, int max, int flags)
|
size_t *currlen,
|
||||||
|
size_t maxlen,
|
||||||
|
LDOUBLE fvalue,
|
||||||
|
int min,
|
||||||
|
int max,
|
||||||
|
int flags)
|
||||||
{
|
{
|
||||||
int signvalue = 0;
|
int signvalue = 0;
|
||||||
LDOUBLE ufvalue;
|
LDOUBLE ufvalue;
|
||||||
@@ -581,11 +592,9 @@ static int fmtfp (char *buffer, size_t *currlen, size_t maxlen,
|
|||||||
|
|
||||||
if (fvalue < 0)
|
if (fvalue < 0)
|
||||||
signvalue = '-';
|
signvalue = '-';
|
||||||
else
|
else if (flags & DP_F_PLUS) /* Do a sign (+/i) */
|
||||||
if (flags & DP_F_PLUS) /* Do a sign (+/i) */
|
|
||||||
signvalue = '+';
|
signvalue = '+';
|
||||||
else
|
else if (flags & DP_F_SPACE)
|
||||||
if (flags & DP_F_SPACE)
|
|
||||||
signvalue = ' ';
|
signvalue = ' ';
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
@@ -606,8 +615,7 @@ static int fmtfp (char *buffer, size_t *currlen, size_t maxlen,
|
|||||||
*/
|
*/
|
||||||
fracpart = _snp_round((_snp_pow10(max)) * (ufvalue - intpart));
|
fracpart = _snp_round((_snp_pow10(max)) * (ufvalue - intpart));
|
||||||
|
|
||||||
if (fracpart >= _snp_pow10 (max))
|
if (fracpart >= _snp_pow10(max)) {
|
||||||
{
|
|
||||||
intpart++;
|
intpart++;
|
||||||
fracpart -= _snp_pow10(max);
|
fracpart -= _snp_pow10(max);
|
||||||
}
|
}
|
||||||
@@ -622,7 +630,8 @@ static int fmtfp (char *buffer, size_t *currlen, size_t maxlen,
|
|||||||
(caps ? "0123456789ABCDEF" : "0123456789abcdef")[intpart % 10];
|
(caps ? "0123456789ABCDEF" : "0123456789abcdef")[intpart % 10];
|
||||||
intpart = (intpart / 10);
|
intpart = (intpart / 10);
|
||||||
} while (intpart && (iplace < 20));
|
} while (intpart && (iplace < 20));
|
||||||
if (iplace == 20) iplace--;
|
if (iplace == 20)
|
||||||
|
iplace--;
|
||||||
iconvert[iplace] = 0;
|
iconvert[iplace] = 0;
|
||||||
|
|
||||||
/* Convert fractional part */
|
/* Convert fractional part */
|
||||||
@@ -631,7 +640,8 @@ static int fmtfp (char *buffer, size_t *currlen, size_t maxlen,
|
|||||||
(caps ? "0123456789ABCDEF" : "0123456789abcdef")[fracpart % 10];
|
(caps ? "0123456789ABCDEF" : "0123456789abcdef")[fracpart % 10];
|
||||||
fracpart = (fracpart / 10);
|
fracpart = (fracpart / 10);
|
||||||
} while (fracpart && (fplace < 20));
|
} while (fracpart && (fplace < 20));
|
||||||
if (fplace == 20) fplace--;
|
if (fplace == 20)
|
||||||
|
fplace--;
|
||||||
fconvert[fplace] = 0;
|
fconvert[fplace] = 0;
|
||||||
|
|
||||||
/* -1 for decimal point, another -1 if we are printing a sign */
|
/* -1 for decimal point, another -1 if we are printing a sign */
|
||||||
@@ -644,22 +654,18 @@ static int fmtfp (char *buffer, size_t *currlen, size_t maxlen,
|
|||||||
if (flags & DP_F_MINUS)
|
if (flags & DP_F_MINUS)
|
||||||
padlen = -padlen; /* Left Justifty */
|
padlen = -padlen; /* Left Justifty */
|
||||||
|
|
||||||
if ((flags & DP_F_ZERO) && (padlen > 0))
|
if ((flags & DP_F_ZERO) && (padlen > 0)) {
|
||||||
{
|
if (signvalue) {
|
||||||
if (signvalue)
|
|
||||||
{
|
|
||||||
total += dopr_outch(buffer, currlen, maxlen, signvalue);
|
total += dopr_outch(buffer, currlen, maxlen, signvalue);
|
||||||
--padlen;
|
--padlen;
|
||||||
signvalue = 0;
|
signvalue = 0;
|
||||||
}
|
}
|
||||||
while (padlen > 0)
|
while (padlen > 0) {
|
||||||
{
|
|
||||||
total += dopr_outch(buffer, currlen, maxlen, '0');
|
total += dopr_outch(buffer, currlen, maxlen, '0');
|
||||||
--padlen;
|
--padlen;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (padlen > 0)
|
while (padlen > 0) {
|
||||||
{
|
|
||||||
total += dopr_outch(buffer, currlen, maxlen, ' ');
|
total += dopr_outch(buffer, currlen, maxlen, ' ');
|
||||||
--padlen;
|
--padlen;
|
||||||
}
|
}
|
||||||
@@ -673,22 +679,19 @@ static int fmtfp (char *buffer, size_t *currlen, size_t maxlen,
|
|||||||
* Decimal point. This should probably use locale to find the correct
|
* Decimal point. This should probably use locale to find the correct
|
||||||
* char to print out.
|
* char to print out.
|
||||||
*/
|
*/
|
||||||
if (max > 0)
|
if (max > 0) {
|
||||||
{
|
|
||||||
total += dopr_outch(buffer, currlen, maxlen, '.');
|
total += dopr_outch(buffer, currlen, maxlen, '.');
|
||||||
|
|
||||||
while (fplace > 0)
|
while (fplace > 0)
|
||||||
total += dopr_outch(buffer, currlen, maxlen, fconvert[--fplace]);
|
total += dopr_outch(buffer, currlen, maxlen, fconvert[--fplace]);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (zpadlen > 0)
|
while (zpadlen > 0) {
|
||||||
{
|
|
||||||
total += dopr_outch(buffer, currlen, maxlen, '0');
|
total += dopr_outch(buffer, currlen, maxlen, '0');
|
||||||
--zpadlen;
|
--zpadlen;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (padlen < 0)
|
while (padlen < 0) {
|
||||||
{
|
|
||||||
total += dopr_outch(buffer, currlen, maxlen, ' ');
|
total += dopr_outch(buffer, currlen, maxlen, ' ');
|
||||||
++padlen;
|
++padlen;
|
||||||
}
|
}
|
||||||
|
|||||||
70
src/sock.c
70
src/sock.c
@@ -21,8 +21,8 @@
|
|||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <winsock2.h>
|
#include <winsock2.h>
|
||||||
#include <ws2tcpip.h>
|
#include <ws2tcpip.h>
|
||||||
#include <Iphlpapi.h>
|
#include <iphlpapi.h>
|
||||||
#include <Mstcpip.h> /* tcp_keepalive */
|
#include <mstcpip.h> /* tcp_keepalive */
|
||||||
#else
|
#else
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
@@ -123,7 +123,8 @@ int sock_set_keepalive(const sock_t sock, int timeout, int interval)
|
|||||||
ka.onoff = optval;
|
ka.onoff = optval;
|
||||||
ka.keepalivetime = timeout * 1000;
|
ka.keepalivetime = timeout * 1000;
|
||||||
ka.keepaliveinterval = interval * 1000;
|
ka.keepaliveinterval = interval * 1000;
|
||||||
ret = WSAIoctl(sock, SIO_KEEPALIVE_VALS, &ka, sizeof(ka), NULL, 0, &dw, NULL, NULL);
|
ret = WSAIoctl(sock, SIO_KEEPALIVE_VALS, &ka, sizeof(ka), NULL, 0, &dw,
|
||||||
|
NULL, NULL);
|
||||||
#else
|
#else
|
||||||
ret = setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval));
|
ret = setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval));
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
@@ -131,15 +132,19 @@ int sock_set_keepalive(const sock_t sock, int timeout, int interval)
|
|||||||
|
|
||||||
if (optval) {
|
if (optval) {
|
||||||
#ifdef TCP_KEEPIDLE
|
#ifdef TCP_KEEPIDLE
|
||||||
ret = setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, &timeout, sizeof(timeout));
|
ret = setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, &timeout,
|
||||||
|
sizeof(timeout));
|
||||||
#elif defined(TCP_KEEPALIVE)
|
#elif defined(TCP_KEEPALIVE)
|
||||||
/* QNX receives `struct timeval' as argument, but it seems OSX does int */
|
/* QNX receives `struct timeval' as argument, but it seems OSX does int
|
||||||
ret = setsockopt(sock, IPPROTO_TCP, TCP_KEEPALIVE, &timeout, sizeof(timeout));
|
*/
|
||||||
|
ret = setsockopt(sock, IPPROTO_TCP, TCP_KEEPALIVE, &timeout,
|
||||||
|
sizeof(timeout));
|
||||||
#endif /* TCP_KEEPIDLE */
|
#endif /* TCP_KEEPIDLE */
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
#ifdef TCP_KEEPINTVL
|
#ifdef TCP_KEEPINTVL
|
||||||
ret = setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, &interval, sizeof(interval));
|
ret = setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, &interval,
|
||||||
|
sizeof(interval));
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
#endif /* TCP_KEEPINTVL */
|
#endif /* TCP_KEEPINTVL */
|
||||||
@@ -158,38 +163,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);
|
||||||
@@ -212,27 +212,29 @@ int sock_is_recoverable(const int error)
|
|||||||
|
|
||||||
int sock_connect_error(const sock_t sock)
|
int sock_connect_error(const sock_t sock)
|
||||||
{
|
{
|
||||||
struct sockaddr sa;
|
struct sockaddr_storage ss;
|
||||||
|
struct sockaddr *sa = (struct sockaddr *)&ss;
|
||||||
socklen_t len;
|
socklen_t len;
|
||||||
char temp;
|
char temp;
|
||||||
|
|
||||||
memset(&sa, 0, sizeof(sa));
|
memset(&ss, 0, sizeof(ss));
|
||||||
sa.sa_family = AF_UNSPEC;
|
len = sizeof(ss);
|
||||||
len = sizeof(sa);
|
sa->sa_family = AF_UNSPEC;
|
||||||
|
|
||||||
/* we don't actually care about the peer name, we're just checking if
|
/* we don't actually care about the peer name, we're just checking if
|
||||||
* we're connected or not */
|
* we're connected or not */
|
||||||
if (getpeername(sock, &sa, &len) == 0)
|
if (getpeername(sock, sa, &len) == 0) {
|
||||||
{
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* it's possible that the error wasn't ENOTCONN, so if it wasn't,
|
/* it's possible that the error wasn't ENOTCONN, so if it wasn't,
|
||||||
* return that */
|
* return that */
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
if (sock_error() != WSAENOTCONN) return sock_error();
|
if (sock_error() != WSAENOTCONN)
|
||||||
|
return sock_error();
|
||||||
#else
|
#else
|
||||||
if (sock_error() != ENOTCONN) return sock_error();
|
if (sock_error() != ENOTCONN)
|
||||||
|
return sock_error();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* load the correct error into errno through error slippage */
|
/* load the correct error into errno through error slippage */
|
||||||
|
|||||||
604
src/stanza.c
604
src/stanza.c
@@ -22,6 +22,7 @@
|
|||||||
#include "strophe.h"
|
#include "strophe.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "hash.h"
|
#include "hash.h"
|
||||||
|
#include "parser.h"
|
||||||
|
|
||||||
/** Create a stanza object.
|
/** Create a stanza object.
|
||||||
* This function allocates and initializes a blank stanza object.
|
* This function allocates and initializes a blank stanza object.
|
||||||
@@ -76,35 +77,29 @@ 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)
|
||||||
goto error;
|
rc = XMPP_EMEM;
|
||||||
while ((key = hash_iter_next(iter))) {
|
|
||||||
val = xmpp_strdup(src->ctx,
|
while (rc == XMPP_EOK && (key = hash_iter_next(iter))) {
|
||||||
(char *)hash_get(src->attributes, key));
|
val = hash_get(src->attributes, key);
|
||||||
if (!val)
|
if (!val)
|
||||||
goto error;
|
rc = XMPP_EINT;
|
||||||
|
if (rc == XMPP_EOK)
|
||||||
if (hash_add(dst->attributes, key, val)) {
|
rc = xmpp_stanza_set_attribute(dst, key, val);
|
||||||
xmpp_free(src->ctx, val);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
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.
|
||||||
@@ -124,13 +119,15 @@ xmpp_stanza_t *xmpp_stanza_copy(const xmpp_stanza_t * const stanza)
|
|||||||
xmpp_stanza_t *copy, *child, *copychild, *tail;
|
xmpp_stanza_t *copy, *child, *copychild, *tail;
|
||||||
|
|
||||||
copy = xmpp_stanza_new(stanza->ctx);
|
copy = xmpp_stanza_new(stanza->ctx);
|
||||||
if (!copy) goto copy_error;
|
if (!copy)
|
||||||
|
goto copy_error;
|
||||||
|
|
||||||
copy->type = stanza->type;
|
copy->type = stanza->type;
|
||||||
|
|
||||||
if (stanza->data) {
|
if (stanza->data) {
|
||||||
copy->data = xmpp_strdup(stanza->ctx, stanza->data);
|
copy->data = xmpp_strdup(stanza->ctx, stanza->data);
|
||||||
if (!copy->data) goto copy_error;
|
if (!copy->data)
|
||||||
|
goto copy_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stanza->attributes) {
|
if (stanza->attributes) {
|
||||||
@@ -141,7 +138,8 @@ xmpp_stanza_t *xmpp_stanza_copy(const xmpp_stanza_t * const stanza)
|
|||||||
tail = copy->children;
|
tail = copy->children;
|
||||||
for (child = stanza->children; child; child = child->next) {
|
for (child = stanza->children; child; child = child->next) {
|
||||||
copychild = xmpp_stanza_copy(child);
|
copychild = xmpp_stanza_copy(child);
|
||||||
if (!copychild) goto copy_error;
|
if (!copychild)
|
||||||
|
goto copy_error;
|
||||||
copychild->parent = copy;
|
copychild->parent = copy;
|
||||||
|
|
||||||
if (tail) {
|
if (tail) {
|
||||||
@@ -156,7 +154,8 @@ xmpp_stanza_t *xmpp_stanza_copy(const xmpp_stanza_t * const stanza)
|
|||||||
|
|
||||||
copy_error:
|
copy_error:
|
||||||
/* release all the hitherto allocated memory */
|
/* release all the hitherto allocated memory */
|
||||||
if (copy) xmpp_stanza_release(copy);
|
if (copy)
|
||||||
|
xmpp_stanza_release(copy);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,8 +186,10 @@ int xmpp_stanza_release(xmpp_stanza_t * const stanza)
|
|||||||
xmpp_stanza_release(tchild);
|
xmpp_stanza_release(tchild);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stanza->attributes) hash_release(stanza->attributes);
|
if (stanza->attributes)
|
||||||
if (stanza->data) xmpp_free(stanza->ctx, stanza->data);
|
hash_release(stanza->attributes);
|
||||||
|
if (stanza->data)
|
||||||
|
xmpp_free(stanza->ctx, stanza->data);
|
||||||
xmpp_free(stanza->ctx, stanza);
|
xmpp_free(stanza->ctx, stanza);
|
||||||
released = 1;
|
released = 1;
|
||||||
}
|
}
|
||||||
@@ -196,6 +197,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
|
||||||
@@ -281,9 +295,11 @@ static char *_escape_xml(xmpp_ctx_t * const ctx, char *text)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* small helper function */
|
/* small helper function */
|
||||||
static void _render_update(int *written, const int length,
|
static void _render_update(int *written,
|
||||||
|
const int length,
|
||||||
const int lastwrite,
|
const int lastwrite,
|
||||||
size_t *left, char **ptr)
|
size_t *left,
|
||||||
|
char **ptr)
|
||||||
{
|
{
|
||||||
*written += lastwrite;
|
*written += lastwrite;
|
||||||
|
|
||||||
@@ -302,7 +318,8 @@ static void _render_update(int *written, const int length,
|
|||||||
* and return values > buflen indicate buffer was not large enough
|
* and return values > buflen indicate buffer was not large enough
|
||||||
*/
|
*/
|
||||||
static int _render_stanza_recursive(xmpp_stanza_t *stanza,
|
static int _render_stanza_recursive(xmpp_stanza_t *stanza,
|
||||||
char * const buf, size_t const buflen)
|
char *const buf,
|
||||||
|
size_t const buflen)
|
||||||
{
|
{
|
||||||
char *ptr = buf;
|
char *ptr = buf;
|
||||||
size_t left = buflen;
|
size_t left = buflen;
|
||||||
@@ -314,23 +331,29 @@ static int _render_stanza_recursive(xmpp_stanza_t *stanza,
|
|||||||
|
|
||||||
written = 0;
|
written = 0;
|
||||||
|
|
||||||
if (stanza->type == XMPP_STANZA_UNKNOWN) return XMPP_EINVOP;
|
if (stanza->type == XMPP_STANZA_UNKNOWN)
|
||||||
|
return XMPP_EINVOP;
|
||||||
|
|
||||||
if (stanza->type == XMPP_STANZA_TEXT) {
|
if (stanza->type == XMPP_STANZA_TEXT) {
|
||||||
if (!stanza->data) return XMPP_EINVOP;
|
if (!stanza->data)
|
||||||
|
return XMPP_EINVOP;
|
||||||
|
|
||||||
tmp = _escape_xml(stanza->ctx, stanza->data);
|
tmp = _escape_xml(stanza->ctx, stanza->data);
|
||||||
if (tmp == NULL) return XMPP_EMEM;
|
if (tmp == NULL)
|
||||||
|
return XMPP_EMEM;
|
||||||
ret = xmpp_snprintf(ptr, left, "%s", tmp);
|
ret = xmpp_snprintf(ptr, left, "%s", tmp);
|
||||||
xmpp_free(stanza->ctx, tmp);
|
xmpp_free(stanza->ctx, tmp);
|
||||||
if (ret < 0) return XMPP_EMEM;
|
if (ret < 0)
|
||||||
|
return XMPP_EMEM;
|
||||||
_render_update(&written, buflen, ret, &left, &ptr);
|
_render_update(&written, buflen, ret, &left, &ptr);
|
||||||
} else { /* stanza->type == XMPP_STANZA_TAG */
|
} else { /* stanza->type == XMPP_STANZA_TAG */
|
||||||
if (!stanza->data) return XMPP_EINVOP;
|
if (!stanza->data)
|
||||||
|
return XMPP_EINVOP;
|
||||||
|
|
||||||
/* write beginning of tag and attributes */
|
/* write beginning of tag and attributes */
|
||||||
ret = xmpp_snprintf(ptr, left, "<%s", stanza->data);
|
ret = xmpp_snprintf(ptr, left, "<%s", stanza->data);
|
||||||
if (ret < 0) return XMPP_EMEM;
|
if (ret < 0)
|
||||||
|
return XMPP_EMEM;
|
||||||
_render_update(&written, buflen, ret, &left, &ptr);
|
_render_update(&written, buflen, ret, &left, &ptr);
|
||||||
|
|
||||||
if (stanza->attributes && hash_num_keys(stanza->attributes) > 0) {
|
if (stanza->attributes && hash_num_keys(stanza->attributes) > 0) {
|
||||||
@@ -338,10 +361,10 @@ static int _render_stanza_recursive(xmpp_stanza_t *stanza,
|
|||||||
while ((key = hash_iter_next(iter))) {
|
while ((key = hash_iter_next(iter))) {
|
||||||
if (!strcmp(key, "xmlns")) {
|
if (!strcmp(key, "xmlns")) {
|
||||||
/* don't output namespace if parent stanza is the same */
|
/* don't output namespace if parent stanza is the same */
|
||||||
if (stanza->parent &&
|
if (stanza->parent && stanza->parent->attributes &&
|
||||||
stanza->parent->attributes &&
|
|
||||||
hash_get(stanza->parent->attributes, key) &&
|
hash_get(stanza->parent->attributes, key) &&
|
||||||
!strcmp((char*)hash_get(stanza->attributes, key),
|
!strcmp(
|
||||||
|
(char *)hash_get(stanza->attributes, key),
|
||||||
(char *)hash_get(stanza->parent->attributes, key)))
|
(char *)hash_get(stanza->parent->attributes, key)))
|
||||||
continue;
|
continue;
|
||||||
/* or if this is the stream namespace */
|
/* or if this is the stream namespace */
|
||||||
@@ -352,10 +375,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);
|
||||||
@@ -364,21 +393,24 @@ static int _render_stanza_recursive(xmpp_stanza_t *stanza,
|
|||||||
if (!stanza->children) {
|
if (!stanza->children) {
|
||||||
/* write end if singleton tag */
|
/* write end if singleton tag */
|
||||||
ret = xmpp_snprintf(ptr, left, "/>");
|
ret = xmpp_snprintf(ptr, left, "/>");
|
||||||
if (ret < 0) return XMPP_EMEM;
|
if (ret < 0)
|
||||||
|
return XMPP_EMEM;
|
||||||
_render_update(&written, buflen, ret, &left, &ptr);
|
_render_update(&written, buflen, ret, &left, &ptr);
|
||||||
} else {
|
} else {
|
||||||
/* this stanza has child stanzas */
|
/* this stanza has child stanzas */
|
||||||
|
|
||||||
/* write end of start tag */
|
/* write end of start tag */
|
||||||
ret = xmpp_snprintf(ptr, left, ">");
|
ret = xmpp_snprintf(ptr, left, ">");
|
||||||
if (ret < 0) return XMPP_EMEM;
|
if (ret < 0)
|
||||||
|
return XMPP_EMEM;
|
||||||
_render_update(&written, buflen, ret, &left, &ptr);
|
_render_update(&written, buflen, ret, &left, &ptr);
|
||||||
|
|
||||||
/* iterate and recurse over child stanzas */
|
/* iterate and recurse over child stanzas */
|
||||||
child = stanza->children;
|
child = stanza->children;
|
||||||
while (child) {
|
while (child) {
|
||||||
ret = _render_stanza_recursive(child, ptr, left);
|
ret = _render_stanza_recursive(child, ptr, left);
|
||||||
if (ret < 0) return ret;
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
_render_update(&written, buflen, ret, &left, &ptr);
|
_render_update(&written, buflen, ret, &left, &ptr);
|
||||||
|
|
||||||
@@ -387,7 +419,8 @@ static int _render_stanza_recursive(xmpp_stanza_t *stanza,
|
|||||||
|
|
||||||
/* write end tag */
|
/* write end tag */
|
||||||
ret = xmpp_snprintf(ptr, left, "</%s>", stanza->data);
|
ret = xmpp_snprintf(ptr, left, "</%s>", stanza->data);
|
||||||
if (ret < 0) return XMPP_EMEM;
|
if (ret < 0)
|
||||||
|
return XMPP_EMEM;
|
||||||
|
|
||||||
_render_update(&written, buflen, ret, &left, &ptr);
|
_render_update(&written, buflen, ret, &left, &ptr);
|
||||||
}
|
}
|
||||||
@@ -429,9 +462,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 +481,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;
|
||||||
@@ -464,12 +507,13 @@ int xmpp_stanza_to_text(xmpp_stanza_t *stanza,
|
|||||||
*
|
*
|
||||||
* @ingroup Stanza
|
* @ingroup Stanza
|
||||||
*/
|
*/
|
||||||
int xmpp_stanza_set_name(xmpp_stanza_t *stanza,
|
int xmpp_stanza_set_name(xmpp_stanza_t *stanza, const char *const name)
|
||||||
const char * const name)
|
|
||||||
{
|
{
|
||||||
if (stanza->type == XMPP_STANZA_TEXT) return XMPP_EINVOP;
|
if (stanza->type == XMPP_STANZA_TEXT)
|
||||||
|
return XMPP_EINVOP;
|
||||||
|
|
||||||
if (stanza->data) xmpp_free(stanza->ctx, stanza->data);
|
if (stanza->data)
|
||||||
|
xmpp_free(stanza->ctx, stanza->data);
|
||||||
|
|
||||||
stanza->type = XMPP_STANZA_TAG;
|
stanza->type = XMPP_STANZA_TAG;
|
||||||
stanza->data = xmpp_strdup(stanza->ctx, name);
|
stanza->data = xmpp_strdup(stanza->ctx, name);
|
||||||
@@ -489,7 +533,8 @@ int xmpp_stanza_set_name(xmpp_stanza_t *stanza,
|
|||||||
*/
|
*/
|
||||||
const char *xmpp_stanza_get_name(xmpp_stanza_t *const stanza)
|
const char *xmpp_stanza_get_name(xmpp_stanza_t *const stanza)
|
||||||
{
|
{
|
||||||
if (stanza->type == XMPP_STANZA_TEXT) return NULL;
|
if (stanza->type == XMPP_STANZA_TEXT)
|
||||||
|
return NULL;
|
||||||
return stanza->data;
|
return stanza->data;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -525,7 +570,8 @@ int xmpp_stanza_get_attribute_count(xmpp_stanza_t * const stanza)
|
|||||||
* @ingroup Stanza
|
* @ingroup Stanza
|
||||||
*/
|
*/
|
||||||
int xmpp_stanza_get_attributes(xmpp_stanza_t *const stanza,
|
int xmpp_stanza_get_attributes(xmpp_stanza_t *const stanza,
|
||||||
const char **attr, int attrlen)
|
const char **attr,
|
||||||
|
int attrlen)
|
||||||
{
|
{
|
||||||
hash_iterator_t *iter;
|
hash_iterator_t *iter;
|
||||||
const char *key;
|
const char *key;
|
||||||
@@ -570,21 +616,27 @@ 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;
|
||||||
|
|
||||||
if (!stanza->attributes) {
|
if (!stanza->attributes) {
|
||||||
stanza->attributes = hash_new(stanza->ctx, 8, xmpp_free);
|
stanza->attributes = hash_new(stanza->ctx, 8, xmpp_free);
|
||||||
if (!stanza->attributes) return XMPP_EMEM;
|
if (!stanza->attributes)
|
||||||
|
return XMPP_EMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
@@ -600,12 +652,52 @@ int xmpp_stanza_set_attribute(xmpp_stanza_t * const stanza,
|
|||||||
*
|
*
|
||||||
* @ingroup Stanza
|
* @ingroup Stanza
|
||||||
*/
|
*/
|
||||||
int xmpp_stanza_set_ns(xmpp_stanza_t * const stanza,
|
int xmpp_stanza_set_ns(xmpp_stanza_t *const stanza, const char *const ns)
|
||||||
const char * const ns)
|
|
||||||
{
|
{
|
||||||
return xmpp_stanza_set_attribute(stanza, "xmlns", ns);
|
return xmpp_stanza_set_attribute(stanza, "xmlns", ns);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Add a child stanza to a stanza object.
|
||||||
|
* If do_clone is TRUE, user keeps reference to the child stanza and must call
|
||||||
|
* 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 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
|
||||||
|
*
|
||||||
|
* @ingroup Stanza
|
||||||
|
*/
|
||||||
|
int xmpp_stanza_add_child_ex(xmpp_stanza_t *stanza,
|
||||||
|
xmpp_stanza_t *child,
|
||||||
|
int do_clone)
|
||||||
|
{
|
||||||
|
xmpp_stanza_t *s;
|
||||||
|
|
||||||
|
if (do_clone) {
|
||||||
|
/* get a reference to the child */
|
||||||
|
xmpp_stanza_clone(child);
|
||||||
|
}
|
||||||
|
|
||||||
|
child->parent = stanza;
|
||||||
|
|
||||||
|
if (!stanza->children)
|
||||||
|
stanza->children = child;
|
||||||
|
else {
|
||||||
|
s = stanza->children;
|
||||||
|
while (s->next)
|
||||||
|
s = s->next;
|
||||||
|
s->next = child;
|
||||||
|
child->prev = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
return XMPP_EOK;
|
||||||
|
}
|
||||||
|
|
||||||
/** 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
|
* This function clones the child and appends it to the stanza object's
|
||||||
* children.
|
* children.
|
||||||
@@ -619,23 +711,7 @@ int xmpp_stanza_set_ns(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)
|
||||||
{
|
{
|
||||||
xmpp_stanza_t *s;
|
return xmpp_stanza_add_child_ex(stanza, child, 1);
|
||||||
|
|
||||||
/* get a reference to the child */
|
|
||||||
xmpp_stanza_clone(child);
|
|
||||||
|
|
||||||
child->parent = stanza;
|
|
||||||
|
|
||||||
if (!stanza->children)
|
|
||||||
stanza->children = child;
|
|
||||||
else {
|
|
||||||
s = stanza->children;
|
|
||||||
while (s->next) s = s->next;
|
|
||||||
s->next = child;
|
|
||||||
child->prev = s;
|
|
||||||
}
|
|
||||||
|
|
||||||
return XMPP_EOK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Set the text data for a text stanza.
|
/** Set the text data for a text stanza.
|
||||||
@@ -651,14 +727,15 @@ int xmpp_stanza_add_child(xmpp_stanza_t *stanza, xmpp_stanza_t *child)
|
|||||||
*
|
*
|
||||||
* @ingroup Stanza
|
* @ingroup Stanza
|
||||||
*/
|
*/
|
||||||
int xmpp_stanza_set_text(xmpp_stanza_t *stanza,
|
int xmpp_stanza_set_text(xmpp_stanza_t *stanza, const char *const text)
|
||||||
const char * const text)
|
|
||||||
{
|
{
|
||||||
if (stanza->type == XMPP_STANZA_TAG) return XMPP_EINVOP;
|
if (stanza->type == XMPP_STANZA_TAG)
|
||||||
|
return XMPP_EINVOP;
|
||||||
|
|
||||||
stanza->type = XMPP_STANZA_TEXT;
|
stanza->type = XMPP_STANZA_TEXT;
|
||||||
|
|
||||||
if (stanza->data) xmpp_free(stanza->ctx, stanza->data);
|
if (stanza->data)
|
||||||
|
xmpp_free(stanza->ctx, stanza->data);
|
||||||
stanza->data = xmpp_strdup(stanza->ctx, text);
|
stanza->data = xmpp_strdup(stanza->ctx, text);
|
||||||
|
|
||||||
return stanza->data == NULL ? XMPP_EMEM : XMPP_EOK;
|
return stanza->data == NULL ? XMPP_EMEM : XMPP_EOK;
|
||||||
@@ -682,13 +759,16 @@ int xmpp_stanza_set_text_with_size(xmpp_stanza_t *stanza,
|
|||||||
const char *const text,
|
const char *const text,
|
||||||
const size_t size)
|
const size_t size)
|
||||||
{
|
{
|
||||||
if (stanza->type == XMPP_STANZA_TAG) return XMPP_EINVOP;
|
if (stanza->type == XMPP_STANZA_TAG)
|
||||||
|
return XMPP_EINVOP;
|
||||||
|
|
||||||
stanza->type = XMPP_STANZA_TEXT;
|
stanza->type = XMPP_STANZA_TEXT;
|
||||||
|
|
||||||
if (stanza->data) xmpp_free(stanza->ctx, stanza->data);
|
if (stanza->data)
|
||||||
|
xmpp_free(stanza->ctx, stanza->data);
|
||||||
stanza->data = xmpp_alloc(stanza->ctx, size + 1);
|
stanza->data = xmpp_alloc(stanza->ctx, size + 1);
|
||||||
if (!stanza->data) return XMPP_EMEM;
|
if (!stanza->data)
|
||||||
|
return XMPP_EMEM;
|
||||||
|
|
||||||
memcpy(stanza->data, text, size);
|
memcpy(stanza->data, text, size);
|
||||||
stanza->data[size] = 0;
|
stanza->data[size] = 0;
|
||||||
@@ -812,16 +892,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
|
||||||
@@ -880,10 +994,12 @@ char *xmpp_stanza_get_text(xmpp_stanza_t * const stanza)
|
|||||||
if (child->type == XMPP_STANZA_TEXT)
|
if (child->type == XMPP_STANZA_TEXT)
|
||||||
len += strlen(child->data);
|
len += strlen(child->data);
|
||||||
|
|
||||||
if (len == 0) return NULL;
|
if (len == 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
text = (char *)xmpp_alloc(stanza->ctx, len + 1);
|
text = (char *)xmpp_alloc(stanza->ctx, len + 1);
|
||||||
if (!text) return NULL;
|
if (!text)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
len = 0;
|
len = 0;
|
||||||
for (child = stanza->children; child; child = child->next)
|
for (child = stanza->children; child; child = child->next)
|
||||||
@@ -930,8 +1046,7 @@ const char *xmpp_stanza_get_text_ptr(xmpp_stanza_t * const stanza)
|
|||||||
*
|
*
|
||||||
* @ingroup Stanza
|
* @ingroup Stanza
|
||||||
*/
|
*/
|
||||||
int xmpp_stanza_set_id(xmpp_stanza_t * const stanza,
|
int xmpp_stanza_set_id(xmpp_stanza_t *const stanza, const char *const id)
|
||||||
const char * const id)
|
|
||||||
{
|
{
|
||||||
return xmpp_stanza_set_attribute(stanza, "id", id);
|
return xmpp_stanza_set_attribute(stanza, "id", id);
|
||||||
}
|
}
|
||||||
@@ -947,8 +1062,7 @@ int xmpp_stanza_set_id(xmpp_stanza_t * const stanza,
|
|||||||
*
|
*
|
||||||
* @ingroup Stanza
|
* @ingroup Stanza
|
||||||
*/
|
*/
|
||||||
int xmpp_stanza_set_type(xmpp_stanza_t * const stanza,
|
int xmpp_stanza_set_type(xmpp_stanza_t *const stanza, const char *const type)
|
||||||
const char * const type)
|
|
||||||
{
|
{
|
||||||
return xmpp_stanza_set_attribute(stanza, "type", type);
|
return xmpp_stanza_set_attribute(stanza, "type", type);
|
||||||
}
|
}
|
||||||
@@ -965,8 +1079,7 @@ int xmpp_stanza_set_type(xmpp_stanza_t * const stanza,
|
|||||||
*
|
*
|
||||||
* @ingroup Stanza
|
* @ingroup Stanza
|
||||||
*/
|
*/
|
||||||
int xmpp_stanza_set_to(xmpp_stanza_t * const stanza,
|
int xmpp_stanza_set_to(xmpp_stanza_t *const stanza, const char *const to)
|
||||||
const char * const to)
|
|
||||||
{
|
{
|
||||||
return xmpp_stanza_set_attribute(stanza, "to", to);
|
return xmpp_stanza_set_attribute(stanza, "to", to);
|
||||||
}
|
}
|
||||||
@@ -983,8 +1096,7 @@ int xmpp_stanza_set_to(xmpp_stanza_t * const stanza,
|
|||||||
*
|
*
|
||||||
* @ingroup Stanza
|
* @ingroup Stanza
|
||||||
*/
|
*/
|
||||||
int xmpp_stanza_set_from(xmpp_stanza_t * const stanza,
|
int xmpp_stanza_set_from(xmpp_stanza_t *const stanza, const char *const from)
|
||||||
const char * const from)
|
|
||||||
{
|
{
|
||||||
return xmpp_stanza_set_attribute(stanza, "from", from);
|
return xmpp_stanza_set_attribute(stanza, "from", from);
|
||||||
}
|
}
|
||||||
@@ -1047,36 +1159,127 @@ 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;
|
||||||
|
|
||||||
copy->type = stanza->type;
|
copy->type = stanza->type;
|
||||||
|
|
||||||
if (stanza->data) {
|
if (stanza->data) {
|
||||||
copy->data = xmpp_strdup(stanza->ctx, stanza->data);
|
copy->data = xmpp_strdup(stanza->ctx, stanza->data);
|
||||||
if (!copy->data) goto copy_error;
|
if (!copy->data)
|
||||||
}
|
|
||||||
|
|
||||||
if (stanza->attributes) {
|
|
||||||
if (_stanza_copy_attributes(copy, stanza) == -1)
|
|
||||||
goto copy_error;
|
goto copy_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
xmpp_stanza_set_to(copy, xmpp_stanza_get_from(stanza));
|
if (stanza->attributes) {
|
||||||
|
if (_stanza_copy_attributes(copy, stanza) < 0)
|
||||||
|
goto copy_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
xmpp_stanza_del_attribute(copy, "to");
|
||||||
xmpp_stanza_del_attribute(copy, "from");
|
xmpp_stanza_del_attribute(copy, "from");
|
||||||
|
xmpp_stanza_del_attribute(copy, "xmlns");
|
||||||
|
rc = xmpp_stanza_set_to(copy, from);
|
||||||
|
if (rc != XMPP_EOK)
|
||||||
|
goto copy_error;
|
||||||
|
|
||||||
return copy;
|
return copy;
|
||||||
|
|
||||||
copy_error:
|
copy_error:
|
||||||
if (copy) xmpp_stanza_release(copy);
|
if (copy)
|
||||||
|
xmpp_stanza_release(copy);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static xmpp_stanza_t *
|
/** Create an error stanza in reply to the provided stanza.
|
||||||
_stanza_new_with_attrs(xmpp_ctx_t *ctx, const char * const name,
|
*
|
||||||
const char * const type, const char * const id,
|
* Check https://tools.ietf.org/html/rfc6120#section-8.3 for details.
|
||||||
|
*
|
||||||
|
* @param stanza a Strophe stanza object
|
||||||
|
* @param error_type type attribute in the <error/> child element
|
||||||
|
* @param condition the defined-condition (e.g. "item-not-found")
|
||||||
|
* @param text optional description, may be NULL
|
||||||
|
*
|
||||||
|
* @return a new Strophe stanza object
|
||||||
|
*
|
||||||
|
* @ingroup Stanza
|
||||||
|
*/
|
||||||
|
xmpp_stanza_t *xmpp_stanza_reply_error(xmpp_stanza_t *const stanza,
|
||||||
|
const char *const error_type,
|
||||||
|
const char *const condition,
|
||||||
|
const char *const text)
|
||||||
|
{
|
||||||
|
xmpp_ctx_t *ctx = stanza->ctx;
|
||||||
|
xmpp_stanza_t *reply = NULL;
|
||||||
|
xmpp_stanza_t *error;
|
||||||
|
xmpp_stanza_t *item;
|
||||||
|
xmpp_stanza_t *text_stanza;
|
||||||
|
const char *to;
|
||||||
|
|
||||||
|
if (!error_type || !condition)
|
||||||
|
goto quit_err;
|
||||||
|
|
||||||
|
reply = xmpp_stanza_reply(stanza);
|
||||||
|
if (!reply)
|
||||||
|
goto quit_err;
|
||||||
|
|
||||||
|
xmpp_stanza_set_type(reply, "error");
|
||||||
|
to = xmpp_stanza_get_to(stanza);
|
||||||
|
if (to)
|
||||||
|
xmpp_stanza_set_from(reply, to);
|
||||||
|
|
||||||
|
error = xmpp_stanza_new(ctx);
|
||||||
|
if (!error)
|
||||||
|
goto quit_err;
|
||||||
|
xmpp_stanza_set_name(error, "error");
|
||||||
|
xmpp_stanza_set_type(error, error_type);
|
||||||
|
xmpp_stanza_add_child(reply, error);
|
||||||
|
xmpp_stanza_release(error);
|
||||||
|
|
||||||
|
item = xmpp_stanza_new(ctx);
|
||||||
|
if (!item)
|
||||||
|
goto quit_err;
|
||||||
|
xmpp_stanza_set_name(item, condition);
|
||||||
|
xmpp_stanza_set_ns(item, XMPP_NS_STANZAS_IETF);
|
||||||
|
xmpp_stanza_add_child(error, item);
|
||||||
|
xmpp_stanza_release(item);
|
||||||
|
|
||||||
|
if (text) {
|
||||||
|
item = xmpp_stanza_new(ctx);
|
||||||
|
if (!item)
|
||||||
|
goto quit_err;
|
||||||
|
xmpp_stanza_set_name(item, "text");
|
||||||
|
xmpp_stanza_set_ns(item, XMPP_NS_STANZAS_IETF);
|
||||||
|
xmpp_stanza_add_child(error, item);
|
||||||
|
xmpp_stanza_release(item);
|
||||||
|
text_stanza = xmpp_stanza_new(ctx);
|
||||||
|
if (!text_stanza)
|
||||||
|
goto quit_err;
|
||||||
|
xmpp_stanza_set_text(text_stanza, text);
|
||||||
|
xmpp_stanza_add_child(item, text_stanza);
|
||||||
|
xmpp_stanza_release(text_stanza);
|
||||||
|
}
|
||||||
|
|
||||||
|
return reply;
|
||||||
|
|
||||||
|
quit_err:
|
||||||
|
if (reply)
|
||||||
|
xmpp_stanza_release(reply);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static xmpp_stanza_t *_stanza_new_with_attrs(xmpp_ctx_t *ctx,
|
||||||
|
const char *const name,
|
||||||
|
const char *const type,
|
||||||
|
const char *const id,
|
||||||
const char *const to)
|
const char *const to)
|
||||||
{
|
{
|
||||||
xmpp_stanza_t *stanza = xmpp_stanza_new(ctx);
|
xmpp_stanza_t *stanza = xmpp_stanza_new(ctx);
|
||||||
@@ -1110,8 +1313,10 @@ _stanza_new_with_attrs(xmpp_ctx_t *ctx, const char * const name,
|
|||||||
*
|
*
|
||||||
* @ingroup Stanza
|
* @ingroup Stanza
|
||||||
*/
|
*/
|
||||||
xmpp_stanza_t *xmpp_message_new(xmpp_ctx_t *ctx, const char * const type,
|
xmpp_stanza_t *xmpp_message_new(xmpp_ctx_t *ctx,
|
||||||
const char * const to, const char * const id)
|
const char *const type,
|
||||||
|
const char *const to,
|
||||||
|
const char *const id)
|
||||||
{
|
{
|
||||||
return _stanza_new_with_attrs(ctx, "message", type, id, to);
|
return _stanza_new_with_attrs(ctx, "message", type, id, to);
|
||||||
}
|
}
|
||||||
@@ -1196,8 +1401,8 @@ int xmpp_message_set_body(xmpp_stanza_t *msg, const char * const text)
|
|||||||
*
|
*
|
||||||
* @ingroup Stanza
|
* @ingroup Stanza
|
||||||
*/
|
*/
|
||||||
xmpp_stanza_t *xmpp_iq_new(xmpp_ctx_t *ctx, const char * const type,
|
xmpp_stanza_t *
|
||||||
const char * const id)
|
xmpp_iq_new(xmpp_ctx_t *ctx, const char *const type, const char *const id)
|
||||||
{
|
{
|
||||||
return _stanza_new_with_attrs(ctx, "iq", type, id, NULL);
|
return _stanza_new_with_attrs(ctx, "iq", type, id, NULL);
|
||||||
}
|
}
|
||||||
@@ -1214,3 +1419,180 @@ 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _stub_stream_start(char *name, char **attrs, void *userdata)
|
||||||
|
{
|
||||||
|
UNUSED(name);
|
||||||
|
UNUSED(attrs);
|
||||||
|
UNUSED(userdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _stub_stream_end(char *name, void *userdata)
|
||||||
|
{
|
||||||
|
UNUSED(name);
|
||||||
|
UNUSED(userdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _stream_stanza(xmpp_stanza_t *stanza, void *userdata)
|
||||||
|
{
|
||||||
|
stanza = xmpp_stanza_clone(stanza);
|
||||||
|
*(xmpp_stanza_t **)userdata = stanza;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Create a stanza object from the string.
|
||||||
|
* This function allocates and initializes a stanza object which represents
|
||||||
|
* stanza located in the string.
|
||||||
|
* The stanza will have a reference count of one, so the caller does not
|
||||||
|
* need to clone it.
|
||||||
|
*
|
||||||
|
* @param ctx a Strophe context object
|
||||||
|
* @param str stanza in NULL terminated string representation
|
||||||
|
*
|
||||||
|
* @return a stanza object or NULL on an error
|
||||||
|
*
|
||||||
|
* @ingroup Stanza
|
||||||
|
*/
|
||||||
|
xmpp_stanza_t *xmpp_stanza_new_from_string(xmpp_ctx_t *ctx, const char *str)
|
||||||
|
{
|
||||||
|
xmpp_stanza_t *stanza = NULL;
|
||||||
|
parser_t *parser;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
static const char *start = "<stream>";
|
||||||
|
static const char *end = "</stream>";
|
||||||
|
|
||||||
|
parser = parser_new(ctx, _stub_stream_start, _stub_stream_end,
|
||||||
|
_stream_stanza, &stanza);
|
||||||
|
if (parser) {
|
||||||
|
ret = parser_feed(parser, (char *)start, strlen(start)) &&
|
||||||
|
parser_feed(parser, (char *)str, strlen(str)) &&
|
||||||
|
parser_feed(parser, (char *)end, strlen(end));
|
||||||
|
parser_free(parser);
|
||||||
|
if (!ret && stanza) {
|
||||||
|
xmpp_stanza_release(stanza);
|
||||||
|
stanza = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return stanza;
|
||||||
|
}
|
||||||
|
|||||||
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,59 +33,75 @@ 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)
|
||||||
{
|
{
|
||||||
|
UNUSED(conn);
|
||||||
/* always fail */
|
/* always fail */
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void tls_free(tls_t *tls)
|
void tls_free(tls_t *tls)
|
||||||
{
|
{
|
||||||
|
UNUSED(tls);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tls_set_credentials(tls_t *tls, const char *cafilename)
|
int tls_set_credentials(tls_t *tls, const char *cafilename)
|
||||||
{
|
{
|
||||||
|
UNUSED(tls);
|
||||||
|
UNUSED(cafilename);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tls_start(tls_t *tls)
|
int tls_start(tls_t *tls)
|
||||||
{
|
{
|
||||||
|
UNUSED(tls);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tls_stop(tls_t *tls)
|
int tls_stop(tls_t *tls)
|
||||||
{
|
{
|
||||||
|
UNUSED(tls);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tls_error(tls_t *tls)
|
int tls_error(tls_t *tls)
|
||||||
{
|
{
|
||||||
|
UNUSED(tls);
|
||||||
/* todo: some kind of error polling/dump */
|
/* todo: some kind of error polling/dump */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tls_pending(tls_t *tls)
|
int tls_pending(tls_t *tls)
|
||||||
{
|
{
|
||||||
|
UNUSED(tls);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tls_read(tls_t *tls, void *const buff, const size_t len)
|
int tls_read(tls_t *tls, void *const buff, const size_t len)
|
||||||
{
|
{
|
||||||
|
UNUSED(tls);
|
||||||
|
UNUSED(buff);
|
||||||
|
UNUSED(len);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tls_write(tls_t *tls, const void *const buff, const size_t len)
|
int tls_write(tls_t *tls, const void *const buff, const size_t len)
|
||||||
{
|
{
|
||||||
|
UNUSED(tls);
|
||||||
|
UNUSED(buff);
|
||||||
|
UNUSED(len);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tls_clear_pending_write(tls_t *tls)
|
int tls_clear_pending_write(tls_t *tls)
|
||||||
{
|
{
|
||||||
|
UNUSED(tls);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tls_is_recoverable(int error)
|
int tls_is_recoverable(int error)
|
||||||
{
|
{
|
||||||
|
UNUSED(error);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
@@ -79,8 +79,8 @@ int tls_set_credentials(tls_t *tls, const char *cafilename)
|
|||||||
int err;
|
int err;
|
||||||
|
|
||||||
/* set trusted credentials -- takes a .pem filename */
|
/* set trusted credentials -- takes a .pem filename */
|
||||||
err = gnutls_certificate_set_x509_trust_file(tls->cred,
|
err = gnutls_certificate_set_x509_trust_file(tls->cred, cafilename,
|
||||||
cafilename, GNUTLS_X509_FMT_PEM);
|
GNUTLS_X509_FMT_PEM);
|
||||||
if (err >= 0) {
|
if (err >= 0) {
|
||||||
err = gnutls_credentials_set(tls->session, GNUTLS_CRD_CERTIFICATE,
|
err = gnutls_credentials_set(tls->session, GNUTLS_CRD_CERTIFICATE,
|
||||||
tls->cred);
|
tls->cred);
|
||||||
@@ -142,5 +142,6 @@ int tls_write(tls_t *tls, const void * const buff, const size_t len)
|
|||||||
|
|
||||||
int tls_clear_pending_write(tls_t *tls)
|
int tls_clear_pending_write(tls_t *tls)
|
||||||
{
|
{
|
||||||
|
UNUSED(tls);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
@@ -44,18 +62,149 @@ enum {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static void _tls_sock_wait(tls_t *tls, int error);
|
static void _tls_sock_wait(tls_t *tls, int error);
|
||||||
|
static const char *_tls_error_str(int error, const char **tbl, size_t tbl_size);
|
||||||
static void _tls_set_error(tls_t *tls, int error);
|
static void _tls_set_error(tls_t *tls, int error);
|
||||||
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);
|
||||||
|
|
||||||
|
#define TLS_ERROR_STR(error, table) \
|
||||||
|
_tls_error_str(error, table, ARRAY_SIZE(table))
|
||||||
|
|
||||||
|
#define TLS_ERROR_FIELD(x) [x] = #x
|
||||||
|
const char *tls_errors[] = {
|
||||||
|
TLS_ERROR_FIELD(SSL_ERROR_NONE),
|
||||||
|
TLS_ERROR_FIELD(SSL_ERROR_SSL),
|
||||||
|
TLS_ERROR_FIELD(SSL_ERROR_WANT_READ),
|
||||||
|
TLS_ERROR_FIELD(SSL_ERROR_WANT_WRITE),
|
||||||
|
TLS_ERROR_FIELD(SSL_ERROR_WANT_X509_LOOKUP),
|
||||||
|
TLS_ERROR_FIELD(SSL_ERROR_SYSCALL),
|
||||||
|
TLS_ERROR_FIELD(SSL_ERROR_ZERO_RETURN),
|
||||||
|
TLS_ERROR_FIELD(SSL_ERROR_WANT_CONNECT),
|
||||||
|
TLS_ERROR_FIELD(SSL_ERROR_WANT_ACCEPT),
|
||||||
|
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
||||||
|
TLS_ERROR_FIELD(SSL_ERROR_WANT_ASYNC),
|
||||||
|
TLS_ERROR_FIELD(SSL_ERROR_WANT_ASYNC_JOB),
|
||||||
|
#endif
|
||||||
|
#if OPENSSL_VERSION_NUMBER >= 0x10101000L
|
||||||
|
TLS_ERROR_FIELD(SSL_ERROR_WANT_CLIENT_HELLO_CB),
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
const char *cert_errors[] = {
|
||||||
|
TLS_ERROR_FIELD(X509_V_OK),
|
||||||
|
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_UNSPECIFIED),
|
||||||
|
#endif
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_UNABLE_TO_GET_CRL),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_CERT_SIGNATURE_FAILURE),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_CRL_SIGNATURE_FAILURE),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_CERT_NOT_YET_VALID),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_CERT_HAS_EXPIRED),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_CRL_NOT_YET_VALID),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_CRL_HAS_EXPIRED),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_OUT_OF_MEM),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_CERT_CHAIN_TOO_LONG),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_CERT_REVOKED),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_INVALID_CA),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_PATH_LENGTH_EXCEEDED),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_INVALID_PURPOSE),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_CERT_UNTRUSTED),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_CERT_REJECTED),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_SUBJECT_ISSUER_MISMATCH),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_AKID_SKID_MISMATCH),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_KEYUSAGE_NO_CERTSIGN),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_KEYUSAGE_NO_CRL_SIGN),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_INVALID_NON_CA),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_INVALID_EXTENSION),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_INVALID_POLICY_EXTENSION),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_NO_EXPLICIT_POLICY),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_APPLICATION_VERIFICATION),
|
||||||
|
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_DIFFERENT_CRL_SCOPE),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_UNNESTED_RESOURCE),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_PERMITTED_VIOLATION),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_EXCLUDED_VIOLATION),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_SUBTREE_MINMAX),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_UNSUPPORTED_NAME_SYNTAX),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_CRL_PATH_VALIDATION_ERROR),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_SUITE_B_INVALID_VERSION),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_SUITE_B_INVALID_ALGORITHM),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_SUITE_B_INVALID_CURVE),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_HOSTNAME_MISMATCH),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_EMAIL_MISMATCH),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_IP_ADDRESS_MISMATCH),
|
||||||
|
#endif
|
||||||
|
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_PATH_LOOP),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_DANE_NO_MATCH),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_EE_KEY_TOO_SMALL),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_CA_KEY_TOO_SMALL),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_CA_MD_TOO_WEAK),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_INVALID_CALL),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_STORE_LOOKUP),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_NO_VALID_SCTS),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_OCSP_VERIFY_NEEDED),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_OCSP_VERIFY_FAILED),
|
||||||
|
TLS_ERROR_FIELD(X509_V_ERR_OCSP_CERT_UNKNOWN),
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
#undef TLS_ERROR_FIELD
|
||||||
|
|
||||||
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 +212,81 @@ 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, NULL);
|
||||||
|
#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 +298,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,6 +312,8 @@ 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)
|
||||||
{
|
{
|
||||||
|
UNUSED(tls);
|
||||||
|
UNUSED(cafilename);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,6 +321,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 +338,18 @@ 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);
|
||||||
|
if (x509_res == X509_V_OK) {
|
||||||
|
xmpp_debug(tls->ctx, "tls", "Certificate verification passed");
|
||||||
|
} else {
|
||||||
|
xmpp_debug(tls->ctx, "tls",
|
||||||
|
"Certificate verification FAILED, result=%s(%ld)",
|
||||||
|
TLS_ERROR_STR((int)x509_res, cert_errors), x509_res);
|
||||||
|
}
|
||||||
|
_tls_dump_cert_info(tls);
|
||||||
|
|
||||||
|
_tls_set_error(tls, error);
|
||||||
return ret <= 0 ? 0 : 1;
|
return ret <= 0 ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,6 +359,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 +374,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;
|
||||||
@@ -162,10 +389,9 @@ int tls_stop(tls_t *tls)
|
|||||||
|
|
||||||
int tls_is_recoverable(int error)
|
int tls_is_recoverable(int error)
|
||||||
{
|
{
|
||||||
return (error == SSL_ERROR_NONE || error == SSL_ERROR_WANT_READ
|
return (error == SSL_ERROR_NONE || error == SSL_ERROR_WANT_READ ||
|
||||||
|| error == SSL_ERROR_WANT_WRITE
|
error == SSL_ERROR_WANT_WRITE || error == SSL_ERROR_WANT_CONNECT ||
|
||||||
|| error == SSL_ERROR_WANT_CONNECT
|
error == SSL_ERROR_WANT_ACCEPT);
|
||||||
|| error == SSL_ERROR_WANT_ACCEPT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int tls_pending(tls_t *tls)
|
int tls_pending(tls_t *tls)
|
||||||
@@ -195,6 +421,7 @@ int tls_write(tls_t *tls, const void * const buff, const size_t len)
|
|||||||
|
|
||||||
int tls_clear_pending_write(tls_t *tls)
|
int tls_clear_pending_write(tls_t *tls)
|
||||||
{
|
{
|
||||||
|
UNUSED(tls);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,14 +433,18 @@ 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)
|
||||||
FD_SET(tls->sock, &rfds);
|
FD_SET(tls->sock, &rfds);
|
||||||
if (error == SSL_ERROR_WANT_WRITE)
|
if (error == SSL_ERROR_WANT_WRITE)
|
||||||
FD_SET(tls->sock, &wfds);
|
FD_SET(tls->sock, &wfds);
|
||||||
nfds = (error == SSL_ERROR_WANT_READ || error == SSL_ERROR_WANT_WRITE) ?
|
nfds = (error == SSL_ERROR_WANT_READ || error == SSL_ERROR_WANT_WRITE)
|
||||||
tls->sock + 1 : 0;
|
? tls->sock + 1
|
||||||
|
: 0;
|
||||||
do {
|
do {
|
||||||
tv.tv_sec = TLS_TIMEOUT_SEC;
|
tv.tv_sec = TLS_TIMEOUT_SEC;
|
||||||
tv.tv_usec = TLS_TIMEOUT_USEC;
|
tv.tv_usec = TLS_TIMEOUT_USEC;
|
||||||
@@ -221,9 +452,16 @@ static void _tls_sock_wait(tls_t *tls, int error)
|
|||||||
} while (ret == -1 && errno == EINTR);
|
} while (ret == -1 && errno == EINTR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char *_tls_error_str(int error, const char **tbl, size_t tbl_size)
|
||||||
|
{
|
||||||
|
return (error >= 0 && (size_t)error < tbl_size) ? tbl[error] : "UNKNOWN";
|
||||||
|
}
|
||||||
|
|
||||||
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=%s(%d) errno=%d",
|
||||||
|
TLS_ERROR_STR(error, tls_errors), error, errno);
|
||||||
_tls_log_error(tls->ctx);
|
_tls_log_error(tls->ctx);
|
||||||
}
|
}
|
||||||
tls->lasterror = error;
|
tls->lasterror = error;
|
||||||
@@ -242,3 +480,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"))) {
|
||||||
@@ -114,8 +118,7 @@ tls_t *tls_new(xmpp_ctx_t *ctx, sock_t sock)
|
|||||||
|
|
||||||
ret = tls->sft->QuerySecurityPackageInfo(UNISP_NAME, &(tls->spi));
|
ret = tls->sft->QuerySecurityPackageInfo(UNISP_NAME, &(tls->spi));
|
||||||
|
|
||||||
if (ret != SEC_E_OK)
|
if (ret != SEC_E_OK) {
|
||||||
{
|
|
||||||
tls_free(tls);
|
tls_free(tls);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -136,11 +139,11 @@ tls_t *tls_new(xmpp_ctx_t *ctx, sock_t sock)
|
|||||||
(void)algs;
|
(void)algs;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ret = tls->sft->AcquireCredentialsHandleA(NULL, UNISP_NAME,
|
ret = tls->sft->AcquireCredentialsHandleA(
|
||||||
SECPKG_CRED_OUTBOUND, NULL, &scred, NULL, NULL, &(tls->hcred), NULL);
|
NULL, UNISP_NAME, SECPKG_CRED_OUTBOUND, NULL, &scred, NULL, NULL,
|
||||||
|
&(tls->hcred), NULL);
|
||||||
|
|
||||||
if (ret != SEC_E_OK)
|
if (ret != SEC_E_OK) {
|
||||||
{
|
|
||||||
tls_free(tls);
|
tls_free(tls);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -151,23 +154,23 @@ tls_t *tls_new(xmpp_ctx_t *ctx, sock_t sock)
|
|||||||
|
|
||||||
/* This bunch of queries should trip up wine until someone fixes
|
/* This bunch of queries should trip up wine until someone fixes
|
||||||
* schannel support there */
|
* schannel support there */
|
||||||
ret = tls->sft->QueryCredentialsAttributes(&(tls->hcred), SECPKG_ATTR_SUPPORTED_ALGS, &spc_sa);
|
ret = tls->sft->QueryCredentialsAttributes(
|
||||||
if (ret != SEC_E_OK)
|
&(tls->hcred), SECPKG_ATTR_SUPPORTED_ALGS, &spc_sa);
|
||||||
{
|
if (ret != SEC_E_OK) {
|
||||||
tls_free(tls);
|
tls_free(tls);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = tls->sft->QueryCredentialsAttributes(&(tls->hcred), SECPKG_ATTR_CIPHER_STRENGTHS, &spc_cs);
|
ret = tls->sft->QueryCredentialsAttributes(
|
||||||
if (ret != SEC_E_OK)
|
&(tls->hcred), SECPKG_ATTR_CIPHER_STRENGTHS, &spc_cs);
|
||||||
{
|
if (ret != SEC_E_OK) {
|
||||||
tls_free(tls);
|
tls_free(tls);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = tls->sft->QueryCredentialsAttributes(&(tls->hcred), SECPKG_ATTR_SUPPORTED_PROTOCOLS, &spc_sp);
|
ret = tls->sft->QueryCredentialsAttributes(
|
||||||
if (ret != SEC_E_OK)
|
&(tls->hcred), SECPKG_ATTR_SUPPORTED_PROTOCOLS, &spc_sp);
|
||||||
{
|
if (ret != SEC_E_OK) {
|
||||||
tls_free(tls);
|
tls_free(tls);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -206,6 +209,8 @@ 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)
|
||||||
{
|
{
|
||||||
|
UNUSED(tls);
|
||||||
|
UNUSED(cafilename);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,29 +221,15 @@ 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) {
|
ctxtreq = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT |
|
||||||
xmpp_conn_t *conn = listentry->conn;
|
ISC_REQ_CONFIDENTIALITY | ISC_RET_EXTENDED_ERROR |
|
||||||
|
ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM |
|
||||||
if (conn->sock == tls->sock) {
|
ISC_REQ_MANUAL_CRED_VALIDATION | ISC_REQ_INTEGRITY;
|
||||||
name = strdup(conn->domain);
|
|
||||||
listentry = NULL;
|
|
||||||
} else {
|
|
||||||
listentry = listentry->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ctxtreq = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT
|
|
||||||
| ISC_REQ_CONFIDENTIALITY | ISC_RET_EXTENDED_ERROR
|
|
||||||
| ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM
|
|
||||||
| ISC_REQ_MANUAL_CRED_VALIDATION | ISC_REQ_INTEGRITY;
|
|
||||||
|
|
||||||
memset(&(sbout[0]), 0, sizeof(sbout[0]));
|
memset(&(sbout[0]), 0, sizeof(sbout[0]));
|
||||||
sbout[0].BufferType = SECBUFFER_TOKEN;
|
sbout[0].BufferType = SECBUFFER_TOKEN;
|
||||||
@@ -261,14 +252,22 @@ int tls_start(tls_t *tls)
|
|||||||
sbdin.cBuffers = 2;
|
sbdin.cBuffers = 2;
|
||||||
sbdin.pBuffers = sbin;
|
sbdin.pBuffers = sbin;
|
||||||
|
|
||||||
ret = tls->sft->InitializeSecurityContextA(&(tls->hcred), NULL, name, ctxtreq, 0, 0,
|
ret = tls->sft->InitializeSecurityContextA(
|
||||||
NULL, 0, &(tls->hctxt), &sbdout,
|
&(tls->hcred), NULL, name, ctxtreq, 0, 0, NULL, 0, &(tls->hctxt),
|
||||||
&ctxtattr, NULL);
|
&sbdout, &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;
|
||||||
@@ -277,9 +276,7 @@ int tls_start(tls_t *tls)
|
|||||||
sent = sock_write(tls->sock, writebuff, writelen);
|
sent = sock_write(tls->sock, writebuff, writelen);
|
||||||
if (sent == -1) {
|
if (sent == -1) {
|
||||||
tls->lasterror = sock_error();
|
tls->lasterror = sock_error();
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
writebuff += sent;
|
writebuff += sent;
|
||||||
writelen -= sent;
|
writelen -= sent;
|
||||||
}
|
}
|
||||||
@@ -321,20 +318,16 @@ int tls_start(tls_t *tls)
|
|||||||
if (inbytes > 0) {
|
if (inbytes > 0) {
|
||||||
len += inbytes;
|
len += inbytes;
|
||||||
p += inbytes;
|
p += inbytes;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
tls->lasterror = sock_error();
|
tls->lasterror = sock_error();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sbin[0].cbBuffer = len;
|
sbin[0].cbBuffer = len;
|
||||||
|
|
||||||
ret = tls->sft->InitializeSecurityContextA(&(tls->hcred), &(tls->hctxt), name,
|
ret = tls->sft->InitializeSecurityContextA(
|
||||||
ctxtreq, 0, 0, &sbdin, 0,
|
&(tls->hcred), &(tls->hctxt), name, ctxtreq, 0, 0, &sbdin, 0,
|
||||||
&(tls->hctxt), &sbdout,
|
&(tls->hctxt), &sbdout, &ctxtattr, NULL);
|
||||||
&ctxtattr, NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret == SEC_E_OK) {
|
if (ret == SEC_E_OK) {
|
||||||
@@ -344,9 +337,7 @@ int tls_start(tls_t *tls)
|
|||||||
sent = sock_write(tls->sock, writebuff, writelen);
|
sent = sock_write(tls->sock, writebuff, writelen);
|
||||||
if (sent == -1) {
|
if (sent == -1) {
|
||||||
tls->lasterror = sock_error();
|
tls->lasterror = sock_error();
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
writebuff += sent;
|
writebuff += sent;
|
||||||
writelen -= sent;
|
writelen -= sent;
|
||||||
}
|
}
|
||||||
@@ -360,20 +351,21 @@ int tls_start(tls_t *tls)
|
|||||||
|
|
||||||
if (ret != SEC_E_OK) {
|
if (ret != SEC_E_OK) {
|
||||||
tls->lasterror = ret;
|
tls->lasterror = ret;
|
||||||
xmpp_error(tls->ctx, "TLSS", "Schannel error 0x%lx", (unsigned long)ret);
|
xmpp_error(tls->ctx, "TLSS", "Schannel error 0x%lx",
|
||||||
|
(unsigned long)ret);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
tls->sft->QueryContextAttributes(&(tls->hctxt), SECPKG_ATTR_STREAM_SIZES,
|
tls->sft->QueryContextAttributes(&(tls->hctxt), SECPKG_ATTR_STREAM_SIZES,
|
||||||
&(tls->spcss));
|
&(tls->spcss));
|
||||||
|
|
||||||
tls->recvbuffermaxlen = tls->spcss.cbHeader + tls->spcss.cbMaximumMessage
|
tls->recvbuffermaxlen = tls->spcss.cbHeader + tls->spcss.cbMaximumMessage +
|
||||||
+ tls->spcss.cbTrailer;
|
tls->spcss.cbTrailer;
|
||||||
tls->recvbuffer = xmpp_alloc(tls->ctx, tls->recvbuffermaxlen);
|
tls->recvbuffer = xmpp_alloc(tls->ctx, tls->recvbuffermaxlen);
|
||||||
tls->recvbufferpos = 0;
|
tls->recvbufferpos = 0;
|
||||||
|
|
||||||
tls->sendbuffermaxlen = tls->spcss.cbHeader + tls->spcss.cbMaximumMessage
|
tls->sendbuffermaxlen = tls->spcss.cbHeader + tls->spcss.cbMaximumMessage +
|
||||||
+ tls->spcss.cbTrailer;
|
tls->spcss.cbTrailer;
|
||||||
tls->sendbuffer = xmpp_alloc(tls->ctx, tls->sendbuffermaxlen);
|
tls->sendbuffer = xmpp_alloc(tls->ctx, tls->sendbuffermaxlen);
|
||||||
tls->sendbufferpos = 0;
|
tls->sendbufferpos = 0;
|
||||||
tls->sendbufferlen = 0;
|
tls->sendbufferlen = 0;
|
||||||
@@ -387,6 +379,7 @@ int tls_start(tls_t *tls)
|
|||||||
|
|
||||||
int tls_stop(tls_t *tls)
|
int tls_stop(tls_t *tls)
|
||||||
{
|
{
|
||||||
|
UNUSED(tls);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -397,12 +390,13 @@ int tls_error(tls_t *tls)
|
|||||||
|
|
||||||
int tls_is_recoverable(int error)
|
int tls_is_recoverable(int error)
|
||||||
{
|
{
|
||||||
return (error == SEC_E_OK || error == SEC_E_INCOMPLETE_MESSAGE
|
return (error == SEC_E_OK || error == SEC_E_INCOMPLETE_MESSAGE ||
|
||||||
|| error == WSAEWOULDBLOCK || error == WSAEMSGSIZE
|
error == WSAEWOULDBLOCK || error == WSAEMSGSIZE ||
|
||||||
|| error == WSAEINPROGRESS);
|
error == WSAEINPROGRESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
int tls_pending(tls_t *tls) {
|
int tls_pending(tls_t *tls)
|
||||||
|
{
|
||||||
// There are 3 cases:
|
// There are 3 cases:
|
||||||
// - there is data in ready buffer, so it is by default pending
|
// - there is data in ready buffer, so it is by default pending
|
||||||
// - there is data in recv buffer. If it is not decrypted yet, means it
|
// - there is data in recv buffer. If it is not decrypted yet, means it
|
||||||
@@ -423,8 +417,7 @@ int tls_read(tls_t *tls, void * const buff, const size_t len)
|
|||||||
int bytes;
|
int bytes;
|
||||||
|
|
||||||
/* first, if we've got some ready data, put that in the buffer */
|
/* first, if we've got some ready data, put that in the buffer */
|
||||||
if (tls->readybufferpos < tls->readybufferlen)
|
if (tls->readybufferpos < tls->readybufferlen) {
|
||||||
{
|
|
||||||
if (len < tls->readybufferlen - tls->readybufferpos) {
|
if (len < tls->readybufferlen - tls->readybufferpos) {
|
||||||
bytes = len;
|
bytes = len;
|
||||||
} else {
|
} else {
|
||||||
@@ -521,8 +514,7 @@ int tls_read(tls_t *tls, void * const buff, const size_t len)
|
|||||||
return -1;
|
return -1;
|
||||||
} else if (ret == SEC_I_RENEGOTIATE) {
|
} else if (ret == SEC_I_RENEGOTIATE) {
|
||||||
ret = tls_start(tls);
|
ret = tls_start(tls);
|
||||||
if (!ret)
|
if (!ret) {
|
||||||
{
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -544,8 +536,7 @@ int tls_read(tls_t *tls, void * const buff, const size_t len)
|
|||||||
|
|
||||||
int tls_clear_pending_write(tls_t *tls)
|
int tls_clear_pending_write(tls_t *tls)
|
||||||
{
|
{
|
||||||
if (tls->sendbufferpos < tls->sendbufferlen)
|
if (tls->sendbufferpos < tls->sendbufferlen) {
|
||||||
{
|
|
||||||
int bytes;
|
int bytes;
|
||||||
|
|
||||||
bytes = sock_write(tls->sock, tls->sendbuffer + tls->sendbufferpos,
|
bytes = sock_write(tls->sock, tls->sendbuffer + tls->sendbufferpos,
|
||||||
@@ -603,23 +594,22 @@ int tls_write(tls_t *tls, const void * const buff, const size_t len)
|
|||||||
|
|
||||||
sbenc[1].pvBuffer = tls->sendbuffer + tls->spcss.cbHeader;
|
sbenc[1].pvBuffer = tls->sendbuffer + tls->spcss.cbHeader;
|
||||||
|
|
||||||
while (remain > 0)
|
while (remain > 0) {
|
||||||
{
|
|
||||||
if (remain > tls->spcss.cbMaximumMessage) {
|
if (remain > tls->spcss.cbMaximumMessage) {
|
||||||
sbenc[1].cbBuffer = tls->spcss.cbMaximumMessage;
|
sbenc[1].cbBuffer = tls->spcss.cbMaximumMessage;
|
||||||
} else {
|
} else {
|
||||||
sbenc[1].cbBuffer = remain;
|
sbenc[1].cbBuffer = remain;
|
||||||
}
|
}
|
||||||
|
|
||||||
sbenc[2].pvBuffer = (unsigned char *)sbenc[1].pvBuffer
|
sbenc[2].pvBuffer =
|
||||||
+ sbenc[1].cbBuffer;
|
(unsigned char *)sbenc[1].pvBuffer + sbenc[1].cbBuffer;
|
||||||
sbenc[2].cbBuffer = tls->spcss.cbTrailer;
|
sbenc[2].cbBuffer = tls->spcss.cbTrailer;
|
||||||
|
|
||||||
memcpy(sbenc[1].pvBuffer, p, sbenc[1].cbBuffer);
|
memcpy(sbenc[1].pvBuffer, p, sbenc[1].cbBuffer);
|
||||||
p += tls->spcss.cbMaximumMessage;
|
p += tls->spcss.cbMaximumMessage;
|
||||||
|
|
||||||
tls->sendbufferlen = sbenc[0].cbBuffer + sbenc[1].cbBuffer
|
tls->sendbufferlen =
|
||||||
+ sbenc[2].cbBuffer;
|
sbenc[0].cbBuffer + sbenc[1].cbBuffer + sbenc[2].cbBuffer;
|
||||||
|
|
||||||
ret = tls->sft->EncryptMessage(&(tls->hctxt), 0, &sbdenc, 0);
|
ret = tls->sft->EncryptMessage(&(tls->hctxt), 0, &sbdenc, 0);
|
||||||
|
|
||||||
@@ -647,7 +637,6 @@ int tls_write(tls_t *tls, const void * const buff, const size_t len)
|
|||||||
if (ret == 0 || (ret == -1 && tls_is_recoverable(tls_error(tls)))) {
|
if (ret == 0 || (ret == -1 && tls_is_recoverable(tls_error(tls)))) {
|
||||||
return sent;
|
return sent;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return sent;
|
return sent;
|
||||||
|
|||||||
36
src/util.c
36
src/util.c
@@ -86,8 +86,24 @@ 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(_WIN32) || defined(_XBOX_ONE)
|
||||||
return timeGetTime();
|
|
||||||
|
#ifndef __GNUC__
|
||||||
|
#define EPOCHFILETIME (116444736000000000i64)
|
||||||
|
#else
|
||||||
|
#define EPOCHFILETIME (116444736000000000LL)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
FILETIME ft;
|
||||||
|
LARGE_INTEGER li;
|
||||||
|
__int64 t;
|
||||||
|
|
||||||
|
GetSystemTimeAsFileTime(&ft);
|
||||||
|
li.LowPart = ft.dwLowDateTime;
|
||||||
|
li.HighPart = ft.dwHighDateTime;
|
||||||
|
t = li.QuadPart; /* In 100-nanosecond intervals */
|
||||||
|
t -= EPOCHFILETIME; /* Offset to the Epoch time */
|
||||||
|
return (uint64_t)(t / 10000); /* Convert to milliseconds */
|
||||||
#else
|
#else
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
|
|
||||||
@@ -112,6 +128,20 @@ uint64_t time_elapsed(uint64_t t1, uint64_t t2)
|
|||||||
return (uint64_t)(t2 - t1);
|
return (uint64_t)(t2 - t1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Disconnect the stream with the error.
|
||||||
|
* This is a convenience function used internally by various parts of
|
||||||
|
* the Strophe library for terminating the connection because of an error.
|
||||||
|
*
|
||||||
|
* @param conn a Strophe connection object
|
||||||
|
* @param error an error code
|
||||||
|
*/
|
||||||
|
void disconnect_with_error(xmpp_conn_t *const conn, int error)
|
||||||
|
{
|
||||||
|
xmpp_error(conn->ctx, "xmpp", "Disconnecting with error %d", error);
|
||||||
|
conn->error = conn->error ?: error;
|
||||||
|
xmpp_disconnect(conn);
|
||||||
|
}
|
||||||
|
|
||||||
/** Disconnect the stream with a memory error.
|
/** Disconnect the stream with a memory error.
|
||||||
* This is a convenience function used internally by various parts of
|
* This is a convenience function used internally by various parts of
|
||||||
* the Strophe library for terminating the connection because of a
|
* the Strophe library for terminating the connection because of a
|
||||||
@@ -122,5 +152,5 @@ uint64_t time_elapsed(uint64_t t1, uint64_t t2)
|
|||||||
void disconnect_mem_error(xmpp_conn_t *const conn)
|
void disconnect_mem_error(xmpp_conn_t *const conn)
|
||||||
{
|
{
|
||||||
xmpp_error(conn->ctx, "xmpp", "Memory allocation error");
|
xmpp_error(conn->ctx, "xmpp", "Memory allocation error");
|
||||||
xmpp_disconnect(conn);
|
disconnect_with_error(conn, XMPP_EMEM);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,10 @@
|
|||||||
|
|
||||||
#include "ostypes.h"
|
#include "ostypes.h"
|
||||||
|
|
||||||
|
#ifndef ARRAY_SIZE
|
||||||
|
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
|
||||||
|
#endif /* ARRAY_SIZE */
|
||||||
|
|
||||||
/* TODO evaluate x and y only once */
|
/* TODO evaluate x and y only once */
|
||||||
#define xmpp_min(x, y) ((x) < (y) ? (x) : (y))
|
#define xmpp_min(x, y) ((x) < (y) ? (x) : (y))
|
||||||
|
|
||||||
|
|||||||
141
strophe.h
141
strophe.h
@@ -39,6 +39,10 @@ extern "C" {
|
|||||||
* Namespace definition for 'urn:ietf:params:xml:ns:xmpp-streams'.
|
* Namespace definition for 'urn:ietf:params:xml:ns:xmpp-streams'.
|
||||||
*/
|
*/
|
||||||
#define XMPP_NS_STREAMS_IETF "urn:ietf:params:xml:ns:xmpp-streams"
|
#define XMPP_NS_STREAMS_IETF "urn:ietf:params:xml:ns:xmpp-streams"
|
||||||
|
/** @def XMPP_NS_STANZAS_IETF
|
||||||
|
* Namespace definition for 'urn:ietf:params:xml:ns:xmpp-stanzas'.
|
||||||
|
*/
|
||||||
|
#define XMPP_NS_STANZAS_IETF "urn:ietf:params:xml:ns:xmpp-stanzas"
|
||||||
/** @def XMPP_NS_TLS
|
/** @def XMPP_NS_TLS
|
||||||
* Namespace definition for 'url:ietf:params:xml:ns:xmpp-tls'.
|
* Namespace definition for 'url:ietf:params:xml:ns:xmpp-tls'.
|
||||||
*/
|
*/
|
||||||
@@ -71,6 +75,10 @@ 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"
|
||||||
|
|
||||||
/* error defines */
|
/* error defines */
|
||||||
/** @def XMPP_EOK
|
/** @def XMPP_EOK
|
||||||
@@ -95,6 +103,26 @@ extern "C" {
|
|||||||
* Internal failure error code.
|
* Internal failure error code.
|
||||||
*/
|
*/
|
||||||
#define XMPP_EINT -3
|
#define XMPP_EINT -3
|
||||||
|
/** @def XMPP_ECERT
|
||||||
|
* Certificate verification failed during TLS establishment.
|
||||||
|
*/
|
||||||
|
#define XMPP_ECERT -4
|
||||||
|
/** @def XMPP_ETIMEDOUT
|
||||||
|
* Operation timed out error code.
|
||||||
|
*/
|
||||||
|
#define XMPP_ETIMEDOUT -5
|
||||||
|
/** @def XMPP_EIO
|
||||||
|
* I/O error code.
|
||||||
|
*/
|
||||||
|
#define XMPP_EIO -6
|
||||||
|
/** @def XMPP_ERESET
|
||||||
|
* Error code for situation when connection closed by remote side.
|
||||||
|
*/
|
||||||
|
#define XMPP_ERESET -7
|
||||||
|
/** @def XMPP_EAUTH
|
||||||
|
* Authentication failed error code.
|
||||||
|
*/
|
||||||
|
#define XMPP_EAUTH -8
|
||||||
|
|
||||||
/* initialization and shutdown */
|
/* initialization and shutdown */
|
||||||
void xmpp_initialize(void);
|
void xmpp_initialize(void);
|
||||||
@@ -136,11 +164,7 @@ typedef enum {
|
|||||||
XMPP_LEVEL_ERROR
|
XMPP_LEVEL_ERROR
|
||||||
} xmpp_log_level_t;
|
} xmpp_log_level_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum { XMPP_UNKNOWN, XMPP_CLIENT, XMPP_COMPONENT } xmpp_conn_type_t;
|
||||||
XMPP_UNKNOWN,
|
|
||||||
XMPP_CLIENT,
|
|
||||||
XMPP_COMPONENT
|
|
||||||
} xmpp_conn_type_t;
|
|
||||||
|
|
||||||
typedef void (*xmpp_log_handler)(void *const userdata,
|
typedef void (*xmpp_log_handler)(void *const userdata,
|
||||||
const xmpp_log_level_t level,
|
const xmpp_log_level_t level,
|
||||||
@@ -165,6 +189,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 +245,9 @@ 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);
|
||||||
@@ -227,7 +262,12 @@ void xmpp_conn_set_pass(xmpp_conn_t * const conn, const char * const pass);
|
|||||||
xmpp_ctx_t *xmpp_conn_get_context(xmpp_conn_t *const conn);
|
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,
|
||||||
@@ -235,8 +275,10 @@ int xmpp_connect_client(xmpp_conn_t * const conn,
|
|||||||
xmpp_conn_handler callback,
|
xmpp_conn_handler callback,
|
||||||
void *const userdata);
|
void *const userdata);
|
||||||
|
|
||||||
int xmpp_connect_component(xmpp_conn_t * const conn, const char * const server,
|
int xmpp_connect_component(xmpp_conn_t *const conn,
|
||||||
unsigned short port, xmpp_conn_handler callback,
|
const char *const server,
|
||||||
|
unsigned short port,
|
||||||
|
xmpp_conn_handler callback,
|
||||||
void *const userdata);
|
void *const userdata);
|
||||||
|
|
||||||
int xmpp_connect_raw(xmpp_conn_t *const conn,
|
int xmpp_connect_raw(xmpp_conn_t *const conn,
|
||||||
@@ -245,24 +287,23 @@ int xmpp_connect_raw(xmpp_conn_t * const conn,
|
|||||||
xmpp_conn_handler callback,
|
xmpp_conn_handler callback,
|
||||||
void *const userdata);
|
void *const userdata);
|
||||||
int xmpp_conn_open_stream_default(xmpp_conn_t *const conn);
|
int xmpp_conn_open_stream_default(xmpp_conn_t *const conn);
|
||||||
int xmpp_conn_open_stream(xmpp_conn_t * const conn, char **attributes,
|
int xmpp_conn_open_stream(xmpp_conn_t *const conn,
|
||||||
|
char **attributes,
|
||||||
size_t attributes_len);
|
size_t attributes_len);
|
||||||
int xmpp_conn_tls_start(xmpp_conn_t *const conn);
|
int xmpp_conn_tls_start(xmpp_conn_t *const conn);
|
||||||
|
|
||||||
void xmpp_disconnect(xmpp_conn_t *const conn);
|
void xmpp_disconnect(xmpp_conn_t *const conn);
|
||||||
|
|
||||||
void xmpp_send(xmpp_conn_t * const conn,
|
void xmpp_send(xmpp_conn_t *const conn, xmpp_stanza_t *const stanza);
|
||||||
xmpp_stanza_t * const stanza);
|
|
||||||
|
|
||||||
void xmpp_send_raw_string(xmpp_conn_t * const conn,
|
void xmpp_send_raw_string(xmpp_conn_t *const conn, const char *const fmt, ...);
|
||||||
const char * const fmt, ...);
|
|
||||||
void xmpp_send_raw(xmpp_conn_t *const conn,
|
void xmpp_send_raw(xmpp_conn_t *const conn,
|
||||||
const char * const data, const size_t len);
|
const char *const data,
|
||||||
|
const size_t len);
|
||||||
|
|
||||||
/* handlers */
|
/* handlers */
|
||||||
|
|
||||||
/* if the handle returns false it is removed */
|
/* if the handler returns false it is removed */
|
||||||
typedef int (*xmpp_timed_handler)(xmpp_conn_t *const conn,
|
typedef int (*xmpp_timed_handler)(xmpp_conn_t *const conn,
|
||||||
void *const userdata);
|
void *const userdata);
|
||||||
|
|
||||||
@@ -273,6 +314,16 @@ void xmpp_timed_handler_add(xmpp_conn_t * const conn,
|
|||||||
void xmpp_timed_handler_delete(xmpp_conn_t *const conn,
|
void xmpp_timed_handler_delete(xmpp_conn_t *const conn,
|
||||||
xmpp_timed_handler handler);
|
xmpp_timed_handler handler);
|
||||||
|
|
||||||
|
/* if the handler returns false it is removed */
|
||||||
|
typedef int (*xmpp_global_timed_handler)(xmpp_ctx_t *const ctx,
|
||||||
|
void *const userdata);
|
||||||
|
|
||||||
|
void xmpp_global_timed_handler_add(xmpp_ctx_t *const ctx,
|
||||||
|
xmpp_global_timed_handler handler,
|
||||||
|
const unsigned long period,
|
||||||
|
void *const userdata);
|
||||||
|
void xmpp_global_timed_handler_delete(xmpp_ctx_t *const ctx,
|
||||||
|
xmpp_global_timed_handler handler);
|
||||||
|
|
||||||
/* if the handler returns false it is removed */
|
/* if the handler returns false it is removed */
|
||||||
typedef int (*xmpp_handler)(xmpp_conn_t *const conn,
|
typedef int (*xmpp_handler)(xmpp_conn_t *const conn,
|
||||||
@@ -285,8 +336,7 @@ void xmpp_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 xmpp_handler_delete(xmpp_conn_t * const conn,
|
void xmpp_handler_delete(xmpp_conn_t *const conn, xmpp_handler handler);
|
||||||
xmpp_handler handler);
|
|
||||||
|
|
||||||
void xmpp_id_handler_add(xmpp_conn_t *const conn,
|
void xmpp_id_handler_add(xmpp_conn_t *const conn,
|
||||||
xmpp_handler handler,
|
xmpp_handler handler,
|
||||||
@@ -304,6 +354,7 @@ void xmpp_register_stanza_handler(conn, stanza, xmlns, type, handler)
|
|||||||
|
|
||||||
/* allocate and initialize a blank stanza */
|
/* allocate and initialize a blank stanza */
|
||||||
xmpp_stanza_t *xmpp_stanza_new(xmpp_ctx_t *ctx);
|
xmpp_stanza_t *xmpp_stanza_new(xmpp_ctx_t *ctx);
|
||||||
|
xmpp_stanza_t *xmpp_stanza_new_from_string(xmpp_ctx_t *ctx, const char *str);
|
||||||
|
|
||||||
/* clone a stanza */
|
/* clone a stanza */
|
||||||
xmpp_stanza_t *xmpp_stanza_clone(xmpp_stanza_t *const stanza);
|
xmpp_stanza_t *xmpp_stanza_clone(xmpp_stanza_t *const stanza);
|
||||||
@@ -314,26 +365,36 @@ 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);
|
||||||
|
|
||||||
/* marshall a stanza into text for transmission or display */
|
/* marshall a stanza into text for transmission or display */
|
||||||
int xmpp_stanza_to_text(xmpp_stanza_t *stanza,
|
int xmpp_stanza_to_text(xmpp_stanza_t *stanza,
|
||||||
char ** const buf, size_t * const buflen);
|
char **const buf,
|
||||||
|
size_t *const buflen);
|
||||||
|
|
||||||
xmpp_stanza_t *xmpp_stanza_get_children(xmpp_stanza_t *const stanza);
|
xmpp_stanza_t *xmpp_stanza_get_children(xmpp_stanza_t *const stanza);
|
||||||
xmpp_stanza_t *xmpp_stanza_get_child_by_name(xmpp_stanza_t *const stanza,
|
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);
|
||||||
int xmpp_stanza_get_attribute_count(xmpp_stanza_t *const stanza);
|
int xmpp_stanza_get_attribute_count(xmpp_stanza_t *const stanza);
|
||||||
int xmpp_stanza_get_attributes(xmpp_stanza_t *const stanza,
|
int xmpp_stanza_get_attributes(xmpp_stanza_t *const stanza,
|
||||||
const char **attr, int attrlen);
|
const char **attr,
|
||||||
|
int attrlen);
|
||||||
/* concatenate all child text nodes. this function
|
/* concatenate all child text nodes. this function
|
||||||
* returns a string that must be freed by the caller */
|
* returns a string that must be freed by the caller */
|
||||||
char *xmpp_stanza_get_text(xmpp_stanza_t *const stanza);
|
char *xmpp_stanza_get_text(xmpp_stanza_t *const stanza);
|
||||||
@@ -343,10 +404,8 @@ const char *xmpp_stanza_get_name(xmpp_stanza_t * const stanza);
|
|||||||
int xmpp_stanza_set_attribute(xmpp_stanza_t *const stanza,
|
int xmpp_stanza_set_attribute(xmpp_stanza_t *const stanza,
|
||||||
const char *const key,
|
const char *const key,
|
||||||
const char *const value);
|
const char *const value);
|
||||||
int xmpp_stanza_set_name(xmpp_stanza_t *stanza,
|
int xmpp_stanza_set_name(xmpp_stanza_t *stanza, const char *const name);
|
||||||
const char * const name);
|
int xmpp_stanza_set_text(xmpp_stanza_t *stanza, const char *const text);
|
||||||
int xmpp_stanza_set_text(xmpp_stanza_t *stanza,
|
|
||||||
const char * const text);
|
|
||||||
int xmpp_stanza_set_text_with_size(xmpp_stanza_t *stanza,
|
int xmpp_stanza_set_text_with_size(xmpp_stanza_t *stanza,
|
||||||
const char *const text,
|
const char *const text,
|
||||||
const size_t size);
|
const size_t size);
|
||||||
@@ -367,21 +426,31 @@ int xmpp_stanza_set_from(xmpp_stanza_t * const stanza, const char * const from);
|
|||||||
|
|
||||||
/* allocate and initialize a stanza in reply to another */
|
/* allocate and initialize a stanza in reply to another */
|
||||||
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 *xmpp_stanza_reply_error(xmpp_stanza_t *const stanza,
|
||||||
|
const char *const error_type,
|
||||||
|
const char *const condition,
|
||||||
|
const char *const text);
|
||||||
|
|
||||||
/* stanza subclasses */
|
/* stanza subclasses */
|
||||||
xmpp_stanza_t *xmpp_message_new(xmpp_ctx_t *ctx, const char * const type,
|
xmpp_stanza_t *xmpp_message_new(xmpp_ctx_t *ctx,
|
||||||
const char * const to, const char * const id);
|
const char *const type,
|
||||||
|
const char *const to,
|
||||||
|
const char *const id);
|
||||||
char *xmpp_message_get_body(xmpp_stanza_t *msg);
|
char *xmpp_message_get_body(xmpp_stanza_t *msg);
|
||||||
int xmpp_message_set_body(xmpp_stanza_t *msg, const char *const text);
|
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 *
|
||||||
const char * const id);
|
xmpp_iq_new(xmpp_ctx_t *ctx, const char *const type, 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 */
|
||||||
|
|
||||||
/* these return new strings that must be xmpp_free()'d */
|
/* these return new strings that must be xmpp_free()'d */
|
||||||
char *xmpp_jid_new(xmpp_ctx_t *ctx, const char *node,
|
char *xmpp_jid_new(xmpp_ctx_t *ctx,
|
||||||
|
const char *node,
|
||||||
const char *domain,
|
const char *domain,
|
||||||
const char *resource);
|
const char *resource);
|
||||||
char *xmpp_jid_bare(xmpp_ctx_t *ctx, const char *jid);
|
char *xmpp_jid_bare(xmpp_ctx_t *ctx, const char *jid);
|
||||||
@@ -394,6 +463,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 +479,9 @@ 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);
|
||||||
@@ -420,10 +493,14 @@ void xmpp_sha1_to_digest(xmpp_sha1_t *sha1, unsigned char *digest);
|
|||||||
|
|
||||||
/* Base64 */
|
/* Base64 */
|
||||||
|
|
||||||
char *xmpp_base64_encode(xmpp_ctx_t *ctx, const unsigned char *data, size_t len);
|
char *
|
||||||
|
xmpp_base64_encode(xmpp_ctx_t *ctx, const unsigned char *data, size_t len);
|
||||||
char *xmpp_base64_decode_str(xmpp_ctx_t *ctx, const char *base64, size_t len);
|
char *xmpp_base64_decode_str(xmpp_ctx_t *ctx, const char *base64, size_t len);
|
||||||
void xmpp_base64_decode_bin(xmpp_ctx_t *ctx, const char *base64, size_t len,
|
void xmpp_base64_decode_bin(xmpp_ctx_t *ctx,
|
||||||
unsigned char **out, size_t *outlen);
|
const char *base64,
|
||||||
|
size_t len,
|
||||||
|
unsigned char **out,
|
||||||
|
size_t *outlen);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
133
strophepp.h
133
strophepp.h
@@ -1,133 +0,0 @@
|
|||||||
/* strophepp.h
|
|
||||||
** strophe XMPP client library C++ API
|
|
||||||
**
|
|
||||||
** 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
|
|
||||||
* Strophe public C++ API definitions.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __LIBSTROPHE_STROPHEPP_H__
|
|
||||||
#define __LIBSTROPHE_STROPHEPP_H__
|
|
||||||
|
|
||||||
#include "strophe.h"
|
|
||||||
|
|
||||||
namespace XMPP {
|
|
||||||
class Context {
|
|
||||||
private:
|
|
||||||
xmpp_mem_t m_mem;
|
|
||||||
xmpp_log_t m_log;
|
|
||||||
xmpp_ctx_t *m_ctx;
|
|
||||||
|
|
||||||
public:
|
|
||||||
Context();
|
|
||||||
virtual ~Context();
|
|
||||||
|
|
||||||
virtual void *alloc(const size_t size);
|
|
||||||
virtual void *realloc(void *p, const size_t size);
|
|
||||||
virtual void free(void *p);
|
|
||||||
virtual void log(const xmpp_log_level_t level,
|
|
||||||
const char * const area,
|
|
||||||
const char * const msg);
|
|
||||||
|
|
||||||
xmpp_ctx_t *getContext();
|
|
||||||
|
|
||||||
private:
|
|
||||||
static void *callAlloc(const size_t size, void * const userdata);
|
|
||||||
static void *callRealloc(void *p, const size_t size,
|
|
||||||
void * const userdata);
|
|
||||||
static void callFree(void *p, void * const userdata);
|
|
||||||
static void callLog(void * const userdata,
|
|
||||||
const xmpp_log_level_t level,
|
|
||||||
const char * const area,
|
|
||||||
const char * const msg);
|
|
||||||
};
|
|
||||||
|
|
||||||
class Stanza {
|
|
||||||
private:
|
|
||||||
Context *m_ctx;
|
|
||||||
xmpp_stanza_t *m_stanza;
|
|
||||||
|
|
||||||
void *operator new(size_t size, Context *ctx);
|
|
||||||
void operator delete(void *p);
|
|
||||||
Stanza(Context *ctx);
|
|
||||||
virtual ~Stanza();
|
|
||||||
|
|
||||||
public:
|
|
||||||
static Stanza *create(Context *ctx);
|
|
||||||
void release();
|
|
||||||
Stanza *clone();
|
|
||||||
Stanza *copy();
|
|
||||||
|
|
||||||
int toText(const char ** const buf, size_t * const buflen);
|
|
||||||
Stanza *getChildren();
|
|
||||||
Stanza *getChildByName(const char * const name);
|
|
||||||
Stanza *getNext();
|
|
||||||
char *getAttribute(const char * const name);
|
|
||||||
char *getNamespace();
|
|
||||||
char *getText();
|
|
||||||
char *getName();
|
|
||||||
void addChild(Stanza *child);
|
|
||||||
void setNamespace(const char * const ns);
|
|
||||||
void setAttribute(const char * const key, const char * const value);
|
|
||||||
void setName(const char * const name);
|
|
||||||
void setText(const char * const text);
|
|
||||||
void setText(const char * const text, const size_t size);
|
|
||||||
char *getType();
|
|
||||||
char *getId();
|
|
||||||
char *getTo();
|
|
||||||
char *getFrom();
|
|
||||||
void setType(const char * const type);
|
|
||||||
void setId(const char * const id);
|
|
||||||
void setTo(const char * const to);
|
|
||||||
void setFrom(const char * const from);
|
|
||||||
};
|
|
||||||
|
|
||||||
class Connection {
|
|
||||||
private:
|
|
||||||
Context *m_ctx;
|
|
||||||
xmpp_conn_t *conn;
|
|
||||||
|
|
||||||
void *operator new(size_t size, Context *ctx);
|
|
||||||
Connection(Context *ctx);
|
|
||||||
|
|
||||||
public:
|
|
||||||
static Connection *create(Context *ctx);
|
|
||||||
virtual ~Connection();
|
|
||||||
Connection *clone();
|
|
||||||
void operator delete(void *p);
|
|
||||||
|
|
||||||
const char *getJID();
|
|
||||||
void setJID(const char * const jid);
|
|
||||||
const char *getPass();
|
|
||||||
void setPass(const char * const pass);
|
|
||||||
bool connectClient(const char * const domain,
|
|
||||||
xmpp_conn_handler callback,
|
|
||||||
void * const userdata);
|
|
||||||
void disconnect();
|
|
||||||
void send(Stanza *stanza);
|
|
||||||
|
|
||||||
void addTimedHandler(xmpp_timed_handler handler,
|
|
||||||
const unsigned long perdio,
|
|
||||||
void * const userdata);
|
|
||||||
void deleteTimedHandler(xmpp_timed_handler handler);
|
|
||||||
void addHandler(xmpp_handler handler,
|
|
||||||
const char * const ns,
|
|
||||||
const char * const name,
|
|
||||||
const char * const type,
|
|
||||||
void * const userdata);
|
|
||||||
void deleteHandler(xmpp_handler handler);
|
|
||||||
void addIdHandler(xmpp_handler handler,
|
|
||||||
const char * const id,
|
|
||||||
void * const userdata);
|
|
||||||
void deleteIdHandler(xmpp_handler handler);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* __LIBSTROPHE_STROPHEPP_H__ */
|
|
||||||
@@ -18,11 +18,12 @@
|
|||||||
|
|
||||||
#include "test.h"
|
#include "test.h"
|
||||||
|
|
||||||
#define fail_unless(expr) do { \
|
#define fail_unless(expr) \
|
||||||
|
do { \
|
||||||
int result = (expr); \
|
int result = (expr); \
|
||||||
if (!result) { \
|
if (!result) { \
|
||||||
printf("%s:%d: Assertion failed: %s\n", \
|
printf("%s:%d: Assertion failed: %s\n", __FILE__, __LINE__, \
|
||||||
__FILE__, __LINE__, #expr); \
|
#expr); \
|
||||||
exit(1); \
|
exit(1); \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
@@ -42,6 +43,9 @@ static void create_destroy(void)
|
|||||||
int cbtest_got_start = 0;
|
int cbtest_got_start = 0;
|
||||||
void cbtest_handle_start(char *name, char **attrs, void *userdata)
|
void cbtest_handle_start(char *name, char **attrs, void *userdata)
|
||||||
{
|
{
|
||||||
|
(void)attrs;
|
||||||
|
(void)userdata;
|
||||||
|
|
||||||
if (strcmp(name, "stream") == 0)
|
if (strcmp(name, "stream") == 0)
|
||||||
cbtest_got_start = 1;
|
cbtest_got_start = 1;
|
||||||
}
|
}
|
||||||
@@ -49,6 +53,8 @@ void cbtest_handle_start(char *name, char **attrs, void *userdata)
|
|||||||
int cbtest_got_end = 0;
|
int cbtest_got_end = 0;
|
||||||
void cbtest_handle_end(char *name, void *userdata)
|
void cbtest_handle_end(char *name, void *userdata)
|
||||||
{
|
{
|
||||||
|
(void)userdata;
|
||||||
|
|
||||||
if (strcmp(name, "stream") == 0)
|
if (strcmp(name, "stream") == 0)
|
||||||
cbtest_got_end = 1;
|
cbtest_got_end = 1;
|
||||||
}
|
}
|
||||||
@@ -56,6 +62,8 @@ void cbtest_handle_end(char *name, void *userdata)
|
|||||||
int cbtest_got_stanza = 0;
|
int cbtest_got_stanza = 0;
|
||||||
void cbtest_handle_stanza(xmpp_stanza_t *stanza, void *userdata)
|
void cbtest_handle_stanza(xmpp_stanza_t *stanza, void *userdata)
|
||||||
{
|
{
|
||||||
|
(void)userdata;
|
||||||
|
|
||||||
if (strcmp(xmpp_stanza_get_name(stanza), "message") == 0)
|
if (strcmp(xmpp_stanza_get_name(stanza), "message") == 0)
|
||||||
cbtest_got_stanza = 1;
|
cbtest_got_stanza = 1;
|
||||||
}
|
}
|
||||||
@@ -67,9 +75,7 @@ static void callbacks(void)
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ctx = xmpp_ctx_new(NULL, NULL);
|
ctx = xmpp_ctx_new(NULL, NULL);
|
||||||
parser = parser_new(ctx,
|
parser = parser_new(ctx, cbtest_handle_start, cbtest_handle_end,
|
||||||
cbtest_handle_start,
|
|
||||||
cbtest_handle_end,
|
|
||||||
cbtest_handle_stanza, NULL);
|
cbtest_handle_stanza, NULL);
|
||||||
|
|
||||||
ret = parser_feed(parser, "<stream>", 8);
|
ret = parser_feed(parser, "<stream>", 8);
|
||||||
|
|||||||
@@ -55,13 +55,13 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
domain = argv[1];
|
domain = argv[1];
|
||||||
snprintf(fulldomain, sizeof(fulldomain), "_%s._%s.%s",
|
snprintf(fulldomain, sizeof(fulldomain), "_%s._%s.%s", service, proto,
|
||||||
service, proto, domain);
|
domain);
|
||||||
errno = 0;
|
errno = 0;
|
||||||
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");
|
||||||
|
|||||||
@@ -16,9 +16,9 @@
|
|||||||
|
|
||||||
static uint8_t char_to_bin(char c)
|
static uint8_t char_to_bin(char c)
|
||||||
{
|
{
|
||||||
return c <= '9' ? (uint8_t)(c - '0') :
|
return c <= '9'
|
||||||
c <= 'Z' ? (uint8_t)(c - 'A' + 10) :
|
? (uint8_t)(c - '0')
|
||||||
(uint8_t)(c - 'a' + 10);
|
: c <= 'Z' ? (uint8_t)(c - 'A' + 10) : (uint8_t)(c - 'a' + 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_hex_to_bin(const char *hex, uint8_t *bin, size_t *bin_len)
|
void test_hex_to_bin(const char *hex, uint8_t *bin, size_t *bin_len)
|
||||||
|
|||||||
13
tests/test.h
13
tests/test.h
@@ -18,7 +18,8 @@
|
|||||||
#include "ostypes.h"
|
#include "ostypes.h"
|
||||||
|
|
||||||
#define TEST_MAIN \
|
#define TEST_MAIN \
|
||||||
int main(int argc, char **argv) { \
|
int main(int argc, char **argv) \
|
||||||
|
{ \
|
||||||
int num_failed; \
|
int num_failed; \
|
||||||
Suite *s = parser_suite(); \
|
Suite *s = parser_suite(); \
|
||||||
SRunner *sr = srunner_create(s); \
|
SRunner *sr = srunner_create(s); \
|
||||||
@@ -51,14 +52,10 @@ do { \
|
|||||||
const uint8_t *__v2 = (uint8_t *)(v2); \
|
const uint8_t *__v2 = (uint8_t *)(v2); \
|
||||||
size_t __len1 = len1; \
|
size_t __len1 = len1; \
|
||||||
size_t __len2 = len2; \
|
size_t __len2 = len2; \
|
||||||
if (__len1 != __len2 || \
|
if (__len1 != __len2 || memcmp(__v1, __v2, __len1) != 0) { \
|
||||||
memcmp(__v1, __v2, __len1) != 0) \
|
|
||||||
{ \
|
|
||||||
printf("%s differs!\n", #v1); \
|
printf("%s differs!\n", #v1); \
|
||||||
printf("expected: 0x%s\n", \
|
printf("expected: 0x%s\n", test_bin_to_hex(__v1, __len1)); \
|
||||||
test_bin_to_hex(__v1, __len1)); \
|
printf("got: 0x%s\n", test_bin_to_hex(__v2, __len2)); \
|
||||||
printf("got: 0x%s\n", \
|
|
||||||
test_bin_to_hex(__v2, __len2)); \
|
|
||||||
exit(1); \
|
exit(1); \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|||||||
@@ -17,11 +17,11 @@
|
|||||||
|
|
||||||
#include "test.h"
|
#include "test.h"
|
||||||
|
|
||||||
static const unsigned char test_2_raw[] =
|
static const unsigned char test_2_raw[] = {0x14, 0xfb, 0x9c, 0x03,
|
||||||
{0x14, 0xfb, 0x9c, 0x03, 0xd9, 0x7e, 0x00};
|
0xd9, 0x7e, 0x00};
|
||||||
static const unsigned char test_4_raw[] =
|
static const unsigned char test_4_raw[] = {0xd6, 0x2f, 0x27, 0x49, 0x7e, 0xdd,
|
||||||
{0xd6, 0x2f, 0x27, 0x49, 0x7e, 0xdd, 0xf3, 0xd5,
|
0xf3, 0xd5, 0x41, 0xbc, 0x1b, 0xe9,
|
||||||
0x41, 0xbc, 0x1b, 0xe9, 0xdf, 0xe9, 0xb3, 0x08, 0x00};
|
0xdf, 0xe9, 0xb3, 0x08, 0x00};
|
||||||
|
|
||||||
static const struct {
|
static const struct {
|
||||||
char *raw;
|
char *raw;
|
||||||
@@ -36,13 +36,11 @@ static const struct {
|
|||||||
.base64 = "FPucA9l+",
|
.base64 = "FPucA9l+",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.raw =
|
.raw = "From rest and sleep, which but thy pictures be, "
|
||||||
"From rest and sleep, which but thy pictures be, "
|
|
||||||
"Much pleasure; then from thee much more must flow, "
|
"Much pleasure; then from thee much more must flow, "
|
||||||
"And soonest our best men with thee do go, "
|
"And soonest our best men with thee do go, "
|
||||||
"Rest of their bones, and soul's delivery.",
|
"Rest of their bones, and soul's delivery.",
|
||||||
.base64 =
|
.base64 = "RnJvbSByZXN0IGFuZCBzbGVlcCwgd2hpY2ggYnV0IHRoeSBwaWN0dXJl"
|
||||||
"RnJvbSByZXN0IGFuZCBzbGVlcCwgd2hpY2ggYnV0IHRoeSBwaWN0dXJl"
|
|
||||||
"cyBiZSwgTXVjaCBwbGVhc3VyZTsgdGhlbiBmcm9tIHRoZWUgbXVjaCBt"
|
"cyBiZSwgTXVjaCBwbGVhc3VyZTsgdGhlbiBmcm9tIHRoZWUgbXVjaCBt"
|
||||||
"b3JlIG11c3QgZmxvdywgQW5kIHNvb25lc3Qgb3VyIGJlc3QgbWVuIHdp"
|
"b3JlIG11c3QgZmxvdywgQW5kIHNvb25lc3Qgb3VyIGJlc3QgbWVuIHdp"
|
||||||
"dGggdGhlZSBkbyBnbywgUmVzdCBvZiB0aGVpciBib25lcywgYW5kIHNv"
|
"dGggdGhlZSBkbyBnbywgUmVzdCBvZiB0aGVpciBib25lcywgYW5kIHNv"
|
||||||
@@ -53,11 +51,9 @@ static const struct {
|
|||||||
.base64 = "1i8nSX7d89VBvBvp3+mzCA==",
|
.base64 = "1i8nSX7d89VBvBvp3+mzCA==",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.raw =
|
.raw = "realm=\"chesspark.com\",nonce=\"b243c0d663257a9149999cef2f83"
|
||||||
"realm=\"chesspark.com\",nonce=\"b243c0d663257a9149999cef2f83"
|
|
||||||
"a22116559e93\",qop=\"auth\",charset=utf-8,algorithm=md5-sess",
|
"a22116559e93\",qop=\"auth\",charset=utf-8,algorithm=md5-sess",
|
||||||
.base64 =
|
.base64 = "cmVhbG09ImNoZXNzcGFyay5jb20iLG5vbmNlPSJiMjQzYzBkNjYzMjU3"
|
||||||
"cmVhbG09ImNoZXNzcGFyay5jb20iLG5vbmNlPSJiMjQzYzBkNjYzMjU3"
|
|
||||||
"YTkxNDk5OTljZWYyZjgzYTIyMTE2NTU5ZTkzIixxb3A9ImF1dGgiLGNo"
|
"YTkxNDk5OTljZWYyZjgzYTIyMTE2NTU5ZTkzIixxb3A9ImF1dGgiLGNo"
|
||||||
"YXJzZXQ9dXRmLTgsYWxnb3JpdGhtPW1kNS1zZXNz",
|
"YXJzZXQ9dXRmLTgsYWxnb3JpdGhtPW1kNS1zZXNz",
|
||||||
},
|
},
|
||||||
@@ -94,48 +90,36 @@ static const struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static const unsigned char bin_data[] = {
|
static const unsigned char bin_data[] = {
|
||||||
0xda, 0xa8, 0x81, 0x80, 0x00, 0x01, 0x00, 0x05,
|
0xda, 0xa8, 0x81, 0x80, 0x00, 0x01, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x0c, 0x5f, 0x78, 0x6d,
|
0x0c, 0x5f, 0x78, 0x6d, 0x70, 0x70, 0x2d, 0x63, 0x6c, 0x69, 0x65, 0x6e,
|
||||||
0x70, 0x70, 0x2d, 0x63, 0x6c, 0x69, 0x65, 0x6e,
|
0x74, 0x04, 0x5f, 0x74, 0x63, 0x70, 0x05, 0x67, 0x6d, 0x61, 0x69, 0x6c,
|
||||||
0x74, 0x04, 0x5f, 0x74, 0x63, 0x70, 0x05, 0x67,
|
0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x21, 0x00, 0x01, 0xc0, 0x0c, 0x00,
|
||||||
0x6d, 0x61, 0x69, 0x6c, 0x03, 0x63, 0x6f, 0x6d,
|
0x21, 0x00, 0x01, 0x00, 0x00, 0x02, 0x43, 0x00, 0x1e, 0x00, 0x14, 0x00,
|
||||||
0x00, 0x00, 0x21, 0x00, 0x01, 0xc0, 0x0c, 0x00,
|
0x00, 0x14, 0x66, 0x04, 0x61, 0x6c, 0x74, 0x31, 0x04, 0x78, 0x6d, 0x70,
|
||||||
0x21, 0x00, 0x01, 0x00, 0x00, 0x02, 0x43, 0x00,
|
0x70, 0x01, 0x6c, 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63,
|
||||||
0x1e, 0x00, 0x14, 0x00, 0x00, 0x14, 0x66, 0x04,
|
0x6f, 0x6d, 0x00, 0xc0, 0x0c, 0x00, 0x21, 0x00, 0x01, 0x00, 0x00, 0x02,
|
||||||
0x61, 0x6c, 0x74, 0x31, 0x04, 0x78, 0x6d, 0x70,
|
0x43, 0x00, 0x1e, 0x00, 0x14, 0x00, 0x00, 0x14, 0x66, 0x04, 0x61, 0x6c,
|
||||||
0x70, 0x01, 0x6c, 0x06, 0x67, 0x6f, 0x6f, 0x67,
|
0x74, 0x34, 0x04, 0x78, 0x6d, 0x70, 0x70, 0x01, 0x6c, 0x06, 0x67, 0x6f,
|
||||||
0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0xc0,
|
0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0xc0, 0x0c, 0x00,
|
||||||
0x0c, 0x00, 0x21, 0x00, 0x01, 0x00, 0x00, 0x02,
|
0x21, 0x00, 0x01, 0x00, 0x00, 0x02, 0x43, 0x00, 0x1e, 0x00, 0x14, 0x00,
|
||||||
0x43, 0x00, 0x1e, 0x00, 0x14, 0x00, 0x00, 0x14,
|
0x00, 0x14, 0x66, 0x04, 0x61, 0x6c, 0x74, 0x32, 0x04, 0x78, 0x6d, 0x70,
|
||||||
0x66, 0x04, 0x61, 0x6c, 0x74, 0x34, 0x04, 0x78,
|
0x70, 0x01, 0x6c, 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63,
|
||||||
0x6d, 0x70, 0x70, 0x01, 0x6c, 0x06, 0x67, 0x6f,
|
0x6f, 0x6d, 0x00, 0xc0, 0x0c, 0x00, 0x21, 0x00, 0x01, 0x00, 0x00, 0x02,
|
||||||
0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d,
|
0x43, 0x00, 0x19, 0x00, 0x05, 0x00, 0x00, 0x14, 0x66, 0x04, 0x78, 0x6d,
|
||||||
0x00, 0xc0, 0x0c, 0x00, 0x21, 0x00, 0x01, 0x00,
|
0x70, 0x70, 0x01, 0x6c, 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03,
|
||||||
0x00, 0x02, 0x43, 0x00, 0x1e, 0x00, 0x14, 0x00,
|
0x63, 0x6f, 0x6d, 0x00, 0xc0, 0x0c, 0x00, 0x21, 0x00, 0x01, 0x00, 0x00,
|
||||||
0x00, 0x14, 0x66, 0x04, 0x61, 0x6c, 0x74, 0x32,
|
0x02, 0x43, 0x00, 0x1e, 0x00, 0x14, 0x00, 0x00, 0x14, 0x66, 0x04, 0x61,
|
||||||
0x04, 0x78, 0x6d, 0x70, 0x70, 0x01, 0x6c, 0x06,
|
0x6c, 0x74, 0x33, 0x04, 0x78, 0x6d, 0x70, 0x70, 0x01, 0x6c, 0x06, 0x67,
|
||||||
0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63,
|
0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00,
|
||||||
0x6f, 0x6d, 0x00, 0xc0, 0x0c, 0x00, 0x21, 0x00,
|
|
||||||
0x01, 0x00, 0x00, 0x02, 0x43, 0x00, 0x19, 0x00,
|
|
||||||
0x05, 0x00, 0x00, 0x14, 0x66, 0x04, 0x78, 0x6d,
|
|
||||||
0x70, 0x70, 0x01, 0x6c, 0x06, 0x67, 0x6f, 0x6f,
|
|
||||||
0x67, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00,
|
|
||||||
0xc0, 0x0c, 0x00, 0x21, 0x00, 0x01, 0x00, 0x00,
|
|
||||||
0x02, 0x43, 0x00, 0x1e, 0x00, 0x14, 0x00, 0x00,
|
|
||||||
0x14, 0x66, 0x04, 0x61, 0x6c, 0x74, 0x33, 0x04,
|
|
||||||
0x78, 0x6d, 0x70, 0x70, 0x01, 0x6c, 0x06, 0x67,
|
|
||||||
0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63, 0x6f,
|
|
||||||
0x6d, 0x00,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main()
|
||||||
{
|
{
|
||||||
xmpp_ctx_t *ctx;
|
xmpp_ctx_t *ctx;
|
||||||
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");
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/* test_ctx.c
|
/* test_ctx.c
|
||||||
** libstrophe XMPP client library -- test routines for the library run-time context
|
** libstrophe XMPP client library -- test routines for the library run-time
|
||||||
|
*context
|
||||||
**
|
**
|
||||||
** Copyright (C) 2005-2009 Collecta, Inc.
|
** Copyright (C) 2005-2009 Collecta, Inc.
|
||||||
**
|
**
|
||||||
@@ -23,31 +24,39 @@ static int mem_realloc_called = 0;
|
|||||||
|
|
||||||
void *my_alloc(const size_t size, void *const userdata)
|
void *my_alloc(const size_t size, void *const userdata)
|
||||||
{
|
{
|
||||||
|
(void)userdata;
|
||||||
|
|
||||||
mem_alloc_called++;
|
mem_alloc_called++;
|
||||||
return malloc(size);
|
return malloc(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void my_free(void *p, void *const userdata)
|
void my_free(void *p, void *const userdata)
|
||||||
{
|
{
|
||||||
|
(void)userdata;
|
||||||
|
|
||||||
mem_free_called++;
|
mem_free_called++;
|
||||||
return free(p);
|
return free(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
void *my_realloc(void *p, const size_t size, void *const userdata)
|
void *my_realloc(void *p, const size_t size, void *const userdata)
|
||||||
{
|
{
|
||||||
|
(void)userdata;
|
||||||
|
|
||||||
mem_realloc_called++;
|
mem_realloc_called++;
|
||||||
return realloc(p, size);
|
return realloc(p, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void my_logger(void * const userdata, const xmpp_log_level_t level,
|
void my_logger(void *const userdata,
|
||||||
const char * const area, const char * const msg)
|
const xmpp_log_level_t level,
|
||||||
|
const char *const area,
|
||||||
|
const char *const msg)
|
||||||
{
|
{
|
||||||
if (strcmp((char *)userdata, "asdf") == 0 && level == XMPP_LEVEL_DEBUG
|
if (strcmp((char *)userdata, "asdf") == 0 && level == XMPP_LEVEL_DEBUG &&
|
||||||
&& strcmp(area, "test") == 0 && strcmp(msg, "hello") == 0)
|
strcmp(area, "test") == 0 && strcmp(msg, "hello") == 0)
|
||||||
log_called++;
|
log_called++;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main()
|
||||||
{
|
{
|
||||||
xmpp_ctx_t *ctx;
|
xmpp_ctx_t *ctx;
|
||||||
xmpp_mem_t mymem;
|
xmpp_mem_t mymem;
|
||||||
@@ -56,7 +65,8 @@ int main(int argc, char **argv)
|
|||||||
void *testptr1, *testptr2;
|
void *testptr1, *testptr2;
|
||||||
|
|
||||||
ctx = xmpp_ctx_new(NULL, NULL);
|
ctx = xmpp_ctx_new(NULL, NULL);
|
||||||
if (ctx == NULL) return 1;
|
if (ctx == NULL)
|
||||||
|
return 1;
|
||||||
|
|
||||||
/* destroy context */
|
/* destroy context */
|
||||||
xmpp_ctx_free(ctx);
|
xmpp_ctx_free(ctx);
|
||||||
|
|||||||
@@ -16,18 +16,15 @@
|
|||||||
#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[] = {"foo", "bar", "baz", "quux", "xyzzy"};
|
||||||
const char *keys[] = {
|
const char *values[] = {"wuzzle", "mug", "canonical", "rosebud", "lottery"};
|
||||||
"foo", "bar", "baz", "quux", "xyzzy"
|
const int nkeys = ARRAY_SIZE(keys);
|
||||||
};
|
|
||||||
const char *values[] = {
|
|
||||||
"wuzzle", "mug", "canonical", "rosebud", "lottery"
|
|
||||||
};
|
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
@@ -58,7 +55,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,8 +63,9 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* test key count */
|
/* test key count */
|
||||||
@@ -76,6 +74,22 @@ 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);
|
||||||
|
|
||||||
@@ -119,14 +133,19 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
/* test drops */
|
/* test drops */
|
||||||
hash_drop(clone, keys[2]);
|
hash_drop(clone, keys[2]);
|
||||||
if (hash_get(clone, keys[2]) != NULL) return 1;
|
if (hash_get(clone, keys[2]) != NULL)
|
||||||
|
return 1;
|
||||||
hash_drop(clone, keys[1]);
|
hash_drop(clone, keys[1]);
|
||||||
hash_drop(clone, keys[4]);
|
hash_drop(clone, keys[4]);
|
||||||
if (hash_get(clone, keys[4]) != NULL) return 1;
|
if (hash_get(clone, keys[4]) != NULL)
|
||||||
if (hash_get(clone, keys[1]) != NULL) return 1;
|
return 1;
|
||||||
|
if (hash_get(clone, keys[1]) != NULL)
|
||||||
|
return 1;
|
||||||
/* keys 0,3 should still be available */
|
/* keys 0,3 should still be available */
|
||||||
if (hash_get(clone, keys[0]) == NULL) return 1;
|
if (hash_get(clone, keys[0]) == NULL)
|
||||||
if (hash_get(clone, keys[3]) == NULL) return 1;
|
return 1;
|
||||||
|
if (hash_get(clone, keys[3]) == NULL)
|
||||||
|
return 1;
|
||||||
|
|
||||||
/* release our clone */
|
/* release our clone */
|
||||||
hash_release(clone);
|
hash_release(clone);
|
||||||
|
|||||||
135
tests/test_jid.c
135
tests/test_jid.c
@@ -27,57 +27,102 @@ 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),
|
||||||
jid1, _s(node), _s(domain), _s(resource));
|
_s(resource));
|
||||||
if (node == NULL || strcmp(node, "foo")) return 1;
|
if (bare == NULL || strcmp(bare, "foo@bar.com"))
|
||||||
if (domain == NULL || strcmp(domain, "bar.com")) return 1;
|
return 1;
|
||||||
if (resource != NULL) return 1;
|
if (node == NULL || strcmp(node, "foo"))
|
||||||
if (node) xmpp_free(ctx, node);
|
return 1;
|
||||||
if (domain) xmpp_free(ctx, domain);
|
if (domain == NULL || strcmp(domain, "bar.com"))
|
||||||
if (resource) xmpp_free(ctx, resource);
|
return 1;
|
||||||
|
if (resource != NULL)
|
||||||
|
return 1;
|
||||||
|
if (bare)
|
||||||
|
xmpp_free(ctx, bare);
|
||||||
|
if (node)
|
||||||
|
xmpp_free(ctx, node);
|
||||||
|
if (domain)
|
||||||
|
xmpp_free(ctx, domain);
|
||||||
|
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),
|
||||||
jid2, _s(node), _s(domain), _s(resource));
|
_s(resource));
|
||||||
if (node == NULL || strcmp(node, "anyone")) return 1;
|
if (bare == NULL || strcmp(bare, "anyone@example.com"))
|
||||||
if (domain == NULL || strcmp(domain, "example.com")) return 1;
|
return 1;
|
||||||
if (resource == NULL || strcmp(resource, "hullo")) return 1;
|
if (node == NULL || strcmp(node, "anyone"))
|
||||||
if (node) xmpp_free(ctx, node);
|
return 1;
|
||||||
if (domain) xmpp_free(ctx, domain);
|
if (domain == NULL || strcmp(domain, "example.com"))
|
||||||
if (resource) xmpp_free(ctx, resource);
|
return 1;
|
||||||
|
if (resource == NULL || strcmp(resource, "hullo"))
|
||||||
|
return 1;
|
||||||
|
if (bare)
|
||||||
|
xmpp_free(ctx, bare);
|
||||||
|
if (node)
|
||||||
|
xmpp_free(ctx, node);
|
||||||
|
if (domain)
|
||||||
|
xmpp_free(ctx, domain);
|
||||||
|
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),
|
||||||
jid3, _s(node), _s(domain), _s(resource));
|
_s(resource));
|
||||||
if (node == NULL || strcmp(node, "manic.porter")) return 1;
|
if (bare == NULL || strcmp(bare, "manic.porter@xyz.net"))
|
||||||
if (domain == NULL || strcmp(domain, "xyz.net")) return 1;
|
return 1;
|
||||||
if (resource == NULL || strcmp(resource, "frob")) return 1;
|
if (node == NULL || strcmp(node, "manic.porter"))
|
||||||
if (node) xmpp_free(ctx, node);
|
return 1;
|
||||||
if (domain) xmpp_free(ctx, domain);
|
if (domain == NULL || strcmp(domain, "xyz.net"))
|
||||||
if (resource) xmpp_free(ctx, resource);
|
return 1;
|
||||||
|
if (resource == NULL || strcmp(resource, "frob"))
|
||||||
|
return 1;
|
||||||
|
if (bare)
|
||||||
|
xmpp_free(ctx, bare);
|
||||||
|
if (node)
|
||||||
|
xmpp_free(ctx, node);
|
||||||
|
if (domain)
|
||||||
|
xmpp_free(ctx, domain);
|
||||||
|
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),
|
||||||
jid4, _s(node), _s(domain), _s(resource));
|
_s(resource));
|
||||||
if (node != NULL) return 1;
|
if (bare == NULL || strcmp(bare, "domain.tld"))
|
||||||
if (domain == NULL || strcmp(domain, "domain.tld")) return 1;
|
return 1;
|
||||||
if (resource != NULL) return 1;
|
if (node != NULL)
|
||||||
if (node) xmpp_free(ctx, node);
|
return 1;
|
||||||
if (domain) xmpp_free(ctx, domain);
|
if (domain == NULL || strcmp(domain, "domain.tld"))
|
||||||
if (resource) xmpp_free(ctx, resource);
|
return 1;
|
||||||
|
if (resource != NULL)
|
||||||
|
return 1;
|
||||||
|
if (bare)
|
||||||
|
xmpp_free(ctx, bare);
|
||||||
|
if (node)
|
||||||
|
xmpp_free(ctx, node);
|
||||||
|
if (domain)
|
||||||
|
xmpp_free(ctx, domain);
|
||||||
|
if (resource)
|
||||||
|
xmpp_free(ctx, resource);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -88,38 +133,46 @@ int test_jid_new(xmpp_ctx_t *ctx)
|
|||||||
|
|
||||||
jid = xmpp_jid_new(ctx, "node", "domain", "resource");
|
jid = xmpp_jid_new(ctx, "node", "domain", "resource");
|
||||||
printf("new jid: '%s'\n", jid);
|
printf("new jid: '%s'\n", jid);
|
||||||
if (strcmp(jid, "node@domain/resource")) return 1;
|
if (strcmp(jid, "node@domain/resource"))
|
||||||
|
return 1;
|
||||||
xmpp_free(ctx, jid);
|
xmpp_free(ctx, jid);
|
||||||
|
|
||||||
jid = xmpp_jid_new(ctx, "foo", "bar.com", NULL);
|
jid = xmpp_jid_new(ctx, "foo", "bar.com", NULL);
|
||||||
printf("new jid: '%s'\n", jid);
|
printf("new jid: '%s'\n", jid);
|
||||||
if (strcmp(jid, "foo@bar.com")) return 1;
|
if (strcmp(jid, "foo@bar.com"))
|
||||||
|
return 1;
|
||||||
xmpp_free(ctx, jid);
|
xmpp_free(ctx, jid);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main()
|
||||||
{
|
{
|
||||||
xmpp_ctx_t *ctx;
|
xmpp_ctx_t *ctx;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
printf("allocating context... ");
|
printf("allocating context... ");
|
||||||
ctx = xmpp_ctx_new(NULL, NULL);
|
ctx = xmpp_ctx_new(NULL, NULL);
|
||||||
if (ctx == NULL) printf("failed to create context\n");
|
if (ctx == NULL)
|
||||||
if (ctx == NULL) return -1;
|
printf("failed to create context\n");
|
||||||
|
if (ctx == NULL)
|
||||||
|
return -1;
|
||||||
printf("ok.\n");
|
printf("ok.\n");
|
||||||
|
|
||||||
printf("testing jid routines...\n");
|
printf("testing jid routines...\n");
|
||||||
ret = test_jid(ctx);
|
ret = test_jid(ctx);
|
||||||
if (ret) printf("testing jid routines... failed!\n");
|
if (ret)
|
||||||
if (ret) return ret;
|
printf("testing jid routines... failed!\n");
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
printf("testing jid routines... ok.\n");
|
printf("testing jid routines... ok.\n");
|
||||||
|
|
||||||
printf("testing jid new routines...\n");
|
printf("testing jid new routines...\n");
|
||||||
ret = test_jid_new(ctx);
|
ret = test_jid_new(ctx);
|
||||||
if (ret) printf("testing jid new routines... failed!\n");
|
if (ret)
|
||||||
if (ret) return ret;
|
printf("testing jid new routines... failed!\n");
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
printf("testing jid new routines... ok.\n");
|
printf("testing jid new routines... ok.\n");
|
||||||
|
|
||||||
printf("freeing context... ");
|
printf("freeing context... ");
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ static const struct {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main()
|
||||||
{
|
{
|
||||||
struct MD5Context ctx;
|
struct MD5Context ctx;
|
||||||
unsigned char digest[16];
|
unsigned char digest[16];
|
||||||
|
|||||||
@@ -21,14 +21,29 @@
|
|||||||
#include "rand.c"
|
#include "rand.c"
|
||||||
|
|
||||||
/* stubs to build test without whole libstrophe */
|
/* stubs to build test without whole libstrophe */
|
||||||
void *xmpp_alloc(const xmpp_ctx_t * const ctx, const size_t size) {
|
void *xmpp_alloc(const xmpp_ctx_t *const ctx, const size_t size)
|
||||||
|
{
|
||||||
|
(void)ctx;
|
||||||
|
(void)size;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
void xmpp_free(const xmpp_ctx_t * const ctx, void *p) { }
|
|
||||||
int xmpp_snprintf (char *str, size_t count, const char *fmt, ...) {
|
void xmpp_free(const xmpp_ctx_t *const ctx, void *p)
|
||||||
|
{
|
||||||
|
(void)ctx;
|
||||||
|
(void)p;
|
||||||
|
}
|
||||||
|
|
||||||
|
int xmpp_snprintf(char *str, size_t count, const char *fmt, ...)
|
||||||
|
{
|
||||||
|
(void)str;
|
||||||
|
(void)count;
|
||||||
|
(void)fmt;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
uint64_t time_stamp(void) {
|
|
||||||
|
uint64_t time_stamp(void)
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,8 +136,8 @@ int main()
|
|||||||
&entropy_input_len);
|
&entropy_input_len);
|
||||||
test_hex_to_bin(test_vectors[i].nonce, nonce, &nonce_len);
|
test_hex_to_bin(test_vectors[i].nonce, nonce, &nonce_len);
|
||||||
|
|
||||||
Hash_DRBG_Instantiate(&ctx, entropy_input, entropy_input_len,
|
Hash_DRBG_Instantiate(&ctx, entropy_input, entropy_input_len, nonce,
|
||||||
nonce, nonce_len);
|
nonce_len);
|
||||||
COMPARE(test_vectors[i].V1, test_bin_to_hex(ctx.V, sizeof(ctx.V)));
|
COMPARE(test_vectors[i].V1, test_bin_to_hex(ctx.V, sizeof(ctx.V)));
|
||||||
COMPARE(test_vectors[i].C1, test_bin_to_hex(ctx.C, sizeof(ctx.C)));
|
COMPARE(test_vectors[i].C1, test_bin_to_hex(ctx.C, sizeof(ctx.C)));
|
||||||
assert(ctx.reseed_counter == 1);
|
assert(ctx.reseed_counter == 1);
|
||||||
|
|||||||
@@ -19,71 +19,51 @@
|
|||||||
|
|
||||||
/* res_query("_xmpp-client._tcp.jabber.kiev.ua", C_IN, T_SRV, ...) */
|
/* res_query("_xmpp-client._tcp.jabber.kiev.ua", C_IN, T_SRV, ...) */
|
||||||
static const unsigned char data1[] = {
|
static const unsigned char data1[] = {
|
||||||
0x95, 0xf3, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
|
0x95, 0xf3, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x0c, 0x5f, 0x78, 0x6d,
|
0x0c, 0x5f, 0x78, 0x6d, 0x70, 0x70, 0x2d, 0x63, 0x6c, 0x69, 0x65, 0x6e,
|
||||||
0x70, 0x70, 0x2d, 0x63, 0x6c, 0x69, 0x65, 0x6e,
|
0x74, 0x04, 0x5f, 0x74, 0x63, 0x70, 0x06, 0x6a, 0x61, 0x62, 0x62, 0x65,
|
||||||
0x74, 0x04, 0x5f, 0x74, 0x63, 0x70, 0x06, 0x6a,
|
0x72, 0x04, 0x6b, 0x69, 0x65, 0x76, 0x02, 0x75, 0x61, 0x00, 0x00, 0x21,
|
||||||
0x61, 0x62, 0x62, 0x65, 0x72, 0x04, 0x6b, 0x69,
|
0x00, 0x01, 0xc0, 0x0c, 0x00, 0x21, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3b,
|
||||||
0x65, 0x76, 0x02, 0x75, 0x61, 0x00, 0x00, 0x21,
|
0x00, 0x16, 0x00, 0x01, 0x00, 0x00, 0x14, 0x66, 0x06, 0x6a, 0x61, 0x62,
|
||||||
0x00, 0x01, 0xc0, 0x0c, 0x00, 0x21, 0x00, 0x01,
|
0x62, 0x65, 0x72, 0x04, 0x6b, 0x69, 0x65, 0x76, 0x02, 0x75, 0x61, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x3b, 0x00, 0x16, 0x00, 0x01,
|
|
||||||
0x00, 0x00, 0x14, 0x66, 0x06, 0x6a, 0x61, 0x62,
|
|
||||||
0x62, 0x65, 0x72, 0x04, 0x6b, 0x69, 0x65, 0x76,
|
|
||||||
0x02, 0x75, 0x61, 0x00,
|
|
||||||
};
|
};
|
||||||
/* res_query("_xmpp-client._tcp.jabber.org", C_IN, T_SRV, ...) */
|
/* res_query("_xmpp-client._tcp.jabber.org", C_IN, T_SRV, ...) */
|
||||||
static const unsigned char data2[] = {
|
static const unsigned char data2[] = {
|
||||||
0xf2, 0x98, 0x81, 0x80, 0x00, 0x01, 0x00, 0x02,
|
0xf2, 0x98, 0x81, 0x80, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x0c, 0x5f, 0x78, 0x6d,
|
0x0c, 0x5f, 0x78, 0x6d, 0x70, 0x70, 0x2d, 0x63, 0x6c, 0x69, 0x65, 0x6e,
|
||||||
0x70, 0x70, 0x2d, 0x63, 0x6c, 0x69, 0x65, 0x6e,
|
0x74, 0x04, 0x5f, 0x74, 0x63, 0x70, 0x06, 0x6a, 0x61, 0x62, 0x62, 0x65,
|
||||||
0x74, 0x04, 0x5f, 0x74, 0x63, 0x70, 0x06, 0x6a,
|
0x72, 0x03, 0x6f, 0x72, 0x67, 0x00, 0x00, 0x21, 0x00, 0x01, 0xc0, 0x0c,
|
||||||
0x61, 0x62, 0x62, 0x65, 0x72, 0x03, 0x6f, 0x72,
|
0x00, 0x21, 0x00, 0x01, 0x00, 0x00, 0x03, 0x83, 0x00, 0x1a, 0x00, 0x1e,
|
||||||
0x67, 0x00, 0x00, 0x21, 0x00, 0x01, 0xc0, 0x0c,
|
0x00, 0x1e, 0x14, 0x66, 0x07, 0x68, 0x65, 0x72, 0x6d, 0x65, 0x73, 0x32,
|
||||||
0x00, 0x21, 0x00, 0x01, 0x00, 0x00, 0x03, 0x83,
|
0x06, 0x6a, 0x61, 0x62, 0x62, 0x65, 0x72, 0x03, 0x6f, 0x72, 0x67, 0x00,
|
||||||
0x00, 0x1a, 0x00, 0x1e, 0x00, 0x1e, 0x14, 0x66,
|
0xc0, 0x0c, 0x00, 0x21, 0x00, 0x01, 0x00, 0x00, 0x03, 0x83, 0x00, 0x1c,
|
||||||
0x07, 0x68, 0x65, 0x72, 0x6d, 0x65, 0x73, 0x32,
|
0x00, 0x1f, 0x00, 0x1e, 0x14, 0x66, 0x09, 0x68, 0x65, 0x72, 0x6d, 0x65,
|
||||||
0x06, 0x6a, 0x61, 0x62, 0x62, 0x65, 0x72, 0x03,
|
0x73, 0x32, 0x76, 0x36, 0x06, 0x6a, 0x61, 0x62, 0x62, 0x65, 0x72, 0x03,
|
||||||
0x6f, 0x72, 0x67, 0x00, 0xc0, 0x0c, 0x00, 0x21,
|
|
||||||
0x00, 0x01, 0x00, 0x00, 0x03, 0x83, 0x00, 0x1c,
|
|
||||||
0x00, 0x1f, 0x00, 0x1e, 0x14, 0x66, 0x09, 0x68,
|
|
||||||
0x65, 0x72, 0x6d, 0x65, 0x73, 0x32, 0x76, 0x36,
|
|
||||||
0x06, 0x6a, 0x61, 0x62, 0x62, 0x65, 0x72, 0x03,
|
|
||||||
0x6f, 0x72, 0x67, 0x00,
|
0x6f, 0x72, 0x67, 0x00,
|
||||||
};
|
};
|
||||||
/* res_query("_xmpp-client._tcp.gmail.com", C_IN, T_SRV, ...) */
|
/* res_query("_xmpp-client._tcp.gmail.com", C_IN, T_SRV, ...) */
|
||||||
static const unsigned char data3[] = {
|
static const unsigned char data3[] = {
|
||||||
0xda, 0xa8, 0x81, 0x80, 0x00, 0x01, 0x00, 0x05,
|
0xda, 0xa8, 0x81, 0x80, 0x00, 0x01, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x0c, 0x5f, 0x78, 0x6d,
|
0x0c, 0x5f, 0x78, 0x6d, 0x70, 0x70, 0x2d, 0x63, 0x6c, 0x69, 0x65, 0x6e,
|
||||||
0x70, 0x70, 0x2d, 0x63, 0x6c, 0x69, 0x65, 0x6e,
|
0x74, 0x04, 0x5f, 0x74, 0x63, 0x70, 0x05, 0x67, 0x6d, 0x61, 0x69, 0x6c,
|
||||||
0x74, 0x04, 0x5f, 0x74, 0x63, 0x70, 0x05, 0x67,
|
0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x21, 0x00, 0x01, 0xc0, 0x0c, 0x00,
|
||||||
0x6d, 0x61, 0x69, 0x6c, 0x03, 0x63, 0x6f, 0x6d,
|
0x21, 0x00, 0x01, 0x00, 0x00, 0x02, 0x43, 0x00, 0x1e, 0x00, 0x14, 0x00,
|
||||||
0x00, 0x00, 0x21, 0x00, 0x01, 0xc0, 0x0c, 0x00,
|
0x00, 0x14, 0x66, 0x04, 0x61, 0x6c, 0x74, 0x31, 0x04, 0x78, 0x6d, 0x70,
|
||||||
0x21, 0x00, 0x01, 0x00, 0x00, 0x02, 0x43, 0x00,
|
0x70, 0x01, 0x6c, 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63,
|
||||||
0x1e, 0x00, 0x14, 0x00, 0x00, 0x14, 0x66, 0x04,
|
0x6f, 0x6d, 0x00, 0xc0, 0x0c, 0x00, 0x21, 0x00, 0x01, 0x00, 0x00, 0x02,
|
||||||
0x61, 0x6c, 0x74, 0x31, 0x04, 0x78, 0x6d, 0x70,
|
0x43, 0x00, 0x1e, 0x00, 0x14, 0x00, 0x00, 0x14, 0x66, 0x04, 0x61, 0x6c,
|
||||||
0x70, 0x01, 0x6c, 0x06, 0x67, 0x6f, 0x6f, 0x67,
|
0x74, 0x34, 0x04, 0x78, 0x6d, 0x70, 0x70, 0x01, 0x6c, 0x06, 0x67, 0x6f,
|
||||||
0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0xc0,
|
0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0xc0, 0x0c, 0x00,
|
||||||
0x0c, 0x00, 0x21, 0x00, 0x01, 0x00, 0x00, 0x02,
|
0x21, 0x00, 0x01, 0x00, 0x00, 0x02, 0x43, 0x00, 0x1e, 0x00, 0x14, 0x00,
|
||||||
0x43, 0x00, 0x1e, 0x00, 0x14, 0x00, 0x00, 0x14,
|
0x00, 0x14, 0x66, 0x04, 0x61, 0x6c, 0x74, 0x32, 0x04, 0x78, 0x6d, 0x70,
|
||||||
0x66, 0x04, 0x61, 0x6c, 0x74, 0x34, 0x04, 0x78,
|
0x70, 0x01, 0x6c, 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63,
|
||||||
0x6d, 0x70, 0x70, 0x01, 0x6c, 0x06, 0x67, 0x6f,
|
0x6f, 0x6d, 0x00, 0xc0, 0x0c, 0x00, 0x21, 0x00, 0x01, 0x00, 0x00, 0x02,
|
||||||
0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d,
|
0x43, 0x00, 0x19, 0x00, 0x05, 0x00, 0x00, 0x14, 0x66, 0x04, 0x78, 0x6d,
|
||||||
0x00, 0xc0, 0x0c, 0x00, 0x21, 0x00, 0x01, 0x00,
|
0x70, 0x70, 0x01, 0x6c, 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03,
|
||||||
0x00, 0x02, 0x43, 0x00, 0x1e, 0x00, 0x14, 0x00,
|
0x63, 0x6f, 0x6d, 0x00, 0xc0, 0x0c, 0x00, 0x21, 0x00, 0x01, 0x00, 0x00,
|
||||||
0x00, 0x14, 0x66, 0x04, 0x61, 0x6c, 0x74, 0x32,
|
0x02, 0x43, 0x00, 0x1e, 0x00, 0x14, 0x00, 0x00, 0x14, 0x66, 0x04, 0x61,
|
||||||
0x04, 0x78, 0x6d, 0x70, 0x70, 0x01, 0x6c, 0x06,
|
0x6c, 0x74, 0x33, 0x04, 0x78, 0x6d, 0x70, 0x70, 0x01, 0x6c, 0x06, 0x67,
|
||||||
0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63,
|
0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00,
|
||||||
0x6f, 0x6d, 0x00, 0xc0, 0x0c, 0x00, 0x21, 0x00,
|
|
||||||
0x01, 0x00, 0x00, 0x02, 0x43, 0x00, 0x19, 0x00,
|
|
||||||
0x05, 0x00, 0x00, 0x14, 0x66, 0x04, 0x78, 0x6d,
|
|
||||||
0x70, 0x70, 0x01, 0x6c, 0x06, 0x67, 0x6f, 0x6f,
|
|
||||||
0x67, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00,
|
|
||||||
0xc0, 0x0c, 0x00, 0x21, 0x00, 0x01, 0x00, 0x00,
|
|
||||||
0x02, 0x43, 0x00, 0x1e, 0x00, 0x14, 0x00, 0x00,
|
|
||||||
0x14, 0x66, 0x04, 0x61, 0x6c, 0x74, 0x33, 0x04,
|
|
||||||
0x78, 0x6d, 0x70, 0x70, 0x01, 0x6c, 0x06, 0x67,
|
|
||||||
0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63, 0x6f,
|
|
||||||
0x6d, 0x00,
|
|
||||||
};
|
};
|
||||||
/* res_query("_xmpp-client._tcp.jabber.calyxinstitute.org", C_IN, T_SRV, ...) */
|
/* res_query("_xmpp-client._tcp.jabber.calyxinstitute.org", C_IN, T_SRV, ...) */
|
||||||
static const unsigned char data4[] = {
|
static const unsigned char data4[] = {
|
||||||
@@ -119,17 +99,14 @@ static const unsigned char data5[] = {
|
|||||||
};
|
};
|
||||||
/* hacked data2 with two empty-string targets. */
|
/* hacked data2 with two empty-string targets. */
|
||||||
static const unsigned char data6[] = {
|
static const unsigned char data6[] = {
|
||||||
0xf2, 0x98, 0x81, 0x80, 0x00, 0x01, 0x00, 0x02,
|
0xf2, 0x98, 0x81, 0x80, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x0c, 0x5f, 0x78, 0x6d,
|
0x00, 0x0c, 0x5f, 0x78, 0x6d, 0x70, 0x70, 0x2d, 0x63, 0x6c, 0x69,
|
||||||
0x70, 0x70, 0x2d, 0x63, 0x6c, 0x69, 0x65, 0x6e,
|
0x65, 0x6e, 0x74, 0x04, 0x5f, 0x74, 0x63, 0x70, 0x06, 0x6a, 0x61,
|
||||||
0x74, 0x04, 0x5f, 0x74, 0x63, 0x70, 0x06, 0x6a,
|
0x62, 0x62, 0x65, 0x72, 0x03, 0x6f, 0x72, 0x67, 0x00, 0x00, 0x21,
|
||||||
0x61, 0x62, 0x62, 0x65, 0x72, 0x03, 0x6f, 0x72,
|
0x00, 0x01, 0xc0, 0x0c, 0x00, 0x21, 0x00, 0x01, 0x00, 0x00, 0x03,
|
||||||
0x67, 0x00, 0x00, 0x21, 0x00, 0x01, 0xc0, 0x0c,
|
0x83, 0x00, 0x07, 0x00, 0x1e, 0x00, 0x1e, 0x14, 0x66, 0x00, 0xc0,
|
||||||
0x00, 0x21, 0x00, 0x01, 0x00, 0x00, 0x03, 0x83,
|
0x0c, 0x00, 0x21, 0x00, 0x01, 0x00, 0x00, 0x03, 0x83, 0x00, 0x08,
|
||||||
0x00, 0x07, 0x00, 0x1e, 0x00, 0x1e, 0x14, 0x66,
|
0x00, 0x1f, 0x00, 0x1e, 0x14, 0x66, 0xc0, 0x40,
|
||||||
0x00, 0xc0, 0x0c, 0x00, 0x21, 0x00, 0x01, 0x00,
|
|
||||||
0x00, 0x03, 0x83, 0x00, 0x08, 0x00, 0x1f, 0x00,
|
|
||||||
0x1e, 0x14, 0x66, 0xc0, 0x40,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct {
|
static const struct {
|
||||||
@@ -187,12 +164,13 @@ static int srv_rr_list_len(resolver_srv_rr_t *list)
|
|||||||
{
|
{
|
||||||
int nr;
|
int nr;
|
||||||
|
|
||||||
for (nr = 0; list != NULL; ++nr, list = list->next);
|
for (nr = 0; list != NULL; ++nr, list = list->next)
|
||||||
|
;
|
||||||
|
|
||||||
return nr;
|
return nr;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main()
|
||||||
{
|
{
|
||||||
xmpp_ctx_t *ctx;
|
xmpp_ctx_t *ctx;
|
||||||
xmpp_rand_t *rand;
|
xmpp_rand_t *rand;
|
||||||
@@ -223,8 +201,8 @@ int main(int argc, char **argv)
|
|||||||
port = srv_rr_list->port;
|
port = srv_rr_list->port;
|
||||||
COMPARE(tests[i].target, domain);
|
COMPARE(tests[i].target, domain);
|
||||||
if (tests[i].port != port) {
|
if (tests[i].port != port) {
|
||||||
printf("fail! got port=%u, but should be %u\n",
|
printf("fail! got port=%u, but should be %u\n", (unsigned)port,
|
||||||
(unsigned)port, (unsigned)tests[i].port);
|
(unsigned)tests[i].port);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
printf("ok\n");
|
printf("ok\n");
|
||||||
|
|||||||
@@ -69,8 +69,8 @@ int test_digest_md5(xmpp_ctx_t *ctx)
|
|||||||
{
|
{
|
||||||
char *result;
|
char *result;
|
||||||
|
|
||||||
result = sasl_digest_md5(ctx, challenge_md5,
|
result =
|
||||||
"somenode@somerealm", "secret");
|
sasl_digest_md5(ctx, challenge_md5, "somenode@somerealm", "secret");
|
||||||
printf("response:\n%s\n", result);
|
printf("response:\n%s\n", result);
|
||||||
if (strcmp(response_md5, result)) {
|
if (strcmp(response_md5, result)) {
|
||||||
/* generated incorrect response to challenge */
|
/* generated incorrect response to challenge */
|
||||||
@@ -80,27 +80,33 @@ int test_digest_md5(xmpp_ctx_t *ctx)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main()
|
||||||
{
|
{
|
||||||
xmpp_ctx_t *ctx;
|
xmpp_ctx_t *ctx;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
printf("allocating context... ");
|
printf("allocating context... ");
|
||||||
ctx = xmpp_ctx_new(NULL, NULL);
|
ctx = xmpp_ctx_new(NULL, NULL);
|
||||||
if (ctx == NULL) printf("failed to create context\n");
|
if (ctx == NULL)
|
||||||
if (ctx == NULL) return -1;
|
printf("failed to create context\n");
|
||||||
|
if (ctx == NULL)
|
||||||
|
return -1;
|
||||||
printf("ok.\n");
|
printf("ok.\n");
|
||||||
|
|
||||||
printf("testing SASL PLAIN... ");
|
printf("testing SASL PLAIN... ");
|
||||||
ret = test_plain(ctx);
|
ret = test_plain(ctx);
|
||||||
if (ret) printf("failed!\n");
|
if (ret)
|
||||||
if (ret) return ret;
|
printf("failed!\n");
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
printf("ok.\n");
|
printf("ok.\n");
|
||||||
|
|
||||||
printf("testing SASL DIGEST-MD5... ");
|
printf("testing SASL DIGEST-MD5... ");
|
||||||
ret = test_digest_md5(ctx);
|
ret = test_digest_md5(ctx);
|
||||||
if (ret) printf("failed!\n");
|
if (ret)
|
||||||
if (ret) return ret;
|
printf("failed!\n");
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
printf("ok.\n");
|
printf("ok.\n");
|
||||||
|
|
||||||
printf("freeing context... ");
|
printf("freeing context... ");
|
||||||
|
|||||||
@@ -58,19 +58,19 @@ static const struct {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static void test_df(void)
|
static void test_df(const struct hash_alg *alg)
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
const char *s;
|
const char *s;
|
||||||
uint8_t dk[SHA1_DIGEST_SIZE];
|
uint8_t dk[SCRAM_DIGEST_SIZE];
|
||||||
|
|
||||||
printf("Derivation function tests (SCRAM_SHA1_Hi).\n");
|
printf("Derivation function SCRAM_Hi tests for %s.\n", alg->scram_name);
|
||||||
for (i = 0; i < ARRAY_SIZE(df_vectors); ++i) {
|
for (i = 0; i < ARRAY_SIZE(df_vectors); ++i) {
|
||||||
printf("Test #%d: ", (int)i + 1);
|
printf("Test #%d: ", (int)i + 1);
|
||||||
SCRAM_SHA1_Hi((uint8_t *)df_vectors[i].P, df_vectors[i].P_len,
|
SCRAM_Hi(alg, (uint8_t *)df_vectors[i].P, df_vectors[i].P_len,
|
||||||
(uint8_t *)df_vectors[i].S, df_vectors[i].S_len,
|
(uint8_t *)df_vectors[i].S, df_vectors[i].S_len,
|
||||||
df_vectors[i].c, dk);
|
df_vectors[i].c, dk);
|
||||||
s = test_bin_to_hex(dk, sizeof(dk));
|
s = test_bin_to_hex(dk, alg->digest_size);
|
||||||
COMPARE(df_vectors[i].DK, s);
|
COMPARE(df_vectors[i].DK, s);
|
||||||
printf("ok\n");
|
printf("ok\n");
|
||||||
}
|
}
|
||||||
@@ -101,42 +101,115 @@ static const struct {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static void test_scram(void)
|
static void test_scram(const struct hash_alg *alg)
|
||||||
{
|
{
|
||||||
uint8_t key[SHA1_DIGEST_SIZE];
|
uint8_t key[SCRAM_DIGEST_SIZE];
|
||||||
uint8_t sign[SHA1_DIGEST_SIZE];
|
uint8_t sign[SCRAM_DIGEST_SIZE];
|
||||||
uint8_t salt[256];
|
uint8_t salt[256];
|
||||||
size_t salt_len;
|
size_t salt_len;
|
||||||
char auth[512];
|
char auth[512];
|
||||||
const char *s;
|
const char *s;
|
||||||
size_t i;
|
size_t i;
|
||||||
int j;
|
size_t j;
|
||||||
|
|
||||||
printf("SCRAM_SHA1_ClientKey and SCRAM_SHA1_ClientSignature tests.\n");
|
printf("SCRAM_ClientKey and SCRAM_ClientSignature tests for %s.\n",
|
||||||
|
alg->scram_name);
|
||||||
for (i = 0; i < ARRAY_SIZE(scram_vectors); ++i) {
|
for (i = 0; i < ARRAY_SIZE(scram_vectors); ++i) {
|
||||||
printf("Test #%d: ", (int)i + 1);
|
printf("Test #%d: ", (int)i + 1);
|
||||||
snprintf(auth, sizeof(auth), "%s,%s,%s",
|
snprintf(auth, sizeof(auth), "%s,%s,%s", scram_vectors[i].initial + 3,
|
||||||
scram_vectors[i].initial + 3, scram_vectors[i].challenge,
|
scram_vectors[i].challenge, scram_vectors[i].response);
|
||||||
scram_vectors[i].response);
|
|
||||||
test_hex_to_bin(scram_vectors[i].salt, salt, &salt_len);
|
test_hex_to_bin(scram_vectors[i].salt, salt, &salt_len);
|
||||||
|
|
||||||
SCRAM_SHA1_ClientKey((uint8_t *)scram_vectors[i].password,
|
SCRAM_ClientKey(alg, (uint8_t *)scram_vectors[i].password,
|
||||||
strlen(scram_vectors[i].password),
|
strlen(scram_vectors[i].password), salt, salt_len,
|
||||||
salt, salt_len, scram_vectors[i].i, key);
|
scram_vectors[i].i, key);
|
||||||
SCRAM_SHA1_ClientSignature(key, (uint8_t *)auth, strlen(auth), sign);
|
SCRAM_ClientSignature(alg, key, (uint8_t *)auth, strlen(auth), sign);
|
||||||
for (j = 0; j < SHA1_DIGEST_SIZE; j++) {
|
for (j = 0; j < alg->digest_size; j++) {
|
||||||
sign[j] ^= key[j];
|
sign[j] ^= key[j];
|
||||||
}
|
}
|
||||||
s = test_bin_to_hex(sign, SHA1_DIGEST_SIZE);
|
s = test_bin_to_hex(sign, alg->digest_size);
|
||||||
COMPARE(scram_vectors[i].sign, s);
|
COMPARE(scram_vectors[i].sign, s);
|
||||||
printf("ok\n");
|
printf("ok\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
/*
|
||||||
|
* Test vectors for HMAC (RFC2202, RFC4231).
|
||||||
|
*/
|
||||||
|
static const uint8_t hmac_key1[] = {0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
|
||||||
|
0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
|
||||||
|
0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b};
|
||||||
|
static const uint8_t hmac_data1[] = {0x48, 0x69, 0x20, 0x54,
|
||||||
|
0x68, 0x65, 0x72, 0x65};
|
||||||
|
static const struct {
|
||||||
|
const uint8_t *key;
|
||||||
|
size_t key_len;
|
||||||
|
const uint8_t *data;
|
||||||
|
size_t data_len;
|
||||||
|
const uint8_t sha1[SHA1_DIGEST_SIZE];
|
||||||
|
const uint8_t sha256[SHA256_DIGEST_SIZE];
|
||||||
|
const uint8_t sha512[SHA512_DIGEST_SIZE];
|
||||||
|
} hmac_vectors[] = {
|
||||||
{
|
{
|
||||||
test_df();
|
.key = hmac_key1,
|
||||||
test_scram();
|
.key_len = sizeof(hmac_key1),
|
||||||
|
.data = hmac_data1,
|
||||||
|
.data_len = sizeof(hmac_data1),
|
||||||
|
.sha1 = {0xb6, 0x17, 0x31, 0x86, 0x55, 0x05, 0x72, 0x64, 0xe2, 0x8b,
|
||||||
|
0xc0, 0xb6, 0xfb, 0x37, 0x8c, 0x8e, 0xf1, 0x46, 0xbe, 0x00},
|
||||||
|
.sha256 = {0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53,
|
||||||
|
0x5c, 0xa8, 0xaf, 0xce, 0xaf, 0x0b, 0xf1, 0x2b,
|
||||||
|
0x88, 0x1d, 0xc2, 0x00, 0xc9, 0x83, 0x3d, 0xa7,
|
||||||
|
0x26, 0xe9, 0x37, 0x6c, 0x2e, 0x32, 0xcf, 0xf7},
|
||||||
|
.sha512 = {0x87, 0xaa, 0x7c, 0xde, 0xa5, 0xef, 0x61, 0x9d, 0x4f, 0xf0,
|
||||||
|
0xb4, 0x24, 0x1a, 0x1d, 0x6c, 0xb0, 0x23, 0x79, 0xf4, 0xe2,
|
||||||
|
0xce, 0x4e, 0xc2, 0x78, 0x7a, 0xd0, 0xb3, 0x05, 0x45, 0xe1,
|
||||||
|
0x7c, 0xde, 0xda, 0xa8, 0x33, 0xb7, 0xd6, 0xb8, 0xa7, 0x02,
|
||||||
|
0x03, 0x8b, 0x27, 0x4e, 0xae, 0xa3, 0xf4, 0xe4, 0xbe, 0x9d,
|
||||||
|
0x91, 0x4e, 0xeb, 0x61, 0xf1, 0x70, 0x2e, 0x69, 0x6c, 0x20,
|
||||||
|
0x3a, 0x12, 0x68, 0x54},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static void test_hmac(const struct hash_alg *alg)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
uint8_t digest[SCRAM_DIGEST_SIZE];
|
||||||
|
|
||||||
|
printf("HMAC tests for %s.\n", alg->scram_name);
|
||||||
|
for (i = 0; i < ARRAY_SIZE(hmac_vectors); ++i) {
|
||||||
|
printf("Test #%d: ", (int)i + 1);
|
||||||
|
memset(digest, 0, sizeof(digest));
|
||||||
|
crypto_HMAC(alg, hmac_vectors[i].key, hmac_vectors[i].key_len,
|
||||||
|
hmac_vectors[i].data, hmac_vectors[i].data_len, digest);
|
||||||
|
switch (alg->digest_size) {
|
||||||
|
case SHA1_DIGEST_SIZE:
|
||||||
|
COMPARE_BUF(hmac_vectors[i].sha1, alg->digest_size, digest,
|
||||||
|
alg->digest_size);
|
||||||
|
break;
|
||||||
|
case SHA256_DIGEST_SIZE:
|
||||||
|
COMPARE_BUF(hmac_vectors[i].sha256, alg->digest_size, digest,
|
||||||
|
alg->digest_size);
|
||||||
|
break;
|
||||||
|
case SHA512_DIGEST_SIZE:
|
||||||
|
COMPARE_BUF(hmac_vectors[i].sha512, alg->digest_size, digest,
|
||||||
|
alg->digest_size);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf("Unknown digest size: %zu\n", alg->digest_size);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
printf("ok\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
test_df(&scram_sha1);
|
||||||
|
test_scram(&scram_sha1);
|
||||||
|
test_hmac(&scram_sha1);
|
||||||
|
test_hmac(&scram_sha256);
|
||||||
|
test_hmac(&scram_sha512);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,13 +12,11 @@
|
|||||||
|
|
||||||
/* Test Vectors (from FIPS PUB 180-1) */
|
/* Test Vectors (from FIPS PUB 180-1) */
|
||||||
static char *test_data[] = {
|
static char *test_data[] = {
|
||||||
"abc",
|
"abc", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
|
||||||
"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
|
|
||||||
"A million repetitions of 'a'",
|
"A million repetitions of 'a'",
|
||||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"};
|
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"};
|
||||||
static char *test_results[] = {
|
static char *test_results[] = {"A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D",
|
||||||
"A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D",
|
|
||||||
"84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1",
|
"84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1",
|
||||||
"34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F",
|
"34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F",
|
||||||
"AD5B3FDB CB526778 C2839D2F 151EA753 995E26A0"};
|
"AD5B3FDB CB526778 C2839D2F 151EA753 995E26A0"};
|
||||||
@@ -39,9 +37,9 @@ static void digest_to_hex(const uint8_t *digest, char *output)
|
|||||||
*(c - 1) = '\0';
|
*(c - 1) = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
int main()
|
||||||
{
|
{
|
||||||
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];
|
||||||
|
|||||||
44
tests/test_sha256.c
Normal file
44
tests/test_sha256.c
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
/* Tests for SHA-256 from LibTomCrypt */
|
||||||
|
/* This file is in the public domain */
|
||||||
|
|
||||||
|
/* gcc -o test_sha256 -I./src tests/test_sha256.c tests/test.c src/sha256.c */
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "sha256.h"
|
||||||
|
#include "test.h"
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
static const struct {
|
||||||
|
const char *msg;
|
||||||
|
unsigned char hash[SHA256_DIGEST_SIZE];
|
||||||
|
} tests[] = {
|
||||||
|
{"abc",
|
||||||
|
{0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40,
|
||||||
|
0xde, 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17,
|
||||||
|
0x7a, 0x9c, 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad}},
|
||||||
|
{"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
|
||||||
|
{0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8, 0xe5, 0xc0, 0x26,
|
||||||
|
0x93, 0x0c, 0x3e, 0x60, 0x39, 0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff,
|
||||||
|
0x21, 0x67, 0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1}},
|
||||||
|
};
|
||||||
|
|
||||||
|
int i;
|
||||||
|
unsigned char tmp[SHA256_DIGEST_SIZE];
|
||||||
|
sha256_context md;
|
||||||
|
|
||||||
|
for (i = 0; i < (int)(sizeof(tests) / sizeof(tests[0])); i++) {
|
||||||
|
sha256_init(&md);
|
||||||
|
sha256_process(&md, (unsigned char *)tests[i].msg,
|
||||||
|
(unsigned long)strlen(tests[i].msg));
|
||||||
|
sha256_done(&md, tmp);
|
||||||
|
COMPARE_BUF(tmp, sizeof(tmp), tests[i].hash, sizeof(tests[i].hash));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* success */
|
||||||
|
fprintf(stdout, "ok\n");
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
65
tests/test_sha512.c
Normal file
65
tests/test_sha512.c
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
/* Tests for SHA-512 from LibTomCrypt */
|
||||||
|
/* This file is in the public domain */
|
||||||
|
|
||||||
|
/* gcc -o test_sha512 -I./src tests/test_sha512.c tests/test.c src/sha512.c */
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "sha512.h"
|
||||||
|
#include "test.h"
|
||||||
|
|
||||||
|
static const uint8_t hash_1m_a[SHA512_DIGEST_SIZE] = {
|
||||||
|
0xe7, 0x18, 0x48, 0x3d, 0x0c, 0xe7, 0x69, 0x64, 0x4e, 0x2e, 0x42,
|
||||||
|
0xc7, 0xbc, 0x15, 0xb4, 0x63, 0x8e, 0x1f, 0x98, 0xb1, 0x3b, 0x20,
|
||||||
|
0x44, 0x28, 0x56, 0x32, 0xa8, 0x03, 0xaf, 0xa9, 0x73, 0xeb, 0xde,
|
||||||
|
0x0f, 0xf2, 0x44, 0x87, 0x7e, 0xa6, 0x0a, 0x4c, 0xb0, 0x43, 0x2c,
|
||||||
|
0xe5, 0x77, 0xc3, 0x1b, 0xeb, 0x00, 0x9c, 0x5c, 0x2c, 0x49, 0xaa,
|
||||||
|
0x2e, 0x4e, 0xad, 0xb2, 0x17, 0xad, 0x8c, 0xc0, 0x9b};
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
static const struct {
|
||||||
|
const char *msg;
|
||||||
|
uint8_t hash[SHA512_DIGEST_SIZE];
|
||||||
|
} tests[] = {
|
||||||
|
{"abc",
|
||||||
|
{0xdd, 0xaf, 0x35, 0xa1, 0x93, 0x61, 0x7a, 0xba, 0xcc, 0x41, 0x73,
|
||||||
|
0x49, 0xae, 0x20, 0x41, 0x31, 0x12, 0xe6, 0xfa, 0x4e, 0x89, 0xa9,
|
||||||
|
0x7e, 0xa2, 0x0a, 0x9e, 0xee, 0xe6, 0x4b, 0x55, 0xd3, 0x9a, 0x21,
|
||||||
|
0x92, 0x99, 0x2a, 0x27, 0x4f, 0xc1, 0xa8, 0x36, 0xba, 0x3c, 0x23,
|
||||||
|
0xa3, 0xfe, 0xeb, 0xbd, 0x45, 0x4d, 0x44, 0x23, 0x64, 0x3c, 0xe8,
|
||||||
|
0x0e, 0x2a, 0x9a, 0xc9, 0x4f, 0xa5, 0x4c, 0xa4, 0x9f}},
|
||||||
|
{"abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklm"
|
||||||
|
"nopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu",
|
||||||
|
{0x8e, 0x95, 0x9b, 0x75, 0xda, 0xe3, 0x13, 0xda, 0x8c, 0xf4, 0xf7,
|
||||||
|
0x28, 0x14, 0xfc, 0x14, 0x3f, 0x8f, 0x77, 0x79, 0xc6, 0xeb, 0x9f,
|
||||||
|
0x7f, 0xa1, 0x72, 0x99, 0xae, 0xad, 0xb6, 0x88, 0x90, 0x18, 0x50,
|
||||||
|
0x1d, 0x28, 0x9e, 0x49, 0x00, 0xf7, 0xe4, 0x33, 0x1b, 0x99, 0xde,
|
||||||
|
0xc4, 0xb5, 0x43, 0x3a, 0xc7, 0xd3, 0x29, 0xee, 0xb6, 0xdd, 0x26,
|
||||||
|
0x54, 0x5e, 0x96, 0xe5, 0x5b, 0x87, 0x4b, 0xe9, 0x09}},
|
||||||
|
};
|
||||||
|
|
||||||
|
size_t i;
|
||||||
|
uint8_t tmp[SHA512_DIGEST_SIZE];
|
||||||
|
sha512_context md;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(tests); i++) {
|
||||||
|
sha512_init(&md);
|
||||||
|
sha512_process(&md, (uint8_t *)tests[i].msg, strlen(tests[i].msg));
|
||||||
|
sha512_done(&md, tmp);
|
||||||
|
COMPARE_BUF(tests[i].hash, sizeof(tests[i].hash), tmp, sizeof(tmp));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* special case: one million repetitions of the character 'a' */
|
||||||
|
sha512_init(&md);
|
||||||
|
for (i = 0; i < 1000000U; ++i)
|
||||||
|
sha512_process(&md, (uint8_t *)"a", 1);
|
||||||
|
sha512_done(&md, tmp);
|
||||||
|
COMPARE_BUF(hash_1m_a, sizeof(hash_1m_a), tmp, sizeof(tmp));
|
||||||
|
|
||||||
|
/* success */
|
||||||
|
fprintf(stdout, "ok\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -20,38 +20,14 @@ int main (void)
|
|||||||
{
|
{
|
||||||
char buf1[LONG_STRING];
|
char buf1[LONG_STRING];
|
||||||
char buf2[LONG_STRING];
|
char buf2[LONG_STRING];
|
||||||
char *fp_fmt[] = {
|
char *fp_fmt[] = {"%-1.5f", "%1.5f", "%123.9f", "%10.5f", "% 10.5f",
|
||||||
"%-1.5f",
|
"%+22.9f", "%+4.9f", "%01.3f", "%4f", "%3.1f",
|
||||||
"%1.5f",
|
"%3.2f", "%.0f", "%.1f", NULL};
|
||||||
"%123.9f",
|
double fp_nums[] = {-1.5, 134.21, 91340.2, 341.1234, 0203.9, 0.96,
|
||||||
"%10.5f",
|
0.996, 0.9996, 1.996, 4.136, 0};
|
||||||
"% 10.5f",
|
char *int_fmt[] = {"%-1.5d", "%1.5d", "%123.9d", "%5.5d",
|
||||||
"%+22.9f",
|
"%10.5d", "% 10.5d", "%+22.33d", "%01.3d",
|
||||||
"%+4.9f",
|
"%4d", "0x%x", "0x%04x", NULL};
|
||||||
"%01.3f",
|
|
||||||
"%4f",
|
|
||||||
"%3.1f",
|
|
||||||
"%3.2f",
|
|
||||||
"%.0f",
|
|
||||||
"%.1f",
|
|
||||||
NULL
|
|
||||||
};
|
|
||||||
double fp_nums[] = { -1.5, 134.21, 91340.2, 341.1234, 0203.9, 0.96, 0.996,
|
|
||||||
0.9996, 1.996, 4.136, 0};
|
|
||||||
char *int_fmt[] = {
|
|
||||||
"%-1.5d",
|
|
||||||
"%1.5d",
|
|
||||||
"%123.9d",
|
|
||||||
"%5.5d",
|
|
||||||
"%10.5d",
|
|
||||||
"% 10.5d",
|
|
||||||
"%+22.33d",
|
|
||||||
"%01.3d",
|
|
||||||
"%4d",
|
|
||||||
"0x%x",
|
|
||||||
"0x%04x",
|
|
||||||
NULL
|
|
||||||
};
|
|
||||||
long int_nums[] = {-1, 134, 91340, 341, 0203, 0x76543210, 0};
|
long int_nums[] = {-1, 134, 91340, 341, 0203, 0x76543210, 0};
|
||||||
int x, y;
|
int x, y;
|
||||||
int fail = 0;
|
int fail = 0;
|
||||||
@@ -60,13 +36,12 @@ int main (void)
|
|||||||
printf("Testing xmpp_snprintf format codes against system sprintf...\n");
|
printf("Testing xmpp_snprintf format codes against system sprintf...\n");
|
||||||
|
|
||||||
for (x = 0; fp_fmt[x] != NULL; x++)
|
for (x = 0; fp_fmt[x] != NULL; x++)
|
||||||
for (y = 0; fp_nums[y] != 0 ; y++)
|
for (y = 0; fp_nums[y] != 0; y++) {
|
||||||
{
|
|
||||||
xmpp_snprintf(buf1, sizeof(buf1), fp_fmt[x], fp_nums[y]);
|
xmpp_snprintf(buf1, sizeof(buf1), fp_fmt[x], fp_nums[y]);
|
||||||
sprintf(buf2, fp_fmt[x], fp_nums[y]);
|
sprintf(buf2, fp_fmt[x], fp_nums[y]);
|
||||||
if (strcmp (buf1, buf2))
|
if (strcmp(buf1, buf2)) {
|
||||||
{
|
printf("xmpp_snprintf doesn't match Format: "
|
||||||
printf("xmpp_snprintf doesn't match Format: %s\n\txmpp_snprintf = %s\n\tsprintf = %s\n",
|
"%s\n\txmpp_snprintf = %s\n\tsprintf = %s\n",
|
||||||
fp_fmt[x], buf1, buf2);
|
fp_fmt[x], buf1, buf2);
|
||||||
fail++;
|
fail++;
|
||||||
}
|
}
|
||||||
@@ -74,13 +49,12 @@ int main (void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (x = 0; int_fmt[x] != NULL; x++)
|
for (x = 0; int_fmt[x] != NULL; x++)
|
||||||
for (y = 0; int_nums[y] != 0 ; y++)
|
for (y = 0; int_nums[y] != 0; y++) {
|
||||||
{
|
|
||||||
xmpp_snprintf(buf1, sizeof(buf1), int_fmt[x], int_nums[y]);
|
xmpp_snprintf(buf1, sizeof(buf1), int_fmt[x], int_nums[y]);
|
||||||
sprintf(buf2, int_fmt[x], int_nums[y]);
|
sprintf(buf2, int_fmt[x], int_nums[y]);
|
||||||
if (strcmp (buf1, buf2))
|
if (strcmp(buf1, buf2)) {
|
||||||
{
|
printf("xmpp_snprintf doesn't match Format: "
|
||||||
printf("xmpp_snprintf doesn't match Format: %s\n\txmpp_snprintf = %s\n\tsprintf = %s\n",
|
"%s\n\txmpp_snprintf = %s\n\tsprintf = %s\n",
|
||||||
int_fmt[x], buf1, buf2);
|
int_fmt[x], buf1, buf2);
|
||||||
fail++;
|
fail++;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,19 +23,24 @@ int wait_for_connect(sock_t sock)
|
|||||||
fd_set wfds, efds;
|
fd_set wfds, efds;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
FD_ZERO(&wfds); FD_SET(sock, &wfds);
|
FD_ZERO(&wfds);
|
||||||
FD_ZERO(&efds); FD_SET(sock, &efds);
|
FD_SET(sock, &wfds);
|
||||||
|
FD_ZERO(&efds);
|
||||||
|
FD_SET(sock, &efds);
|
||||||
|
|
||||||
ret = select(sock + 1, NULL, &wfds, &efds, NULL);
|
ret = select(sock + 1, NULL, &wfds, &efds, NULL);
|
||||||
if (ret <= 0) return -1;
|
if (ret <= 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
if (FD_ISSET(sock, &efds)) return 0;
|
if (FD_ISSET(sock, &efds))
|
||||||
if (FD_ISSET(sock, &wfds)) return 1;
|
return 0;
|
||||||
|
if (FD_ISSET(sock, &wfds))
|
||||||
|
return 1;
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main()
|
||||||
{
|
{
|
||||||
sock_t sock;
|
sock_t sock;
|
||||||
int err;
|
int err;
|
||||||
|
|||||||
131
tests/test_stanza.c
Normal file
131
tests/test_stanza.c
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
/* 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>
|
||||||
|
#include <string.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);
|
||||||
|
|
||||||
|
if (ptr != NULL) {
|
||||||
|
assert(used_blocks > 0);
|
||||||
|
--used_blocks;
|
||||||
|
}
|
||||||
|
free(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *stanza_realloc(void *ptr, size_t size, void *userdata)
|
||||||
|
{
|
||||||
|
assert(userdata == MAGICPTR);
|
||||||
|
|
||||||
|
if (ptr != NULL && size == 0) {
|
||||||
|
/* equivalent to free(ptr) */
|
||||||
|
assert(used_blocks > 0);
|
||||||
|
--used_blocks;
|
||||||
|
} else if (ptr == NULL) {
|
||||||
|
/* equivalent to malloc(size) */
|
||||||
|
++used_blocks;
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_stanza_from_string(xmpp_ctx_t *ctx)
|
||||||
|
{
|
||||||
|
xmpp_stanza_t *stanza;
|
||||||
|
char *buf;
|
||||||
|
size_t buflen;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
static const char *str =
|
||||||
|
"<signcrypt xmlns=\"urn:xmpp:openpgp:0\"><to "
|
||||||
|
"jid=\"user@domain.com\"/><time "
|
||||||
|
"stamp=\"2020-06-03T21:26:24+0200\"/><rpad/><payload><body "
|
||||||
|
"xmlns=\"jabber:client\">Hello World!</body></payload></signcrypt>";
|
||||||
|
|
||||||
|
stanza = xmpp_stanza_new_from_string(ctx, str);
|
||||||
|
assert(stanza != NULL);
|
||||||
|
ret = xmpp_stanza_to_text(stanza, &buf, &buflen);
|
||||||
|
assert(ret == XMPP_EOK);
|
||||||
|
assert(strcmp(buf, str) == 0);
|
||||||
|
xmpp_free(ctx, buf);
|
||||||
|
xmpp_stanza_release(stanza);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
xmpp_ctx_t *ctx;
|
||||||
|
|
||||||
|
xmpp_initialize();
|
||||||
|
ctx = xmpp_ctx_new(&stanza_mem, NULL);
|
||||||
|
assert(ctx != NULL);
|
||||||
|
|
||||||
|
test_stanza_add_child(ctx);
|
||||||
|
test_stanza_from_string(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--";
|
||||||
@@ -65,8 +75,8 @@ static int test_strdup_one(xmpp_ctx_t *ctx, const char *s)
|
|||||||
|
|
||||||
if (!s1 || !s2 || strcmp(s1, s2) != 0) {
|
if (!s1 || !s2 || strcmp(s1, s2) != 0) {
|
||||||
rc = -1;
|
rc = -1;
|
||||||
printf("strdup: '%s', xmpp_strdup: '%s'\n",
|
printf("strdup: '%s', xmpp_strdup: '%s'\n", s1 ? s1 : "<NULL>",
|
||||||
s1 ? s1 : "<NULL>", s2 ? s2 : "<NULL>");
|
s2 ? s2 : "<NULL>");
|
||||||
}
|
}
|
||||||
|
|
||||||
free(s1);
|
free(s1);
|
||||||
@@ -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