Compare commits
235 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9dfe01bf83 | ||
|
|
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 | ||
|
|
9931ad4fa2 | ||
|
|
5a1f282292 | ||
|
|
b360316b8b | ||
|
|
c6aaa96dcb | ||
|
|
f0706f56c4 | ||
|
|
4ef2740c36 | ||
|
|
5e0330f0ad | ||
|
|
717a19859f | ||
|
|
209f21905e | ||
|
|
38aa05624d | ||
|
|
136055024e | ||
|
|
8d3f3d837a | ||
|
|
151debf7ee | ||
|
|
d8da993a73 | ||
|
|
72173087a9 | ||
|
|
229215b49c | ||
|
|
dd7aeff5d2 | ||
|
|
3e95806d2e | ||
|
|
7ad42add73 | ||
|
|
936ddb0d15 | ||
|
|
233094af10 | ||
|
|
94e84f0643 | ||
|
|
8662611a34 | ||
|
|
60e6c191e9 | ||
|
|
211170822f | ||
|
|
c80f99bc68 | ||
|
|
53e44aa0e3 | ||
|
|
2b249130c9 | ||
|
|
84fa4466ee | ||
|
|
beaaab5742 | ||
|
|
f351d62355 | ||
|
|
b6fcb7035d | ||
|
|
c0a224cf84 | ||
|
|
384ef8023e | ||
|
|
f44232762e | ||
|
|
111659cc91 | ||
|
|
4ae4b8c94b | ||
|
|
2b2de142ef | ||
|
|
a45af3a929 | ||
|
|
3e77afb27e | ||
|
|
0c60e8d384 | ||
|
|
2bff3f8722 | ||
|
|
dc56737b71 | ||
|
|
3869906357 | ||
|
|
75b19be572 | ||
|
|
b0a1842a53 | ||
|
|
14066d0bff | ||
|
|
171b285cbe | ||
|
|
f46cf669a3 | ||
|
|
09e5103eee | ||
|
|
1a657c67e2 | ||
|
|
3e86987f5f | ||
|
|
e83d0d6b62 | ||
|
|
2ffb278aa4 | ||
|
|
7f57e3987a | ||
|
|
c62d1d64ab | ||
|
|
c9a5cba113 | ||
|
|
e4a4bdd3a3 | ||
|
|
565ace7982 | ||
|
|
71d90d60a5 | ||
|
|
b5d9b33b6f | ||
|
|
063f4deb22 | ||
|
|
192ab59608 | ||
|
|
a3da77b8f6 | ||
|
|
c0aad0bf00 | ||
|
|
a2834f8f92 | ||
|
|
2ef432f632 | ||
|
|
a50d706bcd | ||
|
|
ca7af9c837 | ||
|
|
a65679dd72 | ||
|
|
211748e65a | ||
|
|
4c0c12343f | ||
|
|
96873984b2 | ||
|
|
b06599963b | ||
|
|
ab80d72518 | ||
|
|
ba7422c893 | ||
|
|
4b444ea699 | ||
|
|
96dc61c772 | ||
|
|
f5c2c81142 | ||
|
|
838ed493a3 | ||
|
|
9d7b3394e7 | ||
|
|
9e4e274c4d | ||
|
|
e3b9fa1e53 | ||
|
|
85bf3f4241 | ||
|
|
6d70bf4b0d | ||
|
|
3aafeef215 | ||
|
|
e60895087e | ||
|
|
b169c0a91e | ||
|
|
968cb7dcdf | ||
|
|
367aeb5844 | ||
|
|
5518a9e10a | ||
|
|
6c1c2a86f8 | ||
|
|
cb79f5c10b | ||
|
|
b7e308d057 | ||
|
|
714b2f9c03 | ||
|
|
a7c18ba6c7 | ||
|
|
fc82aaeef2 | ||
|
|
c291513663 | ||
|
|
a413c68e52 | ||
|
|
5b41247bac | ||
|
|
fc563272fe | ||
|
|
38545af533 | ||
|
|
6f612d4f4d | ||
|
|
a1bc5e82cf | ||
|
|
98c8afd5fc | ||
|
|
cff4a4cd71 | ||
|
|
7bbfd00344 | ||
|
|
01af2deed9 | ||
|
|
a54def3e92 | ||
|
|
2aea1a627c | ||
|
|
e475ca13ea | ||
|
|
31582cac92 | ||
|
|
c012f20c99 | ||
|
|
d460a5eb16 | ||
|
|
3a56d68f47 | ||
|
|
9de0293405 | ||
|
|
21f742f888 | ||
|
|
0d4bcc0228 | ||
|
|
90a595f8ef | ||
|
|
64d65b3aed | ||
|
|
a39267c1b0 | ||
|
|
331db6f565 | ||
|
|
9cea7e4002 | ||
|
|
f63aba88d4 | ||
|
|
a78201bae0 | ||
|
|
a61dba0c13 | ||
|
|
60cfcc72e6 | ||
|
|
4cc9ba79c4 | ||
|
|
182803926b | ||
|
|
e41b7a06e4 | ||
|
|
0994022066 | ||
|
|
c156e13791 | ||
|
|
a47b71e52b | ||
|
|
db908563d0 | ||
|
|
b5e49a0600 | ||
|
|
e0a13ecdaa | ||
|
|
fc856f36a3 | ||
|
|
9b67acbfc4 | ||
|
|
b04c40d3ea | ||
|
|
442914c375 | ||
|
|
a4558b69df | ||
|
|
07751974ac | ||
|
|
8ff46add8c | ||
|
|
b7fbc81740 | ||
|
|
36af7afa27 | ||
|
|
254b9d73a1 | ||
|
|
8fcac79301 | ||
|
|
a48add8f13 | ||
|
|
8627fbb13f | ||
|
|
5e64c850bd | ||
|
|
533664903a | ||
|
|
cda805163f | ||
|
|
3d4c657467 | ||
|
|
8339fd0420 | ||
|
|
63946ff7ef | ||
|
|
e6bbfa7a62 | ||
|
|
b2a98fb9b6 | ||
|
|
f326c2f42f | ||
|
|
3b55c20879 | ||
|
|
a335466450 | ||
|
|
c73ddf065b | ||
|
|
fa585fd107 | ||
|
|
7a782df9f5 | ||
|
|
982d840472 | ||
|
|
75938845fd | ||
|
|
e70e755e19 | ||
|
|
5e37de2b63 | ||
|
|
10656ead46 | ||
|
|
75b1a633d6 | ||
|
|
109aaa71a5 | ||
|
|
92709a773c | ||
|
|
93f9a5d1e8 | ||
|
|
0acec5c335 | ||
|
|
0e8d407f93 | ||
|
|
ed5f982312 |
18
.gitignore
vendored
18
.gitignore
vendored
@@ -1,8 +1,7 @@
|
||||
*.swp
|
||||
Makefile
|
||||
test-driver
|
||||
.libs
|
||||
src/*.lo
|
||||
*.la
|
||||
Makefile.in
|
||||
configure
|
||||
libtool
|
||||
@@ -21,8 +20,10 @@ autom4te.cache
|
||||
.deps
|
||||
.sconsign*
|
||||
src/*.o
|
||||
src/*.lo
|
||||
examples/*.o
|
||||
*.a
|
||||
*.la
|
||||
*.pc
|
||||
*.tar.gz
|
||||
*.zip
|
||||
@@ -33,7 +34,10 @@ examples/active
|
||||
examples/basic
|
||||
examples/bot
|
||||
examples/component
|
||||
examples/ext_auth
|
||||
examples/roster
|
||||
examples/uuid
|
||||
examples/vcard
|
||||
test_stamp
|
||||
test-suite.log
|
||||
tests/*.o
|
||||
@@ -44,7 +48,17 @@ tests/test_base64
|
||||
tests/test_ctx
|
||||
tests/test_hash
|
||||
tests/test_jid
|
||||
tests/test_md5
|
||||
tests/test_rand
|
||||
tests/test_resolver
|
||||
tests/test_sasl
|
||||
tests/test_scram
|
||||
tests/test_sha1
|
||||
tests/test_snprintf
|
||||
tests/test_string
|
||||
tests/test_sock
|
||||
m4/
|
||||
libstrophe.project
|
||||
libs/
|
||||
obj/
|
||||
expat/
|
||||
|
||||
15
.travis.yml
Normal file
15
.travis.yml
Normal file
@@ -0,0 +1,15 @@
|
||||
language: c
|
||||
install:
|
||||
- sudo apt-get update
|
||||
- sudo apt-get -y install libtool pkg-config libexpat1-dev libxml2-dev libssl-dev check
|
||||
before_script:
|
||||
- ./bootstrap.sh
|
||||
script:
|
||||
- ./configure ${CONFIGURE_OPT} && make && make check-TESTS
|
||||
env:
|
||||
- CONFIGURE_OPT="--without-libxml2"
|
||||
- CONFIGURE_OPT="--with-libxml2"
|
||||
- CONFIGURE_OPT="--disable-tls --without-libxml2"
|
||||
- CONFIGURE_OPT="--disable-tls --with-libxml2"
|
||||
matrix:
|
||||
fast_finish: true
|
||||
59
ChangeLog
59
ChangeLog
@@ -1,3 +1,62 @@
|
||||
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
|
||||
- New functions:
|
||||
- xmpp_ctx_set_timeout()
|
||||
- xmpp_sha1_digest()
|
||||
|
||||
0.9.1
|
||||
- Fixed bug #95 (DNS lookup failing on Cygwin)
|
||||
- Removed dependency on the check package
|
||||
|
||||
0.9.0
|
||||
- IPv6 support
|
||||
- Legacy SSL support
|
||||
- Initial Android support
|
||||
- Resolver returns all SRV records instead of one. Lookup is performed
|
||||
according to RFC2052
|
||||
- xmpp_connect_raw() provides access to a xmpp_conn object just after
|
||||
establishing TCP connection. This allows to implement in-band
|
||||
registration, authentication mechanisms or serverless messaging
|
||||
- xmpp_conn_t object is reusable now and can be reconnected with saving
|
||||
all handlers, flags, jid and password
|
||||
- New API:
|
||||
- xmpp_uuid_gen()
|
||||
- xmpp_connect_raw()
|
||||
- xmpp_conn_open_stream_default()
|
||||
- xmpp_conn_open_stream()
|
||||
- xmpp_conn_tls_start()
|
||||
- xmpp_conn_get_flags()
|
||||
- xmpp_conn_set_flags()
|
||||
- xmpp_conn_set_keepalive()
|
||||
- xmpp_conn_is_secured()
|
||||
- xmpp_stanza_del_attribute()
|
||||
- xmpp_stanza_get_to()
|
||||
- xmpp_stanza_get_from()
|
||||
- xmpp_stanza_set_to()
|
||||
- xmpp_stanza_set_from()
|
||||
- xmpp_stanza_reply()
|
||||
- xmpp_message_new()
|
||||
- xmpp_message_get_body()
|
||||
- xmpp_message_set_body()
|
||||
- xmpp_iq_new()
|
||||
- xmpp_presence_new()
|
||||
- Exposed private API:
|
||||
- xmpp_jid_new()
|
||||
- xmpp_jid_bare()
|
||||
- xmpp_jid_node()
|
||||
- xmpp_jid_domain()
|
||||
- xmpp_jid_resource()
|
||||
- xmpp_stanza_get_attribute_count()
|
||||
- xmpp_stanza_get_attributes()
|
||||
|
||||
0.8.8
|
||||
- XML namespace support
|
||||
- XEP-0114 support
|
||||
|
||||
168
Makefile.am
168
Makefile.am
@@ -9,25 +9,61 @@ PARSER_LIBS=@PARSER_LIBS@
|
||||
SSL_CFLAGS = @openssl_CFLAGS@
|
||||
SSL_LIBS = @openssl_LIBS@
|
||||
|
||||
STROPHE_FLAGS = -I$(top_srcdir)
|
||||
RESOLV_LIBS = @RESOLV_LIBS@
|
||||
|
||||
STROPHE_FLAGS = -I$(top_srcdir) -Wall -Wextra -Werror -Wno-unused-parameter
|
||||
STROPHE_LIBS = libstrophe.la
|
||||
|
||||
## Main build targets
|
||||
lib_LTLIBRARIES = libstrophe.la
|
||||
|
||||
libstrophe_la_CFLAGS = $(SSL_CFLAGS) $(STROPHE_FLAGS) $(PARSER_CFLAGS)
|
||||
libstrophe_la_LDFLAGS = $(SSL_LIBS) $(PARSER_LIBS)
|
||||
libstrophe_la_LDFLAGS = $(SSL_LIBS) $(PARSER_LIBS) $(RESOLV_LIBS) -no-undefined
|
||||
# Export only public API
|
||||
libstrophe_la_LDFLAGS += -export-symbols-regex '^xmpp_'
|
||||
libstrophe_la_SOURCES = src/auth.c src/conn.c src/ctx.c \
|
||||
src/event.c src/handler.c src/hash.c \
|
||||
src/jid.c src/md5.c src/sasl.c src/scram.c src/sha1.c \
|
||||
src/snprintf.c src/sock.c src/stanza.c src/thread.c \
|
||||
src/tls_openssl.c src/util.c \
|
||||
src/common.h src/hash.h src/md5.h src/ostypes.h src/parser.h \
|
||||
src/sasl.h src/scram.h src/sha1.h src/sock.h src/thread.h src/tls.h \
|
||||
|
||||
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 \
|
||||
src/rand.c \
|
||||
src/resolver.c \
|
||||
src/sasl.c \
|
||||
src/scram.c \
|
||||
src/sha1.c \
|
||||
src/snprintf.c \
|
||||
src/sock.c \
|
||||
src/stanza.c \
|
||||
src/util.c \
|
||||
src/uuid.c
|
||||
libstrophe_la_SOURCES += \
|
||||
src/common.h \
|
||||
src/hash.h \
|
||||
src/md5.h \
|
||||
src/ostypes.h \
|
||||
src/parser.h \
|
||||
src/rand.h \
|
||||
src/resolver.h \
|
||||
src/sasl.h \
|
||||
src/scram.h \
|
||||
src/sha1.h \
|
||||
src/snprintf.h \
|
||||
src/sock.h \
|
||||
src/tls.h \
|
||||
src/util.h
|
||||
|
||||
if DISABLE_TLS
|
||||
libstrophe_la_SOURCES += src/tls_dummy.c
|
||||
else
|
||||
libstrophe_la_SOURCES += src/tls_openssl.c
|
||||
endif
|
||||
|
||||
if PARSER_EXPAT
|
||||
libstrophe_la_SOURCES += src/parser_expat.c
|
||||
else
|
||||
@@ -39,32 +75,124 @@ noinst_HEADERS = strophepp.h
|
||||
|
||||
pkgconfig_DATA = libstrophe.pc
|
||||
|
||||
EXTRA_DIST = docs
|
||||
EXTRA_DIST = \
|
||||
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 \
|
||||
rpm/README \
|
||||
rpm/libstrophe.spec \
|
||||
src/tls_gnutls.c \
|
||||
src/tls_schannel.c \
|
||||
tests/res_query_dump.c
|
||||
|
||||
## Examples
|
||||
noinst_PROGRAMS = examples/active examples/roster examples/basic examples/bot examples/component
|
||||
noinst_PROGRAMS = \
|
||||
examples/active \
|
||||
examples/basic \
|
||||
examples/bot \
|
||||
examples/component \
|
||||
examples/ext_auth \
|
||||
examples/roster \
|
||||
examples/uuid \
|
||||
examples/vcard
|
||||
|
||||
examples_active_SOURCES = examples/active.c
|
||||
examples_active_CFLAGS = $(STROPHE_FLAGS)
|
||||
examples_active_LDADD = $(STROPHE_LIBS)
|
||||
examples_roster_SOURCES = examples/roster.c
|
||||
examples_roster_CFLAGS = $(STROPHE_FLAGS)
|
||||
examples_roster_LDADD = $(STROPHE_LIBS)
|
||||
examples_active_LDADD = $(STROPHE_LIBS)
|
||||
examples_basic_SOURCES = examples/basic.c
|
||||
examples_basic_CFLAGS = $(STROPHE_FLAGS)
|
||||
examples_basic_LDADD = $(STROPHE_LIBS)
|
||||
examples_basic_LDADD = $(STROPHE_LIBS)
|
||||
examples_bot_SOURCES = examples/bot.c
|
||||
examples_bot_CFLAGS = $(STROPHE_FLAGS)
|
||||
examples_bot_LDADD = $(STROPHE_LIBS)
|
||||
examples_component_SOURCES = examples/component.c
|
||||
examples_component_CFLAGS = $(STROPHE_FLAGS)
|
||||
examples_component_LDADD = $(STROPHE_LIBS)
|
||||
examples_ext_auth_SOURCES = examples/ext_auth.c
|
||||
examples_ext_auth_CFLAGS = $(STROPHE_FLAGS)
|
||||
examples_ext_auth_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_CFLAGS = $(STROPHE_FLAGS)
|
||||
examples_uuid_LDADD = $(STROPHE_LIBS)
|
||||
examples_vcard_SOURCES = examples/vcard.c
|
||||
examples_vcard_CFLAGS = $(STROPHE_FLAGS)
|
||||
examples_vcard_LDADD = $(STROPHE_LIBS)
|
||||
|
||||
|
||||
## Tests
|
||||
TESTS = tests/check_parser
|
||||
check_PROGRAMS = tests/check_parser
|
||||
TESTS = \
|
||||
tests/check_parser \
|
||||
tests/test_sha1 \
|
||||
tests/test_md5 \
|
||||
tests/test_rand \
|
||||
tests/test_scram \
|
||||
tests/test_ctx \
|
||||
tests/test_base64 \
|
||||
tests/test_hash \
|
||||
tests/test_jid \
|
||||
tests/test_snprintf \
|
||||
tests/test_string \
|
||||
tests/test_resolver
|
||||
|
||||
check_PROGRAMS = $(TESTS)
|
||||
|
||||
tests_check_parser_SOURCES = tests/check_parser.c tests/test.h
|
||||
tests_check_parser_CFLAGS = @check_CFLAGS@ $(PARSER_CFLAGS) $(STROPHE_FLAGS) \
|
||||
tests_check_parser_CFLAGS = $(PARSER_CFLAGS) $(STROPHE_FLAGS) \
|
||||
-I$(top_srcdir)/src
|
||||
tests_check_parser_LDADD = @check_LIBS@ $(STROPHE_LIBS)
|
||||
tests_check_parser_LDADD = $(STROPHE_LIBS)
|
||||
tests_check_parser_LDFLAGS = -static
|
||||
|
||||
tests_test_ctx_SOURCES = tests/test_ctx.c
|
||||
tests_test_ctx_CFLAGS = $(STROPHE_FLAGS) -I$(top_srcdir)/src
|
||||
tests_test_ctx_LDADD = $(STROPHE_LIBS)
|
||||
tests_test_ctx_LDFLAGS = -static
|
||||
|
||||
tests_test_base64_SOURCES = tests/test_base64.c tests/test.c tests/test.h
|
||||
tests_test_base64_CFLAGS = $(STROPHE_FLAGS) -I$(top_srcdir)/src
|
||||
tests_test_base64_LDADD = $(STROPHE_LIBS)
|
||||
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_CFLAGS = $(STROPHE_FLAGS) -I$(top_srcdir)/src
|
||||
tests_test_jid_LDADD = $(STROPHE_LIBS)
|
||||
tests_test_jid_LDFLAGS = -static
|
||||
|
||||
tests_test_resolver_SOURCES = tests/test_resolver.c tests/test.h
|
||||
tests_test_resolver_CFLAGS = $(STROPHE_FLAGS) -I$(top_srcdir)/src
|
||||
tests_test_resolver_LDADD = $(STROPHE_LIBS)
|
||||
tests_test_resolver_LDFLAGS = -static
|
||||
|
||||
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_scram_SOURCES = tests/test_scram.c tests/test.c src/sha1.c
|
||||
tests_test_scram_CFLAGS = $(STROPHE_FLAGS) -I$(top_srcdir)/src
|
||||
|
||||
tests_test_sha1_SOURCES = tests/test_sha1.c src/sha1.c
|
||||
tests_test_sha1_CFLAGS = -I$(top_srcdir)/src
|
||||
|
||||
tests_test_md5_SOURCES = tests/test_md5.c tests/test.c src/md5.c
|
||||
tests_test_md5_CFLAGS = -I$(top_srcdir)/src
|
||||
|
||||
tests_test_snprintf_SOURCES = tests/test_snprintf.c
|
||||
tests_test_snprintf_CFLAGS = -I$(top_srcdir)/src
|
||||
|
||||
tests_test_string_SOURCES = tests/test_string.c tests/test.h
|
||||
tests_test_string_CFLAGS = $(STROPHE_FLAGS) -I$(top_srcdir)/src
|
||||
tests_test_string_LDADD = $(STROPHE_LIBS)
|
||||
tests_test_string_LDFLAGS = -static
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
# libstrophe
|
||||
libstrophe [](https://travis-ci.org/strophe/libstrophe)
|
||||
==========
|
||||
|
||||
libstrophe is a lightweight XMPP client library written in C. It has
|
||||
minimal dependencies and is configurable for various environments. It
|
||||
runs well on both Linux, Unix, and Windows based platforms.
|
||||
runs well on Linux, Unix and Windows based platforms.
|
||||
|
||||
Its goals are:
|
||||
|
||||
@@ -10,7 +11,8 @@ Its goals are:
|
||||
- well documented
|
||||
- reliable
|
||||
|
||||
## Build Instructions
|
||||
Build Instructions
|
||||
------------------
|
||||
|
||||
If you are building from a source control checkout, run:
|
||||
|
||||
@@ -23,9 +25,7 @@ From the top-level directory, run the following commands:
|
||||
./configure
|
||||
make
|
||||
|
||||
This will create a static library, also in the top-level
|
||||
directory, which can be linked into other programs. The
|
||||
public API is defined in `strophe.h` which is also in the
|
||||
The public API is defined in `strophe.h` which is in the
|
||||
top-level directory.
|
||||
|
||||
The `examples` directory contains some examples of how to
|
||||
@@ -41,26 +41,31 @@ another path use the `--prefix` option during configure, e.g.:
|
||||
|
||||
./configure --prefix=/usr
|
||||
|
||||
## Requirements
|
||||
### Android
|
||||
|
||||
Run script `build-android.sh` and follow the instructions. You will
|
||||
need expat sources and android-ndk.
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
libstrophe requires:
|
||||
|
||||
- expat or libxml2 - expat is the default; use --with-libxml2 to
|
||||
switch
|
||||
- libresolv on UNIX systems - make sure you include -lresolv
|
||||
if you are compiling by hand.
|
||||
- libtool
|
||||
- openssl on UNIX systems
|
||||
|
||||
In addition, if you wish to run the unit tests, you will need the
|
||||
check package.
|
||||
To build libstrophe using autotools you will need autoconf, automake,
|
||||
libtool and pkg-config.
|
||||
|
||||
### OS X (with Homebrew package manager)
|
||||
Installation
|
||||
------------
|
||||
|
||||
You can install libstrophe with:
|
||||
libstrophe package has been added to popular Linux distributions,
|
||||
BSD systems and OSX package managers.
|
||||
|
||||
brew install libstrophe
|
||||
|
||||
## Documentation
|
||||
Documentation
|
||||
-------------
|
||||
|
||||
API documentation is inline with the code and conforms to Doxygen
|
||||
standards. You can generate an HTML version of the API documentation
|
||||
|
||||
39
build-android.sh
Executable file
39
build-android.sh
Executable file
@@ -0,0 +1,39 @@
|
||||
#!/bin/sh
|
||||
|
||||
DIR=`dirname $0`
|
||||
EXPAT_PATH="$DIR/expat"
|
||||
EXPAT_FILE='lib/expat.h'
|
||||
|
||||
echo
|
||||
echo Attention: libstrophe will be built without TLS support. To enable TLS
|
||||
echo you need to replace \'src/tls_dummy.c\' with \'src/tls_opnessl.c\' in
|
||||
echo \'jni/Android.mk\', add path to the openssl headers and link your program
|
||||
echo with libssl and libcrypto.
|
||||
echo
|
||||
|
||||
if [ ! -d $EXPAT_PATH ]; then
|
||||
mkdir $EXPAT_PATH
|
||||
fi
|
||||
|
||||
# TODO Accept expat tarball as argument and extract it to the right place.
|
||||
# Or download sources from sf.net.
|
||||
|
||||
if [ ! -d $EXPAT_PATH/lib -o ! -f "$EXPAT_PATH/$EXPAT_FILE" ]; then
|
||||
cat <<EOT
|
||||
Error: expat sources not found.
|
||||
|
||||
Extract expat sources to $EXPAT_PATH. Make sure $EXPAT_PATH/$EXPAT_FILE and
|
||||
other source files exist.
|
||||
EOT
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ndk-build -C "$DIR" clean || exit 1
|
||||
ndk-build -C "$DIR" || exit 1
|
||||
|
||||
echo
|
||||
echo "basic example:"
|
||||
ls -l "$DIR"/libs/*/basic
|
||||
echo
|
||||
echo "libstrophe.a:"
|
||||
ls -l "$DIR"/obj/local/*/libstrophe.a
|
||||
173
configure.ac
173
configure.ac
@@ -1,4 +1,4 @@
|
||||
AC_INIT([libstrophe], [0.8.8], [jack@metajack.im])
|
||||
AC_INIT([libstrophe], [0.9.1], [jack@metajack.im])
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
AM_INIT_AUTOMAKE([foreign])
|
||||
LT_INIT([dlopen])
|
||||
@@ -9,100 +9,123 @@ PKG_PROG_PKG_CONFIG
|
||||
|
||||
AC_CANONICAL_HOST
|
||||
AS_CASE([$host_os],
|
||||
[freebsd*], [PLATFORM="freebsd"],
|
||||
[PLATFORM="nix"])
|
||||
|
||||
PKG_CHECK_MODULES([openssl], [openssl], [PC_REQUIRES+=(openssl)],
|
||||
[AC_CHECK_HEADER([openssl/ssl.h],
|
||||
[
|
||||
openssl_LIBS="-lssl -lcrypto"
|
||||
PC_LIBS+=($openssl_LIBS)
|
||||
],
|
||||
[AC_MSG_ERROR([openssl not found; openssl required])]
|
||||
)])
|
||||
|
||||
PKG_CHECK_MODULES([check], [check >= 0.9.4], [], [AC_MSG_WARN([libcheck not found; unit tests will not be compilable])])
|
||||
[freebsd*], [PLATFORM="bsd"],
|
||||
[openbsd*], [PLATFORM="bsd"],
|
||||
[netbsd*], [PLATFORM="bsd"],
|
||||
[*nto*|*qnx*], [PLATFORM="qnx"],
|
||||
[*solaris*], [PLATFORM="solaris"],
|
||||
[*android*], [PLATFORM="android"],
|
||||
[PLATFORM="nix"])
|
||||
|
||||
AC_ARG_WITH([libxml2],
|
||||
[AS_HELP_STRING([--with-libxml2], [use libxml2 for XML parsing])],
|
||||
[with_libxml2=check],
|
||||
[with_libxml2=no])
|
||||
[AS_HELP_STRING([--with-libxml2], [use libxml2 for XML parsing, expat is the default])])
|
||||
AC_ARG_ENABLE([tls],
|
||||
[AS_HELP_STRING([--disable-tls], [disable TLS support])])
|
||||
|
||||
if test "x$with_libxml2" != xno; then
|
||||
PKG_CHECK_MODULES([libxml2], [libxml-2.0 >= 2.7],
|
||||
[
|
||||
with_libxml2=yes
|
||||
PC_REQUIRES+=(libxml-2.0)
|
||||
],
|
||||
[
|
||||
old_CFLAGS=$CFLAGS
|
||||
CFLAGS="-I${includedir}/libxml2"
|
||||
AC_CHECK_HEADER([libxml/parser.h],
|
||||
[
|
||||
with_libxml2=yes
|
||||
libxml2_CFLAGS="-I${includedir}/libxml2"
|
||||
libxml2_LIBS="-lxml2"
|
||||
PC_LIBS+=($libxml2_LIBS)
|
||||
PC_CFLAGS+=($libxml2_CFLAGS)
|
||||
],
|
||||
[AC_MSG_ERROR([libxml2 not found.])])
|
||||
CFLAGS=$old_CFLAGS
|
||||
])
|
||||
else
|
||||
PKG_CHECK_MODULES([expat], [expat >= 2.0.0],
|
||||
[PC_REQUIRES+=(expat)],
|
||||
[AC_CHECK_HEADER([expat.h],
|
||||
[
|
||||
expat_LIBS="-lexpat"
|
||||
PC_LIBS+=($expat_LIBS)
|
||||
],
|
||||
[AC_MSG_ERROR([expat not found; expat required.])]
|
||||
)
|
||||
])
|
||||
if test "x$enable_tls" != xno; then
|
||||
PKG_CHECK_MODULES([openssl], [openssl],
|
||||
[PC_REQUIRES="openssl ${PC_REQUIRES}"],
|
||||
[AC_CHECK_HEADER([openssl/ssl.h],
|
||||
[
|
||||
openssl_LIBS="-lssl -lcrypto"
|
||||
PC_LIBS="${openssl_LIBS} ${PC_LIBS}"
|
||||
],
|
||||
[AC_MSG_ERROR([openssl not found; openssl required])]
|
||||
)])
|
||||
fi
|
||||
|
||||
if test "x$with_libxml2" = xyes; then
|
||||
with_parser=libxml2
|
||||
PARSER_NAME=libxml2
|
||||
PARSER_CFLAGS=$libxml2_CFLAGS
|
||||
PARSER_LIBS=$libxml2_LIBS
|
||||
with_parser=""
|
||||
if test "x$with_libxml2" != xyes; then
|
||||
PKG_CHECK_MODULES([expat], [expat >= 2.0.0],
|
||||
[
|
||||
with_parser="expat"
|
||||
PC_REQUIRES="expat ${PC_REQUIRES}"
|
||||
],
|
||||
[AC_CHECK_HEADER([expat.h],
|
||||
[
|
||||
with_parser="expat"
|
||||
expat_LIBS="-lexpat"
|
||||
PC_LIBS="${expat_LIBS} ${PC_LIBS}"
|
||||
])
|
||||
])
|
||||
fi
|
||||
if test "x$with_libxml2" != xno -a "x$with_parser" = x; then
|
||||
PKG_CHECK_MODULES([libxml2], [libxml-2.0 >= 2.7],
|
||||
[
|
||||
with_parser="libxml2"
|
||||
PC_REQUIRES="libxml-2.0 ${PC_REQUIRES}"
|
||||
],
|
||||
[
|
||||
old_CFLAGS=$CFLAGS
|
||||
CFLAGS="-I${includedir}/libxml2"
|
||||
AC_CHECK_HEADER([libxml/parser.h],
|
||||
[
|
||||
with_parser="libxml2"
|
||||
libxml2_CFLAGS="-I${includedir}/libxml2"
|
||||
libxml2_LIBS="-lxml2"
|
||||
PC_LIBS="${libxml2_LIBS} ${PC_LIBS}"
|
||||
PC_CFLAGS="${libxml2_CFLAGS} ${PC_CFLAGS}"
|
||||
])
|
||||
CFLAGS=$old_CFLAGS
|
||||
])
|
||||
fi
|
||||
|
||||
if test "x$with_parser" = xlibxml2; then
|
||||
PARSER_CFLAGS=$libxml2_CFLAGS
|
||||
PARSER_LIBS=$libxml2_LIBS
|
||||
elif test "x$with_parser" = xexpat; then
|
||||
PARSER_CFLAGS=$expat_CFLAGS
|
||||
PARSER_LIBS=$expat_LIBS
|
||||
else
|
||||
with_parser=expat
|
||||
PARSER_NAME=expat
|
||||
PARSER_CFLAGS=$expat_CFLAGS
|
||||
PARSER_LIBS=$expat_LIBS
|
||||
AC_MSG_ERROR([no XML parser was found, libstrophe requires expat or libxml2])
|
||||
fi
|
||||
|
||||
AC_MSG_NOTICE([libstrophe will use the $with_parser XML parser])
|
||||
|
||||
AC_SEARCH_LIBS([socket], [socket])
|
||||
|
||||
if test "x$PLATFORM" != xfreebsd; then
|
||||
AC_CHECK_LIB([resolv], [res_query], [],
|
||||
[AC_CHECK_LIB([resolv], [__res_query], [],
|
||||
[AC_MSG_ERROR([libresolv not found; libresolv required.])])])
|
||||
PC_LIBS+=(-lresolv)
|
||||
else
|
||||
AC_MSG_NOTICE([skipping libresolv checks for freebsd])
|
||||
fi
|
||||
AS_CASE([$PLATFORM],
|
||||
[bsd], [RESOLV_LIBS=""],
|
||||
[qnx], [RESOLV_LIBS="-lsocket"],
|
||||
[solaris], [RESOLV_LIBS="-lresolv -lsocket -lnsl"],
|
||||
[android], [RESOLV_LIBS=""],
|
||||
[RESOLV_LIBS="-lresolv"])
|
||||
|
||||
AC_CHECK_HEADERS([arpa/nameser_compat.h])
|
||||
LIBS_TMP="${LIBS}"
|
||||
LIBS="${RESOLV_LIBS}"
|
||||
AC_LINK_IFELSE([AC_LANG_SOURCE([
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/nameser.h>
|
||||
#include <resolv.h>
|
||||
#include <netdb.h>
|
||||
|
||||
int main() {
|
||||
(void)res_query(NULL, 0, 0, NULL, 0);
|
||||
return 0;
|
||||
}
|
||||
])],
|
||||
[],
|
||||
[AC_MSG_ERROR([res_query() not found with LIBS="${LIBS}"])])
|
||||
LIBS="${LIBS_TMP}"
|
||||
PC_LIBS="${RESOLV_LIBS} ${PC_LIBS}"
|
||||
|
||||
m4_ifdef([PKG_INSTALLDIR], [PKG_INSTALLDIR],
|
||||
[AC_ARG_WITH([pkgconfigdir],
|
||||
[AS_HELP_STRING([--with-pkgconfigdir],
|
||||
[install directory for libstrophe.pc pkg-config file])],
|
||||
[],[with_pkgconfigdir='$(libdir)/pkgconfig'])
|
||||
AC_SUBST([pkgconfigdir], [${with_pkgconfigdir}])])
|
||||
[AC_ARG_WITH([pkgconfigdir],
|
||||
[AS_HELP_STRING([--with-pkgconfigdir],
|
||||
[install directory for libstrophe.pc pkg-config file])],
|
||||
[], [with_pkgconfigdir='$(libdir)/pkgconfig'])
|
||||
AC_SUBST([pkgconfigdir], [${with_pkgconfigdir}])])
|
||||
|
||||
AM_CONDITIONAL([PARSER_EXPAT], [test x$with_parser != xlibxml2])
|
||||
AM_CONDITIONAL([DISABLE_TLS], [test x$enable_tls = xno])
|
||||
|
||||
AC_SUBST([PC_REQUIRES], [${PC_REQUIRES[[@]]}])
|
||||
AC_SUBST([PC_CFLAGS], [${PC_CFLAGS[[@]]}])
|
||||
AC_SUBST([PC_LIBS], [${PC_LIBS[[@]]}])
|
||||
AC_SUBST([PC_REQUIRES], [${PC_REQUIRES}])
|
||||
AC_SUBST([PC_CFLAGS], [${PC_CFLAGS}])
|
||||
AC_SUBST([PC_LIBS], [${PC_LIBS}])
|
||||
|
||||
AC_SUBST(PARSER_NAME)
|
||||
AC_SUBST(PARSER_CFLAGS)
|
||||
AC_SUBST(PARSER_LIBS)
|
||||
AC_SUBST(RESOLV_LIBS)
|
||||
AC_CONFIG_FILES([Makefile libstrophe.pc])
|
||||
AC_OUTPUT
|
||||
|
||||
7
examples/README.md
Normal file
7
examples/README.md
Normal file
@@ -0,0 +1,7 @@
|
||||
Build Instructions
|
||||
==================
|
||||
|
||||
Compile example files with the following gcc flags:
|
||||
```
|
||||
gcc -o bot bot.c `pkg-config --cflags --libs libstrophe`
|
||||
```
|
||||
@@ -24,7 +24,7 @@ int handle_reply(xmpp_conn_t * const conn,
|
||||
void * const userdata)
|
||||
{
|
||||
xmpp_stanza_t *query, *item;
|
||||
char *type;
|
||||
const char *type;
|
||||
|
||||
type = xmpp_stanza_get_type(stanza);
|
||||
if (strcmp(type, "error") == 0)
|
||||
@@ -55,11 +55,8 @@ void conn_handler(xmpp_conn_t * const conn, const xmpp_conn_event_t status,
|
||||
fprintf(stderr, "DEBUG: connected\n");
|
||||
|
||||
/* create iq stanza for request */
|
||||
iq = xmpp_stanza_new(ctx);
|
||||
xmpp_stanza_set_name(iq, "iq");
|
||||
xmpp_stanza_set_type(iq, "get");
|
||||
xmpp_stanza_set_id(iq, "active1");
|
||||
xmpp_stanza_set_attribute(iq, "to", "xxxxxxxxx.com");
|
||||
iq = xmpp_iq_new(ctx, "get", "active1");
|
||||
xmpp_stanza_set_to(iq, "xxxxxxxxx.com");
|
||||
|
||||
query = xmpp_stanza_new(ctx);
|
||||
xmpp_stanza_set_name(query, "query");
|
||||
@@ -104,6 +101,13 @@ int main(int argc, char **argv)
|
||||
/* create a connection */
|
||||
conn = xmpp_conn_new(ctx);
|
||||
|
||||
/*
|
||||
* also you can disable TLS support or force legacy SSL
|
||||
* connection without STARTTLS
|
||||
*
|
||||
* see xmpp_conn_set_flags() or examples/basic.c
|
||||
*/
|
||||
|
||||
/* setup authentication information */
|
||||
xmpp_conn_set_jid(conn, argv[1]);
|
||||
xmpp_conn_set_pass(conn, argv[2]);
|
||||
|
||||
@@ -10,9 +10,13 @@
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <strophe.h>
|
||||
|
||||
/* hardcoded TCP keepalive timeout and interval */
|
||||
#define KA_TIMEOUT 60
|
||||
#define KA_INTERVAL 1
|
||||
|
||||
/* define a handler for connection events */
|
||||
void conn_handler(xmpp_conn_t * const conn, const xmpp_conn_event_t status,
|
||||
@@ -20,9 +24,13 @@ void conn_handler(xmpp_conn_t * const conn, const xmpp_conn_event_t status,
|
||||
void * const userdata)
|
||||
{
|
||||
xmpp_ctx_t *ctx = (xmpp_ctx_t *)userdata;
|
||||
int secured;
|
||||
|
||||
if (status == XMPP_CONN_CONNECT) {
|
||||
fprintf(stderr, "DEBUG: connected\n");
|
||||
secured = xmpp_conn_is_secured(conn);
|
||||
fprintf(stderr, "DEBUG: connection is %s.\n",
|
||||
secured ? "secured" : "NOT secured");
|
||||
xmpp_disconnect(conn);
|
||||
}
|
||||
else {
|
||||
@@ -36,20 +44,45 @@ int main(int argc, char **argv)
|
||||
xmpp_ctx_t *ctx;
|
||||
xmpp_conn_t *conn;
|
||||
xmpp_log_t *log;
|
||||
char *jid, *pass, *host;
|
||||
char *jid, *pass, *host = NULL;
|
||||
long flags = 0;
|
||||
int tcp_keepalive = 0;
|
||||
int i;
|
||||
|
||||
/* take a jid and password on the command line */
|
||||
if (argc < 3 || argc > 4) {
|
||||
fprintf(stderr, "Usage: basic <jid> <pass> [<host>]\n\n");
|
||||
for (i = 1; i < argc; ++i) {
|
||||
if (strcmp(argv[i], "--disable-tls") == 0)
|
||||
flags |= XMPP_CONN_FLAG_DISABLE_TLS;
|
||||
else if (strcmp(argv[i], "--mandatory-tls") == 0)
|
||||
flags |= XMPP_CONN_FLAG_MANDATORY_TLS;
|
||||
else if (strcmp(argv[i], "--legacy-ssl") == 0)
|
||||
flags |= XMPP_CONN_FLAG_LEGACY_SSL;
|
||||
else if (strcmp(argv[i], "--tcp-keepalive") == 0)
|
||||
tcp_keepalive = 1;
|
||||
else
|
||||
break;
|
||||
}
|
||||
if ((argc - i) < 2 || (argc - i) > 3) {
|
||||
fprintf(stderr, "Usage: basic [options] <jid> <pass> [<host>]\n\n"
|
||||
"Options:\n"
|
||||
" --disable-tls Disable TLS.\n"
|
||||
" --mandatory-tls Deny plaintext connection.\n"
|
||||
" --legacy-ssl Use old style SSL.\n"
|
||||
" --tcp-keepalive Configure TCP keepalive.\n\n"
|
||||
"Note: --disable-tls conflicts with --mandatory-tls or "
|
||||
"--legacy-ssl\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
jid = argv[1];
|
||||
pass = argv[2];
|
||||
host = NULL;
|
||||
jid = argv[i];
|
||||
pass = argv[i + 1];
|
||||
if (i + 2 < argc)
|
||||
host = argv[i + 2];
|
||||
|
||||
if (argc == 4)
|
||||
host = argv[3];
|
||||
/*
|
||||
* Note, this example doesn't handle errors. Applications should check
|
||||
* return values of non-void functions.
|
||||
*/
|
||||
|
||||
/* init library */
|
||||
xmpp_initialize();
|
||||
@@ -61,6 +94,11 @@ int main(int argc, char **argv)
|
||||
/* create a connection */
|
||||
conn = xmpp_conn_new(ctx);
|
||||
|
||||
/* configure connection properties (optional) */
|
||||
xmpp_conn_set_flags(conn, flags);
|
||||
/* configure TCP keepalive (optional) */
|
||||
if (tcp_keepalive) xmpp_conn_set_keepalive(conn, KA_TIMEOUT, KA_INTERVAL);
|
||||
|
||||
/* setup authentication information */
|
||||
xmpp_conn_set_jid(conn, jid);
|
||||
xmpp_conn_set_pass(conn, pass);
|
||||
|
||||
181
examples/bot.c
181
examples/bot.c
@@ -25,106 +25,116 @@
|
||||
|
||||
int version_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata)
|
||||
{
|
||||
xmpp_stanza_t *reply, *query, *name, *version, *text;
|
||||
char *ns;
|
||||
xmpp_ctx_t *ctx = (xmpp_ctx_t*)userdata;
|
||||
printf("Received version request from %s\n", xmpp_stanza_get_attribute(stanza, "from"));
|
||||
|
||||
reply = xmpp_stanza_new(ctx);
|
||||
xmpp_stanza_set_name(reply, "iq");
|
||||
xmpp_stanza_set_type(reply, "result");
|
||||
xmpp_stanza_set_id(reply, xmpp_stanza_get_id(stanza));
|
||||
xmpp_stanza_set_attribute(reply, "to", xmpp_stanza_get_attribute(stanza, "from"));
|
||||
|
||||
query = xmpp_stanza_new(ctx);
|
||||
xmpp_stanza_set_name(query, "query");
|
||||
xmpp_stanza_t *reply, *query, *name, *version, *text;
|
||||
const char *ns;
|
||||
xmpp_ctx_t *ctx = (xmpp_ctx_t*)userdata;
|
||||
|
||||
printf("Received version request from %s\n", xmpp_stanza_get_from(stanza));
|
||||
|
||||
reply = xmpp_stanza_reply(stanza);
|
||||
xmpp_stanza_set_type(reply, "result");
|
||||
|
||||
query = xmpp_stanza_new(ctx);
|
||||
xmpp_stanza_set_name(query, "query");
|
||||
ns = xmpp_stanza_get_ns(xmpp_stanza_get_children(stanza));
|
||||
if (ns) {
|
||||
xmpp_stanza_set_ns(query, ns);
|
||||
}
|
||||
|
||||
name = xmpp_stanza_new(ctx);
|
||||
xmpp_stanza_set_name(name, "name");
|
||||
xmpp_stanza_add_child(query, name);
|
||||
|
||||
text = xmpp_stanza_new(ctx);
|
||||
xmpp_stanza_set_text(text, "libstrophe example bot");
|
||||
xmpp_stanza_add_child(name, text);
|
||||
|
||||
version = xmpp_stanza_new(ctx);
|
||||
xmpp_stanza_set_name(version, "version");
|
||||
xmpp_stanza_add_child(query, version);
|
||||
|
||||
text = xmpp_stanza_new(ctx);
|
||||
xmpp_stanza_set_text(text, "1.0");
|
||||
xmpp_stanza_add_child(version, text);
|
||||
|
||||
xmpp_stanza_add_child(reply, query);
|
||||
name = xmpp_stanza_new(ctx);
|
||||
xmpp_stanza_set_name(name, "name");
|
||||
xmpp_stanza_add_child(query, name);
|
||||
xmpp_stanza_release(name);
|
||||
|
||||
xmpp_send(conn, reply);
|
||||
xmpp_stanza_release(reply);
|
||||
return 1;
|
||||
text = xmpp_stanza_new(ctx);
|
||||
xmpp_stanza_set_text(text, "libstrophe example bot");
|
||||
xmpp_stanza_add_child(name, text);
|
||||
xmpp_stanza_release(text);
|
||||
|
||||
version = xmpp_stanza_new(ctx);
|
||||
xmpp_stanza_set_name(version, "version");
|
||||
xmpp_stanza_add_child(query, version);
|
||||
xmpp_stanza_release(version);
|
||||
|
||||
text = xmpp_stanza_new(ctx);
|
||||
xmpp_stanza_set_text(text, "1.0");
|
||||
xmpp_stanza_add_child(version, text);
|
||||
xmpp_stanza_release(text);
|
||||
|
||||
xmpp_stanza_add_child(reply, query);
|
||||
xmpp_stanza_release(query);
|
||||
|
||||
xmpp_send(conn, reply);
|
||||
xmpp_stanza_release(reply);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int message_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata)
|
||||
{
|
||||
xmpp_stanza_t *reply, *body, *text;
|
||||
char *intext, *replytext;
|
||||
xmpp_ctx_t *ctx = (xmpp_ctx_t*)userdata;
|
||||
|
||||
if(!xmpp_stanza_get_child_by_name(stanza, "body")) return 1;
|
||||
if(xmpp_stanza_get_attribute(stanza, "type") !=NULL && !strcmp(xmpp_stanza_get_attribute(stanza, "type"), "error")) return 1;
|
||||
|
||||
intext = xmpp_stanza_get_text(xmpp_stanza_get_child_by_name(stanza, "body"));
|
||||
|
||||
printf("Incoming message from %s: %s\n", xmpp_stanza_get_attribute(stanza, "from"), intext);
|
||||
|
||||
reply = xmpp_stanza_new(ctx);
|
||||
xmpp_stanza_set_name(reply, "message");
|
||||
xmpp_stanza_set_type(reply, xmpp_stanza_get_type(stanza)?xmpp_stanza_get_type(stanza):"chat");
|
||||
xmpp_stanza_set_attribute(reply, "to", xmpp_stanza_get_attribute(stanza, "from"));
|
||||
|
||||
body = xmpp_stanza_new(ctx);
|
||||
xmpp_stanza_set_name(body, "body");
|
||||
|
||||
replytext = malloc(strlen(" to you too!") + strlen(intext) + 1);
|
||||
strcpy(replytext, intext);
|
||||
strcat(replytext, " to you too!");
|
||||
|
||||
text = xmpp_stanza_new(ctx);
|
||||
xmpp_stanza_set_text(text, replytext);
|
||||
xmpp_stanza_add_child(body, text);
|
||||
xmpp_stanza_add_child(reply, body);
|
||||
|
||||
xmpp_send(conn, reply);
|
||||
xmpp_stanza_release(reply);
|
||||
free(replytext);
|
||||
return 1;
|
||||
xmpp_ctx_t *ctx = (xmpp_ctx_t*)userdata;
|
||||
xmpp_stanza_t *body, *reply;
|
||||
const char *type;
|
||||
char *intext, *replytext;
|
||||
int quit = 0;
|
||||
|
||||
body = xmpp_stanza_get_child_by_name(stanza, "body");
|
||||
if (body == NULL)
|
||||
return 1;
|
||||
type = xmpp_stanza_get_type(stanza);
|
||||
if (type != NULL && strcmp(type, "error") == 0)
|
||||
return 1;
|
||||
|
||||
intext = xmpp_stanza_get_text(body);
|
||||
|
||||
printf("Incoming message from %s: %s\n", xmpp_stanza_get_from(stanza), intext);
|
||||
|
||||
reply = xmpp_stanza_reply(stanza);
|
||||
if (xmpp_stanza_get_type(reply) == NULL)
|
||||
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);
|
||||
strcpy(replytext, intext);
|
||||
strcat(replytext, " to you too!");
|
||||
}
|
||||
xmpp_free(ctx, intext);
|
||||
xmpp_message_set_body(reply, replytext);
|
||||
|
||||
xmpp_send(conn, reply);
|
||||
xmpp_stanza_release(reply);
|
||||
free(replytext);
|
||||
|
||||
if (quit)
|
||||
xmpp_disconnect(conn);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* define a handler for connection events */
|
||||
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)
|
||||
const int error, xmpp_stream_error_t * const stream_error,
|
||||
void * const userdata)
|
||||
{
|
||||
xmpp_ctx_t *ctx = (xmpp_ctx_t *)userdata;
|
||||
|
||||
if (status == XMPP_CONN_CONNECT) {
|
||||
xmpp_stanza_t* pres;
|
||||
fprintf(stderr, "DEBUG: connected\n");
|
||||
xmpp_handler_add(conn,version_handler, "jabber:iq:version", "iq", NULL, ctx);
|
||||
xmpp_handler_add(conn,message_handler, NULL, "message", NULL, ctx);
|
||||
|
||||
/* Send initial <presence/> so that we appear online to contacts */
|
||||
pres = xmpp_stanza_new(ctx);
|
||||
xmpp_stanza_set_name(pres, "presence");
|
||||
xmpp_send(conn, pres);
|
||||
xmpp_stanza_release(pres);
|
||||
xmpp_stanza_t* pres;
|
||||
fprintf(stderr, "DEBUG: connected\n");
|
||||
xmpp_handler_add(conn, version_handler, "jabber:iq:version", "iq", NULL, ctx);
|
||||
xmpp_handler_add(conn, message_handler, NULL, "message", NULL, ctx);
|
||||
|
||||
/* Send initial <presence/> so that we appear online to contacts */
|
||||
pres = xmpp_presence_new(ctx);
|
||||
xmpp_send(conn, pres);
|
||||
xmpp_stanza_release(pres);
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "DEBUG: disconnected\n");
|
||||
xmpp_stop(ctx);
|
||||
fprintf(stderr, "DEBUG: disconnected\n");
|
||||
xmpp_stop(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,10 +147,10 @@ int main(int argc, char **argv)
|
||||
|
||||
/* take a jid and password on the command line */
|
||||
if (argc != 3) {
|
||||
fprintf(stderr, "Usage: bot <jid> <pass>\n\n");
|
||||
return 1;
|
||||
fprintf(stderr, "Usage: bot <jid> <pass>\n\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
jid = argv[1];
|
||||
pass = argv[2];
|
||||
|
||||
@@ -154,6 +164,13 @@ int main(int argc, char **argv)
|
||||
/* create a connection */
|
||||
conn = xmpp_conn_new(ctx);
|
||||
|
||||
/*
|
||||
* also you can disable TLS support or force legacy SSL
|
||||
* connection without STARTTLS
|
||||
*
|
||||
* see xmpp_conn_set_flags() or examples/basic.c
|
||||
*/
|
||||
|
||||
/* setup authentication information */
|
||||
xmpp_conn_set_jid(conn, jid);
|
||||
xmpp_conn_set_pass(conn, pass);
|
||||
|
||||
290
examples/ext_auth.c
Normal file
290
examples/ext_auth.c
Normal file
@@ -0,0 +1,290 @@
|
||||
/* ext_auth.c
|
||||
* strophe XMPP client library -- PLAIN mechanism example with a raw connection
|
||||
*
|
||||
* 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <strophe.h>
|
||||
|
||||
typedef struct {
|
||||
xmpp_ctx_t *ctx;
|
||||
const char *jid;
|
||||
const char *pass;
|
||||
char *domain;
|
||||
int authenticated;
|
||||
} xmpp_auth_t;
|
||||
|
||||
#define FEATURES_TIMEOUT 5000 /* 5 seconds */
|
||||
|
||||
static int _handle_error(xmpp_conn_t * const conn,
|
||||
xmpp_stanza_t * const stanza,
|
||||
void * const userdata)
|
||||
{
|
||||
fprintf(stderr, "DEBUG: received stream error\n");
|
||||
xmpp_disconnect(conn);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _handle_proceedtls_default(xmpp_conn_t * const conn,
|
||||
xmpp_stanza_t * const stanza,
|
||||
void * const userdata)
|
||||
{
|
||||
xmpp_auth_t *auth = (xmpp_auth_t *)userdata;
|
||||
const char *name = xmpp_stanza_get_name(stanza);
|
||||
|
||||
(void)auth;
|
||||
if (strcmp(name, "proceed") == 0) {
|
||||
if (xmpp_conn_tls_start(conn) == 0) {
|
||||
xmpp_handler_delete(conn, _handle_error);
|
||||
xmpp_conn_open_stream_default(conn);
|
||||
} else {
|
||||
/* failed tls spoils the connection, so disconnect */
|
||||
xmpp_disconnect(conn);
|
||||
}
|
||||
} else
|
||||
xmpp_disconnect(conn);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _plain_mechanim_exists(xmpp_ctx_t *ctx, xmpp_stanza_t *features)
|
||||
{
|
||||
xmpp_stanza_t *mechanisms;
|
||||
xmpp_stanza_t *child;
|
||||
char *text;
|
||||
int found = 0;
|
||||
|
||||
mechanisms = xmpp_stanza_get_child_by_name(features, "mechanisms");
|
||||
child = mechanisms ? xmpp_stanza_get_children(mechanisms) : NULL;
|
||||
while (!found && mechanisms && child) {
|
||||
/* TODO xmpp_stanza_get_name(child) is "mechanism" */
|
||||
text = xmpp_stanza_get_text(child);
|
||||
found = text && strcmp(text, "PLAIN") == 0;
|
||||
xmpp_free(ctx, text);
|
||||
child = xmpp_stanza_get_next(child);
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
static char *_plain_mechanism_authdata(xmpp_auth_t *auth)
|
||||
{
|
||||
char *node, *b64;
|
||||
unsigned char *msg;
|
||||
size_t node_len, pass_len;
|
||||
|
||||
node = xmpp_jid_node(auth->ctx, auth->jid);
|
||||
node_len = strlen(node);
|
||||
pass_len = strlen(auth->pass);
|
||||
msg = malloc(node_len + pass_len + 2);
|
||||
msg[0] = '\0';
|
||||
memcpy(msg + 1, node, node_len);
|
||||
msg[node_len + 1] = '\0';
|
||||
memcpy(msg + node_len + 2, auth->pass, pass_len);
|
||||
b64 = xmpp_base64_encode(auth->ctx, msg, node_len + pass_len + 2);
|
||||
|
||||
free(msg);
|
||||
xmpp_free(auth->ctx, node);
|
||||
|
||||
return b64;
|
||||
}
|
||||
|
||||
static int _plain_mechanism_handle_result(xmpp_conn_t * const conn,
|
||||
xmpp_stanza_t * const stanza,
|
||||
void * const userdata)
|
||||
{
|
||||
xmpp_auth_t *auth = (xmpp_auth_t *)userdata;
|
||||
const char *name;
|
||||
|
||||
name = xmpp_stanza_get_name(stanza);
|
||||
|
||||
if (strcmp(name, "success") == 0) {
|
||||
/* SASL PLAIN auth successful, we need to restart the stream */
|
||||
fprintf(stderr, "DEBUG: SASL PLAIN auth successful\n");
|
||||
auth->authenticated = 1;
|
||||
xmpp_handler_delete(conn, _handle_error);
|
||||
xmpp_conn_open_stream_default(conn);
|
||||
} else {
|
||||
fprintf(stderr, "DEBUG: SASL authentication failed: %s\n", name);
|
||||
xmpp_disconnect(conn);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _handle_missing_features(xmpp_conn_t * const conn,
|
||||
void * const userdata)
|
||||
{
|
||||
fprintf(stderr, "DEBUG: timeout\n");
|
||||
xmpp_disconnect(conn);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _handle_features(xmpp_conn_t * const conn,
|
||||
xmpp_stanza_t * const stanza,
|
||||
void * const userdata)
|
||||
{
|
||||
xmpp_auth_t *auth = (xmpp_auth_t *)userdata;
|
||||
xmpp_ctx_t *ctx = auth->ctx;
|
||||
xmpp_stanza_t *plain, *child;
|
||||
char *str;
|
||||
|
||||
xmpp_timed_handler_delete(conn, _handle_missing_features);
|
||||
|
||||
if (auth->authenticated) {
|
||||
/* after successful SASL authentication */
|
||||
/* TODO bind, session and we'are done */
|
||||
xmpp_disconnect(conn); /* XXX */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 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)) {
|
||||
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, userdata);
|
||||
xmpp_send(conn, child);
|
||||
xmpp_stanza_release(child);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* check if PLAIN mechanism is supported */
|
||||
if (!_plain_mechanim_exists(ctx, stanza)) {
|
||||
fprintf(stderr, "DEBUG: PLAIN mechanism is NOT supported\n");
|
||||
xmpp_disconnect(conn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* perform authentication */
|
||||
plain = xmpp_stanza_new(ctx);
|
||||
xmpp_stanza_set_name(plain, "auth");
|
||||
xmpp_stanza_set_ns(plain, XMPP_NS_SASL);
|
||||
xmpp_stanza_set_attribute(plain, "mechanism", "PLAIN");
|
||||
str = _plain_mechanism_authdata(auth);
|
||||
child = xmpp_stanza_new(ctx);
|
||||
xmpp_stanza_set_text(child, str);
|
||||
xmpp_free(ctx, str);
|
||||
xmpp_stanza_add_child(plain, child);
|
||||
xmpp_stanza_release(child);
|
||||
|
||||
xmpp_handler_add(conn, _plain_mechanism_handle_result,
|
||||
XMPP_NS_SASL, NULL, NULL, userdata);
|
||||
xmpp_send(conn, plain);
|
||||
xmpp_stanza_release(plain);
|
||||
|
||||
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_auth_t *auth = (xmpp_auth_t *)userdata;
|
||||
xmpp_ctx_t *ctx = auth->ctx;
|
||||
int secured;
|
||||
|
||||
if (status == XMPP_CONN_RAW_CONNECT) {
|
||||
fprintf(stderr, "DEBUG: raw connection established\n");
|
||||
xmpp_conn_open_stream_default(conn);
|
||||
} else if (status == XMPP_CONN_CONNECT) {
|
||||
fprintf(stderr, "DEBUG: stream opened\n");
|
||||
secured = xmpp_conn_is_secured(conn);
|
||||
fprintf(stderr, "DEBUG: connection is %s.\n",
|
||||
secured ? "secured" : "NOT secured");
|
||||
|
||||
/* setup handler for stream:error */
|
||||
xmpp_handler_add(conn, _handle_error, XMPP_NS_STREAMS,
|
||||
"error", NULL, NULL);
|
||||
|
||||
/* setup handlers for incoming <stream:features> */
|
||||
xmpp_handler_add(conn, _handle_features, XMPP_NS_STREAMS,
|
||||
"features", NULL, auth);
|
||||
xmpp_timed_handler_add(conn, _handle_missing_features,
|
||||
FEATURES_TIMEOUT, NULL);
|
||||
} else {
|
||||
fprintf(stderr, "DEBUG: disconnected\n");
|
||||
xmpp_stop(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
static xmpp_auth_t *xmpp_auth_new(void)
|
||||
{
|
||||
xmpp_auth_t *auth;
|
||||
|
||||
auth = malloc(sizeof(*auth));
|
||||
if (auth != NULL) {
|
||||
memset(auth, 0, sizeof(*auth));
|
||||
}
|
||||
return auth;
|
||||
}
|
||||
|
||||
static void xmpp_auth_release(xmpp_auth_t *auth)
|
||||
{
|
||||
free(auth);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
xmpp_ctx_t *ctx;
|
||||
xmpp_conn_t *conn;
|
||||
xmpp_log_t *log;
|
||||
xmpp_auth_t *auth;
|
||||
const char *jid;
|
||||
const char *pass;
|
||||
const char *host = NULL;
|
||||
|
||||
if (argc < 3 || argc > 4) {
|
||||
fprintf(stderr, "Usage: %s <jid> <pass> [<host>]\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
jid = argv[1];
|
||||
pass = argv[2];
|
||||
if (argc > 3)
|
||||
host = argv[3];
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
xmpp_conn_set_jid(conn, jid);
|
||||
|
||||
/* private data */
|
||||
auth = xmpp_auth_new();
|
||||
auth->ctx = ctx;
|
||||
auth->jid = jid;
|
||||
auth->pass = pass;
|
||||
auth->domain = xmpp_jid_domain(ctx, jid);
|
||||
|
||||
xmpp_connect_raw(conn, host, 0, conn_handler, auth);
|
||||
xmpp_run(ctx);
|
||||
|
||||
/* release private data */
|
||||
xmpp_auth_release(auth);
|
||||
|
||||
xmpp_conn_release(conn);
|
||||
xmpp_ctx_free(ctx);
|
||||
xmpp_shutdown();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -23,7 +23,7 @@ int handle_reply(xmpp_conn_t * const conn,
|
||||
void * const userdata)
|
||||
{
|
||||
xmpp_stanza_t *query, *item;
|
||||
char *type, *name;
|
||||
const char *type, *name;
|
||||
|
||||
type = xmpp_stanza_get_type(stanza);
|
||||
if (strcmp(type, "error") == 0)
|
||||
@@ -62,10 +62,7 @@ void conn_handler(xmpp_conn_t * const conn, const xmpp_conn_event_t status,
|
||||
fprintf(stderr, "DEBUG: connected\n");
|
||||
|
||||
/* create iq stanza for request */
|
||||
iq = xmpp_stanza_new(ctx);
|
||||
xmpp_stanza_set_name(iq, "iq");
|
||||
xmpp_stanza_set_type(iq, "get");
|
||||
xmpp_stanza_set_id(iq, "roster1");
|
||||
iq = xmpp_iq_new(ctx, "get", "roster1");
|
||||
|
||||
query = xmpp_stanza_new(ctx);
|
||||
xmpp_stanza_set_name(query, "query");
|
||||
@@ -109,6 +106,13 @@ int main(int argc, char **argv)
|
||||
/* create a connection */
|
||||
conn = xmpp_conn_new(ctx);
|
||||
|
||||
/*
|
||||
* also you can disable TLS support or force legacy SSL
|
||||
* connection without STARTTLS
|
||||
*
|
||||
* see xmpp_conn_set_flags() or examples/basic.c
|
||||
*/
|
||||
|
||||
/* setup authentication information */
|
||||
xmpp_conn_set_jid(conn, argv[1]);
|
||||
xmpp_conn_set_pass(conn, argv[2]);
|
||||
|
||||
23
examples/uuid.c
Normal file
23
examples/uuid.c
Normal file
@@ -0,0 +1,23 @@
|
||||
#include <stdio.h>
|
||||
#include <strophe.h>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
xmpp_ctx_t *ctx;
|
||||
char *uuid;
|
||||
int rc = 0;
|
||||
|
||||
ctx = xmpp_ctx_new(NULL, NULL);
|
||||
|
||||
uuid = xmpp_uuid_gen(ctx);
|
||||
if (uuid != NULL) {
|
||||
printf("%s\n", uuid);
|
||||
xmpp_free(ctx, uuid);
|
||||
} else {
|
||||
fprintf(stderr, "Couldn't allocate memory.\n");
|
||||
rc = 1;
|
||||
}
|
||||
|
||||
xmpp_ctx_free(ctx);
|
||||
return rc;
|
||||
}
|
||||
284
examples/vcard.c
Normal file
284
examples/vcard.c
Normal file
@@ -0,0 +1,284 @@
|
||||
/* vcard.c
|
||||
* strophe XMPP client library -- vCard example
|
||||
*
|
||||
* Copyright (C) 2016 Dmitry Podgorny <pasis.ua@gmail.com>
|
||||
*
|
||||
* This software is provided AS-IS with no warranty, either express
|
||||
* or implied.
|
||||
*
|
||||
* This program is dual licensed under the MIT and GPLv3 licenses.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <libgen.h> /* basename */
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <strophe.h>
|
||||
|
||||
typedef struct {
|
||||
xmpp_ctx_t *ctx;
|
||||
const char *recipient;
|
||||
const char *img_path;
|
||||
} vcard_t;
|
||||
|
||||
typedef void (*vcard_cb_t)(vcard_t *, xmpp_stanza_t *);
|
||||
|
||||
#define REQ_TIMEOUT 5000
|
||||
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
|
||||
|
||||
static void vcard_photo(vcard_t *vc, xmpp_stanza_t *stanza)
|
||||
{
|
||||
xmpp_stanza_t *tmp;
|
||||
char *s;
|
||||
char *tok;
|
||||
char *saveptr = NULL;
|
||||
char *copy;
|
||||
unsigned char *img;
|
||||
size_t img_size;
|
||||
size_t written;
|
||||
FILE *fd;
|
||||
|
||||
tmp = xmpp_stanza_get_child_by_name(stanza, "TYPE");
|
||||
assert(tmp != NULL);
|
||||
s = xmpp_stanza_get_text(tmp);
|
||||
assert(s != NULL);
|
||||
printf("PHOTO: %s, saving to file %s\n", s, vc->img_path);
|
||||
xmpp_free(vc->ctx, s);
|
||||
|
||||
tmp = xmpp_stanza_get_child_by_name(stanza, "BINVAL");
|
||||
assert(tmp != NULL);
|
||||
s = xmpp_stanza_get_text(tmp);
|
||||
assert(s != NULL);
|
||||
|
||||
/* remove \n and \r */
|
||||
copy = (char *)malloc(strlen(s) + 1);
|
||||
assert(copy != NULL);
|
||||
copy[0] = '\0';
|
||||
tok = strtok_r(s, "\n\r", &saveptr);
|
||||
while (tok != NULL) {
|
||||
strcat(copy, tok);
|
||||
tok = strtok_r(NULL, "\n\r", &saveptr);
|
||||
}
|
||||
|
||||
xmpp_base64_decode_bin(vc->ctx, copy, strlen(copy), &img, &img_size);
|
||||
assert(img != NULL);
|
||||
|
||||
fd = fopen(vc->img_path, "w");
|
||||
assert(fd != NULL);
|
||||
written = fwrite(img, 1, img_size, fd);
|
||||
if (written < img_size)
|
||||
printf("Saving photo failed\n");
|
||||
fclose(fd);
|
||||
|
||||
free(copy);
|
||||
xmpp_free(vc->ctx, s);
|
||||
xmpp_free(vc->ctx, img);
|
||||
}
|
||||
|
||||
static void vcard_print_string(vcard_t *vc, xmpp_stanza_t *stanza,
|
||||
const char *info)
|
||||
{
|
||||
char *s = xmpp_stanza_get_text(stanza);
|
||||
|
||||
assert(s != NULL);
|
||||
printf("%s: %s\n", info, s);
|
||||
xmpp_free(vc->ctx, s);
|
||||
}
|
||||
|
||||
static void vcard_bday(vcard_t *vc, xmpp_stanza_t *stanza)
|
||||
{
|
||||
vcard_print_string(vc, stanza, "Birthday");
|
||||
}
|
||||
|
||||
static void vcard_desc(vcard_t *vc, xmpp_stanza_t *stanza)
|
||||
{
|
||||
vcard_print_string(vc, stanza, "Description");
|
||||
}
|
||||
|
||||
static void vcard_email(vcard_t *vc, xmpp_stanza_t *stanza)
|
||||
{
|
||||
xmpp_stanza_t *userid = xmpp_stanza_get_child_by_name(stanza, "USERID");
|
||||
|
||||
if (userid != NULL)
|
||||
vcard_print_string(vc, userid, "E-mail");
|
||||
}
|
||||
|
||||
static void vcard_fn(vcard_t *vc, xmpp_stanza_t *stanza)
|
||||
{
|
||||
vcard_print_string(vc, stanza, "Full name");
|
||||
}
|
||||
|
||||
static void vcard_name(vcard_t *vc, xmpp_stanza_t *stanza)
|
||||
{
|
||||
xmpp_stanza_t *name = xmpp_stanza_get_child_by_name(stanza, "GIVEN");
|
||||
xmpp_stanza_t *family = xmpp_stanza_get_child_by_name(stanza, "FAMILY");
|
||||
|
||||
if (name != NULL)
|
||||
vcard_print_string(vc, name, "Given name");
|
||||
if (family != NULL)
|
||||
vcard_print_string(vc, family, "Family name");
|
||||
}
|
||||
|
||||
static void vcard_nick(vcard_t *vc, xmpp_stanza_t *stanza)
|
||||
{
|
||||
vcard_print_string(vc, stanza, "Nickname");
|
||||
}
|
||||
|
||||
static void vcard_url(vcard_t *vc, xmpp_stanza_t *stanza)
|
||||
{
|
||||
vcard_print_string(vc, stanza, "URL");
|
||||
}
|
||||
|
||||
static vcard_cb_t vcard_cb_get(xmpp_stanza_t *stanza)
|
||||
{
|
||||
vcard_cb_t cb = NULL;
|
||||
const char *tag;
|
||||
size_t i;
|
||||
|
||||
static struct {
|
||||
const char *tag;
|
||||
vcard_cb_t cb;
|
||||
} vcard_tbl[] = {
|
||||
{ "PHOTO", vcard_photo },
|
||||
{ "BDAY", vcard_bday },
|
||||
{ "DESC", vcard_desc },
|
||||
{ "EMAIL", vcard_email },
|
||||
{ "FN", vcard_fn },
|
||||
{ "N", vcard_name },
|
||||
{ "NICKNAME", vcard_nick },
|
||||
{ "URL", vcard_url },
|
||||
};
|
||||
|
||||
tag = xmpp_stanza_get_name(stanza);
|
||||
if (tag == NULL)
|
||||
goto exit;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(vcard_tbl); ++i) {
|
||||
if (strcmp(tag, vcard_tbl[i].tag) == 0) {
|
||||
cb = vcard_tbl[i].cb;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
return cb;
|
||||
}
|
||||
|
||||
static int timedout(xmpp_conn_t * const conn, void * const userdata)
|
||||
{
|
||||
fprintf(stderr, "Timeout reached.\n");
|
||||
xmpp_disconnect(conn);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int recv_vcard(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza,
|
||||
void * const userdata)
|
||||
{
|
||||
vcard_t *vc = userdata;
|
||||
vcard_cb_t cb;
|
||||
xmpp_stanza_t *child;
|
||||
char *s;
|
||||
size_t s_size;
|
||||
int rc;
|
||||
|
||||
printf("Received vCard.\n\n");
|
||||
|
||||
child = xmpp_stanza_get_child_by_name(stanza, "error");
|
||||
if (child != NULL) {
|
||||
rc = xmpp_stanza_to_text(child, &s, &s_size);
|
||||
assert(rc == XMPP_EOK);
|
||||
printf("Error returned: %s.\n", s);
|
||||
xmpp_free(vc->ctx, s);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
child = xmpp_stanza_get_child_by_name(stanza, "vCard");
|
||||
assert(child != NULL);
|
||||
child = xmpp_stanza_get_children(child);
|
||||
while (child != NULL) {
|
||||
cb = vcard_cb_get(child);
|
||||
if (cb != NULL)
|
||||
cb(vc, child);
|
||||
child = xmpp_stanza_get_next(child);
|
||||
}
|
||||
|
||||
exit:
|
||||
xmpp_disconnect(conn);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void send_vcard_req(xmpp_conn_t *conn, const char *to, const char *id)
|
||||
{
|
||||
printf("Requesting vCard from %s.\n", to);
|
||||
xmpp_send_raw_string(conn, "<iq from='%s' to='%s' type='get' id='%s'>"
|
||||
"<vCard xmlns='vcard-temp'/></iq>",
|
||||
xmpp_conn_get_bound_jid(conn), to, id);
|
||||
}
|
||||
|
||||
static void conn_handler(xmpp_conn_t * const conn,
|
||||
const xmpp_conn_event_t status,
|
||||
const int error,
|
||||
xmpp_stream_error_t * const stream_error,
|
||||
void * const userdata)
|
||||
{
|
||||
vcard_t *vc = userdata;
|
||||
|
||||
if (status == XMPP_CONN_CONNECT) {
|
||||
send_vcard_req(conn, vc->recipient, "vc1");
|
||||
xmpp_id_handler_add(conn, recv_vcard, "vc1", vc);
|
||||
xmpp_timed_handler_add(conn, timedout, REQ_TIMEOUT, NULL);
|
||||
} else {
|
||||
if (error != 0)
|
||||
fprintf(stderr, "Disconnected with error=%d.\n", error);
|
||||
if (stream_error != NULL)
|
||||
fprintf(stderr, "Stream error type=%d text=%s.\n",
|
||||
stream_error->type, stream_error->text);
|
||||
xmpp_stop(vc->ctx);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
xmpp_log_t *log;
|
||||
xmpp_ctx_t *ctx;
|
||||
xmpp_conn_t *conn;
|
||||
const char *jid;
|
||||
const char *pass;
|
||||
char *prog;
|
||||
vcard_t vcard;
|
||||
|
||||
if (argc < 4 || argc > 5) {
|
||||
prog = argc > 0 ? strdup(argv[0]) : NULL;
|
||||
printf("Usage: %s <login-jid> <password> <recipient-jid> "
|
||||
"[image-file]\n\n", prog == NULL ? "vcard" : basename(prog));
|
||||
printf("If vCard contains a photo it will be stored to "
|
||||
"image-file. If you don't provide the image-file "
|
||||
"default filename will be generated.\n");
|
||||
free(prog);
|
||||
return 1;
|
||||
}
|
||||
|
||||
jid = argv[1];
|
||||
pass = argv[2];
|
||||
vcard.recipient = argv[3];
|
||||
vcard.img_path = argc > 4 ? argv[4] : "vcard.jpg";
|
||||
|
||||
xmpp_initialize();
|
||||
log = xmpp_get_default_logger(XMPP_LEVEL_INFO);
|
||||
ctx = xmpp_ctx_new(NULL, log);
|
||||
conn = xmpp_conn_new(ctx);
|
||||
xmpp_conn_set_jid(conn, jid);
|
||||
xmpp_conn_set_pass(conn, pass);
|
||||
vcard.ctx = ctx;
|
||||
xmpp_connect_client(conn, NULL, 0, conn_handler, &vcard);
|
||||
xmpp_run(ctx);
|
||||
xmpp_conn_release(conn);
|
||||
xmpp_ctx_free(ctx);
|
||||
xmpp_shutdown();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
1
expat
1
expat
Submodule expat deleted from adf19a3186
78
jni/Android.mk
Normal file
78
jni/Android.mk
Normal file
@@ -0,0 +1,78 @@
|
||||
LOCAL_PATH:= $(call my-dir)
|
||||
|
||||
#
|
||||
# examples/basic
|
||||
#
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := basic
|
||||
LOCAL_CFLAGS :=
|
||||
LOCAL_C_INCLUDES := \
|
||||
$(LOCAL_PATH)/..
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
../examples/basic.c
|
||||
|
||||
LOCAL_STATIC_LIBRARIES := libstrophe libexpat
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
#
|
||||
# libstrohe (static library)
|
||||
#
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := libstrophe
|
||||
LOCAL_CFLAGS :=
|
||||
LOCAL_C_INCLUDES := \
|
||||
$(LOCAL_PATH)/.. \
|
||||
$(LOCAL_PATH)/../src \
|
||||
$(LOCAL_PATH)/../expat/lib
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
../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 \
|
||||
../src/parser_expat.c \
|
||||
../src/rand.c \
|
||||
../src/resolver.c \
|
||||
../src/sasl.c \
|
||||
../src/scram.c \
|
||||
../src/sha1.c \
|
||||
../src/snprintf.c \
|
||||
../src/sock.c \
|
||||
../src/stanza.c \
|
||||
../src/tls_dummy.c \
|
||||
../src/util.c \
|
||||
../src/uuid.c
|
||||
|
||||
LOCAL_STATIC_LIBRARIES := libstrophe
|
||||
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
#
|
||||
# expat
|
||||
#
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := libexpat
|
||||
LOCAL_CFLAGS := -DHAVE_MEMMOVE
|
||||
#LOCAL_C_INCLUDES := \
|
||||
# $(LOCAL_PATH)/expat
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
../expat/lib/xmlparse.c \
|
||||
../expat/lib/xmlrole.c \
|
||||
../expat/lib/xmltok.c \
|
||||
../expat/lib/xmltok_impl.c \
|
||||
../expat/lib/xmltok_ns.c
|
||||
|
||||
LOCAL_STATIC_LIBRARIES := libexpat
|
||||
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
2
jni/Application.mk
Normal file
2
jni/Application.mk
Normal file
@@ -0,0 +1,2 @@
|
||||
APP_ABI := armeabi armeabi-v7a mips x86
|
||||
APP_PLATFORM := android-19
|
||||
@@ -1,6 +1,6 @@
|
||||
1. Setup
|
||||
|
||||
yum install gcc make expat-devel libstrophe
|
||||
yum install gcc make autoconf automake expat-devel openssl-devel
|
||||
|
||||
Fedora:
|
||||
|
||||
|
||||
@@ -8,10 +8,12 @@ License: MIT/GPLv3
|
||||
URL: http://strophe.im/libstrophe/
|
||||
Source0: libstrophe_git.tar.gz
|
||||
|
||||
BuildRequires: autoconf
|
||||
BuildRequires: automake
|
||||
BuildRequires: libtool
|
||||
BuildRequires: openssl-devel
|
||||
BuildRequires: expat-devel
|
||||
Requires: openssl
|
||||
Requires: expat
|
||||
|
||||
%description
|
||||
|
||||
194
src/auth.c
194
src/auth.c
@@ -16,12 +16,12 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "strophe.h"
|
||||
#include "common.h"
|
||||
#include "sasl.h"
|
||||
#include "sha1.h"
|
||||
#include "rand.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define strcasecmp stricmp
|
||||
@@ -62,6 +62,7 @@
|
||||
|
||||
static void _auth(xmpp_conn_t * const conn);
|
||||
static void _handle_open_sasl(xmpp_conn_t * const conn);
|
||||
static void _handle_open_tls(xmpp_conn_t * const conn);
|
||||
|
||||
static int _handle_component_auth(xmpp_conn_t * const conn);
|
||||
static int _handle_component_hs_response(xmpp_conn_t * const conn,
|
||||
@@ -111,7 +112,7 @@ static int _handle_error(xmpp_conn_t * const conn,
|
||||
void * const userdata)
|
||||
{
|
||||
xmpp_stanza_t *child;
|
||||
char *name;
|
||||
const char *name;
|
||||
|
||||
/* free old stream error if it's still there */
|
||||
if (conn->stream_error) {
|
||||
@@ -130,7 +131,7 @@ static int _handle_error(xmpp_conn_t * const conn,
|
||||
if (conn->stream_error) {
|
||||
child = xmpp_stanza_get_children(stanza);
|
||||
do {
|
||||
char *ns = NULL;
|
||||
const char *ns = NULL;
|
||||
|
||||
if (child) {
|
||||
ns = xmpp_stanza_get_ns(child);
|
||||
@@ -279,33 +280,21 @@ static int _handle_proceedtls_default(xmpp_conn_t * const conn,
|
||||
xmpp_stanza_t * const stanza,
|
||||
void * const userdata)
|
||||
{
|
||||
char *name;
|
||||
const char *name;
|
||||
|
||||
name = xmpp_stanza_get_name(stanza);
|
||||
xmpp_debug(conn->ctx, "xmpp",
|
||||
"handle proceedtls called for %s", name);
|
||||
xmpp_debug(conn->ctx, "xmpp", "handle proceedtls called for %s", name);
|
||||
|
||||
if (strcmp(name, "proceed") == 0) {
|
||||
xmpp_debug(conn->ctx, "xmpp", "proceeding with TLS");
|
||||
|
||||
conn->tls = tls_new(conn->ctx, conn->sock);
|
||||
|
||||
if (!tls_start(conn->tls))
|
||||
{
|
||||
xmpp_debug(conn->ctx, "xmpp", "Couldn't start TLS! error %d", tls_error(conn->tls));
|
||||
tls_free(conn->tls);
|
||||
conn->tls = NULL;
|
||||
conn->tls_failed = 1;
|
||||
|
||||
/* failed tls spoils the connection, so disconnect */
|
||||
xmpp_disconnect(conn);
|
||||
}
|
||||
else
|
||||
{
|
||||
conn->secured = 1;
|
||||
conn_prepare_reset(conn, auth_handle_open);
|
||||
|
||||
conn_open_stream(conn);
|
||||
}
|
||||
if (conn_tls_start(conn) == 0) {
|
||||
conn_prepare_reset(conn, _handle_open_tls);
|
||||
conn_open_stream(conn);
|
||||
} else {
|
||||
/* failed tls spoils the connection, so disconnect */
|
||||
xmpp_disconnect(conn);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -315,7 +304,7 @@ static int _handle_sasl_result(xmpp_conn_t * const conn,
|
||||
xmpp_stanza_t * const stanza,
|
||||
void * const userdata)
|
||||
{
|
||||
char *name;
|
||||
const char *name;
|
||||
|
||||
name = xmpp_stanza_get_name(stanza);
|
||||
|
||||
@@ -327,7 +316,7 @@ static int _handle_sasl_result(xmpp_conn_t * const conn,
|
||||
/* fall back to next auth method */
|
||||
_auth(conn);
|
||||
} else if (strcmp(name, "success") == 0) {
|
||||
/* SASL PLAIN auth successful, we need to restart the stream */
|
||||
/* SASL auth successful, we need to restart the stream */
|
||||
xmpp_debug(conn->ctx, "xmpp", "SASL %s auth successful",
|
||||
(char *)userdata);
|
||||
|
||||
@@ -354,7 +343,7 @@ static int _handle_digestmd5_challenge(xmpp_conn_t * const conn,
|
||||
char *text;
|
||||
char *response;
|
||||
xmpp_stanza_t *auth, *authdata;
|
||||
char *name;
|
||||
const char *name;
|
||||
|
||||
name = xmpp_stanza_get_name(stanza);
|
||||
xmpp_debug(conn->ctx, "xmpp",\
|
||||
@@ -409,7 +398,7 @@ static int _handle_digestmd5_rspauth(xmpp_conn_t * const conn,
|
||||
void * const userdata)
|
||||
{
|
||||
xmpp_stanza_t *auth;
|
||||
char *name;
|
||||
const char *name;
|
||||
|
||||
name = xmpp_stanza_get_name(stanza);
|
||||
xmpp_debug(conn->ctx, "xmpp",
|
||||
@@ -442,7 +431,7 @@ static int _handle_scram_sha1_challenge(xmpp_conn_t * const conn,
|
||||
char *text;
|
||||
char *response;
|
||||
xmpp_stanza_t *auth, *authdata;
|
||||
char *name;
|
||||
const char *name;
|
||||
char *challenge;
|
||||
char *scram_init = (char *)userdata;
|
||||
|
||||
@@ -455,7 +444,7 @@ static int _handle_scram_sha1_challenge(xmpp_conn_t * const conn,
|
||||
if (!text)
|
||||
goto err;
|
||||
|
||||
challenge = (char *)base64_decode(conn->ctx, text, strlen(text));
|
||||
challenge = xmpp_base64_decode_str(conn->ctx, text, strlen(text));
|
||||
xmpp_free(conn->ctx, text);
|
||||
if (!challenge)
|
||||
goto err;
|
||||
@@ -501,46 +490,25 @@ err:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *_get_nonce(xmpp_ctx_t *ctx)
|
||||
{
|
||||
unsigned char buffer[sizeof(clock_t) + sizeof(time_t)] = {0};
|
||||
clock_t ticks = clock();
|
||||
time_t t;
|
||||
|
||||
if (ticks != (clock_t)-1) {
|
||||
*(clock_t *)buffer = ticks;
|
||||
}
|
||||
t = time((time_t *)(buffer + sizeof(clock_t)));
|
||||
if (t == (time_t)-1) {
|
||||
*(time_t *)(buffer + sizeof(clock_t)) = (time_t)rand();
|
||||
}
|
||||
|
||||
return base64_encode(ctx, buffer, sizeof(buffer));
|
||||
}
|
||||
|
||||
static char *_make_scram_sha1_init_msg(xmpp_conn_t * const conn)
|
||||
{
|
||||
xmpp_ctx_t *ctx = conn->ctx;
|
||||
size_t message_len;
|
||||
char *node;
|
||||
char *message;
|
||||
char *nonce;
|
||||
char nonce[32];
|
||||
|
||||
node = xmpp_jid_node(conn->ctx, conn->jid);
|
||||
node = xmpp_jid_node(ctx, conn->jid);
|
||||
if (!node) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
nonce = _get_nonce(conn->ctx);
|
||||
if (!nonce) {
|
||||
return NULL;
|
||||
}
|
||||
xmpp_rand_nonce(ctx->rand, nonce, sizeof(nonce));
|
||||
message_len = strlen(node) + strlen(nonce) + 8 + 1;
|
||||
message = xmpp_alloc(conn->ctx, message_len);
|
||||
message = xmpp_alloc(ctx, message_len);
|
||||
if (message) {
|
||||
xmpp_snprintf(message, message_len, "n,,n=%s,r=%s", node, nonce);
|
||||
xmpp_free(conn->ctx, node);
|
||||
}
|
||||
xmpp_free(conn->ctx, nonce);
|
||||
xmpp_free(ctx, node);
|
||||
|
||||
return message;
|
||||
}
|
||||
@@ -596,19 +564,15 @@ static void _auth(xmpp_conn_t * const conn)
|
||||
anonjid = 0;
|
||||
}
|
||||
|
||||
if (conn->tls_support)
|
||||
{
|
||||
tls_t *tls = tls_new(conn->ctx, conn->sock);
|
||||
if (conn->tls_support) {
|
||||
tls_t *tls = tls_new(conn);
|
||||
|
||||
/* If we couldn't init tls, it isn't there, so go on */
|
||||
if (!tls)
|
||||
{
|
||||
if (!tls) {
|
||||
conn->tls_support = 0;
|
||||
_auth(conn);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
tls_free(tls);
|
||||
}
|
||||
|
||||
@@ -627,7 +591,18 @@ static void _auth(xmpp_conn_t * const conn)
|
||||
|
||||
/* TLS was tried, unset flag */
|
||||
conn->tls_support = 0;
|
||||
} else if (anonjid && conn->sasl_support & SASL_MASK_ANONYMOUS) {
|
||||
/* _auth() will be called later */
|
||||
return;
|
||||
}
|
||||
|
||||
if (conn->tls_mandatory && !xmpp_conn_is_secured(conn)) {
|
||||
xmpp_error(conn->ctx, "xmpp", "TLS is not supported, but set as "
|
||||
"mandatory for this connection");
|
||||
conn_disconnect(conn);
|
||||
return;
|
||||
}
|
||||
|
||||
if (anonjid && conn->sasl_support & SASL_MASK_ANONYMOUS) {
|
||||
/* some crap here */
|
||||
auth = _make_sasl_auth(conn, "ANONYMOUS");
|
||||
if (!auth) {
|
||||
@@ -662,8 +637,8 @@ static void _auth(xmpp_conn_t * const conn)
|
||||
return;
|
||||
}
|
||||
|
||||
str = (char *)base64_encode(conn->ctx, (unsigned char *)scram_init,
|
||||
strlen(scram_init));
|
||||
str = xmpp_base64_encode(conn->ctx, (unsigned char *)scram_init,
|
||||
strlen(scram_init));
|
||||
if (!str) {
|
||||
xmpp_free(conn->ctx, scram_init);
|
||||
xmpp_stanza_release(auth);
|
||||
@@ -747,14 +722,11 @@ static void _auth(xmpp_conn_t * const conn)
|
||||
} else if (conn->type == XMPP_CLIENT) {
|
||||
/* legacy client authentication */
|
||||
|
||||
iq = xmpp_stanza_new(conn->ctx);
|
||||
iq = xmpp_iq_new(conn->ctx, "set", "_xmpp_auth1");
|
||||
if (!iq) {
|
||||
disconnect_mem_error(conn);
|
||||
return;
|
||||
}
|
||||
xmpp_stanza_set_name(iq, "iq");
|
||||
xmpp_stanza_set_type(iq, "set");
|
||||
xmpp_stanza_set_id(iq, "_xmpp_auth1");
|
||||
|
||||
query = xmpp_stanza_new(conn->ctx);
|
||||
if (!query) {
|
||||
@@ -864,15 +836,23 @@ void auth_handle_open(xmpp_conn_t * const conn)
|
||||
/* reset all timed handlers */
|
||||
handler_reset_timed(conn, 0);
|
||||
|
||||
/* setup handler for stream:error */
|
||||
handler_add(conn, _handle_error,
|
||||
XMPP_NS_STREAMS, "error", NULL, NULL);
|
||||
/* setup handler for stream:error, we will keep this handler
|
||||
* for reopened streams until connection is disconnected */
|
||||
handler_add(conn, _handle_error, XMPP_NS_STREAMS, "error", NULL, NULL);
|
||||
|
||||
/* setup handlers for incoming <stream:features> */
|
||||
handler_add(conn, _handle_features,
|
||||
XMPP_NS_STREAMS, "features", NULL, NULL);
|
||||
handler_add_timed(conn, _handle_missing_features,
|
||||
FEATURES_TIMEOUT, NULL);
|
||||
handler_add_timed(conn, _handle_missing_features, FEATURES_TIMEOUT, NULL);
|
||||
}
|
||||
|
||||
/* called when stream:stream tag received after TLS establishment */
|
||||
static void _handle_open_tls(xmpp_conn_t * const conn)
|
||||
{
|
||||
/* setup handlers for incoming <stream:features> */
|
||||
handler_add(conn, _handle_features,
|
||||
XMPP_NS_STREAMS, "features", NULL, NULL);
|
||||
handler_add_timed(conn, _handle_missing_features, FEATURES_TIMEOUT, NULL);
|
||||
}
|
||||
|
||||
/* called when stream:stream tag received after SASL auth */
|
||||
@@ -922,16 +902,12 @@ static int _handle_features_sasl(xmpp_conn_t * const conn,
|
||||
BIND_TIMEOUT, NULL);
|
||||
|
||||
/* send bind request */
|
||||
iq = xmpp_stanza_new(conn->ctx);
|
||||
iq = xmpp_iq_new(conn->ctx, "set", "_xmpp_bind1");
|
||||
if (!iq) {
|
||||
disconnect_mem_error(conn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
xmpp_stanza_set_name(iq, "iq");
|
||||
xmpp_stanza_set_type(iq, "set");
|
||||
xmpp_stanza_set_id(iq, "_xmpp_bind1");
|
||||
|
||||
bind = xmpp_stanza_copy(bind);
|
||||
if (!bind) {
|
||||
xmpp_stanza_release(iq);
|
||||
@@ -1003,7 +979,7 @@ static int _handle_bind(xmpp_conn_t * const conn,
|
||||
xmpp_stanza_t * const stanza,
|
||||
void * const userdata)
|
||||
{
|
||||
char *type;
|
||||
const char *type;
|
||||
xmpp_stanza_t *iq, *session;
|
||||
|
||||
/* delete missing bind handler */
|
||||
@@ -1034,20 +1010,17 @@ static int _handle_bind(xmpp_conn_t * const conn,
|
||||
SESSION_TIMEOUT, NULL);
|
||||
|
||||
/* send session request */
|
||||
iq = xmpp_stanza_new(conn->ctx);
|
||||
iq = xmpp_iq_new(conn->ctx, "set", "_xmpp_session1");
|
||||
if (!iq) {
|
||||
disconnect_mem_error(conn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
xmpp_stanza_set_name(iq, "iq");
|
||||
xmpp_stanza_set_type(iq, "set");
|
||||
xmpp_stanza_set_id(iq, "_xmpp_session1");
|
||||
|
||||
session = xmpp_stanza_new(conn->ctx);
|
||||
if (!session) {
|
||||
xmpp_stanza_release(iq);
|
||||
disconnect_mem_error(conn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
xmpp_stanza_set_name(session, "session");
|
||||
@@ -1086,7 +1059,7 @@ static int _handle_session(xmpp_conn_t * const conn,
|
||||
xmpp_stanza_t * const stanza,
|
||||
void * const userdata)
|
||||
{
|
||||
char *type;
|
||||
const char *type;
|
||||
|
||||
/* delete missing session handler */
|
||||
xmpp_timed_handler_delete(conn, _handle_missing_session);
|
||||
@@ -1123,7 +1096,8 @@ static int _handle_legacy(xmpp_conn_t * const conn,
|
||||
xmpp_stanza_t * const stanza,
|
||||
void * const userdata)
|
||||
{
|
||||
char *type, *name;
|
||||
const char *type;
|
||||
const char *name;
|
||||
|
||||
/* delete missing handler */
|
||||
xmpp_timed_handler_delete(conn, _handle_missing_legacy);
|
||||
@@ -1165,6 +1139,8 @@ static int _handle_missing_legacy(xmpp_conn_t * const conn,
|
||||
|
||||
void auth_handle_component_open(xmpp_conn_t * const conn)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* reset all timed handlers */
|
||||
handler_reset_timed(conn, 0);
|
||||
|
||||
@@ -1173,7 +1149,11 @@ void auth_handle_component_open(xmpp_conn_t * const conn)
|
||||
"handshake", NULL, NULL);
|
||||
handler_add_timed(conn, _handle_missing_handshake, HANDSHAKE_TIMEOUT, NULL);
|
||||
|
||||
_handle_component_auth(conn);
|
||||
rc = _handle_component_auth(conn);
|
||||
if (rc != 0) {
|
||||
xmpp_error(conn->ctx, "auth", "Component authentication failed.");
|
||||
xmpp_disconnect(conn);
|
||||
}
|
||||
}
|
||||
|
||||
/* Will compute SHA1 and authenticate the component to the server */
|
||||
@@ -1184,13 +1164,19 @@ int _handle_component_auth(xmpp_conn_t * const conn)
|
||||
char *digest;
|
||||
size_t i;
|
||||
|
||||
if (conn->stream_id == NULL) {
|
||||
xmpp_error(conn->ctx, "auth", "Received no stream id from the server.");
|
||||
return XMPP_EINT;
|
||||
}
|
||||
|
||||
/* Feed the session id and passphrase to the algorithm.
|
||||
* We need to compute SHA1(session_id + passphrase)
|
||||
*/
|
||||
SHA1_Init(&mdctx);
|
||||
SHA1_Update(&mdctx, (uint8_t*)conn->stream_id, strlen(conn->stream_id));
|
||||
SHA1_Update(&mdctx, (uint8_t*)conn->pass, strlen(conn->pass));
|
||||
SHA1_Final(&mdctx, md_value);
|
||||
crypto_SHA1_Init(&mdctx);
|
||||
crypto_SHA1_Update(&mdctx, (uint8_t*)conn->stream_id,
|
||||
strlen(conn->stream_id));
|
||||
crypto_SHA1_Update(&mdctx, (uint8_t*)conn->pass, strlen(conn->pass));
|
||||
crypto_SHA1_Final(&mdctx, md_value);
|
||||
|
||||
digest = xmpp_alloc(conn->ctx, 2*sizeof(md_value)+1);
|
||||
if (digest) {
|
||||
@@ -1210,7 +1196,6 @@ int _handle_component_auth(xmpp_conn_t * const conn)
|
||||
} else {
|
||||
xmpp_debug(conn->ctx, "auth", "Couldn't allocate memory for component "\
|
||||
"handshake digest.");
|
||||
xmpp_disconnect(conn);
|
||||
return XMPP_EMEM;
|
||||
}
|
||||
|
||||
@@ -1224,7 +1209,7 @@ int _handle_component_hs_response(xmpp_conn_t * const conn,
|
||||
xmpp_stanza_t * const stanza,
|
||||
void * const userdata)
|
||||
{
|
||||
char *name;
|
||||
const char *name;
|
||||
|
||||
xmpp_timed_handler_delete(conn, _handle_missing_handshake);
|
||||
|
||||
@@ -1256,3 +1241,16 @@ int _handle_missing_handshake(xmpp_conn_t * const conn, void * const userdata)
|
||||
xmpp_disconnect(conn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void auth_handle_open_raw(xmpp_conn_t * const conn)
|
||||
{
|
||||
handler_reset_timed(conn, 0);
|
||||
/* user handlers are not called before authentication is completed. */
|
||||
conn->authenticated = 1;
|
||||
conn->conn_handler(conn, XMPP_CONN_CONNECT, 0, NULL, conn->userdata);
|
||||
}
|
||||
|
||||
void auth_handle_open_stub(xmpp_conn_t * const conn)
|
||||
{
|
||||
xmpp_warn(conn->ctx, "auth", "Stub callback is called.");
|
||||
}
|
||||
|
||||
156
src/common.h
156
src/common.h
@@ -1,7 +1,7 @@
|
||||
/* common.h
|
||||
** strophe XMPP client library -- internal common structures
|
||||
**
|
||||
** Copyright (C) 2005-2009 Collecta, Inc.
|
||||
** Copyright (C) 2005-2009 Collecta, Inc.
|
||||
**
|
||||
** This software is provided AS-IS with no warranty, either express or
|
||||
** implied.
|
||||
@@ -27,6 +27,8 @@
|
||||
#include "hash.h"
|
||||
#include "util.h"
|
||||
#include "parser.h"
|
||||
#include "rand.h"
|
||||
#include "snprintf.h"
|
||||
|
||||
/** run-time context **/
|
||||
|
||||
@@ -45,51 +47,43 @@ struct _xmpp_ctx_t {
|
||||
const xmpp_mem_t *mem;
|
||||
const xmpp_log_t *log;
|
||||
|
||||
xmpp_rand_t *rand;
|
||||
xmpp_loop_status_t loop_status;
|
||||
xmpp_connlist_t *connlist;
|
||||
|
||||
unsigned long timeout;
|
||||
};
|
||||
|
||||
|
||||
/* convenience functions for accessing the context */
|
||||
void *xmpp_alloc(const xmpp_ctx_t * const ctx, const size_t size);
|
||||
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);
|
||||
|
||||
void xmpp_log(const xmpp_ctx_t * const ctx,
|
||||
const xmpp_log_level_t level,
|
||||
const char * const area,
|
||||
const char * const fmt,
|
||||
va_list ap);
|
||||
void xmpp_log(const xmpp_ctx_t * const ctx,
|
||||
const xmpp_log_level_t level,
|
||||
const char * const area,
|
||||
const char * const fmt,
|
||||
va_list ap);
|
||||
|
||||
/* wrappers for xmpp_log at specific levels */
|
||||
void xmpp_error(const xmpp_ctx_t * const ctx,
|
||||
const char * const area,
|
||||
const char * const fmt,
|
||||
...);
|
||||
const char * const area,
|
||||
const char * const fmt,
|
||||
...);
|
||||
void xmpp_warn(const xmpp_ctx_t * const ctx,
|
||||
const char * const area,
|
||||
const char * const fmt,
|
||||
...);
|
||||
const char * const area,
|
||||
const char * const fmt,
|
||||
...);
|
||||
void xmpp_info(const xmpp_ctx_t * const ctx,
|
||||
const char * const area,
|
||||
const char * const fmt,
|
||||
...);
|
||||
const char * const area,
|
||||
const char * const fmt,
|
||||
...);
|
||||
void xmpp_debug(const xmpp_ctx_t * const ctx,
|
||||
const char * const area,
|
||||
const char * const fmt,
|
||||
...);
|
||||
|
||||
/** jid */
|
||||
/* these return new strings that must be xmpp_free()'d */
|
||||
char *xmpp_jid_new(xmpp_ctx_t *ctx, const char *node,
|
||||
const char *domain,
|
||||
const char *resource);
|
||||
char *xmpp_jid_bare(xmpp_ctx_t *ctx, const char *jid);
|
||||
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_resource(xmpp_ctx_t *ctx, const char *jid);
|
||||
|
||||
const char * const area,
|
||||
const char * const fmt,
|
||||
...);
|
||||
|
||||
/** connection **/
|
||||
|
||||
@@ -113,36 +107,44 @@ typedef struct _xmpp_handlist_t xmpp_handlist_t;
|
||||
struct _xmpp_handlist_t {
|
||||
/* common members */
|
||||
int user_handler;
|
||||
void *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 */
|
||||
* 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;
|
||||
};
|
||||
/* 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 SASL_MASK_PLAIN 0x01
|
||||
#define SASL_MASK_DIGESTMD5 0x02
|
||||
#define SASL_MASK_ANONYMOUS 0x04
|
||||
#define SASL_MASK_SCRAMSHA1 0x08
|
||||
#define MAX_DOMAIN_LEN 256
|
||||
|
||||
#define SASL_MASK_PLAIN (1 << 0)
|
||||
#define SASL_MASK_DIGESTMD5 (1 << 1)
|
||||
#define SASL_MASK_ANONYMOUS (1 << 2)
|
||||
#define SASL_MASK_SCRAMSHA1 (1 << 3)
|
||||
|
||||
enum {
|
||||
XMPP_PORT_CLIENT = 5222,
|
||||
XMPP_PORT_CLIENT_LEGACY_SSL = 5223,
|
||||
XMPP_PORT_COMPONENT = 5347,
|
||||
};
|
||||
|
||||
typedef void (*xmpp_open_handler)(xmpp_conn_t * const conn);
|
||||
|
||||
@@ -150,19 +152,26 @@ struct _xmpp_conn_t {
|
||||
unsigned int ref;
|
||||
xmpp_ctx_t *ctx;
|
||||
xmpp_conn_type_t type;
|
||||
int is_raw;
|
||||
|
||||
xmpp_conn_state_t state;
|
||||
uint64_t timeout_stamp;
|
||||
int error;
|
||||
xmpp_stream_error_t *stream_error;
|
||||
sock_t sock;
|
||||
tls_t *tls;
|
||||
|
||||
sock_t sock;
|
||||
int ka_timeout; /* TCP keepalive timeout */
|
||||
int ka_interval; /* TCP keepalive interval */
|
||||
|
||||
tls_t *tls;
|
||||
int tls_support;
|
||||
int tls_disabled;
|
||||
int tls_mandatory;
|
||||
int tls_legacy_ssl;
|
||||
int tls_trust;
|
||||
int tls_failed; /* set when tls fails, so we don't try again */
|
||||
int sasl_support; /* if true, field is a bitfield of supported
|
||||
mechanisms */
|
||||
mechanisms */
|
||||
int secured; /* set when stream is secured with TLS */
|
||||
|
||||
/* if server returns <bind/> or <session/> we must do them */
|
||||
@@ -171,8 +180,6 @@ struct _xmpp_conn_t {
|
||||
|
||||
char *lang;
|
||||
char *domain;
|
||||
char *connectdomain;
|
||||
char *connectport;
|
||||
char *jid;
|
||||
char *pass;
|
||||
char *bound_jid;
|
||||
@@ -192,7 +199,7 @@ struct _xmpp_conn_t {
|
||||
/* timeouts */
|
||||
unsigned int connect_timeout;
|
||||
|
||||
/* event handlers */
|
||||
/* event handlers */
|
||||
|
||||
/* stream open handler */
|
||||
xmpp_open_handler open_handler;
|
||||
@@ -212,7 +219,9 @@ struct _xmpp_conn_t {
|
||||
|
||||
void conn_disconnect(xmpp_conn_t * const conn);
|
||||
void conn_disconnect_clean(xmpp_conn_t * const conn);
|
||||
void conn_established(xmpp_conn_t * const conn);
|
||||
void conn_open_stream(xmpp_conn_t * const conn);
|
||||
int conn_tls_start(xmpp_conn_t * const conn);
|
||||
void conn_prepare_reset(xmpp_conn_t * const conn, xmpp_open_handler handler);
|
||||
void conn_parser_reset(xmpp_conn_t * const conn);
|
||||
|
||||
@@ -241,23 +250,24 @@ struct _xmpp_stanza_t {
|
||||
|
||||
/* handler management */
|
||||
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);
|
||||
void handler_reset_timed(xmpp_conn_t *conn, int user_only);
|
||||
void handler_add_timed(xmpp_conn_t * const conn,
|
||||
xmpp_timed_handler handler,
|
||||
const unsigned long period,
|
||||
void * const userdata);
|
||||
xmpp_timed_handler handler,
|
||||
const unsigned long period,
|
||||
void * const userdata);
|
||||
void handler_add_id(xmpp_conn_t * const conn,
|
||||
xmpp_handler handler,
|
||||
const char * const id,
|
||||
void * const userdata);
|
||||
xmpp_handler handler,
|
||||
const char * const id,
|
||||
void * const userdata);
|
||||
void handler_add(xmpp_conn_t * const conn,
|
||||
xmpp_handler handler,
|
||||
const char * const ns,
|
||||
const char * const name,
|
||||
const char * const type,
|
||||
void * const userdata);
|
||||
xmpp_handler handler,
|
||||
const char * const ns,
|
||||
const char * const name,
|
||||
const char * const type,
|
||||
void * const userdata);
|
||||
void handler_system_delete_all(xmpp_conn_t *conn);
|
||||
|
||||
/* utility functions */
|
||||
void disconnect_mem_error(xmpp_conn_t * const conn);
|
||||
@@ -265,9 +275,7 @@ void disconnect_mem_error(xmpp_conn_t * const conn);
|
||||
/* auth functions */
|
||||
void auth_handle_open(xmpp_conn_t * const conn);
|
||||
void auth_handle_component_open(xmpp_conn_t * const conn);
|
||||
|
||||
/* replacement snprintf and vsnprintf */
|
||||
int xmpp_snprintf (char *str, size_t count, const char *fmt, ...);
|
||||
int xmpp_vsnprintf (char *str, size_t count, const char *fmt, va_list arg);
|
||||
void auth_handle_open_raw(xmpp_conn_t * const conn);
|
||||
void auth_handle_open_stub(xmpp_conn_t * const conn);
|
||||
|
||||
#endif /* __LIBSTROPHE_COMMON_H__ */
|
||||
|
||||
1090
src/conn.c
1090
src/conn.c
File diff suppressed because it is too large
Load Diff
491
src/crypto.c
Normal file
491
src/crypto.c
Normal file
@@ -0,0 +1,491 @@
|
||||
/* crypto.c
|
||||
* strophe XMPP client library -- public interface for digests, encodings
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/** @file
|
||||
* Public interface for digests and encodings used in XEPs.
|
||||
*/
|
||||
|
||||
/** @defgroup Digests Message digests
|
||||
*/
|
||||
|
||||
/** @defgroup Encodings Encodings
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h> /* memset, memcpy */
|
||||
|
||||
#include "common.h" /* xmpp_alloc */
|
||||
#include "ostypes.h" /* uint8_t, size_t */
|
||||
#include "sha1.h"
|
||||
#include "snprintf.h" /* xmpp_snprintf */
|
||||
#include "strophe.h" /* xmpp_ctx_t, xmpp_free */
|
||||
|
||||
struct _xmpp_sha1_t {
|
||||
xmpp_ctx_t *xmpp_ctx;
|
||||
SHA1_CTX ctx;
|
||||
uint8_t digest[SHA1_DIGEST_SIZE];
|
||||
};
|
||||
|
||||
static char *digest_to_string(const uint8_t *digest, char *s, size_t len)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (len < SHA1_DIGEST_SIZE * 2 + 1)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < SHA1_DIGEST_SIZE; ++i)
|
||||
xmpp_snprintf(s + i * 2, 3, "%02x", digest[i]);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
static char *digest_to_string_alloc(xmpp_ctx_t *ctx, const uint8_t *digest)
|
||||
{
|
||||
char *s;
|
||||
size_t slen;
|
||||
|
||||
slen = SHA1_DIGEST_SIZE * 2 + 1;
|
||||
s = xmpp_alloc(ctx, slen);
|
||||
if (s) {
|
||||
s = digest_to_string(digest, s, slen);
|
||||
assert(s != NULL);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
/** Compute SHA1 message digest
|
||||
* Returns an allocated string which represents SHA1 message digest in
|
||||
* hexadecimal notation. The string must be freed with xmpp_free().
|
||||
*
|
||||
* @param ctx a Strophe context object
|
||||
* @param data buffer for digest computation
|
||||
* @param len size of the data buffer
|
||||
*
|
||||
* @return an allocated string or NULL on allocation error
|
||||
*
|
||||
* @ingroup Digests
|
||||
*/
|
||||
char *xmpp_sha1(xmpp_ctx_t *ctx, const unsigned char *data, size_t len)
|
||||
{
|
||||
uint8_t digest[SHA1_DIGEST_SIZE];
|
||||
|
||||
crypto_SHA1((const uint8_t *)data, len, digest);
|
||||
return digest_to_string_alloc(ctx, digest);
|
||||
}
|
||||
|
||||
/** Compute SHA1 message digest
|
||||
* Stores digest in user's buffer which must be at least XMPP_SHA1_DIGEST_SIZE
|
||||
* bytes long.
|
||||
*
|
||||
* @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 onject
|
||||
*
|
||||
* @return new SHA1 object
|
||||
*
|
||||
* @ingroup Digests
|
||||
*/
|
||||
xmpp_sha1_t *xmpp_sha1_new(xmpp_ctx_t *ctx)
|
||||
{
|
||||
xmpp_sha1_t *sha1;
|
||||
|
||||
sha1 = xmpp_alloc(ctx, sizeof(*sha1));
|
||||
if (sha1) {
|
||||
memset(sha1, 0, sizeof(*sha1));
|
||||
crypto_SHA1_Init(&sha1->ctx);
|
||||
sha1->xmpp_ctx = ctx;
|
||||
}
|
||||
return sha1;
|
||||
}
|
||||
|
||||
/** Destroy SHA1 object
|
||||
*
|
||||
* @param sha1 a SHA1 object
|
||||
*
|
||||
* @ingroup Digests
|
||||
*/
|
||||
void xmpp_sha1_free(xmpp_sha1_t *sha1)
|
||||
{
|
||||
xmpp_free(sha1->xmpp_ctx, sha1);
|
||||
}
|
||||
|
||||
/** Update SHA1 context with the next portion of data
|
||||
* Can be called repeatedly.
|
||||
*
|
||||
* @param sha1 a SHA1 object
|
||||
* @param data pointer to a buffer to be hashed
|
||||
* @param len size of the data buffer
|
||||
*
|
||||
* @ingroup Digests
|
||||
*/
|
||||
void xmpp_sha1_update(xmpp_sha1_t *sha1, const unsigned char *data, size_t len)
|
||||
{
|
||||
crypto_SHA1_Update(&sha1->ctx, data, len);
|
||||
}
|
||||
|
||||
/** Finish SHA1 computation
|
||||
* Don't call xmpp_sha1_update() after this function. Retrieve resulting
|
||||
* message digest with xmpp_sha1_to_string() or xmpp_sha1_to_digest().
|
||||
*
|
||||
* @param sha1 a SHA1 object
|
||||
*
|
||||
* @ingroup Digests
|
||||
*/
|
||||
void xmpp_sha1_final(xmpp_sha1_t *sha1)
|
||||
{
|
||||
crypto_SHA1_Final(&sha1->ctx, sha1->digest);
|
||||
}
|
||||
|
||||
/** Return message digest rendered as a string
|
||||
* Stores the string to a user's buffer and returns the buffer. Call this
|
||||
* function after xmpp_sha1_final().
|
||||
*
|
||||
* @param sha1 a SHA1 object
|
||||
* @param s output string
|
||||
* @param slen size reserved for the string including '\0'
|
||||
*
|
||||
* @return pointer s or NULL if resulting string is bigger than slen bytes
|
||||
*
|
||||
* @ingroup Digests
|
||||
*/
|
||||
char *xmpp_sha1_to_string(xmpp_sha1_t *sha1, char *s, size_t slen)
|
||||
{
|
||||
return digest_to_string(sha1->digest, s, slen);
|
||||
}
|
||||
|
||||
/** Return message digest rendered as a string
|
||||
* Returns an allocated string. Free the string using the Strophe context
|
||||
* which is passed to xmpp_sha1_new(). Call this function after
|
||||
* xmpp_sha1_final().
|
||||
*
|
||||
* @param sha1 a SHA1 object
|
||||
*
|
||||
* @return an allocated string
|
||||
*
|
||||
* @ingroup Digests
|
||||
*/
|
||||
char *xmpp_sha1_to_string_alloc(xmpp_sha1_t *sha1)
|
||||
{
|
||||
return digest_to_string_alloc(sha1->xmpp_ctx, sha1->digest);
|
||||
}
|
||||
|
||||
/** Stores message digest to a user's buffer
|
||||
*
|
||||
* @param sha1 a SHA1 object
|
||||
* @param digest output buffer of XMPP_SHA1_DIGEST_SIZE bytes
|
||||
*
|
||||
* @ingroup Digests
|
||||
*/
|
||||
void xmpp_sha1_to_digest(xmpp_sha1_t *sha1, unsigned char *digest)
|
||||
{
|
||||
assert(SHA1_DIGEST_SIZE == XMPP_SHA1_DIGEST_SIZE);
|
||||
memcpy(digest, sha1->digest, SHA1_DIGEST_SIZE);
|
||||
}
|
||||
|
||||
|
||||
/* Base64 encoding routines. Implemented according to RFC 3548. */
|
||||
|
||||
/* map of all byte values to the base64 values, or to
|
||||
'65' which indicates an invalid character. '=' is '64' */
|
||||
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,62, 65,65,65,63,
|
||||
52,53,54,55, 56,57,58,59, 60,61,65,65, 65,64,65,65,
|
||||
65, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14,
|
||||
15,16,17,18, 19,20,21,22, 23,24,25,65, 65,65,65,65,
|
||||
65,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
|
||||
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
|
||||
};
|
||||
|
||||
/* map of all 6-bit values to their corresponding byte
|
||||
in the base64 alphabet. Padding char is the value '64' */
|
||||
static const char _base64_charmap[65] = {
|
||||
'A','B','C','D', 'E','F','G','H',
|
||||
'I','J','K','L', 'M','N','O','P',
|
||||
'Q','R','S','T', 'U','V','W','X',
|
||||
'Y','Z','a','b', 'c','d','e','f',
|
||||
'g','h','i','j', 'k','l','m','n',
|
||||
'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)
|
||||
{
|
||||
/* encoded steam is 4 bytes for every three, rounded up */
|
||||
return ((len + 2)/3) << 2;
|
||||
}
|
||||
|
||||
static char *base64_encode(xmpp_ctx_t *ctx,
|
||||
const unsigned char * const buffer, const size_t len)
|
||||
{
|
||||
size_t clen;
|
||||
char *cbuf, *c;
|
||||
uint32_t word, hextet;
|
||||
size_t i;
|
||||
|
||||
clen = base64_encoded_len(len);
|
||||
cbuf = xmpp_alloc(ctx, clen + 1);
|
||||
if (cbuf != NULL) {
|
||||
c = cbuf;
|
||||
/* loop over data, turning every 3 bytes into 4 characters */
|
||||
for (i = 0; i + 2 < len; i += 3) {
|
||||
word = buffer[i] << 16 | buffer[i+1] << 8 | buffer[i+2];
|
||||
hextet = (word & 0x00FC0000) >> 18;
|
||||
*c++ = _base64_charmap[hextet];
|
||||
hextet = (word & 0x0003F000) >> 12;
|
||||
*c++ = _base64_charmap[hextet];
|
||||
hextet = (word & 0x00000FC0) >> 6;
|
||||
*c++ = _base64_charmap[hextet];
|
||||
hextet = (word & 0x000003F);
|
||||
*c++ = _base64_charmap[hextet];
|
||||
}
|
||||
/* zero, one or two bytes left */
|
||||
switch (len - i) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
hextet = (buffer[len-1] & 0xFC) >> 2;
|
||||
*c++ = _base64_charmap[hextet];
|
||||
hextet = (buffer[len-1] & 0x03) << 4;
|
||||
*c++ = _base64_charmap[hextet];
|
||||
*c++ = _base64_charmap[64]; /* pad */
|
||||
*c++ = _base64_charmap[64]; /* pad */
|
||||
break;
|
||||
case 2:
|
||||
hextet = (buffer[len-2] & 0xFC) >> 2;
|
||||
*c++ = _base64_charmap[hextet];
|
||||
hextet = ((buffer[len-2] & 0x03) << 4) |
|
||||
((buffer[len-1] & 0xF0) >> 4);
|
||||
*c++ = _base64_charmap[hextet];
|
||||
hextet = (buffer[len-1] & 0x0F) << 2;
|
||||
*c++ = _base64_charmap[hextet];
|
||||
*c++ = _base64_charmap[64]; /* pad */
|
||||
break;
|
||||
}
|
||||
/* add a terminal null */
|
||||
*c = '\0';
|
||||
}
|
||||
return cbuf;
|
||||
}
|
||||
|
||||
static size_t base64_decoded_len(const char * const buffer, const size_t len)
|
||||
{
|
||||
size_t nudge = 0;
|
||||
unsigned char c;
|
||||
size_t i;
|
||||
|
||||
if (len < 4) return 0;
|
||||
|
||||
/* count the padding characters for the remainder */
|
||||
for (i = len; i > 0; --i) {
|
||||
c = _base64_invcharmap[(unsigned char)buffer[i-1]];
|
||||
if (c < 64) break;
|
||||
if (c == 64) ++nudge;
|
||||
if (c > 64) return 0;
|
||||
}
|
||||
if (nudge > 2) return 0;
|
||||
|
||||
/* decoded steam is 3 bytes for every four */
|
||||
return 3 * (len >> 2) - nudge;
|
||||
}
|
||||
|
||||
static void base64_decode(xmpp_ctx_t *ctx,
|
||||
const char * const buffer, const size_t len,
|
||||
unsigned char **out, size_t *outlen)
|
||||
{
|
||||
size_t dlen;
|
||||
unsigned char *dbuf, *d;
|
||||
uint32_t word, hextet = 0;
|
||||
size_t i;
|
||||
|
||||
/* len must be a multiple of 4 */
|
||||
if (len & 0x03) goto _base64_error;
|
||||
|
||||
dlen = base64_decoded_len(buffer, len);
|
||||
if (dlen == 0) goto _base64_error;
|
||||
|
||||
dbuf = xmpp_alloc(ctx, dlen + 1);
|
||||
if (dbuf != NULL) {
|
||||
d = dbuf;
|
||||
/* loop over each set of 4 characters, decoding 3 bytes */
|
||||
for (i = 0; i + 3 < len; i += 4) {
|
||||
hextet = _base64_invcharmap[(unsigned char)buffer[i]];
|
||||
if (hextet & 0xC0) break;
|
||||
word = hextet << 18;
|
||||
hextet = _base64_invcharmap[(unsigned char)buffer[i+1]];
|
||||
if (hextet & 0xC0) break;
|
||||
word |= hextet << 12;
|
||||
hextet = _base64_invcharmap[(unsigned char)buffer[i+2]];
|
||||
if (hextet & 0xC0) break;
|
||||
word |= hextet << 6;
|
||||
hextet = _base64_invcharmap[(unsigned char)buffer[i+3]];
|
||||
if (hextet & 0xC0) break;
|
||||
word |= hextet;
|
||||
*d++ = (word & 0x00FF0000) >> 16;
|
||||
*d++ = (word & 0x0000FF00) >> 8;
|
||||
*d++ = (word & 0x000000FF);
|
||||
}
|
||||
if (hextet > 64) goto _base64_decode_error;
|
||||
/* handle the remainder */
|
||||
switch (dlen % 3) {
|
||||
case 0:
|
||||
/* nothing to do */
|
||||
break;
|
||||
case 1:
|
||||
/* redo the last quartet, checking for correctness */
|
||||
hextet = _base64_invcharmap[(unsigned char)buffer[len-4]];
|
||||
if (hextet & 0xC0) goto _base64_decode_error;
|
||||
word = hextet << 2;
|
||||
hextet = _base64_invcharmap[(unsigned char)buffer[len-3]];
|
||||
if (hextet & 0xC0) goto _base64_decode_error;
|
||||
word |= hextet >> 4;
|
||||
*d++ = word & 0xFF;
|
||||
hextet = _base64_invcharmap[(unsigned char)buffer[len-2]];
|
||||
if (hextet != 64) goto _base64_decode_error;
|
||||
hextet = _base64_invcharmap[(unsigned char)buffer[len-1]];
|
||||
if (hextet != 64) goto _base64_decode_error;
|
||||
break;
|
||||
case 2:
|
||||
/* redo the last quartet, checking for correctness */
|
||||
hextet = _base64_invcharmap[(unsigned char)buffer[len-4]];
|
||||
if (hextet & 0xC0) goto _base64_decode_error;
|
||||
word = hextet << 10;
|
||||
hextet = _base64_invcharmap[(unsigned char)buffer[len-3]];
|
||||
if (hextet & 0xC0) goto _base64_decode_error;
|
||||
word |= hextet << 4;
|
||||
hextet = _base64_invcharmap[(unsigned char)buffer[len-2]];
|
||||
if (hextet & 0xC0) goto _base64_decode_error;
|
||||
word |= hextet >> 2;
|
||||
*d++ = (word & 0xFF00) >> 8;
|
||||
*d++ = (word & 0x00FF);
|
||||
hextet = _base64_invcharmap[(unsigned char)buffer[len-1]];
|
||||
if (hextet != 64) goto _base64_decode_error;
|
||||
break;
|
||||
}
|
||||
*d = '\0';
|
||||
}
|
||||
*out = dbuf;
|
||||
*outlen = dbuf == NULL ? 0 : dlen;
|
||||
return;
|
||||
|
||||
_base64_decode_error:
|
||||
/* invalid character; abort decoding! */
|
||||
xmpp_free(ctx, dbuf);
|
||||
_base64_error:
|
||||
*out = NULL;
|
||||
*outlen = 0;
|
||||
}
|
||||
|
||||
/** Base64 encoding routine
|
||||
* Returns an allocated string which must be freed with xmpp_free().
|
||||
*
|
||||
* @param ctx a Strophe context
|
||||
* @param data buffer to encode
|
||||
* @param len size of the data buffer
|
||||
*
|
||||
* @return an allocated null-terminated string or NULL on error
|
||||
*
|
||||
* @ingroup Encodings
|
||||
*/
|
||||
char *xmpp_base64_encode(xmpp_ctx_t *ctx, const unsigned char *data, size_t len)
|
||||
{
|
||||
return base64_encode(ctx, data, len);
|
||||
}
|
||||
|
||||
/** Base64 decoding routine
|
||||
* 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
|
||||
* contains '\0' NULL is returned.
|
||||
*
|
||||
* @param ctx a Strophe context
|
||||
* @param base64 encoded buffer
|
||||
* @param len size of the buffer
|
||||
*
|
||||
* @return an allocated null-terminated string or NULL on error
|
||||
*
|
||||
* @ingroup Encodings
|
||||
*/
|
||||
char *xmpp_base64_decode_str(xmpp_ctx_t *ctx, const char *base64, size_t len)
|
||||
{
|
||||
unsigned char *buf = NULL;
|
||||
size_t buflen;
|
||||
|
||||
if (len == 0) {
|
||||
/* handle empty string */
|
||||
buf = xmpp_alloc(ctx, 1);
|
||||
if (buf)
|
||||
buf[0] = '\0';
|
||||
buflen = 0;
|
||||
} else {
|
||||
base64_decode(ctx, base64, len, &buf, &buflen);
|
||||
}
|
||||
if (buf) {
|
||||
if (buflen != strlen((char *)buf)) {
|
||||
xmpp_free(ctx, buf);
|
||||
buf = NULL;
|
||||
}
|
||||
}
|
||||
return (char *)buf;
|
||||
}
|
||||
|
||||
/** Base64 decoding routine
|
||||
* Returns an allocated buffer which must be freed with xmpp_free().
|
||||
*
|
||||
* @param ctx a Strophe context
|
||||
* @param base64 encoded buffer
|
||||
* @param len size of the encoded buffer
|
||||
* @param out allocated buffer is stored here
|
||||
* @param outlen size of the allocated buffer
|
||||
*
|
||||
* @note on an error the `*out` will be NULL
|
||||
*
|
||||
* @ingroup Encodings
|
||||
*/
|
||||
void xmpp_base64_decode_bin(xmpp_ctx_t *ctx, const char *base64, size_t len,
|
||||
unsigned char **out, size_t *outlen)
|
||||
{
|
||||
base64_decode(ctx, base64, len, out, outlen);
|
||||
}
|
||||
142
src/ctx.c
142
src/ctx.c
@@ -1,9 +1,9 @@
|
||||
/* ctx.c
|
||||
** strophe XMPP client library -- run-time context implementation
|
||||
**
|
||||
** Copyright (C) 2005-2009 Collecta, Inc.
|
||||
** Copyright (C) 2005-2009 Collecta, Inc.
|
||||
**
|
||||
** This software is provided AS-IS with no warranty, either express
|
||||
** This software is provided AS-IS with no warranty, either express
|
||||
** or implied.
|
||||
**
|
||||
** This program is dual licensed under the MIT and GPLv3 licenses.
|
||||
@@ -36,7 +36,7 @@
|
||||
* result in strange (and platform dependent) behavior.
|
||||
*
|
||||
* Specifically, the socket library on Win32 platforms must be initialized
|
||||
* before use (although this is not the case on POSIX systems). The TLS
|
||||
* before use (although this is not the case on POSIX systems). The TLS
|
||||
* subsystem must also seed the random number generator.
|
||||
*/
|
||||
|
||||
@@ -49,6 +49,11 @@
|
||||
#include "common.h"
|
||||
#include "util.h"
|
||||
|
||||
/* Workaround for visual studio without va_copy support. */
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1800
|
||||
#define va_copy(d,s) ((d) = (s))
|
||||
#endif
|
||||
|
||||
/** Initialize the Strophe library.
|
||||
* This function initializes subcomponents of the Strophe library and must
|
||||
* be called for Strophe to operate correctly.
|
||||
@@ -86,6 +91,14 @@ void xmpp_shutdown(void)
|
||||
#define LIBXMPP_VERSION_MINOR (0)
|
||||
#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.
|
||||
*
|
||||
* @param major the major version number
|
||||
@@ -98,12 +111,12 @@ void xmpp_shutdown(void)
|
||||
int xmpp_version_check(int major, int minor)
|
||||
{
|
||||
return (major == LIBXMPP_VERSION_MAJOR) &&
|
||||
(minor >= LIBXMPP_VERSION_MINOR);
|
||||
(minor >= LIBXMPP_VERSION_MINOR);
|
||||
}
|
||||
|
||||
/* We define the global default allocator, logger, and context here. */
|
||||
|
||||
/* Wrap stdlib routines malloc, free, and realloc for default memory
|
||||
/* Wrap stdlib routines malloc, free, and realloc for default memory
|
||||
* management.
|
||||
*/
|
||||
static void *_malloc(const size_t size, void * const userdata)
|
||||
@@ -132,9 +145,9 @@ static xmpp_mem_t xmpp_default_mem = {
|
||||
/* log levels and names */
|
||||
static const char * const _xmpp_log_level_name[4] = {"DEBUG", "INFO", "WARN", "ERROR"};
|
||||
static const xmpp_log_level_t _xmpp_default_logger_levels[] = {XMPP_LEVEL_DEBUG,
|
||||
XMPP_LEVEL_INFO,
|
||||
XMPP_LEVEL_WARN,
|
||||
XMPP_LEVEL_ERROR};
|
||||
XMPP_LEVEL_INFO,
|
||||
XMPP_LEVEL_WARN,
|
||||
XMPP_LEVEL_ERROR};
|
||||
|
||||
/** Log a message.
|
||||
* The default logger writes to stderr.
|
||||
@@ -145,21 +158,21 @@ static const xmpp_log_level_t _xmpp_default_logger_levels[] = {XMPP_LEVEL_DEBUG,
|
||||
* @param area the area the log message is for
|
||||
* @param msg the log message
|
||||
*/
|
||||
void xmpp_default_logger(void * const userdata,
|
||||
const xmpp_log_level_t level,
|
||||
const char * const area,
|
||||
const char * const msg)
|
||||
static void xmpp_default_logger(void * const userdata,
|
||||
const xmpp_log_level_t level,
|
||||
const char * const area,
|
||||
const char * const msg)
|
||||
{
|
||||
xmpp_log_level_t filter_level = * (xmpp_log_level_t*)userdata;
|
||||
if (level >= filter_level)
|
||||
fprintf(stderr, "%s %s %s\n", area, _xmpp_log_level_name[level], msg);
|
||||
fprintf(stderr, "%s %s %s\n", area, _xmpp_log_level_name[level], msg);
|
||||
}
|
||||
|
||||
static const xmpp_log_t _xmpp_default_loggers[] = {
|
||||
{&xmpp_default_logger, (void*)&_xmpp_default_logger_levels[XMPP_LEVEL_DEBUG]},
|
||||
{&xmpp_default_logger, (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]}
|
||||
{&xmpp_default_logger, (void*)&_xmpp_default_logger_levels[XMPP_LEVEL_DEBUG]},
|
||||
{&xmpp_default_logger, (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.
|
||||
@@ -177,7 +190,6 @@ xmpp_log_t *xmpp_get_default_logger(xmpp_log_level_t level)
|
||||
{
|
||||
/* clamp to the known range */
|
||||
if (level > XMPP_LEVEL_ERROR) level = XMPP_LEVEL_ERROR;
|
||||
if (level < XMPP_LEVEL_DEBUG) level = XMPP_LEVEL_DEBUG;
|
||||
|
||||
return (xmpp_log_t*)&_xmpp_default_loggers[level];
|
||||
}
|
||||
@@ -187,7 +199,7 @@ static xmpp_log_t xmpp_default_log = { NULL, NULL };
|
||||
/* convenience functions for accessing the context */
|
||||
|
||||
/** Allocate memory in a Strophe context.
|
||||
* All Strophe functions will use this to allocate memory.
|
||||
* All Strophe functions will use this to allocate memory.
|
||||
*
|
||||
* @param ctx a Strophe context object
|
||||
* @param size the number of bytes to allocate
|
||||
@@ -220,7 +232,7 @@ void xmpp_free(const xmpp_ctx_t * const ctx, void *p)
|
||||
* @return a pointer to the reallocated memory or NULL on an error
|
||||
*/
|
||||
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);
|
||||
}
|
||||
@@ -229,7 +241,7 @@ void *xmpp_realloc(const xmpp_ctx_t * const ctx, void *p,
|
||||
* Write a log message to the logger for the context for the specified
|
||||
* level and area. This function takes a printf-style format string and a
|
||||
* variable argument list (in va_list) format. This function is not meant
|
||||
* to be called directly, but is used via xmpp_error, xmpp_warn, xmpp_info,
|
||||
* to be called directly, but is used via xmpp_error, xmpp_warn, xmpp_info,
|
||||
* and xmpp_debug.
|
||||
*
|
||||
* @param ctx a Strophe context object
|
||||
@@ -239,10 +251,10 @@ void *xmpp_realloc(const xmpp_ctx_t * const ctx, void *p,
|
||||
* @param ap variable argument list supplied for the format string
|
||||
*/
|
||||
void xmpp_log(const xmpp_ctx_t * const ctx,
|
||||
const xmpp_log_level_t level,
|
||||
const char * const area,
|
||||
const char * const fmt,
|
||||
va_list ap)
|
||||
const xmpp_log_level_t level,
|
||||
const char * const area,
|
||||
const char * const fmt,
|
||||
va_list ap)
|
||||
{
|
||||
int oldret, ret;
|
||||
char smbuf[1024];
|
||||
@@ -252,23 +264,23 @@ void xmpp_log(const xmpp_ctx_t * const ctx,
|
||||
va_copy(copy, ap);
|
||||
ret = xmpp_vsnprintf(smbuf, sizeof(smbuf), fmt, ap);
|
||||
if (ret >= (int)sizeof(smbuf)) {
|
||||
buf = (char *)xmpp_alloc(ctx, ret + 1);
|
||||
if (!buf) {
|
||||
buf = NULL;
|
||||
xmpp_error(ctx, "log", "Failed allocating memory for log message.");
|
||||
va_end(copy);
|
||||
return;
|
||||
}
|
||||
oldret = ret;
|
||||
ret = xmpp_vsnprintf(buf, ret + 1, fmt, copy);
|
||||
if (ret > oldret) {
|
||||
xmpp_error(ctx, "log", "Unexpected error");
|
||||
xmpp_free(ctx, buf);
|
||||
va_end(copy);
|
||||
return;
|
||||
}
|
||||
buf = (char *)xmpp_alloc(ctx, ret + 1);
|
||||
if (!buf) {
|
||||
buf = NULL;
|
||||
xmpp_error(ctx, "log", "Failed allocating memory for log message.");
|
||||
va_end(copy);
|
||||
return;
|
||||
}
|
||||
oldret = ret;
|
||||
ret = xmpp_vsnprintf(buf, ret + 1, fmt, copy);
|
||||
if (ret > oldret) {
|
||||
xmpp_error(ctx, "log", "Unexpected error");
|
||||
xmpp_free(ctx, buf);
|
||||
va_end(copy);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
buf = smbuf;
|
||||
buf = smbuf;
|
||||
}
|
||||
va_end(copy);
|
||||
|
||||
@@ -281,7 +293,7 @@ void xmpp_log(const xmpp_ctx_t * const ctx,
|
||||
|
||||
/** Write to the log at the ERROR level.
|
||||
* This is a convenience function for writing to the log at the
|
||||
* ERROR level. It takes a printf-style format string followed by a
|
||||
* ERROR level. It takes a printf-style format string followed by a
|
||||
* variable list of arguments for formatting.
|
||||
*
|
||||
* @param ctx a Strophe context object
|
||||
@@ -381,29 +393,35 @@ void xmpp_debug(const xmpp_ctx_t * const ctx,
|
||||
*
|
||||
* @ingroup Context
|
||||
*/
|
||||
xmpp_ctx_t *xmpp_ctx_new(const xmpp_mem_t * const mem,
|
||||
const xmpp_log_t * const log)
|
||||
xmpp_ctx_t *xmpp_ctx_new(const xmpp_mem_t * const mem,
|
||||
const xmpp_log_t * const log)
|
||||
{
|
||||
xmpp_ctx_t *ctx = NULL;
|
||||
|
||||
if (mem == NULL)
|
||||
ctx = xmpp_default_mem.alloc(sizeof(xmpp_ctx_t), NULL);
|
||||
ctx = xmpp_default_mem.alloc(sizeof(xmpp_ctx_t), NULL);
|
||||
else
|
||||
ctx = mem->alloc(sizeof(xmpp_ctx_t), mem->userdata);
|
||||
ctx = mem->alloc(sizeof(xmpp_ctx_t), mem->userdata);
|
||||
|
||||
if (ctx != NULL) {
|
||||
if (mem != NULL)
|
||||
ctx->mem = mem;
|
||||
else
|
||||
ctx->mem = &xmpp_default_mem;
|
||||
if (mem != NULL)
|
||||
ctx->mem = mem;
|
||||
else
|
||||
ctx->mem = &xmpp_default_mem;
|
||||
|
||||
if (log == NULL)
|
||||
ctx->log = &xmpp_default_log;
|
||||
else
|
||||
ctx->log = log;
|
||||
if (log == NULL)
|
||||
ctx->log = &xmpp_default_log;
|
||||
else
|
||||
ctx->log = log;
|
||||
|
||||
ctx->connlist = NULL;
|
||||
ctx->loop_status = XMPP_LOOP_NOTSTARTED;
|
||||
ctx->connlist = NULL;
|
||||
ctx->loop_status = XMPP_LOOP_NOTSTARTED;
|
||||
ctx->rand = xmpp_rand_new(ctx);
|
||||
ctx->timeout = EVENT_LOOP_DEFAULT_TIMEOUT;
|
||||
if (ctx->rand == NULL) {
|
||||
xmpp_free(ctx, ctx);
|
||||
ctx = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return ctx;
|
||||
@@ -418,6 +436,18 @@ xmpp_ctx_t *xmpp_ctx_new(const xmpp_mem_t * const mem,
|
||||
void xmpp_ctx_free(xmpp_ctx_t * const ctx)
|
||||
{
|
||||
/* mem and log are owned by their suppliers */
|
||||
xmpp_rand_free(ctx, ctx->rand);
|
||||
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;
|
||||
}
|
||||
|
||||
351
src/event.c
351
src/event.c
@@ -14,15 +14,15 @@
|
||||
*/
|
||||
|
||||
/** @defgroup EventLoop Event loop
|
||||
* These functions manage the Strophe event loop.
|
||||
*
|
||||
* These functions manage the Strophe event loop.
|
||||
*
|
||||
* Simple tools can use xmpp_run() and xmpp_stop() to manage the life
|
||||
* cycle of the program. A common idiom is to set up a few initial
|
||||
* event handers, call xmpp_run(), and then respond and react to
|
||||
* events as they come in. At some point, one of the handlers will
|
||||
* call xmpp_stop() to quit the event loop which leads to the program
|
||||
* terminating.
|
||||
*
|
||||
*
|
||||
* More complex programs will have their own event loops, and should
|
||||
* ensure that xmpp_run_once() is called regularly from there. For
|
||||
* example, a GUI program will already include an event loop to
|
||||
@@ -38,7 +38,7 @@
|
||||
#include <sys/select.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#define _sleep(x) usleep(x*1000)
|
||||
#define _sleep(x) usleep((x) * 1000)
|
||||
#else
|
||||
#include <winsock2.h>
|
||||
#define ETIMEDOUT WSAETIMEDOUT
|
||||
@@ -51,14 +51,6 @@
|
||||
#include "common.h"
|
||||
#include "parser.h"
|
||||
|
||||
#ifndef DEFAULT_TIMEOUT
|
||||
/** @def DEFAULT_TIMEOUT
|
||||
* 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.
|
||||
* This function will run send any data that has been queued by
|
||||
* xmpp_send and related functions and run through the Strophe even
|
||||
@@ -84,147 +76,134 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
|
||||
int towrite;
|
||||
char buf[4096];
|
||||
uint64_t next;
|
||||
long usec;
|
||||
uint64_t usec;
|
||||
int tls_read_bytes = 0;
|
||||
|
||||
if (ctx->loop_status == XMPP_LOOP_QUIT) return;
|
||||
ctx->loop_status = XMPP_LOOP_RUNNING;
|
||||
|
||||
/* send queued data */
|
||||
connitem = ctx->connlist;
|
||||
while (connitem) {
|
||||
conn = connitem->conn;
|
||||
if (conn->state != XMPP_STATE_CONNECTED) {
|
||||
connitem = connitem->next;
|
||||
continue;
|
||||
}
|
||||
conn = connitem->conn;
|
||||
if (conn->state != XMPP_STATE_CONNECTED) {
|
||||
connitem = connitem->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* if we're running tls, there may be some remaining data waiting to
|
||||
* be sent, so push that out */
|
||||
if (conn->tls) {
|
||||
ret = tls_clear_pending_write(conn->tls);
|
||||
/* if we're running tls, there may be some remaining data waiting to
|
||||
* be sent, so push that out */
|
||||
if (conn->tls) {
|
||||
ret = tls_clear_pending_write(conn->tls);
|
||||
|
||||
if (ret < 0 && !tls_is_recoverable(tls_error(conn->tls))) {
|
||||
/* an error occured */
|
||||
xmpp_debug(ctx, "xmpp", "Send error occured, disconnecting.");
|
||||
conn->error = ECONNABORTED;
|
||||
conn_disconnect(conn);
|
||||
}
|
||||
}
|
||||
if (ret < 0 && !tls_is_recoverable(tls_error(conn->tls))) {
|
||||
/* an error occurred */
|
||||
xmpp_debug(ctx, "xmpp", "Send error occurred, disconnecting.");
|
||||
conn->error = ECONNABORTED;
|
||||
conn_disconnect(conn);
|
||||
}
|
||||
}
|
||||
|
||||
/* write all data from the send queue to the socket */
|
||||
sq = conn->send_queue_head;
|
||||
while (sq) {
|
||||
towrite = sq->len - sq->written;
|
||||
/* write all data from the send queue to the socket */
|
||||
sq = conn->send_queue_head;
|
||||
while (sq) {
|
||||
towrite = sq->len - sq->written;
|
||||
|
||||
if (conn->tls) {
|
||||
ret = tls_write(conn->tls, &sq->data[sq->written], towrite);
|
||||
if (conn->tls) {
|
||||
ret = tls_write(conn->tls, &sq->data[sq->written], towrite);
|
||||
if (ret < 0 && !tls_is_recoverable(tls_error(conn->tls)))
|
||||
conn->error = tls_error(conn->tls);
|
||||
} else {
|
||||
ret = sock_write(conn->sock, &sq->data[sq->written], towrite);
|
||||
if (ret < 0 && !sock_is_recoverable(sock_error()))
|
||||
conn->error = sock_error();
|
||||
}
|
||||
if (ret > 0 && ret < towrite)
|
||||
sq->written += ret; /* not all data could be sent now */
|
||||
if (ret != towrite)
|
||||
break; /* partial write or an error */
|
||||
|
||||
if (ret < 0 && !tls_is_recoverable(tls_error(conn->tls))) {
|
||||
/* 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;
|
||||
}
|
||||
/* all data for this queue item written, delete and move on */
|
||||
xmpp_free(ctx, sq->data);
|
||||
tsq = sq;
|
||||
sq = sq->next;
|
||||
conn->send_queue_len--;
|
||||
xmpp_free(ctx, tsq);
|
||||
|
||||
} else {
|
||||
ret = sock_write(conn->sock, &sq->data[sq->written], towrite);
|
||||
/* pop the top item */
|
||||
conn->send_queue_head = sq;
|
||||
/* if we've sent everything update the tail */
|
||||
if (!sq) conn->send_queue_tail = NULL;
|
||||
}
|
||||
|
||||
if (ret < 0 && !sock_is_recoverable(sock_error())) {
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
/* tear down connection on error */
|
||||
if (conn->error) {
|
||||
/* FIXME: need to tear down send queues and random other things
|
||||
* maybe this should be abstracted */
|
||||
xmpp_debug(ctx, "xmpp", "Send error occurred, disconnecting.");
|
||||
conn->error = ECONNABORTED;
|
||||
conn_disconnect(conn);
|
||||
}
|
||||
|
||||
/* all data for this queue item written, delete and move on */
|
||||
xmpp_free(ctx, sq->data);
|
||||
tsq = sq;
|
||||
sq = sq->next;
|
||||
xmpp_free(ctx, tsq);
|
||||
|
||||
/* pop the top item */
|
||||
conn->send_queue_head = sq;
|
||||
/* if we've sent everything update the tail */
|
||||
if (!sq) conn->send_queue_tail = NULL;
|
||||
}
|
||||
|
||||
/* tear down connection on error */
|
||||
if (conn->error) {
|
||||
/* FIXME: need to tear down send queues and random other things
|
||||
* maybe this should be abstracted */
|
||||
xmpp_debug(ctx, "xmpp", "Send error occured, disconnecting.");
|
||||
conn->error = ECONNABORTED;
|
||||
conn_disconnect(conn);
|
||||
}
|
||||
|
||||
connitem = connitem->next;
|
||||
connitem = connitem->next;
|
||||
}
|
||||
|
||||
/* reset parsers if needed */
|
||||
for (connitem = ctx->connlist; connitem; connitem = connitem->next) {
|
||||
if (connitem->conn->reset_parser)
|
||||
conn_parser_reset(connitem->conn);
|
||||
if (connitem->conn->reset_parser)
|
||||
conn_parser_reset(connitem->conn);
|
||||
}
|
||||
|
||||
|
||||
/* fire any ready timed handlers, then
|
||||
make sure we don't wait past the time when timed handlers need
|
||||
to be called */
|
||||
/* fire any ready timed handlers, then make sure we don't wait past
|
||||
the time when timed handlers need to be called */
|
||||
next = handler_fire_timed(ctx);
|
||||
|
||||
usec = ((next < timeout) ? next : timeout) * 1000;
|
||||
tv.tv_sec = usec / 1000000;
|
||||
tv.tv_usec = usec % 1000000;
|
||||
tv.tv_sec = (long)(usec / 1000000);
|
||||
tv.tv_usec = (long)(usec % 1000000);
|
||||
|
||||
FD_ZERO(&rfds);
|
||||
FD_ZERO(&rfds);
|
||||
FD_ZERO(&wfds);
|
||||
|
||||
/* find events to watch */
|
||||
connitem = ctx->connlist;
|
||||
while (connitem) {
|
||||
conn = connitem->conn;
|
||||
|
||||
switch (conn->state) {
|
||||
case XMPP_STATE_CONNECTING:
|
||||
/* connect has been called and we're waiting for it to complete */
|
||||
/* connection will give us write or error events */
|
||||
|
||||
/* make sure the timeout hasn't expired */
|
||||
if (time_elapsed(conn->timeout_stamp, time_stamp()) <=
|
||||
conn->connect_timeout)
|
||||
FD_SET(conn->sock, &wfds);
|
||||
else {
|
||||
conn->error = ETIMEDOUT;
|
||||
xmpp_info(ctx, "xmpp", "Connection attempt timed out.");
|
||||
conn_disconnect(conn);
|
||||
}
|
||||
break;
|
||||
case XMPP_STATE_CONNECTED:
|
||||
FD_SET(conn->sock, &rfds);
|
||||
break;
|
||||
case XMPP_STATE_DISCONNECTED:
|
||||
/* do nothing */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Check if there is something in the SSL buffer. */
|
||||
if (conn->tls) {
|
||||
tls_read_bytes += tls_pending(conn->tls);
|
||||
}
|
||||
|
||||
if (conn->state != XMPP_STATE_DISCONNECTED && conn->sock > max)
|
||||
max = conn->sock;
|
||||
conn = connitem->conn;
|
||||
|
||||
connitem = connitem->next;
|
||||
switch (conn->state) {
|
||||
case XMPP_STATE_CONNECTING:
|
||||
/* connect has been called and we're waiting for it to complete */
|
||||
/* connection will give us write or error events */
|
||||
|
||||
/* make sure the timeout hasn't expired */
|
||||
if (time_elapsed(conn->timeout_stamp, time_stamp()) <=
|
||||
conn->connect_timeout)
|
||||
FD_SET(conn->sock, &wfds);
|
||||
else {
|
||||
conn->error = ETIMEDOUT;
|
||||
xmpp_info(ctx, "xmpp", "Connection attempt timed out.");
|
||||
conn_disconnect(conn);
|
||||
}
|
||||
break;
|
||||
case XMPP_STATE_CONNECTED:
|
||||
FD_SET(conn->sock, &rfds);
|
||||
if (conn->send_queue_len > 0)
|
||||
FD_SET(conn->sock, &wfds);
|
||||
break;
|
||||
case XMPP_STATE_DISCONNECTED:
|
||||
/* do nothing */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Check if there is something in the SSL buffer. */
|
||||
if (conn->tls)
|
||||
tls_read_bytes += tls_pending(conn->tls);
|
||||
|
||||
if (conn->state != XMPP_STATE_DISCONNECTED && conn->sock > max)
|
||||
max = conn->sock;
|
||||
|
||||
connitem = connitem->next;
|
||||
}
|
||||
|
||||
/* check for events */
|
||||
@@ -238,83 +217,80 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
|
||||
|
||||
/* select errored */
|
||||
if (ret < 0) {
|
||||
if (!sock_is_recoverable(sock_error()))
|
||||
xmpp_error(ctx, "xmpp", "event watcher internal error %d",
|
||||
sock_error());
|
||||
return;
|
||||
if (!sock_is_recoverable(sock_error()))
|
||||
xmpp_error(ctx, "xmpp", "event watcher internal error %d",
|
||||
sock_error());
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* no events happened */
|
||||
if (ret == 0 && tls_read_bytes == 0) return;
|
||||
|
||||
/* process events */
|
||||
connitem = ctx->connlist;
|
||||
while (connitem) {
|
||||
conn = connitem->conn;
|
||||
conn = connitem->conn;
|
||||
|
||||
switch (conn->state) {
|
||||
case XMPP_STATE_CONNECTING:
|
||||
if (FD_ISSET(conn->sock, &wfds)) {
|
||||
/* connection complete */
|
||||
switch (conn->state) {
|
||||
case XMPP_STATE_CONNECTING:
|
||||
if (FD_ISSET(conn->sock, &wfds)) {
|
||||
/* connection complete */
|
||||
|
||||
/* check for error */
|
||||
if (sock_connect_error(conn->sock) != 0) {
|
||||
/* connection failed */
|
||||
xmpp_debug(ctx, "xmpp", "connection failed");
|
||||
conn_disconnect(conn);
|
||||
break;
|
||||
}
|
||||
/* check for error */
|
||||
ret = sock_connect_error(conn->sock);
|
||||
if (ret != 0) {
|
||||
/* connection failed */
|
||||
xmpp_debug(ctx, "xmpp", "connection failed, error %d", ret);
|
||||
conn_disconnect(conn);
|
||||
break;
|
||||
}
|
||||
|
||||
conn->state = XMPP_STATE_CONNECTED;
|
||||
xmpp_debug(ctx, "xmpp", "connection successful");
|
||||
conn->state = XMPP_STATE_CONNECTED;
|
||||
xmpp_debug(ctx, "xmpp", "connection successful");
|
||||
conn_established(conn);
|
||||
}
|
||||
|
||||
|
||||
/* send stream init */
|
||||
conn_open_stream(conn);
|
||||
}
|
||||
break;
|
||||
case XMPP_STATE_CONNECTED:
|
||||
if (FD_ISSET(conn->sock, &rfds) || (conn->tls && tls_pending(conn->tls))) {
|
||||
if (conn->tls) {
|
||||
ret = tls_read(conn->tls, buf, 4096);
|
||||
} else {
|
||||
ret = sock_read(conn->sock, buf, 4096);
|
||||
}
|
||||
|
||||
break;
|
||||
case XMPP_STATE_CONNECTED:
|
||||
if (FD_ISSET(conn->sock, &rfds) || (conn->tls && tls_pending(conn->tls))) {
|
||||
if (conn->tls) {
|
||||
ret = tls_read(conn->tls, buf, 4096);
|
||||
} else {
|
||||
ret = sock_read(conn->sock, buf, 4096);
|
||||
}
|
||||
if (ret > 0) {
|
||||
ret = parser_feed(conn->parser, buf, ret);
|
||||
if (!ret) {
|
||||
/* parse error, we need to shut down */
|
||||
/* FIXME */
|
||||
xmpp_debug(ctx, "xmpp", "parse error, disconnecting");
|
||||
conn_disconnect(conn);
|
||||
}
|
||||
} else {
|
||||
if (conn->tls) {
|
||||
if (!tls_is_recoverable(tls_error(conn->tls))) {
|
||||
xmpp_debug(ctx, "xmpp", "Unrecoverable TLS error, %d.", tls_error(conn->tls));
|
||||
conn->error = tls_error(conn->tls);
|
||||
conn_disconnect(conn);
|
||||
}
|
||||
} else {
|
||||
/* return of 0 means socket closed by server */
|
||||
xmpp_debug(ctx, "xmpp", "Socket closed by remote host.");
|
||||
conn->error = ECONNRESET;
|
||||
conn_disconnect(conn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ret > 0) {
|
||||
ret = parser_feed(conn->parser, buf, ret);
|
||||
if (!ret) {
|
||||
/* parse error, we need to shut down */
|
||||
/* FIXME */
|
||||
xmpp_debug(ctx, "xmpp", "parse error, disconnecting");
|
||||
conn_disconnect(conn);
|
||||
}
|
||||
} else {
|
||||
if (conn->tls) {
|
||||
if (!tls_is_recoverable(tls_error(conn->tls)))
|
||||
{
|
||||
xmpp_debug(ctx, "xmpp", "Unrecoverable TLS error, %d.", tls_error(conn->tls));
|
||||
conn->error = tls_error(conn->tls);
|
||||
conn_disconnect(conn);
|
||||
}
|
||||
} else {
|
||||
/* return of 0 means socket closed by server */
|
||||
xmpp_debug(ctx, "xmpp", "Socket closed by remote host.");
|
||||
conn->error = ECONNRESET;
|
||||
conn_disconnect(conn);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case XMPP_STATE_DISCONNECTED:
|
||||
/* do nothing */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
case XMPP_STATE_DISCONNECTED:
|
||||
/* do nothing */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
connitem = connitem->next;
|
||||
connitem = connitem->next;
|
||||
}
|
||||
|
||||
/* fire any ready handlers */
|
||||
@@ -335,9 +311,12 @@ void xmpp_run(xmpp_ctx_t *ctx)
|
||||
|
||||
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 */
|
||||
ctx->loop_status = XMPP_LOOP_NOTSTARTED;
|
||||
|
||||
xmpp_debug(ctx, "event", "Event loop completed.");
|
||||
}
|
||||
|
||||
@@ -354,5 +333,5 @@ void xmpp_stop(xmpp_ctx_t *ctx)
|
||||
xmpp_debug(ctx, "event", "Stopping event loop.");
|
||||
|
||||
if (ctx->loop_status == XMPP_LOOP_RUNNING)
|
||||
ctx->loop_status = XMPP_LOOP_QUIT;
|
||||
ctx->loop_status = XMPP_LOOP_QUIT;
|
||||
}
|
||||
|
||||
569
src/handler.c
569
src/handler.c
@@ -1,7 +1,7 @@
|
||||
/* handler.c
|
||||
** strophe XMPP client library -- event handler management
|
||||
**
|
||||
** Copyright (C) 2005-2009 Collecta, Inc.
|
||||
** Copyright (C) 2005-2009 Collecta, Inc.
|
||||
**
|
||||
** This software is provided AS-IS with no warranty, either express
|
||||
** or implied.
|
||||
@@ -24,6 +24,31 @@
|
||||
#include "common.h"
|
||||
#include "ostypes.h"
|
||||
|
||||
/* Remove item from the list pointed by head, but don't free it.
|
||||
* There can be a situation when user's handler deletes another handler which
|
||||
* is the previous in the list. handler_fire_stanza() and handler_fire_timed()
|
||||
* must handle this situation correctly. Current function helps to avoid
|
||||
* list corruption in described scenario.
|
||||
*
|
||||
* TODO Convert handler lists to double-linked lists. Current implementation
|
||||
* works for O(n).
|
||||
*/
|
||||
static void _handler_item_remove(xmpp_handlist_t **head,
|
||||
xmpp_handlist_t *item)
|
||||
{
|
||||
xmpp_handlist_t *i = *head;
|
||||
|
||||
if (i == item)
|
||||
*head = item->next;
|
||||
else if (i != NULL) {
|
||||
while (i->next != NULL && i->next != item)
|
||||
i = i->next;
|
||||
if (i->next == item) {
|
||||
i->next = item->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Fire off all stanza handlers that match.
|
||||
* This function is called internally by the event loop whenever stanzas
|
||||
* are received from the XMPP server.
|
||||
@@ -32,92 +57,83 @@
|
||||
* @param stanza a Strophe stanza object
|
||||
*/
|
||||
void handler_fire_stanza(xmpp_conn_t * const conn,
|
||||
xmpp_stanza_t * const stanza)
|
||||
xmpp_stanza_t * const stanza)
|
||||
{
|
||||
xmpp_handlist_t *item, *prev;
|
||||
char *id, *ns, *name, *type;
|
||||
|
||||
xmpp_handlist_t *item, *next, *head, *head_old;
|
||||
const char *id, *ns, *name, *type;
|
||||
int ret;
|
||||
|
||||
/* call id handlers */
|
||||
id = xmpp_stanza_get_id(stanza);
|
||||
if (id) {
|
||||
prev = NULL;
|
||||
item = (xmpp_handlist_t *)hash_get(conn->id_handlers, id);
|
||||
while (item) {
|
||||
xmpp_handlist_t *next = item->next;
|
||||
head = (xmpp_handlist_t *)hash_get(conn->id_handlers, id);
|
||||
/* enable all added handlers */
|
||||
for (item = head; item; item = item->next)
|
||||
item->enabled = 1;
|
||||
|
||||
if (item->user_handler && !conn->authenticated) {
|
||||
item = next;
|
||||
continue;
|
||||
}
|
||||
item = head;
|
||||
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;
|
||||
}
|
||||
|
||||
if (!((xmpp_handler)(item->handler))(conn, stanza, item->userdata)) {
|
||||
/* handler is one-shot, so delete it */
|
||||
if (prev)
|
||||
prev->next = next;
|
||||
else {
|
||||
hash_drop(conn->id_handlers, id);
|
||||
hash_add(conn->id_handlers, id, next);
|
||||
}
|
||||
ret = ((xmpp_handler)(item->handler))(conn, stanza, item->userdata);
|
||||
next = item->next;
|
||||
if (!ret) {
|
||||
/* handler is one-shot, so delete it */
|
||||
head_old = head;
|
||||
_handler_item_remove(&head, item);
|
||||
if (head != head_old) {
|
||||
/* replace old value */
|
||||
hash_add(conn->id_handlers, id, head);
|
||||
}
|
||||
xmpp_free(conn->ctx, item->id);
|
||||
xmpp_free(conn->ctx, item);
|
||||
item = NULL;
|
||||
}
|
||||
if (item)
|
||||
prev = item;
|
||||
item = next;
|
||||
}
|
||||
xmpp_free(conn->ctx, item);
|
||||
}
|
||||
item = next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* call handlers */
|
||||
ns = xmpp_stanza_get_ns(stanza);
|
||||
name = xmpp_stanza_get_name(stanza);
|
||||
type = xmpp_stanza_get_type(stanza);
|
||||
|
||||
|
||||
/* enable all added handlers */
|
||||
for (item = conn->handlers; item; item = item->next)
|
||||
item->enabled = 1;
|
||||
item->enabled = 1;
|
||||
|
||||
prev = NULL;
|
||||
item = conn->handlers;
|
||||
while (item) {
|
||||
/* skip newly added handlers */
|
||||
if (!item->enabled) {
|
||||
prev = item;
|
||||
item = item->next;
|
||||
continue;
|
||||
}
|
||||
/* don't fire user handlers until authentication succeeds and
|
||||
skip newly added handlers */
|
||||
if ((item->user_handler && !conn->authenticated) || !item->enabled) {
|
||||
item = item->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* don't call user handlers until authentication succeeds */
|
||||
if (item->user_handler && !conn->authenticated) {
|
||||
prev = item;
|
||||
item = item->next;
|
||||
continue;
|
||||
}
|
||||
next = item->next;
|
||||
if ((!item->ns || (ns && strcmp(ns, item->ns) == 0) ||
|
||||
xmpp_stanza_get_child_by_ns(stanza, item->ns)) &&
|
||||
(!item->name || (name && strcmp(name, item->name) == 0)) &&
|
||||
(!item->type || (type && strcmp(type, item->type) == 0))) {
|
||||
|
||||
if ((!item->ns || (ns && strcmp(ns, item->ns) == 0) ||
|
||||
xmpp_stanza_get_child_by_ns(stanza, item->ns)) &&
|
||||
(!item->name || (name && strcmp(name, item->name) == 0)) &&
|
||||
(!item->type || (type && strcmp(type, item->type) == 0)))
|
||||
if (!((xmpp_handler)(item->handler))(conn, stanza, item->userdata)) {
|
||||
/* handler is one-shot, so delete it */
|
||||
if (prev)
|
||||
prev->next = item->next;
|
||||
else
|
||||
conn->handlers = item->next;
|
||||
ret = ((xmpp_handler)(item->handler))(conn, stanza, item->userdata);
|
||||
/* list may be changed during execution of a handler */
|
||||
next = item->next;
|
||||
if (!ret) {
|
||||
/* handler is one-shot, so delete it */
|
||||
_handler_item_remove(&conn->handlers, item);
|
||||
if (item->ns) xmpp_free(conn->ctx, item->ns);
|
||||
if (item->name) xmpp_free(conn->ctx, item->name);
|
||||
if (item->type) xmpp_free(conn->ctx, item->type);
|
||||
xmpp_free(conn->ctx, item);
|
||||
item = NULL;
|
||||
}
|
||||
|
||||
if (item) {
|
||||
prev = item;
|
||||
item = item->next;
|
||||
} else if (prev)
|
||||
item = prev->next;
|
||||
else
|
||||
item = conn->handlers;
|
||||
xmpp_free(conn->ctx, item);
|
||||
}
|
||||
}
|
||||
item = next;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,57 +147,56 @@ void handler_fire_stanza(xmpp_conn_t * const conn,
|
||||
uint64_t handler_fire_timed(xmpp_ctx_t * const ctx)
|
||||
{
|
||||
xmpp_connlist_t *connitem;
|
||||
xmpp_handlist_t *handitem, *temp;
|
||||
int ret, fired;
|
||||
xmpp_handlist_t *item, *next;
|
||||
xmpp_conn_t *conn;
|
||||
uint64_t elapsed, min;
|
||||
uint64_t timestamp;
|
||||
int ret;
|
||||
|
||||
min = (uint64_t)(-1);
|
||||
|
||||
connitem = ctx->connlist;
|
||||
while (connitem) {
|
||||
if (connitem->conn->state != XMPP_STATE_CONNECTED) {
|
||||
connitem = connitem->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* enable all handlers that were added */
|
||||
for (handitem = connitem->conn->timed_handlers; handitem;
|
||||
handitem = handitem->next)
|
||||
handitem->enabled = 1;
|
||||
conn = connitem->conn;
|
||||
if (conn->state != XMPP_STATE_CONNECTED) {
|
||||
connitem = connitem->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
handitem = connitem->conn->timed_handlers;
|
||||
while (handitem) {
|
||||
/* skip newly added handlers */
|
||||
if (!handitem->enabled) {
|
||||
handitem = handitem->next;
|
||||
continue;
|
||||
}
|
||||
/* enable all handlers that were added */
|
||||
for (item = conn->timed_handlers; item; item = item->next)
|
||||
item->enabled = 1;
|
||||
|
||||
/* only fire user handlers after authentication */
|
||||
if (handitem->user_handler && !connitem->conn->authenticated) {
|
||||
handitem = handitem->next;
|
||||
continue;
|
||||
}
|
||||
item = conn->timed_handlers;
|
||||
while (item) {
|
||||
/* don't fire user handlers until authentication succeeds and
|
||||
skip newly added handlers */
|
||||
if ((item->user_handler && !conn->authenticated) || !item->enabled) {
|
||||
item = item->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
fired = 0;
|
||||
elapsed = time_elapsed(handitem->last_stamp, time_stamp());
|
||||
if (elapsed >= handitem->period) {
|
||||
/* fire! */
|
||||
fired = 1;
|
||||
handitem->last_stamp = time_stamp();
|
||||
ret = ((xmpp_timed_handler)handitem->handler)(connitem->conn, handitem->userdata);
|
||||
} else if (min > (handitem->period - elapsed))
|
||||
min = handitem->period - elapsed;
|
||||
|
||||
temp = handitem;
|
||||
handitem = handitem->next;
|
||||
next = item->next;
|
||||
timestamp = time_stamp();
|
||||
elapsed = time_elapsed(item->last_stamp, timestamp);
|
||||
if (elapsed >= item->period) {
|
||||
/* fire! */
|
||||
item->last_stamp = timestamp;
|
||||
ret = ((xmpp_timed_handler)item->handler)(conn, 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(&conn->timed_handlers, item);
|
||||
xmpp_free(conn->ctx, item);
|
||||
}
|
||||
} else if (min > (item->period - elapsed))
|
||||
min = item->period - elapsed;
|
||||
|
||||
/* delete handler if it returned false */
|
||||
if (fired && !ret)
|
||||
xmpp_timed_handler_delete(connitem->conn, temp->handler);
|
||||
}
|
||||
item = next;
|
||||
}
|
||||
|
||||
connitem = connitem->next;
|
||||
connitem = connitem->next;
|
||||
}
|
||||
|
||||
return min;
|
||||
@@ -199,25 +214,27 @@ void handler_reset_timed(xmpp_conn_t *conn, int user_only)
|
||||
|
||||
handitem = conn->timed_handlers;
|
||||
while (handitem) {
|
||||
if ((user_only && handitem->user_handler) || !user_only)
|
||||
handitem->last_stamp = time_stamp();
|
||||
|
||||
handitem = handitem->next;
|
||||
if ((user_only && handitem->user_handler) || !user_only)
|
||||
handitem->last_stamp = time_stamp();
|
||||
|
||||
handitem = handitem->next;
|
||||
}
|
||||
}
|
||||
|
||||
static void _timed_handler_add(xmpp_conn_t * const conn,
|
||||
xmpp_timed_handler handler,
|
||||
const unsigned long period,
|
||||
void * const userdata,
|
||||
const int user_handler)
|
||||
xmpp_timed_handler handler,
|
||||
const unsigned long period,
|
||||
void * const userdata,
|
||||
const int user_handler)
|
||||
{
|
||||
xmpp_handlist_t *item, *tail;
|
||||
|
||||
/* check if handler is already in the list */
|
||||
for (item = conn->timed_handlers; item; item = item->next) {
|
||||
if (item->handler == (void *)handler)
|
||||
break;
|
||||
if (item->handler == handler && item->userdata == userdata) {
|
||||
xmpp_warn(conn->ctx, "xmpp", "Timed handler already exists.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (item) return;
|
||||
|
||||
@@ -226,7 +243,7 @@ static void _timed_handler_add(xmpp_conn_t * const conn,
|
||||
if (!item) return;
|
||||
|
||||
item->user_handler = user_handler;
|
||||
item->handler = (void *)handler;
|
||||
item->handler = handler;
|
||||
item->userdata = userdata;
|
||||
item->enabled = 0;
|
||||
item->next = NULL;
|
||||
@@ -236,12 +253,12 @@ static void _timed_handler_add(xmpp_conn_t * const conn,
|
||||
|
||||
/* append item to list */
|
||||
if (!conn->timed_handlers)
|
||||
conn->timed_handlers = item;
|
||||
conn->timed_handlers = item;
|
||||
else {
|
||||
tail = conn->timed_handlers;
|
||||
while (tail->next)
|
||||
tail = tail->next;
|
||||
tail->next = item;
|
||||
tail = conn->timed_handlers;
|
||||
while (tail->next)
|
||||
tail = tail->next;
|
||||
tail->next = item;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -253,7 +270,7 @@ static void _timed_handler_add(xmpp_conn_t * const conn,
|
||||
* @ingroup Handlers
|
||||
*/
|
||||
void xmpp_timed_handler_delete(xmpp_conn_t * const conn,
|
||||
xmpp_timed_handler handler)
|
||||
xmpp_timed_handler handler)
|
||||
{
|
||||
xmpp_handlist_t *item, *prev;
|
||||
|
||||
@@ -262,35 +279,36 @@ void xmpp_timed_handler_delete(xmpp_conn_t * const conn,
|
||||
prev = NULL;
|
||||
item = conn->timed_handlers;
|
||||
while (item) {
|
||||
if (item->handler == (void *)handler)
|
||||
break;
|
||||
prev = item;
|
||||
item = item->next;
|
||||
}
|
||||
if (item->handler == handler) {
|
||||
if (prev)
|
||||
prev->next = item->next;
|
||||
else
|
||||
conn->timed_handlers = item->next;
|
||||
|
||||
if (item) {
|
||||
if (prev)
|
||||
prev->next = item->next;
|
||||
else
|
||||
conn->timed_handlers = item->next;
|
||||
|
||||
xmpp_free(conn->ctx, item);
|
||||
xmpp_free(conn->ctx, item);
|
||||
item = prev ? prev->next : conn->timed_handlers;
|
||||
} else {
|
||||
prev = item;
|
||||
item = item->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void _id_handler_add(xmpp_conn_t * const conn,
|
||||
xmpp_handler handler,
|
||||
const char * const id,
|
||||
void * const userdata, int user_handler)
|
||||
xmpp_handler handler,
|
||||
const char * const id,
|
||||
void * const userdata, int user_handler)
|
||||
{
|
||||
xmpp_handlist_t *item, *tail;
|
||||
|
||||
/* check if handler is already in the list */
|
||||
item = (xmpp_handlist_t *)hash_get(conn->id_handlers, id);
|
||||
while (item) {
|
||||
if (item->handler == (void *)handler)
|
||||
break;
|
||||
item = item->next;
|
||||
if (item->handler == handler && item->userdata == userdata) {
|
||||
xmpp_warn(conn->ctx, "xmpp", "Id handler already exists.");
|
||||
break;
|
||||
}
|
||||
item = item->next;
|
||||
}
|
||||
if (item) return;
|
||||
|
||||
@@ -299,25 +317,25 @@ static void _id_handler_add(xmpp_conn_t * const conn,
|
||||
if (!item) return;
|
||||
|
||||
item->user_handler = user_handler;
|
||||
item->handler = (void *)handler;
|
||||
item->handler = handler;
|
||||
item->userdata = userdata;
|
||||
item->enabled = 0;
|
||||
item->next = NULL;
|
||||
|
||||
item->id = xmpp_strdup(conn->ctx, id);
|
||||
if (!item->id) {
|
||||
xmpp_free(conn->ctx, item);
|
||||
return;
|
||||
xmpp_free(conn->ctx, item);
|
||||
return;
|
||||
}
|
||||
|
||||
/* put on list in hash table */
|
||||
tail = (xmpp_handlist_t *)hash_get(conn->id_handlers, id);
|
||||
if (!tail)
|
||||
hash_add(conn->id_handlers, id, item);
|
||||
hash_add(conn->id_handlers, id, item);
|
||||
else {
|
||||
while (tail->next)
|
||||
tail = tail->next;
|
||||
tail->next = item;
|
||||
while (tail->next)
|
||||
tail = tail->next;
|
||||
tail->next = item;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -330,49 +348,54 @@ static void _id_handler_add(xmpp_conn_t * const conn,
|
||||
* @ingroup Handlers
|
||||
*/
|
||||
void xmpp_id_handler_delete(xmpp_conn_t * const conn,
|
||||
xmpp_handler handler,
|
||||
const char * const id)
|
||||
xmpp_handler handler,
|
||||
const char * const id)
|
||||
{
|
||||
xmpp_handlist_t *item, *prev;
|
||||
xmpp_handlist_t *item, *prev, *next;
|
||||
|
||||
prev = NULL;
|
||||
item = (xmpp_handlist_t *)hash_get(conn->id_handlers, id);
|
||||
if (!item) return;
|
||||
|
||||
while (item) {
|
||||
if (item->handler == (void *)handler)
|
||||
break;
|
||||
next = item->next;
|
||||
|
||||
prev = item;
|
||||
item = item->next;
|
||||
}
|
||||
if (item->handler == handler) {
|
||||
if (prev)
|
||||
prev->next = next;
|
||||
else {
|
||||
hash_drop(conn->id_handlers, id);
|
||||
hash_add(conn->id_handlers, id, next);
|
||||
}
|
||||
|
||||
if (item) {
|
||||
if (prev)
|
||||
prev->next = item->next;
|
||||
else {
|
||||
hash_drop(conn->id_handlers, id);
|
||||
hash_add(conn->id_handlers, id, item->next);
|
||||
}
|
||||
xmpp_free(conn->ctx, item->id);
|
||||
xmpp_free(conn->ctx, item);
|
||||
xmpp_free(conn->ctx, item->id);
|
||||
xmpp_free(conn->ctx, item);
|
||||
item = next;
|
||||
} else {
|
||||
prev = item;
|
||||
item = next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* add a stanza handler */
|
||||
static void _handler_add(xmpp_conn_t * const conn,
|
||||
xmpp_handler handler,
|
||||
const char * const ns,
|
||||
const char * const name,
|
||||
const char * const type,
|
||||
void * const userdata, int user_handler)
|
||||
xmpp_handler handler,
|
||||
const char * const ns,
|
||||
const char * const name,
|
||||
const char * const type,
|
||||
void * const userdata, int user_handler)
|
||||
{
|
||||
xmpp_handlist_t *item, *tail;
|
||||
|
||||
/* check if handler already in list */
|
||||
for (item = conn->handlers; item; item = item->next) {
|
||||
if (item->handler == (void *)handler)
|
||||
break;
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
if (item) return;
|
||||
|
||||
@@ -381,46 +404,46 @@ static void _handler_add(xmpp_conn_t * const conn,
|
||||
if (!item) return;
|
||||
|
||||
item->user_handler = user_handler;
|
||||
item->handler = (void *)handler;
|
||||
item->handler = handler;
|
||||
item->userdata = userdata;
|
||||
item->enabled = 0;
|
||||
item->next = NULL;
|
||||
|
||||
|
||||
if (ns) {
|
||||
item->ns = xmpp_strdup(conn->ctx, ns);
|
||||
if (!item->ns) {
|
||||
xmpp_free(conn->ctx, item);
|
||||
return;
|
||||
}
|
||||
item->ns = xmpp_strdup(conn->ctx, ns);
|
||||
if (!item->ns) {
|
||||
xmpp_free(conn->ctx, item);
|
||||
return;
|
||||
}
|
||||
} else
|
||||
item->ns = NULL;
|
||||
item->ns = NULL;
|
||||
if (name) {
|
||||
item->name = xmpp_strdup(conn->ctx, name);
|
||||
if (!item->name) {
|
||||
if (item->ns) xmpp_free(conn->ctx, item->ns);
|
||||
xmpp_free(conn->ctx, item);
|
||||
return;
|
||||
}
|
||||
item->name = xmpp_strdup(conn->ctx, name);
|
||||
if (!item->name) {
|
||||
if (item->ns) xmpp_free(conn->ctx, item->ns);
|
||||
xmpp_free(conn->ctx, item);
|
||||
return;
|
||||
}
|
||||
} else
|
||||
item->name = NULL;
|
||||
item->name = NULL;
|
||||
if (type) {
|
||||
item->type = xmpp_strdup(conn->ctx, type);
|
||||
if (!item->type) {
|
||||
if (item->ns) xmpp_free(conn->ctx, item->ns);
|
||||
if (item->name) xmpp_free(conn->ctx, item->name);
|
||||
xmpp_free(conn->ctx, item);
|
||||
}
|
||||
item->type = xmpp_strdup(conn->ctx, type);
|
||||
if (!item->type) {
|
||||
if (item->ns) xmpp_free(conn->ctx, item->ns);
|
||||
if (item->name) xmpp_free(conn->ctx, item->name);
|
||||
xmpp_free(conn->ctx, item);
|
||||
}
|
||||
} else
|
||||
item->type = NULL;
|
||||
item->type = NULL;
|
||||
|
||||
/* append to list */
|
||||
if (!conn->handlers)
|
||||
conn->handlers = item;
|
||||
conn->handlers = item;
|
||||
else {
|
||||
tail = conn->handlers;
|
||||
while (tail->next)
|
||||
tail = tail->next;
|
||||
tail->next = item;
|
||||
tail = conn->handlers;
|
||||
while (tail->next)
|
||||
tail = tail->next;
|
||||
tail->next = item;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -432,7 +455,7 @@ static void _handler_add(xmpp_conn_t * const conn,
|
||||
* @ingroup Handlers
|
||||
*/
|
||||
void xmpp_handler_delete(xmpp_conn_t * const conn,
|
||||
xmpp_handler handler)
|
||||
xmpp_handler handler)
|
||||
{
|
||||
xmpp_handlist_t *prev, *item;
|
||||
|
||||
@@ -441,23 +464,21 @@ void xmpp_handler_delete(xmpp_conn_t * const conn,
|
||||
prev = NULL;
|
||||
item = conn->handlers;
|
||||
while (item) {
|
||||
if (item->handler == (void *)handler)
|
||||
break;
|
||||
|
||||
prev = item;
|
||||
item = item->next;
|
||||
}
|
||||
if (item->handler == handler) {
|
||||
if (prev)
|
||||
prev->next = item->next;
|
||||
else
|
||||
conn->handlers = item->next;
|
||||
|
||||
if (item) {
|
||||
if (prev)
|
||||
prev->next = item->next;
|
||||
else
|
||||
conn->handlers = item->next;
|
||||
|
||||
if (item->ns) xmpp_free(conn->ctx, item->ns);
|
||||
if (item->name) xmpp_free(conn->ctx, item->name);
|
||||
if (item->type) xmpp_free(conn->ctx, item->type);
|
||||
xmpp_free(conn->ctx, item);
|
||||
if (item->ns) xmpp_free(conn->ctx, item->ns);
|
||||
if (item->name) xmpp_free(conn->ctx, item->name);
|
||||
if (item->type) xmpp_free(conn->ctx, item->type);
|
||||
xmpp_free(conn->ctx, item);
|
||||
item = prev ? prev->next : conn->handlers;
|
||||
} else {
|
||||
prev = item;
|
||||
item = item->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -466,7 +487,7 @@ void xmpp_handler_delete(xmpp_conn_t * const conn,
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
* If the handler function returns true, it will be kept, and if it
|
||||
* returns false, it will be deleted from the list of handlers.
|
||||
*
|
||||
@@ -478,9 +499,9 @@ void xmpp_handler_delete(xmpp_conn_t * const conn,
|
||||
* @ingroup Handlers
|
||||
*/
|
||||
void xmpp_timed_handler_add(xmpp_conn_t * const conn,
|
||||
xmpp_timed_handler handler,
|
||||
const unsigned long period,
|
||||
void * const userdata)
|
||||
xmpp_timed_handler handler,
|
||||
const unsigned long period,
|
||||
void * const userdata)
|
||||
{
|
||||
_timed_handler_add(conn, handler, period, userdata, 1);
|
||||
}
|
||||
@@ -495,9 +516,9 @@ void xmpp_timed_handler_add(xmpp_conn_t * const conn,
|
||||
* @param userdata an opaque data pointer that will be passed to the handler
|
||||
*/
|
||||
void handler_add_timed(xmpp_conn_t * const conn,
|
||||
xmpp_timed_handler handler,
|
||||
const unsigned long period,
|
||||
void * const userdata)
|
||||
xmpp_timed_handler handler,
|
||||
const unsigned long period,
|
||||
void * const userdata)
|
||||
{
|
||||
_timed_handler_add(conn, handler, period, userdata, 0);
|
||||
}
|
||||
@@ -519,9 +540,9 @@ void handler_add_timed(xmpp_conn_t * const conn,
|
||||
* @ingroup Handlers
|
||||
*/
|
||||
void xmpp_id_handler_add(xmpp_conn_t * const conn,
|
||||
xmpp_handler handler,
|
||||
const char * const id,
|
||||
void * const userdata)
|
||||
xmpp_handler handler,
|
||||
const char * const id,
|
||||
void * const userdata)
|
||||
{
|
||||
_id_handler_add(conn, handler, id, userdata, 1);
|
||||
}
|
||||
@@ -536,9 +557,9 @@ void xmpp_id_handler_add(xmpp_conn_t * const conn,
|
||||
* @param userdata an opaque data pointer that will be passed to the handler
|
||||
*/
|
||||
void handler_add_id(xmpp_conn_t * const conn,
|
||||
xmpp_handler handler,
|
||||
const char * const id,
|
||||
void * const userdata)
|
||||
xmpp_handler handler,
|
||||
const char * const id,
|
||||
void * const userdata)
|
||||
{
|
||||
_id_handler_add(conn, handler, id, userdata, 0);
|
||||
}
|
||||
@@ -566,11 +587,11 @@ void handler_add_id(xmpp_conn_t * const conn,
|
||||
* @ingroup Handlers
|
||||
*/
|
||||
void xmpp_handler_add(xmpp_conn_t * const conn,
|
||||
xmpp_handler handler,
|
||||
const char * const ns,
|
||||
const char * const name,
|
||||
const char * const type,
|
||||
void * const userdata)
|
||||
xmpp_handler handler,
|
||||
const char * const ns,
|
||||
const char * const name,
|
||||
const char * const type,
|
||||
void * const userdata)
|
||||
{
|
||||
_handler_add(conn, handler, ns, name, type, userdata, 1);
|
||||
}
|
||||
@@ -587,11 +608,83 @@ void xmpp_handler_add(xmpp_conn_t * const conn,
|
||||
* @param userdata an opaque data pointer that will be passed to the handler
|
||||
*/
|
||||
void handler_add(xmpp_conn_t * const conn,
|
||||
xmpp_handler handler,
|
||||
const char * const ns,
|
||||
const char * const name,
|
||||
const char * const type,
|
||||
void * const userdata)
|
||||
xmpp_handler handler,
|
||||
const char * const ns,
|
||||
const char * const name,
|
||||
const char * const type,
|
||||
void * const userdata)
|
||||
{
|
||||
_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->ns) xmpp_free(conn->ctx, item->ns);
|
||||
if (item->name) xmpp_free(conn->ctx, item->name);
|
||||
if (item->type) xmpp_free(conn->ctx, item->type);
|
||||
xmpp_free(conn->ctx, item);
|
||||
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->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);
|
||||
}
|
||||
|
||||
89
src/hash.c
89
src/hash.c
@@ -47,7 +47,7 @@ struct _hash_iterator_t {
|
||||
|
||||
/** allocate and initialize a new hash table */
|
||||
hash_t *hash_new(xmpp_ctx_t * const ctx, const int size,
|
||||
hash_free_func free)
|
||||
hash_free_func free_func)
|
||||
{
|
||||
hash_t *result = NULL;
|
||||
|
||||
@@ -62,7 +62,7 @@ hash_t *hash_new(xmpp_ctx_t * const ctx, const int size,
|
||||
result->length = size;
|
||||
|
||||
result->ctx = ctx;
|
||||
result->free = free;
|
||||
result->free = free_func;
|
||||
result->num_keys = 0;
|
||||
/* give the caller a reference */
|
||||
result->ref = 1;
|
||||
@@ -106,18 +106,35 @@ void hash_release(hash_t * const table)
|
||||
/** hash a key for our table lookup */
|
||||
static int _hash_key(hash_t *table, const char *key)
|
||||
{
|
||||
int hash = 0;
|
||||
int shift = 0;
|
||||
const char *c = key;
|
||||
unsigned hash = 0;
|
||||
unsigned shift = 0;
|
||||
const unsigned char *c = (const unsigned char *)key;
|
||||
|
||||
while (*c != '\0') {
|
||||
while (*c != 0) {
|
||||
/* assume 32 bit ints */
|
||||
hash ^= ((int)*c++ << shift);
|
||||
hash ^= ((unsigned)*c++ << shift);
|
||||
shift += 8;
|
||||
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.
|
||||
@@ -128,25 +145,27 @@ int hash_add(hash_t *table, const char * const key, void *data)
|
||||
{
|
||||
xmpp_ctx_t *ctx = table->ctx;
|
||||
hashentry_t *entry = NULL;
|
||||
int index = _hash_key(table, key);
|
||||
int table_index = _hash_key(table, key);
|
||||
|
||||
/* drop existing entry, if any */
|
||||
hash_drop(table, key);
|
||||
/* find and replace existing entry, if any */
|
||||
entry = _hash_entry_find(table, key);
|
||||
|
||||
/* allocate and fill a new entry */
|
||||
entry = xmpp_alloc(ctx, sizeof(hashentry_t));
|
||||
if (!entry) return -1;
|
||||
entry->key = xmpp_strdup(ctx, key);
|
||||
if (!entry->key) {
|
||||
xmpp_free(ctx, entry);
|
||||
return -1;
|
||||
if (entry == NULL) {
|
||||
/* allocate and fill a new entry */
|
||||
entry = xmpp_alloc(ctx, sizeof(hashentry_t));
|
||||
if (!entry) return -1;
|
||||
entry->key = xmpp_strdup(ctx, key);
|
||||
if (!entry->key) {
|
||||
xmpp_free(ctx, entry);
|
||||
return -1;
|
||||
}
|
||||
/* insert ourselves in the linked list */
|
||||
entry->next = table->entries[table_index];
|
||||
table->entries[table_index] = entry;
|
||||
table->num_keys++;
|
||||
}
|
||||
|
||||
entry->value = data;
|
||||
/* insert ourselves in the linked list */
|
||||
/* TODO: this leaks duplicate keys */
|
||||
entry->next = table->entries[index];
|
||||
table->entries[index] = entry;
|
||||
table->num_keys++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -155,22 +174,9 @@ int hash_add(hash_t *table, const char * const key, void *data)
|
||||
void *hash_get(hash_t *table, const char *key)
|
||||
{
|
||||
hashentry_t *entry;
|
||||
int index = _hash_key(table, key);
|
||||
void *result = NULL;
|
||||
|
||||
/* look up the hash entry */
|
||||
entry = table->entries[index];
|
||||
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;
|
||||
entry = _hash_entry_find(table, key);
|
||||
return entry == NULL ? NULL : entry->value;
|
||||
}
|
||||
|
||||
/** delete a key from a hash table */
|
||||
@@ -178,10 +184,10 @@ int hash_drop(hash_t *table, const char *key)
|
||||
{
|
||||
xmpp_ctx_t *ctx = table->ctx;
|
||||
hashentry_t *entry, *prev;
|
||||
int index = _hash_key(table, key);
|
||||
int table_index = _hash_key(table, key);
|
||||
|
||||
/* look up the hash entry */
|
||||
entry = table->entries[index];
|
||||
entry = table->entries[table_index];
|
||||
prev = NULL;
|
||||
while (entry != NULL) {
|
||||
/* traverse the linked list looking for the key */
|
||||
@@ -190,7 +196,7 @@ int hash_drop(hash_t *table, const char *key)
|
||||
xmpp_free(ctx, entry->key);
|
||||
if (table->free) table->free(ctx, entry->value);
|
||||
if (prev == NULL) {
|
||||
table->entries[index] = entry->next;
|
||||
table->entries[table_index] = entry->next;
|
||||
} else {
|
||||
prev->next = entry->next;
|
||||
}
|
||||
@@ -273,4 +279,3 @@ const char * hash_iter_next(hash_iterator_t *iter)
|
||||
iter->entry = entry;
|
||||
return entry->key;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ typedef void (*hash_free_func)(const xmpp_ctx_t * const ctx, void *p);
|
||||
|
||||
/** allocate and initialize a new hash table */
|
||||
hash_t *hash_new(xmpp_ctx_t * const ctx, const int size,
|
||||
hash_free_func free);
|
||||
hash_free_func free_func);
|
||||
|
||||
/** allocate a new reference to an existing hash table */
|
||||
hash_t *hash_clone(hash_t * const table);
|
||||
|
||||
45
src/jid.c
45
src/jid.c
@@ -33,7 +33,7 @@ char *xmpp_jid_new(xmpp_ctx_t *ctx, const char *node,
|
||||
const char *resource)
|
||||
{
|
||||
char *result;
|
||||
int len,nlen,dlen,rlen;
|
||||
size_t len, nlen, dlen, rlen;
|
||||
|
||||
/* jid must at least have a domain */
|
||||
if (domain == NULL) return NULL;
|
||||
@@ -56,7 +56,7 @@ char *xmpp_jid_new(xmpp_ctx_t *ctx, const char *node,
|
||||
result[nlen+dlen] = '/';
|
||||
memcpy(result+nlen+dlen+1, resource, rlen - 1);
|
||||
}
|
||||
result[nlen+dlen+rlen] = '\0';
|
||||
result[len] = '\0';
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -72,15 +72,13 @@ char *xmpp_jid_new(xmpp_ctx_t *ctx, const char *node,
|
||||
char *xmpp_jid_bare(xmpp_ctx_t *ctx, const char *jid)
|
||||
{
|
||||
char *result;
|
||||
const char *c;
|
||||
size_t len;
|
||||
|
||||
c = strchr(jid, '/');
|
||||
if (c == NULL) return xmpp_strdup(ctx, jid);
|
||||
|
||||
result = xmpp_alloc(ctx, c-jid+1);
|
||||
len = strcspn(jid, "/");
|
||||
result = xmpp_alloc(ctx, len + 1);
|
||||
if (result != NULL) {
|
||||
memcpy(result, jid, c-jid);
|
||||
result[c-jid] = '\0';
|
||||
memcpy(result, jid, len);
|
||||
result[len] = '\0';
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -121,7 +119,8 @@ char *xmpp_jid_node(xmpp_ctx_t *ctx, const char *jid)
|
||||
char *xmpp_jid_domain(xmpp_ctx_t *ctx, const char *jid)
|
||||
{
|
||||
char *result = NULL;
|
||||
const char *c,*s;
|
||||
const char *c;
|
||||
size_t dlen;
|
||||
|
||||
c = strchr(jid, '@');
|
||||
if (c == NULL) {
|
||||
@@ -131,15 +130,11 @@ char *xmpp_jid_domain(xmpp_ctx_t *ctx, const char *jid)
|
||||
/* advance past the separator */
|
||||
c++;
|
||||
}
|
||||
s = strchr(c, '/');
|
||||
if (s == NULL) {
|
||||
/* no resource */
|
||||
s = c + strlen(c);
|
||||
}
|
||||
result = xmpp_alloc(ctx, (s-c) + 1);
|
||||
dlen = strcspn(c, "/"); /* do not include resource */
|
||||
result = xmpp_alloc(ctx, dlen + 1);
|
||||
if (result != NULL) {
|
||||
memcpy(result, c, (s-c));
|
||||
result[s-c] = '\0';
|
||||
memcpy(result, c, dlen);
|
||||
result[dlen] = '\0';
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -155,20 +150,8 @@ char *xmpp_jid_domain(xmpp_ctx_t *ctx, const char *jid)
|
||||
*/
|
||||
char *xmpp_jid_resource(xmpp_ctx_t *ctx, const char *jid)
|
||||
{
|
||||
char *result = NULL;
|
||||
const char *c;
|
||||
int len;
|
||||
|
||||
c = strchr(jid, '/');
|
||||
if (c != NULL) {
|
||||
c++;
|
||||
len = strlen(c);
|
||||
result = xmpp_alloc(ctx, len + 1);
|
||||
if (result != NULL) {
|
||||
memcpy(result, c, len);
|
||||
result[len] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return c != NULL ? xmpp_strdup(ctx, c + 1) : NULL;
|
||||
}
|
||||
|
||||
96
src/md5.c
96
src/md5.c
@@ -37,14 +37,14 @@
|
||||
|
||||
#define PUT_32BIT_LSB_FIRST(cp, value) \
|
||||
do { \
|
||||
(cp)[0] = (value) & 0xFF; \
|
||||
(cp)[1] = ((value) >> 8) & 0xFF; \
|
||||
(cp)[2] = ((value) >> 16) & 0xFF; \
|
||||
(cp)[3] = ((value) >> 24) & 0xFF; \
|
||||
(cp)[0] = (value) & 0xFF; \
|
||||
(cp)[1] = ((value) >> 8) & 0xFF; \
|
||||
(cp)[2] = ((value) >> 16) & 0xFF; \
|
||||
(cp)[3] = ((value) >> 24) & 0xFF; \
|
||||
} while(0)
|
||||
|
||||
static void MD5Transform(uint32_t buf[4], const unsigned char inext[64],
|
||||
struct MD5Context *ctx);
|
||||
struct MD5Context *ctx);
|
||||
|
||||
/*
|
||||
* Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
|
||||
@@ -60,7 +60,7 @@ void MD5Init(struct MD5Context *ctx)
|
||||
ctx->bits[0] = 0;
|
||||
ctx->bits[1] = 0;
|
||||
|
||||
memset(ctx->in, 0, 64);
|
||||
memset(ctx->in, 0, 64);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -75,33 +75,33 @@ void MD5Update(struct MD5Context *ctx, unsigned char const *buf, uint32_t len)
|
||||
|
||||
t = ctx->bits[0];
|
||||
if ((ctx->bits[0] = (t + ((uint32_t)len << 3)) & 0xffffffff) < t)
|
||||
ctx->bits[1]++; /* Carry from low to high */
|
||||
ctx->bits[1]++; /* Carry from low to high */
|
||||
ctx->bits[1] += len >> 29;
|
||||
|
||||
t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
|
||||
t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
|
||||
|
||||
/* Handle any leading odd-sized chunks */
|
||||
|
||||
if (t) {
|
||||
unsigned char *p = ctx->in + t;
|
||||
unsigned char *p = ctx->in + t;
|
||||
|
||||
t = 64 - t;
|
||||
if (len < t) {
|
||||
memcpy(p, buf, len);
|
||||
return;
|
||||
}
|
||||
memcpy(p, buf, t);
|
||||
MD5Transform(ctx->buf, ctx->in, ctx);
|
||||
buf += t;
|
||||
len -= t;
|
||||
t = 64 - t;
|
||||
if (len < t) {
|
||||
memcpy(p, buf, len);
|
||||
return;
|
||||
}
|
||||
memcpy(p, buf, t);
|
||||
MD5Transform(ctx->buf, ctx->in, ctx);
|
||||
buf += t;
|
||||
len -= t;
|
||||
}
|
||||
/* Process data in 64-byte chunks */
|
||||
|
||||
while (len >= 64) {
|
||||
memcpy(ctx->in, buf, 64);
|
||||
MD5Transform(ctx->buf, ctx->in, ctx);
|
||||
buf += 64;
|
||||
len -= 64;
|
||||
memcpy(ctx->in, buf, 64);
|
||||
MD5Transform(ctx->buf, ctx->in, ctx);
|
||||
buf += 64;
|
||||
len -= 64;
|
||||
}
|
||||
|
||||
/* Handle any remaining bytes of data. */
|
||||
@@ -131,15 +131,15 @@ void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
|
||||
|
||||
/* Pad out to 56 mod 64 */
|
||||
if (count < 8) {
|
||||
/* Two lots of padding: Pad the first block to 64 bytes */
|
||||
memset(p, 0, count);
|
||||
MD5Transform(ctx->buf, ctx->in, ctx);
|
||||
/* Two lots of padding: Pad the first block to 64 bytes */
|
||||
memset(p, 0, count);
|
||||
MD5Transform(ctx->buf, ctx->in, ctx);
|
||||
|
||||
/* Now fill the next block with 56 bytes */
|
||||
memset(ctx->in, 0, 56);
|
||||
/* Now fill the next block with 56 bytes */
|
||||
memset(ctx->in, 0, 56);
|
||||
} else {
|
||||
/* Pad block to 56 bytes */
|
||||
memset(p, 0, count - 8);
|
||||
/* Pad block to 56 bytes */
|
||||
memset(p, 0, count - 8);
|
||||
}
|
||||
|
||||
/* Append length in bits and transform */
|
||||
@@ -151,11 +151,9 @@ void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
|
||||
PUT_32BIT_LSB_FIRST(digest + 4, ctx->buf[1]);
|
||||
PUT_32BIT_LSB_FIRST(digest + 8, ctx->buf[2]);
|
||||
PUT_32BIT_LSB_FIRST(digest + 12, ctx->buf[3]);
|
||||
memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */
|
||||
memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */
|
||||
}
|
||||
|
||||
#ifndef ASM_MD5
|
||||
|
||||
/* The four core functions - F1 is optimized somewhat */
|
||||
|
||||
/* #define F1(x, y, z) (x & y | ~x & z) */
|
||||
@@ -168,14 +166,14 @@ void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
|
||||
/* debugging version: */
|
||||
/*
|
||||
#define MD5STEP(f, w, x, y, z, data, s) \
|
||||
printf("MD5STEP: w: %x x: %x y: %x z: %x data: %x s: %x\n", \
|
||||
w, x, y, z, data, s); \
|
||||
printf("f(x,y,z) = %x\n", f(x,y,z)+data); \
|
||||
( w += f(x, y, z) + data, printf(" - w: %x ", w), \
|
||||
w = w<<s | w>>(32-s), printf(" - w: %x\n", w), w += x )
|
||||
printf("MD5STEP: w: %x x: %x y: %x z: %x data: %x s: %x\n", \
|
||||
w, x, y, z, data, s); \
|
||||
printf("f(x,y,z) = %x\n", f(x,y,z)+data); \
|
||||
( w += f(x, y, z) + data, printf(" - w: %x ", w), \
|
||||
w = w<<s | w>>(32-s), printf(" - w: %x\n", w), w += x )
|
||||
*/
|
||||
#define MD5STEP(f, w, x, y, z, data, s) \
|
||||
( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
|
||||
( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
|
||||
|
||||
/*
|
||||
* The core of the MD5 algorithm, this alters an existing MD5 hash to
|
||||
@@ -183,7 +181,7 @@ void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
|
||||
* the data and converts bytes into longwords for this routine.
|
||||
*/
|
||||
static void MD5Transform(uint32_t buf[4], const unsigned char inext[64],
|
||||
struct MD5Context *ctx)
|
||||
struct MD5Context *ctx)
|
||||
{
|
||||
register uint32_t a, b, c, d, i;
|
||||
uint32_t in[16];
|
||||
@@ -270,23 +268,3 @@ static void MD5Transform(uint32_t buf[4], const unsigned char inext[64],
|
||||
buf[2] += c;
|
||||
buf[3] += d;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_MD5
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
void MD5DumpBytes(unsigned char *b, int len)
|
||||
{
|
||||
int i;
|
||||
for (i=0; i<len; i++) {
|
||||
if (i%32==0 && i!=0) {
|
||||
printf("\n");
|
||||
}
|
||||
printf("%02x", b[i]&0xff);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
#endif /* DEBUG_MD5 */
|
||||
|
||||
#endif /* !MD5_ASM */
|
||||
|
||||
12
src/md5.h
12
src/md5.h
@@ -15,18 +15,14 @@
|
||||
#include "ostypes.h"
|
||||
|
||||
struct MD5Context {
|
||||
uint32_t buf[4];
|
||||
uint32_t bits[2];
|
||||
unsigned char in[64];
|
||||
uint32_t buf[4];
|
||||
uint32_t bits[2];
|
||||
unsigned char in[64];
|
||||
};
|
||||
|
||||
void MD5Init(struct MD5Context *context);
|
||||
void MD5Update(struct MD5Context *context, unsigned char const *buf,
|
||||
uint32_t len);
|
||||
uint32_t len);
|
||||
void MD5Final(unsigned char digest[16], struct MD5Context *context);
|
||||
|
||||
#ifdef DEBUG_MD5
|
||||
void MD5DumpBytes(unsigned char *b, int len);
|
||||
#endif
|
||||
|
||||
#endif /* !MD5_H */
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* oocontext.cpp
|
||||
** strophe XMPP client library -- C++ context implementation
|
||||
**
|
||||
** Copyright (C) 2005-2009 Collecta, Inc.
|
||||
**
|
||||
** Copyright (C) 2005-2009 Collecta, Inc.
|
||||
**
|
||||
** This software is provided AS-IS with no warranty, either express
|
||||
** or implied.
|
||||
@@ -14,7 +14,7 @@
|
||||
#include "strophe.h"
|
||||
#include "strophepp.h"
|
||||
|
||||
XMPP::Context::Context()
|
||||
XMPP::Context::Context()
|
||||
{
|
||||
m_mem.alloc = callAlloc;
|
||||
m_mem.realloc = callRealloc;
|
||||
@@ -48,8 +48,8 @@ void XMPP::Context::free(void *p)
|
||||
}
|
||||
|
||||
void XMPP::Context::log(const xmpp_log_level_t level,
|
||||
const char * const area,
|
||||
const char * const msg)
|
||||
const char * const area,
|
||||
const char * const msg)
|
||||
{
|
||||
/* do nothing by default */
|
||||
}
|
||||
@@ -65,7 +65,7 @@ void *XMPP::Context::callAlloc(const size_t size, void * const userdata)
|
||||
}
|
||||
|
||||
void *XMPP::Context::callRealloc(void *p, const size_t size,
|
||||
void * const userdata)
|
||||
void * const userdata)
|
||||
{
|
||||
return reinterpret_cast<Context *>(userdata)->realloc(p, size);
|
||||
}
|
||||
@@ -76,10 +76,9 @@ void XMPP::Context::callFree(void *p, void * const userdata)
|
||||
}
|
||||
|
||||
void XMPP::Context::callLog(void * const userdata,
|
||||
const xmpp_log_level_t level,
|
||||
const char * const area,
|
||||
const char * const msg)
|
||||
const xmpp_log_level_t level,
|
||||
const char * const area,
|
||||
const char * const msg)
|
||||
{
|
||||
reinterpret_cast<Context *>(userdata)->log(level, area, msg);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* oostanza.cpp
|
||||
** strophe XMPP client library -- C++ context implementation
|
||||
**
|
||||
** Copyright (C) 2005-2009 Collecta, Inc.
|
||||
**
|
||||
** Copyright (C) 2005-2009 Collecta, Inc.
|
||||
**
|
||||
** This software is provided AS-IS with no warranty, either express
|
||||
** or implied.
|
||||
@@ -28,8 +28,8 @@ void *Stanza::operator new(size_t size, Context *ctx)
|
||||
if (!p) return p;
|
||||
|
||||
*reinterpret_cast<Context **>(p) = ctx;
|
||||
p = reinterpret_cast<void *>(reinterpret_cast<char *>(p) +
|
||||
sizeof(Context *));
|
||||
p = reinterpret_cast<void *>(reinterpret_cast<char *>(p) +
|
||||
sizeof(Context *));
|
||||
|
||||
return p;
|
||||
}
|
||||
@@ -61,7 +61,7 @@ Stanza *Stanza::create(Context *ctx)
|
||||
void Stanza::release()
|
||||
{
|
||||
if (::xmpp_stanza_release(m_stanza))
|
||||
delete this;
|
||||
delete this;
|
||||
}
|
||||
|
||||
Stanza *Stanza::clone()
|
||||
@@ -75,5 +75,3 @@ Stanza *Stanza::copy()
|
||||
// TODO
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
#ifndef __LIBSTROPHE_OSTYPES_H__
|
||||
#define __LIBSTROPHE_OSTYPES_H__
|
||||
|
||||
#include <stddef.h> /* size_t */
|
||||
|
||||
#if defined (_MSC_VER) && _MSC_VER < 1600
|
||||
typedef signed char int8_t;
|
||||
typedef short int int16_t;
|
||||
@@ -27,6 +29,17 @@ typedef unsigned char uint8_t;
|
||||
typedef unsigned short int uint16_t;
|
||||
typedef unsigned int uint32_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
|
||||
#ifndef UINT16_MAX
|
||||
#define UINT16_MAX ((uint16_t)0xffff)
|
||||
#endif /* UINT16_MAX */
|
||||
#ifndef UINT32_MAX
|
||||
#define UINT32_MAX ((uint32_t)0xffffffff)
|
||||
#endif /* UINT32_MAX */
|
||||
#ifndef SIZE_MAX
|
||||
#define SIZE_MAX UINT32_MAX
|
||||
#endif /* SIZE_MAX */
|
||||
|
||||
#else
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
@@ -33,7 +33,7 @@ parser_t *parser_new(xmpp_ctx_t *ctx,
|
||||
parser_end_callback endcb,
|
||||
parser_stanza_callback stanzacb,
|
||||
void *userdata);
|
||||
void parser_free(parser_t * const parser);
|
||||
void parser_free(parser_t *parser);
|
||||
char* parser_attr_name(xmpp_ctx_t *ctx, char *nsname);
|
||||
int parser_reset(parser_t *parser);
|
||||
int parser_feed(parser_t *parser, char *chunk, int len);
|
||||
|
||||
@@ -23,8 +23,14 @@
|
||||
#include "common.h"
|
||||
#include "parser.h"
|
||||
|
||||
/* ASCII FF is invalid UTF-8 and should never be present in well-formed XML */
|
||||
#define NAMESPACE_SEP ('\xFF')
|
||||
/* Use the Unit Separator to delimit namespace and name in our XML*/
|
||||
#define NAMESPACE_SEP ('\x1F')
|
||||
|
||||
/* Allocate inner text by this number bytes more. Expat splits string
|
||||
* "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 {
|
||||
xmpp_ctx_t *ctx;
|
||||
@@ -35,6 +41,11 @@ struct _parser_t {
|
||||
void *userdata;
|
||||
int depth;
|
||||
xmpp_stanza_t *stanza;
|
||||
char* inner_text;
|
||||
/* number of allocated bytes */
|
||||
int inner_text_size;
|
||||
/* excluding terminal '\0' */
|
||||
int inner_text_used;
|
||||
};
|
||||
|
||||
/* return allocated string with the name from a delimited
|
||||
@@ -43,7 +54,7 @@ static char *_xml_name(xmpp_ctx_t *ctx, const char *nsname)
|
||||
{
|
||||
char *result = NULL;
|
||||
const char *c;
|
||||
int len;
|
||||
size_t len;
|
||||
|
||||
c = strchr(nsname, NAMESPACE_SEP);
|
||||
if (c == NULL) return xmpp_strdup(ctx, nsname);
|
||||
@@ -92,6 +103,26 @@ static void _set_attributes(xmpp_stanza_t *stanza, const XML_Char **attrs)
|
||||
}
|
||||
}
|
||||
|
||||
static void complete_inner_text(parser_t *parser)
|
||||
{
|
||||
xmpp_stanza_t *stanza;
|
||||
|
||||
if (parser->inner_text) {
|
||||
/* create and populate stanza */
|
||||
stanza = xmpp_stanza_new(parser->ctx);
|
||||
/* FIXME: disconnect on allocation error */
|
||||
if (stanza) {
|
||||
xmpp_stanza_set_text(stanza, parser->inner_text);
|
||||
xmpp_stanza_add_child(parser->stanza, stanza);
|
||||
xmpp_stanza_release(stanza);
|
||||
}
|
||||
xmpp_free(parser->ctx, parser->inner_text);
|
||||
parser->inner_text = NULL;
|
||||
parser->inner_text_size = 0;
|
||||
parser->inner_text_used = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void _start_element(void *userdata,
|
||||
const XML_Char *nsname,
|
||||
const XML_Char **attrs)
|
||||
@@ -109,41 +140,28 @@ static void _start_element(void *userdata,
|
||||
parser->startcb((char *)name, (char **)attrs,
|
||||
parser->userdata);
|
||||
} else {
|
||||
/* build stanzas at depth 1 */
|
||||
if (!parser->stanza && parser->depth != 1) {
|
||||
/* something terrible happened */
|
||||
/* FIXME: shutdown disconnect */
|
||||
xmpp_error(parser->ctx, "parser", "oops, where did our stanza go?");
|
||||
} else if (!parser->stanza) {
|
||||
/* starting a new toplevel stanza */
|
||||
parser->stanza = xmpp_stanza_new(parser->ctx);
|
||||
if (!parser->stanza) {
|
||||
/* FIXME: can't allocate, disconnect */
|
||||
}
|
||||
xmpp_stanza_set_name(parser->stanza, name);
|
||||
_set_attributes(parser->stanza, attrs);
|
||||
if (ns)
|
||||
xmpp_stanza_set_ns(parser->stanza, ns);
|
||||
} else {
|
||||
/* starting a child of parser->stanza */
|
||||
child = xmpp_stanza_new(parser->ctx);
|
||||
if (!child) {
|
||||
/* FIXME: can't allocate, disconnect */
|
||||
}
|
||||
xmpp_stanza_set_name(child, name);
|
||||
_set_attributes(child, attrs);
|
||||
if (ns)
|
||||
xmpp_stanza_set_ns(child, ns);
|
||||
/* build stanzas at depth 1 */
|
||||
if (!parser->stanza && parser->depth != 1) {
|
||||
/* something terrible happened */
|
||||
/* FIXME: shutdown disconnect */
|
||||
xmpp_error(parser->ctx, "parser", "oops, where did our stanza go?");
|
||||
} else {
|
||||
child = xmpp_stanza_new(parser->ctx);
|
||||
if (!child) {
|
||||
/* FIXME: can't allocate, disconnect */
|
||||
}
|
||||
xmpp_stanza_set_name(child, name);
|
||||
_set_attributes(child, attrs);
|
||||
if (ns)
|
||||
xmpp_stanza_set_ns(child, ns);
|
||||
|
||||
/* add child to parent */
|
||||
xmpp_stanza_add_child(parser->stanza, child);
|
||||
|
||||
/* the child is owned by the toplevel stanza now */
|
||||
xmpp_stanza_release(child);
|
||||
|
||||
/* make child the current stanza */
|
||||
parser->stanza = child;
|
||||
}
|
||||
if (parser->stanza != NULL) {
|
||||
complete_inner_text(parser);
|
||||
xmpp_stanza_add_child(parser->stanza, child);
|
||||
xmpp_stanza_release(child);
|
||||
}
|
||||
parser->stanza = child;
|
||||
}
|
||||
}
|
||||
|
||||
if (ns) xmpp_free(parser->ctx, ns);
|
||||
@@ -163,36 +181,46 @@ static void _end_element(void *userdata, const XML_Char *name)
|
||||
if (parser->endcb)
|
||||
parser->endcb((char *)name, parser->userdata);
|
||||
} else {
|
||||
if (parser->stanza->parent) {
|
||||
/* we're finishing a child stanza, so set current to the parent */
|
||||
parser->stanza = parser->stanza->parent;
|
||||
} else {
|
||||
complete_inner_text(parser);
|
||||
if (parser->stanza->parent) {
|
||||
/* we're finishing a child stanza, so set current to the parent */
|
||||
parser->stanza = parser->stanza->parent;
|
||||
} else {
|
||||
if (parser->stanzacb)
|
||||
parser->stanzacb(parser->stanza,
|
||||
parser->userdata);
|
||||
xmpp_stanza_release(parser->stanza);
|
||||
parser->stanza = NULL;
|
||||
}
|
||||
xmpp_stanza_release(parser->stanza);
|
||||
parser->stanza = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void _characters(void *userdata, const XML_Char *s, int len)
|
||||
{
|
||||
parser_t *parser = (parser_t *)userdata;
|
||||
xmpp_stanza_t *stanza;
|
||||
char *p;
|
||||
|
||||
if (parser->depth < 2) return;
|
||||
|
||||
/* create and populate stanza */
|
||||
stanza = xmpp_stanza_new(parser->ctx);
|
||||
if (!stanza) {
|
||||
/* FIXME: allocation error, disconnect */
|
||||
return;
|
||||
/* Join all parts to a single resulting string. Stanza is created in
|
||||
* _start_element() and _end_element(). */
|
||||
if (parser->inner_text_used + len >= parser->inner_text_size) {
|
||||
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;
|
||||
}
|
||||
parser->inner_text = p;
|
||||
parser->inner_text[parser->inner_text_used] = '\0';
|
||||
}
|
||||
xmpp_stanza_set_text_with_size(stanza, s, len);
|
||||
|
||||
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,
|
||||
@@ -213,6 +241,9 @@ parser_t *parser_new(xmpp_ctx_t *ctx,
|
||||
parser->userdata = userdata;
|
||||
parser->depth = 0;
|
||||
parser->stanza = NULL;
|
||||
parser->inner_text = NULL;
|
||||
parser->inner_text_size = 0;
|
||||
parser->inner_text_used = 0;
|
||||
|
||||
parser_reset(parser);
|
||||
}
|
||||
@@ -231,6 +262,11 @@ void parser_free(parser_t *parser)
|
||||
if (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);
|
||||
}
|
||||
|
||||
@@ -249,6 +285,11 @@ int parser_reset(parser_t *parser)
|
||||
parser->depth = 0;
|
||||
parser->stanza = NULL;
|
||||
|
||||
if (parser->inner_text) {
|
||||
xmpp_free (parser->ctx, parser->inner_text);
|
||||
parser->inner_text = NULL;
|
||||
}
|
||||
|
||||
XML_SetUserData(parser->expat, parser);
|
||||
XML_SetElementHandler(parser->expat, _start_element, _end_element);
|
||||
XML_SetCharacterDataHandler(parser->expat, _characters);
|
||||
|
||||
@@ -116,11 +116,12 @@ static void _start_element(void *userdata,
|
||||
|
||||
if (parser->depth == 0) {
|
||||
/* notify the owner */
|
||||
if (parser->startcb)
|
||||
if (parser->startcb) {
|
||||
cbattrs = _convert_attrs(parser, nattrs, attrs);
|
||||
parser->startcb((char *)name, cbattrs,
|
||||
parser->userdata);
|
||||
_free_cbattrs(parser, cbattrs);
|
||||
}
|
||||
} else {
|
||||
/* build stanzas at depth 1 */
|
||||
if (!parser->stanza && parser->depth != 1) {
|
||||
@@ -273,11 +274,7 @@ int parser_reset(parser_t *parser)
|
||||
/* feed a chunk of data to the parser */
|
||||
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 */
|
||||
if(!xmlParseChunk(parser->xmlctx, chunk, len, 0)) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
return !xmlParseChunk(parser->xmlctx, chunk, len, 0);
|
||||
}
|
||||
|
||||
311
src/rand.c
Normal file
311
src/rand.c
Normal file
@@ -0,0 +1,311 @@
|
||||
/* rand.c
|
||||
* strophe XMPP client library -- pseudo-random number generator
|
||||
*
|
||||
* Copyright (C) 2014 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.
|
||||
*/
|
||||
|
||||
/** @file
|
||||
* Pseudo-random number generator.
|
||||
*
|
||||
* Implemented Hash_DRBG mechanism according to NIST SP 800-90A.
|
||||
* Hash function is SHA1.
|
||||
*/
|
||||
|
||||
/** @defgroup Random Pseudo-random number generator
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h> /* memeset */
|
||||
#include <time.h> /* clock, time */
|
||||
|
||||
#include "common.h" /* xmpp_alloc, xmpp_free */
|
||||
#include "ostypes.h" /* uint8_t, uint32_t, size_t */
|
||||
#include "sha1.h"
|
||||
#include "snprintf.h" /* xmpp_snprintf */
|
||||
|
||||
#include "rand.h" /* xmpp_rand_t */
|
||||
|
||||
#define outlen SHA1_DIGEST_SIZE
|
||||
#define seedlen (440 / 8)
|
||||
#define reseed_interval 0x7fffffff
|
||||
|
||||
/* maximum number of bytes that can be generated per call */
|
||||
#define GENERATE_MAX (outlen * 10)
|
||||
#define ENTROPY_MAX 128
|
||||
#define NONCE_MAX 8
|
||||
|
||||
#define RESEED_NEEDED (-1)
|
||||
|
||||
struct Hash_DRBG_CTX_struc {
|
||||
uint8_t V[seedlen];
|
||||
uint8_t C[seedlen];
|
||||
uint32_t reseed_counter;
|
||||
};
|
||||
typedef struct Hash_DRBG_CTX_struc Hash_DRBG_CTX;
|
||||
|
||||
struct _xmpp_rand_t {
|
||||
int inited;
|
||||
unsigned reseed_count;
|
||||
Hash_DRBG_CTX ctx;
|
||||
};
|
||||
|
||||
/* returns smallest number mupliple of y that not less than x */
|
||||
#define round_up(x, y) (((x) + (y) - 1) / (y) * (y))
|
||||
/* returns smallest integer number that not less than x/y */
|
||||
#define div_round_up(x, y) (((x) + (y) - 1) / (y))
|
||||
|
||||
/* adds two arrays as numbers in big-endian representation and stores
|
||||
* result in the first one.
|
||||
*/
|
||||
static void arr_add(uint8_t *arr1, size_t arr1_len,
|
||||
uint8_t *arr2, size_t arr2_len)
|
||||
{
|
||||
size_t i;
|
||||
uint32_t acc;
|
||||
uint32_t carry = 0;
|
||||
|
||||
assert(arr1_len >= arr2_len);
|
||||
|
||||
for (i = 1; (i <= arr2_len) || (carry != 0 && i <= arr1_len); ++i) {
|
||||
acc = (uint32_t)arr1[arr1_len - i] + carry;
|
||||
if (i <= arr2_len)
|
||||
acc += (uint32_t)arr2[arr2_len - i];
|
||||
carry = acc >> 8;
|
||||
arr1[arr1_len - i] = (uint8_t)(acc & 0xff);
|
||||
}
|
||||
}
|
||||
|
||||
/* stores 32-bit number in big-endian representation */
|
||||
static void store_be32(uint32_t val, uint8_t be[4])
|
||||
{
|
||||
be[0] = (uint8_t)((val >> 24) & 0xff);
|
||||
be[1] = (uint8_t)((val >> 16) & 0xff);
|
||||
be[2] = (uint8_t)((val >> 8) & 0xff);
|
||||
be[3] = (uint8_t)(val & 0xff);
|
||||
}
|
||||
|
||||
static void Hash_df(uint8_t *input_string, size_t input_string_len,
|
||||
uint8_t *output_string, size_t no_of_bytes_to_return)
|
||||
{
|
||||
uint8_t counter;
|
||||
uint8_t temp[round_up(seedlen, outlen)];
|
||||
uint8_t conj[ENTROPY_MAX + NONCE_MAX + seedlen + 6];
|
||||
size_t len;
|
||||
size_t i;
|
||||
size_t offset;
|
||||
|
||||
assert(no_of_bytes_to_return <= sizeof(temp));
|
||||
assert(input_string_len + 5 <= sizeof(conj));
|
||||
|
||||
len = div_round_up(no_of_bytes_to_return, outlen);
|
||||
for (i = 1; i <= len; ++i) {
|
||||
offset = (i - 1) * outlen;
|
||||
counter = (uint8_t)i;
|
||||
conj[0] = counter;
|
||||
store_be32((uint32_t)no_of_bytes_to_return * 8, conj + 1);
|
||||
memcpy(conj + 5, input_string, input_string_len);
|
||||
crypto_SHA1(conj, input_string_len + 5, temp + offset);
|
||||
}
|
||||
|
||||
memcpy(output_string, temp, no_of_bytes_to_return);
|
||||
}
|
||||
|
||||
/* assume personalization_string is zero length string */
|
||||
static void Hash_DRBG_Instantiate(Hash_DRBG_CTX *ctx,
|
||||
uint8_t *entropy_input,
|
||||
size_t entropy_input_len,
|
||||
uint8_t *nonce, size_t nonce_len)
|
||||
{
|
||||
uint8_t seed_material[ENTROPY_MAX + NONCE_MAX];
|
||||
uint8_t seed0[seedlen + 1];
|
||||
uint8_t *seed = seed0 + 1;
|
||||
|
||||
assert(entropy_input_len <= ENTROPY_MAX);
|
||||
assert(nonce_len <= NONCE_MAX);
|
||||
|
||||
memcpy(seed_material, entropy_input, entropy_input_len);
|
||||
memcpy(seed_material + entropy_input_len, nonce, nonce_len);
|
||||
Hash_df(seed_material, entropy_input_len + nonce_len, seed, seedlen);
|
||||
seed0[0] = 0;
|
||||
|
||||
memcpy(ctx->V, seed, seedlen);
|
||||
Hash_df(seed0, sizeof(seed0), ctx->C, seedlen);
|
||||
ctx->reseed_counter = 1;
|
||||
}
|
||||
|
||||
/* assume additional_input is zero length string */
|
||||
static void Hash_DRBG_Reseed(Hash_DRBG_CTX *ctx,
|
||||
uint8_t *entropy_input,
|
||||
size_t entropy_input_len)
|
||||
{
|
||||
uint8_t seed_material[1 + seedlen + ENTROPY_MAX];
|
||||
uint8_t seed0[seedlen + 1];
|
||||
uint8_t *seed = seed0 + 1;
|
||||
|
||||
assert(entropy_input_len <= ENTROPY_MAX);
|
||||
|
||||
seed_material[0] = 1;
|
||||
memcpy(seed_material + 1, ctx->V, seedlen);
|
||||
memcpy(seed_material + 1 + seedlen, entropy_input, entropy_input_len);
|
||||
Hash_df(seed_material, entropy_input_len + seedlen + 1, seed, seedlen);
|
||||
seed0[0] = 0;
|
||||
|
||||
memcpy(ctx->V, seed, seedlen);
|
||||
Hash_df(seed0, sizeof(seed0), ctx->C, seedlen);
|
||||
ctx->reseed_counter = 1;
|
||||
}
|
||||
|
||||
static void Hashgen(uint8_t *V, uint8_t *output,
|
||||
size_t requested_number_of_bytes)
|
||||
{
|
||||
uint8_t data[seedlen];
|
||||
uint8_t W[GENERATE_MAX];
|
||||
uint8_t i1 = 1;
|
||||
size_t m;
|
||||
size_t i;
|
||||
size_t offset;
|
||||
|
||||
assert(requested_number_of_bytes <= sizeof(W));
|
||||
|
||||
m = div_round_up(requested_number_of_bytes, outlen);
|
||||
memcpy(data, V, seedlen);
|
||||
for (i = 1; i <= m; ++i) {
|
||||
offset = (i - 1) * outlen;
|
||||
crypto_SHA1(data, seedlen, W + offset);
|
||||
/* increase data by 1 */
|
||||
arr_add(data, sizeof(data), &i1, 1);
|
||||
}
|
||||
|
||||
memcpy(output, W, requested_number_of_bytes);
|
||||
}
|
||||
|
||||
/* assume additional_input is zero length string */
|
||||
static int Hash_DRBG_Generate(Hash_DRBG_CTX *ctx, uint8_t *output,
|
||||
size_t requested_number_of_bytes)
|
||||
{
|
||||
uint8_t H[outlen];
|
||||
uint8_t V3[seedlen + 1];
|
||||
uint8_t reseed_counter[4];
|
||||
|
||||
if (ctx->reseed_counter > reseed_interval || ctx->reseed_counter == 0)
|
||||
return RESEED_NEEDED;
|
||||
|
||||
Hashgen(ctx->V, output, requested_number_of_bytes);
|
||||
|
||||
V3[0] = 3;
|
||||
memcpy(V3 + 1, ctx->V, seedlen);
|
||||
crypto_SHA1(V3, sizeof(V3), H);
|
||||
arr_add(ctx->V, sizeof(ctx->V), ctx->C, sizeof(ctx->C));
|
||||
arr_add(ctx->V, sizeof(ctx->V), H, sizeof(H));
|
||||
store_be32(ctx->reseed_counter, reseed_counter);
|
||||
arr_add(ctx->V, sizeof(ctx->V), reseed_counter, sizeof(reseed_counter));
|
||||
|
||||
++ctx->reseed_counter;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define ENTROPY_ACCUMULATE(ptr, last, type, arg) \
|
||||
do { \
|
||||
type __arg = (type)(arg); \
|
||||
if ((char*)ptr + sizeof(__arg) < (char*)last) { \
|
||||
*(type*)ptr = __arg; \
|
||||
ptr = (void*)((char*)ptr + sizeof(__arg)); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static void xmpp_rand_reseed(xmpp_rand_t *rand)
|
||||
{
|
||||
uint8_t entropy[ENTROPY_MAX];
|
||||
uint8_t *ptr = entropy;
|
||||
const uint8_t *last = entropy + sizeof(entropy);
|
||||
size_t len;
|
||||
|
||||
/* entropy:
|
||||
* 1. time_stamp()
|
||||
* 2. clock(3)
|
||||
* 3. xmpp_rand_t address to make unique seed within one process
|
||||
* 4. counter to make unique seed within one context
|
||||
* 5. stack address
|
||||
* 6. local ports of every connection in list (getsockname)
|
||||
* 7. other non-constant info that can be retieved from socket
|
||||
*
|
||||
* rand(3) can't be used as it isn't thread-safe.
|
||||
* XXX 6 and 7 are not implemented yet.
|
||||
*/
|
||||
|
||||
ENTROPY_ACCUMULATE(ptr, last, uint64_t, time_stamp());
|
||||
ENTROPY_ACCUMULATE(ptr, last, clock_t, clock());
|
||||
ENTROPY_ACCUMULATE(ptr, last, void *, rand);
|
||||
ENTROPY_ACCUMULATE(ptr, last, unsigned, ++rand->reseed_count);
|
||||
ENTROPY_ACCUMULATE(ptr, last, void *, &entropy);
|
||||
len = ptr - entropy;
|
||||
|
||||
if (rand->inited) {
|
||||
Hash_DRBG_Reseed(&rand->ctx, entropy, len);
|
||||
} else {
|
||||
Hash_DRBG_Instantiate(&rand->ctx, entropy, len, NULL, 0);
|
||||
rand->inited = 1;
|
||||
}
|
||||
}
|
||||
|
||||
xmpp_rand_t *xmpp_rand_new(xmpp_ctx_t *ctx)
|
||||
{
|
||||
xmpp_rand_t *out = xmpp_alloc(ctx, sizeof(*out));
|
||||
if (out != NULL) {
|
||||
memset(out, 0, sizeof(*out));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
void xmpp_rand_free(xmpp_ctx_t *ctx, xmpp_rand_t *rand)
|
||||
{
|
||||
xmpp_free(ctx, rand);
|
||||
}
|
||||
|
||||
void xmpp_rand_bytes(xmpp_rand_t *rand, unsigned char *output, size_t len)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = Hash_DRBG_Generate(&rand->ctx, (uint8_t *)output, len);
|
||||
if (rc == RESEED_NEEDED) {
|
||||
xmpp_rand_reseed(rand);
|
||||
rc = Hash_DRBG_Generate(&rand->ctx, (uint8_t *)output, len);
|
||||
assert(rc == 0);
|
||||
}
|
||||
}
|
||||
|
||||
int xmpp_rand(xmpp_rand_t *rand)
|
||||
{
|
||||
int result;
|
||||
|
||||
xmpp_rand_bytes(rand, (unsigned char *)&result, sizeof(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
void xmpp_rand_nonce(xmpp_rand_t *rand, char *output, size_t len)
|
||||
{
|
||||
size_t i;
|
||||
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;
|
||||
* the only problem is that base64_encode() allocates memory and
|
||||
* as result can fail.
|
||||
*/
|
||||
|
||||
xmpp_rand_bytes(rand, rand_buf, rand_len);
|
||||
for (i = 0; i < rand_len; ++i) {
|
||||
xmpp_snprintf(output + i * 2, len, "%02x", rand_buf[i]);
|
||||
len -= 2;
|
||||
}
|
||||
}
|
||||
65
src/rand.h
Normal file
65
src/rand.h
Normal file
@@ -0,0 +1,65 @@
|
||||
/* rand.h
|
||||
* strophe XMPP client library -- pseudo-random number generator
|
||||
*
|
||||
* Copyright (C) 2014 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.
|
||||
*/
|
||||
|
||||
/** @file
|
||||
* Pseudo-random number generator.
|
||||
*/
|
||||
|
||||
#ifndef __LIBSTROPHE_RAND_H__
|
||||
#define __LIBSTROPHE_RAND_H__
|
||||
|
||||
#include <stddef.h> /* size_t */
|
||||
#include "strophe.h" /* xmpp_ctx_t */
|
||||
|
||||
typedef struct _xmpp_rand_t xmpp_rand_t;
|
||||
|
||||
/** Create new xmpp_rand_t object.
|
||||
*
|
||||
* @param ctx A Strophe context object
|
||||
*
|
||||
* @ingroup Random
|
||||
*/
|
||||
xmpp_rand_t *xmpp_rand_new(xmpp_ctx_t *ctx);
|
||||
/** Destroy an xmpp_rand_t object.
|
||||
*
|
||||
* @param ctx A Strophe context object
|
||||
*
|
||||
* @ingroup Random
|
||||
*/
|
||||
void xmpp_rand_free(xmpp_ctx_t *ctx, xmpp_rand_t *rand);
|
||||
|
||||
/** Generate random integer
|
||||
* Analogue of rand(3).
|
||||
*
|
||||
* @ingroup Random
|
||||
*/
|
||||
int xmpp_rand(xmpp_rand_t *rand);
|
||||
|
||||
/** Generate random bytes.
|
||||
* Generates len bytes and stores them to the output buffer.
|
||||
*
|
||||
* @ingroup Random
|
||||
*/
|
||||
void xmpp_rand_bytes(xmpp_rand_t *rand, unsigned char *output, size_t len);
|
||||
|
||||
/** Generate a nonce that is printable randomized string.
|
||||
* This function doesn't allocate memory and doesn't fail.
|
||||
*
|
||||
* @param output A buffer where a NULL-terminated string will be placed.
|
||||
* The string will contain len-1 printable symbols.
|
||||
* @param len Number of bytes reserved for the output string, including
|
||||
* end of line '\0'.
|
||||
*
|
||||
* @ingroup Random
|
||||
*/
|
||||
void xmpp_rand_nonce(xmpp_rand_t *rand, char *output, size_t len);
|
||||
|
||||
#endif /* __LIBSTROPHE_RAND_H__ */
|
||||
767
src/resolver.c
Normal file
767
src/resolver.c
Normal file
@@ -0,0 +1,767 @@
|
||||
/* resolver.h
|
||||
* strophe XMPP client library -- DNS resolver
|
||||
*
|
||||
* Copyright (C) 2015 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.
|
||||
*/
|
||||
|
||||
/** @file
|
||||
* DNS resolver.
|
||||
*/
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/nameser.h>
|
||||
#include <resolv.h> /* res_query */
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#include <string.h> /* strncpy */
|
||||
|
||||
#include "ostypes.h"
|
||||
#include "snprintf.h"
|
||||
#include "util.h" /* xmpp_min */
|
||||
#include "resolver.h"
|
||||
|
||||
#define MESSAGE_HEADER_LEN 12
|
||||
#define MESSAGE_RESPONSE 1
|
||||
#define MESSAGE_T_SRV 33
|
||||
#define MESSAGE_C_IN 1
|
||||
|
||||
struct message_header {
|
||||
uint16_t id;
|
||||
uint8_t octet2;
|
||||
uint8_t octet3;
|
||||
uint16_t qdcount;
|
||||
uint16_t ancount;
|
||||
uint16_t nscount;
|
||||
uint16_t arcount;
|
||||
};
|
||||
|
||||
#ifdef _WIN32
|
||||
static int resolver_win32_srv_lookup(xmpp_ctx_t *ctx, const char *fulldomain,
|
||||
resolver_srv_rr_t **srv_rr_list);
|
||||
static int resolver_win32_srv_query(const char *fulldomain,
|
||||
unsigned char *buf, size_t len);
|
||||
#endif /* _WIN32 */
|
||||
|
||||
/* the same as ntohs(), but receives pointer to the value */
|
||||
static uint16_t xmpp_ntohs_ptr(const void *ptr)
|
||||
{
|
||||
const uint8_t *p = (const uint8_t *)ptr;
|
||||
|
||||
return (uint16_t)((p[0] << 8U) + p[1]);
|
||||
}
|
||||
|
||||
static uint8_t message_header_qr(const struct message_header *header)
|
||||
{
|
||||
return (header->octet2 >> 7) & 1;
|
||||
}
|
||||
|
||||
static uint8_t message_header_rcode(const struct message_header *header)
|
||||
{
|
||||
return header->octet3 & 0x0f;
|
||||
}
|
||||
|
||||
/*
|
||||
* Append a label or a dot to the target name with buffer overflow checks.
|
||||
* Returns length of the non-truncated resulting string, may be bigger than
|
||||
* name_max.
|
||||
*/
|
||||
static size_t message_name_append_safe(char *name, size_t name_len,
|
||||
size_t name_max,
|
||||
const char *tail, size_t tail_len)
|
||||
{
|
||||
size_t copy_len;
|
||||
|
||||
copy_len = name_max > name_len ? name_max - name_len : 0;
|
||||
copy_len = xmpp_min(tail_len, copy_len);
|
||||
if (copy_len > 0)
|
||||
strncpy(&name[name_len], tail, copy_len);
|
||||
|
||||
return name_len + tail_len;
|
||||
}
|
||||
|
||||
/* Returns length of the compressed name. This is NOT the same as strlen(). */
|
||||
static unsigned message_name_get(const unsigned char *buf, size_t buf_len,
|
||||
unsigned buf_offset,
|
||||
char *name, size_t name_max)
|
||||
{
|
||||
size_t name_len = 0;
|
||||
unsigned i = buf_offset;
|
||||
unsigned pointer;
|
||||
unsigned rc;
|
||||
unsigned char label_len;
|
||||
|
||||
|
||||
while (1) {
|
||||
if (i >= buf_len) return 0;
|
||||
label_len = buf[i++];
|
||||
if (label_len == 0) break;
|
||||
|
||||
/* Label */
|
||||
if ((label_len & 0xc0) == 0) {
|
||||
if (i + label_len - 1 >= buf_len) return 0;
|
||||
if (name != NULL) {
|
||||
name_len = message_name_append_safe(name, name_len, name_max,
|
||||
(char *)&buf[i], label_len);
|
||||
name_len = message_name_append_safe(name, name_len, name_max,
|
||||
".", 1);
|
||||
}
|
||||
i += label_len;
|
||||
|
||||
/* Pointer */
|
||||
} else if ((label_len & 0xc0) == 0xc0) {
|
||||
if (i >= buf_len) return 0;
|
||||
pointer = (label_len & 0x3f) << 8 | buf[i++];
|
||||
if (name != NULL && name_len >= name_max && name_max > 0) {
|
||||
/* We have filled the name buffer. Don't pass it recursively. */
|
||||
name[name_max - 1] = '\0';
|
||||
name = NULL;
|
||||
name_max = 0;
|
||||
}
|
||||
rc = message_name_get(buf, buf_len, pointer,
|
||||
name != NULL ? &name[name_len] : NULL,
|
||||
name_max > name_len ? name_max - name_len : 0);
|
||||
if (rc == 0) return 0;
|
||||
/* Pointer is always the last. */
|
||||
break;
|
||||
|
||||
/* The 10 and 01 combinations are reserved for future use. */
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (label_len == 0) {
|
||||
if (name_len == 0) name_len = 1;
|
||||
/*
|
||||
* At this point name_len is length of the resulting name,
|
||||
* including '\0'. This value can be exported to allocate buffer
|
||||
* of precise size.
|
||||
*/
|
||||
if (name != NULL && name_max > 0) {
|
||||
/*
|
||||
* Overwrite leading '.' with a '\0'. If the resulting name is
|
||||
* bigger than name_max it is truncated.
|
||||
*/
|
||||
name[xmpp_min(name_len, name_max) - 1] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
return i - buf_offset;
|
||||
}
|
||||
|
||||
static unsigned message_name_len(const unsigned char *buf, size_t buf_len,
|
||||
unsigned buf_offset)
|
||||
{
|
||||
return message_name_get(buf, buf_len, buf_offset, NULL, SIZE_MAX);
|
||||
}
|
||||
|
||||
static void resolver_srv_list_sort(resolver_srv_rr_t **srv_rr_list)
|
||||
{
|
||||
resolver_srv_rr_t * rr_head;
|
||||
resolver_srv_rr_t * rr_current;
|
||||
resolver_srv_rr_t * rr_next;
|
||||
resolver_srv_rr_t * rr_prev;
|
||||
int swap;
|
||||
|
||||
rr_head = *srv_rr_list;
|
||||
|
||||
if ((rr_head == NULL) || (rr_head->next == NULL)) {
|
||||
/* Empty or single record list */
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
rr_prev = NULL;
|
||||
rr_current = rr_head;
|
||||
rr_next = rr_head->next;
|
||||
swap = 0;
|
||||
while (rr_next != NULL) {
|
||||
/*
|
||||
* RFC2052: A client MUST attempt to contact the target host
|
||||
* with the lowest-numbered priority it can reach.
|
||||
* RFC2052: When selecting a target host among the
|
||||
* those that have the same priority, the chance of trying
|
||||
* this one first SHOULD be proportional to its weight.
|
||||
*/
|
||||
if ((rr_current->priority > rr_next->priority) ||
|
||||
(rr_current->priority == rr_next->priority &&
|
||||
rr_current->weight < rr_next->weight))
|
||||
{
|
||||
/* Swap node */
|
||||
swap = 1;
|
||||
if (rr_prev != NULL) {
|
||||
rr_prev->next = rr_next;
|
||||
} else {
|
||||
/* Swap head node */
|
||||
rr_head = rr_next;
|
||||
}
|
||||
rr_current->next = rr_next->next;
|
||||
rr_next->next = rr_current;
|
||||
|
||||
rr_prev = rr_next;
|
||||
rr_next = rr_current->next;
|
||||
} else {
|
||||
/* Next node */
|
||||
rr_prev = rr_current;
|
||||
rr_current = rr_next;
|
||||
rr_next = rr_next->next;
|
||||
}
|
||||
}
|
||||
} while (swap != 0);
|
||||
|
||||
*srv_rr_list = rr_head;
|
||||
}
|
||||
|
||||
#define BUF_OVERFLOW_CHECK(ptr, len) do { \
|
||||
if ((ptr) >= (len)) { \
|
||||
if (*srv_rr_list != NULL) \
|
||||
resolver_srv_free(ctx, *srv_rr_list); \
|
||||
*srv_rr_list = NULL; \
|
||||
return XMPP_DOMAIN_NOT_FOUND; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
int resolver_srv_lookup_buf(xmpp_ctx_t *ctx, const unsigned char *buf,
|
||||
size_t len, resolver_srv_rr_t **srv_rr_list)
|
||||
{
|
||||
unsigned i;
|
||||
unsigned j;
|
||||
unsigned name_len;
|
||||
unsigned rdlength;
|
||||
uint16_t type;
|
||||
uint16_t class;
|
||||
struct message_header header;
|
||||
resolver_srv_rr_t *rr;
|
||||
|
||||
*srv_rr_list = NULL;
|
||||
|
||||
if (len < MESSAGE_HEADER_LEN)
|
||||
return XMPP_DOMAIN_NOT_FOUND;
|
||||
|
||||
header.id = xmpp_ntohs_ptr(&buf[0]);
|
||||
header.octet2 = buf[2];
|
||||
header.octet3 = buf[3];
|
||||
header.qdcount = xmpp_ntohs_ptr(&buf[4]);
|
||||
header.ancount = xmpp_ntohs_ptr(&buf[6]);
|
||||
header.nscount = xmpp_ntohs_ptr(&buf[8]);
|
||||
header.arcount = xmpp_ntohs_ptr(&buf[10]);
|
||||
if (message_header_qr(&header) != MESSAGE_RESPONSE ||
|
||||
message_header_rcode(&header) != 0)
|
||||
{
|
||||
return XMPP_DOMAIN_NOT_FOUND;
|
||||
}
|
||||
j = MESSAGE_HEADER_LEN;
|
||||
|
||||
/* skip question section */
|
||||
for (i = 0; i < header.qdcount; ++i) {
|
||||
BUF_OVERFLOW_CHECK(j, len);
|
||||
name_len = message_name_len(buf, len, j);
|
||||
/* error in name format */
|
||||
if (name_len == 0) return XMPP_DOMAIN_NOT_FOUND;
|
||||
j += name_len + 4;
|
||||
}
|
||||
|
||||
for (i = 0; i < header.ancount; ++i) {
|
||||
BUF_OVERFLOW_CHECK(j, len);
|
||||
name_len = message_name_len(buf, len, j);
|
||||
/* error in name format */
|
||||
if (name_len == 0) return XMPP_DOMAIN_NOT_FOUND;
|
||||
j += name_len;
|
||||
BUF_OVERFLOW_CHECK(j + 16, len);
|
||||
type = xmpp_ntohs_ptr(&buf[j]);
|
||||
class = xmpp_ntohs_ptr(&buf[j + 2]);
|
||||
rdlength = xmpp_ntohs_ptr(&buf[j + 8]);
|
||||
j += 10;
|
||||
if (type == MESSAGE_T_SRV && class == MESSAGE_C_IN) {
|
||||
rr = xmpp_alloc(ctx, sizeof(*rr));
|
||||
rr->next = *srv_rr_list;
|
||||
rr->priority = xmpp_ntohs_ptr(&buf[j]);
|
||||
rr->weight = xmpp_ntohs_ptr(&buf[j + 2]);
|
||||
rr->port = xmpp_ntohs_ptr(&buf[j + 4]);
|
||||
name_len = message_name_get(buf, len, j + 6, rr->target,
|
||||
sizeof(rr->target));
|
||||
if (name_len > 0)
|
||||
*srv_rr_list = rr;
|
||||
else
|
||||
xmpp_free(ctx, rr); /* skip broken record */
|
||||
}
|
||||
j += rdlength;
|
||||
}
|
||||
resolver_srv_list_sort(srv_rr_list);
|
||||
|
||||
return *srv_rr_list != NULL ? XMPP_DOMAIN_FOUND : XMPP_DOMAIN_NOT_FOUND;
|
||||
}
|
||||
|
||||
int resolver_srv_lookup(xmpp_ctx_t *ctx, const char *service, const char *proto,
|
||||
const char *domain, resolver_srv_rr_t **srv_rr_list)
|
||||
{
|
||||
char fulldomain[2048];
|
||||
unsigned char buf[65535];
|
||||
int len;
|
||||
int set = XMPP_DOMAIN_NOT_FOUND;
|
||||
|
||||
xmpp_snprintf(fulldomain, sizeof(fulldomain),
|
||||
"_%s._%s.%s", service, proto, domain);
|
||||
|
||||
*srv_rr_list = NULL;
|
||||
|
||||
#ifdef _WIN32
|
||||
set = resolver_win32_srv_lookup(ctx, fulldomain, srv_rr_list);
|
||||
if (set == XMPP_DOMAIN_FOUND)
|
||||
return set;
|
||||
len = resolver_win32_srv_query(fulldomain, buf, sizeof(buf));
|
||||
#else /* _WIN32 */
|
||||
len = res_query(fulldomain, MESSAGE_C_IN, MESSAGE_T_SRV, buf, sizeof(buf));
|
||||
#endif /* _WIN32 */
|
||||
|
||||
if (len > 0)
|
||||
set = resolver_srv_lookup_buf(ctx, buf, (size_t)len, srv_rr_list);
|
||||
|
||||
return set;
|
||||
}
|
||||
|
||||
void resolver_srv_free(xmpp_ctx_t *ctx, resolver_srv_rr_t *srv_rr_list)
|
||||
{
|
||||
resolver_srv_rr_t *rr;
|
||||
|
||||
while (srv_rr_list != NULL) {
|
||||
rr = srv_rr_list->next;
|
||||
xmpp_free(ctx, srv_rr_list);
|
||||
srv_rr_list = rr;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
/*******************************************************************************
|
||||
* Next part was copied from sock.c and contains old win32 code.
|
||||
*
|
||||
* The idea is to get raw response from a name server and pass it to
|
||||
* resolver_srv_lookup_buf(). In fact, resolver_win32_srv_query() replaces
|
||||
* the call of res_query().
|
||||
* Dnsapi code is moved to a separated function resolver_srv_win32_lookup() and
|
||||
* changed to meet new API.
|
||||
*
|
||||
* XXX If the code is compiled it should work like before.
|
||||
******************************************************************************/
|
||||
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <windns.h>
|
||||
#include <Iphlpapi.h>
|
||||
|
||||
struct dnsquery_header
|
||||
{
|
||||
unsigned short id;
|
||||
unsigned char qr;
|
||||
unsigned char opcode;
|
||||
unsigned char aa;
|
||||
unsigned char tc;
|
||||
unsigned char rd;
|
||||
unsigned char ra;
|
||||
unsigned char z;
|
||||
unsigned char rcode;
|
||||
unsigned short qdcount;
|
||||
unsigned short ancount;
|
||||
unsigned short nscount;
|
||||
unsigned short arcount;
|
||||
};
|
||||
|
||||
struct dnsquery_question
|
||||
{
|
||||
char qname[1024];
|
||||
unsigned short qtype;
|
||||
unsigned short qclass;
|
||||
};
|
||||
|
||||
static void netbuf_add_16bitnum(unsigned char *buf, int buflen, int *offset, unsigned short num)
|
||||
{
|
||||
unsigned char *start = buf + *offset;
|
||||
unsigned char *p = start;
|
||||
|
||||
/* assuming big endian */
|
||||
*p++ = (num >> 8) & 0xff;
|
||||
*p++ = (num) & 0xff;
|
||||
|
||||
*offset += 2;
|
||||
}
|
||||
|
||||
static void netbuf_add_domain_name(unsigned char *buf, int buflen, int *offset,
|
||||
char *name)
|
||||
{
|
||||
unsigned char *start = buf + *offset;
|
||||
unsigned char *p = start;
|
||||
unsigned char *wordstart, *wordend;
|
||||
|
||||
wordstart = (unsigned char *)name;
|
||||
|
||||
while (*wordstart)
|
||||
{
|
||||
int len;
|
||||
wordend = wordstart;
|
||||
while (*wordend && *wordend != '.')
|
||||
{
|
||||
wordend++;
|
||||
}
|
||||
|
||||
len = (int)(wordend - wordstart);
|
||||
|
||||
if (len > 0x3F)
|
||||
{
|
||||
len = 0x3F;
|
||||
}
|
||||
|
||||
*p++ = len;
|
||||
|
||||
while (wordstart != wordend)
|
||||
{
|
||||
*p++ = *wordstart++;
|
||||
}
|
||||
|
||||
if (*wordstart == '.')
|
||||
{
|
||||
wordstart++;
|
||||
}
|
||||
}
|
||||
|
||||
*p++ = '\0';
|
||||
|
||||
*offset += (int)(p - start);
|
||||
}
|
||||
|
||||
static void netbuf_add_dnsquery_header(unsigned char *buf, int buflen, int *offset, struct dnsquery_header *header)
|
||||
{
|
||||
unsigned char *p;
|
||||
|
||||
netbuf_add_16bitnum(buf, buflen, offset, header->id);
|
||||
|
||||
p = buf + *offset;
|
||||
*p++ = ((header->qr & 0x01) << 7)
|
||||
| ((header->opcode & 0x0F) << 3)
|
||||
| ((header->aa & 0x01) << 2)
|
||||
| ((header->tc & 0x01) << 1)
|
||||
| ((header->rd & 0x01));
|
||||
*p++ = ((header->ra & 0x01) << 7)
|
||||
| ((header->z & 0x07) << 4)
|
||||
| ((header->rcode & 0x0F));
|
||||
*offset += 2;
|
||||
|
||||
netbuf_add_16bitnum(buf, buflen, offset, header->qdcount);
|
||||
netbuf_add_16bitnum(buf, buflen, offset, header->ancount);
|
||||
netbuf_add_16bitnum(buf, buflen, offset, header->nscount);
|
||||
netbuf_add_16bitnum(buf, buflen, offset, header->arcount);
|
||||
}
|
||||
|
||||
static void netbuf_add_dnsquery_question(unsigned char *buf, int buflen, int *offset, struct dnsquery_question *question)
|
||||
{
|
||||
netbuf_add_domain_name(buf, buflen, offset, question->qname);
|
||||
netbuf_add_16bitnum(buf, buflen, offset, question->qtype);
|
||||
netbuf_add_16bitnum(buf, buflen, offset, question->qclass);
|
||||
}
|
||||
|
||||
static int resolver_win32_srv_lookup(xmpp_ctx_t *ctx, const char *fulldomain,
|
||||
resolver_srv_rr_t **srv_rr_list)
|
||||
{
|
||||
resolver_srv_rr_t *rr;
|
||||
HINSTANCE hdnsapi = NULL;
|
||||
|
||||
DNS_STATUS (WINAPI * pDnsQuery_A)(PCSTR, WORD, DWORD, PIP4_ARRAY, PDNS_RECORD*, PVOID*);
|
||||
void (WINAPI * pDnsRecordListFree)(PDNS_RECORD, DNS_FREE_TYPE);
|
||||
|
||||
if (hdnsapi = LoadLibrary("dnsapi.dll")) {
|
||||
pDnsQuery_A = (void *)GetProcAddress(hdnsapi, "DnsQuery_A");
|
||||
pDnsRecordListFree = (void *)GetProcAddress(hdnsapi, "DnsRecordListFree");
|
||||
|
||||
if (pDnsQuery_A && pDnsRecordListFree) {
|
||||
PDNS_RECORD dnsrecords = NULL;
|
||||
DNS_STATUS error;
|
||||
|
||||
error = pDnsQuery_A(fulldomain, DNS_TYPE_SRV, DNS_QUERY_STANDARD, NULL, &dnsrecords, NULL);
|
||||
|
||||
if (error == 0) {
|
||||
PDNS_RECORD current = dnsrecords;
|
||||
|
||||
while (current) {
|
||||
if (current->wType == DNS_TYPE_SRV) {
|
||||
rr = xmpp_alloc(ctx, sizeof(*rr));
|
||||
if (rr == NULL)
|
||||
break;
|
||||
rr->next = *srv_rr_list;
|
||||
rr->port = current->Data.Srv.wPort;
|
||||
rr->priority = current->Data.Srv.wPriority;
|
||||
rr->weight = current->Data.Srv.wWeight;
|
||||
xmpp_snprintf(rr->target, sizeof(rr->target), "%s",
|
||||
current->Data.Srv.pNameTarget);
|
||||
*srv_rr_list = rr;
|
||||
}
|
||||
current = current->pNext;
|
||||
}
|
||||
}
|
||||
|
||||
pDnsRecordListFree(dnsrecords, DnsFreeRecordList);
|
||||
}
|
||||
|
||||
FreeLibrary(hdnsapi);
|
||||
}
|
||||
resolver_srv_list_sort(srv_rr_list);
|
||||
|
||||
return *srv_rr_list != NULL ? XMPP_DOMAIN_FOUND : XMPP_DOMAIN_NOT_FOUND;
|
||||
}
|
||||
|
||||
static int resolver_win32_srv_query(const char *fulldomain,
|
||||
unsigned char *buf, size_t len)
|
||||
{
|
||||
int set = 0;
|
||||
int insize;
|
||||
|
||||
/* if dnsapi didn't work/isn't there, try querying the dns server manually */
|
||||
if (!set)
|
||||
{
|
||||
struct dnsquery_header header;
|
||||
struct dnsquery_question question;
|
||||
int offset = 0;
|
||||
int addrlen;
|
||||
sock_t sock;
|
||||
struct sockaddr_in dnsaddr;
|
||||
char dnsserverips[16][256];
|
||||
int numdnsservers = 0;
|
||||
int j;
|
||||
|
||||
/* Try getting the DNS server ips from GetNetworkParams() in iphlpapi first */
|
||||
if (!numdnsservers)
|
||||
{
|
||||
HINSTANCE hiphlpapi = NULL;
|
||||
DWORD (WINAPI * pGetNetworkParams)(PFIXED_INFO, PULONG);
|
||||
|
||||
if (hiphlpapi = LoadLibrary("Iphlpapi.dll"))
|
||||
{
|
||||
pGetNetworkParams = (void *)GetProcAddress(hiphlpapi, "GetNetworkParams");
|
||||
|
||||
if (pGetNetworkParams)
|
||||
{
|
||||
FIXED_INFO *fi;
|
||||
ULONG len;
|
||||
DWORD error;
|
||||
char buffer[65535];
|
||||
|
||||
len = 65535;
|
||||
fi = buffer;
|
||||
|
||||
if ((error = pGetNetworkParams(fi, &len)) == ERROR_SUCCESS)
|
||||
{
|
||||
IP_ADDR_STRING *pias = &(fi->DnsServerList);
|
||||
|
||||
while (pias && numdnsservers < 16)
|
||||
{
|
||||
strcpy(dnsserverips[numdnsservers++], pias->IpAddress.String);
|
||||
pias = pias->Next;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
FreeLibrary(hiphlpapi);
|
||||
}
|
||||
|
||||
/* Next, try getting the DNS server ips from the registry */
|
||||
if (!numdnsservers)
|
||||
{
|
||||
HKEY search;
|
||||
LONG error;
|
||||
|
||||
error = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters", 0, KEY_READ, &search);
|
||||
|
||||
if (error != ERROR_SUCCESS)
|
||||
{
|
||||
error = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP", 0, KEY_READ, &search);
|
||||
}
|
||||
|
||||
if (error == ERROR_SUCCESS)
|
||||
{
|
||||
char name[512];
|
||||
DWORD len = 512;
|
||||
|
||||
error = RegQueryValueEx(search, "NameServer", NULL, NULL, (LPBYTE)name, &len);
|
||||
|
||||
if (error != ERROR_SUCCESS)
|
||||
{
|
||||
error = RegQueryValueEx(search, "DhcpNameServer", NULL, NULL, (LPBYTE)name, &len);
|
||||
}
|
||||
|
||||
if (error == ERROR_SUCCESS)
|
||||
{
|
||||
char *parse = "0123456789.", *start, *end;
|
||||
start = name;
|
||||
end = name;
|
||||
name[len] = '\0';
|
||||
|
||||
while (*start && numdnsservers < 16)
|
||||
{
|
||||
while (strchr(parse, *end))
|
||||
{
|
||||
end++;
|
||||
}
|
||||
|
||||
strncpy(dnsserverips[numdnsservers++], start, end - start);
|
||||
|
||||
while (*end && !strchr(parse, *end))
|
||||
{
|
||||
end++;
|
||||
}
|
||||
|
||||
start = end;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RegCloseKey(search);
|
||||
}
|
||||
|
||||
if (!numdnsservers)
|
||||
{
|
||||
HKEY searchlist;
|
||||
LONG error;
|
||||
|
||||
error = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces", 0, KEY_READ, &searchlist);
|
||||
|
||||
if (error == ERROR_SUCCESS)
|
||||
{
|
||||
unsigned int i;
|
||||
DWORD numinterfaces = 0;
|
||||
|
||||
RegQueryInfoKey(searchlist, NULL, NULL, NULL, &numinterfaces, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
|
||||
for (i = 0; i < numinterfaces; i++)
|
||||
{
|
||||
char name[512];
|
||||
DWORD len = 512;
|
||||
HKEY searchentry;
|
||||
|
||||
RegEnumKeyEx(searchlist, i, (LPTSTR)name, &len, NULL, NULL, NULL, NULL);
|
||||
|
||||
if (RegOpenKeyEx(searchlist, name, 0, KEY_READ, &searchentry) == ERROR_SUCCESS)
|
||||
{
|
||||
if (RegQueryValueEx(searchentry, "DhcpNameServer", NULL, NULL, (LPBYTE)name, &len) == ERROR_SUCCESS)
|
||||
{
|
||||
char *parse = "0123456789.", *start, *end;
|
||||
start = name;
|
||||
end = name;
|
||||
name[len] = '\0';
|
||||
|
||||
while (*start && numdnsservers < 16)
|
||||
{
|
||||
while (strchr(parse, *end))
|
||||
{
|
||||
end++;
|
||||
}
|
||||
|
||||
strncpy(dnsserverips[numdnsservers++], start, end - start);
|
||||
|
||||
while (*end && !strchr(parse, *end))
|
||||
{
|
||||
end++;
|
||||
}
|
||||
|
||||
start = end;
|
||||
}
|
||||
}
|
||||
else if (RegQueryValueEx(searchentry, "NameServer", NULL, NULL, (LPBYTE)name, &len) == ERROR_SUCCESS)
|
||||
{
|
||||
char *parse = "0123456789.", *start, *end;
|
||||
start = name;
|
||||
end = name;
|
||||
name[len] = '\0';
|
||||
|
||||
while (*start && numdnsservers < 16)
|
||||
{
|
||||
while (strchr(parse, *end))
|
||||
{
|
||||
end++;
|
||||
}
|
||||
|
||||
strncpy(dnsserverips[numdnsservers++], start, end - start);
|
||||
|
||||
while (*end && !strchr(parse, *end))
|
||||
{
|
||||
end++;
|
||||
}
|
||||
|
||||
start = end;
|
||||
}
|
||||
}
|
||||
RegCloseKey(searchentry);
|
||||
}
|
||||
}
|
||||
RegCloseKey(searchlist);
|
||||
}
|
||||
}
|
||||
|
||||
/* If we have a DNS server, use it */
|
||||
if (numdnsservers)
|
||||
{
|
||||
ULONG nonblocking = 1;
|
||||
int i;
|
||||
|
||||
memset(&header, 0, sizeof(header));
|
||||
header.id = 12345; /* FIXME: Get a better id here */
|
||||
header.rd = 1;
|
||||
header.qdcount = 1;
|
||||
|
||||
netbuf_add_dnsquery_header(buf, (int)len, &offset, &header);
|
||||
|
||||
memset(&question, 0, sizeof(question));
|
||||
strncpy(question.qname, fulldomain, 1024);
|
||||
question.qtype = 33; /* SRV */
|
||||
question.qclass = 1; /* INTERNET! */
|
||||
|
||||
netbuf_add_dnsquery_question(buf, (int)len, &offset, &question);
|
||||
|
||||
insize = 0;
|
||||
for (i = 0; i < numdnsservers && insize <= 0; i++)
|
||||
{
|
||||
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
ioctlsocket(sock, FIONBIO, &nonblocking);
|
||||
|
||||
memset(&dnsaddr, 0, sizeof(dnsaddr));
|
||||
|
||||
dnsaddr.sin_family = AF_INET;
|
||||
dnsaddr.sin_port = htons(53);
|
||||
dnsaddr.sin_addr.s_addr = inet_addr(dnsserverips[i]);
|
||||
|
||||
addrlen = sizeof(dnsaddr);
|
||||
sendto(sock, (char *)buf, offset, 0, (struct sockaddr *)&dnsaddr, addrlen);
|
||||
for (j = 0; j < 50; j++)
|
||||
{
|
||||
insize = recvfrom(sock, (char *)buf, (int)len, 0, (struct sockaddr *)&dnsaddr, &addrlen);
|
||||
if (insize == SOCKET_ERROR)
|
||||
{
|
||||
if (sock_error() == WSAEWOULDBLOCK)
|
||||
{
|
||||
Sleep(100);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
closesocket(sock);
|
||||
}
|
||||
set = insize > 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return set ? insize : -1;
|
||||
}
|
||||
|
||||
#endif /* _WIN32 */
|
||||
69
src/resolver.h
Normal file
69
src/resolver.h
Normal file
@@ -0,0 +1,69 @@
|
||||
/* resolver.h
|
||||
* strophe XMPP client library -- DNS resolver
|
||||
*
|
||||
* Copyright (C) 2015 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.
|
||||
*/
|
||||
|
||||
/** @file
|
||||
* DNS resolver.
|
||||
*/
|
||||
|
||||
#ifndef __LIBSTROPHE_RESOLVER_H__
|
||||
#define __LIBSTROPHE_RESOLVER_H__
|
||||
|
||||
#include "ostypes.h"
|
||||
#include "common.h"
|
||||
|
||||
typedef enum {
|
||||
XMPP_DOMAIN_NOT_FOUND,
|
||||
XMPP_DOMAIN_FOUND,
|
||||
XMPP_DOMAIN_ALTDOMAIN
|
||||
} xmpp_domain_state_t;
|
||||
|
||||
typedef struct resolver_srv_rr_struc {
|
||||
uint16_t priority;
|
||||
uint16_t weight;
|
||||
uint16_t port;
|
||||
char target[MAX_DOMAIN_LEN];
|
||||
struct resolver_srv_rr_struc *next;
|
||||
} resolver_srv_rr_t;
|
||||
|
||||
/** Perform lookup for RFC1035 message format.
|
||||
* This function allocates all elements.
|
||||
*
|
||||
* @param ctx a Strophe context object
|
||||
* @param buf message in RFC1035 format
|
||||
* @param len length of the message
|
||||
* @param srv_rr_list is the result
|
||||
*
|
||||
* @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,
|
||||
size_t len, resolver_srv_rr_t **srv_rr_list);
|
||||
/** Resolve SRV record.
|
||||
*
|
||||
* @param ctx a Strophe context object
|
||||
* @param service service of the SRV record
|
||||
* @param proto protocol of the SRV record
|
||||
* @param domain resolving domain
|
||||
* @param srv_rr_list is the result
|
||||
*
|
||||
* @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,
|
||||
const char *domain, resolver_srv_rr_t **srv_rr_list);
|
||||
|
||||
/** Release a list returned by resolver_srv_lookup() or
|
||||
* resolver_srv_lookup_buf().
|
||||
*
|
||||
* @param ctx a Strophe context object
|
||||
* @param srv_rr_list a list allocated by lookup functions
|
||||
*/
|
||||
void resolver_srv_free(xmpp_ctx_t *ctx, resolver_srv_rr_t *srv_rr_list);
|
||||
|
||||
#endif /* __LIBSTROPHE_RESOLVER_H__ */
|
||||
298
src/sasl.c
298
src/sasl.c
@@ -23,15 +23,24 @@
|
||||
#include "md5.h"
|
||||
#include "sha1.h"
|
||||
#include "scram.h"
|
||||
#include "rand.h"
|
||||
#include "util.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#define strtok_r strtok_s
|
||||
#endif
|
||||
/* 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 */
|
||||
|
||||
|
||||
/** generate authentication string for the SASL PLAIN mechanism */
|
||||
char *sasl_plain(xmpp_ctx_t *ctx, const char *authid, const char *password) {
|
||||
int idlen, passlen;
|
||||
size_t idlen, passlen;
|
||||
size_t msglen;
|
||||
char *result = NULL;
|
||||
char *msg;
|
||||
|
||||
@@ -40,13 +49,14 @@ char *sasl_plain(xmpp_ctx_t *ctx, const char *authid, const char *password) {
|
||||
|
||||
idlen = strlen(authid);
|
||||
passlen = strlen(password);
|
||||
msg = xmpp_alloc(ctx, 2 + idlen + passlen);
|
||||
msglen = 2 + idlen + passlen;
|
||||
msg = xmpp_alloc(ctx, msglen);
|
||||
if (msg != NULL) {
|
||||
msg[0] = '\0';
|
||||
memcpy(msg+1, authid, idlen);
|
||||
msg[1+idlen] = '\0';
|
||||
memcpy(msg+1+idlen+1, password, passlen);
|
||||
result = base64_encode(ctx, (unsigned char *)msg, 2 + idlen + passlen);
|
||||
result = xmpp_base64_encode(ctx, (unsigned char *)msg, msglen);
|
||||
xmpp_free(ctx, msg);
|
||||
}
|
||||
|
||||
@@ -72,7 +82,7 @@ static char *_make_string(xmpp_ctx_t *ctx, const char *s, const unsigned len)
|
||||
static char *_make_quoted(xmpp_ctx_t *ctx, const char *s)
|
||||
{
|
||||
char *result;
|
||||
int len = strlen(s);
|
||||
size_t len = strlen(s);
|
||||
|
||||
result = xmpp_alloc(ctx, len + 3);
|
||||
if (result != NULL) {
|
||||
@@ -92,7 +102,7 @@ static hash_t *_parse_digest_challenge(xmpp_ctx_t *ctx, const char *msg)
|
||||
char *key, *value;
|
||||
unsigned char *s, *t;
|
||||
|
||||
text = base64_decode(ctx, msg, strlen(msg));
|
||||
text = (unsigned char *)xmpp_base64_decode_str(ctx, msg, strlen(msg));
|
||||
if (text == NULL) {
|
||||
xmpp_error(ctx, "SASL", "couldn't Base64 decode challenge!");
|
||||
return NULL;
|
||||
@@ -218,6 +228,7 @@ char *sasl_digest_md5(xmpp_ctx_t *ctx, const char *challenge,
|
||||
struct MD5Context MD5;
|
||||
unsigned char digest[16], HA1[16], HA2[16];
|
||||
char hex[32];
|
||||
char cnonce[13];
|
||||
|
||||
/* our digest response is
|
||||
Hex( KD( HEX(MD5(A1)),
|
||||
@@ -250,8 +261,8 @@ char *sasl_digest_md5(xmpp_ctx_t *ctx, const char *challenge,
|
||||
|
||||
/* add our response fields */
|
||||
hash_add(table, "username", xmpp_strdup(ctx, node));
|
||||
/* TODO: generate a random cnonce */
|
||||
hash_add(table, "cnonce", xmpp_strdup(ctx, "00DEADBEEF00"));
|
||||
xmpp_rand_nonce(ctx->rand, cnonce, sizeof(cnonce));
|
||||
hash_add(table, "cnonce", xmpp_strdup(ctx, cnonce));
|
||||
hash_add(table, "nc", xmpp_strdup(ctx, "00000001"));
|
||||
hash_add(table, "qop", xmpp_strdup(ctx, "auth"));
|
||||
value = xmpp_alloc(ctx, 5 + strlen(domain) + 1);
|
||||
@@ -344,7 +355,7 @@ char *sasl_digest_md5(xmpp_ctx_t *ctx, const char *challenge,
|
||||
hash_release(table); /* also frees value strings */
|
||||
|
||||
/* reuse response for the base64 encode of our result */
|
||||
response = base64_encode(ctx, (unsigned char *)result, strlen(result));
|
||||
response = xmpp_base64_encode(ctx, (unsigned char *)result, strlen(result));
|
||||
xmpp_free(ctx, result);
|
||||
|
||||
return response;
|
||||
@@ -360,7 +371,7 @@ char *sasl_scram_sha1(xmpp_ctx_t *ctx, const char *challenge,
|
||||
char *r = NULL;
|
||||
char *s = NULL;
|
||||
char *i = NULL;
|
||||
char *sval;
|
||||
unsigned char *sval;
|
||||
size_t sval_len;
|
||||
long ival;
|
||||
char *tmp;
|
||||
@@ -396,11 +407,10 @@ char *sasl_scram_sha1(xmpp_ctx_t *ctx, const char *challenge,
|
||||
goto out;
|
||||
}
|
||||
|
||||
sval = (char *)base64_decode(ctx, s, strlen(s));
|
||||
xmpp_base64_decode_bin(ctx, s, strlen(s), &sval, &sval_len);
|
||||
if (!sval) {
|
||||
goto out;
|
||||
}
|
||||
sval_len = base64_decoded_len(ctx, s, strlen(s));
|
||||
ival = strtol(i, &saveptr, 10);
|
||||
|
||||
auth_len = 10 + strlen(r) + strlen(first_bare) + strlen(challenge);
|
||||
@@ -426,7 +436,7 @@ char *sasl_scram_sha1(xmpp_ctx_t *ctx, const char *challenge,
|
||||
sign[j] ^= key[j];
|
||||
}
|
||||
|
||||
sign_b64 = base64_encode(ctx, sign, sizeof(sign));
|
||||
sign_b64 = xmpp_base64_encode(ctx, sign, sizeof(sign));
|
||||
if (!sign_b64) {
|
||||
goto out_response;
|
||||
}
|
||||
@@ -439,8 +449,8 @@ char *sasl_scram_sha1(xmpp_ctx_t *ctx, const char *challenge,
|
||||
strcat(response, sign_b64);
|
||||
xmpp_free(ctx, sign_b64);
|
||||
|
||||
response_b64 = base64_encode(ctx, (unsigned char *)response,
|
||||
strlen(response));
|
||||
response_b64 = xmpp_base64_encode(ctx, (unsigned char *)response,
|
||||
strlen(response));
|
||||
if (!response_b64) {
|
||||
goto out_response;
|
||||
}
|
||||
@@ -456,257 +466,3 @@ out:
|
||||
xmpp_free(ctx, tmp);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/** Base64 encoding routines. Implemented according to RFC 3548 */
|
||||
|
||||
/** map of all byte values to the base64 values, or to
|
||||
'65' which indicates an invalid character. '=' is '64' */
|
||||
static const 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,62, 65,65,65,63,
|
||||
52,53,54,55, 56,57,58,59, 60,61,65,65, 65,64,65,65,
|
||||
65, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14,
|
||||
15,16,17,18, 19,20,21,22, 23,24,25,65, 65,65,65,65,
|
||||
65,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
|
||||
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
|
||||
};
|
||||
|
||||
/** map of all 6-bit values to their corresponding byte
|
||||
in the base64 alphabet. Padding char is the value '64' */
|
||||
static const char _base64_charmap[65] = {
|
||||
'A','B','C','D', 'E','F','G','H',
|
||||
'I','J','K','L', 'M','N','O','P',
|
||||
'Q','R','S','T', 'U','V','W','X',
|
||||
'Y','Z','a','b', 'c','d','e','f',
|
||||
'g','h','i','j', 'k','l','m','n',
|
||||
'o','p','q','r', 's','t','u','v',
|
||||
'w','x','y','z', '0','1','2','3',
|
||||
'4','5','6','7', '8','9','+','/',
|
||||
'='
|
||||
};
|
||||
|
||||
int base64_encoded_len(xmpp_ctx_t *ctx, const unsigned len)
|
||||
{
|
||||
/* encoded steam is 4 bytes for every three, rounded up */
|
||||
return ((len + 2)/3) << 2;
|
||||
}
|
||||
|
||||
char *base64_encode(xmpp_ctx_t *ctx,
|
||||
const unsigned char * const buffer, const unsigned len)
|
||||
{
|
||||
int clen;
|
||||
char *cbuf, *c;
|
||||
uint32_t word, hextet;
|
||||
int i;
|
||||
|
||||
clen = base64_encoded_len(ctx, len);
|
||||
cbuf = xmpp_alloc(ctx, clen + 1);
|
||||
if (cbuf != NULL) {
|
||||
c = cbuf;
|
||||
/* loop over data, turning every 3 bytes into 4 characters */
|
||||
for (i = 0; i < len - 2; i += 3) {
|
||||
word = buffer[i] << 16 | buffer[i+1] << 8 | buffer[i+2];
|
||||
hextet = (word & 0x00FC0000) >> 18;
|
||||
*c++ = _base64_charmap[hextet];
|
||||
hextet = (word & 0x0003F000) >> 12;
|
||||
*c++ = _base64_charmap[hextet];
|
||||
hextet = (word & 0x00000FC0) >> 6;
|
||||
*c++ = _base64_charmap[hextet];
|
||||
hextet = (word & 0x000003F);
|
||||
*c++ = _base64_charmap[hextet];
|
||||
}
|
||||
/* zero, one or two bytes left */
|
||||
switch (len - i) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
hextet = (buffer[len-1] & 0xFC) >> 2;
|
||||
*c++ = _base64_charmap[hextet];
|
||||
hextet = (buffer[len-1] & 0x03) << 4;
|
||||
*c++ = _base64_charmap[hextet];
|
||||
*c++ = _base64_charmap[64]; /* pad */
|
||||
*c++ = _base64_charmap[64]; /* pad */
|
||||
break;
|
||||
case 2:
|
||||
hextet = (buffer[len-2] & 0xFC) >> 2;
|
||||
*c++ = _base64_charmap[hextet];
|
||||
hextet = ((buffer[len-2] & 0x03) << 4) |
|
||||
((buffer[len-1] & 0xF0) >> 4);
|
||||
*c++ = _base64_charmap[hextet];
|
||||
hextet = (buffer[len-1] & 0x0F) << 2;
|
||||
*c++ = _base64_charmap[hextet];
|
||||
*c++ = _base64_charmap[64]; /* pad */
|
||||
break;
|
||||
}
|
||||
/* add a terminal null */
|
||||
*c = '\0';
|
||||
}
|
||||
|
||||
return cbuf;
|
||||
}
|
||||
|
||||
int base64_decoded_len(xmpp_ctx_t *ctx,
|
||||
const char * const buffer, const unsigned len)
|
||||
{
|
||||
int nudge;
|
||||
int c;
|
||||
|
||||
/* count the padding characters for the remainder */
|
||||
nudge = -1;
|
||||
c = _base64_invcharmap[(int)buffer[len-1]];
|
||||
if (c < 64) nudge = 0;
|
||||
else if (c == 64) {
|
||||
c = _base64_invcharmap[(int)buffer[len-2]];
|
||||
if (c < 64) nudge = 1;
|
||||
else if (c == 64) {
|
||||
c = _base64_invcharmap[(int)buffer[len-3]];
|
||||
if (c < 64) nudge = 2;
|
||||
}
|
||||
}
|
||||
if (nudge < 0) return 0; /* reject bad coding */
|
||||
|
||||
/* decoded steam is 3 bytes for every four */
|
||||
return 3 * (len >> 2) - nudge;
|
||||
}
|
||||
|
||||
unsigned char *base64_decode(xmpp_ctx_t *ctx,
|
||||
const char * const buffer, const unsigned len)
|
||||
{
|
||||
int dlen;
|
||||
unsigned char *dbuf, *d;
|
||||
uint32_t word, hextet;
|
||||
int i;
|
||||
|
||||
/* len must be a multiple of 4 */
|
||||
if (len & 0x03) return NULL;
|
||||
|
||||
dlen = base64_decoded_len(ctx, buffer, len);
|
||||
dbuf = xmpp_alloc(ctx, dlen + 1);
|
||||
if (dbuf != NULL) {
|
||||
d = dbuf;
|
||||
/* loop over each set of 4 characters, decoding 3 bytes */
|
||||
for (i = 0; i < len - 3; i += 4) {
|
||||
hextet = _base64_invcharmap[(int)buffer[i]];
|
||||
if (hextet & 0xC0) break;
|
||||
word = hextet << 18;
|
||||
hextet = _base64_invcharmap[(int)buffer[i+1]];
|
||||
if (hextet & 0xC0) break;
|
||||
word |= hextet << 12;
|
||||
hextet = _base64_invcharmap[(int)buffer[i+2]];
|
||||
if (hextet & 0xC0) break;
|
||||
word |= hextet << 6;
|
||||
hextet = _base64_invcharmap[(int)buffer[i+3]];
|
||||
if (hextet & 0xC0) break;
|
||||
word |= hextet;
|
||||
*d++ = (word & 0x00FF0000) >> 16;
|
||||
*d++ = (word & 0x0000FF00) >> 8;
|
||||
*d++ = (word & 0x000000FF);
|
||||
}
|
||||
if (hextet > 64) goto _base64_decode_error;
|
||||
/* handle the remainder */
|
||||
switch (dlen % 3) {
|
||||
case 0:
|
||||
/* nothing to do */
|
||||
break;
|
||||
case 1:
|
||||
/* redo the last quartet, checking for correctness */
|
||||
hextet = _base64_invcharmap[(int)buffer[len-4]];
|
||||
if (hextet & 0xC0) goto _base64_decode_error;
|
||||
word = hextet << 2;
|
||||
hextet = _base64_invcharmap[(int)buffer[len-3]];
|
||||
if (hextet & 0xC0) goto _base64_decode_error;
|
||||
word |= hextet >> 4;
|
||||
*d++ = word & 0xFF;
|
||||
hextet = _base64_invcharmap[(int)buffer[len-2]];
|
||||
if (hextet != 64) goto _base64_decode_error;
|
||||
hextet = _base64_invcharmap[(int)buffer[len-1]];
|
||||
if (hextet != 64) goto _base64_decode_error;
|
||||
break;
|
||||
case 2:
|
||||
/* redo the last quartet, checking for correctness */
|
||||
hextet = _base64_invcharmap[(int)buffer[len-4]];
|
||||
if (hextet & 0xC0) goto _base64_decode_error;
|
||||
word = hextet << 10;
|
||||
hextet = _base64_invcharmap[(int)buffer[len-3]];
|
||||
if (hextet & 0xC0) goto _base64_decode_error;
|
||||
word |= hextet << 4;
|
||||
hextet = _base64_invcharmap[(int)buffer[len-2]];
|
||||
if (hextet & 0xC0) goto _base64_decode_error;
|
||||
word |= hextet >> 2;
|
||||
*d++ = (word & 0xFF00) >> 8;
|
||||
*d++ = (word & 0x00FF);
|
||||
hextet = _base64_invcharmap[(int)buffer[len-1]];
|
||||
if (hextet != 64) goto _base64_decode_error;
|
||||
break;
|
||||
}
|
||||
*d = '\0';
|
||||
}
|
||||
return dbuf;
|
||||
|
||||
_base64_decode_error:
|
||||
/* invalid character; abort decoding! */
|
||||
xmpp_free(ctx, dbuf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*** self tests ***/
|
||||
#ifdef TEST
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int test_charmap_identity(void)
|
||||
{
|
||||
int i, v, u;
|
||||
|
||||
for (i = 0; i < 65; i++) {
|
||||
v = _base64_charmap[i];
|
||||
if (v > 255) return 1;
|
||||
u = _base64_invcharmap[v];
|
||||
/* printf("map: %d -> %d -> %d\n", i, v, u); */
|
||||
if (u != i) return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test_charmap_range(void)
|
||||
{
|
||||
int i, v;
|
||||
|
||||
for (i = 64; i < 256; i++) {
|
||||
v = _base64_invcharmap[i];
|
||||
if (i < 64) return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
printf("testing charmap identity...");
|
||||
ret = test_charmap_identity();
|
||||
if (ret) return ret;
|
||||
printf(" ok.\n");
|
||||
|
||||
printf("testing charmap range...");
|
||||
ret = test_charmap_range();
|
||||
if (ret) return ret;
|
||||
printf(" ok.\n");
|
||||
|
||||
printf("no error\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* TEST */
|
||||
|
||||
14
src/sasl.h
14
src/sasl.h
@@ -27,18 +27,4 @@ char *sasl_scram_sha1(xmpp_ctx_t *ctx, const char *challenge,
|
||||
const char *first_bare, const char *jid,
|
||||
const char *password);
|
||||
|
||||
|
||||
/** Base64 encoding routines. Implemented according to RFC 3548 */
|
||||
|
||||
int base64_encoded_len(xmpp_ctx_t *ctx, const unsigned len);
|
||||
|
||||
char *base64_encode(xmpp_ctx_t *ctx,
|
||||
const unsigned char * const buffer, const unsigned len);
|
||||
|
||||
int base64_decoded_len(xmpp_ctx_t *ctx,
|
||||
const char * const buffer, const unsigned len);
|
||||
|
||||
unsigned char *base64_decode(xmpp_ctx_t *ctx,
|
||||
const char * const buffer, const unsigned len);
|
||||
|
||||
#endif /* _LIBXMPP_SASL_H__ */
|
||||
|
||||
78
src/scram.c
78
src/scram.c
@@ -24,64 +24,52 @@
|
||||
|
||||
#include "scram.h"
|
||||
|
||||
/* block size for HMAC */
|
||||
#define BLOCK_SIZE 64
|
||||
#if BLOCK_SIZE < SHA1_DIGEST_SIZE
|
||||
#error BLOCK_SIZE must not be less than SHA1_DIGEST_SIZE
|
||||
#endif
|
||||
#define HMAC_BLOCK_SIZE 64
|
||||
|
||||
static const uint8_t ipad = 0x36;
|
||||
static const uint8_t opad = 0x5C;
|
||||
|
||||
static void SHA1(const uint8_t* data, size_t len,
|
||||
uint8_t digest[SHA1_DIGEST_SIZE])
|
||||
static void crypto_HMAC_SHA1(const uint8_t *key, size_t key_len,
|
||||
const uint8_t *text, size_t len,
|
||||
uint8_t *digest)
|
||||
{
|
||||
SHA1_CTX ctx;
|
||||
SHA1_Init(&ctx);
|
||||
SHA1_Update(&ctx, data, len);
|
||||
SHA1_Final(&ctx, digest);
|
||||
}
|
||||
|
||||
static void HMAC_SHA1(const uint8_t *key, size_t key_len,
|
||||
const uint8_t *text, size_t len,
|
||||
uint8_t digest[SHA1_DIGEST_SIZE])
|
||||
{
|
||||
uint8_t key_pad[BLOCK_SIZE];
|
||||
uint8_t key_ipad[BLOCK_SIZE];
|
||||
uint8_t key_opad[BLOCK_SIZE];
|
||||
uint8_t key_pad[HMAC_BLOCK_SIZE];
|
||||
uint8_t key_ipad[HMAC_BLOCK_SIZE];
|
||||
uint8_t key_opad[HMAC_BLOCK_SIZE];
|
||||
uint8_t sha_digest[SHA1_DIGEST_SIZE];
|
||||
int i;
|
||||
SHA1_CTX ctx;
|
||||
|
||||
memset(key_pad, 0, sizeof(key_pad));
|
||||
if (key_len <= BLOCK_SIZE) {
|
||||
if (key_len <= HMAC_BLOCK_SIZE) {
|
||||
memcpy(key_pad, key, key_len);
|
||||
} else {
|
||||
/* according to RFC2104 */
|
||||
SHA1(key, key_len, key_pad);
|
||||
crypto_SHA1(key, key_len, key_pad);
|
||||
}
|
||||
|
||||
for (i = 0; i < BLOCK_SIZE; i++) {
|
||||
for (i = 0; i < HMAC_BLOCK_SIZE; i++) {
|
||||
key_ipad[i] = key_pad[i] ^ ipad;
|
||||
key_opad[i] = key_pad[i] ^ opad;
|
||||
}
|
||||
|
||||
SHA1_Init(&ctx);
|
||||
SHA1_Update(&ctx, key_ipad, BLOCK_SIZE);
|
||||
SHA1_Update(&ctx, text, len);
|
||||
SHA1_Final(&ctx, sha_digest);
|
||||
crypto_SHA1_Init(&ctx);
|
||||
crypto_SHA1_Update(&ctx, key_ipad, HMAC_BLOCK_SIZE);
|
||||
crypto_SHA1_Update(&ctx, text, len);
|
||||
crypto_SHA1_Final(&ctx, sha_digest);
|
||||
|
||||
SHA1_Init(&ctx);
|
||||
SHA1_Update(&ctx, key_opad, BLOCK_SIZE);
|
||||
SHA1_Update(&ctx, sha_digest, SHA1_DIGEST_SIZE);
|
||||
SHA1_Final(&ctx, digest);
|
||||
crypto_SHA1_Init(&ctx);
|
||||
crypto_SHA1_Update(&ctx, key_opad, HMAC_BLOCK_SIZE);
|
||||
crypto_SHA1_Update(&ctx, sha_digest, SHA1_DIGEST_SIZE);
|
||||
crypto_SHA1_Final(&ctx, digest);
|
||||
}
|
||||
|
||||
static void SCRAM_SHA1_Hi(const uint8_t *text, size_t len,
|
||||
const uint8_t *salt, size_t salt_len, uint32_t i,
|
||||
uint8_t digest[SHA1_DIGEST_SIZE])
|
||||
uint8_t *digest)
|
||||
{
|
||||
int j, k;
|
||||
int k;
|
||||
uint32_t j;
|
||||
uint8_t tmp[128];
|
||||
|
||||
static uint8_t int1[] = {0x0, 0x0, 0x0, 0x1};
|
||||
@@ -98,11 +86,11 @@ static void SCRAM_SHA1_Hi(const uint8_t *text, size_t len,
|
||||
memcpy(&tmp[salt_len], int1, sizeof(int1));
|
||||
|
||||
/* 'text' for Hi is a 'key' for HMAC */
|
||||
HMAC_SHA1(text, len, tmp, salt_len + sizeof(int1), digest);
|
||||
crypto_HMAC_SHA1(text, len, tmp, salt_len + sizeof(int1), digest);
|
||||
memcpy(tmp, digest, SHA1_DIGEST_SIZE);
|
||||
|
||||
for (j = 1; j < i; j++) {
|
||||
HMAC_SHA1(text, len, tmp, SHA1_DIGEST_SIZE, tmp);
|
||||
crypto_HMAC_SHA1(text, len, tmp, SHA1_DIGEST_SIZE, tmp);
|
||||
for (k = 0; k < SHA1_DIGEST_SIZE; k++) {
|
||||
digest[k] ^= tmp[k];
|
||||
}
|
||||
@@ -111,30 +99,30 @@ static void SCRAM_SHA1_Hi(const uint8_t *text, size_t len,
|
||||
|
||||
void SCRAM_SHA1_ClientKey(const uint8_t *password, size_t len,
|
||||
const uint8_t *salt, size_t salt_len, uint32_t i,
|
||||
uint8_t key[SHA1_DIGEST_SIZE])
|
||||
uint8_t *key)
|
||||
{
|
||||
uint8_t salted[SHA1_DIGEST_SIZE];
|
||||
|
||||
/* XXX: Normalize(password) is omitted */
|
||||
|
||||
SCRAM_SHA1_Hi(password, len, salt, salt_len, i, salted);
|
||||
HMAC_SHA1(salted, SHA1_DIGEST_SIZE, (uint8_t *)"Client Key",
|
||||
strlen("Client Key"), key);
|
||||
crypto_HMAC_SHA1(salted, SHA1_DIGEST_SIZE, (uint8_t *)"Client Key",
|
||||
strlen("Client Key"), key);
|
||||
}
|
||||
|
||||
void SCRAM_SHA1_ClientSignature(const uint8_t ClientKey[SHA1_DIGEST_SIZE],
|
||||
void SCRAM_SHA1_ClientSignature(const uint8_t *ClientKey,
|
||||
const uint8_t *AuthMessage, size_t len,
|
||||
uint8_t sign[SHA1_DIGEST_SIZE])
|
||||
uint8_t *sign)
|
||||
{
|
||||
uint8_t stored[SHA1_DIGEST_SIZE];
|
||||
|
||||
SHA1(ClientKey, SHA1_DIGEST_SIZE, stored);
|
||||
HMAC_SHA1(stored, SHA1_DIGEST_SIZE, AuthMessage, len, sign);
|
||||
crypto_SHA1(ClientKey, SHA1_DIGEST_SIZE, stored);
|
||||
crypto_HMAC_SHA1(stored, SHA1_DIGEST_SIZE, AuthMessage, len, sign);
|
||||
}
|
||||
|
||||
void SCRAM_SHA1_ClientProof(const uint8_t ClientKey[SHA1_DIGEST_SIZE],
|
||||
const uint8_t ClientSignature[SHA1_DIGEST_SIZE],
|
||||
uint8_t proof[SHA1_DIGEST_SIZE])
|
||||
void SCRAM_SHA1_ClientProof(const uint8_t *ClientKey,
|
||||
const uint8_t *ClientSignature,
|
||||
uint8_t *proof)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < SHA1_DIGEST_SIZE; i++) {
|
||||
|
||||
12
src/scram.h
12
src/scram.h
@@ -23,14 +23,14 @@
|
||||
|
||||
void SCRAM_SHA1_ClientKey(const uint8_t *password, size_t len,
|
||||
const uint8_t *salt, size_t salt_len, uint32_t i,
|
||||
uint8_t key[SHA1_DIGEST_SIZE]);
|
||||
uint8_t *key);
|
||||
|
||||
void SCRAM_SHA1_ClientSignature(const uint8_t ClientKey[SHA1_DIGEST_SIZE],
|
||||
void SCRAM_SHA1_ClientSignature(const uint8_t *ClientKey,
|
||||
const uint8_t *AuthMessage, size_t len,
|
||||
uint8_t sign[SHA1_DIGEST_SIZE]);
|
||||
uint8_t *sign);
|
||||
|
||||
void SCRAM_SHA1_ClientProof(const uint8_t ClientKey[SHA1_DIGEST_SIZE],
|
||||
const uint8_t ClientSignature[SHA1_DIGEST_SIZE],
|
||||
uint8_t proof[SHA1_DIGEST_SIZE]);
|
||||
void SCRAM_SHA1_ClientProof(const uint8_t *ClientKey,
|
||||
const uint8_t *ClientSignature,
|
||||
uint8_t *proof);
|
||||
|
||||
#endif /* __LIBSTROPHE_SCRAM_H__ */
|
||||
|
||||
172
src/sha1.c
172
src/sha1.c
@@ -70,26 +70,14 @@ use SHA1_ prefix for public api
|
||||
move public api to sha1.h
|
||||
*/
|
||||
|
||||
/*
|
||||
Test Vectors (from FIPS PUB 180-1)
|
||||
"abc"
|
||||
A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
|
||||
"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
|
||||
84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
|
||||
A million repetitions of "a"
|
||||
34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
|
||||
*/
|
||||
|
||||
/* #define SHA1HANDSOFF */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
/* make sure the stdint.h types are available */
|
||||
#include "ostypes.h"
|
||||
|
||||
#include "sha1.h"
|
||||
|
||||
/* Don't change user's data */
|
||||
#define SHA1HANDSOFF
|
||||
|
||||
static uint32_t host_to_be(uint32_t i);
|
||||
static void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64]);
|
||||
|
||||
@@ -109,19 +97,6 @@ static void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64]);
|
||||
#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
|
||||
|
||||
|
||||
#ifdef VERBOSE /* SAK */
|
||||
void SHAPrintContext(SHA1_CTX *context, char *msg){
|
||||
printf("%s (%d,%d) %x %x %x %x %x\n",
|
||||
msg,
|
||||
context->count[0], context->count[1],
|
||||
context->state[0],
|
||||
context->state[1],
|
||||
context->state[2],
|
||||
context->state[3],
|
||||
context->state[4]);
|
||||
}
|
||||
#endif /* VERBOSE */
|
||||
|
||||
static uint32_t host_to_be(uint32_t i)
|
||||
{
|
||||
#define le_to_be(i) ((rol((i),24) & 0xFF00FF00) | (rol((i),8) & 0x00FF00FF))
|
||||
@@ -140,6 +115,7 @@ static uint32_t host_to_be(uint32_t i)
|
||||
} check = {1};
|
||||
return check.c ? le_to_be(i) : i;
|
||||
#endif
|
||||
#undef le_to_be
|
||||
}
|
||||
|
||||
/* Hash a single 512-bit block. This is the core of the algorithm. */
|
||||
@@ -202,7 +178,7 @@ static void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64])
|
||||
|
||||
|
||||
/* SHA1Init - Initialize new context */
|
||||
void SHA1_Init(SHA1_CTX* context)
|
||||
void crypto_SHA1_Init(SHA1_CTX* context)
|
||||
{
|
||||
/* SHA1 initialization constants */
|
||||
context->state[0] = 0x67452301;
|
||||
@@ -215,14 +191,11 @@ void SHA1_Init(SHA1_CTX* context)
|
||||
|
||||
|
||||
/* Run your data through this. */
|
||||
void SHA1_Update(SHA1_CTX* context, const uint8_t* data, const size_t len)
|
||||
void crypto_SHA1_Update(SHA1_CTX* context, const uint8_t* data,
|
||||
const size_t len)
|
||||
{
|
||||
size_t i, j;
|
||||
|
||||
#ifdef VERBOSE
|
||||
SHAPrintContext(context, "before");
|
||||
#endif
|
||||
|
||||
j = (context->count[0] >> 3) & 63;
|
||||
if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++;
|
||||
context->count[1] += (len >> 29);
|
||||
@@ -236,15 +209,11 @@ void SHA1_Update(SHA1_CTX* context, const uint8_t* data, const size_t len)
|
||||
}
|
||||
else i = 0;
|
||||
memcpy(&context->buffer[j], &data[i], len - i);
|
||||
|
||||
#ifdef VERBOSE
|
||||
SHAPrintContext(context, "after ");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/* Add padding and return the message digest. */
|
||||
void SHA1_Final(SHA1_CTX* context, uint8_t digest[SHA1_DIGEST_SIZE])
|
||||
void crypto_SHA1_Final(SHA1_CTX* context, uint8_t* digest)
|
||||
{
|
||||
uint32_t i;
|
||||
uint8_t finalcount[8];
|
||||
@@ -253,11 +222,11 @@ void SHA1_Final(SHA1_CTX* context, uint8_t digest[SHA1_DIGEST_SIZE])
|
||||
finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
|
||||
>> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */
|
||||
}
|
||||
SHA1_Update(context, (uint8_t *)"\200", 1);
|
||||
crypto_SHA1_Update(context, (uint8_t *)"\200", 1);
|
||||
while ((context->count[0] & 504) != 448) {
|
||||
SHA1_Update(context, (uint8_t *)"\0", 1);
|
||||
crypto_SHA1_Update(context, (uint8_t *)"\0", 1);
|
||||
}
|
||||
SHA1_Update(context, finalcount, 8); /* Should cause a SHA1_Transform() */
|
||||
crypto_SHA1_Update(context, finalcount, 8); /* Should cause a SHA1_Transform() */
|
||||
for (i = 0; i < SHA1_DIGEST_SIZE; i++) {
|
||||
digest[i] = (uint8_t)
|
||||
((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
|
||||
@@ -274,119 +243,12 @@ void SHA1_Final(SHA1_CTX* context, uint8_t digest[SHA1_DIGEST_SIZE])
|
||||
SHA1_Transform(context->state, context->buffer);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*************************************************************/
|
||||
|
||||
#if 0
|
||||
int main(int argc, char** argv)
|
||||
|
||||
void crypto_SHA1(const uint8_t* data, size_t len, uint8_t* digest)
|
||||
{
|
||||
int i, j;
|
||||
SHA1_CTX context;
|
||||
unsigned char digest[SHA1_DIGEST_SIZE], buffer[16384];
|
||||
FILE* file;
|
||||
|
||||
if (argc > 2) {
|
||||
puts("Public domain SHA-1 implementation - by Steve Reid <sreid@sea-to-sky.net>");
|
||||
puts("Modified for 16 bit environments 7/98 - by James H. Brown <jbrown@burgoyne.com>"); /* JHB */
|
||||
puts("Produces the SHA-1 hash of a file, or stdin if no file is specified.");
|
||||
return(0);
|
||||
}
|
||||
if (argc < 2) {
|
||||
file = stdin;
|
||||
}
|
||||
else {
|
||||
if (!(file = fopen(argv[1], "rb"))) {
|
||||
fputs("Unable to open file.", stderr);
|
||||
return(-1);
|
||||
}
|
||||
}
|
||||
SHA1_Init(&context);
|
||||
while (!feof(file)) { /* note: what if ferror(file) */
|
||||
i = fread(buffer, 1, 16384, file);
|
||||
SHA1_Update(&context, buffer, i);
|
||||
}
|
||||
SHA1_Final(&context, digest);
|
||||
fclose(file);
|
||||
for (i = 0; i < SHA1_DIGEST_SIZE/4; i++) {
|
||||
for (j = 0; j < 4; j++) {
|
||||
printf("%02X", digest[i*4+j]);
|
||||
}
|
||||
putchar(' ');
|
||||
}
|
||||
putchar('\n');
|
||||
return(0); /* JHB */
|
||||
SHA1_CTX ctx;
|
||||
crypto_SHA1_Init(&ctx);
|
||||
crypto_SHA1_Update(&ctx, data, len);
|
||||
crypto_SHA1_Final(&ctx, digest);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* self test */
|
||||
|
||||
#ifdef TEST
|
||||
|
||||
static char *test_data[] = {
|
||||
"abc",
|
||||
"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
|
||||
"A million repetitions of 'a'"};
|
||||
static char *test_results[] = {
|
||||
"A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D",
|
||||
"84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1",
|
||||
"34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F"};
|
||||
|
||||
|
||||
void digest_to_hex(const uint8_t digest[SHA1_DIGEST_SIZE], char *output)
|
||||
{
|
||||
int i,j;
|
||||
char *c = output;
|
||||
|
||||
for (i = 0; i < SHA1_DIGEST_SIZE/4; i++) {
|
||||
for (j = 0; j < 4; j++) {
|
||||
sprintf(c,"%02X", digest[i*4+j]);
|
||||
c += 2;
|
||||
}
|
||||
sprintf(c, " ");
|
||||
c += 1;
|
||||
}
|
||||
*(c - 1) = '\0';
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
int k;
|
||||
SHA1_CTX context;
|
||||
uint8_t digest[20];
|
||||
char output[80];
|
||||
|
||||
fprintf(stdout, "verifying SHA-1 implementation... ");
|
||||
|
||||
for (k = 0; k < 2; k++){
|
||||
SHA1_Init(&context);
|
||||
SHA1_Update(&context, (uint8_t*)test_data[k], strlen(test_data[k]));
|
||||
SHA1_Final(&context, digest);
|
||||
digest_to_hex(digest, output);
|
||||
|
||||
if (strcmp(output, test_results[k])) {
|
||||
fprintf(stdout, "FAIL\n");
|
||||
fprintf(stderr,"* hash of \"%s\" incorrect:\n", test_data[k]);
|
||||
fprintf(stderr,"\t%s returned\n", output);
|
||||
fprintf(stderr,"\t%s is correct\n", test_results[k]);
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
/* million 'a' vector we feed separately */
|
||||
SHA1_Init(&context);
|
||||
for (k = 0; k < 1000000; k++)
|
||||
SHA1_Update(&context, (uint8_t*)"a", 1);
|
||||
SHA1_Final(&context, digest);
|
||||
digest_to_hex(digest, output);
|
||||
if (strcmp(output, test_results[2])) {
|
||||
fprintf(stdout, "FAIL\n");
|
||||
fprintf(stderr,"* hash of \"%s\" incorrect:\n", test_data[2]);
|
||||
fprintf(stderr,"\t%s returned\n", output);
|
||||
fprintf(stderr,"\t%s is correct\n", test_results[2]);
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* success */
|
||||
fprintf(stdout, "ok\n");
|
||||
return(0);
|
||||
}
|
||||
#endif /* TEST */
|
||||
|
||||
14
src/sha1.h
14
src/sha1.h
@@ -5,8 +5,8 @@
|
||||
* SHA-1 hash API.
|
||||
*/
|
||||
|
||||
#ifndef __SHA1_H
|
||||
#define __SHA1_H
|
||||
#ifndef __LIBSTROPHE_SHA1_H__
|
||||
#define __LIBSTROPHE_SHA1_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -23,12 +23,14 @@ typedef struct {
|
||||
|
||||
#define SHA1_DIGEST_SIZE 20
|
||||
|
||||
void SHA1_Init(SHA1_CTX* context);
|
||||
void SHA1_Update(SHA1_CTX* context, const uint8_t* data, const size_t len);
|
||||
void SHA1_Final(SHA1_CTX* context, uint8_t digest[SHA1_DIGEST_SIZE]);
|
||||
void crypto_SHA1_Init(SHA1_CTX* context);
|
||||
void crypto_SHA1_Update(SHA1_CTX* context, const uint8_t* data,
|
||||
const size_t len);
|
||||
void crypto_SHA1_Final(SHA1_CTX* context, uint8_t* digest);
|
||||
void crypto_SHA1(const uint8_t* data, size_t len, uint8_t* digest);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __SHA1_H */
|
||||
#endif /* __LIBSTROPHE_SHA1_H__ */
|
||||
|
||||
140
src/snprintf.c
140
src/snprintf.c
@@ -64,49 +64,27 @@
|
||||
/* JAM: changed declarations to xmpp_snprintf and xmpp_vsnprintf to
|
||||
avoid namespace collision. */
|
||||
|
||||
#if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF)
|
||||
#include "snprintf.h"
|
||||
|
||||
/* varargs declarations: */
|
||||
|
||||
#include <stdarg.h>
|
||||
#define VA_LOCAL_DECL va_list ap
|
||||
#define VA_START(f) va_start(ap, f)
|
||||
#define VA_END va_end(ap)
|
||||
|
||||
#ifndef HAVE_VSNPRINTF
|
||||
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
/* Define this as a fall through, HAVE_STDARG_H is probably already set */
|
||||
|
||||
#define HAVE_VARARGS_H
|
||||
#define HAVE_STDARG_H /* JAM: set always */
|
||||
|
||||
|
||||
/* varargs declarations: */
|
||||
|
||||
#if defined(HAVE_STDARG_H)
|
||||
# include <stdarg.h>
|
||||
# define HAVE_STDARGS /* let's hope that works everywhere (mj) */
|
||||
# define VA_LOCAL_DECL va_list ap
|
||||
# define VA_START(f) va_start(ap, f)
|
||||
# define VA_SHIFT(v,t) ; /* no-op for ANSI */
|
||||
# define VA_END va_end(ap)
|
||||
#else
|
||||
# if defined(HAVE_VARARGS_H)
|
||||
# include <varargs.h>
|
||||
# undef HAVE_STDARGS
|
||||
# define VA_LOCAL_DECL va_list ap
|
||||
# define VA_START(f) va_start(ap) /* f is ignored! */
|
||||
# define VA_SHIFT(v,t) v = va_arg(ap,t)
|
||||
# define VA_END va_end(ap)
|
||||
# else
|
||||
/*XX ** NO VARARGS ** XX*/
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LONG_DOUBLE
|
||||
#define LDOUBLE long double
|
||||
#else
|
||||
#define LDOUBLE double
|
||||
#endif
|
||||
|
||||
int xmpp_snprintf (char *str, size_t count, const char *fmt, ...);
|
||||
int xmpp_vsnprintf (char *str, size_t count, const char *fmt, va_list arg);
|
||||
|
||||
static int dopr (char *buffer, size_t maxlen, const char *format,
|
||||
va_list args);
|
||||
static int fmtstr (char *buffer, size_t *currlen, size_t maxlen,
|
||||
@@ -308,6 +286,7 @@ static int dopr (char *buffer, size_t maxlen, const char *format, va_list args)
|
||||
break;
|
||||
case 'X':
|
||||
flags |= DP_F_UP;
|
||||
//-fallthrough
|
||||
case 'x':
|
||||
flags |= DP_F_UNSIGNED;
|
||||
if (cflags == DP_C_SHORT)
|
||||
@@ -328,6 +307,7 @@ static int dopr (char *buffer, size_t maxlen, const char *format, va_list args)
|
||||
break;
|
||||
case 'E':
|
||||
flags |= DP_F_UP;
|
||||
//-fallthrough
|
||||
case 'e':
|
||||
if (cflags == DP_C_LDOUBLE)
|
||||
fvalue = va_arg (args, LDOUBLE);
|
||||
@@ -336,6 +316,7 @@ static int dopr (char *buffer, size_t maxlen, const char *format, va_list args)
|
||||
break;
|
||||
case 'G':
|
||||
flags |= DP_F_UP;
|
||||
//-fallthrough
|
||||
case 'g':
|
||||
if (cflags == DP_C_LDOUBLE)
|
||||
fvalue = va_arg (args, LDOUBLE);
|
||||
@@ -397,7 +378,7 @@ static int dopr (char *buffer, size_t maxlen, const char *format, va_list args)
|
||||
break; /* some picky compilers need this */
|
||||
}
|
||||
}
|
||||
if (buffer != NULL)
|
||||
if (buffer != NULL && maxlen > 0)
|
||||
{
|
||||
if (currlen < maxlen - 1)
|
||||
buffer[currlen] = '\0';
|
||||
@@ -725,10 +706,9 @@ static int dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c)
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifndef HAVE_VSNPRINTF
|
||||
int xmpp_vsnprintf (char *str, size_t count, const char *fmt, va_list args)
|
||||
{
|
||||
if (str != NULL)
|
||||
if (str != NULL && count > 0)
|
||||
str[0] = 0;
|
||||
return dopr(str, count, fmt, args);
|
||||
}
|
||||
@@ -736,104 +716,14 @@ int xmpp_vsnprintf (char *str, size_t count, const char *fmt, va_list args)
|
||||
|
||||
#ifndef HAVE_SNPRINTF
|
||||
/* VARARGS3 */
|
||||
#ifdef HAVE_STDARGS
|
||||
int xmpp_snprintf (char *str,size_t count,const char *fmt,...)
|
||||
#else
|
||||
int xmpp_snprintf (va_alist) va_dcl
|
||||
#endif
|
||||
{
|
||||
#ifndef HAVE_STDARGS
|
||||
char *str;
|
||||
size_t count;
|
||||
char *fmt;
|
||||
#endif
|
||||
VA_LOCAL_DECL;
|
||||
int total;
|
||||
|
||||
VA_START (fmt);
|
||||
VA_SHIFT (str, char *);
|
||||
VA_SHIFT (count, size_t );
|
||||
VA_SHIFT (fmt, char *);
|
||||
total = xmpp_vsnprintf(str, count, fmt, ap);
|
||||
VA_END;
|
||||
return total;
|
||||
}
|
||||
#endif /* !HAVE_SNPRINTF */
|
||||
|
||||
#ifdef TEST_SNPRINTF
|
||||
#ifndef LONG_STRING
|
||||
#define LONG_STRING 1024
|
||||
#endif
|
||||
int main (void)
|
||||
{
|
||||
char buf1[LONG_STRING];
|
||||
char buf2[LONG_STRING];
|
||||
char *fp_fmt[] = {
|
||||
"%-1.5f",
|
||||
"%1.5f",
|
||||
"%123.9f",
|
||||
"%10.5f",
|
||||
"% 10.5f",
|
||||
"%+22.9f",
|
||||
"%+4.9f",
|
||||
"%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",
|
||||
NULL
|
||||
};
|
||||
long int_nums[] = { -1, 134, 91340, 341, 0203, 0};
|
||||
int x, y;
|
||||
int fail = 0;
|
||||
int num = 0;
|
||||
|
||||
printf ("Testing xmpp_snprintf format codes against system sprintf...\n");
|
||||
|
||||
for (x = 0; fp_fmt[x] != NULL ; x++)
|
||||
for (y = 0; fp_nums[y] != 0 ; y++)
|
||||
{
|
||||
xmpp_snprintf (buf1, sizeof (buf1), fp_fmt[x], fp_nums[y]);
|
||||
sprintf (buf2, fp_fmt[x], fp_nums[y]);
|
||||
if (strcmp (buf1, buf2))
|
||||
{
|
||||
printf("xmpp_snprintf doesn't match Format: %s\n\txmpp_snprintf = %s\n\tsprintf = %s\n",
|
||||
fp_fmt[x], buf1, buf2);
|
||||
fail++;
|
||||
}
|
||||
num++;
|
||||
}
|
||||
|
||||
for (x = 0; int_fmt[x] != NULL ; x++)
|
||||
for (y = 0; int_nums[y] != 0 ; y++)
|
||||
{
|
||||
xmpp_snprintf (buf1, sizeof (buf1), int_fmt[x], int_nums[y]);
|
||||
sprintf (buf2, int_fmt[x], int_nums[y]);
|
||||
if (strcmp (buf1, buf2))
|
||||
{
|
||||
printf("xmpp_snprintf doesn't match Format: %s\n\txmpp_snprintf = %s\n\tsprintf = %s\n",
|
||||
int_fmt[x], buf1, buf2);
|
||||
fail++;
|
||||
}
|
||||
num++;
|
||||
}
|
||||
printf ("%d tests failed out of %d.\n", fail, num);
|
||||
}
|
||||
#endif /* SNPRINTF_TEST */
|
||||
|
||||
#endif /* !HAVE_SNPRINTF */
|
||||
|
||||
34
src/snprintf.h
Normal file
34
src/snprintf.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright Patrick Powell 1995
|
||||
* This code is based on code written by Patrick Powell (papowell@astart.com)
|
||||
* It may be used for any purpose as long as this notice remains intact
|
||||
* on all source code distributions
|
||||
*/
|
||||
|
||||
/** @file
|
||||
* Compatibility wrappers for OSes lacking snprintf(3) and/or vsnprintf(3).
|
||||
*/
|
||||
|
||||
#ifndef __LIBSTROPHE_SNPRINTF_H__
|
||||
#define __LIBSTROPHE_SNPRINTF_H__
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#if defined(HAVE_SNPRINTF) || defined(HAVE_VSNPRINTF)
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SNPRINTF
|
||||
#define xmpp_snprintf snprintf
|
||||
#else
|
||||
int xmpp_snprintf(char *str, size_t count, const char *fmt, ...);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_VSNPRINTF
|
||||
#define xmpp_vsnprintf vsnprintf
|
||||
#else
|
||||
int xmpp_vsnprintf(char *str, size_t count, const char *fmt, va_list arg);
|
||||
#endif
|
||||
|
||||
#endif /* __LIBSTROPHE_SNPRINTF_H__ */
|
||||
838
src/sock.c
838
src/sock.c
@@ -21,24 +21,20 @@
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <windns.h>
|
||||
#include <Iphlpapi.h>
|
||||
#define snprintf _snprintf
|
||||
#include <Mstcpip.h> /* tcp_keepalive */
|
||||
#else
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <netdb.h>
|
||||
#include <fcntl.h>
|
||||
#include <arpa/nameser.h>
|
||||
#ifdef HAVE_ARPA_NAMESER_COMPAT_H
|
||||
#include <arpa/nameser_compat.h>
|
||||
#endif
|
||||
#include <resolv.h>
|
||||
#endif
|
||||
|
||||
#include "sock.h"
|
||||
#include "snprintf.h"
|
||||
|
||||
void sock_initialize(void)
|
||||
{
|
||||
@@ -69,49 +65,90 @@ static int _in_progress(int error)
|
||||
#ifdef _WIN32
|
||||
return (error == WSAEWOULDBLOCK || error == WSAEINPROGRESS);
|
||||
#else
|
||||
return (errno == EINPROGRESS);
|
||||
return (error == EINPROGRESS);
|
||||
#endif
|
||||
}
|
||||
|
||||
sock_t sock_connect(const char * const host, const unsigned int port)
|
||||
sock_t sock_connect(const char * const host, const unsigned short port)
|
||||
{
|
||||
sock_t sock;
|
||||
char service[6];
|
||||
struct addrinfo *res, *ainfo, hints;
|
||||
int err;
|
||||
|
||||
sock = -1;
|
||||
|
||||
snprintf(service, 6, "%u", port);
|
||||
xmpp_snprintf(service, 6, "%u", port);
|
||||
|
||||
memset(&hints, 0, sizeof(struct addrinfo));
|
||||
hints.ai_family = AF_INET;
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
#ifdef AI_ADDRCONFIG
|
||||
hints.ai_flags = AI_ADDRCONFIG;
|
||||
#endif /* AI_ADDRCONFIG */
|
||||
hints.ai_protocol = IPPROTO_TCP;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
|
||||
if ((err = getaddrinfo(host, service, &hints, &res)) != 0)
|
||||
return -1;
|
||||
err = getaddrinfo(host, service, &hints, &res);
|
||||
if (err != 0)
|
||||
return -1;
|
||||
|
||||
ainfo = res;
|
||||
while (ainfo) {
|
||||
if ((sock = socket(ainfo->ai_family, ainfo->ai_socktype,
|
||||
ainfo->ai_protocol)) >= 0) {
|
||||
sock_set_nonblocking(sock);
|
||||
for (ainfo = res; ainfo != NULL; ainfo = ainfo->ai_next) {
|
||||
sock = socket(ainfo->ai_family, ainfo->ai_socktype, ainfo->ai_protocol);
|
||||
if (sock < 0)
|
||||
continue;
|
||||
|
||||
err = connect(sock, ainfo->ai_addr, ainfo->ai_addrlen);
|
||||
|
||||
if ((err == 0) || (err < 0 && _in_progress(sock_error())))
|
||||
break;
|
||||
}
|
||||
|
||||
ainfo = ainfo->ai_next;
|
||||
err = sock_set_nonblocking(sock);
|
||||
if (err == 0) {
|
||||
err = connect(sock, ainfo->ai_addr, ainfo->ai_addrlen);
|
||||
if (err == 0 || _in_progress(sock_error()))
|
||||
break;
|
||||
}
|
||||
sock_close(sock);
|
||||
}
|
||||
|
||||
if (res) freeaddrinfo(res);
|
||||
freeaddrinfo(res);
|
||||
sock = ainfo == NULL ? -1 : sock;
|
||||
|
||||
return sock;
|
||||
}
|
||||
|
||||
int sock_set_keepalive(const sock_t sock, int timeout, int interval)
|
||||
{
|
||||
int ret;
|
||||
int optval = (timeout && interval) ? 1 : 0;
|
||||
|
||||
/* This function doesn't change maximum number of keepalive probes */
|
||||
|
||||
#ifdef _WIN32
|
||||
struct tcp_keepalive ka;
|
||||
DWORD dw = 0;
|
||||
|
||||
ka.onoff = optval;
|
||||
ka.keepalivetime = timeout * 1000;
|
||||
ka.keepaliveinterval = interval * 1000;
|
||||
ret = WSAIoctl(sock, SIO_KEEPALIVE_VALS, &ka, sizeof(ka), NULL, 0, &dw, NULL, NULL);
|
||||
#else
|
||||
ret = setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (optval) {
|
||||
#ifdef TCP_KEEPIDLE
|
||||
ret = setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, &timeout, sizeof(timeout));
|
||||
#elif defined(TCP_KEEPALIVE)
|
||||
/* QNX receives `struct timeval' as argument, but it seems OSX does int */
|
||||
ret = setsockopt(sock, IPPROTO_TCP, TCP_KEEPALIVE, &timeout, sizeof(timeout));
|
||||
#endif /* TCP_KEEPIDLE */
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
#ifdef TCP_KEEPINTVL
|
||||
ret = setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, &interval, sizeof(interval));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
#endif /* TCP_KEEPINTVL */
|
||||
}
|
||||
#endif /* _WIN32 */
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int sock_close(const sock_t sock)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
@@ -127,7 +164,13 @@ int sock_set_blocking(const sock_t sock)
|
||||
u_long block = 0;
|
||||
return ioctlsocket(sock, FIONBIO, &block);
|
||||
#else
|
||||
return fcntl(sock, F_SETFL, 0);
|
||||
int rc;
|
||||
|
||||
rc = fcntl(sock, F_GETFL, NULL);
|
||||
if (rc >= 0) {
|
||||
rc = fcntl(sock, F_SETFL, rc & (~O_NONBLOCK));
|
||||
}
|
||||
return rc;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -137,7 +180,13 @@ int sock_set_nonblocking(const sock_t sock)
|
||||
u_long nonblock = 1;
|
||||
return ioctlsocket(sock, FIONBIO, &nonblock);
|
||||
#else
|
||||
return fcntl(sock, F_SETFL, O_NONBLOCK);
|
||||
int rc;
|
||||
|
||||
rc = fcntl(sock, F_GETFL, NULL);
|
||||
if (rc >= 0) {
|
||||
rc = fcntl(sock, F_SETFL, rc | O_NONBLOCK);
|
||||
}
|
||||
return rc;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -155,7 +204,7 @@ int sock_is_recoverable(const int error)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return (error == WSAEINTR || error == WSAEWOULDBLOCK ||
|
||||
error == WSAEINPROGRESS);
|
||||
error == WSAEINPROGRESS);
|
||||
#else
|
||||
return (error == EAGAIN || error == EINTR);
|
||||
#endif
|
||||
@@ -164,18 +213,18 @@ int sock_is_recoverable(const int error)
|
||||
int sock_connect_error(const sock_t sock)
|
||||
{
|
||||
struct sockaddr sa;
|
||||
unsigned len;
|
||||
socklen_t len;
|
||||
char temp;
|
||||
|
||||
sa.sa_family = AF_INET;
|
||||
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.sa_family = AF_UNSPEC;
|
||||
len = sizeof(sa);
|
||||
|
||||
/* we don't actually care about the peer name, we're just checking if
|
||||
* we're connected or not */
|
||||
if (getpeername(sock, &sa, &len) == 0)
|
||||
{
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* it's possible that the error wasn't ENOTCONN, so if it wasn't,
|
||||
@@ -191,720 +240,3 @@ int sock_connect_error(const sock_t sock)
|
||||
|
||||
return sock_error();
|
||||
}
|
||||
|
||||
struct dnsquery_header
|
||||
{
|
||||
unsigned short id;
|
||||
unsigned char qr;
|
||||
unsigned char opcode;
|
||||
unsigned char aa;
|
||||
unsigned char tc;
|
||||
unsigned char rd;
|
||||
unsigned char ra;
|
||||
unsigned char z;
|
||||
unsigned char rcode;
|
||||
unsigned short qdcount;
|
||||
unsigned short ancount;
|
||||
unsigned short nscount;
|
||||
unsigned short arcount;
|
||||
};
|
||||
|
||||
struct dnsquery_question
|
||||
{
|
||||
char qname[1024];
|
||||
unsigned short qtype;
|
||||
unsigned short qclass;
|
||||
};
|
||||
|
||||
struct dnsquery_srvrdata
|
||||
{
|
||||
unsigned short priority;
|
||||
unsigned short weight;
|
||||
unsigned short port;
|
||||
char target[1024];
|
||||
};
|
||||
|
||||
struct dnsquery_resourcerecord
|
||||
{
|
||||
char name[1024];
|
||||
unsigned short type;
|
||||
unsigned short _class;
|
||||
unsigned int ttl;
|
||||
unsigned short rdlength;
|
||||
struct dnsquery_srvrdata rdata;
|
||||
};
|
||||
|
||||
|
||||
void netbuf_add_32bitnum(unsigned char *buf, int buflen, int *offset, unsigned int num)
|
||||
{
|
||||
unsigned char *start = buf + *offset;
|
||||
unsigned char *p = start;
|
||||
|
||||
/* assuming big endian */
|
||||
*p++ = (num >> 24) & 0xff;
|
||||
*p++ = (num >> 16) & 0xff;
|
||||
*p++ = (num >> 8) & 0xff;
|
||||
*p++ = (num) & 0xff;
|
||||
|
||||
*offset += 4;
|
||||
}
|
||||
|
||||
void netbuf_get_32bitnum(unsigned char *buf, int buflen, int *offset, unsigned int *num)
|
||||
{
|
||||
unsigned char *start = buf + *offset;
|
||||
unsigned char *p = start;
|
||||
*num = 0;
|
||||
|
||||
/* assuming big endian */
|
||||
*num |= (*p++) << 24;
|
||||
*num |= (*p++) << 16;
|
||||
*num |= (*p++) << 8;
|
||||
*num |= (*p++);
|
||||
|
||||
*offset += 4;
|
||||
}
|
||||
|
||||
void netbuf_add_16bitnum(unsigned char *buf, int buflen, int *offset, unsigned short num)
|
||||
{
|
||||
unsigned char *start = buf + *offset;
|
||||
unsigned char *p = start;
|
||||
|
||||
/* assuming big endian */
|
||||
*p++ = (num >> 8) & 0xff;
|
||||
*p++ = (num) & 0xff;
|
||||
|
||||
*offset += 2;
|
||||
}
|
||||
|
||||
void netbuf_get_16bitnum(unsigned char *buf, int buflen, int *offset, unsigned short *num)
|
||||
{
|
||||
unsigned char *start = buf + *offset;
|
||||
unsigned char *p = start;
|
||||
*num = 0;
|
||||
|
||||
/* assuming big endian */
|
||||
*num |= (*p++) << 8;
|
||||
*num |= (*p++);
|
||||
|
||||
*offset += 2;
|
||||
}
|
||||
|
||||
void netbuf_add_domain_name(unsigned char *buf, int buflen, int *offset,
|
||||
char *name)
|
||||
{
|
||||
unsigned char *start = buf + *offset;
|
||||
unsigned char *p = start;
|
||||
unsigned char *wordstart, *wordend;
|
||||
|
||||
wordstart = (unsigned char *)name;
|
||||
|
||||
while (*wordstart)
|
||||
{
|
||||
int len;
|
||||
wordend = wordstart;
|
||||
while (*wordend && *wordend != '.')
|
||||
{
|
||||
wordend++;
|
||||
}
|
||||
|
||||
len = (int)(wordend - wordstart);
|
||||
|
||||
if (len > 0x3F)
|
||||
{
|
||||
len = 0x3F;
|
||||
}
|
||||
|
||||
*p++ = len;
|
||||
|
||||
while (wordstart != wordend)
|
||||
{
|
||||
*p++ = *wordstart++;
|
||||
}
|
||||
|
||||
if (*wordstart == '.')
|
||||
{
|
||||
wordstart++;
|
||||
}
|
||||
}
|
||||
|
||||
*p++ = '\0';
|
||||
|
||||
*offset += p - start;
|
||||
}
|
||||
|
||||
int calc_domain_name_size(unsigned char *buf, int buflen, int offset)
|
||||
{
|
||||
unsigned char *p = buf + offset;
|
||||
int len = 0;
|
||||
|
||||
while (*p)
|
||||
{
|
||||
if ((*p & 0xC0) == 0xC0)
|
||||
{
|
||||
int newoffset = 0;
|
||||
newoffset |= (*p++ & 0x3F) << 8;
|
||||
newoffset |= *p;
|
||||
|
||||
p = buf + newoffset;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (len)
|
||||
{
|
||||
len += 1;
|
||||
}
|
||||
len += *p;
|
||||
p += *p + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
int netbuf_get_domain_name(unsigned char *buf, int buflen, int *offset, char *namebuf, int namebuflen)
|
||||
{
|
||||
unsigned char *start = buf + *offset;
|
||||
unsigned char *p, *p2;
|
||||
int *curroffset = offset;
|
||||
int len = 0;
|
||||
|
||||
*namebuf = '\0';
|
||||
|
||||
/* measure length */
|
||||
p = start;
|
||||
while (*p)
|
||||
{
|
||||
if ((*p & 0xC0) == 0xC0)
|
||||
{
|
||||
int newoffset = 0;
|
||||
newoffset |= (*p++ & 0x3F) << 8;
|
||||
newoffset |= *p++;
|
||||
|
||||
p = buf + newoffset;
|
||||
}
|
||||
else
|
||||
{
|
||||
len += *p;
|
||||
p += *p + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (namebuflen < len)
|
||||
{
|
||||
return len;
|
||||
}
|
||||
|
||||
/* actually copy in name */
|
||||
p = start;
|
||||
p2 = (unsigned char *)namebuf;
|
||||
while (*p)
|
||||
{
|
||||
if ((*p & 0xC0) == 0xC0)
|
||||
{
|
||||
int newoffset = 0;
|
||||
newoffset |= (*p++ & 0x3F) << 8;
|
||||
newoffset |= *p++;
|
||||
|
||||
if (curroffset)
|
||||
{
|
||||
*curroffset += (int)(p - start);
|
||||
curroffset = NULL;
|
||||
}
|
||||
|
||||
p = buf + newoffset;
|
||||
}
|
||||
else
|
||||
{
|
||||
int i, partlen;
|
||||
|
||||
if (*namebuf != '\0')
|
||||
{
|
||||
*p2++ = '.';
|
||||
}
|
||||
|
||||
partlen = *p++;
|
||||
|
||||
for (i=0; i < partlen; i++)
|
||||
{
|
||||
*p2++ = *p++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (curroffset)
|
||||
{
|
||||
p++;
|
||||
*curroffset += (int)(p - start);
|
||||
curroffset = NULL;
|
||||
}
|
||||
|
||||
*p2 = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void netbuf_add_dnsquery_header(unsigned char *buf, int buflen, int *offset, struct dnsquery_header *header)
|
||||
{
|
||||
unsigned char *p;
|
||||
|
||||
netbuf_add_16bitnum(buf, buflen, offset, header->id);
|
||||
|
||||
p = buf + *offset;
|
||||
*p++ = ((header->qr & 0x01) << 7)
|
||||
| ((header->opcode & 0x0F) << 3)
|
||||
| ((header->aa & 0x01) << 2)
|
||||
| ((header->tc & 0x01) << 1)
|
||||
| ((header->rd & 0x01));
|
||||
*p++ = ((header->ra & 0x01) << 7)
|
||||
| ((header->z & 0x07) << 4)
|
||||
| ((header->rcode & 0x0F));
|
||||
*offset += 2;
|
||||
|
||||
netbuf_add_16bitnum(buf, buflen, offset, header->qdcount);
|
||||
netbuf_add_16bitnum(buf, buflen, offset, header->ancount);
|
||||
netbuf_add_16bitnum(buf, buflen, offset, header->nscount);
|
||||
netbuf_add_16bitnum(buf, buflen, offset, header->arcount);
|
||||
}
|
||||
|
||||
void netbuf_get_dnsquery_header(unsigned char *buf, int buflen, int *offset, struct dnsquery_header *header)
|
||||
{
|
||||
unsigned char *p;
|
||||
|
||||
netbuf_get_16bitnum(buf, buflen, offset, &(header->id));
|
||||
|
||||
p = buf + *offset;
|
||||
header->qr = (*p >> 7) & 0x01;
|
||||
header->opcode = (*p >> 3) & 0x0F;
|
||||
header->aa = (*p >> 2) & 0x01;
|
||||
header->tc = (*p >> 1) & 0x01;
|
||||
header->rd = (*p) & 0x01;
|
||||
p++;
|
||||
header->ra = (*p >> 7) & 0x01;
|
||||
header->z = (*p >> 4) & 0x07;
|
||||
header->rcode = (*p) & 0x0F;
|
||||
p++;
|
||||
*offset += 2;
|
||||
|
||||
netbuf_get_16bitnum(buf, buflen, offset, &(header->qdcount));
|
||||
netbuf_get_16bitnum(buf, buflen, offset, &(header->ancount));
|
||||
netbuf_get_16bitnum(buf, buflen, offset, &(header->nscount));
|
||||
netbuf_get_16bitnum(buf, buflen, offset, &(header->arcount));
|
||||
}
|
||||
|
||||
void netbuf_add_dnsquery_question(unsigned char *buf, int buflen, int *offset, struct dnsquery_question *question)
|
||||
{
|
||||
netbuf_add_domain_name(buf, buflen, offset, question->qname);
|
||||
netbuf_add_16bitnum(buf, buflen, offset, question->qtype);
|
||||
netbuf_add_16bitnum(buf, buflen, offset, question->qclass);
|
||||
}
|
||||
|
||||
void netbuf_get_dnsquery_question(unsigned char *buf, int buflen, int *offset, struct dnsquery_question *question)
|
||||
{
|
||||
netbuf_get_domain_name(buf, buflen, offset, question->qname, 1024);
|
||||
netbuf_get_16bitnum(buf, buflen, offset, &(question->qtype));
|
||||
netbuf_get_16bitnum(buf, buflen, offset, &(question->qclass));
|
||||
}
|
||||
|
||||
void netbuf_get_dnsquery_srvrdata(unsigned char *buf, int buflen, int *offset, struct dnsquery_srvrdata *srvrdata)
|
||||
{
|
||||
netbuf_get_16bitnum(buf, buflen, offset, &(srvrdata->priority));
|
||||
netbuf_get_16bitnum(buf, buflen, offset, &(srvrdata->weight));
|
||||
netbuf_get_16bitnum(buf, buflen, offset, &(srvrdata->port));
|
||||
netbuf_get_domain_name(buf, buflen, offset, srvrdata->target, 1024);
|
||||
}
|
||||
|
||||
void netbuf_get_dnsquery_resourcerecord(unsigned char *buf, int buflen, int *offset, struct dnsquery_resourcerecord *rr)
|
||||
{
|
||||
netbuf_get_domain_name(buf, buflen, offset, rr->name, 1024);
|
||||
netbuf_get_16bitnum(buf, buflen, offset, &(rr->type));
|
||||
netbuf_get_16bitnum(buf, buflen, offset, &(rr->_class));
|
||||
netbuf_get_32bitnum(buf, buflen, offset, &(rr->ttl));
|
||||
netbuf_get_16bitnum(buf, buflen, offset, &(rr->rdlength));
|
||||
if (rr->type == 33) /* SRV */
|
||||
{
|
||||
int newoffset = *offset;
|
||||
netbuf_get_dnsquery_srvrdata(buf, buflen, &newoffset, &(rr->rdata));
|
||||
}
|
||||
*offset += rr->rdlength;
|
||||
}
|
||||
|
||||
|
||||
int sock_srv_lookup(const char *service, const char *proto, const char *domain, char *resulttarget, int resulttargetlength, int *resultport)
|
||||
{
|
||||
int set = 0;
|
||||
char fulldomain[2048];
|
||||
|
||||
snprintf(fulldomain, 2048, "_%s._%s.%s", service, proto, domain);
|
||||
#ifdef _WIN32
|
||||
|
||||
/* try using dnsapi first */
|
||||
if (!set)
|
||||
{
|
||||
HINSTANCE hdnsapi = NULL;
|
||||
|
||||
DNS_STATUS (WINAPI * pDnsQuery_A)(PCSTR, WORD, DWORD, PIP4_ARRAY, PDNS_RECORD*, PVOID*);
|
||||
void (WINAPI * pDnsRecordListFree)(PDNS_RECORD, DNS_FREE_TYPE);
|
||||
|
||||
if (hdnsapi = LoadLibrary("dnsapi.dll")) {
|
||||
|
||||
pDnsQuery_A = (void *)GetProcAddress(hdnsapi, "DnsQuery_A");
|
||||
pDnsRecordListFree = (void *)GetProcAddress(hdnsapi, "DnsRecordListFree");
|
||||
|
||||
if (pDnsQuery_A && pDnsRecordListFree) {
|
||||
PDNS_RECORD dnsrecords = NULL;
|
||||
DNS_STATUS error;
|
||||
|
||||
error = pDnsQuery_A(fulldomain, DNS_TYPE_SRV, DNS_QUERY_STANDARD, NULL, &dnsrecords, NULL);
|
||||
|
||||
if (error == 0) {
|
||||
PDNS_RECORD current = dnsrecords;
|
||||
|
||||
while (current) {
|
||||
if (current->wType == DNS_TYPE_SRV) {
|
||||
snprintf(resulttarget, resulttargetlength, "%s", current->Data.Srv.pNameTarget);
|
||||
*resultport = current->Data.Srv.wPort;
|
||||
set = 1;
|
||||
|
||||
current = NULL;
|
||||
} else {
|
||||
current = current->pNext;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pDnsRecordListFree(dnsrecords, DnsFreeRecordList);
|
||||
}
|
||||
|
||||
FreeLibrary(hdnsapi);
|
||||
}
|
||||
}
|
||||
|
||||
/* if dnsapi didn't work/isn't there, try querying the dns server manually */
|
||||
if (!set)
|
||||
{
|
||||
unsigned char buf[65536];
|
||||
struct dnsquery_header header;
|
||||
struct dnsquery_question question;
|
||||
int offset = 0;
|
||||
int addrlen;
|
||||
sock_t sock;
|
||||
struct sockaddr_in dnsaddr;
|
||||
char dnsserverips[16][256];
|
||||
int numdnsservers = 0;
|
||||
int j;
|
||||
|
||||
/* Try getting the DNS server ips from GetNetworkParams() in iphlpapi first */
|
||||
if (!numdnsservers)
|
||||
{
|
||||
HINSTANCE hiphlpapi = NULL;
|
||||
DWORD (WINAPI * pGetNetworkParams)(PFIXED_INFO, PULONG);
|
||||
|
||||
if (hiphlpapi = LoadLibrary("Iphlpapi.dll"))
|
||||
{
|
||||
pGetNetworkParams = (void *)GetProcAddress(hiphlpapi, "GetNetworkParams");
|
||||
|
||||
if (pGetNetworkParams)
|
||||
{
|
||||
FIXED_INFO *fi;
|
||||
ULONG len;
|
||||
DWORD error;
|
||||
char buffer[65535];
|
||||
|
||||
len = 65535;
|
||||
fi = buffer;
|
||||
|
||||
if ((error = pGetNetworkParams(fi, &len)) == ERROR_SUCCESS)
|
||||
{
|
||||
IP_ADDR_STRING *pias = &(fi->DnsServerList);
|
||||
|
||||
while (pias && numdnsservers < 16)
|
||||
{
|
||||
strcpy(dnsserverips[numdnsservers++], pias->IpAddress.String);
|
||||
pias = pias->Next;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
FreeLibrary(hiphlpapi);
|
||||
}
|
||||
|
||||
/* Next, try getting the DNS server ips from the registry */
|
||||
if (!numdnsservers)
|
||||
{
|
||||
HKEY search;
|
||||
LONG error;
|
||||
|
||||
error = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters", 0, KEY_READ, &search);
|
||||
|
||||
if (error != ERROR_SUCCESS)
|
||||
{
|
||||
error = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP", 0, KEY_READ, &search);
|
||||
}
|
||||
|
||||
if (error == ERROR_SUCCESS)
|
||||
{
|
||||
char name[512];
|
||||
DWORD len = 512;
|
||||
|
||||
error = RegQueryValueEx(search, "NameServer", NULL, NULL, (LPBYTE)name, &len);
|
||||
|
||||
if (error != ERROR_SUCCESS)
|
||||
{
|
||||
error = RegQueryValueEx(search, "DhcpNameServer", NULL, NULL, (LPBYTE)name, &len);
|
||||
}
|
||||
|
||||
if (error == ERROR_SUCCESS)
|
||||
{
|
||||
char *parse = "0123456789.", *start, *end;
|
||||
start = name;
|
||||
end = name;
|
||||
name[len] = '\0';
|
||||
|
||||
while (*start && numdnsservers < 16)
|
||||
{
|
||||
while (strchr(parse, *end))
|
||||
{
|
||||
end++;
|
||||
}
|
||||
|
||||
strncpy(dnsserverips[numdnsservers++], start, end - start);
|
||||
|
||||
while (*end && !strchr(parse, *end))
|
||||
{
|
||||
end++;
|
||||
}
|
||||
|
||||
start = end;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RegCloseKey(search);
|
||||
}
|
||||
|
||||
if (!numdnsservers)
|
||||
{
|
||||
HKEY searchlist;
|
||||
LONG error;
|
||||
|
||||
error = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces", 0, KEY_READ, &searchlist);
|
||||
|
||||
if (error == ERROR_SUCCESS)
|
||||
{
|
||||
unsigned int i;
|
||||
DWORD numinterfaces = 0;
|
||||
|
||||
RegQueryInfoKey(searchlist, NULL, NULL, NULL, &numinterfaces, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
|
||||
for (i = 0; i < numinterfaces; i++)
|
||||
{
|
||||
char name[512];
|
||||
DWORD len = 512;
|
||||
HKEY searchentry;
|
||||
|
||||
RegEnumKeyEx(searchlist, i, (LPTSTR)name, &len, NULL, NULL, NULL, NULL);
|
||||
|
||||
if (RegOpenKeyEx(searchlist, name, 0, KEY_READ, &searchentry) == ERROR_SUCCESS)
|
||||
{
|
||||
if (RegQueryValueEx(searchentry, "DhcpNameServer", NULL, NULL, (LPBYTE)name, &len) == ERROR_SUCCESS)
|
||||
{
|
||||
char *parse = "0123456789.", *start, *end;
|
||||
start = name;
|
||||
end = name;
|
||||
name[len] = '\0';
|
||||
|
||||
while (*start && numdnsservers < 16)
|
||||
{
|
||||
while (strchr(parse, *end))
|
||||
{
|
||||
end++;
|
||||
}
|
||||
|
||||
strncpy(dnsserverips[numdnsservers++], start, end - start);
|
||||
|
||||
while (*end && !strchr(parse, *end))
|
||||
{
|
||||
end++;
|
||||
}
|
||||
|
||||
start = end;
|
||||
}
|
||||
}
|
||||
else if (RegQueryValueEx(searchentry, "NameServer", NULL, NULL, (LPBYTE)name, &len) == ERROR_SUCCESS)
|
||||
{
|
||||
char *parse = "0123456789.", *start, *end;
|
||||
start = name;
|
||||
end = name;
|
||||
name[len] = '\0';
|
||||
|
||||
while (*start && numdnsservers < 16)
|
||||
{
|
||||
while (strchr(parse, *end))
|
||||
{
|
||||
end++;
|
||||
}
|
||||
|
||||
strncpy(dnsserverips[numdnsservers++], start, end - start);
|
||||
|
||||
while (*end && !strchr(parse, *end))
|
||||
{
|
||||
end++;
|
||||
}
|
||||
|
||||
start = end;
|
||||
}
|
||||
}
|
||||
RegCloseKey(searchentry);
|
||||
}
|
||||
}
|
||||
RegCloseKey(searchlist);
|
||||
}
|
||||
}
|
||||
|
||||
/* If we have a DNS server, use it */
|
||||
if (numdnsservers)
|
||||
{
|
||||
ULONG nonblocking = 1;
|
||||
int i;
|
||||
int insize;
|
||||
|
||||
memset(&header, 0, sizeof(header));
|
||||
header.id = 12345; /* FIXME: Get a better id here */
|
||||
header.rd = 1;
|
||||
header.qdcount = 1;
|
||||
|
||||
netbuf_add_dnsquery_header(buf, 65536, &offset, &header);
|
||||
|
||||
memset(&question, 0, sizeof(question));
|
||||
strncpy(question.qname, fulldomain, 1024);
|
||||
question.qtype = 33; /* SRV */
|
||||
question.qclass = 1; /* INTERNET! */
|
||||
|
||||
netbuf_add_dnsquery_question(buf, 65536, &offset, &question);
|
||||
|
||||
insize = 0;
|
||||
for (i = 0; i < numdnsservers && insize <= 0; i++)
|
||||
{
|
||||
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
ioctlsocket(sock, FIONBIO, &nonblocking);
|
||||
|
||||
memset(&dnsaddr, 0, sizeof(dnsaddr));
|
||||
|
||||
dnsaddr.sin_family = AF_INET;
|
||||
dnsaddr.sin_port = htons(53);
|
||||
dnsaddr.sin_addr.s_addr = inet_addr(dnsserverips[i]);
|
||||
|
||||
addrlen = sizeof(dnsaddr);
|
||||
sendto(sock, (char *)buf, offset, 0, (struct sockaddr *)&dnsaddr, addrlen);
|
||||
for (j = 0; j < 50; j++)
|
||||
{
|
||||
insize = recvfrom(sock, (char *)buf, 65536, 0, (struct sockaddr *)&dnsaddr, &addrlen);
|
||||
if (insize == SOCKET_ERROR)
|
||||
{
|
||||
if (sock_error() == WSAEWOULDBLOCK)
|
||||
{
|
||||
Sleep(100);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
closesocket(sock);
|
||||
}
|
||||
|
||||
offset = insize;
|
||||
|
||||
if (offset > 0)
|
||||
{
|
||||
int len = offset;
|
||||
int i;
|
||||
struct dnsquery_header header;
|
||||
struct dnsquery_question question;
|
||||
struct dnsquery_resourcerecord rr;
|
||||
|
||||
offset = 0;
|
||||
netbuf_get_dnsquery_header(buf, 65536, &offset, &header);
|
||||
|
||||
for (i = 0; i < header.qdcount; i++)
|
||||
{
|
||||
netbuf_get_dnsquery_question(buf, 65536, &offset, &question);
|
||||
}
|
||||
|
||||
for (i = 0; i < header.ancount; i++)
|
||||
{
|
||||
netbuf_get_dnsquery_resourcerecord(buf, 65536, &offset, &rr);
|
||||
|
||||
if (rr.type == 33)
|
||||
{
|
||||
struct dnsquery_srvrdata *srvrdata = &(rr.rdata);
|
||||
|
||||
snprintf(resulttarget, resulttargetlength, "%s", srvrdata->target);
|
||||
*resultport = srvrdata->port;
|
||||
set = 1;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < header.ancount; i++)
|
||||
{
|
||||
netbuf_get_dnsquery_resourcerecord(buf, 65536, &offset, &rr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
if (!set) {
|
||||
unsigned char buf[65535];
|
||||
int len;
|
||||
|
||||
if ((len = res_query(fulldomain, C_IN, T_SRV, buf, 65535)) > 0) {
|
||||
int offset;
|
||||
int i;
|
||||
struct dnsquery_header header;
|
||||
struct dnsquery_question question;
|
||||
struct dnsquery_resourcerecord rr;
|
||||
|
||||
offset = 0;
|
||||
netbuf_get_dnsquery_header(buf, 65536, &offset, &header);
|
||||
|
||||
for (i = 0; i < header.qdcount; i++) {
|
||||
netbuf_get_dnsquery_question(buf, 65536, &offset, &question);
|
||||
}
|
||||
|
||||
for (i = 0; i < header.ancount; i++) {
|
||||
netbuf_get_dnsquery_resourcerecord(buf, 65536, &offset, &rr);
|
||||
|
||||
if (rr.type == 33) {
|
||||
struct dnsquery_srvrdata *srvrdata = &(rr.rdata);
|
||||
|
||||
snprintf(resulttarget, resulttargetlength, "%s",
|
||||
srvrdata->target);
|
||||
*resultport = srvrdata->port;
|
||||
set = 1;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < header.ancount; i++) {
|
||||
netbuf_get_dnsquery_resourcerecord(buf, 65536, &offset, &rr);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!set)
|
||||
{
|
||||
snprintf(resulttarget, resulttargetlength, "%s", domain);
|
||||
*resultport = 5222;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ void sock_shutdown(void);
|
||||
|
||||
int sock_error(void);
|
||||
|
||||
sock_t sock_connect(const char * const host, const unsigned int port);
|
||||
sock_t sock_connect(const char * const host, const unsigned short port);
|
||||
int sock_close(const sock_t sock);
|
||||
|
||||
int sock_set_blocking(const sock_t sock);
|
||||
@@ -40,9 +40,6 @@ int sock_write(const sock_t sock, const void * const buff, const size_t len);
|
||||
int sock_is_recoverable(const int error);
|
||||
/* checks for an error after connect, return 0 if connect successful */
|
||||
int sock_connect_error(const sock_t sock);
|
||||
|
||||
int sock_srv_lookup(const char *service, const char *proto,
|
||||
const char *domain, char *resulttarget,
|
||||
int resulttargetlength, int *resultport);
|
||||
int sock_set_keepalive(const sock_t sock, int timeout, int interval);
|
||||
|
||||
#endif /* __LIBSTROPHE_SOCK_H__ */
|
||||
|
||||
403
src/stanza.c
403
src/stanza.c
@@ -23,12 +23,8 @@
|
||||
#include "common.h"
|
||||
#include "hash.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#define inline __inline
|
||||
#endif
|
||||
|
||||
/** Create a stanza object.
|
||||
* This function allocates and initializes and blank stanza object.
|
||||
* This function allocates and initializes a blank stanza object.
|
||||
* The stanza will have a reference count of one, so the caller does not
|
||||
* need to clone it.
|
||||
*
|
||||
@@ -74,6 +70,35 @@ xmpp_stanza_t *xmpp_stanza_clone(xmpp_stanza_t * const stanza)
|
||||
return stanza;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy the attributes of stanza src into stanza dst. Return -1 on error.
|
||||
*/
|
||||
static int _stanza_copy_attributes(xmpp_stanza_t * dst,
|
||||
const xmpp_stanza_t * const src)
|
||||
{
|
||||
hash_iterator_t *iter;
|
||||
const char *key;
|
||||
const char *val;
|
||||
int rc = XMPP_EOK;
|
||||
|
||||
iter = hash_iter_new(src->attributes);
|
||||
if (!iter) rc = XMPP_EMEM;
|
||||
|
||||
while (rc == XMPP_EOK && (key = hash_iter_next(iter))) {
|
||||
val = hash_get(src->attributes, key);
|
||||
if (!val) rc = XMPP_EINT;
|
||||
if (rc == XMPP_EOK)
|
||||
rc = xmpp_stanza_set_attribute(dst, key, val);
|
||||
}
|
||||
hash_iter_release(iter);
|
||||
|
||||
if (rc != XMPP_EOK && dst->attributes) {
|
||||
hash_release(dst->attributes);
|
||||
dst->attributes = NULL;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/** Copy a stanza and its children.
|
||||
* This function copies a stanza along with all its children and returns
|
||||
* the new stanza and children with a reference count of 1. The returned
|
||||
@@ -89,9 +114,6 @@ xmpp_stanza_t *xmpp_stanza_clone(xmpp_stanza_t * const stanza)
|
||||
xmpp_stanza_t *xmpp_stanza_copy(const xmpp_stanza_t * const stanza)
|
||||
{
|
||||
xmpp_stanza_t *copy, *child, *copychild, *tail;
|
||||
hash_iterator_t *iter;
|
||||
const char *key;
|
||||
void *val;
|
||||
|
||||
copy = xmpp_stanza_new(stanza->ctx);
|
||||
if (!copy) goto copy_error;
|
||||
@@ -104,19 +126,8 @@ xmpp_stanza_t *xmpp_stanza_copy(const xmpp_stanza_t * const stanza)
|
||||
}
|
||||
|
||||
if (stanza->attributes) {
|
||||
copy->attributes = hash_new(stanza->ctx, 8, xmpp_free);
|
||||
if (!copy->attributes) goto copy_error;
|
||||
iter = hash_iter_new(stanza->attributes);
|
||||
if (!iter) { printf("DEBUG HERE\n"); goto copy_error; }
|
||||
while ((key = hash_iter_next(iter))) {
|
||||
val = xmpp_strdup(stanza->ctx,
|
||||
(char *)hash_get(stanza->attributes, key));
|
||||
if (!val) goto copy_error;
|
||||
|
||||
if (hash_add(copy->attributes, key, val))
|
||||
goto copy_error;
|
||||
}
|
||||
hash_iter_release(iter);
|
||||
if (_stanza_copy_attributes(copy, stanza) == -1)
|
||||
goto copy_error;
|
||||
}
|
||||
|
||||
tail = copy->children;
|
||||
@@ -204,7 +215,7 @@ int xmpp_stanza_is_tag(xmpp_stanza_t * const stanza)
|
||||
}
|
||||
|
||||
/* Escape a string with for use in a XML text node or attribute. Assumes that
|
||||
* the input string is encoded in UTF-8. On sucess, returns a pointer to a
|
||||
* the input string is encoded in UTF-8. On success, returns a pointer to a
|
||||
* buffer with the resulting data which must be xmpp_free()'d by the caller.
|
||||
* On failure, returns NULL.
|
||||
*/
|
||||
@@ -262,13 +273,13 @@ static char *_escape_xml(xmpp_ctx_t * const ctx, char *text)
|
||||
}
|
||||
|
||||
/* small helper function */
|
||||
static inline void _render_update(int *written, const int length,
|
||||
static void _render_update(int *written, const int length,
|
||||
const int lastwrite,
|
||||
size_t *left, char **ptr)
|
||||
{
|
||||
*written += lastwrite;
|
||||
|
||||
if (*written > length) {
|
||||
if (*written >= length) {
|
||||
*left = 0;
|
||||
*ptr = NULL;
|
||||
} else {
|
||||
@@ -279,7 +290,7 @@ static inline void _render_update(int *written, const int length,
|
||||
|
||||
/* always returns number of bytes written or that would have been
|
||||
* written if the buffer was large enough
|
||||
* return values < 0 indicate some error occured,
|
||||
* return values < 0 indicate some error occurred,
|
||||
* and return values > buflen indicate buffer was not large enough
|
||||
*/
|
||||
static int _render_stanza_recursive(xmpp_stanza_t *stanza,
|
||||
@@ -309,7 +320,7 @@ static int _render_stanza_recursive(xmpp_stanza_t *stanza,
|
||||
} else { /* stanza->type == XMPP_STANZA_TAG */
|
||||
if (!stanza->data) return XMPP_EINVOP;
|
||||
|
||||
/* write begining of tag and attributes */
|
||||
/* write beginning of tag and attributes */
|
||||
ret = xmpp_snprintf(ptr, left, "<%s", stanza->data);
|
||||
if (ret < 0) return XMPP_EMEM;
|
||||
_render_update(&written, buflen, ret, &left, &ptr);
|
||||
@@ -392,9 +403,9 @@ static int _render_stanza_recursive(xmpp_stanza_t *stanza,
|
||||
*
|
||||
* @ingroup Stanza
|
||||
*/
|
||||
int xmpp_stanza_to_text(xmpp_stanza_t *stanza,
|
||||
char ** const buf,
|
||||
size_t * const buflen)
|
||||
int xmpp_stanza_to_text(xmpp_stanza_t *stanza,
|
||||
char ** const buf,
|
||||
size_t * const buflen)
|
||||
{
|
||||
char *buffer, *tmp;
|
||||
size_t length;
|
||||
@@ -412,7 +423,7 @@ int xmpp_stanza_to_text(xmpp_stanza_t *stanza,
|
||||
ret = _render_stanza_recursive(stanza, buffer, length);
|
||||
if (ret < 0) return ret;
|
||||
|
||||
if (ret > length - 1) {
|
||||
if ((size_t)ret > length - 1) {
|
||||
tmp = xmpp_realloc(stanza->ctx, buffer, ret + 1);
|
||||
if (!tmp) {
|
||||
xmpp_free(stanza->ctx, buffer);
|
||||
@@ -424,7 +435,7 @@ int xmpp_stanza_to_text(xmpp_stanza_t *stanza,
|
||||
buffer = tmp;
|
||||
|
||||
ret = _render_stanza_recursive(stanza, buffer, length);
|
||||
if (ret > length - 1) return XMPP_EMEM;
|
||||
if ((size_t)ret > length - 1) return XMPP_EMEM;
|
||||
}
|
||||
|
||||
buffer[length - 1] = 0;
|
||||
@@ -455,7 +466,7 @@ int xmpp_stanza_set_name(xmpp_stanza_t *stanza,
|
||||
stanza->type = XMPP_STANZA_TAG;
|
||||
stanza->data = xmpp_strdup(stanza->ctx, name);
|
||||
|
||||
return XMPP_EOK;
|
||||
return stanza->data == NULL ? XMPP_EMEM : XMPP_EOK;
|
||||
}
|
||||
|
||||
/** Get the stanza name.
|
||||
@@ -468,7 +479,7 @@ int xmpp_stanza_set_name(xmpp_stanza_t *stanza,
|
||||
*
|
||||
* @ingroup Stanza
|
||||
*/
|
||||
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;
|
||||
return stanza->data;
|
||||
@@ -551,6 +562,7 @@ int xmpp_stanza_set_attribute(xmpp_stanza_t * const stanza,
|
||||
const char * const value)
|
||||
{
|
||||
char *val;
|
||||
int rc;
|
||||
|
||||
if (stanza->type != XMPP_STANZA_TAG) return XMPP_EINVOP;
|
||||
|
||||
@@ -560,9 +572,16 @@ int xmpp_stanza_set_attribute(xmpp_stanza_t * const stanza,
|
||||
}
|
||||
|
||||
val = xmpp_strdup(stanza->ctx, value);
|
||||
if (!val) return XMPP_EMEM;
|
||||
if (!val) {
|
||||
hash_release(stanza->attributes);
|
||||
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;
|
||||
}
|
||||
@@ -639,11 +658,11 @@ int xmpp_stanza_set_text(xmpp_stanza_t *stanza,
|
||||
if (stanza->data) xmpp_free(stanza->ctx, stanza->data);
|
||||
stanza->data = xmpp_strdup(stanza->ctx, text);
|
||||
|
||||
return XMPP_EOK;
|
||||
return stanza->data == NULL ? XMPP_EMEM : XMPP_EOK;
|
||||
}
|
||||
|
||||
/** Set the text data for a text stanza.
|
||||
* This function copies the text given and sets teh stanza object's text to
|
||||
* This function copies the text given and sets the stanza object's text to
|
||||
* it. Attempting to use this function on a stanza that has a name will
|
||||
* fail with XMPP_EINVOP. This function takes the text as buffer and a length
|
||||
* as opposed to a null-terminated string.
|
||||
@@ -684,15 +703,9 @@ int xmpp_stanza_set_text_with_size(xmpp_stanza_t *stanza,
|
||||
*
|
||||
* @ingroup Stanza
|
||||
*/
|
||||
char *xmpp_stanza_get_id(xmpp_stanza_t * const stanza)
|
||||
const char *xmpp_stanza_get_id(xmpp_stanza_t * const stanza)
|
||||
{
|
||||
if (stanza->type != XMPP_STANZA_TAG)
|
||||
return NULL;
|
||||
|
||||
if (!stanza->attributes)
|
||||
return NULL;
|
||||
|
||||
return (char *)hash_get(stanza->attributes, "id");
|
||||
return xmpp_stanza_get_attribute(stanza, "id");
|
||||
}
|
||||
|
||||
/** Get the namespace attribute of the stanza object.
|
||||
@@ -705,15 +718,9 @@ char *xmpp_stanza_get_id(xmpp_stanza_t * const stanza)
|
||||
*
|
||||
* @ingroup Stanza
|
||||
*/
|
||||
char *xmpp_stanza_get_ns(xmpp_stanza_t * const stanza)
|
||||
const char *xmpp_stanza_get_ns(xmpp_stanza_t * const stanza)
|
||||
{
|
||||
if (stanza->type != XMPP_STANZA_TAG)
|
||||
return NULL;
|
||||
|
||||
if (!stanza->attributes)
|
||||
return NULL;
|
||||
|
||||
return (char *)hash_get(stanza->attributes, "xmlns");
|
||||
return xmpp_stanza_get_attribute(stanza, "xmlns");
|
||||
}
|
||||
|
||||
/** Get the 'type' attribute of the stanza object.
|
||||
@@ -726,15 +733,39 @@ char *xmpp_stanza_get_ns(xmpp_stanza_t * const stanza)
|
||||
*
|
||||
* @ingroup Stanza
|
||||
*/
|
||||
char *xmpp_stanza_get_type(xmpp_stanza_t * const stanza)
|
||||
const char *xmpp_stanza_get_type(xmpp_stanza_t * const stanza)
|
||||
{
|
||||
if (stanza->type != XMPP_STANZA_TAG)
|
||||
return NULL;
|
||||
|
||||
if (!stanza->attributes)
|
||||
return NULL;
|
||||
return xmpp_stanza_get_attribute(stanza, "type");
|
||||
}
|
||||
|
||||
return (char *)hash_get(stanza->attributes, "type");
|
||||
/** Get the 'to' attribute of the stanza object.
|
||||
* This is a convenience function equivalent to:
|
||||
* xmpp_stanza_get_attribute(stanza, "to");
|
||||
*
|
||||
* @param stanza a Strophe stanza object
|
||||
*
|
||||
* @return a string with the 'to' attribute value
|
||||
*
|
||||
* @ingroup Stanza
|
||||
*/
|
||||
const char *xmpp_stanza_get_to(xmpp_stanza_t * const stanza)
|
||||
{
|
||||
return xmpp_stanza_get_attribute(stanza, "to");
|
||||
}
|
||||
|
||||
/** Get the 'from' attribute of the stanza object.
|
||||
* This is a convenience function equivalent to:
|
||||
* xmpp_stanza_get_attribute(stanza, "from");
|
||||
*
|
||||
* @param stanza a Strophe stanza object
|
||||
*
|
||||
* @return a string with the 'from' attribute value
|
||||
*
|
||||
* @ingroup Stanza
|
||||
*/
|
||||
const char *xmpp_stanza_get_from(xmpp_stanza_t * const stanza)
|
||||
{
|
||||
return xmpp_stanza_get_attribute(stanza, "from");
|
||||
}
|
||||
|
||||
/** Get the first child of stanza with name.
|
||||
@@ -877,7 +908,7 @@ char *xmpp_stanza_get_text(xmpp_stanza_t * const stanza)
|
||||
*
|
||||
* @ingroup Stanza
|
||||
*/
|
||||
char *xmpp_stanza_get_text_ptr(xmpp_stanza_t * const stanza)
|
||||
const char *xmpp_stanza_get_text_ptr(xmpp_stanza_t * const stanza)
|
||||
{
|
||||
if (stanza->type == XMPP_STANZA_TEXT)
|
||||
return stanza->data;
|
||||
@@ -919,6 +950,42 @@ int xmpp_stanza_set_type(xmpp_stanza_t * const stanza,
|
||||
return xmpp_stanza_set_attribute(stanza, "type", type);
|
||||
}
|
||||
|
||||
/** Set the 'to' attribute of a stanza.
|
||||
*
|
||||
* This is a convenience function for:
|
||||
* xmpp_stanza_set_attribute(stanza, 'to', to);
|
||||
*
|
||||
* @param stanza a Strophe stanza object
|
||||
* @param to a string containing the 'to' value
|
||||
*
|
||||
* @return XMPP_EOK (0) on success or a number less than 0 on failure
|
||||
*
|
||||
* @ingroup Stanza
|
||||
*/
|
||||
int xmpp_stanza_set_to(xmpp_stanza_t * const stanza,
|
||||
const char * const to)
|
||||
{
|
||||
return xmpp_stanza_set_attribute(stanza, "to", to);
|
||||
}
|
||||
|
||||
/** Set the 'from' attribute of a stanza.
|
||||
*
|
||||
* This is a convenience function for:
|
||||
* xmpp_stanza_set_attribute(stanza, 'from', from);
|
||||
*
|
||||
* @param stanza a Strophe stanza object
|
||||
* @param from a string containing the 'from' value
|
||||
*
|
||||
* @return XMPP_EOK (0) on success or a number less than 0 on failure
|
||||
*
|
||||
* @ingroup Stanza
|
||||
*/
|
||||
int xmpp_stanza_set_from(xmpp_stanza_t * const stanza,
|
||||
const char * const from)
|
||||
{
|
||||
return xmpp_stanza_set_attribute(stanza, "from", from);
|
||||
}
|
||||
|
||||
/** Get an attribute from a stanza.
|
||||
* This function returns a pointer to the attribute value. If the caller
|
||||
* wishes to save this value it must make its own copy.
|
||||
@@ -930,8 +997,8 @@ int xmpp_stanza_set_type(xmpp_stanza_t * const stanza,
|
||||
*
|
||||
* @ingroup Stanza
|
||||
*/
|
||||
char *xmpp_stanza_get_attribute(xmpp_stanza_t * const stanza,
|
||||
const char * const name)
|
||||
const char *xmpp_stanza_get_attribute(xmpp_stanza_t * const stanza,
|
||||
const char * const name)
|
||||
{
|
||||
if (stanza->type != XMPP_STANZA_TAG)
|
||||
return NULL;
|
||||
@@ -941,3 +1008,213 @@ char *xmpp_stanza_get_attribute(xmpp_stanza_t * const stanza,
|
||||
|
||||
return hash_get(stanza->attributes, name);
|
||||
}
|
||||
|
||||
/** Delete an attribute from a stanza.
|
||||
*
|
||||
* @param stanza a Strophe stanza object
|
||||
* @param name a string containing attribute name
|
||||
*
|
||||
* @return XMPP_EOK (0) on success or a number less than 0 on failure
|
||||
*
|
||||
* @ingroup Stanza
|
||||
*/
|
||||
int xmpp_stanza_del_attribute(xmpp_stanza_t * const stanza,
|
||||
const char * const name)
|
||||
{
|
||||
if (stanza->type != XMPP_STANZA_TAG)
|
||||
return -1;
|
||||
|
||||
if (!stanza->attributes)
|
||||
return -1;
|
||||
|
||||
return hash_drop(stanza->attributes, name);
|
||||
}
|
||||
|
||||
/** Create a stanza object in reply to another.
|
||||
* This function makes a copy of a stanza object with the attribute “to” set
|
||||
* its original “from”.
|
||||
* The stanza will have a reference count of one, so the caller does not
|
||||
* need to clone it.
|
||||
*
|
||||
* @param stanza a Strophe stanza object
|
||||
*
|
||||
* @return a new Strophe stanza object
|
||||
*
|
||||
* @ingroup Stanza
|
||||
*/
|
||||
xmpp_stanza_t *xmpp_stanza_reply(xmpp_stanza_t * const stanza)
|
||||
{
|
||||
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);
|
||||
if (!copy) goto copy_error;
|
||||
|
||||
copy->type = stanza->type;
|
||||
|
||||
if (stanza->data) {
|
||||
copy->data = xmpp_strdup(stanza->ctx, stanza->data);
|
||||
if (!copy->data) goto copy_error;
|
||||
}
|
||||
|
||||
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");
|
||||
rc = xmpp_stanza_set_to(copy, from);
|
||||
if (rc != XMPP_EOK) goto copy_error;
|
||||
|
||||
return copy;
|
||||
|
||||
copy_error:
|
||||
if (copy) xmpp_stanza_release(copy);
|
||||
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)
|
||||
{
|
||||
xmpp_stanza_t *stanza = xmpp_stanza_new(ctx);
|
||||
int ret;
|
||||
|
||||
if (stanza) {
|
||||
ret = xmpp_stanza_set_name(stanza, name);
|
||||
if (ret == XMPP_EOK && type)
|
||||
ret = xmpp_stanza_set_type(stanza, type);
|
||||
if (ret == XMPP_EOK && id)
|
||||
ret = xmpp_stanza_set_id(stanza, id);
|
||||
if (ret == XMPP_EOK && to)
|
||||
ret = xmpp_stanza_set_to(stanza, to);
|
||||
if (ret != XMPP_EOK) {
|
||||
xmpp_stanza_release(stanza);
|
||||
stanza = NULL;
|
||||
}
|
||||
}
|
||||
return stanza;
|
||||
}
|
||||
|
||||
/** Create a <message/> stanza object with given attributes.
|
||||
* Attributes are optional and may be NULL.
|
||||
*
|
||||
* @param ctx a Strophe context object
|
||||
* @param type attribute 'type'
|
||||
* @param to attribute 'to'
|
||||
* @param id attribute 'id'
|
||||
*
|
||||
* @return a new Strophe stanza object
|
||||
*
|
||||
* @ingroup Stanza
|
||||
*/
|
||||
xmpp_stanza_t *xmpp_message_new(xmpp_ctx_t *ctx, const char * const type,
|
||||
const char * const to, const char * const id)
|
||||
{
|
||||
return _stanza_new_with_attrs(ctx, "message", type, id, to);
|
||||
}
|
||||
|
||||
/** Get text from <body/> child element.
|
||||
* This function returns new allocated string. The caller is responsible
|
||||
* for freeing this string with xmpp_free().
|
||||
*
|
||||
* @param msg well formed <message/> stanza
|
||||
*
|
||||
* @return allocated string or NULL on failure (no <body/> element or
|
||||
* memory allocation error)
|
||||
*
|
||||
* @ingroup Stanza
|
||||
*/
|
||||
char *xmpp_message_get_body(xmpp_stanza_t *msg)
|
||||
{
|
||||
xmpp_stanza_t *body;
|
||||
const char *name;
|
||||
char *text = NULL;
|
||||
|
||||
name = xmpp_stanza_get_name(msg);
|
||||
body = xmpp_stanza_get_child_by_name(msg, "body");
|
||||
if (name && strcmp(name, "message") == 0 && body) {
|
||||
text = xmpp_stanza_get_text(body);
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
/** Add <body/> child element to a <message/> stanza with the given text.
|
||||
*
|
||||
* @param msg a <message> stanza object without <body/> child element.
|
||||
*
|
||||
* @return 0 on success (XMPP_EOK), and a number less than 0 on failure
|
||||
* (XMPP_EMEM, XMPP_EINVOP)
|
||||
*
|
||||
* @ingroup Stanza
|
||||
*/
|
||||
int xmpp_message_set_body(xmpp_stanza_t *msg, const char * const text)
|
||||
{
|
||||
xmpp_ctx_t *ctx = msg->ctx;
|
||||
xmpp_stanza_t *body;
|
||||
xmpp_stanza_t *text_stanza;
|
||||
const char *name;
|
||||
int ret;
|
||||
|
||||
/* check that msg is a <message/> stanza and doesn't contain <body/> */
|
||||
name = xmpp_stanza_get_name(msg);
|
||||
body = xmpp_stanza_get_child_by_name(msg, "body");
|
||||
if (!name || strcmp(name, "message") != 0 || body)
|
||||
return XMPP_EINVOP;
|
||||
|
||||
body = xmpp_stanza_new(ctx);
|
||||
text_stanza = xmpp_stanza_new(ctx);
|
||||
|
||||
ret = body && text_stanza ? XMPP_EOK : XMPP_EMEM;
|
||||
if (ret == XMPP_EOK)
|
||||
ret = xmpp_stanza_set_name(body, "body");
|
||||
if (ret == XMPP_EOK)
|
||||
ret = xmpp_stanza_set_text(text_stanza, text);
|
||||
if (ret == XMPP_EOK)
|
||||
ret = xmpp_stanza_add_child(body, text_stanza);
|
||||
if (ret == XMPP_EOK)
|
||||
ret = xmpp_stanza_add_child(msg, body);
|
||||
|
||||
if (text_stanza)
|
||||
xmpp_stanza_release(text_stanza);
|
||||
if (body)
|
||||
xmpp_stanza_release(body);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Create an <iq/> stanza object with given attributes.
|
||||
* Attributes are optional and may be NULL.
|
||||
*
|
||||
* @param ctx a Strophe context object
|
||||
* @param type attribute 'type'
|
||||
* @param id attribute 'id'
|
||||
*
|
||||
* @return a new Strophe stanza object
|
||||
*
|
||||
* @ingroup Stanza
|
||||
*/
|
||||
xmpp_stanza_t *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);
|
||||
}
|
||||
|
||||
/** Create a <presence/> stanza object.
|
||||
*
|
||||
* @param ctx a Strophe context object
|
||||
*
|
||||
* @return a new Strophe stanza object
|
||||
*
|
||||
* @ingroup Stanza
|
||||
*/
|
||||
xmpp_stanza_t *xmpp_presence_new(xmpp_ctx_t *ctx)
|
||||
{
|
||||
return _stanza_new_with_attrs(ctx, "presence", NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
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_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);
|
||||
|
||||
int tls_set_credentials(tls_t *tls, const char *cafilename);
|
||||
|
||||
@@ -33,7 +33,7 @@ void tls_shutdown(void)
|
||||
return;
|
||||
}
|
||||
|
||||
tls_t *tls_new(xmpp_ctx_t *ctx, sock_t sock)
|
||||
tls_t *tls_new(xmpp_conn_t *conn)
|
||||
{
|
||||
/* always fail */
|
||||
return NULL;
|
||||
|
||||
@@ -19,11 +19,15 @@
|
||||
#include "tls.h"
|
||||
#include "sock.h"
|
||||
|
||||
/* FIXME this shouldn't be a constant string */
|
||||
#define CAFILE "/etc/ssl/certs/ca-certificates.crt"
|
||||
|
||||
struct _tls {
|
||||
xmpp_ctx_t *ctx; /* do we need this? */
|
||||
sock_t sock;
|
||||
gnutls_session_t session;
|
||||
gnutls_certificate_credentials_t cred;
|
||||
int lasterror;
|
||||
};
|
||||
|
||||
void tls_initialize(void)
|
||||
@@ -42,25 +46,22 @@ void tls_shutdown(void)
|
||||
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));
|
||||
const int cert_type_priority[3] = { GNUTLS_CRT_X509,
|
||||
GNUTLS_CRT_OPENPGP, 0 };
|
||||
tls_t *tls = xmpp_alloc(conn->ctx, sizeof(tls_t));
|
||||
|
||||
if (tls) {
|
||||
tls->ctx = ctx;
|
||||
tls->sock = sock;
|
||||
gnutls_init(&tls->session, GNUTLS_CLIENT);
|
||||
tls->ctx = conn->ctx;
|
||||
tls->sock = conn->sock;
|
||||
gnutls_init(&tls->session, GNUTLS_CLIENT);
|
||||
|
||||
gnutls_certificate_allocate_credentials(&tls->cred);
|
||||
gnutls_certificate_allocate_credentials(&tls->cred);
|
||||
tls_set_credentials(tls, CAFILE);
|
||||
|
||||
gnutls_set_default_priority(tls->session);
|
||||
gnutls_certificate_type_set_priority(tls->session, cert_type_priority);
|
||||
gnutls_set_default_priority(tls->session);
|
||||
|
||||
/* fixme: this may require setting a callback on win32? */
|
||||
gnutls_transport_set_ptr(tls->session,
|
||||
(gnutls_transport_ptr_t)sock);
|
||||
/* fixme: this may require setting a callback on win32? */
|
||||
gnutls_transport_set_int(tls->session, conn->sock);
|
||||
}
|
||||
|
||||
return tls;
|
||||
@@ -79,29 +80,39 @@ int tls_set_credentials(tls_t *tls, const char *cafilename)
|
||||
|
||||
/* set trusted credentials -- takes a .pem filename */
|
||||
err = gnutls_certificate_set_x509_trust_file(tls->cred,
|
||||
cafilename, GNUTLS_X509_FMT_PEM);
|
||||
if (err < 0) return err;
|
||||
cafilename, GNUTLS_X509_FMT_PEM);
|
||||
if (err >= 0) {
|
||||
err = gnutls_credentials_set(tls->session, GNUTLS_CRD_CERTIFICATE,
|
||||
tls->cred);
|
||||
}
|
||||
tls->lasterror = err;
|
||||
|
||||
err = gnutls_credentials_set(tls->session, GNUTLS_CRD_CERTIFICATE,
|
||||
tls->cred);
|
||||
|
||||
return err;
|
||||
return err == GNUTLS_E_SUCCESS;
|
||||
}
|
||||
|
||||
int tls_start(tls_t *tls)
|
||||
{
|
||||
return gnutls_handshake(tls->session);
|
||||
sock_set_blocking(tls->sock);
|
||||
tls->lasterror = gnutls_handshake(tls->session);
|
||||
sock_set_nonblocking(tls->sock);
|
||||
|
||||
return tls->lasterror == GNUTLS_E_SUCCESS;
|
||||
}
|
||||
|
||||
int tls_stop(tls_t *tls)
|
||||
{
|
||||
return gnutls_bye(tls->session, GNUTLS_SHUT_RDWR);
|
||||
tls->lasterror = gnutls_bye(tls->session, GNUTLS_SHUT_RDWR);
|
||||
return tls->lasterror == GNUTLS_E_SUCCESS;
|
||||
}
|
||||
|
||||
int tls_error(tls_t *tls)
|
||||
{
|
||||
/* todo: some kind of error polling/dump */
|
||||
return 0;
|
||||
return tls->lasterror;
|
||||
}
|
||||
|
||||
int tls_is_recoverable(int error)
|
||||
{
|
||||
return !gnutls_error_is_fatal(error);
|
||||
}
|
||||
|
||||
int tls_pending(tls_t *tls)
|
||||
@@ -114,6 +125,7 @@ int tls_read(tls_t *tls, void * const buff, const size_t len)
|
||||
int ret;
|
||||
|
||||
ret = gnutls_record_recv(tls->session, buff, len);
|
||||
tls->lasterror = ret < 0 ? ret : 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -123,7 +135,12 @@ int tls_write(tls_t *tls, const void * const buff, const size_t len)
|
||||
int ret;
|
||||
|
||||
ret = gnutls_record_send(tls->session, buff, len);
|
||||
tls->lasterror = ret < 0 ? ret : 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int tls_clear_pending_write(tls_t *tls)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
* TLS implementation with OpenSSL.
|
||||
*/
|
||||
|
||||
#include <errno.h> /* EINTR */
|
||||
#include <string.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
@@ -22,6 +23,9 @@
|
||||
#endif
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/opensslv.h>
|
||||
#include <openssl/x509v3.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "tls.h"
|
||||
@@ -35,15 +39,46 @@ struct _tls {
|
||||
int lasterror;
|
||||
};
|
||||
|
||||
enum {
|
||||
TLS_SHUTDOWN_MAX_RETRIES = 10,
|
||||
TLS_TIMEOUT_SEC = 0,
|
||||
TLS_TIMEOUT_USEC = 100000,
|
||||
};
|
||||
|
||||
static void _tls_sock_wait(tls_t *tls, int error);
|
||||
static void _tls_set_error(tls_t *tls, int error);
|
||||
static void _tls_log_error(xmpp_ctx_t *ctx);
|
||||
|
||||
void tls_initialize(void)
|
||||
{
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||
SSL_library_init();
|
||||
SSL_load_error_strings();
|
||||
#else
|
||||
OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
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)
|
||||
@@ -51,34 +86,69 @@ int tls_error(tls_t *tls)
|
||||
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) {
|
||||
int ret;
|
||||
memset(tls, 0, sizeof(*tls));
|
||||
memset(tls, 0, sizeof(*tls));
|
||||
|
||||
tls->ctx = ctx;
|
||||
tls->sock = sock;
|
||||
tls->ssl_ctx = SSL_CTX_new(SSLv23_client_method());
|
||||
tls->ctx = conn->ctx;
|
||||
tls->sock = conn->sock;
|
||||
tls->ssl_ctx = SSL_CTX_new(SSLv23_client_method());
|
||||
if (tls->ssl_ctx == NULL)
|
||||
goto err;
|
||||
|
||||
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_verify (tls->ssl_ctx, SSL_VERIFY_NONE, NULL);
|
||||
/* Enable bug workarounds. */
|
||||
SSL_CTX_set_options(tls->ssl_ctx, SSL_OP_ALL);
|
||||
|
||||
tls->ssl = SSL_new(tls->ssl_ctx);
|
||||
/* 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 */
|
||||
|
||||
ret = SSL_set_fd(tls->ssl, sock);
|
||||
if (ret <= 0) {
|
||||
tls->lasterror = SSL_get_error(tls->ssl, ret);
|
||||
tls_error(tls);
|
||||
tls_free(tls);
|
||||
tls = 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_default_verify_paths(tls->ssl_ctx);
|
||||
|
||||
tls->ssl = SSL_new(tls->ssl_ctx);
|
||||
if (tls->ssl == NULL)
|
||||
goto err_free_ctx;
|
||||
|
||||
/* Trust server's certificate when user sets the flag explicitly. */
|
||||
mode = conn->tls_trust ? SSL_VERIFY_NONE : SSL_VERIFY_PEER;
|
||||
SSL_set_verify(tls->ssl, mode, 0);
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
|
||||
/* Hostname verification is supported in OpenSSL 1.0.2 and newer. */
|
||||
X509_VERIFY_PARAM *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)
|
||||
goto err_free_ssl;
|
||||
}
|
||||
|
||||
return tls;
|
||||
|
||||
err_free_ssl:
|
||||
SSL_free(tls->ssl);
|
||||
err_free_ctx:
|
||||
SSL_CTX_free(tls->ssl_ctx);
|
||||
err:
|
||||
xmpp_free(conn->ctx, tls);
|
||||
_tls_log_error(conn->ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void tls_free(tls_t *tls)
|
||||
@@ -86,7 +156,6 @@ void tls_free(tls_t *tls)
|
||||
SSL_free(tls->ssl);
|
||||
SSL_CTX_free(tls->ssl_ctx);
|
||||
xmpp_free(tls->ctx, tls);
|
||||
return;
|
||||
}
|
||||
|
||||
int tls_set_credentials(tls_t *tls, const char *cafilename)
|
||||
@@ -96,57 +165,61 @@ int tls_set_credentials(tls_t *tls, const char *cafilename)
|
||||
|
||||
int tls_start(tls_t *tls)
|
||||
{
|
||||
int ret = -1;
|
||||
int error;
|
||||
int ret;
|
||||
long x509_res;
|
||||
|
||||
/* Since we're non-blocking, loop the connect call until it
|
||||
succeeds or fails */
|
||||
while (ret == -1) {
|
||||
ret = SSL_connect(tls->ssl);
|
||||
while (1) {
|
||||
ret = SSL_connect(tls->ssl);
|
||||
error = ret <= 0 ? SSL_get_error(tls->ssl, ret) : 0;
|
||||
|
||||
/* wait for something to happen on the sock before looping back */
|
||||
if (ret == -1) {
|
||||
fd_set fds;
|
||||
struct timeval tv;
|
||||
if (ret == -1 && tls_is_recoverable(error)) {
|
||||
/* wait for something to happen on the sock before looping back */
|
||||
_tls_sock_wait(tls, error);
|
||||
continue;
|
||||
}
|
||||
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 1000;
|
||||
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(tls->sock, &fds);
|
||||
|
||||
select(tls->sock + 1, &fds, &fds, NULL, &tv);
|
||||
}
|
||||
/* success or fatal error */
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret <= 0) {
|
||||
tls->lasterror = SSL_get_error(tls->ssl, ret);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
x509_res = SSL_get_verify_result(tls->ssl);
|
||||
xmpp_debug(tls->ctx, "tls", "Certificate verification %s",
|
||||
x509_res == X509_V_OK ? "passed" : "FAILED");
|
||||
|
||||
_tls_set_error(tls, error);
|
||||
return ret <= 0 ? 0 : 1;
|
||||
}
|
||||
|
||||
int tls_stop(tls_t *tls)
|
||||
{
|
||||
int retries = 0;
|
||||
int error;
|
||||
int ret;
|
||||
|
||||
ret = SSL_shutdown(tls->ssl);
|
||||
|
||||
if (ret <= 0) {
|
||||
tls->lasterror = SSL_get_error(tls->ssl, ret);
|
||||
return 0;
|
||||
while (1) {
|
||||
++retries;
|
||||
ret = SSL_shutdown(tls->ssl);
|
||||
error = ret < 0 ? SSL_get_error(tls->ssl, ret) : 0;
|
||||
if (ret == 1 || !tls_is_recoverable(error) ||
|
||||
retries >= TLS_SHUTDOWN_MAX_RETRIES) {
|
||||
break;
|
||||
}
|
||||
_tls_sock_wait(tls, error);
|
||||
}
|
||||
_tls_set_error(tls, error);
|
||||
|
||||
return 1;
|
||||
return ret <= 0 ? 0 : 1;
|
||||
}
|
||||
|
||||
int tls_is_recoverable(int error)
|
||||
{
|
||||
return (error == SSL_ERROR_NONE || error == SSL_ERROR_WANT_READ
|
||||
|| error == SSL_ERROR_WANT_WRITE
|
||||
|| error == SSL_ERROR_WANT_CONNECT
|
||||
|| error == SSL_ERROR_WANT_ACCEPT);
|
||||
|| error == SSL_ERROR_WANT_WRITE
|
||||
|| error == SSL_ERROR_WANT_CONNECT
|
||||
|| error == SSL_ERROR_WANT_ACCEPT);
|
||||
}
|
||||
|
||||
int tls_pending(tls_t *tls)
|
||||
@@ -156,22 +229,20 @@ int tls_pending(tls_t *tls)
|
||||
|
||||
int tls_read(tls_t *tls, void * const buff, const size_t len)
|
||||
{
|
||||
int ret = SSL_read(tls->ssl, buff, len);
|
||||
int ret;
|
||||
|
||||
if (ret <= 0) {
|
||||
tls->lasterror = SSL_get_error(tls->ssl, ret);
|
||||
}
|
||||
ret = SSL_read(tls->ssl, buff, len);
|
||||
_tls_set_error(tls, ret <= 0 ? SSL_get_error(tls->ssl, ret) : 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int tls_write(tls_t *tls, const void * const buff, const size_t len)
|
||||
{
|
||||
int ret = SSL_write(tls->ssl, buff, len);
|
||||
int ret;
|
||||
|
||||
if (ret <= 0) {
|
||||
tls->lasterror = SSL_get_error(tls->ssl, ret);
|
||||
}
|
||||
ret = SSL_write(tls->ssl, buff, len);
|
||||
_tls_set_error(tls, ret <= 0 ? SSL_get_error(tls->ssl, ret) : 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -180,3 +251,48 @@ int tls_clear_pending_write(tls_t *tls)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _tls_sock_wait(tls_t *tls, int error)
|
||||
{
|
||||
struct timeval tv;
|
||||
fd_set rfds;
|
||||
fd_set wfds;
|
||||
int nfds;
|
||||
int ret;
|
||||
|
||||
FD_ZERO(&rfds);
|
||||
FD_ZERO(&wfds);
|
||||
if (error == SSL_ERROR_WANT_READ)
|
||||
FD_SET(tls->sock, &rfds);
|
||||
if (error == SSL_ERROR_WANT_WRITE)
|
||||
FD_SET(tls->sock, &wfds);
|
||||
nfds = (error == SSL_ERROR_WANT_READ || error == SSL_ERROR_WANT_WRITE) ?
|
||||
tls->sock + 1 : 0;
|
||||
do {
|
||||
tv.tv_sec = TLS_TIMEOUT_SEC;
|
||||
tv.tv_usec = TLS_TIMEOUT_USEC;
|
||||
ret = select(nfds, &rfds, &wfds, NULL, &tv);
|
||||
} while (ret == -1 && errno == EINTR);
|
||||
}
|
||||
|
||||
static void _tls_set_error(tls_t *tls, int error)
|
||||
{
|
||||
if (error != 0 && !tls_is_recoverable(error)) {
|
||||
_tls_log_error(tls->ctx);
|
||||
}
|
||||
tls->lasterror = error;
|
||||
}
|
||||
|
||||
static void _tls_log_error(xmpp_ctx_t *ctx)
|
||||
{
|
||||
unsigned long e;
|
||||
char buf[256];
|
||||
|
||||
do {
|
||||
e = ERR_get_error();
|
||||
if (e != 0) {
|
||||
ERR_error_string_n(e, buf, sizeof(buf));
|
||||
xmpp_debug(ctx, "tls", "%s", buf);
|
||||
}
|
||||
} while (e != 0);
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
|
||||
struct _tls {
|
||||
xmpp_ctx_t *ctx;
|
||||
xmpp_conn_t *conn;
|
||||
sock_t sock;
|
||||
|
||||
HANDLE hsec32;
|
||||
@@ -60,8 +61,10 @@ void tls_shutdown(void)
|
||||
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;
|
||||
PSecurityFunctionTable (*pInitSecurityInterface)(void);
|
||||
SCHANNEL_CRED scred;
|
||||
@@ -92,6 +95,7 @@ tls_t *tls_new(xmpp_ctx_t *ctx, sock_t sock)
|
||||
|
||||
memset(tls, 0, sizeof(*tls));
|
||||
tls->ctx = ctx;
|
||||
tls->conn = conn;
|
||||
tls->sock = sock;
|
||||
|
||||
if (!(tls->hsec32 = LoadLibrary ("secur32.dll"))) {
|
||||
@@ -125,10 +129,16 @@ tls_t *tls_new(xmpp_ctx_t *ctx, sock_t sock)
|
||||
memset(&scred, 0, sizeof(scred));
|
||||
scred.dwVersion = SCHANNEL_CRED_VERSION;
|
||||
/*scred.grbitEnabledProtocols = SP_PROT_TLS1_CLIENT;*/
|
||||
/* Remote server closes connection with forced RC4.
|
||||
The below lines are commented to leave default system configuration */
|
||||
#if 0
|
||||
/* Something down the line doesn't like AES, so force it to RC4 */
|
||||
algs[0] = CALG_RC4;
|
||||
scred.cSupportedAlgs = 1;
|
||||
scred.palgSupportedAlgs = algs;
|
||||
#else
|
||||
(void)algs;
|
||||
#endif
|
||||
|
||||
ret = tls->sft->AcquireCredentialsHandleA(NULL, UNISP_NAME,
|
||||
SECPKG_CRED_OUTBOUND, NULL, &scred, NULL, NULL, &(tls->hcred), NULL);
|
||||
@@ -210,24 +220,10 @@ int tls_start(tls_t *tls)
|
||||
SecBuffer sbin[2], sbout[1];
|
||||
SECURITY_STATUS ret;
|
||||
int sent;
|
||||
char *name = NULL;
|
||||
char *name;
|
||||
|
||||
/* search the ctx's conns for our sock, and use the domain there as our
|
||||
* name */
|
||||
{
|
||||
xmpp_connlist_t *listentry = tls->ctx->connlist;
|
||||
|
||||
while (listentry) {
|
||||
xmpp_conn_t *conn = listentry->conn;
|
||||
|
||||
if (conn->sock == tls->sock) {
|
||||
name = strdup(conn->domain);
|
||||
listentry = NULL;
|
||||
} else {
|
||||
listentry = listentry->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* use the domain there as our name */
|
||||
name = tls->conn->domain;
|
||||
|
||||
ctxtreq = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT
|
||||
| ISC_REQ_CONFIDENTIALITY | ISC_RET_EXTENDED_ERROR
|
||||
@@ -354,6 +350,7 @@ int tls_start(tls_t *tls)
|
||||
|
||||
if (ret != SEC_E_OK) {
|
||||
tls->lasterror = ret;
|
||||
xmpp_error(tls->ctx, "TLSS", "Schannel error 0x%lx", (unsigned long)ret);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -563,7 +560,6 @@ int tls_write(tls_t *tls, const void * const buff, const size_t len)
|
||||
{
|
||||
SecBufferDesc sbdenc;
|
||||
SecBuffer sbenc[4];
|
||||
unsigned char *sendbuffer;
|
||||
const unsigned char *p = buff;
|
||||
int sent = 0, ret, remain = len;
|
||||
|
||||
|
||||
22
src/util.c
22
src/util.c
@@ -55,6 +55,28 @@ char *xmpp_strdup(const xmpp_ctx_t * const ctx, const char * const s)
|
||||
return copy;
|
||||
}
|
||||
|
||||
/** strtok_r(3) implementation.
|
||||
* This function has appeared in POSIX.1-2001, but not in C standard.
|
||||
* For example, visual studio older than 2005 doesn't provide strtok_r()
|
||||
* nor strtok_s().
|
||||
*/
|
||||
char *xmpp_strtok_r(char *s, const char *delim, char **saveptr)
|
||||
{
|
||||
size_t len;
|
||||
|
||||
s = s ? s : *saveptr;
|
||||
len = strspn(s, delim);
|
||||
s += len;
|
||||
if (*s == '\0')
|
||||
return NULL;
|
||||
|
||||
len = strcspn(s, delim);
|
||||
*saveptr = s[len] == '\0' ? &s[len] : &s[len + 1];
|
||||
s[len] = '\0';
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
/** Return an integer based time stamp.
|
||||
* This function uses gettimeofday or timeGetTime (on Win32 platforms) to
|
||||
* compute an integer based time stamp. This is used internally by the
|
||||
|
||||
@@ -18,6 +18,12 @@
|
||||
|
||||
#include "ostypes.h"
|
||||
|
||||
/* TODO evaluate x and y only once */
|
||||
#define xmpp_min(x, y) ((x) < (y) ? (x) : (y))
|
||||
|
||||
/* string functions */
|
||||
char *xmpp_strtok_r(char *s, const char *delim, char **saveptr);
|
||||
|
||||
/* timing functions */
|
||||
uint64_t time_stamp(void);
|
||||
uint64_t time_elapsed(uint64_t t1, uint64_t t2);
|
||||
|
||||
73
src/uuid.c
Normal file
73
src/uuid.c
Normal file
@@ -0,0 +1,73 @@
|
||||
/* uuid.c
|
||||
* strophe XMPP client library -- UUID generation
|
||||
*
|
||||
* Copyright (C) 2015 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.
|
||||
*/
|
||||
|
||||
/** @file
|
||||
* Generation of UUID version 4 according to RFC4122.
|
||||
*/
|
||||
|
||||
#include "strophe.h"
|
||||
#include "common.h"
|
||||
#include "rand.h"
|
||||
|
||||
/** @def XMPP_UUID_LEN
|
||||
* UUID length in string representation excluding '\0'.
|
||||
*/
|
||||
#define XMPP_UUID_LEN 36
|
||||
|
||||
/** Generate UUID version 4 in pre-allocated buffer.
|
||||
*
|
||||
* @param ctx a Strophe context object
|
||||
* @param uuid pre-allocated buffer of size (XMPP_UUID_LEN + 1)
|
||||
*/
|
||||
static void crypto_uuid_gen(xmpp_ctx_t *ctx, char *uuid)
|
||||
{
|
||||
unsigned char buf[16];
|
||||
int i = 0; /* uuid iterator */
|
||||
int j = 0; /* buf iterator */
|
||||
|
||||
static const char hex[] = {'0', '1', '2', '3', '4', '5', '6', '7',
|
||||
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
|
||||
|
||||
xmpp_rand_bytes(ctx->rand, buf, sizeof(buf));
|
||||
buf[8] &= 0x3f;
|
||||
buf[8] |= 0x80;
|
||||
buf[6] &= 0x0f;
|
||||
buf[6] |= 0x40;
|
||||
while (i < XMPP_UUID_LEN) {
|
||||
if (i == 8 || i == 13 || i == 18 || i == 23)
|
||||
uuid[i++] = '-';
|
||||
else {
|
||||
uuid[i++] = hex[buf[j] >> 4];
|
||||
uuid[i++] = hex[buf[j] & 0x0f];
|
||||
++j;
|
||||
}
|
||||
}
|
||||
uuid[XMPP_UUID_LEN] = '\0';
|
||||
}
|
||||
|
||||
/** Generate UUID version 4.
|
||||
* This function allocates memory for the resulting string and must be freed
|
||||
* with xmpp_free().
|
||||
*
|
||||
* @param ctx a Strophe context object
|
||||
*
|
||||
* @return ASCIIZ string
|
||||
*/
|
||||
char *xmpp_uuid_gen(xmpp_ctx_t *ctx)
|
||||
{
|
||||
char *uuid;
|
||||
|
||||
uuid = xmpp_alloc(ctx, XMPP_UUID_LEN + 1);
|
||||
if (uuid != NULL) {
|
||||
crypto_uuid_gen(ctx, uuid);
|
||||
}
|
||||
return uuid;
|
||||
}
|
||||
163
strophe.h
163
strophe.h
@@ -16,12 +16,12 @@
|
||||
#ifndef __LIBSTROPHE_STROPHE_H__
|
||||
#define __LIBSTROPHE_STROPHE_H__
|
||||
|
||||
#include <stddef.h> /* size_t */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/* namespace defines */
|
||||
/** @def XMPP_NS_CLIENT
|
||||
* Namespace definition for 'jabber:client'.
|
||||
@@ -115,9 +115,13 @@ typedef struct _xmpp_log_t xmpp_log_t;
|
||||
typedef struct _xmpp_ctx_t xmpp_ctx_t;
|
||||
|
||||
xmpp_ctx_t *xmpp_ctx_new(const xmpp_mem_t * const mem,
|
||||
const xmpp_log_t * const log);
|
||||
const xmpp_log_t * const log);
|
||||
void xmpp_ctx_free(xmpp_ctx_t * const ctx);
|
||||
|
||||
/* free some blocks returned by other APIs, for example the
|
||||
buffer you get from xmpp_stanza_to_text */
|
||||
void xmpp_free(const xmpp_ctx_t * const ctx, void *p);
|
||||
|
||||
struct _xmpp_mem_t {
|
||||
void *(*alloc)(const size_t size, void * const userdata);
|
||||
void (*free)(void *p, void * const userdata);
|
||||
@@ -146,7 +150,6 @@ typedef void (*xmpp_log_handler)(void * const userdata,
|
||||
struct _xmpp_log_t {
|
||||
xmpp_log_handler handler;
|
||||
void *userdata;
|
||||
/* mutex_t lock; */
|
||||
};
|
||||
|
||||
/* return a default logger filtering at a given level */
|
||||
@@ -158,9 +161,19 @@ xmpp_log_t *xmpp_get_default_logger(xmpp_log_level_t level);
|
||||
typedef struct _xmpp_conn_t xmpp_conn_t;
|
||||
typedef struct _xmpp_stanza_t xmpp_stanza_t;
|
||||
|
||||
/* connection flags */
|
||||
#define XMPP_CONN_FLAG_DISABLE_TLS (1UL << 0)
|
||||
#define XMPP_CONN_FLAG_MANDATORY_TLS (1UL << 1)
|
||||
#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)
|
||||
|
||||
/* connect callback */
|
||||
typedef enum {
|
||||
XMPP_CONN_CONNECT,
|
||||
XMPP_CONN_RAW_CONNECT,
|
||||
XMPP_CONN_DISCONNECT,
|
||||
XMPP_CONN_FAIL
|
||||
} xmpp_conn_event_t;
|
||||
@@ -205,16 +218,20 @@ typedef void (*xmpp_conn_handler)(xmpp_conn_t * const conn,
|
||||
void * const userdata);
|
||||
|
||||
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);
|
||||
|
||||
long xmpp_conn_get_flags(const xmpp_conn_t * const conn);
|
||||
int xmpp_conn_set_flags(xmpp_conn_t * const conn, long flags);
|
||||
const char *xmpp_conn_get_jid(const xmpp_conn_t * const conn);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
int xmpp_conn_is_secured(xmpp_conn_t * const conn);
|
||||
void xmpp_conn_set_keepalive(xmpp_conn_t * const conn, int timeout, int interval);
|
||||
|
||||
int xmpp_connect_client(xmpp_conn_t * const conn,
|
||||
const char * const altdomain,
|
||||
@@ -226,6 +243,16 @@ int xmpp_connect_component(xmpp_conn_t * const conn, const char * const server,
|
||||
unsigned short port, xmpp_conn_handler callback,
|
||||
void * const userdata);
|
||||
|
||||
int xmpp_connect_raw(xmpp_conn_t * const conn,
|
||||
const char * const altdomain,
|
||||
unsigned short altport,
|
||||
xmpp_conn_handler callback,
|
||||
void * const userdata);
|
||||
int xmpp_conn_open_stream_default(xmpp_conn_t * const conn);
|
||||
int xmpp_conn_open_stream(xmpp_conn_t * const conn, char **attributes,
|
||||
size_t attributes_len);
|
||||
int xmpp_conn_tls_start(xmpp_conn_t * const conn);
|
||||
|
||||
void xmpp_disconnect(xmpp_conn_t * const conn);
|
||||
|
||||
void xmpp_send(xmpp_conn_t * const conn,
|
||||
@@ -277,28 +304,24 @@ void xmpp_id_handler_delete(xmpp_conn_t * const conn,
|
||||
void xmpp_register_stanza_handler(conn, stanza, xmlns, type, handler)
|
||||
*/
|
||||
|
||||
/** stanzas **/
|
||||
/* stanzas */
|
||||
|
||||
/** allocate an initialize a blank stanza */
|
||||
/* allocate and initialize a blank stanza */
|
||||
xmpp_stanza_t *xmpp_stanza_new(xmpp_ctx_t *ctx);
|
||||
|
||||
/** clone a stanza */
|
||||
/* clone a stanza */
|
||||
xmpp_stanza_t *xmpp_stanza_clone(xmpp_stanza_t * const stanza);
|
||||
|
||||
/** copies a stanza and all children */
|
||||
xmpp_stanza_t * xmpp_stanza_copy(const xmpp_stanza_t * const stanza);
|
||||
/* copies a stanza and all children */
|
||||
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);
|
||||
|
||||
/** free some blocks returned by other APIs, for example the
|
||||
buffer you get from xmpp_stanza_to_text **/
|
||||
void xmpp_free(const xmpp_ctx_t * const ctx, void *p);
|
||||
|
||||
int xmpp_stanza_is_text(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,
|
||||
char ** const buf, size_t * const buflen);
|
||||
|
||||
@@ -308,18 +331,18 @@ xmpp_stanza_t *xmpp_stanza_get_child_by_name(xmpp_stanza_t * const stanza,
|
||||
xmpp_stanza_t *xmpp_stanza_get_child_by_ns(xmpp_stanza_t * const stanza,
|
||||
const char * const ns);
|
||||
xmpp_stanza_t *xmpp_stanza_get_next(xmpp_stanza_t * const stanza);
|
||||
char *xmpp_stanza_get_attribute(xmpp_stanza_t * const stanza,
|
||||
const char * const name);
|
||||
char * xmpp_stanza_get_ns(xmpp_stanza_t * const stanza);
|
||||
int xmpp_stanza_add_child(xmpp_stanza_t *stanza, xmpp_stanza_t *child);
|
||||
|
||||
const char *xmpp_stanza_get_attribute(xmpp_stanza_t * const stanza,
|
||||
const char * const name);
|
||||
int xmpp_stanza_get_attribute_count(xmpp_stanza_t * const stanza);
|
||||
int xmpp_stanza_get_attributes(xmpp_stanza_t * const stanza,
|
||||
const char **attr, int attrlen);
|
||||
/* concatenate all child text nodes. this function
|
||||
* 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_ptr(xmpp_stanza_t * const stanza);
|
||||
char *xmpp_stanza_get_name(xmpp_stanza_t * const stanza);
|
||||
|
||||
int xmpp_stanza_add_child(xmpp_stanza_t *stanza, xmpp_stanza_t *child);
|
||||
int xmpp_stanza_set_ns(xmpp_stanza_t * const stanza, const char * const ns);
|
||||
const char *xmpp_stanza_get_text_ptr(xmpp_stanza_t * const stanza);
|
||||
const char *xmpp_stanza_get_name(xmpp_stanza_t * const stanza);
|
||||
/* set_attribute adds/replaces attributes */
|
||||
int xmpp_stanza_set_attribute(xmpp_stanza_t * const stanza,
|
||||
const char * const key,
|
||||
@@ -331,39 +354,83 @@ int xmpp_stanza_set_text(xmpp_stanza_t *stanza,
|
||||
int xmpp_stanza_set_text_with_size(xmpp_stanza_t *stanza,
|
||||
const char * const text,
|
||||
const size_t size);
|
||||
int xmpp_stanza_del_attribute(xmpp_stanza_t * const stanza,
|
||||
const char * const name);
|
||||
|
||||
/* common stanza helpers */
|
||||
char *xmpp_stanza_get_type(xmpp_stanza_t * const stanza);
|
||||
char *xmpp_stanza_get_id(xmpp_stanza_t * const stanza);
|
||||
int xmpp_stanza_set_id(xmpp_stanza_t * const stanza,
|
||||
const char * const id);
|
||||
int xmpp_stanza_set_type(xmpp_stanza_t * const stanza,
|
||||
const char * const type);
|
||||
|
||||
/* unimplemented
|
||||
int xmpp_stanza_set_to();
|
||||
int xmpp_stanza_set_from();
|
||||
*/
|
||||
const char *xmpp_stanza_get_ns(xmpp_stanza_t * const stanza);
|
||||
const char *xmpp_stanza_get_type(xmpp_stanza_t * const stanza);
|
||||
const char *xmpp_stanza_get_id(xmpp_stanza_t * const stanza);
|
||||
const char *xmpp_stanza_get_to(xmpp_stanza_t * const stanza);
|
||||
const char *xmpp_stanza_get_from(xmpp_stanza_t * const stanza);
|
||||
int xmpp_stanza_set_ns(xmpp_stanza_t * const stanza, const char * const ns);
|
||||
int xmpp_stanza_set_id(xmpp_stanza_t * const stanza, const char * const id);
|
||||
int xmpp_stanza_set_type(xmpp_stanza_t * const stanza, const char * const type);
|
||||
int xmpp_stanza_set_to(xmpp_stanza_t * const stanza, const char * const to);
|
||||
int xmpp_stanza_set_from(xmpp_stanza_t * const stanza, const char * const from);
|
||||
|
||||
/* allocate and initialize a stanza in reply to another */
|
||||
/* unimplemented
|
||||
xmpp_stanza_t *xmpp_stanza_reply(const xmpp_stanza_t *stanza);
|
||||
*/
|
||||
xmpp_stanza_t *xmpp_stanza_reply(xmpp_stanza_t * const stanza);
|
||||
|
||||
/* stanza subclasses */
|
||||
/* unimplemented
|
||||
void xmpp_message_new();
|
||||
void xmpp_message_get_body();
|
||||
void xmpp_message_set_body();
|
||||
xmpp_stanza_t *xmpp_message_new(xmpp_ctx_t *ctx, const char * const type,
|
||||
const char * const to, const char * const id);
|
||||
char *xmpp_message_get_body(xmpp_stanza_t *msg);
|
||||
int xmpp_message_set_body(xmpp_stanza_t *msg, const char * const text);
|
||||
|
||||
void xmpp_iq_new();
|
||||
void xmpp_presence_new();
|
||||
*/
|
||||
xmpp_stanza_t *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);
|
||||
|
||||
/* jid */
|
||||
|
||||
/* these return new strings that must be xmpp_free()'d */
|
||||
char *xmpp_jid_new(xmpp_ctx_t *ctx, const char *node,
|
||||
const char *domain,
|
||||
const char *resource);
|
||||
char *xmpp_jid_bare(xmpp_ctx_t *ctx, const char *jid);
|
||||
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_resource(xmpp_ctx_t *ctx, const char *jid);
|
||||
|
||||
/* event loop */
|
||||
|
||||
/** event loop **/
|
||||
void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout);
|
||||
void xmpp_run(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 */
|
||||
|
||||
char *xmpp_uuid_gen(xmpp_ctx_t *ctx);
|
||||
|
||||
/* SHA1 */
|
||||
|
||||
/** @def XMPP_SHA1_DIGEST_SIZE
|
||||
* Size of the SHA1 message digest.
|
||||
*/
|
||||
#define XMPP_SHA1_DIGEST_SIZE 20
|
||||
|
||||
typedef struct _xmpp_sha1_t xmpp_sha1_t;
|
||||
|
||||
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);
|
||||
void xmpp_sha1_free(xmpp_sha1_t *sha1);
|
||||
void xmpp_sha1_update(xmpp_sha1_t *sha1, const unsigned char *data, size_t len);
|
||||
void xmpp_sha1_final(xmpp_sha1_t *sha1);
|
||||
char *xmpp_sha1_to_string(xmpp_sha1_t *sha1, char *s, size_t slen);
|
||||
char *xmpp_sha1_to_string_alloc(xmpp_sha1_t *sha1);
|
||||
void xmpp_sha1_to_digest(xmpp_sha1_t *sha1, unsigned char *digest);
|
||||
|
||||
/* Base64 */
|
||||
|
||||
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);
|
||||
void xmpp_base64_decode_bin(xmpp_ctx_t *ctx, const char *base64, size_t len,
|
||||
unsigned char **out, size_t *outlen);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
168
strophepp.h
168
strophepp.h
@@ -5,7 +5,7 @@
|
||||
**
|
||||
** This software is provided AS-IS with no warranty, either express or
|
||||
** implied.
|
||||
**
|
||||
**
|
||||
** This program is dual licensed under the MIT and GPLv3 licenses.
|
||||
*/
|
||||
|
||||
@@ -21,112 +21,112 @@
|
||||
namespace XMPP {
|
||||
class Context {
|
||||
private:
|
||||
xmpp_mem_t m_mem;
|
||||
xmpp_log_t m_log;
|
||||
xmpp_ctx_t *m_ctx;
|
||||
xmpp_mem_t m_mem;
|
||||
xmpp_log_t m_log;
|
||||
xmpp_ctx_t *m_ctx;
|
||||
|
||||
public:
|
||||
Context();
|
||||
virtual ~Context();
|
||||
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);
|
||||
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();
|
||||
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);
|
||||
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;
|
||||
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();
|
||||
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();
|
||||
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);
|
||||
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;
|
||||
Context *m_ctx;
|
||||
xmpp_conn_t *conn;
|
||||
|
||||
void *operator new(size_t size, Context *ctx);
|
||||
Connection(Context *ctx);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -10,26 +10,34 @@
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <check.h>
|
||||
|
||||
#include <strophe.h>
|
||||
#include "strophe.h"
|
||||
#include "parser.h"
|
||||
|
||||
#include "test.h"
|
||||
|
||||
START_TEST(create_destroy)
|
||||
#define fail_unless(expr) do { \
|
||||
int result = (expr); \
|
||||
if (!result) { \
|
||||
printf("%s:%d: Assertion failed: %s\n", \
|
||||
__FILE__, __LINE__, #expr); \
|
||||
exit(1); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static void create_destroy(void)
|
||||
{
|
||||
xmpp_ctx_t *ctx;
|
||||
parser_t *parser;
|
||||
|
||||
ctx = xmpp_ctx_new(NULL, NULL);
|
||||
parser = parser_new(ctx, NULL, NULL, NULL, NULL);
|
||||
fail_unless(parser != NULL, "Parser creation failed.");
|
||||
fail_unless(parser != NULL);
|
||||
parser_free(parser);
|
||||
xmpp_ctx_free(ctx);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
int cbtest_got_start = 0;
|
||||
void cbtest_handle_start(char *name, char **attrs, void *userdata)
|
||||
@@ -52,7 +60,7 @@ void cbtest_handle_stanza(xmpp_stanza_t *stanza, void *userdata)
|
||||
cbtest_got_stanza = 1;
|
||||
}
|
||||
|
||||
START_TEST(callbacks)
|
||||
static void callbacks(void)
|
||||
{
|
||||
xmpp_ctx_t *ctx;
|
||||
parser_t *parser;
|
||||
@@ -65,8 +73,11 @@ START_TEST(callbacks)
|
||||
cbtest_handle_stanza, NULL);
|
||||
|
||||
ret = parser_feed(parser, "<stream>", 8);
|
||||
fail_unless(ret != 0);
|
||||
ret = parser_feed(parser, "<message/>", 10);
|
||||
parser_feed(parser, "</stream>", 9);
|
||||
fail_unless(ret != 0);
|
||||
ret = parser_feed(parser, "</stream>", 9);
|
||||
fail_unless(ret != 0);
|
||||
|
||||
fail_unless(cbtest_got_start == 1);
|
||||
fail_unless(cbtest_got_end == 1);
|
||||
@@ -75,16 +86,18 @@ START_TEST(callbacks)
|
||||
parser_free(parser);
|
||||
xmpp_ctx_free(ctx);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
Suite *parser_suite(void)
|
||||
int main()
|
||||
{
|
||||
Suite *s = suite_create("Parser");
|
||||
TCase *tc_core = tcase_create("Core");
|
||||
tcase_add_test(tc_core, create_destroy);
|
||||
tcase_add_test(tc_core, callbacks);
|
||||
suite_add_tcase(s, tc_core);
|
||||
return s;
|
||||
}
|
||||
printf("XML parser tests.\n");
|
||||
|
||||
TEST_MAIN
|
||||
printf("create-destroy: ");
|
||||
create_destroy();
|
||||
printf("ok\n");
|
||||
|
||||
printf("callbacks: ");
|
||||
callbacks();
|
||||
printf("ok\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
90
tests/res_query_dump.c
Normal file
90
tests/res_query_dump.c
Normal file
@@ -0,0 +1,90 @@
|
||||
/* res_query_dump.c
|
||||
* Simple program to dump res_query(3) response
|
||||
*
|
||||
* Copyright (C) 2014 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.
|
||||
*/
|
||||
|
||||
/* Linux and OSX:
|
||||
* gcc -o res_query_dump tests/res_query_dump.c -lresolv
|
||||
* *BSD:
|
||||
* gcc -o res_query_dump tests/res_query_dump.c
|
||||
* QNX:
|
||||
* gcc -o res_query_dump tests/res_query_dump.c -lsocket
|
||||
* Solaris:
|
||||
* gcc -o res_query_dump tests/res_query_dump.c -lresolv -lsocket -lnsl
|
||||
*/
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/nameser.h>
|
||||
#include <resolv.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef T_SRV
|
||||
#define T_SRV 33
|
||||
#endif /* T_SRV */
|
||||
#ifndef C_IN
|
||||
#define C_IN 1
|
||||
#endif /* C_IN */
|
||||
|
||||
#define STEP 10
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
unsigned char buf[65536];
|
||||
char fulldomain[2048];
|
||||
char *service = "xmpp-client";
|
||||
char *proto = "tcp";
|
||||
char *domain = NULL;
|
||||
int len;
|
||||
int i;
|
||||
int j;
|
||||
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "%s: argument missed\n", argc > 0 ? argv[0] : "$0");
|
||||
fprintf(stderr, "Usage: %s <domain>\n", argc > 0 ? argv[0] : "$0");
|
||||
return 1;
|
||||
}
|
||||
|
||||
domain = argv[1];
|
||||
snprintf(fulldomain, sizeof(fulldomain), "_%s._%s.%s",
|
||||
service, proto, domain);
|
||||
errno = 0;
|
||||
len = res_query(fulldomain, C_IN, T_SRV, buf, sizeof(buf));
|
||||
|
||||
if (len < 0) {
|
||||
fprintf(stderr, "res_query(): Error occurred (errno=%d)\n", errno);
|
||||
}
|
||||
if (len == 0) {
|
||||
fprintf(stderr, "res_query(): Empty result\n");
|
||||
}
|
||||
if (len > 0) {
|
||||
printf("/* res_query(\"%s\", C_IN, T_SRV, ...) */\n", fulldomain);
|
||||
printf("static const unsigned char data[] = {\n");
|
||||
for (i = 0; i < len; i += STEP) {
|
||||
printf(" ");
|
||||
for (j = i; j < len && j < i + STEP; ++j) {
|
||||
printf(" 0x%02x,", buf[j]);
|
||||
}
|
||||
for (j = len; j < i + STEP; ++j) {
|
||||
printf(" ");
|
||||
}
|
||||
printf(" // ");
|
||||
for (j = i; j < len && j < i + STEP; ++j) {
|
||||
printf("%c", isprint(buf[j]) ? buf[j] : '.');
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
printf("};\n");
|
||||
}
|
||||
|
||||
return len <= 0;
|
||||
}
|
||||
54
tests/test.c
Normal file
54
tests/test.c
Normal file
@@ -0,0 +1,54 @@
|
||||
/* test.c
|
||||
* strophe XMPP client library -- common routines for tests
|
||||
*
|
||||
* Copyright (C) 2014 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 <string.h>
|
||||
|
||||
#include "test.h"
|
||||
|
||||
static uint8_t char_to_bin(char c)
|
||||
{
|
||||
return c <= '9' ? (uint8_t)(c - '0') :
|
||||
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)
|
||||
{
|
||||
size_t len = strlen(hex);
|
||||
size_t i;
|
||||
|
||||
assert(len % 2 == 0);
|
||||
|
||||
for (i = 0; i < len / 2; ++i) {
|
||||
bin[i] = char_to_bin(hex[i * 2]) * 16 + char_to_bin(hex[i * 2 + 1]);
|
||||
}
|
||||
*bin_len = len / 2;
|
||||
}
|
||||
|
||||
const char *test_bin_to_hex(const uint8_t *bin, size_t len)
|
||||
{
|
||||
static char buf[2048];
|
||||
size_t i;
|
||||
|
||||
static const char hex[] = {'0', '1', '2', '3', '4', '5', '6', '7',
|
||||
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
|
||||
|
||||
assert(ARRAY_SIZE(buf) > len * 2);
|
||||
|
||||
for (i = 0; i < len; ++i) {
|
||||
buf[i * 2] = hex[(bin[i] >> 4) & 0x0f];
|
||||
buf[i * 2 + 1] = hex[bin[i] & 0x0f];
|
||||
}
|
||||
buf[len * 2] = '\0';
|
||||
|
||||
return buf;
|
||||
}
|
||||
75
tests/test.h
75
tests/test.h
@@ -1,16 +1,69 @@
|
||||
/* test.h
|
||||
** libstrophe XMPP client library -- common routines for tests
|
||||
**
|
||||
** 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.
|
||||
*/
|
||||
|
||||
#ifndef __LIBSTROPHE_TEST_H__
|
||||
#define __LIBSTROPHE_TEST_H__
|
||||
|
||||
#define TEST_MAIN \
|
||||
int main(int argc, char **argv) {\
|
||||
int num_failed;\
|
||||
Suite *s = parser_suite();\
|
||||
SRunner *sr = srunner_create(s);\
|
||||
srunner_run_all(sr, CK_NORMAL);\
|
||||
num_failed = srunner_ntests_failed(sr);\
|
||||
srunner_free(sr);\
|
||||
return (num_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;\
|
||||
}\
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "ostypes.h"
|
||||
|
||||
#define TEST_MAIN \
|
||||
int main(int argc, char **argv) { \
|
||||
int num_failed; \
|
||||
Suite *s = parser_suite(); \
|
||||
SRunner *sr = srunner_create(s); \
|
||||
srunner_run_all(sr, CK_NORMAL); \
|
||||
num_failed = srunner_ntests_failed(sr); \
|
||||
srunner_free(sr); \
|
||||
return (num_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; \
|
||||
}
|
||||
|
||||
#ifndef ARRAY_SIZE
|
||||
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
|
||||
#endif
|
||||
|
||||
#define COMPARE(v1, v2) \
|
||||
do { \
|
||||
const char *__v1 = v1; \
|
||||
const char *__v2 = v2; \
|
||||
if (strcmp(__v1, __v2) != 0) { \
|
||||
printf("%s differs!\n" \
|
||||
"expected: %s\n" \
|
||||
"got: %s\n", \
|
||||
#v1, __v1, __v2); \
|
||||
exit(1); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define COMPARE_BUF(v1, len1, v2, len2) \
|
||||
do { \
|
||||
const uint8_t *__v1 = (uint8_t *)(v1); \
|
||||
const uint8_t *__v2 = (uint8_t *)(v2); \
|
||||
size_t __len1 = len1; \
|
||||
size_t __len2 = len2; \
|
||||
if (__len1 != __len2 || \
|
||||
memcmp(__v1, __v2, __len1) != 0) \
|
||||
{ \
|
||||
printf("%s differs!\n", #v1); \
|
||||
printf("expected: 0x%s\n", \
|
||||
test_bin_to_hex(__v1, __len1)); \
|
||||
printf("got: 0x%s\n", \
|
||||
test_bin_to_hex(__v2, __len2)); \
|
||||
exit(1); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
void test_hex_to_bin(const char *hex, uint8_t *bin, size_t *bin_len);
|
||||
const char *test_bin_to_hex(const uint8_t *bin, size_t len);
|
||||
|
||||
#endif /* __LIBSTROPHE_TEST_H__ */
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* test_base64.c
|
||||
** libstrophe XMPP client library -- test routines for the base64 codec
|
||||
**
|
||||
** Copyright (C) 2005-2009 Collecta, Inc.
|
||||
** Copyright (C) 2005-2009 Collecta, Inc.
|
||||
**
|
||||
** This software is provided AS-IS with no warranty, either express
|
||||
** or implied.
|
||||
@@ -9,140 +9,170 @@
|
||||
** This program is dual licensed under the MIT and GPLv3 licenses.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "strophe.h"
|
||||
#include "common.h"
|
||||
#include "sasl.h"
|
||||
|
||||
static const unsigned char text_1[] = "How now brown cow?";
|
||||
static const char base64_1[] = "SG93IG5vdyBicm93biBjb3c/";
|
||||
static const unsigned char text_2[] = {0x14,0xfb,0x9c,0x03,0xd9,0x7e,0x00};
|
||||
static const char base64_2[] = "FPucA9l+";
|
||||
static const unsigned char text_3[] =
|
||||
"From rest and sleep, which but thy pictures be, "
|
||||
"Much pleasure; then from thee much more must flow, "
|
||||
"And soonest our best men with thee do go, "
|
||||
"Rest of their bones, and soul's delivery.";
|
||||
static const char base64_3[] =
|
||||
"RnJvbSByZXN0IGFuZCBzbGVlcCwgd2hpY2ggYnV0IHRoeSBwaWN0dXJl"
|
||||
"cyBiZSwgTXVjaCBwbGVhc3VyZTsgdGhlbiBmcm9tIHRoZWUgbXVjaCBt"
|
||||
"b3JlIG11c3QgZmxvdywgQW5kIHNvb25lc3Qgb3VyIGJlc3QgbWVuIHdp"
|
||||
"dGggdGhlZSBkbyBnbywgUmVzdCBvZiB0aGVpciBib25lcywgYW5kIHNv"
|
||||
"dWwncyBkZWxpdmVyeS4=";
|
||||
static const unsigned char text_4[] =
|
||||
{0xd6, 0x2f, 0x27, 0x49, 0x7e, 0xdd, 0xf3, 0xd5,
|
||||
#include "test.h"
|
||||
|
||||
static const unsigned char test_2_raw[] =
|
||||
{0x14, 0xfb, 0x9c, 0x03, 0xd9, 0x7e, 0x00};
|
||||
static const unsigned char test_4_raw[] =
|
||||
{0xd6, 0x2f, 0x27, 0x49, 0x7e, 0xdd, 0xf3, 0xd5,
|
||||
0x41, 0xbc, 0x1b, 0xe9, 0xdf, 0xe9, 0xb3, 0x08, 0x00};
|
||||
static const char base64_4[] = "1i8nSX7d89VBvBvp3+mzCA==";
|
||||
static const char text_5[] =
|
||||
"realm=\"chesspark.com\",nonce=\"b243c0d663257a9149999cef2f83a22116559e93\",qop=\"auth\",charset=utf-8,algorithm=md5-sess";
|
||||
static const char base64_5[] =
|
||||
"cmVhbG09ImNoZXNzcGFyay5jb20iLG5vbmNlPSJiMjQzYzBkNjYzMjU3"
|
||||
"YTkxNDk5OTljZWYyZjgzYTIyMTE2NTU5ZTkzIixxb3A9ImF1dGgiLGNo"
|
||||
"YXJzZXQ9dXRmLTgsYWxnb3JpdGhtPW1kNS1zZXNz";
|
||||
|
||||
int test_encode(xmpp_ctx_t *ctx)
|
||||
{
|
||||
char *result;
|
||||
result = base64_encode(ctx, text_1, strlen(text_1));
|
||||
if (result == NULL) return 2;
|
||||
if (strlen(result) != strlen(base64_1)) return 1;
|
||||
if (strncmp(base64_1, result, strlen(base64_1))) return 1;
|
||||
xmpp_free(ctx,result);
|
||||
static const struct {
|
||||
char *raw;
|
||||
char *base64;
|
||||
} tests[] = {
|
||||
{
|
||||
.raw = "How now brown cow?",
|
||||
.base64 = "SG93IG5vdyBicm93biBjb3c/",
|
||||
},
|
||||
{
|
||||
.raw = (char *)test_2_raw,
|
||||
.base64 = "FPucA9l+",
|
||||
},
|
||||
{
|
||||
.raw =
|
||||
"From rest and sleep, which but thy pictures be, "
|
||||
"Much pleasure; then from thee much more must flow, "
|
||||
"And soonest our best men with thee do go, "
|
||||
"Rest of their bones, and soul's delivery.",
|
||||
.base64 =
|
||||
"RnJvbSByZXN0IGFuZCBzbGVlcCwgd2hpY2ggYnV0IHRoeSBwaWN0dXJl"
|
||||
"cyBiZSwgTXVjaCBwbGVhc3VyZTsgdGhlbiBmcm9tIHRoZWUgbXVjaCBt"
|
||||
"b3JlIG11c3QgZmxvdywgQW5kIHNvb25lc3Qgb3VyIGJlc3QgbWVuIHdp"
|
||||
"dGggdGhlZSBkbyBnbywgUmVzdCBvZiB0aGVpciBib25lcywgYW5kIHNv"
|
||||
"dWwncyBkZWxpdmVyeS4=",
|
||||
},
|
||||
{
|
||||
.raw = (char *)test_4_raw,
|
||||
.base64 = "1i8nSX7d89VBvBvp3+mzCA==",
|
||||
},
|
||||
{
|
||||
.raw =
|
||||
"realm=\"chesspark.com\",nonce=\"b243c0d663257a9149999cef2f83"
|
||||
"a22116559e93\",qop=\"auth\",charset=utf-8,algorithm=md5-sess",
|
||||
.base64 =
|
||||
"cmVhbG09ImNoZXNzcGFyay5jb20iLG5vbmNlPSJiMjQzYzBkNjYzMjU3"
|
||||
"YTkxNDk5OTljZWYyZjgzYTIyMTE2NTU5ZTkzIixxb3A9ImF1dGgiLGNo"
|
||||
"YXJzZXQ9dXRmLTgsYWxnb3JpdGhtPW1kNS1zZXNz",
|
||||
},
|
||||
|
||||
result = base64_encode(ctx, text_2, strlen(text_2));
|
||||
if (result == NULL) return 2;
|
||||
if (strlen(result) != strlen(base64_2)) return 1;
|
||||
if (strncmp(base64_2, result, strlen(base64_2))) return 1;
|
||||
xmpp_free(ctx,result);
|
||||
|
||||
result = base64_encode(ctx, text_3, strlen(text_3));
|
||||
if (result == NULL) return 2;
|
||||
if (strlen(result) != strlen(base64_3)) return 1;
|
||||
if (strncmp(base64_3, result, strlen(base64_3))) return 1;
|
||||
xmpp_free(ctx,result);
|
||||
|
||||
result = base64_encode(ctx, text_4, strlen(text_4));
|
||||
if (result == NULL) return 2;
|
||||
if (strlen(result) != strlen(base64_4)) return 1;
|
||||
if (strncmp(base64_4, result, strlen(base64_4))) return 1;
|
||||
xmpp_free(ctx,result);
|
||||
|
||||
result = base64_encode(ctx, text_5, strlen(text_5));
|
||||
if (result == NULL) return 2;
|
||||
if (strlen(result) != strlen(base64_5)) return 1;
|
||||
if (strncmp(base64_5, result, strlen(base64_5))) return 1;
|
||||
xmpp_free(ctx,result);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int test_decode(xmpp_ctx_t *ctx)
|
||||
{
|
||||
unsigned char *result;
|
||||
|
||||
result = base64_decode(ctx, base64_1, strlen(base64_1));
|
||||
if (result == NULL) return 2;
|
||||
if (strlen(result) != strlen(text_1)) return 1;
|
||||
if (strncmp(text_1, result, strlen(text_1))) return 1;
|
||||
xmpp_free(ctx,result);
|
||||
|
||||
result = base64_decode(ctx, base64_2, strlen(base64_2));
|
||||
if (result == NULL) return 2;
|
||||
if (strlen(result) != strlen(text_2)) return 1;
|
||||
if (strncmp(text_2, result, strlen(text_2))) return 1;
|
||||
xmpp_free(ctx,result);
|
||||
|
||||
result = base64_decode(ctx, base64_3, strlen(base64_3));
|
||||
if (result == NULL) return 2;
|
||||
if (strlen(result) != strlen(text_3)) return 1;
|
||||
if (strncmp(text_3, result, strlen(text_3))) return 1;
|
||||
xmpp_free(ctx,result);
|
||||
|
||||
result = base64_decode(ctx, base64_4, strlen(base64_4));
|
||||
if (result == NULL) return 2;
|
||||
if (strlen(result) != strlen(text_4)) return 1;
|
||||
if (strncmp(text_4, result, strlen(text_4))) return 1;
|
||||
xmpp_free(ctx,result);
|
||||
|
||||
result = base64_decode(ctx, base64_5, strlen(base64_5));
|
||||
if (result == NULL) return 2;
|
||||
if (strlen(result) != strlen(text_5)) return 1;
|
||||
if (strncmp(text_5, result, strlen(text_5))) return 1;
|
||||
xmpp_free(ctx,result);
|
||||
|
||||
return 0;
|
||||
}
|
||||
/* RFC4648 test vectors */
|
||||
{
|
||||
.raw = "",
|
||||
.base64 = "",
|
||||
},
|
||||
{
|
||||
.raw = "f",
|
||||
.base64 = "Zg==",
|
||||
},
|
||||
{
|
||||
.raw = "fo",
|
||||
.base64 = "Zm8=",
|
||||
},
|
||||
{
|
||||
.raw = "foo",
|
||||
.base64 = "Zm9v",
|
||||
},
|
||||
{
|
||||
.raw = "foob",
|
||||
.base64 = "Zm9vYg==",
|
||||
},
|
||||
{
|
||||
.raw = "fooba",
|
||||
.base64 = "Zm9vYmE=",
|
||||
},
|
||||
{
|
||||
.raw = "foobar",
|
||||
.base64 = "Zm9vYmFy",
|
||||
},
|
||||
};
|
||||
|
||||
static const unsigned char bin_data[] = {
|
||||
0xda, 0xa8, 0x81, 0x80, 0x00, 0x01, 0x00, 0x05,
|
||||
0x00, 0x00, 0x00, 0x00, 0x0c, 0x5f, 0x78, 0x6d,
|
||||
0x70, 0x70, 0x2d, 0x63, 0x6c, 0x69, 0x65, 0x6e,
|
||||
0x74, 0x04, 0x5f, 0x74, 0x63, 0x70, 0x05, 0x67,
|
||||
0x6d, 0x61, 0x69, 0x6c, 0x03, 0x63, 0x6f, 0x6d,
|
||||
0x00, 0x00, 0x21, 0x00, 0x01, 0xc0, 0x0c, 0x00,
|
||||
0x21, 0x00, 0x01, 0x00, 0x00, 0x02, 0x43, 0x00,
|
||||
0x1e, 0x00, 0x14, 0x00, 0x00, 0x14, 0x66, 0x04,
|
||||
0x61, 0x6c, 0x74, 0x31, 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, 0x34, 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, 0x32,
|
||||
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, 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[])
|
||||
{
|
||||
xmpp_ctx_t *ctx;
|
||||
int ret;
|
||||
unsigned char *udec;
|
||||
char *dec;
|
||||
char *enc;
|
||||
size_t len, i;
|
||||
|
||||
printf("BASE64 tests.\n");
|
||||
|
||||
printf("allocating context... ");
|
||||
ctx = xmpp_ctx_new(NULL, NULL);
|
||||
if (ctx == NULL) printf("failed to create context\n");
|
||||
if (ctx == NULL) return -1;
|
||||
printf("ok.\n");
|
||||
if (ctx == NULL) {
|
||||
fprintf(stderr, "failed to create context\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("testing encode... ");
|
||||
ret = test_encode(ctx);
|
||||
if (ret) printf("base64_encode failed!\n");
|
||||
if (ret) return ret;
|
||||
printf("ok.\n");
|
||||
for (i = 0; i < ARRAY_SIZE(tests); ++i) {
|
||||
printf("Test #%d: ", (int)i + 1);
|
||||
enc = xmpp_base64_encode(ctx, (unsigned char *)tests[i].raw,
|
||||
strlen(tests[i].raw));
|
||||
assert(enc != NULL);
|
||||
COMPARE(tests[i].base64, enc);
|
||||
xmpp_free(ctx, enc);
|
||||
|
||||
printf("testing decode... ");
|
||||
ret = test_decode(ctx);
|
||||
if (ret) printf("base64_decode failed!\n");
|
||||
if (ret) return ret;
|
||||
printf("ok.\n");
|
||||
dec = xmpp_base64_decode_str(ctx, tests[i].base64,
|
||||
strlen(tests[i].base64));
|
||||
assert(dec != NULL);
|
||||
COMPARE_BUF(tests[i].raw, strlen(tests[i].raw), dec, strlen(dec));
|
||||
xmpp_free(ctx, dec);
|
||||
printf("ok\n");
|
||||
}
|
||||
|
||||
printf("Test with binary data: ");
|
||||
enc = xmpp_base64_encode(ctx, bin_data, sizeof(bin_data));
|
||||
assert(enc != NULL);
|
||||
xmpp_base64_decode_bin(ctx, enc, strlen(enc), &udec, &len);
|
||||
assert(udec != NULL);
|
||||
assert(len != 0);
|
||||
assert(len == sizeof(bin_data));
|
||||
COMPARE_BUF(bin_data, sizeof(bin_data), udec, len);
|
||||
xmpp_free(ctx, udec);
|
||||
xmpp_free(ctx, enc);
|
||||
printf("ok\n");
|
||||
|
||||
printf("freeing context... ");
|
||||
xmpp_ctx_free(ctx);
|
||||
printf("ok.\n");
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -94,6 +94,8 @@ int main(int argc, char **argv)
|
||||
if (!(log_called && mem_alloc_called && mem_realloc_called &&
|
||||
mem_free_called))
|
||||
return 1;
|
||||
if (mem_alloc_called != mem_free_called)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -76,6 +76,18 @@ int main(int argc, char **argv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* test replacing old values */
|
||||
for (i = 0; i < nkeys; i++) {
|
||||
err = hash_add(table, keys[0], (void*)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], (void*)values[0]);
|
||||
|
||||
/* test cloning */
|
||||
clone = hash_clone(table);
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* test_base64.c
|
||||
/* test_jid.c
|
||||
** libstrophe XMPP client library -- test routines for the jid utils
|
||||
**
|
||||
** Copyright (C) 2005-2009 Collecta, Inc.
|
||||
** Copyright (C) 2005-2009 Collecta, Inc.
|
||||
**
|
||||
** This software is provided AS-IS with no warranty, either express
|
||||
** or implied.
|
||||
@@ -20,56 +20,74 @@ static const char jid2[] = "anyone@example.com/hullo";
|
||||
static const char jid3[] = "manic.porter@xyz.net/frob";
|
||||
static const char jid4[] = "domain.tld";
|
||||
|
||||
static const char *_s(const char *s)
|
||||
{
|
||||
return s == NULL ? "<NULL>" : s;
|
||||
}
|
||||
|
||||
int test_jid(xmpp_ctx_t *ctx)
|
||||
{
|
||||
char *bare;
|
||||
char *node;
|
||||
char *domain;
|
||||
char *resource;
|
||||
|
||||
bare = xmpp_jid_bare(ctx, jid1);
|
||||
node = xmpp_jid_node(ctx, jid1);
|
||||
domain = xmpp_jid_domain(ctx, jid1);
|
||||
resource = xmpp_jid_resource(ctx, jid1);
|
||||
printf("jid '%s' parsed to %s, %s, %s\n",
|
||||
jid1, node, domain, resource);
|
||||
if (strcmp(node, "foo")) return 1;
|
||||
if (strcmp(domain, "bar.com")) return 1;
|
||||
jid1, _s(node), _s(domain), _s(resource));
|
||||
if (bare == NULL || strcmp(bare, "foo@bar.com")) return 1;
|
||||
if (node == NULL || strcmp(node, "foo")) return 1;
|
||||
if (domain == NULL || strcmp(domain, "bar.com")) 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);
|
||||
domain = xmpp_jid_domain(ctx, jid2);
|
||||
resource = xmpp_jid_resource(ctx, jid2);
|
||||
printf("jid '%s' parsed to %s, %s, %s\n",
|
||||
jid2, node, domain, resource);
|
||||
if (strcmp(node, "anyone")) return 1;
|
||||
if (strcmp(domain, "example.com")) return 1;
|
||||
if (strcmp(resource, "hullo")) return 1;
|
||||
jid2, _s(node), _s(domain), _s(resource));
|
||||
if (bare == NULL || strcmp(bare, "anyone@example.com")) return 1;
|
||||
if (node == NULL || strcmp(node, "anyone")) return 1;
|
||||
if (domain == NULL || strcmp(domain, "example.com")) 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);
|
||||
domain = xmpp_jid_domain(ctx, jid3);
|
||||
resource = xmpp_jid_resource(ctx, jid3);
|
||||
printf("jid '%s' parsed to %s, %s, %s\n",
|
||||
jid3, node, domain, resource);
|
||||
if (strcmp(node, "manic.porter")) return 1;
|
||||
if (strcmp(domain, "xyz.net")) return 1;
|
||||
if (strcmp(resource, "frob")) return 1;
|
||||
jid3, _s(node), _s(domain), _s(resource));
|
||||
if (bare == NULL || strcmp(bare, "manic.porter@xyz.net")) return 1;
|
||||
if (node == NULL || strcmp(node, "manic.porter")) return 1;
|
||||
if (domain == NULL || strcmp(domain, "xyz.net")) 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);
|
||||
domain = xmpp_jid_domain(ctx, jid4);
|
||||
resource = xmpp_jid_resource(ctx, jid4);
|
||||
printf("jid '%s' parsed to %s, %s, %s\n",
|
||||
jid4, node, domain, resource);
|
||||
jid4, _s(node), _s(domain), _s(resource));
|
||||
if (bare == NULL || strcmp(bare, "domain.tld")) return 1;
|
||||
if (node != NULL) return 1;
|
||||
if (strcmp(domain, "domain.tld")) return 1;
|
||||
if (domain == NULL || strcmp(domain, "domain.tld")) 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);
|
||||
@@ -99,23 +117,23 @@ int main(int argc, char *argv[])
|
||||
xmpp_ctx_t *ctx;
|
||||
int ret;
|
||||
|
||||
printf("allocating context... ");
|
||||
printf("allocating context... ");
|
||||
ctx = xmpp_ctx_new(NULL, NULL);
|
||||
if (ctx == NULL) printf("failed to create context\n");
|
||||
if (ctx == NULL) return -1;
|
||||
printf("ok.\n");
|
||||
|
||||
printf("testing jid routines... ");
|
||||
printf("testing jid routines...\n");
|
||||
ret = test_jid(ctx);
|
||||
if (ret) printf("failed!\n");
|
||||
if (ret) printf("testing jid routines... failed!\n");
|
||||
if (ret) return ret;
|
||||
printf("ok.\n");
|
||||
printf("testing jid routines... ok.\n");
|
||||
|
||||
printf("testing jid new routines... ");
|
||||
printf("testing jid new routines...\n");
|
||||
ret = test_jid_new(ctx);
|
||||
if (ret) printf("failed!\n");
|
||||
if (ret) printf("testing jid new routines... failed!\n");
|
||||
if (ret) return ret;
|
||||
printf("ok.\n");
|
||||
printf("testing jid new routines... ok.\n");
|
||||
|
||||
printf("freeing context... ");
|
||||
xmpp_ctx_free(ctx);
|
||||
|
||||
77
tests/test_md5.c
Normal file
77
tests/test_md5.c
Normal file
@@ -0,0 +1,77 @@
|
||||
/* test_md5.c
|
||||
* strophe XMPP client library -- test vectors for MD5
|
||||
*
|
||||
* Copyright (C) 2015 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_md5 -I./src tests/test_md5.c tests/test.c src/md5.c */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "test.h"
|
||||
#include "md5.h"
|
||||
|
||||
/*
|
||||
* Test vectors for MD5 (RFC1321).
|
||||
*/
|
||||
static const struct {
|
||||
const char *data;
|
||||
const char *md5;
|
||||
} tests[] = {
|
||||
{
|
||||
.data = "",
|
||||
.md5 = "d41d8cd98f00b204e9800998ecf8427e",
|
||||
},
|
||||
{
|
||||
.data = "a",
|
||||
.md5 = "0cc175b9c0f1b6a831c399e269772661",
|
||||
},
|
||||
{
|
||||
.data = "abc",
|
||||
.md5 = "900150983cd24fb0d6963f7d28e17f72",
|
||||
},
|
||||
{
|
||||
.data = "message digest",
|
||||
.md5 = "f96b697d7cb7938d525a2f31aaf161d0",
|
||||
},
|
||||
{
|
||||
.data = "abcdefghijklmnopqrstuvwxyz",
|
||||
.md5 = "c3fcd3d76192e4007dfb496cca67e13b",
|
||||
},
|
||||
{
|
||||
.data = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcde"
|
||||
"fghijklmnopqrstuvwxyz0123456789",
|
||||
.md5 = "d174ab98d277d9f5a5611c2c9f419d9f",
|
||||
},
|
||||
{
|
||||
.data = "1234567890123456789012345678901"
|
||||
"2345678901234567890123456789012"
|
||||
"345678901234567890",
|
||||
.md5 = "57edf4a22be3c955ac49da2e2107b67a",
|
||||
},
|
||||
};
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct MD5Context ctx;
|
||||
unsigned char digest[16];
|
||||
size_t i;
|
||||
|
||||
printf("MD5 tests.\n");
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(tests); ++i) {
|
||||
printf("Test #%zu: ", i + 1);
|
||||
MD5Init(&ctx);
|
||||
MD5Update(&ctx, (unsigned char *)tests[i].data, strlen(tests[i].data));
|
||||
MD5Final(digest, &ctx);
|
||||
COMPARE(tests[i].md5, test_bin_to_hex(digest, sizeof(digest)));
|
||||
printf("ok\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
145
tests/test_rand.c
Normal file
145
tests/test_rand.c
Normal file
@@ -0,0 +1,145 @@
|
||||
/* check_rand.c
|
||||
* strophe XMPP client library -- test vectors for Hash_DRBG
|
||||
*
|
||||
* Copyright (C) 2014 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_rand -I./src tests/test_rand.c tests/test.c src/sha1.c */
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "test.h"
|
||||
|
||||
/* include rand.c to access private structures and functions */
|
||||
#include "rand.c"
|
||||
|
||||
/* stubs to build test without whole libstrophe */
|
||||
void *xmpp_alloc(const xmpp_ctx_t * const ctx, const size_t size) {
|
||||
return NULL;
|
||||
}
|
||||
void xmpp_free(const xmpp_ctx_t * const ctx, void *p) { }
|
||||
int xmpp_snprintf (char *str, size_t count, const char *fmt, ...) {
|
||||
return 0;
|
||||
}
|
||||
uint64_t time_stamp(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct {
|
||||
const char *entropy_input;
|
||||
const char *nonce;
|
||||
size_t returned_bytes;
|
||||
/* after instantiate */
|
||||
const char *V1;
|
||||
const char *C1;
|
||||
/* after first generate */
|
||||
const char *V2;
|
||||
const char *C2;
|
||||
/* after second generate */
|
||||
const char *V3;
|
||||
const char *C3;
|
||||
const char *output;
|
||||
} test_vectors[] = {
|
||||
{
|
||||
.entropy_input = "136cf1c174e5a09f66b962d994396525",
|
||||
.nonce = "fff1c6645f19231f",
|
||||
.returned_bytes = 80,
|
||||
.V1 = "a884a83fa40bcf730e7395dd5800ea7101b48"
|
||||
"77aaa29da9b7bc0bd2bd052b9b4022f83bae3"
|
||||
"8064134a233835845fdd1442bf3a0221bdc8",
|
||||
.C1 = "4977fb1268c1f6286b5b3969d416fb8ca7e4e"
|
||||
"aab7fd2edefc239202baa033f8b44e9145148"
|
||||
"ad24ce83d597176a0bacc84c99246f15e088",
|
||||
.V2 = "f1fca3520ccdc59b79cecf472c17e5fda9997"
|
||||
"22629fcc88b3df9dd577a55f93f47189892b1"
|
||||
"8e1c5f39dfc077ae256588eecec7bbd0323c",
|
||||
.C2 = "4977fb1268c1f6286b5b3969d416fb8ca7e4e"
|
||||
"aab7fd2edefc239202baa033f8b44e9145148"
|
||||
"ad24ce83d597176a0bacc84c99246f15e088",
|
||||
.V3 = "3b749e64758fbbc3e52a08b1002ee18a517e5"
|
||||
"cd1a9cfb67b0032fd83245938ca8c01add770"
|
||||
"68515bde248c75adea10bbaaf0bc18e66a2c",
|
||||
.C3 = "4977fb1268c1f6286b5b3969d416fb8ca7e4e"
|
||||
"aab7fd2edefc239202baa033f8b44e9145148"
|
||||
"ad24ce83d597176a0bacc84c99246f15e088",
|
||||
.output = "0e28130fa5ca11edd3293ca26fdb8ae1810611f7"
|
||||
"8715082ed3841e7486f16677b28e33ffe0b93d98"
|
||||
"ba57ba358c1343ab2a26b4eb7940f5bc63938464"
|
||||
"1ee80a25140331076268bd1ce702ad534dda0ed8",
|
||||
},
|
||||
|
||||
{
|
||||
.entropy_input = "dfed69b08902fcfb795d5d35dbe23f6b",
|
||||
.nonce = "37258e820432e392",
|
||||
.returned_bytes = 80,
|
||||
.V1 = "2708022f0f6d13cd8bc139ceb86ee237ee124"
|
||||
"e17029ac4f053d41526285599d4eac5029972"
|
||||
"7d83a0df0d5fa9824d5f14d7e7e9c8bdb165",
|
||||
.C1 = "fdb1a827c30e436c997261da6dc31ae7c27ee"
|
||||
"28e5c29b2ee0ca57b44ab78b7b0d1e8b459ba"
|
||||
"7285f5d93abf218d16d834a803c2330321cd",
|
||||
.V2 = "24b9aa56d27b573a25339ba92631fd1fb0913"
|
||||
"0a55ec477de6079906ad3ce5185bcadb7b047"
|
||||
"627060f80afb8529c18b46567e6b79dffb01",
|
||||
.C2 = "fdb1a827c30e436c997261da6dc31ae7c27ee"
|
||||
"28e5c29b2ee0ca57b44ab78b7b0d1e8b459ba"
|
||||
"7285f5d93abf218d16d834a803c2330321cd",
|
||||
.V3 = "226b527e95899aa6bea5fd8393f5180773101"
|
||||
"333baee2acc6d1f0baf7f4709368e966c945c"
|
||||
"d4a0d86093183375443379b09c08e4381fa8",
|
||||
.C3 = "fdb1a827c30e436c997261da6dc31ae7c27ee"
|
||||
"28e5c29b2ee0ca57b44ab78b7b0d1e8b459ba"
|
||||
"7285f5d93abf218d16d834a803c2330321cd",
|
||||
.output = "adcb8e2cbbc5957d538a20db18b5e7fe350a90a2"
|
||||
"01359fab9e0f154c53aa146bc6af1fcc7ff8f330"
|
||||
"b8d9f3d7b038488ba627e6fa21d0147377b13404"
|
||||
"22b22634b412dac69ac82c35b5fb411a4e42a133",
|
||||
},
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
size_t i;
|
||||
uint8_t entropy_input[1024];
|
||||
size_t entropy_input_len;
|
||||
uint8_t nonce[1024];
|
||||
size_t nonce_len;
|
||||
uint8_t output[1024];
|
||||
Hash_DRBG_CTX ctx;
|
||||
|
||||
printf("Hash_DRBG tests.\n");
|
||||
for (i = 0; i < ARRAY_SIZE(test_vectors); ++i) {
|
||||
printf("Test #%d: ", (int)i + 1);
|
||||
test_hex_to_bin(test_vectors[i].entropy_input, entropy_input,
|
||||
&entropy_input_len);
|
||||
test_hex_to_bin(test_vectors[i].nonce, nonce, &nonce_len);
|
||||
|
||||
Hash_DRBG_Instantiate(&ctx, entropy_input, entropy_input_len,
|
||||
nonce, nonce_len);
|
||||
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)));
|
||||
assert(ctx.reseed_counter == 1);
|
||||
|
||||
Hash_DRBG_Generate(&ctx, output, test_vectors[i].returned_bytes);
|
||||
COMPARE(test_vectors[i].V2, test_bin_to_hex(ctx.V, sizeof(ctx.V)));
|
||||
COMPARE(test_vectors[i].C2, test_bin_to_hex(ctx.C, sizeof(ctx.C)));
|
||||
assert(ctx.reseed_counter == 2);
|
||||
|
||||
Hash_DRBG_Generate(&ctx, output, test_vectors[i].returned_bytes);
|
||||
COMPARE(test_vectors[i].V3, test_bin_to_hex(ctx.V, sizeof(ctx.V)));
|
||||
COMPARE(test_vectors[i].C3, test_bin_to_hex(ctx.C, sizeof(ctx.C)));
|
||||
COMPARE(test_vectors[i].output,
|
||||
test_bin_to_hex(output, test_vectors[i].returned_bytes));
|
||||
assert(ctx.reseed_counter == 3);
|
||||
printf("ok\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
256
tests/test_resolver.c
Normal file
256
tests/test_resolver.c
Normal file
@@ -0,0 +1,256 @@
|
||||
/* test_resolver.c
|
||||
* strophe XMPP client library -- tests for resolver
|
||||
*
|
||||
* Copyright (C) 2015 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 <stdio.h>
|
||||
|
||||
#include "strophe.h"
|
||||
#include "rand.h"
|
||||
#include "resolver.h"
|
||||
#include "test.h"
|
||||
|
||||
/* res_query("_xmpp-client._tcp.jabber.kiev.ua", C_IN, T_SRV, ...) */
|
||||
static const unsigned char data1[] = {
|
||||
0x95, 0xf3, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
|
||||
0x00, 0x00, 0x00, 0x00, 0x0c, 0x5f, 0x78, 0x6d,
|
||||
0x70, 0x70, 0x2d, 0x63, 0x6c, 0x69, 0x65, 0x6e,
|
||||
0x74, 0x04, 0x5f, 0x74, 0x63, 0x70, 0x06, 0x6a,
|
||||
0x61, 0x62, 0x62, 0x65, 0x72, 0x04, 0x6b, 0x69,
|
||||
0x65, 0x76, 0x02, 0x75, 0x61, 0x00, 0x00, 0x21,
|
||||
0x00, 0x01, 0xc0, 0x0c, 0x00, 0x21, 0x00, 0x01,
|
||||
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, ...) */
|
||||
static const unsigned char data2[] = {
|
||||
0xf2, 0x98, 0x81, 0x80, 0x00, 0x01, 0x00, 0x02,
|
||||
0x00, 0x00, 0x00, 0x00, 0x0c, 0x5f, 0x78, 0x6d,
|
||||
0x70, 0x70, 0x2d, 0x63, 0x6c, 0x69, 0x65, 0x6e,
|
||||
0x74, 0x04, 0x5f, 0x74, 0x63, 0x70, 0x06, 0x6a,
|
||||
0x61, 0x62, 0x62, 0x65, 0x72, 0x03, 0x6f, 0x72,
|
||||
0x67, 0x00, 0x00, 0x21, 0x00, 0x01, 0xc0, 0x0c,
|
||||
0x00, 0x21, 0x00, 0x01, 0x00, 0x00, 0x03, 0x83,
|
||||
0x00, 0x1a, 0x00, 0x1e, 0x00, 0x1e, 0x14, 0x66,
|
||||
0x07, 0x68, 0x65, 0x72, 0x6d, 0x65, 0x73, 0x32,
|
||||
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,
|
||||
};
|
||||
/* res_query("_xmpp-client._tcp.gmail.com", C_IN, T_SRV, ...) */
|
||||
static const unsigned char data3[] = {
|
||||
0xda, 0xa8, 0x81, 0x80, 0x00, 0x01, 0x00, 0x05,
|
||||
0x00, 0x00, 0x00, 0x00, 0x0c, 0x5f, 0x78, 0x6d,
|
||||
0x70, 0x70, 0x2d, 0x63, 0x6c, 0x69, 0x65, 0x6e,
|
||||
0x74, 0x04, 0x5f, 0x74, 0x63, 0x70, 0x05, 0x67,
|
||||
0x6d, 0x61, 0x69, 0x6c, 0x03, 0x63, 0x6f, 0x6d,
|
||||
0x00, 0x00, 0x21, 0x00, 0x01, 0xc0, 0x0c, 0x00,
|
||||
0x21, 0x00, 0x01, 0x00, 0x00, 0x02, 0x43, 0x00,
|
||||
0x1e, 0x00, 0x14, 0x00, 0x00, 0x14, 0x66, 0x04,
|
||||
0x61, 0x6c, 0x74, 0x31, 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, 0x34, 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, 0x32,
|
||||
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, 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, ...) */
|
||||
static const unsigned char data4[] = {
|
||||
0x8d, 0x58, 0x81, 0x80, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, // .X........
|
||||
0x00, 0x00, 0x0c, 0x5f, 0x78, 0x6d, 0x70, 0x70, 0x2d, 0x63, // ..._xmpp-c
|
||||
0x6c, 0x69, 0x65, 0x6e, 0x74, 0x04, 0x5f, 0x74, 0x63, 0x70, // lient._tcp
|
||||
0x06, 0x6a, 0x61, 0x62, 0x62, 0x65, 0x72, 0x0e, 0x63, 0x61, // .jabber.ca
|
||||
0x6c, 0x79, 0x78, 0x69, 0x6e, 0x73, 0x74, 0x69, 0x74, 0x75, // lyxinstitu
|
||||
0x74, 0x65, 0x03, 0x6f, 0x72, 0x67, 0x00, 0x00, 0x21, 0x00, // te.org..!.
|
||||
0x01, 0xc0, 0x0c, 0x00, 0x21, 0x00, 0x01, 0x00, 0x00, 0x03, // ....!.....
|
||||
0x83, 0x00, 0x1e, 0x00, 0x04, 0x00, 0x00, 0x14, 0x66, 0x10, // ........f.
|
||||
0x69, 0x6a, 0x65, 0x65, 0x79, 0x6e, 0x72, 0x63, 0x36, 0x78, // ijeeynrc6x
|
||||
0x32, 0x75, 0x79, 0x35, 0x6f, 0x62, 0x05, 0x6f, 0x6e, 0x69, // 2uy5ob.oni
|
||||
0x6f, 0x6e, 0x00, 0xc0, 0x0c, 0x00, 0x21, 0x00, 0x01, 0x00, // on....!...
|
||||
0x00, 0x03, 0x83, 0x00, 0x21, 0x00, 0x05, 0x00, 0x01, 0x14, // ....!.....
|
||||
0x66, 0x06, 0x6a, 0x61, 0x62, 0x62, 0x65, 0x72, 0x0e, 0x63, // f.jabber.c
|
||||
0x61, 0x6c, 0x79, 0x78, 0x69, 0x6e, 0x73, 0x74, 0x69, 0x74, // alyxinstit
|
||||
0x75, 0x74, 0x65, 0x03, 0x6f, 0x72, 0x67, 0x00, // ute.org.
|
||||
};
|
||||
/* res_query("_xmpp-client._tcp.jabber.org", C_IN, T_SRV, ...) with pointers */
|
||||
static const unsigned char data5[] = {
|
||||
0x00, 0x00, 0x81, 0x80, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, // ..........
|
||||
0x00, 0x00, 0x0c, 0x5f, 0x78, 0x6d, 0x70, 0x70, 0x2d, 0x63, // ..._xmpp-c
|
||||
0x6c, 0x69, 0x65, 0x6e, 0x74, 0x04, 0x5f, 0x74, 0x63, 0x70, // lient._tcp
|
||||
0x06, 0x6a, 0x61, 0x62, 0x62, 0x65, 0x72, 0x03, 0x6f, 0x72, // .jabber.or
|
||||
0x67, 0x00, 0x00, 0x21, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x21, // g..!.....!
|
||||
0x00, 0x01, 0x00, 0x00, 0x01, 0x9e, 0x00, 0x12, 0x00, 0x1f, // ..........
|
||||
0x00, 0x1e, 0x14, 0x66, 0x09, 0x68, 0x65, 0x72, 0x6d, 0x65, // ...f.herme
|
||||
0x73, 0x32, 0x76, 0x36, 0xc0, 0x1e, 0xc0, 0x0c, 0x00, 0x21, // s2v6.....!
|
||||
0x00, 0x01, 0x00, 0x00, 0x01, 0x9e, 0x00, 0x10, 0x00, 0x1e, // ..........
|
||||
0x00, 0x1e, 0x14, 0x66, 0x07, 0x68, 0x65, 0x72, 0x6d, 0x65, // ...f.herme
|
||||
0x73, 0x32, 0xc0, 0x1e, // s2..
|
||||
};
|
||||
/* hacked data2 with two empty-string targets. */
|
||||
static const unsigned char data6[] = {
|
||||
0xf2, 0x98, 0x81, 0x80, 0x00, 0x01, 0x00, 0x02,
|
||||
0x00, 0x00, 0x00, 0x00, 0x0c, 0x5f, 0x78, 0x6d,
|
||||
0x70, 0x70, 0x2d, 0x63, 0x6c, 0x69, 0x65, 0x6e,
|
||||
0x74, 0x04, 0x5f, 0x74, 0x63, 0x70, 0x06, 0x6a,
|
||||
0x61, 0x62, 0x62, 0x65, 0x72, 0x03, 0x6f, 0x72,
|
||||
0x67, 0x00, 0x00, 0x21, 0x00, 0x01, 0xc0, 0x0c,
|
||||
0x00, 0x21, 0x00, 0x01, 0x00, 0x00, 0x03, 0x83,
|
||||
0x00, 0x07, 0x00, 0x1e, 0x00, 0x1e, 0x14, 0x66,
|
||||
0x00, 0xc0, 0x0c, 0x00, 0x21, 0x00, 0x01, 0x00,
|
||||
0x00, 0x03, 0x83, 0x00, 0x08, 0x00, 0x1f, 0x00,
|
||||
0x1e, 0x14, 0x66, 0xc0, 0x40,
|
||||
};
|
||||
|
||||
static const struct {
|
||||
const unsigned char *data;
|
||||
size_t len;
|
||||
char *target;
|
||||
unsigned short port;
|
||||
int target_nr;
|
||||
} tests[] = {
|
||||
{
|
||||
.data = data1,
|
||||
.len = sizeof(data1),
|
||||
.target = "jabber.kiev.ua",
|
||||
.port = 5222,
|
||||
.target_nr = 1,
|
||||
},
|
||||
{
|
||||
.data = data2,
|
||||
.len = sizeof(data2),
|
||||
.target = "hermes2.jabber.org",
|
||||
.port = 5222,
|
||||
.target_nr = 2,
|
||||
},
|
||||
{
|
||||
.data = data3,
|
||||
.len = sizeof(data3),
|
||||
.target = "xmpp.l.google.com",
|
||||
.port = 5222,
|
||||
.target_nr = 5,
|
||||
},
|
||||
{
|
||||
.data = data4,
|
||||
.len = sizeof(data4),
|
||||
.target = "ijeeynrc6x2uy5ob.onion",
|
||||
.port = 5222,
|
||||
.target_nr = 2,
|
||||
},
|
||||
{
|
||||
.data = data5,
|
||||
.len = sizeof(data5),
|
||||
.target = "hermes2.jabber.org",
|
||||
.port = 5222,
|
||||
.target_nr = 2,
|
||||
},
|
||||
{
|
||||
.data = data6,
|
||||
.len = sizeof(data6),
|
||||
.target = "",
|
||||
.port = 5222,
|
||||
.target_nr = 2,
|
||||
},
|
||||
};
|
||||
|
||||
static int srv_rr_list_len(resolver_srv_rr_t *list)
|
||||
{
|
||||
int nr;
|
||||
|
||||
for (nr = 0; list != NULL; ++nr, list = list->next);
|
||||
|
||||
return nr;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
xmpp_ctx_t *ctx;
|
||||
xmpp_rand_t *rand;
|
||||
resolver_srv_rr_t *srv_rr_list;
|
||||
char *domain;
|
||||
unsigned char *buf;
|
||||
unsigned short port;
|
||||
size_t i;
|
||||
int ret;
|
||||
|
||||
ctx = xmpp_ctx_new(NULL, NULL);
|
||||
assert(ctx != NULL);
|
||||
|
||||
printf("resolver_srv_lookup_buf() tests.\n");
|
||||
for (i = 0; i < ARRAY_SIZE(tests); ++i) {
|
||||
printf("Test #%zu: ", i + 1);
|
||||
ret = resolver_srv_lookup_buf(ctx, tests[i].data, tests[i].len,
|
||||
&srv_rr_list);
|
||||
assert(ret == XMPP_DOMAIN_FOUND);
|
||||
assert(srv_rr_list != NULL);
|
||||
if (tests[i].target_nr != srv_rr_list_len(srv_rr_list)) {
|
||||
printf("fail! got %d targets, but should be %d\n",
|
||||
srv_rr_list_len(srv_rr_list), tests[i].target_nr);
|
||||
return 1;
|
||||
}
|
||||
/* check only 1st result */
|
||||
domain = srv_rr_list->target;
|
||||
port = srv_rr_list->port;
|
||||
COMPARE(tests[i].target, domain);
|
||||
if (tests[i].port != port) {
|
||||
printf("fail! got port=%u, but should be %u\n",
|
||||
(unsigned)port, (unsigned)tests[i].port);
|
||||
return 1;
|
||||
}
|
||||
printf("ok\n");
|
||||
resolver_srv_free(ctx, srv_rr_list);
|
||||
}
|
||||
|
||||
/*
|
||||
* The next test case must not crash and is supposed to be checked
|
||||
* under valgrind.
|
||||
*/
|
||||
printf("Test of a broken message: ");
|
||||
rand = xmpp_rand_new(ctx);
|
||||
assert(rand != NULL);
|
||||
assert(sizeof(data2) > 64);
|
||||
buf = xmpp_alloc(ctx, sizeof(data2));
|
||||
assert(buf != NULL);
|
||||
memcpy(buf, data2, 64);
|
||||
xmpp_rand_bytes(rand, &buf[64], sizeof(data2) - 64);
|
||||
ret = resolver_srv_lookup_buf(ctx, buf, sizeof(data2), &srv_rr_list);
|
||||
if (ret == XMPP_DOMAIN_FOUND && srv_rr_list != NULL)
|
||||
resolver_srv_free(ctx, srv_rr_list);
|
||||
xmpp_free(ctx, buf);
|
||||
xmpp_rand_free(ctx, rand);
|
||||
printf("ok\n");
|
||||
|
||||
xmpp_ctx_free(ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
142
tests/test_scram.c
Normal file
142
tests/test_scram.c
Normal file
@@ -0,0 +1,142 @@
|
||||
/* test_scram.c
|
||||
* strophe XMPP client library -- test vectors for SCRAM-SHA1
|
||||
*
|
||||
* Copyright (C) 2014 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_scram -I./src tests/test_scram.c tests/test.c src/sha1.c */
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "test.h"
|
||||
|
||||
/* include scram.c to access static functions */
|
||||
#include "scram.c"
|
||||
|
||||
/*
|
||||
* Test vectors for derivation function (RFC6070).
|
||||
*/
|
||||
static const struct {
|
||||
char *P; /* text */
|
||||
char *S; /* salt */
|
||||
size_t P_len;
|
||||
size_t S_len;
|
||||
uint32_t c; /* i */
|
||||
char *DK; /* resulting digest */
|
||||
} df_vectors[] = {
|
||||
{
|
||||
.P = "password",
|
||||
.S = "salt",
|
||||
.P_len = 8,
|
||||
.S_len = 4,
|
||||
.c = 1,
|
||||
.DK = "0c60c80f961f0e71f3a9b524af6012062fe037a6",
|
||||
},
|
||||
{
|
||||
.P = "password",
|
||||
.S = "salt",
|
||||
.P_len = 8,
|
||||
.S_len = 4,
|
||||
.c = 2,
|
||||
.DK = "ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957",
|
||||
},
|
||||
{
|
||||
.P = "password",
|
||||
.S = "salt",
|
||||
.P_len = 8,
|
||||
.S_len = 4,
|
||||
.c = 4096,
|
||||
.DK = "4b007901b765489abead49d926f721d065a429c1",
|
||||
},
|
||||
};
|
||||
|
||||
static void test_df(void)
|
||||
{
|
||||
size_t i;
|
||||
const char *s;
|
||||
uint8_t dk[SHA1_DIGEST_SIZE];
|
||||
|
||||
printf("Derivation function tests (SCRAM_SHA1_Hi).\n");
|
||||
for (i = 0; i < ARRAY_SIZE(df_vectors); ++i) {
|
||||
printf("Test #%d: ", (int)i + 1);
|
||||
SCRAM_SHA1_Hi((uint8_t *)df_vectors[i].P, df_vectors[i].P_len,
|
||||
(uint8_t *)df_vectors[i].S, df_vectors[i].S_len,
|
||||
df_vectors[i].c, dk);
|
||||
s = test_bin_to_hex(dk, sizeof(dk));
|
||||
COMPARE(df_vectors[i].DK, s);
|
||||
printf("ok\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* RFC6120 */
|
||||
static const struct {
|
||||
char *password;
|
||||
char *initial;
|
||||
char *challenge;
|
||||
char *response;
|
||||
char *salt;
|
||||
uint32_t i;
|
||||
char *sign;
|
||||
} scram_vectors[] = {
|
||||
{
|
||||
.password = "r0m30myr0m30",
|
||||
.initial = "n,,n=juliet,r=oMsTAAwAAAAMAAAANP0TAAAAAABPU0AA",
|
||||
.challenge = "r=oMsTAAwAAAAMAAAANP0TAAAAAABPU0AAe124695b-69a9-4de6-9c30"
|
||||
"-b51b3808c59e,s=NjhkYTM0MDgtNGY0Zi00NjdmLTkxMmUtNDlmNTNmN"
|
||||
"DNkMDMz,i=4096",
|
||||
.response = "c=biws,r=oMsTAAwAAAAMAAAANP0TAAAAAABPU0AAe124695b-69a9-4de"
|
||||
"6-9c30-b51b3808c59e",
|
||||
.salt = "36386461333430382d346634662d34363766"
|
||||
"2d393132652d343966353366343364303333",
|
||||
.i = 4096,
|
||||
.sign = "500e7bb4cfd2be90130641f6157b345835ef258c",
|
||||
},
|
||||
};
|
||||
|
||||
static void test_scram(void)
|
||||
{
|
||||
uint8_t key[SHA1_DIGEST_SIZE];
|
||||
uint8_t sign[SHA1_DIGEST_SIZE];
|
||||
uint8_t salt[256];
|
||||
size_t salt_len;
|
||||
char auth[512];
|
||||
const char *s;
|
||||
size_t i;
|
||||
int j;
|
||||
|
||||
printf("SCRAM_SHA1_ClientKey and SCRAM_SHA1_ClientSignature tests.\n");
|
||||
for (i = 0; i < ARRAY_SIZE(scram_vectors); ++i) {
|
||||
printf("Test #%d: ", (int)i + 1);
|
||||
snprintf(auth, sizeof(auth), "%s,%s,%s",
|
||||
scram_vectors[i].initial + 3, scram_vectors[i].challenge,
|
||||
scram_vectors[i].response);
|
||||
test_hex_to_bin(scram_vectors[i].salt, salt, &salt_len);
|
||||
|
||||
SCRAM_SHA1_ClientKey((uint8_t *)scram_vectors[i].password,
|
||||
strlen(scram_vectors[i].password),
|
||||
salt, salt_len, scram_vectors[i].i, key);
|
||||
SCRAM_SHA1_ClientSignature(key, (uint8_t *)auth, strlen(auth), sign);
|
||||
for (j = 0; j < SHA1_DIGEST_SIZE; j++) {
|
||||
sign[j] ^= key[j];
|
||||
}
|
||||
s = test_bin_to_hex(sign, SHA1_DIGEST_SIZE);
|
||||
COMPARE(scram_vectors[i].sign, s);
|
||||
printf("ok\n");
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
test_df();
|
||||
test_scram();
|
||||
|
||||
return 0;
|
||||
}
|
||||
95
tests/test_sha1.c
Normal file
95
tests/test_sha1.c
Normal file
@@ -0,0 +1,95 @@
|
||||
/* Tests for Steve Reid's public domain SHA-1 implementation */
|
||||
/* This file is in the public domain */
|
||||
|
||||
/* gcc -o test_sha1 -I./src tests/test_sha1.c src/sha1.c */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "sha1.h"
|
||||
#include "test.h"
|
||||
|
||||
/* Test Vectors (from FIPS PUB 180-1) */
|
||||
static char *test_data[] = {
|
||||
"abc",
|
||||
"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
|
||||
"A million repetitions of 'a'",
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"};
|
||||
static char *test_results[] = {
|
||||
"A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D",
|
||||
"84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1",
|
||||
"34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F",
|
||||
"AD5B3FDB CB526778 C2839D2F 151EA753 995E26A0"};
|
||||
|
||||
static void digest_to_hex(const uint8_t *digest, char *output)
|
||||
{
|
||||
int i,j;
|
||||
char *c = output;
|
||||
|
||||
for (i = 0; i < SHA1_DIGEST_SIZE/4; i++) {
|
||||
for (j = 0; j < 4; j++) {
|
||||
sprintf(c,"%02X", digest[i*4+j]);
|
||||
c += 2;
|
||||
}
|
||||
sprintf(c, " ");
|
||||
c += 1;
|
||||
}
|
||||
*(c - 1) = '\0';
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
int k;
|
||||
SHA1_CTX context;
|
||||
uint8_t digest[20];
|
||||
char output[80];
|
||||
char *copy;
|
||||
|
||||
fprintf(stdout, "verifying SHA-1 implementation... ");
|
||||
|
||||
for (k = 0; k < ARRAY_SIZE(test_data); k++){
|
||||
if (k == 2) {
|
||||
/* this case will be checked below */
|
||||
continue;
|
||||
}
|
||||
copy = strdup(test_data[k]);
|
||||
crypto_SHA1_Init(&context);
|
||||
crypto_SHA1_Update(&context, (uint8_t*)test_data[k],
|
||||
strlen(test_data[k]));
|
||||
crypto_SHA1_Final(&context, digest);
|
||||
digest_to_hex(digest, output);
|
||||
|
||||
if (strcmp(output, test_results[k])) {
|
||||
fprintf(stdout, "FAIL\n");
|
||||
fprintf(stderr,"* hash of \"%s\" incorrect:\n", test_data[k]);
|
||||
fprintf(stderr,"\t%s returned\n", output);
|
||||
fprintf(stderr,"\t%s is correct\n", test_results[k]);
|
||||
return (1);
|
||||
}
|
||||
if (strcmp(copy, test_data[k])) {
|
||||
fprintf(stdout, "FAIL\n");
|
||||
fprintf(stdout, "* original string was changed by SHA1\n");
|
||||
return (1);
|
||||
}
|
||||
free(copy);
|
||||
}
|
||||
/* million 'a' vector we feed separately */
|
||||
crypto_SHA1_Init(&context);
|
||||
for (k = 0; k < 1000000; k++)
|
||||
crypto_SHA1_Update(&context, (uint8_t*)"a", 1);
|
||||
crypto_SHA1_Final(&context, digest);
|
||||
digest_to_hex(digest, output);
|
||||
if (strcmp(output, test_results[2])) {
|
||||
fprintf(stdout, "FAIL\n");
|
||||
fprintf(stderr,"* hash of \"%s\" incorrect:\n", test_data[2]);
|
||||
fprintf(stderr,"\t%s returned\n", output);
|
||||
fprintf(stderr,"\t%s is correct\n", test_results[2]);
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* success */
|
||||
fprintf(stdout, "ok\n");
|
||||
return(0);
|
||||
}
|
||||
91
tests/test_snprintf.c
Normal file
91
tests/test_snprintf.c
Normal file
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright Patrick Powell 1995
|
||||
* This code is based on code written by Patrick Powell (papowell@astart.com)
|
||||
* It may be used for any purpose as long as this notice remains intact
|
||||
* on all source code distributions
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#undef HAVE_VSNPRINTF
|
||||
#undef HAVE_SNPRINTF
|
||||
#include "snprintf.c"
|
||||
|
||||
#ifndef LONG_STRING
|
||||
#define LONG_STRING 1024
|
||||
#endif
|
||||
|
||||
int main (void)
|
||||
{
|
||||
char buf1[LONG_STRING];
|
||||
char buf2[LONG_STRING];
|
||||
char *fp_fmt[] = {
|
||||
"%-1.5f",
|
||||
"%1.5f",
|
||||
"%123.9f",
|
||||
"%10.5f",
|
||||
"% 10.5f",
|
||||
"%+22.9f",
|
||||
"%+4.9f",
|
||||
"%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};
|
||||
int x, y;
|
||||
int fail = 0;
|
||||
int num = 0;
|
||||
|
||||
printf ("Testing xmpp_snprintf format codes against system sprintf...\n");
|
||||
|
||||
for (x = 0; fp_fmt[x] != NULL ; x++)
|
||||
for (y = 0; fp_nums[y] != 0 ; y++)
|
||||
{
|
||||
xmpp_snprintf (buf1, sizeof (buf1), fp_fmt[x], fp_nums[y]);
|
||||
sprintf (buf2, fp_fmt[x], fp_nums[y]);
|
||||
if (strcmp (buf1, buf2))
|
||||
{
|
||||
printf("xmpp_snprintf doesn't match Format: %s\n\txmpp_snprintf = %s\n\tsprintf = %s\n",
|
||||
fp_fmt[x], buf1, buf2);
|
||||
fail++;
|
||||
}
|
||||
num++;
|
||||
}
|
||||
|
||||
for (x = 0; int_fmt[x] != NULL ; x++)
|
||||
for (y = 0; int_nums[y] != 0 ; y++)
|
||||
{
|
||||
xmpp_snprintf (buf1, sizeof (buf1), int_fmt[x], int_nums[y]);
|
||||
sprintf (buf2, int_fmt[x], int_nums[y]);
|
||||
if (strcmp (buf1, buf2))
|
||||
{
|
||||
printf("xmpp_snprintf doesn't match Format: %s\n\txmpp_snprintf = %s\n\tsprintf = %s\n",
|
||||
int_fmt[x], buf1, buf2);
|
||||
fail++;
|
||||
}
|
||||
num++;
|
||||
}
|
||||
printf ("%d tests failed out of %d.\n", fail, num);
|
||||
return fail != 0 ? 1 : 0;
|
||||
}
|
||||
116
tests/test_string.c
Normal file
116
tests/test_string.c
Normal file
@@ -0,0 +1,116 @@
|
||||
/* test_string.c
|
||||
* strophe XMPP client library -- tests for re-implemented string functions
|
||||
*
|
||||
* 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "strophe.h"
|
||||
#include "common.h"
|
||||
#include "util.h"
|
||||
|
||||
#include "test.h" /* ARRAY_SIZE */
|
||||
|
||||
static int test_strtok_r(void)
|
||||
{
|
||||
const char *test = "-abc-=-def--";
|
||||
char *s1, *s2, *sub1, *sub2;
|
||||
char *sp1, *sp2;
|
||||
|
||||
s1 = strdup(test);
|
||||
s2 = strdup(test);
|
||||
assert(strcmp(s1, s2) == 0);
|
||||
|
||||
sub1 = strtok_r(s1, "-", &sp1);
|
||||
sub2 = xmpp_strtok_r(s2, "-", &sp2);
|
||||
if (strcmp(sub1, sub2) != 0) {
|
||||
printf("1st token is '%s', must be '%s'\n", sub2, sub1);
|
||||
return -1;
|
||||
}
|
||||
sub1 = strtok_r(NULL, "-=", &sp1);
|
||||
sub2 = xmpp_strtok_r(NULL, "-=", &sp2);
|
||||
if (strcmp(sub1, sub2) != 0) {
|
||||
printf("2nd token is '%s', must be '%s'\n", sub2, sub1);
|
||||
return -1;
|
||||
}
|
||||
sub1 = strtok_r(NULL, "-", &sp1);
|
||||
sub2 = xmpp_strtok_r(NULL, "-", &sp2);
|
||||
if (sub1 != sub2) {
|
||||
printf("3rd call returns %p instead of NULL\n", sub2);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free(s1);
|
||||
free(s2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_strdup_one(xmpp_ctx_t *ctx, const char *s)
|
||||
{
|
||||
char *s1, *s2;
|
||||
int rc = 0;
|
||||
|
||||
s1 = strdup(s);
|
||||
s2 = xmpp_strdup(ctx, s);
|
||||
|
||||
if (!s1 || !s2 || strcmp(s1, s2) != 0) {
|
||||
rc = -1;
|
||||
printf("strdup: '%s', xmpp_strdup: '%s'\n",
|
||||
s1 ? s1 : "<NULL>", s2 ? s2 : "<NULL>");
|
||||
}
|
||||
|
||||
free(s1);
|
||||
if (s2)
|
||||
xmpp_free(ctx, s2);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int test_strdup(void)
|
||||
{
|
||||
xmpp_ctx_t *ctx;
|
||||
size_t i;
|
||||
int rc = 0;
|
||||
|
||||
static const char *tests[] = { "", "\0", "test", "s p a c e", "\n\r" };
|
||||
|
||||
ctx = xmpp_ctx_new(NULL, NULL);
|
||||
assert(ctx != NULL);
|
||||
for (i = 0; i < ARRAY_SIZE(tests); ++i) {
|
||||
rc = test_strdup_one(ctx, tests[i]);
|
||||
if (rc != 0)
|
||||
break;
|
||||
}
|
||||
xmpp_ctx_free(ctx);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int rc;
|
||||
|
||||
printf("xmpp_strtok_r() tests... ");
|
||||
rc = test_strtok_r();
|
||||
if (rc != 0)
|
||||
return 1;
|
||||
printf("ok\n");
|
||||
|
||||
printf("xmpp_strdup() tests... ");
|
||||
rc = test_strdup();
|
||||
if (rc != 0)
|
||||
return 1;
|
||||
printf("ok\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,195 +0,0 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="9.00"
|
||||
Name="active example"
|
||||
ProjectGUID="{FB499990-F569-426A-9215-5B013D94B70C}"
|
||||
RootNamespace="active"
|
||||
Keyword="Win32Proj"
|
||||
TargetFrameworkVersion="196613"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="../"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="Ws2_32.lib winmm.lib"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="2"
|
||||
EnableIntrinsicFunctions="true"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
|
||||
RuntimeLibrary="2"
|
||||
EnableFunctionLevelLinking="true"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\examples\active.c"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||
>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Resource Files"
|
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
|
||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
|
||||
>
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
@@ -1,195 +0,0 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="9.00"
|
||||
Name="basic example"
|
||||
ProjectGUID="{7BD355D0-941D-4630-B82F-1FB43A971440}"
|
||||
RootNamespace="basic"
|
||||
Keyword="Win32Proj"
|
||||
TargetFrameworkVersion="196613"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="../"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="Ws2_32.lib winmm.lib"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="2"
|
||||
EnableIntrinsicFunctions="true"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
|
||||
RuntimeLibrary="2"
|
||||
EnableFunctionLevelLinking="true"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\examples\basic.c"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||
>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Resource Files"
|
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
|
||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
|
||||
>
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
@@ -1,195 +0,0 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="9.00"
|
||||
Name="bot example"
|
||||
ProjectGUID="{DEE25458-271F-4F9A-8979-C460C64B49C8}"
|
||||
RootNamespace="bot"
|
||||
Keyword="Win32Proj"
|
||||
TargetFrameworkVersion="196613"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="../"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="Ws2_32.lib winmm.lib"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="2"
|
||||
EnableIntrinsicFunctions="true"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
|
||||
RuntimeLibrary="2"
|
||||
EnableFunctionLevelLinking="true"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\examples\bot.c"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||
>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Resource Files"
|
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
|
||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
|
||||
>
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
@@ -1,288 +0,0 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="9.00"
|
||||
Name="expat"
|
||||
ProjectGUID="{AAFBC1E9-6192-46AE-95BC-642DCB20D361}"
|
||||
RootNamespace="expat"
|
||||
TargetFrameworkVersion="0"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory=".\Debug"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="4"
|
||||
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"
|
||||
UseOfMFC="0"
|
||||
ATLMinimizesCRunTimeLibraryUsage="false"
|
||||
CharacterSet="2"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;COMPILED_FROM_DSP;_LIB"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
PrecompiledHeaderFile=".\Debug/expat_static.pch"
|
||||
BrowseInformation="1"
|
||||
WarningLevel="3"
|
||||
SuppressStartupBanner="true"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
PreprocessorDefinitions="_DEBUG"
|
||||
Culture="1033"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
OutputFile="Debug\libexpatMTD.lib"
|
||||
SuppressStartupBanner="true"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
SuppressStartupBanner="true"
|
||||
OutputFile=".\Debug/expat_static.bsc"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory=".\Release_static"
|
||||
IntermediateDirectory=".\Release_static"
|
||||
ConfigurationType="4"
|
||||
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"
|
||||
UseOfMFC="0"
|
||||
ATLMinimizesCRunTimeLibraryUsage="false"
|
||||
CharacterSet="2"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="2"
|
||||
InlineFunctionExpansion="1"
|
||||
PreprocessorDefinitions="WIN32;_WINDOWS;NDEBUG;_LIB;COMPILED_FROM_DSP"
|
||||
StringPooling="true"
|
||||
RuntimeLibrary="0"
|
||||
EnableFunctionLevelLinking="true"
|
||||
PrecompiledHeaderFile=".\Release_static/expat_static.pch"
|
||||
AssemblerListingLocation=".\Release_static/"
|
||||
ObjectFile=".\Release_static/"
|
||||
ProgramDataBaseFileName=".\Release_static/"
|
||||
WarningLevel="3"
|
||||
SuppressStartupBanner="true"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
PreprocessorDefinitions="NDEBUG"
|
||||
Culture="1033"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
OutputFile="Release_static\libexpatMT.lib"
|
||||
SuppressStartupBanner="true"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
SuppressStartupBanner="true"
|
||||
OutputFile=".\Release_static/expat_static.bsc"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\expat\lib\xmlparse.c"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
PreprocessorDefinitions=""
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
PreprocessorDefinitions=""
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\expat\lib\xmlrole.c"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
PreprocessorDefinitions=""
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
PreprocessorDefinitions=""
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\expat\lib\xmltok.c"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
PreprocessorDefinitions=""
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
PreprocessorDefinitions=""
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\expat\lib\ascii.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\expat\lib\asciitab.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\expat\lib\expat.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\expat\lib\expat_external.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\expat\lib\iasciitab.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\expat\lib\internal.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\expat\lib\latin1tab.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\expat\lib\nametab.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\expat\lib\utf8tab.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\expat\lib\xmlrole.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\expat\lib\xmltok.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\expat\lib\xmltok_impl.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
@@ -1,66 +0,0 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 10.00
|
||||
# Visual C++ Express 2008
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libstrophe", "libstrophe.vcproj", "{659E3B17-B1BF-4D3B-94E6-438F85EBC410}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "active example", "active.vcproj", "{FB499990-F569-426A-9215-5B013D94B70C}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{659E3B17-B1BF-4D3B-94E6-438F85EBC410} = {659E3B17-B1BF-4D3B-94E6-438F85EBC410}
|
||||
{AAFBC1E9-6192-46AE-95BC-642DCB20D361} = {AAFBC1E9-6192-46AE-95BC-642DCB20D361}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "basic example", "basic.vcproj", "{7BD355D0-941D-4630-B82F-1FB43A971440}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{659E3B17-B1BF-4D3B-94E6-438F85EBC410} = {659E3B17-B1BF-4D3B-94E6-438F85EBC410}
|
||||
{AAFBC1E9-6192-46AE-95BC-642DCB20D361} = {AAFBC1E9-6192-46AE-95BC-642DCB20D361}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bot example", "bot.vcproj", "{DEE25458-271F-4F9A-8979-C460C64B49C8}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{659E3B17-B1BF-4D3B-94E6-438F85EBC410} = {659E3B17-B1BF-4D3B-94E6-438F85EBC410}
|
||||
{AAFBC1E9-6192-46AE-95BC-642DCB20D361} = {AAFBC1E9-6192-46AE-95BC-642DCB20D361}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "roster example", "roster.vcproj", "{5F6591E0-3FAD-45AE-80CF-A47C1F8BA2CC}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{659E3B17-B1BF-4D3B-94E6-438F85EBC410} = {659E3B17-B1BF-4D3B-94E6-438F85EBC410}
|
||||
{AAFBC1E9-6192-46AE-95BC-642DCB20D361} = {AAFBC1E9-6192-46AE-95BC-642DCB20D361}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "expat", "expat.vcproj", "{AAFBC1E9-6192-46AE-95BC-642DCB20D361}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
Release|Win32 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{659E3B17-B1BF-4D3B-94E6-438F85EBC410}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{659E3B17-B1BF-4D3B-94E6-438F85EBC410}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{659E3B17-B1BF-4D3B-94E6-438F85EBC410}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{659E3B17-B1BF-4D3B-94E6-438F85EBC410}.Release|Win32.Build.0 = Release|Win32
|
||||
{FB499990-F569-426A-9215-5B013D94B70C}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{FB499990-F569-426A-9215-5B013D94B70C}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{FB499990-F569-426A-9215-5B013D94B70C}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{FB499990-F569-426A-9215-5B013D94B70C}.Release|Win32.Build.0 = Release|Win32
|
||||
{7BD355D0-941D-4630-B82F-1FB43A971440}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{7BD355D0-941D-4630-B82F-1FB43A971440}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{7BD355D0-941D-4630-B82F-1FB43A971440}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{7BD355D0-941D-4630-B82F-1FB43A971440}.Release|Win32.Build.0 = Release|Win32
|
||||
{DEE25458-271F-4F9A-8979-C460C64B49C8}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{DEE25458-271F-4F9A-8979-C460C64B49C8}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{DEE25458-271F-4F9A-8979-C460C64B49C8}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{DEE25458-271F-4F9A-8979-C460C64B49C8}.Release|Win32.Build.0 = Release|Win32
|
||||
{5F6591E0-3FAD-45AE-80CF-A47C1F8BA2CC}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{5F6591E0-3FAD-45AE-80CF-A47C1F8BA2CC}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{5F6591E0-3FAD-45AE-80CF-A47C1F8BA2CC}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{5F6591E0-3FAD-45AE-80CF-A47C1F8BA2CC}.Release|Win32.Build.0 = Release|Win32
|
||||
{AAFBC1E9-6192-46AE-95BC-642DCB20D361}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{AAFBC1E9-6192-46AE-95BC-642DCB20D361}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{AAFBC1E9-6192-46AE-95BC-642DCB20D361}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{AAFBC1E9-6192-46AE-95BC-642DCB20D361}.Release|Win32.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -1,276 +0,0 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="9.00"
|
||||
Name="libstrophe"
|
||||
ProjectGUID="{659E3B17-B1BF-4D3B-94E6-438F85EBC410}"
|
||||
RootNamespace="libstrophe"
|
||||
Keyword="Win32Proj"
|
||||
TargetFrameworkVersion="196613"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="4"
|
||||
CharacterSet="2"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="../;../expat/lib"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_LIB;XML_STATIC"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="4"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="2"
|
||||
EnableIntrinsicFunctions="true"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_LIB"
|
||||
RuntimeLibrary="2"
|
||||
EnableFunctionLevelLinking="true"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\src\auth.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\conn.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\ctx.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\event.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\handler.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\hash.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\jid.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\md5.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\sasl.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\sha1.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\snprintf.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\sock.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\stanza.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\thread.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\tls_schannel.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\util.c"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\src\common.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\hash.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\md5.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\ostypes.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\sasl.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\sha1.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\sock.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\thread.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\tls.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\util.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Resource Files"
|
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
|
||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
|
||||
>
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
@@ -1,195 +0,0 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="9.00"
|
||||
Name="roster example"
|
||||
ProjectGUID="{5F6591E0-3FAD-45AE-80CF-A47C1F8BA2CC}"
|
||||
RootNamespace="rosterexample"
|
||||
Keyword="Win32Proj"
|
||||
TargetFrameworkVersion="196613"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="../"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="Ws2_32.lib winmm.lib"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="2"
|
||||
EnableIntrinsicFunctions="true"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
|
||||
RuntimeLibrary="2"
|
||||
EnableFunctionLevelLinking="true"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\examples\roster.c"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||
>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Resource Files"
|
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
|
||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
|
||||
>
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
Reference in New Issue
Block a user