8 Commits

Author SHA1 Message Date
James Booth
160a124619 OpenSSL: Debug certificate chain 2015-09-14 00:57:44 +01:00
James Booth
450bbca8e7 OpenSSL: Added debug logging to certificate verification 2015-09-13 22:44:12 +01:00
James Booth
20380157ba OpenSSL: debug name string on cert verify fail 2015-09-11 01:18:48 +01:00
James Booth
3e12f33cce OpenSSL: Use simpler cert callback 2015-09-11 00:46:49 +01:00
James Booth
f05529b09a Added open SSL dummy certificate check callback 2015-09-10 23:14:08 +01:00
James Booth
cc486b2ebf Continue open SSL connect loop on recoverable errors 2015-09-10 23:06:05 +01:00
James Booth
165d2487bb Change openssl connect err check for < 0 instead of == -1 2015-09-10 22:54:14 +01:00
James Booth
32591e3e77 Reformat tls_openssl.c 2015-09-10 22:51:15 +01:00
89 changed files with 5853 additions and 8669 deletions

18
.gitignore vendored
View File

@@ -1,7 +1,8 @@
*.swp
Makefile Makefile
test-driver test-driver
.libs .libs
src/*.lo
*.la
Makefile.in Makefile.in
configure configure
libtool libtool
@@ -20,10 +21,8 @@ autom4te.cache
.deps .deps
.sconsign* .sconsign*
src/*.o src/*.o
src/*.lo
examples/*.o examples/*.o
*.a *.a
*.la
*.pc *.pc
*.tar.gz *.tar.gz
*.zip *.zip
@@ -35,9 +34,6 @@ examples/basic
examples/bot examples/bot
examples/component examples/component
examples/roster examples/roster
examples/server
examples/uuid
examples/vcard
test_stamp test_stamp
test-suite.log test-suite.log
tests/*.o tests/*.o
@@ -48,17 +44,7 @@ tests/test_base64
tests/test_ctx tests/test_ctx
tests/test_hash tests/test_hash
tests/test_jid tests/test_jid
tests/test_md5
tests/test_rand
tests/test_resolver
tests/test_sasl tests/test_sasl
tests/test_scram
tests/test_sha1
tests/test_snprintf
tests/test_string
tests/test_sock tests/test_sock
m4/ m4/
libstrophe.project libstrophe.project
libs/
obj/
expat/

View File

@@ -1,15 +0,0 @@
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

View File

@@ -1,62 +1,3 @@
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 0.8.8
- XML namespace support - XML namespace support
- XEP-0114 support - XEP-0114 support

2333
Doxyfile

File diff suppressed because it is too large Load Diff

View File

@@ -9,62 +9,25 @@ PARSER_LIBS=@PARSER_LIBS@
SSL_CFLAGS = @openssl_CFLAGS@ SSL_CFLAGS = @openssl_CFLAGS@
SSL_LIBS = @openssl_LIBS@ SSL_LIBS = @openssl_LIBS@
RESOLV_LIBS = @RESOLV_LIBS@ STROPHE_FLAGS = -I$(top_srcdir)
STROPHE_FLAGS = -I$(top_srcdir) -Wall -Wextra -Werror -Wno-unused-parameter
STROPHE_LIBS = libstrophe.la STROPHE_LIBS = libstrophe.la
## Main build targets ## Main build targets
lib_LTLIBRARIES = libstrophe.la lib_LTLIBRARIES = libstrophe.la
libstrophe_la_CFLAGS = $(SSL_CFLAGS) $(STROPHE_FLAGS) $(PARSER_CFLAGS) libstrophe_la_CFLAGS = $(SSL_CFLAGS) $(STROPHE_FLAGS) $(PARSER_CFLAGS)
libstrophe_la_LDFLAGS = $(SSL_LIBS) $(PARSER_LIBS) $(RESOLV_LIBS) -no-undefined libstrophe_la_LDFLAGS = $(SSL_LIBS) $(PARSER_LIBS)
# Export only public API # Export only public API
libstrophe_la_LDFLAGS += -export-symbols-regex '^xmpp_' libstrophe_la_LDFLAGS += -export-symbols-regex '^xmpp_'
libstrophe_la_SOURCES = src/auth.c src/conn.c src/ctx.c \
libstrophe_la_SOURCES = \ src/event.c src/handler.c src/hash.c \
src/auth.c \ src/jid.c src/md5.c src/sasl.c src/scram.c src/sha1.c \
src/conn.c \ src/snprintf.c src/sock.c src/stanza.c src/thread.c \
src/crypto.c \ src/tls_openssl.c src/util.c \
src/ctx.c \ src/common.h src/hash.h src/md5.h src/ostypes.h src/parser.h \
src/event.c \ src/sasl.h src/scram.h src/sha1.h src/sock.h src/thread.h src/tls.h \
src/handler.c \
src/hash.c \
src/jid.c \
src/md5.c \
src/rand.c \
src/resolver.c \
src/sasl.c \
src/scram.c \
src/server.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 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 if PARSER_EXPAT
libstrophe_la_SOURCES += src/parser_expat.c libstrophe_la_SOURCES += src/parser_expat.c
else else
@@ -76,37 +39,16 @@ noinst_HEADERS = strophepp.h
pkgconfig_DATA = libstrophe.pc pkgconfig_DATA = libstrophe.pc
EXTRA_DIST = \ EXTRA_DIST = docs
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 ## Examples
noinst_PROGRAMS = \ noinst_PROGRAMS = examples/active examples/roster examples/basic examples/bot examples/component
examples/active \
examples/basic \
examples/bot \
examples/component \
examples/roster \
examples/server \
examples/uuid \
examples/vcard
examples_active_SOURCES = examples/active.c examples_active_SOURCES = examples/active.c
examples_active_CFLAGS = $(STROPHE_FLAGS) examples_active_CFLAGS = $(STROPHE_FLAGS)
examples_active_LDADD = $(STROPHE_LIBS) examples_active_LDADD = $(STROPHE_LIBS)
examples_roster_SOURCES = examples/roster.c
examples_roster_CFLAGS = $(STROPHE_FLAGS)
examples_roster_LDADD = $(STROPHE_LIBS)
examples_basic_SOURCES = examples/basic.c examples_basic_SOURCES = examples/basic.c
examples_basic_CFLAGS = $(STROPHE_FLAGS) examples_basic_CFLAGS = $(STROPHE_FLAGS)
examples_basic_LDADD = $(STROPHE_LIBS) examples_basic_LDADD = $(STROPHE_LIBS)
@@ -116,84 +58,13 @@ examples_bot_LDADD = $(STROPHE_LIBS)
examples_component_SOURCES = examples/component.c examples_component_SOURCES = examples/component.c
examples_component_CFLAGS = $(STROPHE_FLAGS) examples_component_CFLAGS = $(STROPHE_FLAGS)
examples_component_LDADD = $(STROPHE_LIBS) examples_component_LDADD = $(STROPHE_LIBS)
examples_roster_SOURCES = examples/roster.c
examples_roster_CFLAGS = $(STROPHE_FLAGS)
examples_roster_LDADD = $(STROPHE_LIBS)
examples_server_SOURCES = examples/server.c
examples_server_CFLAGS = $(STROPHE_FLAGS)
examples_server_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 = \ TESTS = tests/check_parser
tests/check_parser \ check_PROGRAMS = 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_SOURCES = tests/check_parser.c tests/test.h
tests_check_parser_CFLAGS = $(PARSER_CFLAGS) $(STROPHE_FLAGS) \ tests_check_parser_CFLAGS = @check_CFLAGS@ $(PARSER_CFLAGS) $(STROPHE_FLAGS) \
-I$(top_srcdir)/src -I$(top_srcdir)/src
tests_check_parser_LDADD = $(STROPHE_LIBS) tests_check_parser_LDADD = @check_LIBS@ $(STROPHE_LIBS)
tests_check_parser_LDFLAGS = -static 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

View File

@@ -1,9 +1,8 @@
libstrophe [![Build Status](https://travis-ci.org/strophe/libstrophe.png?branch=master)](https://travis-ci.org/strophe/libstrophe) # libstrophe
==========
libstrophe is a lightweight XMPP client library written in C. It has libstrophe is a lightweight XMPP client library written in C. It has
minimal dependencies and is configurable for various environments. It minimal dependencies and is configurable for various environments. It
runs well on Linux, Unix and Windows based platforms. runs well on both Linux, Unix, and Windows based platforms.
Its goals are: Its goals are:
@@ -11,8 +10,7 @@ Its goals are:
- well documented - well documented
- reliable - reliable
Build Instructions ## Build Instructions
------------------
If you are building from a source control checkout, run: If you are building from a source control checkout, run:
@@ -25,7 +23,9 @@ From the top-level directory, run the following commands:
./configure ./configure
make make
The public API is defined in `strophe.h` which is in the 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
top-level directory. top-level directory.
The `examples` directory contains some examples of how to The `examples` directory contains some examples of how to
@@ -41,31 +41,26 @@ another path use the `--prefix` option during configure, e.g.:
./configure --prefix=/usr ./configure --prefix=/usr
### Android ## Requirements
Run script `build-android.sh` and follow the instructions. You will
need expat sources and android-ndk.
Requirements
------------
libstrophe requires: libstrophe requires:
- expat or libxml2 - expat is the default; use --with-libxml2 to - expat or libxml2 - expat is the default; use --with-libxml2 to
switch switch
- openssl on UNIX systems - libresolv on UNIX systems - make sure you include -lresolv
if you are compiling by hand.
- libtool
To build libstrophe using autotools you will need autoconf, automake, In addition, if you wish to run the unit tests, you will need the
libtool and pkg-config. check package.
Installation ### OS X (with Homebrew package manager)
------------
libstrophe package has been added to popular Linux distributions, You can install libstrophe with:
BSD systems and OSX package managers.
Documentation brew install libstrophe
-------------
## Documentation
API documentation is inline with the code and conforms to Doxygen API documentation is inline with the code and conforms to Doxygen
standards. You can generate an HTML version of the API documentation standards. You can generate an HTML version of the API documentation

View File

@@ -1,39 +0,0 @@
#!/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

View File

@@ -1,4 +1,4 @@
AC_INIT([libstrophe], [0.9.1], [jack@metajack.im]) AC_INIT([libstrophe], [0.8.8], [jack@metajack.im])
AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_MACRO_DIR([m4])
AM_INIT_AUTOMAKE([foreign]) AM_INIT_AUTOMAKE([foreign])
LT_INIT([dlopen]) LT_INIT([dlopen])
@@ -9,106 +9,84 @@ PKG_PROG_PKG_CONFIG
AC_CANONICAL_HOST AC_CANONICAL_HOST
AS_CASE([$host_os], AS_CASE([$host_os],
[freebsd*], [PLATFORM="bsd"], [freebsd*], [PLATFORM="freebsd"],
[openbsd*], [PLATFORM="bsd"],
[netbsd*], [PLATFORM="bsd"],
[*nto*|*qnx*], [PLATFORM="qnx"],
[*solaris*], [PLATFORM="solaris"],
[*android*], [PLATFORM="android"],
[PLATFORM="nix"]) [PLATFORM="nix"])
AC_ARG_WITH([libxml2], PKG_CHECK_MODULES([openssl], [openssl], [PC_REQUIRES+=(openssl)],
[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$enable_tls" != xno; then
PKG_CHECK_MODULES([openssl], [openssl],
[PC_REQUIRES="openssl ${PC_REQUIRES}"],
[AC_CHECK_HEADER([openssl/ssl.h], [AC_CHECK_HEADER([openssl/ssl.h],
[ [
openssl_LIBS="-lssl -lcrypto" openssl_LIBS="-lssl -lcrypto"
PC_LIBS="${openssl_LIBS} ${PC_LIBS}" PC_LIBS+=($openssl_LIBS)
], ],
[AC_MSG_ERROR([openssl not found; openssl required])] [AC_MSG_ERROR([openssl not found; openssl required])]
)]) )])
fi
with_parser="" PKG_CHECK_MODULES([check], [check >= 0.9.4], [], [AC_MSG_WARN([libcheck not found; unit tests will not be compilable])])
if test "x$with_libxml2" != xyes; then
PKG_CHECK_MODULES([expat], [expat >= 2.0.0], AC_ARG_WITH([libxml2],
[ [AS_HELP_STRING([--with-libxml2], [use libxml2 for XML parsing])],
with_parser="expat" [with_libxml2=check],
PC_REQUIRES="expat ${PC_REQUIRES}" [with_libxml2=no])
],
[AC_CHECK_HEADER([expat.h], if test "x$with_libxml2" != xno; then
[
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], PKG_CHECK_MODULES([libxml2], [libxml-2.0 >= 2.7],
[ [
with_parser="libxml2" with_libxml2=yes
PC_REQUIRES="libxml-2.0 ${PC_REQUIRES}" PC_REQUIRES+=(libxml-2.0)
], ],
[ [
old_CFLAGS=$CFLAGS old_CFLAGS=$CFLAGS
CFLAGS="-I${includedir}/libxml2" CFLAGS="-I${includedir}/libxml2"
AC_CHECK_HEADER([libxml/parser.h], AC_CHECK_HEADER([libxml/parser.h],
[ [
with_parser="libxml2" with_libxml2=yes
libxml2_CFLAGS="-I${includedir}/libxml2" libxml2_CFLAGS="-I${includedir}/libxml2"
libxml2_LIBS="-lxml2" libxml2_LIBS="-lxml2"
PC_LIBS="${libxml2_LIBS} ${PC_LIBS}" PC_LIBS+=($libxml2_LIBS)
PC_CFLAGS="${libxml2_CFLAGS} ${PC_CFLAGS}" PC_CFLAGS+=($libxml2_CFLAGS)
]) ],
[AC_MSG_ERROR([libxml2 not found.])])
CFLAGS=$old_CFLAGS 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.])]
)
])
fi fi
if test "x$with_parser" = xlibxml2; then if test "x$with_libxml2" = xyes; then
with_parser=libxml2
PARSER_NAME=libxml2
PARSER_CFLAGS=$libxml2_CFLAGS PARSER_CFLAGS=$libxml2_CFLAGS
PARSER_LIBS=$libxml2_LIBS PARSER_LIBS=$libxml2_LIBS
elif test "x$with_parser" = xexpat; then else
with_parser=expat
PARSER_NAME=expat
PARSER_CFLAGS=$expat_CFLAGS PARSER_CFLAGS=$expat_CFLAGS
PARSER_LIBS=$expat_LIBS PARSER_LIBS=$expat_LIBS
else
AC_MSG_ERROR([no XML parser was found, libstrophe requires expat or libxml2])
fi fi
AC_MSG_NOTICE([libstrophe will use the $with_parser XML parser]) AC_MSG_NOTICE([libstrophe will use the $with_parser XML parser])
AC_SEARCH_LIBS([socket], [socket]) AC_SEARCH_LIBS([socket], [socket])
AS_CASE([$PLATFORM], if test "x$PLATFORM" != xfreebsd; then
[bsd], [RESOLV_LIBS=""], AC_CHECK_LIB([resolv], [res_query], [],
[qnx], [RESOLV_LIBS="-lsocket"], [AC_CHECK_LIB([resolv], [__res_query], [],
[solaris], [RESOLV_LIBS="-lresolv -lsocket -lnsl"], [AC_MSG_ERROR([libresolv not found; libresolv required.])])])
[android], [RESOLV_LIBS=""], PC_LIBS+=(-lresolv)
[RESOLV_LIBS="-lresolv"]) else
AC_MSG_NOTICE([skipping libresolv checks for freebsd])
fi
LIBS_TMP="${LIBS}" AC_CHECK_HEADERS([arpa/nameser_compat.h])
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], m4_ifdef([PKG_INSTALLDIR], [PKG_INSTALLDIR],
[AC_ARG_WITH([pkgconfigdir], [AC_ARG_WITH([pkgconfigdir],
@@ -118,14 +96,13 @@ m4_ifdef([PKG_INSTALLDIR], [PKG_INSTALLDIR],
AC_SUBST([pkgconfigdir], [${with_pkgconfigdir}])]) AC_SUBST([pkgconfigdir], [${with_pkgconfigdir}])])
AM_CONDITIONAL([PARSER_EXPAT], [test x$with_parser != xlibxml2]) AM_CONDITIONAL([PARSER_EXPAT], [test x$with_parser != xlibxml2])
AM_CONDITIONAL([DISABLE_TLS], [test x$enable_tls = xno])
AC_SUBST([PC_REQUIRES], [${PC_REQUIRES}]) AC_SUBST([PC_REQUIRES], [${PC_REQUIRES[[@]]}])
AC_SUBST([PC_CFLAGS], [${PC_CFLAGS}]) AC_SUBST([PC_CFLAGS], [${PC_CFLAGS[[@]]}])
AC_SUBST([PC_LIBS], [${PC_LIBS}]) AC_SUBST([PC_LIBS], [${PC_LIBS[[@]]}])
AC_SUBST(PARSER_NAME)
AC_SUBST(PARSER_CFLAGS) AC_SUBST(PARSER_CFLAGS)
AC_SUBST(PARSER_LIBS) AC_SUBST(PARSER_LIBS)
AC_SUBST(RESOLV_LIBS)
AC_CONFIG_FILES([Makefile libstrophe.pc]) AC_CONFIG_FILES([Makefile libstrophe.pc])
AC_OUTPUT AC_OUTPUT

View File

@@ -1,7 +0,0 @@
Build Instructions
==================
Compile example files with the following gcc flags:
```
gcc -o bot bot.c `pkg-config --cflags --libs libstrophe`
```

View File

@@ -24,7 +24,7 @@ int handle_reply(xmpp_conn_t * const conn,
void * const userdata) void * const userdata)
{ {
xmpp_stanza_t *query, *item; xmpp_stanza_t *query, *item;
const char *type; char *type;
type = xmpp_stanza_get_type(stanza); type = xmpp_stanza_get_type(stanza);
if (strcmp(type, "error") == 0) if (strcmp(type, "error") == 0)
@@ -55,8 +55,11 @@ void conn_handler(xmpp_conn_t * const conn, const xmpp_conn_event_t status,
fprintf(stderr, "DEBUG: connected\n"); fprintf(stderr, "DEBUG: connected\n");
/* create iq stanza for request */ /* create iq stanza for request */
iq = xmpp_iq_new(ctx, "get", "active1"); iq = xmpp_stanza_new(ctx);
xmpp_stanza_set_to(iq, "xxxxxxxxx.com"); 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");
query = xmpp_stanza_new(ctx); query = xmpp_stanza_new(ctx);
xmpp_stanza_set_name(query, "query"); xmpp_stanza_set_name(query, "query");
@@ -101,13 +104,6 @@ int main(int argc, char **argv)
/* create a connection */ /* create a connection */
conn = xmpp_conn_new(ctx); 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 */ /* setup authentication information */
xmpp_conn_set_jid(conn, argv[1]); xmpp_conn_set_jid(conn, argv[1]);
xmpp_conn_set_pass(conn, argv[2]); xmpp_conn_set_pass(conn, argv[2]);

View File

@@ -10,13 +10,9 @@
*/ */
#include <stdio.h> #include <stdio.h>
#include <string.h>
#include <strophe.h> #include <strophe.h>
/* hardcoded TCP keepalive timeout and interval */
#define KA_TIMEOUT 60
#define KA_INTERVAL 1
/* define a handler for connection events */ /* define a handler for connection events */
void conn_handler(xmpp_conn_t * const conn, const xmpp_conn_event_t status, void conn_handler(xmpp_conn_t * const conn, const xmpp_conn_event_t status,
@@ -24,13 +20,9 @@ void conn_handler(xmpp_conn_t * const conn, const xmpp_conn_event_t status,
void * const userdata) void * const userdata)
{ {
xmpp_ctx_t *ctx = (xmpp_ctx_t *)userdata; xmpp_ctx_t *ctx = (xmpp_ctx_t *)userdata;
int secured;
if (status == XMPP_CONN_CONNECT) { if (status == XMPP_CONN_CONNECT) {
fprintf(stderr, "DEBUG: connected\n"); fprintf(stderr, "DEBUG: connected\n");
secured = xmpp_conn_is_secured(conn);
fprintf(stderr, "DEBUG: connection is %s.\n",
secured ? "secured" : "NOT secured");
xmpp_disconnect(conn); xmpp_disconnect(conn);
} }
else { else {
@@ -44,45 +36,20 @@ int main(int argc, char **argv)
xmpp_ctx_t *ctx; xmpp_ctx_t *ctx;
xmpp_conn_t *conn; xmpp_conn_t *conn;
xmpp_log_t *log; xmpp_log_t *log;
char *jid, *pass, *host = NULL; char *jid, *pass, *host;
long flags = 0;
int tcp_keepalive = 0;
int i;
/* take a jid and password on the command line */ /* take a jid and password on the command line */
for (i = 1; i < argc; ++i) { if (argc < 3 || argc > 4) {
if (strcmp(argv[i], "--disable-tls") == 0) fprintf(stderr, "Usage: basic <jid> <pass> [<host>]\n\n");
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; return 1;
} }
jid = argv[i]; jid = argv[1];
pass = argv[i + 1]; pass = argv[2];
if (i + 2 < argc) host = NULL;
host = argv[i + 2];
/* if (argc == 4)
* Note, this example doesn't handle errors. Applications should check host = argv[3];
* return values of non-void functions.
*/
/* init library */ /* init library */
xmpp_initialize(); xmpp_initialize();
@@ -94,11 +61,6 @@ int main(int argc, char **argv)
/* create a connection */ /* create a connection */
conn = xmpp_conn_new(ctx); 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 */ /* setup authentication information */
xmpp_conn_set_jid(conn, jid); xmpp_conn_set_jid(conn, jid);
xmpp_conn_set_pass(conn, pass); xmpp_conn_set_pass(conn, pass);

View File

@@ -26,13 +26,15 @@
int version_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) int version_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata)
{ {
xmpp_stanza_t *reply, *query, *name, *version, *text; xmpp_stanza_t *reply, *query, *name, *version, *text;
const char *ns; char *ns;
xmpp_ctx_t *ctx = (xmpp_ctx_t*)userdata; xmpp_ctx_t *ctx = (xmpp_ctx_t*)userdata;
printf("Received version request from %s\n", xmpp_stanza_get_attribute(stanza, "from"));
printf("Received version request from %s\n", xmpp_stanza_get_from(stanza)); reply = xmpp_stanza_new(ctx);
xmpp_stanza_set_name(reply, "iq");
reply = xmpp_stanza_reply(stanza);
xmpp_stanza_set_type(reply, "result"); 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); query = xmpp_stanza_new(ctx);
xmpp_stanza_set_name(query, "query"); xmpp_stanza_set_name(query, "query");
@@ -44,25 +46,20 @@ int version_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void
name = xmpp_stanza_new(ctx); name = xmpp_stanza_new(ctx);
xmpp_stanza_set_name(name, "name"); xmpp_stanza_set_name(name, "name");
xmpp_stanza_add_child(query, name); xmpp_stanza_add_child(query, name);
xmpp_stanza_release(name);
text = xmpp_stanza_new(ctx); text = xmpp_stanza_new(ctx);
xmpp_stanza_set_text(text, "libstrophe example bot"); xmpp_stanza_set_text(text, "libstrophe example bot");
xmpp_stanza_add_child(name, text); xmpp_stanza_add_child(name, text);
xmpp_stanza_release(text);
version = xmpp_stanza_new(ctx); version = xmpp_stanza_new(ctx);
xmpp_stanza_set_name(version, "version"); xmpp_stanza_set_name(version, "version");
xmpp_stanza_add_child(query, version); xmpp_stanza_add_child(query, version);
xmpp_stanza_release(version);
text = xmpp_stanza_new(ctx); text = xmpp_stanza_new(ctx);
xmpp_stanza_set_text(text, "1.0"); xmpp_stanza_set_text(text, "1.0");
xmpp_stanza_add_child(version, text); xmpp_stanza_add_child(version, text);
xmpp_stanza_release(text);
xmpp_stanza_add_child(reply, query); xmpp_stanza_add_child(reply, query);
xmpp_stanza_release(query);
xmpp_send(conn, reply); xmpp_send(conn, reply);
xmpp_stanza_release(reply); xmpp_stanza_release(reply);
@@ -72,45 +69,37 @@ int version_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void
int message_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) int message_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata)
{ {
xmpp_ctx_t *ctx = (xmpp_ctx_t*)userdata; xmpp_stanza_t *reply, *body, *text;
xmpp_stanza_t *body, *reply;
const char *type;
char *intext, *replytext; char *intext, *replytext;
int quit = 0; xmpp_ctx_t *ctx = (xmpp_ctx_t*)userdata;
body = xmpp_stanza_get_child_by_name(stanza, "body"); if(!xmpp_stanza_get_child_by_name(stanza, "body")) return 1;
if (body == NULL) if(xmpp_stanza_get_attribute(stanza, "type") !=NULL && !strcmp(xmpp_stanza_get_attribute(stanza, "type"), "error")) return 1;
return 1;
type = xmpp_stanza_get_type(stanza);
if (type != NULL && strcmp(type, "error") == 0)
return 1;
intext = xmpp_stanza_get_text(body); intext = xmpp_stanza_get_text(xmpp_stanza_get_child_by_name(stanza, "body"));
printf("Incoming message from %s: %s\n", xmpp_stanza_get_from(stanza), intext); printf("Incoming message from %s: %s\n", xmpp_stanza_get_attribute(stanza, "from"), intext);
reply = xmpp_stanza_reply(stanza); reply = xmpp_stanza_new(ctx);
if (xmpp_stanza_get_type(reply) == NULL) xmpp_stanza_set_name(reply, "message");
xmpp_stanza_set_type(reply, "chat"); 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"));
if (strcmp(intext, "quit") == 0) { body = xmpp_stanza_new(ctx);
replytext = strdup("bye!"); xmpp_stanza_set_name(body, "body");
quit = 1;
} else { replytext = malloc(strlen(" to you too!") + strlen(intext) + 1);
replytext = (char *) malloc(strlen(" to you too!") + strlen(intext) + 1);
strcpy(replytext, intext); strcpy(replytext, intext);
strcat(replytext, " to you too!"); strcat(replytext, " to you too!");
}
xmpp_free(ctx, intext); text = xmpp_stanza_new(ctx);
xmpp_message_set_body(reply, replytext); xmpp_stanza_set_text(text, replytext);
xmpp_stanza_add_child(body, text);
xmpp_stanza_add_child(reply, body);
xmpp_send(conn, reply); xmpp_send(conn, reply);
xmpp_stanza_release(reply); xmpp_stanza_release(reply);
free(replytext); free(replytext);
if (quit)
xmpp_disconnect(conn);
return 1; return 1;
} }
@@ -128,7 +117,8 @@ void conn_handler(xmpp_conn_t * const conn, const xmpp_conn_event_t status,
xmpp_handler_add(conn,message_handler, NULL, "message", NULL, ctx); xmpp_handler_add(conn,message_handler, NULL, "message", NULL, ctx);
/* Send initial <presence/> so that we appear online to contacts */ /* Send initial <presence/> so that we appear online to contacts */
pres = xmpp_presence_new(ctx); pres = xmpp_stanza_new(ctx);
xmpp_stanza_set_name(pres, "presence");
xmpp_send(conn, pres); xmpp_send(conn, pres);
xmpp_stanza_release(pres); xmpp_stanza_release(pres);
} }
@@ -164,13 +154,6 @@ int main(int argc, char **argv)
/* create a connection */ /* create a connection */
conn = xmpp_conn_new(ctx); 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 */ /* setup authentication information */
xmpp_conn_set_jid(conn, jid); xmpp_conn_set_jid(conn, jid);
xmpp_conn_set_pass(conn, pass); xmpp_conn_set_pass(conn, pass);

View File

@@ -23,7 +23,7 @@ int handle_reply(xmpp_conn_t * const conn,
void * const userdata) void * const userdata)
{ {
xmpp_stanza_t *query, *item; xmpp_stanza_t *query, *item;
const char *type, *name; char *type, *name;
type = xmpp_stanza_get_type(stanza); type = xmpp_stanza_get_type(stanza);
if (strcmp(type, "error") == 0) if (strcmp(type, "error") == 0)
@@ -62,7 +62,10 @@ void conn_handler(xmpp_conn_t * const conn, const xmpp_conn_event_t status,
fprintf(stderr, "DEBUG: connected\n"); fprintf(stderr, "DEBUG: connected\n");
/* create iq stanza for request */ /* create iq stanza for request */
iq = xmpp_iq_new(ctx, "get", "roster1"); iq = xmpp_stanza_new(ctx);
xmpp_stanza_set_name(iq, "iq");
xmpp_stanza_set_type(iq, "get");
xmpp_stanza_set_id(iq, "roster1");
query = xmpp_stanza_new(ctx); query = xmpp_stanza_new(ctx);
xmpp_stanza_set_name(query, "query"); xmpp_stanza_set_name(query, "query");
@@ -106,13 +109,6 @@ int main(int argc, char **argv)
/* create a connection */ /* create a connection */
conn = xmpp_conn_new(ctx); 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 */ /* setup authentication information */
xmpp_conn_set_jid(conn, argv[1]); xmpp_conn_set_jid(conn, argv[1]);
xmpp_conn_set_pass(conn, argv[2]); xmpp_conn_set_pass(conn, argv[2]);

View File

@@ -1,83 +0,0 @@
#include <stdio.h>
#include <string.h>
#include <strophe.h>
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
#endif
int message_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza,
void * const userdata)
{
xmpp_ctx_t *ctx = (xmpp_ctx_t *)userdata;
xmpp_stanza_t *success;
if (strcmp(xmpp_stanza_get_name(stanza), "auth") == 0) {
success = xmpp_stanza_new(ctx);
xmpp_stanza_set_name(success, "success");
xmpp_stanza_set_ns(success, XMPP_NS_SASL);
xmpp_send(conn, success);
xmpp_stanza_release(success);
} else
xmpp_disconnect(conn);
return 1;
}
void server_handler(xmpp_server_t * const srv, xmpp_conn_t * const conn,
const xmpp_server_event_t event, const int error,
void * const userdata)
{
xmpp_ctx_t *ctx = (xmpp_ctx_t *)userdata;
static char *attrs[] = {
"xmlns", XMPP_NS_CLIENT, "xmlns:stream", XMPP_NS_STREAMS,
"id", "0123456789", "from", "127.0.0.1", "version", "1.0",
"xml:lang", "en",
};
switch (event) {
case XMPP_SERVER_ACCEPT:
printf("Event XMPP_SERVER_ACCEPT\n");
break;
case XMPP_SERVER_OPEN_STREAM:
printf("Event XMPP_SERVER_OPEN_STREAM\n");
xmpp_handler_add(conn, message_handler, NULL, NULL, NULL, ctx);
xmpp_conn_open_stream(conn, attrs, ARRAY_SIZE(attrs));
xmpp_send_raw_string(conn,
"<stream:features>"
"<mechanisms xmlns=\"%s\"><mechanism>PLAIN</mechanism>"
"</mechanisms></stream:features>", XMPP_NS_SASL);
break;
case XMPP_SERVER_DISCONNECT:
printf("Event XMPP_SERVER_DISCONNECT\n");
xmpp_stop(ctx);
break;
default:
printf("Unknown event\n");
break;
}
}
int main()
{
xmpp_ctx_t *ctx;
xmpp_log_t *log;
xmpp_server_t *srv;
xmpp_initialize();
log = xmpp_get_default_logger(XMPP_LEVEL_DEBUG);
ctx = xmpp_ctx_new(NULL, log);
srv = xmpp_server_new(ctx);
xmpp_server_listen(srv, 0, server_handler, ctx);
xmpp_run(ctx);
xmpp_server_stop(srv);
xmpp_server_free(srv);
xmpp_ctx_free(ctx);
xmpp_shutdown();
return 0;
}

View File

@@ -1,23 +0,0 @@
#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;
}

View File

@@ -1,284 +0,0 @@
/* 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 Submodule

Submodule expat added at adf19a3186

View File

@@ -1,79 +0,0 @@
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/server.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)

View File

@@ -1,2 +0,0 @@
APP_ABI := armeabi armeabi-v7a mips x86
APP_PLATFORM := android-19

View File

@@ -1,6 +1,6 @@
1. Setup 1. Setup
yum install gcc make autoconf automake expat-devel openssl-devel yum install gcc make expat-devel libstrophe
Fedora: Fedora:

View File

@@ -8,12 +8,10 @@ License: MIT/GPLv3
URL: http://strophe.im/libstrophe/ URL: http://strophe.im/libstrophe/
Source0: libstrophe_git.tar.gz Source0: libstrophe_git.tar.gz
BuildRequires: autoconf
BuildRequires: automake BuildRequires: automake
BuildRequires: libtool BuildRequires: libtool
BuildRequires: openssl-devel BuildRequires: openssl-devel
BuildRequires: expat-devel BuildRequires: expat-devel
Requires: openssl
Requires: expat Requires: expat
%description %description

View File

@@ -16,12 +16,12 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <time.h>
#include "strophe.h" #include "strophe.h"
#include "common.h" #include "common.h"
#include "sasl.h" #include "sasl.h"
#include "sha1.h" #include "sha1.h"
#include "rand.h"
#ifdef _MSC_VER #ifdef _MSC_VER
#define strcasecmp stricmp #define strcasecmp stricmp
@@ -62,7 +62,6 @@
static void _auth(xmpp_conn_t * const conn); static void _auth(xmpp_conn_t * const conn);
static void _handle_open_sasl(xmpp_conn_t * const conn); static void _handle_open_sasl(xmpp_conn_t * const conn);
static void _handle_open_tls(xmpp_conn_t * const conn);
static int _handle_component_auth(xmpp_conn_t * const conn); static int _handle_component_auth(xmpp_conn_t * const conn);
static int _handle_component_hs_response(xmpp_conn_t * const conn, static int _handle_component_hs_response(xmpp_conn_t * const conn,
@@ -112,7 +111,7 @@ static int _handle_error(xmpp_conn_t * const conn,
void * const userdata) void * const userdata)
{ {
xmpp_stanza_t *child; xmpp_stanza_t *child;
const char *name; char *name;
/* free old stream error if it's still there */ /* free old stream error if it's still there */
if (conn->stream_error) { if (conn->stream_error) {
@@ -131,7 +130,7 @@ static int _handle_error(xmpp_conn_t * const conn,
if (conn->stream_error) { if (conn->stream_error) {
child = xmpp_stanza_get_children(stanza); child = xmpp_stanza_get_children(stanza);
do { do {
const char *ns = NULL; char *ns = NULL;
if (child) { if (child) {
ns = xmpp_stanza_get_ns(child); ns = xmpp_stanza_get_ns(child);
@@ -280,21 +279,33 @@ static int _handle_proceedtls_default(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza, xmpp_stanza_t * const stanza,
void * const userdata) void * const userdata)
{ {
const char *name; char *name;
name = xmpp_stanza_get_name(stanza); 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) { if (strcmp(name, "proceed") == 0) {
xmpp_debug(conn->ctx, "xmpp", "proceeding with TLS"); xmpp_debug(conn->ctx, "xmpp", "proceeding with TLS");
if (conn_tls_start(conn) == 0) { conn->tls = tls_new(conn->ctx, conn->sock);
conn_prepare_reset(conn, _handle_open_tls);
conn_open_stream(conn); if (!tls_start(conn->tls))
} else { {
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 */ /* failed tls spoils the connection, so disconnect */
xmpp_disconnect(conn); xmpp_disconnect(conn);
} }
else
{
conn->secured = 1;
conn_prepare_reset(conn, auth_handle_open);
conn_open_stream(conn);
}
} }
return 0; return 0;
@@ -304,7 +315,7 @@ static int _handle_sasl_result(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza, xmpp_stanza_t * const stanza,
void * const userdata) void * const userdata)
{ {
const char *name; char *name;
name = xmpp_stanza_get_name(stanza); name = xmpp_stanza_get_name(stanza);
@@ -316,7 +327,7 @@ static int _handle_sasl_result(xmpp_conn_t * const conn,
/* fall back to next auth method */ /* fall back to next auth method */
_auth(conn); _auth(conn);
} else if (strcmp(name, "success") == 0) { } else if (strcmp(name, "success") == 0) {
/* SASL auth successful, we need to restart the stream */ /* SASL PLAIN auth successful, we need to restart the stream */
xmpp_debug(conn->ctx, "xmpp", "SASL %s auth successful", xmpp_debug(conn->ctx, "xmpp", "SASL %s auth successful",
(char *)userdata); (char *)userdata);
@@ -343,7 +354,7 @@ static int _handle_digestmd5_challenge(xmpp_conn_t * const conn,
char *text; char *text;
char *response; char *response;
xmpp_stanza_t *auth, *authdata; xmpp_stanza_t *auth, *authdata;
const char *name; char *name;
name = xmpp_stanza_get_name(stanza); name = xmpp_stanza_get_name(stanza);
xmpp_debug(conn->ctx, "xmpp",\ xmpp_debug(conn->ctx, "xmpp",\
@@ -398,7 +409,7 @@ static int _handle_digestmd5_rspauth(xmpp_conn_t * const conn,
void * const userdata) void * const userdata)
{ {
xmpp_stanza_t *auth; xmpp_stanza_t *auth;
const char *name; char *name;
name = xmpp_stanza_get_name(stanza); name = xmpp_stanza_get_name(stanza);
xmpp_debug(conn->ctx, "xmpp", xmpp_debug(conn->ctx, "xmpp",
@@ -431,7 +442,7 @@ static int _handle_scram_sha1_challenge(xmpp_conn_t * const conn,
char *text; char *text;
char *response; char *response;
xmpp_stanza_t *auth, *authdata; xmpp_stanza_t *auth, *authdata;
const char *name; char *name;
char *challenge; char *challenge;
char *scram_init = (char *)userdata; char *scram_init = (char *)userdata;
@@ -444,7 +455,7 @@ static int _handle_scram_sha1_challenge(xmpp_conn_t * const conn,
if (!text) if (!text)
goto err; goto err;
challenge = xmpp_base64_decode_str(conn->ctx, text, strlen(text)); challenge = (char *)base64_decode(conn->ctx, text, strlen(text));
xmpp_free(conn->ctx, text); xmpp_free(conn->ctx, text);
if (!challenge) if (!challenge)
goto err; goto err;
@@ -490,25 +501,46 @@ err:
return 0; 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) static char *_make_scram_sha1_init_msg(xmpp_conn_t * const conn)
{ {
xmpp_ctx_t *ctx = conn->ctx;
size_t message_len; size_t message_len;
char *node; char *node;
char *message; char *message;
char nonce[32]; char *nonce;
node = xmpp_jid_node(ctx, conn->jid); node = xmpp_jid_node(conn->ctx, conn->jid);
if (!node) { if (!node) {
return NULL; return NULL;
} }
xmpp_rand_nonce(ctx->rand, nonce, sizeof(nonce));
nonce = _get_nonce(conn->ctx);
if (!nonce) {
return NULL;
}
message_len = strlen(node) + strlen(nonce) + 8 + 1; message_len = strlen(node) + strlen(nonce) + 8 + 1;
message = xmpp_alloc(ctx, message_len); message = xmpp_alloc(conn->ctx, message_len);
if (message) { if (message) {
xmpp_snprintf(message, message_len, "n,,n=%s,r=%s", node, nonce); xmpp_snprintf(message, message_len, "n,,n=%s,r=%s", node, nonce);
xmpp_free(conn->ctx, node);
} }
xmpp_free(ctx, node); xmpp_free(conn->ctx, nonce);
return message; return message;
} }
@@ -564,15 +596,19 @@ static void _auth(xmpp_conn_t * const conn)
anonjid = 0; anonjid = 0;
} }
if (conn->tls_support) { if (conn->tls_support)
tls_t *tls = tls_new(conn); {
tls_t *tls = tls_new(conn->ctx, conn->sock);
/* If we couldn't init tls, it isn't there, so go on */ /* If we couldn't init tls, it isn't there, so go on */
if (!tls) { if (!tls)
{
conn->tls_support = 0; conn->tls_support = 0;
_auth(conn); _auth(conn);
return; return;
} else { }
else
{
tls_free(tls); tls_free(tls);
} }
@@ -591,18 +627,7 @@ static void _auth(xmpp_conn_t * const conn)
/* TLS was tried, unset flag */ /* TLS was tried, unset flag */
conn->tls_support = 0; conn->tls_support = 0;
/* _auth() will be called later */ } else if (anonjid && conn->sasl_support & SASL_MASK_ANONYMOUS) {
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 */ /* some crap here */
auth = _make_sasl_auth(conn, "ANONYMOUS"); auth = _make_sasl_auth(conn, "ANONYMOUS");
if (!auth) { if (!auth) {
@@ -637,7 +662,7 @@ static void _auth(xmpp_conn_t * const conn)
return; return;
} }
str = xmpp_base64_encode(conn->ctx, (unsigned char *)scram_init, str = (char *)base64_encode(conn->ctx, (unsigned char *)scram_init,
strlen(scram_init)); strlen(scram_init));
if (!str) { if (!str) {
xmpp_free(conn->ctx, scram_init); xmpp_free(conn->ctx, scram_init);
@@ -722,11 +747,14 @@ static void _auth(xmpp_conn_t * const conn)
} else if (conn->type == XMPP_CLIENT) { } else if (conn->type == XMPP_CLIENT) {
/* legacy client authentication */ /* legacy client authentication */
iq = xmpp_iq_new(conn->ctx, "set", "_xmpp_auth1"); iq = xmpp_stanza_new(conn->ctx);
if (!iq) { if (!iq) {
disconnect_mem_error(conn); disconnect_mem_error(conn);
return; 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); query = xmpp_stanza_new(conn->ctx);
if (!query) { if (!query) {
@@ -836,23 +864,15 @@ void auth_handle_open(xmpp_conn_t * const conn)
/* reset all timed handlers */ /* reset all timed handlers */
handler_reset_timed(conn, 0); handler_reset_timed(conn, 0);
/* setup handler for stream:error, we will keep this handler /* setup handler for stream:error */
* for reopened streams until connection is disconnected */ handler_add(conn, _handle_error,
handler_add(conn, _handle_error, XMPP_NS_STREAMS, "error", NULL, NULL); XMPP_NS_STREAMS, "error", NULL, NULL);
/* setup handlers for incoming <stream:features> */ /* setup handlers for incoming <stream:features> */
handler_add(conn, _handle_features, handler_add(conn, _handle_features,
XMPP_NS_STREAMS, "features", NULL, NULL); XMPP_NS_STREAMS, "features", NULL, NULL);
handler_add_timed(conn, _handle_missing_features, 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 */ /* called when stream:stream tag received after SASL auth */
@@ -902,12 +922,16 @@ static int _handle_features_sasl(xmpp_conn_t * const conn,
BIND_TIMEOUT, NULL); BIND_TIMEOUT, NULL);
/* send bind request */ /* send bind request */
iq = xmpp_iq_new(conn->ctx, "set", "_xmpp_bind1"); iq = xmpp_stanza_new(conn->ctx);
if (!iq) { if (!iq) {
disconnect_mem_error(conn); disconnect_mem_error(conn);
return 0; return 0;
} }
xmpp_stanza_set_name(iq, "iq");
xmpp_stanza_set_type(iq, "set");
xmpp_stanza_set_id(iq, "_xmpp_bind1");
bind = xmpp_stanza_copy(bind); bind = xmpp_stanza_copy(bind);
if (!bind) { if (!bind) {
xmpp_stanza_release(iq); xmpp_stanza_release(iq);
@@ -979,7 +1003,7 @@ static int _handle_bind(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza, xmpp_stanza_t * const stanza,
void * const userdata) void * const userdata)
{ {
const char *type; char *type;
xmpp_stanza_t *iq, *session; xmpp_stanza_t *iq, *session;
/* delete missing bind handler */ /* delete missing bind handler */
@@ -1010,17 +1034,20 @@ static int _handle_bind(xmpp_conn_t * const conn,
SESSION_TIMEOUT, NULL); SESSION_TIMEOUT, NULL);
/* send session request */ /* send session request */
iq = xmpp_iq_new(conn->ctx, "set", "_xmpp_session1"); iq = xmpp_stanza_new(conn->ctx);
if (!iq) { if (!iq) {
disconnect_mem_error(conn); disconnect_mem_error(conn);
return 0; return 0;
} }
xmpp_stanza_set_name(iq, "iq");
xmpp_stanza_set_type(iq, "set");
xmpp_stanza_set_id(iq, "_xmpp_session1");
session = xmpp_stanza_new(conn->ctx); session = xmpp_stanza_new(conn->ctx);
if (!session) { if (!session) {
xmpp_stanza_release(iq); xmpp_stanza_release(iq);
disconnect_mem_error(conn); disconnect_mem_error(conn);
return 0;
} }
xmpp_stanza_set_name(session, "session"); xmpp_stanza_set_name(session, "session");
@@ -1059,7 +1086,7 @@ static int _handle_session(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza, xmpp_stanza_t * const stanza,
void * const userdata) void * const userdata)
{ {
const char *type; char *type;
/* delete missing session handler */ /* delete missing session handler */
xmpp_timed_handler_delete(conn, _handle_missing_session); xmpp_timed_handler_delete(conn, _handle_missing_session);
@@ -1096,8 +1123,7 @@ static int _handle_legacy(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza, xmpp_stanza_t * const stanza,
void * const userdata) void * const userdata)
{ {
const char *type; char *type, *name;
const char *name;
/* delete missing handler */ /* delete missing handler */
xmpp_timed_handler_delete(conn, _handle_missing_legacy); xmpp_timed_handler_delete(conn, _handle_missing_legacy);
@@ -1139,8 +1165,6 @@ static int _handle_missing_legacy(xmpp_conn_t * const conn,
void auth_handle_component_open(xmpp_conn_t * const conn) void auth_handle_component_open(xmpp_conn_t * const conn)
{ {
int rc;
/* reset all timed handlers */ /* reset all timed handlers */
handler_reset_timed(conn, 0); handler_reset_timed(conn, 0);
@@ -1149,11 +1173,7 @@ void auth_handle_component_open(xmpp_conn_t * const conn)
"handshake", NULL, NULL); "handshake", NULL, NULL);
handler_add_timed(conn, _handle_missing_handshake, HANDSHAKE_TIMEOUT, NULL); handler_add_timed(conn, _handle_missing_handshake, HANDSHAKE_TIMEOUT, NULL);
rc = _handle_component_auth(conn); _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 */ /* Will compute SHA1 and authenticate the component to the server */
@@ -1164,19 +1184,13 @@ int _handle_component_auth(xmpp_conn_t * const conn)
char *digest; char *digest;
size_t i; 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. /* Feed the session id and passphrase to the algorithm.
* We need to compute SHA1(session_id + passphrase) * We need to compute SHA1(session_id + passphrase)
*/ */
crypto_SHA1_Init(&mdctx); SHA1_Init(&mdctx);
crypto_SHA1_Update(&mdctx, (uint8_t*)conn->stream_id, SHA1_Update(&mdctx, (uint8_t*)conn->stream_id, strlen(conn->stream_id));
strlen(conn->stream_id)); SHA1_Update(&mdctx, (uint8_t*)conn->pass, strlen(conn->pass));
crypto_SHA1_Update(&mdctx, (uint8_t*)conn->pass, strlen(conn->pass)); SHA1_Final(&mdctx, md_value);
crypto_SHA1_Final(&mdctx, md_value);
digest = xmpp_alloc(conn->ctx, 2*sizeof(md_value)+1); digest = xmpp_alloc(conn->ctx, 2*sizeof(md_value)+1);
if (digest) { if (digest) {
@@ -1196,6 +1210,7 @@ int _handle_component_auth(xmpp_conn_t * const conn)
} else { } else {
xmpp_debug(conn->ctx, "auth", "Couldn't allocate memory for component "\ xmpp_debug(conn->ctx, "auth", "Couldn't allocate memory for component "\
"handshake digest."); "handshake digest.");
xmpp_disconnect(conn);
return XMPP_EMEM; return XMPP_EMEM;
} }
@@ -1209,7 +1224,7 @@ int _handle_component_hs_response(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza, xmpp_stanza_t * const stanza,
void * const userdata) void * const userdata)
{ {
const char *name; char *name;
xmpp_timed_handler_delete(conn, _handle_missing_handshake); xmpp_timed_handler_delete(conn, _handle_missing_handshake);
@@ -1241,16 +1256,3 @@ int _handle_missing_handshake(xmpp_conn_t * const conn, void * const userdata)
xmpp_disconnect(conn); xmpp_disconnect(conn);
return 0; 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.");
}

View File

@@ -27,8 +27,6 @@
#include "hash.h" #include "hash.h"
#include "util.h" #include "util.h"
#include "parser.h" #include "parser.h"
#include "rand.h"
#include "snprintf.h"
/** run-time context **/ /** run-time context **/
@@ -43,21 +41,12 @@ typedef struct _xmpp_connlist_t {
struct _xmpp_connlist_t *next; struct _xmpp_connlist_t *next;
} xmpp_connlist_t; } xmpp_connlist_t;
typedef struct _xmpp_serverlist_t {
xmpp_server_t *server;
struct _xmpp_serverlist_t *next;
} xmpp_serverlist_t;
struct _xmpp_ctx_t { struct _xmpp_ctx_t {
const xmpp_mem_t *mem; const xmpp_mem_t *mem;
const xmpp_log_t *log; const xmpp_log_t *log;
xmpp_rand_t *rand;
xmpp_loop_status_t loop_status; xmpp_loop_status_t loop_status;
xmpp_connlist_t *connlist; xmpp_connlist_t *connlist;
xmpp_serverlist_t *serverlist;
unsigned long timeout;
}; };
@@ -91,6 +80,17 @@ void xmpp_debug(const xmpp_ctx_t * const ctx,
const char * const fmt, 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);
/** connection **/ /** connection **/
/* opaque connection object */ /* opaque connection object */
@@ -113,7 +113,7 @@ typedef struct _xmpp_handlist_t xmpp_handlist_t;
struct _xmpp_handlist_t { struct _xmpp_handlist_t {
/* common members */ /* common members */
int user_handler; int user_handler;
int (*handler)(); void *handler;
void *userdata; void *userdata;
int enabled; /* handlers are added disabled and enabled after the int enabled; /* handlers are added disabled and enabled after the
* handler chain is processed to prevent stanzas from * handler chain is processed to prevent stanzas from
@@ -139,18 +139,10 @@ struct _xmpp_handlist_t {
}; };
}; };
#define MAX_DOMAIN_LEN 256 #define SASL_MASK_PLAIN 0x01
#define SASL_MASK_DIGESTMD5 0x02
#define SASL_MASK_PLAIN (1 << 0) #define SASL_MASK_ANONYMOUS 0x04
#define SASL_MASK_DIGESTMD5 (1 << 1) #define SASL_MASK_SCRAMSHA1 0x08
#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); typedef void (*xmpp_open_handler)(xmpp_conn_t * const conn);
@@ -158,23 +150,16 @@ struct _xmpp_conn_t {
unsigned int ref; unsigned int ref;
xmpp_ctx_t *ctx; xmpp_ctx_t *ctx;
xmpp_conn_type_t type; xmpp_conn_type_t type;
int is_raw;
xmpp_conn_state_t state; xmpp_conn_state_t state;
uint64_t timeout_stamp; uint64_t timeout_stamp;
int error; int error;
xmpp_stream_error_t *stream_error; xmpp_stream_error_t *stream_error;
sock_t sock; sock_t sock;
int ka_timeout; /* TCP keepalive timeout */
int ka_interval; /* TCP keepalive interval */
tls_t *tls; tls_t *tls;
int tls_support; int tls_support;
int tls_disabled; 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 tls_failed; /* set when tls fails, so we don't try again */
int sasl_support; /* if true, field is a bitfield of supported int sasl_support; /* if true, field is a bitfield of supported
mechanisms */ mechanisms */
@@ -186,6 +171,8 @@ struct _xmpp_conn_t {
char *lang; char *lang;
char *domain; char *domain;
char *connectdomain;
char *connectport;
char *jid; char *jid;
char *pass; char *pass;
char *bound_jid; char *bound_jid;
@@ -225,30 +212,10 @@ struct _xmpp_conn_t {
void conn_disconnect(xmpp_conn_t * const conn); void conn_disconnect(xmpp_conn_t * const conn);
void conn_disconnect_clean(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); 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_prepare_reset(xmpp_conn_t * const conn, xmpp_open_handler handler);
void conn_parser_reset(xmpp_conn_t * const conn); void conn_parser_reset(xmpp_conn_t * const conn);
typedef enum {
XMPP_STATE_STOPPED,
XMPP_STATE_LISTENING
} xmpp_server_state_t;
struct _xmpp_server_t {
xmpp_ctx_t *ctx;
xmpp_server_state_t state;
sock_t sock;
unsigned short port;
xmpp_server_handler callback;
void *userdata;
/* incomming connections list */
};
void server_accept(xmpp_server_t * const srv);
void server_handle_open(xmpp_conn_t * const conn);
typedef enum { typedef enum {
XMPP_STANZA_UNKNOWN, XMPP_STANZA_UNKNOWN,
@@ -291,7 +258,6 @@ void handler_add(xmpp_conn_t * const conn,
const char * const name, const char * const name,
const char * const type, const char * const type,
void * const userdata); void * const userdata);
void handler_system_delete_all(xmpp_conn_t *conn);
/* utility functions */ /* utility functions */
void disconnect_mem_error(xmpp_conn_t * const conn); void disconnect_mem_error(xmpp_conn_t * const conn);
@@ -299,7 +265,9 @@ void disconnect_mem_error(xmpp_conn_t * const conn);
/* auth functions */ /* auth functions */
void auth_handle_open(xmpp_conn_t * const conn); void auth_handle_open(xmpp_conn_t * const conn);
void auth_handle_component_open(xmpp_conn_t * const conn); void auth_handle_component_open(xmpp_conn_t * const conn);
void auth_handle_open_raw(xmpp_conn_t * const conn);
void auth_handle_open_stub(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);
#endif /* __LIBSTROPHE_COMMON_H__ */ #endif /* __LIBSTROPHE_COMMON_H__ */

View File

@@ -16,16 +16,15 @@
/** @defgroup Connections Connection management /** @defgroup Connections Connection management
*/ */
#include <errno.h> #include <stdio.h>
#include <stdarg.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "strophe.h" #include <strophe.h>
#include "common.h" #include "common.h"
#include "util.h" #include "util.h"
#include "parser.h" #include "parser.h"
#include "resolver.h"
#ifndef DEFAULT_SEND_QUEUE_MAX #ifndef DEFAULT_SEND_QUEUE_MAX
/** @def DEFAULT_SEND_QUEUE_MAX /** @def DEFAULT_SEND_QUEUE_MAX
@@ -50,28 +49,13 @@
static int _disconnect_cleanup(xmpp_conn_t * const conn, static int _disconnect_cleanup(xmpp_conn_t * const conn,
void * const userdata); void * const userdata);
static char *_conn_build_stream_tag(xmpp_conn_t * const conn,
char **attributes, size_t attributes_len);
static void _conn_attributes_new(xmpp_conn_t *conn, char **attrs,
char ***attributes, size_t *attributes_len);
static void _conn_attributes_destroy(xmpp_conn_t *conn, char **attributes,
size_t attributes_len);
static void _handle_stream_start(char *name, char **attrs, static void _handle_stream_start(char *name, char **attrs,
void * const userdata); void * const userdata);
static void _handle_stream_end(char *name, static void _handle_stream_end(char *name,
void * const userdata); void * const userdata);
static void _handle_stream_stanza(xmpp_stanza_t *stanza, static void _handle_stream_stanza(xmpp_stanza_t *stanza,
void * const userdata); void * const userdata);
static unsigned short _conn_default_port(xmpp_conn_t * const conn,
xmpp_conn_type_t type);
static void _conn_reset(xmpp_conn_t * const conn);
static int _conn_connect(xmpp_conn_t * const conn,
const char * const domain,
const char * const host,
unsigned short port,
xmpp_conn_type_t type,
xmpp_conn_handler callback,
void * const userdata);
/** Create a new Strophe connection object. /** Create a new Strophe connection object.
* *
@@ -87,16 +71,14 @@ xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t * const ctx)
xmpp_connlist_t *tail, *item; xmpp_connlist_t *tail, *item;
if (ctx == NULL) return NULL; if (ctx == NULL) return NULL;
conn = xmpp_alloc(ctx, sizeof(xmpp_conn_t)); conn = xmpp_alloc(ctx, sizeof(xmpp_conn_t));
if (conn != NULL) { if (conn != NULL) {
conn->ctx = ctx; conn->ctx = ctx;
conn->type = XMPP_UNKNOWN; conn->type = XMPP_UNKNOWN;
conn->state = XMPP_STATE_DISCONNECTED; conn->state = XMPP_STATE_DISCONNECTED;
conn->sock = -1; conn->sock = -1;
conn->ka_timeout = 0;
conn->ka_interval = 0;
conn->tls = NULL; conn->tls = NULL;
conn->timeout_stamp = 0; conn->timeout_stamp = 0;
conn->error = 0; conn->error = 0;
@@ -123,12 +105,8 @@ xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t * const ctx)
conn->stream_id = NULL; conn->stream_id = NULL;
conn->bound_jid = NULL; conn->bound_jid = NULL;
conn->is_raw = 0;
conn->tls_support = 0; conn->tls_support = 0;
conn->tls_disabled = 0; conn->tls_disabled = 0;
conn->tls_mandatory = 0;
conn->tls_legacy_ssl = 0;
conn->tls_trust = 0;
conn->tls_failed = 0; conn->tls_failed = 0;
conn->sasl_support = 0; conn->sasl_support = 0;
conn->secured = 0; conn->secured = 0;
@@ -142,6 +120,7 @@ xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t * const ctx)
_handle_stream_stanza, _handle_stream_stanza,
conn); conn);
conn->reset_parser = 0; conn->reset_parser = 0;
conn_prepare_reset(conn, auth_handle_open);
conn->authenticated = 0; conn->authenticated = 0;
conn->conn_handler = NULL; conn->conn_handler = NULL;
@@ -192,34 +171,6 @@ xmpp_conn_t *xmpp_conn_clone(xmpp_conn_t * const conn)
return conn; return conn;
} }
/** Set TCP keepalive parameters
* Turn on TCP keepalive and set timeout and interval. Zero timeout
* disables TCP keepalives. The parameters are applied immediately for
* a non disconnected object. Also, they are applied when the connection
* object connects successfully.
*
* @param conn a Strophe connection object
* @param timeout TCP keepalive timeout in seconds
* @param interval TCP keepalive interval in seconds
*
* @ingroup Connections
*/
void xmpp_conn_set_keepalive(xmpp_conn_t * const conn, int timeout, int interval)
{
int ret = 0;
conn->ka_timeout = timeout;
conn->ka_interval = interval;
if (conn->state != XMPP_STATE_DISCONNECTED)
ret = sock_set_keepalive(conn->sock, timeout, interval);
if (ret < 0) {
xmpp_error(conn->ctx, "xmpp", "Setting TCP keepalive (%d,%d) error: %d",
timeout, interval, sock_error());
}
}
/** Release a Strophe connection object. /** Release a Strophe connection object.
* Decrement the reference count by one for a connection, freeing the * Decrement the reference count by one for a connection, freeing the
* connection object if the count reaches 0. * connection object if the count reaches 0.
@@ -265,8 +216,6 @@ int xmpp_conn_release(xmpp_conn_t * const conn)
} }
} }
_conn_reset(conn);
/* free handler stuff /* free handler stuff
* note that userdata is the responsibility of the client * note that userdata is the responsibility of the client
* and the handler pointers don't need to be freed since they * and the handler pointers don't need to be freed since they
@@ -307,10 +256,20 @@ int xmpp_conn_release(xmpp_conn_t * const conn)
xmpp_free(ctx, thli); xmpp_free(ctx, thli);
} }
if (conn->stream_error) {
xmpp_stanza_release(conn->stream_error->stanza);
if (conn->stream_error->text)
xmpp_free(ctx, conn->stream_error->text);
xmpp_free(ctx, conn->stream_error);
}
parser_free(conn->parser); parser_free(conn->parser);
if (conn->domain) xmpp_free(ctx, conn->domain);
if (conn->jid) xmpp_free(ctx, conn->jid); if (conn->jid) xmpp_free(ctx, conn->jid);
if (conn->bound_jid) xmpp_free(ctx, conn->bound_jid);
if (conn->pass) xmpp_free(ctx, conn->pass); if (conn->pass) xmpp_free(ctx, conn->pass);
if (conn->stream_id) xmpp_free(ctx, conn->stream_id);
if (conn->lang) xmpp_free(ctx, conn->lang); if (conn->lang) xmpp_free(ctx, conn->lang);
xmpp_free(ctx, conn); xmpp_free(ctx, conn);
released = 1; released = 1;
@@ -353,7 +312,7 @@ const char *xmpp_conn_get_bound_jid(const xmpp_conn_t * const conn)
/** Set the JID of the user that will be bound to the connection. /** Set the JID of the user that will be bound to the connection.
* If any JID was previously set, it will be discarded. This should not be * If any JID was previously set, it will be discarded. This should not be
* be used after a connection is created. The function will make a copy of * be used after a connection is created. The function will make a copy of
* the JID string. If the supplied JID is missing the node, SASL * the JID string. If the supllied JID is missing the node, SASL
* ANONYMOUS authentication will be used. * ANONYMOUS authentication will be used.
* *
* @param conn a Strophe connection object * @param conn a Strophe connection object
@@ -409,7 +368,7 @@ xmpp_ctx_t* xmpp_conn_get_context(xmpp_conn_t * const conn)
/** Initiate a connection to the XMPP server. /** Initiate a connection to the XMPP server.
* This function returns immediately after starting the connection * This function returns immediately after starting the connection
* process to the XMPP server, and notifications of connection state changes * process to the XMPP server, and notifiations of connection state changes
* will be sent to the callback function. The domain and port to connect to * will be sent to the callback function. The domain and port to connect to
* are usually determined by an SRV lookup for the xmpp-client service at * are usually determined by an SRV lookup for the xmpp-client service at
* the domain specified in the JID. If SRV lookup fails, altdomain and * the domain specified in the JID. If SRV lookup fails, altdomain and
@@ -419,12 +378,12 @@ xmpp_ctx_t* xmpp_conn_get_context(xmpp_conn_t * const conn)
* @param altdomain a string with domain to use if SRV lookup fails. If this * @param altdomain a string with domain to use if SRV lookup fails. If this
* is NULL, the domain from the JID will be used. * is NULL, the domain from the JID will be used.
* @param altport an integer port number to use if SRV lookup fails. If this * @param altport an integer port number to use if SRV lookup fails. If this
* is 0, the default port will be assumed. * is 0, the default port (5222) will be assumed.
* @param callback a xmpp_conn_handler callback function that will receive * @param callback a xmpp_conn_handler callback function that will receive
* notifications of connection status * notifications of connection status
* @param userdata an opaque data pointer that will be passed to the callback * @param userdata an opaque data pointer that will be passed to the callback
* *
* @return XMPP_EOK (0) on success or a number less than 0 on failure * @return 0 on success and -1 on an error
* *
* @ingroup Connections * @ingroup Connections
*/ */
@@ -434,58 +393,55 @@ int xmpp_connect_client(xmpp_conn_t * const conn,
xmpp_conn_handler callback, xmpp_conn_handler callback,
void * const userdata) void * const userdata)
{ {
resolver_srv_rr_t *srv_rr_list = NULL; char connectdomain[2048];
resolver_srv_rr_t *rr; int connectport;
char *domain; const char * domain;
const char *host = NULL;
unsigned short port = 0;
int found = XMPP_DOMAIN_NOT_FOUND;
int rc;
domain = xmpp_jid_domain(conn->ctx, conn->jid); conn->type = XMPP_CLIENT;
if (!domain) return XMPP_EMEM;
if (altdomain != NULL) { conn->domain = xmpp_jid_domain(conn->ctx, conn->jid);
if (!conn->domain) return -1;
if (altdomain) {
xmpp_debug(conn->ctx, "xmpp", "Connecting via altdomain."); xmpp_debug(conn->ctx, "xmpp", "Connecting via altdomain.");
host = altdomain; strcpy(connectdomain, altdomain);
port = altport ? altport : _conn_default_port(conn, XMPP_CLIENT); connectport = altport ? altport : 5222;
found = XMPP_DOMAIN_ALTDOMAIN; } else if (!sock_srv_lookup("xmpp-client", "tcp", conn->domain,
connectdomain, 2048, &connectport)) {
/* SSL tunneled connection on 5223 port is legacy and doesn't xmpp_debug(conn->ctx, "xmpp", "SRV lookup failed.");
* have an SRV record. */ if (!altdomain)
} else if (!conn->tls_legacy_ssl) { domain = conn->domain;
found = resolver_srv_lookup(conn->ctx, "xmpp-client", "tcp", domain, else
&srv_rr_list); domain = altdomain;
xmpp_debug(conn->ctx, "xmpp", "Using alternate domain %s, port %d",
altdomain, altport);
strcpy(connectdomain, domain);
connectport = altport ? altport : 5222;
} }
conn->sock = sock_connect(connectdomain, connectport);
xmpp_debug(conn->ctx, "xmpp", "sock_connect to %s:%d returned %d",
connectdomain, connectport, conn->sock);
if (conn->sock == -1) return -1;
if (XMPP_DOMAIN_NOT_FOUND == found) { /* setup handler */
xmpp_debug(conn->ctx, "xmpp", "SRV lookup failed, " conn->conn_handler = callback;
"connecting via domain."); conn->userdata = userdata;
host = domain;
port = altport ? altport : _conn_default_port(conn, XMPP_CLIENT);
found = XMPP_DOMAIN_ALTDOMAIN;
}
rr = srv_rr_list; /* FIXME: it could happen that the connect returns immediately as
do { * successful, though this is pretty unlikely. This would be a little
if (XMPP_DOMAIN_FOUND == found && rr != NULL) { * hard to fix, since we'd have to detect and fire off the callback
host = rr->target; * from within the event loop */
port = rr->port;
rr = rr->next;
}
rc = _conn_connect(conn, domain, host, port, XMPP_CLIENT,
callback, userdata);
} while (rc != 0 && rr != NULL);
xmpp_free(conn->ctx, domain); conn->state = XMPP_STATE_CONNECTING;
resolver_srv_free(conn->ctx, srv_rr_list); conn->timeout_stamp = time_stamp();
xmpp_debug(conn->ctx, "xmpp", "attempting to connect to %s", connectdomain);
return rc; return 0;
} }
/** Initiate a component connection to server. /** Initiate a component connection to server.
* This function returns immediately after starting the connection * This function returns immediately after starting the connection
* process to the XMPP server, and notifications of connection state changes * process to the XMPP server, and notifiations of connection state changes
* will be sent to the internal callback function that will set up handler * will be sent to the internal callback function that will set up handler
* for the component handshake as defined in XEP-0114. * for the component handshake as defined in XEP-0114.
* The domain and port to connect to must be provided in this case as the JID * The domain and port to connect to must be provided in this case as the JID
@@ -502,7 +458,7 @@ int xmpp_connect_client(xmpp_conn_t * const conn,
* notifications of connection status * notifications of connection status
* @param userdata an opaque data pointer that will be passed to the callback * @param userdata an opaque data pointer that will be passed to the callback
* *
* @return XMPP_EOK (0) on success or a number less than 0 on failure * @return 0 on success and -1 on an error
* *
* @ingroup Connections * @ingroup Connections
*/ */
@@ -510,145 +466,44 @@ int xmpp_connect_component(xmpp_conn_t * const conn, const char * const server,
unsigned short port, xmpp_conn_handler callback, unsigned short port, xmpp_conn_handler callback,
void * const userdata) void * const userdata)
{ {
int connectport;
conn->type = XMPP_COMPONENT;
/* JID serves as an identificator here and will be used as "to" attribute
of the stream */
conn->domain = xmpp_strdup(conn->ctx, conn->jid);
/* The server domain, jid and password MUST be specified. */ /* The server domain, jid and password MUST be specified. */
if (!(server && conn->jid && conn->pass)) return XMPP_EINVOP; if (!(server && conn->jid && conn->pass)) return -1;
connectport = port ? port : 5347;
xmpp_debug(conn->ctx, "xmpp", "Connecting via %s", server);
conn->sock = sock_connect(server, connectport);
xmpp_debug(conn->ctx, "xmpp", "sock_connect to %s:%d returned %d",
server, connectport, conn->sock);
if (conn->sock == -1) return -1;
/* XEP-0114 does not support TLS */ /* XEP-0114 does not support TLS */
xmpp_conn_disable_tls(conn); conn->tls_disabled = 1;
if (!conn->tls_disabled) {
xmpp_error(conn->ctx, "conn", "Failed to disable TLS. "
"XEP-0114 does not support TLS");
return XMPP_EINT;
}
port = port ? port : _conn_default_port(conn, XMPP_COMPONENT); /* setup handler */
/* JID serves as an identifier here and will be used as "to" attribute conn->conn_handler = callback;
of the stream */ conn->userdata = userdata;
return _conn_connect(conn, conn->jid, server, port, XMPP_COMPONENT,
callback, userdata);
}
/** Initiate a raw connection to the XMPP server. conn_prepare_reset(conn, auth_handle_component_open);
* Arguments and behaviour of the function are similar to
* xmpp_connect_client(), but it skips authentication process. In opposite to
* xmpp_connect_client() during connection process two events are generated
* instead of one. User's callback is called with event XMPP_CONN_RAW_CONNECT
* when the TCP connection with the server is established. At this point user
* might want to open an XMPP stream with xmpp_conn_open_stream() or establish
* TLS session with xmpp_conn_tls_start(). Event XMPP_CONN_CONNECT is generated
* when the XMPP stream is opened successfully and user may send stanzas over
* the connection.
*
* This function doesn't use password nor node part of a jid. Therefore,
* the only required configuration is a domain (or full jid) passed via
* xmpp_conn_set_jid().
*
* @see xmpp_connect_client()
*
* @return XMPP_EOK (0) on success a number less than 0 on failure
*
* @ingroup Connections
*/
int xmpp_connect_raw(xmpp_conn_t * const conn,
const char * const altdomain,
unsigned short altport,
xmpp_conn_handler callback,
void * const userdata)
{
conn->is_raw = 1;
return xmpp_connect_client(conn, altdomain, altport, callback, userdata);
}
/* Called when tcp connection is established. */ /* FIXME: it could happen that the connect returns immediately as
void conn_established(xmpp_conn_t * const conn) * successful, though this is pretty unlikely. This would be a little
{ * hard to fix, since we'd have to detect and fire off the callback
if (conn->tls_legacy_ssl && !conn->is_raw) { * from within the event loop */
xmpp_debug(conn->ctx, "xmpp", "using legacy SSL connection");
if (conn_tls_start(conn) != 0) {
conn_disconnect(conn);
return;
}
}
if (conn->is_raw) { conn->state = XMPP_STATE_CONNECTING;
handler_reset_timed(conn, 0); conn->timeout_stamp = time_stamp();
/* we skip authentication for a "raw" connection, but the event loop xmpp_debug(conn->ctx, "xmpp", "attempting to connect to %s", server);
ignores user's handlers when conn->authenticated is not set. */
conn->authenticated = 1;
conn->conn_handler(conn, XMPP_CONN_RAW_CONNECT, 0, NULL, conn->userdata);
} else {
/* send stream init */
conn_open_stream(conn);
}
}
/** Send the default opening stream tag. return 0;
* The default tag is the one sent by xmpp_connect_client().
* User's connection handler is called with event XMPP_CONN_CONNECT when
* server replies with its opening tag.
*
* @return XMPP_EOK (0) on success a number less than 0 on failure
*
* @note The connection must be connected with xmpp_connect_raw().
*
* @ingroup Connections
*/
int xmpp_conn_open_stream_default(xmpp_conn_t * const conn)
{
if (!conn->is_raw)
return XMPP_EINVOP;
conn_prepare_reset(conn, auth_handle_open_raw);
conn_open_stream(conn);
return XMPP_EOK;
}
/** Send an opening stream tag.
* User's connection handler is called with event XMPP_CONN_CONNECT when
* server replies with its opening tag.
*
* @param conn a Strophe connection object
* @param attributes Array of strings in format: even index points to
* an attribute name and odd index points to its value
* @param attributes_len Number of elements in the attributes array, it
* should be number of attributes multiplied by 2
*
* @return XMPP_EOK (0) on success a number less than 0 on failure
*
* @note The connection must be connected with xmpp_connect_raw().
*
* @ingroup Connections
*/
int xmpp_conn_open_stream(xmpp_conn_t * const conn, char **attributes,
size_t attributes_len)
{
char *tag;
if (!conn->is_raw && conn->type != XMPP_INCOMING)
return XMPP_EINVOP;
tag = _conn_build_stream_tag(conn, attributes, attributes_len);
if (!tag)
return XMPP_EMEM;
if (conn->type != XMPP_INCOMING)
conn_prepare_reset(conn, auth_handle_open_raw);
xmpp_send_raw_string(conn, "<?xml version=\"1.0\"?>%s", tag);
xmpp_free(conn->ctx, tag);
return XMPP_EOK;
}
/** Start synchronous TLS handshake with the server.
*
* @return XMPP_EOK (0) on success a number less than 0 on failure
*
* @ingroup Connections
*/
int xmpp_conn_tls_start(xmpp_conn_t * const conn)
{
return conn_tls_start(conn);
} }
/** Cleanly disconnect the connection. /** Cleanly disconnect the connection.
@@ -702,6 +557,18 @@ void conn_parser_reset(xmpp_conn_t * const conn)
parser_reset(conn->parser); parser_reset(conn->parser);
} }
/* timed handler for cleanup if normal disconnect procedure takes too long */
static int _disconnect_cleanup(xmpp_conn_t * const conn,
void * const userdata)
{
xmpp_debug(conn->ctx, "xmpp",
"disconnection forced by cleanup timeout");
conn_disconnect(conn);
return 0;
}
/** Initiate termination of the connection to the XMPP server. /** Initiate termination of the connection to the XMPP server.
* This function starts the disconnection sequence by sending * This function starts the disconnection sequence by sending
* </stream:stream> to the XMPP server. This function will do nothing * </stream:stream> to the XMPP server. This function will do nothing
@@ -735,8 +602,6 @@ void xmpp_disconnect(xmpp_conn_t * const conn)
* @param conn a Strophe connection object * @param conn a Strophe connection object
* @param fmt a printf-style format string followed by a variable list of * @param fmt a printf-style format string followed by a variable list of
* arguments to format * arguments to format
*
* @ingroup Connections
*/ */
void xmpp_send_raw_string(xmpp_conn_t * const conn, void xmpp_send_raw_string(xmpp_conn_t * const conn,
const char * const fmt, ...) const char * const fmt, ...)
@@ -778,15 +643,13 @@ void xmpp_send_raw_string(xmpp_conn_t * const conn,
/** Send raw bytes to the XMPP server. /** Send raw bytes to the XMPP server.
* This function is a convenience function to send raw bytes to the * This function is a convenience function to send raw bytes to the
* XMPP server. It is used primarily by xmpp_send_raw_string(). This * XMPP server. It is usedly primarly by xmpp_send_raw_string. This
* function should be used with care as it does not validate the bytes and * function should be used with care as it does not validate the bytes and
* invalid data may result in stream termination by the XMPP server. * invalid data may result in stream termination by the XMPP server.
* *
* @param conn a Strophe connection object * @param conn a Strophe connection object
* @param data a buffer of raw bytes * @param data a buffer of raw bytes
* @param len the length of the data in the buffer * @param len the length of the data in the buffer
*
* @ingroup Connections
*/ */
void xmpp_send_raw(xmpp_conn_t * const conn, void xmpp_send_raw(xmpp_conn_t * const conn,
const char * const data, const size_t len) const char * const data, const size_t len)
@@ -864,239 +727,49 @@ void conn_open_stream(xmpp_conn_t * const conn)
"xmlns:stream=\"%s\">", "xmlns:stream=\"%s\">",
conn->domain, conn->domain,
conn->lang, conn->lang,
conn->type == XMPP_CLIENT ? XMPP_NS_CLIENT : conn->type == XMPP_CLIENT ? XMPP_NS_CLIENT : XMPP_NS_COMPONENT,
XMPP_NS_COMPONENT,
XMPP_NS_STREAMS); XMPP_NS_STREAMS);
} }
int conn_tls_start(xmpp_conn_t * const conn)
{
int rc;
if (conn->tls_disabled) {
conn->tls = NULL;
rc = XMPP_EINVOP;
} else {
conn->tls = tls_new(conn);
rc = conn->tls == NULL ? XMPP_EMEM : 0;
}
if (conn->tls != NULL) {
if (tls_start(conn->tls)) {
conn->secured = 1;
} else {
rc = XMPP_EINT;
conn->error = tls_error(conn->tls);
tls_free(conn->tls);
conn->tls = NULL;
conn->tls_failed = 1;
}
}
if (rc != 0) {
xmpp_debug(conn->ctx, "conn", "Couldn't start TLS! "
"error %d tls_error %d", rc, conn->error);
}
return rc;
}
/** Return applied flags for the connection.
*
* @param conn a Strophe connection object
*
* @return ORed connection flags that are applied for the connection.
*
* @ingroup Connections
*/
long xmpp_conn_get_flags(const xmpp_conn_t * const conn)
{
long flags;
flags = XMPP_CONN_FLAG_DISABLE_TLS * conn->tls_disabled |
XMPP_CONN_FLAG_MANDATORY_TLS * conn->tls_mandatory |
XMPP_CONN_FLAG_LEGACY_SSL * conn->tls_legacy_ssl |
XMPP_CONN_FLAG_TRUST_TLS * conn->tls_trust;
return flags;
}
/** Set flags for the connection.
* This function applies set flags and resets unset ones. Default connection
* configuration is all flags unset. Flags can be applied only for a connection
* in disconnected state.
* All unsupported flags are ignored. If a flag is unset after successful set
* operation then the flag is not supported by current version.
*
* Supported flags are:
*
* - XMPP_CONN_FLAG_DISABLE_TLS
* - XMPP_CONN_FLAG_MANDATORY_TLS
* - XMPP_CONN_FLAG_LEGACY_SSL
* - XMPP_CONN_FLAG_TRUST_TLS
*
* @param conn a Strophe connection object
* @param flags ORed connection flags
*
* @return XMPP_EOK (0) on success or a number less than 0 on failure
*
* @ingroup Connections
*/
int xmpp_conn_set_flags(xmpp_conn_t * const conn, long flags)
{
if (conn->state != XMPP_STATE_DISCONNECTED) {
xmpp_error(conn->ctx, "conn", "Flags can be set only "
"for disconnected connection");
return XMPP_EINVOP;
}
if (flags & XMPP_CONN_FLAG_DISABLE_TLS &&
flags & (XMPP_CONN_FLAG_MANDATORY_TLS | XMPP_CONN_FLAG_LEGACY_SSL |
XMPP_CONN_FLAG_TRUST_TLS)) {
xmpp_error(conn->ctx, "conn", "Flags 0x%04lx conflict", flags);
return XMPP_EINVOP;
}
conn->tls_disabled = (flags & XMPP_CONN_FLAG_DISABLE_TLS) ? 1 : 0;
conn->tls_mandatory = (flags & XMPP_CONN_FLAG_MANDATORY_TLS) ? 1 : 0;
conn->tls_legacy_ssl = (flags & XMPP_CONN_FLAG_LEGACY_SSL) ? 1 : 0;
conn->tls_trust = (flags & XMPP_CONN_FLAG_TRUST_TLS) ? 1 : 0;
return 0;
}
/** Disable TLS for this connection, called by users of the library. /** Disable TLS for this connection, called by users of the library.
* Occasionally a server will be misconfigured to send the starttls * Occasionally a server will be misconfigured to send the starttls
* feature, but will not support the handshake. * feature, but wil not support the handshake.
* *
* @param conn a Strophe connection object * @param conn a Strophe connection object
*
* @note this function is deprecated
* @see xmpp_conn_set_flags()
*
* @ingroup Connections
*/ */
void xmpp_conn_disable_tls(xmpp_conn_t * const conn) void xmpp_conn_disable_tls(xmpp_conn_t * const conn)
{ {
long flags = xmpp_conn_get_flags(conn); conn->tls_disabled = 1;
flags |= XMPP_CONN_FLAG_DISABLE_TLS;
(void)xmpp_conn_set_flags(conn, flags);
}
/** Return whether TLS session is established or not.
*
* @return TRUE if TLS session is established and FALSE otherwise
*
* @ingroup Connections
*/
int xmpp_conn_is_secured(xmpp_conn_t * const conn)
{
return conn->secured && !conn->tls_failed && conn->tls != NULL ? 1 : 0;
}
/* timed handler for cleanup if normal disconnect procedure takes too long */
static int _disconnect_cleanup(xmpp_conn_t * const conn,
void * const userdata)
{
xmpp_debug(conn->ctx, "xmpp",
"disconnection forced by cleanup timeout");
conn_disconnect(conn);
return 0;
}
static char *_conn_build_stream_tag(xmpp_conn_t * const conn,
char **attributes, size_t attributes_len)
{
char *tag;
size_t len;
size_t i;
static const char *tag_head = "<stream:stream";
static const char *tag_tail = ">";
/* ignore the last element unless number is even */
attributes_len &= ~(size_t)1;
len = strlen(tag_head) + strlen(tag_tail);
for (i = 0; i < attributes_len; ++i)
len += strlen(attributes[i]) + 2;
tag = xmpp_alloc(conn->ctx, len + 1);
if (!tag) return NULL;
strcpy(tag, tag_head);
for (i = 0; i < attributes_len; ++i) {
if ((i & 1) == 0) {
strcat(tag, " ");
strcat(tag, attributes[i]);
strcat(tag, "=\"");
} else {
strcat(tag, attributes[i]);
strcat(tag, "\"");
}
}
strcat(tag, tag_tail);
if (strlen(tag) != len) {
xmpp_error(conn->ctx, "xmpp", "Internal error in "
"_conn_build_stream_tag().");
xmpp_free(conn->ctx, tag);
tag = NULL;
}
return tag;
}
static void _conn_attributes_new(xmpp_conn_t *conn, char **attrs,
char ***attributes, size_t *attributes_len)
{
char **array = NULL;
size_t nr = 0;
size_t i;
if (attrs) {
for (; attrs[nr]; ++nr);
array = xmpp_alloc(conn->ctx, sizeof(*array) * nr);
for (i = 0; array && i < nr; ++i) {
array[i] = (i & 1) == 0 ? parser_attr_name(conn->ctx, attrs[i])
: xmpp_strdup(conn->ctx, attrs[i]);
if (array[i] == NULL) break;
}
if (!array || i < nr) {
xmpp_error(conn->ctx, "xmpp", "Memory allocation error.");
_conn_attributes_destroy(conn, array, i);
array = NULL;
nr = 0;
}
}
*attributes = array;
*attributes_len = nr;
}
static void _conn_attributes_destroy(xmpp_conn_t *conn, char **attributes,
size_t attributes_len)
{
size_t i;
if (attributes) {
for (i = 0; i < attributes_len; ++i)
xmpp_free(conn->ctx, attributes[i]);
xmpp_free(conn->ctx, attributes);
}
} }
static void _log_open_tag(xmpp_conn_t *conn, char **attrs) static void _log_open_tag(xmpp_conn_t *conn, char **attrs)
{ {
char **attributes; char buf[4096];
char *tag; size_t pos;
size_t nr; int len;
int i;
char *attr;
_conn_attributes_new(conn, attrs, &attributes, &nr); if (!attrs) return;
tag = _conn_build_stream_tag(conn, attributes, nr);
if (tag) { pos = 0;
xmpp_debug(conn->ctx, "xmpp", "RECV: %s", tag); len = xmpp_snprintf(buf, 4096, "<stream:stream");
xmpp_free(conn->ctx, tag); if (len < 0) return;
pos += len;
for (i = 0; attrs[i]; i += 2) {
attr = parser_attr_name(conn->ctx, attrs[i]);
len = xmpp_snprintf(&buf[pos], 4096 - pos, " %s='%s'",
attr, attrs[i+1]);
xmpp_free(conn->ctx, attr);
if (len < 0) return;
pos += len;
} }
_conn_attributes_destroy(conn, attributes, nr);
len = xmpp_snprintf(&buf[pos], 4096 - pos, ">");
if (len < 0) return;
xmpp_debug(conn->ctx, "xmpp", "RECV: %s", buf);
} }
static char *_get_stream_attribute(char **attrs, char *name) static char *_get_stream_attribute(char **attrs, char *name)
@@ -1117,35 +790,30 @@ static void _handle_stream_start(char *name, char **attrs,
{ {
xmpp_conn_t *conn = (xmpp_conn_t *)userdata; xmpp_conn_t *conn = (xmpp_conn_t *)userdata;
char *id; char *id;
int failed = 0;
if (strcmp(name, "stream")) {
printf("name = %s\n", name);
xmpp_error(conn->ctx, "conn", "Server did not open valid stream.");
conn_disconnect(conn);
} else {
_log_open_tag(conn, attrs);
if (conn->stream_id) xmpp_free(conn->ctx, conn->stream_id); if (conn->stream_id) xmpp_free(conn->ctx, conn->stream_id);
conn->stream_id = NULL;
if (strcmp(name, "stream") == 0) {
_log_open_tag(conn, attrs);
id = _get_stream_attribute(attrs, "id"); id = _get_stream_attribute(attrs, "id");
if (id) if (id)
conn->stream_id = xmpp_strdup(conn->ctx, id); conn->stream_id = xmpp_strdup(conn->ctx, id);
if (id && !conn->stream_id) { if (!conn->stream_id) {
xmpp_error(conn->ctx, "conn", "Memory allocation failed."); xmpp_error(conn->ctx, "conn", "Memory allocation failed.");
failed = 1;
}
} else {
xmpp_error(conn->ctx, "conn", "Server did not open valid stream."
" name = %s.", name);
failed = 1;
}
if (!failed) {
/* call stream open handler */
conn->open_handler(conn);
} else {
conn_disconnect(conn); conn_disconnect(conn);
} }
} }
/* call stream open handler */
conn->open_handler(conn);
}
static void _handle_stream_end(char *name, static void _handle_stream_end(char *name,
void * const userdata) void * const userdata)
{ {
@@ -1170,110 +838,3 @@ static void _handle_stream_stanza(xmpp_stanza_t *stanza,
handler_fire_stanza(conn, stanza); handler_fire_stanza(conn, stanza);
} }
static unsigned short _conn_default_port(xmpp_conn_t * const conn,
xmpp_conn_type_t type)
{
switch (type) {
case XMPP_CLIENT:
return conn->tls_legacy_ssl ? XMPP_PORT_CLIENT_LEGACY_SSL :
XMPP_PORT_CLIENT;
case XMPP_COMPONENT:
return XMPP_PORT_COMPONENT;
default:
return 0;
};
}
static void _conn_reset(xmpp_conn_t * const conn)
{
xmpp_ctx_t *ctx = conn->ctx;
xmpp_send_queue_t *sq, *tsq;
if (conn->state != XMPP_STATE_DISCONNECTED) {
xmpp_debug(ctx, "conn", "Can't reset connected object.");
return;
}
/* free queued */
sq = conn->send_queue_head;
while (sq) {
tsq = sq;
sq = sq->next;
xmpp_free(ctx, tsq->data);
xmpp_free(ctx, tsq);
}
if (conn->stream_error) {
xmpp_stanza_release(conn->stream_error->stanza);
if (conn->stream_error->text)
xmpp_free(ctx, conn->stream_error->text);
xmpp_free(ctx, conn->stream_error);
conn->stream_error = NULL;
}
if (conn->domain) xmpp_free(ctx, conn->domain);
if (conn->bound_jid) xmpp_free(ctx, conn->bound_jid);
if (conn->stream_id) xmpp_free(ctx, conn->stream_id);
conn->domain = NULL;
conn->bound_jid = NULL;
conn->stream_id = NULL;
conn->authenticated = 0;
conn->secured = 0;
conn->tls_failed = 0;
conn->error = 0;
conn->tls_support = 0;
conn->bind_required = 0;
conn->session_required = 0;
handler_system_delete_all(conn);
}
static int _conn_connect(xmpp_conn_t * const conn,
const char * const domain,
const char * const host,
unsigned short port,
xmpp_conn_type_t type,
xmpp_conn_handler callback,
void * const userdata)
{
xmpp_open_handler open_handler;
if (conn->state != XMPP_STATE_DISCONNECTED) return XMPP_EINVOP;
if (type != XMPP_CLIENT && type != XMPP_COMPONENT) return XMPP_EINVOP;
if (host == NULL || port == 0) return XMPP_EINT;
_conn_reset(conn);
conn->type = type;
conn->domain = xmpp_strdup(conn->ctx, domain);
if (!conn->domain) return XMPP_EMEM;
conn->sock = sock_connect(host, port);
xmpp_debug(conn->ctx, "xmpp", "sock_connect() to %s:%u returned %d",
host, port, conn->sock);
if (conn->sock == -1) return XMPP_EINT;
if (conn->ka_timeout || conn->ka_interval)
sock_set_keepalive(conn->sock, conn->ka_timeout, conn->ka_interval);
/* setup handler */
conn->conn_handler = callback;
conn->userdata = userdata;
open_handler = conn->is_raw ? auth_handle_open_stub :
type == XMPP_CLIENT ? auth_handle_open :
auth_handle_component_open;
conn_prepare_reset(conn, open_handler);
/* FIXME: it could happen that the connect returns immediately as
* successful, though this is pretty unlikely. This would be a little
* hard to fix, since we'd have to detect and fire off the callback
* from within the event loop */
conn->state = XMPP_STATE_CONNECTING;
conn->timeout_stamp = time_stamp();
xmpp_debug(conn->ctx, "xmpp", "Attempting to connect to %s", host);
return 0;
}

View File

@@ -1,491 +0,0 @@
/* 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);
}

View File

@@ -49,11 +49,6 @@
#include "common.h" #include "common.h"
#include "util.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. /** Initialize the Strophe library.
* This function initializes subcomponents of the Strophe library and must * This function initializes subcomponents of the Strophe library and must
* be called for Strophe to operate correctly. * be called for Strophe to operate correctly.
@@ -91,14 +86,6 @@ void xmpp_shutdown(void)
#define LIBXMPP_VERSION_MINOR (0) #define LIBXMPP_VERSION_MINOR (0)
#endif #endif
#ifndef EVENT_LOOP_DEFAULT_TIMEOUT
/** @def EVENT_LOOP_DEFAULT_TIMEOUT
* The default timeout in milliseconds for the event loop.
* This is set to 1 second.
*/
#define EVENT_LOOP_DEFAULT_TIMEOUT 1000
#endif
/** Check that Strophe supports a specific API version. /** Check that Strophe supports a specific API version.
* *
* @param major the major version number * @param major the major version number
@@ -158,7 +145,7 @@ static const xmpp_log_level_t _xmpp_default_logger_levels[] = {XMPP_LEVEL_DEBUG,
* @param area the area the log message is for * @param area the area the log message is for
* @param msg the log message * @param msg the log message
*/ */
static void xmpp_default_logger(void * const userdata, void xmpp_default_logger(void * const userdata,
const xmpp_log_level_t level, const xmpp_log_level_t level,
const char * const area, const char * const area,
const char * const msg) const char * const msg)
@@ -190,6 +177,7 @@ xmpp_log_t *xmpp_get_default_logger(xmpp_log_level_t level)
{ {
/* clamp to the known range */ /* clamp to the known range */
if (level > XMPP_LEVEL_ERROR) level = XMPP_LEVEL_ERROR; if (level > XMPP_LEVEL_ERROR) level = XMPP_LEVEL_ERROR;
if (level < XMPP_LEVEL_DEBUG) level = XMPP_LEVEL_DEBUG;
return (xmpp_log_t*)&_xmpp_default_loggers[level]; return (xmpp_log_t*)&_xmpp_default_loggers[level];
} }
@@ -415,14 +403,7 @@ xmpp_ctx_t *xmpp_ctx_new(const xmpp_mem_t * const mem,
ctx->log = log; ctx->log = log;
ctx->connlist = NULL; ctx->connlist = NULL;
ctx->serverlist = NULL;
ctx->loop_status = XMPP_LOOP_NOTSTARTED; 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; return ctx;
@@ -437,18 +418,6 @@ xmpp_ctx_t *xmpp_ctx_new(const xmpp_mem_t * const mem,
void xmpp_ctx_free(xmpp_ctx_t * const ctx) void xmpp_ctx_free(xmpp_ctx_t * const ctx)
{ {
/* mem and log are owned by their suppliers */ /* mem and log are owned by their suppliers */
xmpp_rand_free(ctx, ctx->rand);
xmpp_free(ctx, ctx); /* pull the hole in after us */ xmpp_free(ctx, ctx); /* pull the hole in after us */
} }
/** Set the timeout to use when calling xmpp_run().
*
* @param ctx a Strophe context object
* @param timeout the time to wait for events in milliseconds
*
* @ingroup Context
*/
void xmpp_ctx_set_timeout(xmpp_ctx_t * const ctx, const unsigned long timeout)
{
ctx->timeout = timeout;
}

View File

@@ -38,7 +38,7 @@
#include <sys/select.h> #include <sys/select.h>
#include <errno.h> #include <errno.h>
#include <unistd.h> #include <unistd.h>
#define _sleep(x) usleep((x) * 1000) #define _sleep(x) usleep(x*1000)
#else #else
#include <winsock2.h> #include <winsock2.h>
#define ETIMEDOUT WSAETIMEDOUT #define ETIMEDOUT WSAETIMEDOUT
@@ -51,6 +51,14 @@
#include "common.h" #include "common.h"
#include "parser.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. /** Run the event loop once.
* This function will run send any data that has been queued by * This function will run send any data that has been queued by
* xmpp_send and related functions and run through the Strophe even * xmpp_send and related functions and run through the Strophe even
@@ -67,9 +75,7 @@
void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout) void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
{ {
xmpp_connlist_t *connitem; xmpp_connlist_t *connitem;
xmpp_serverlist_t *serveritem;
xmpp_conn_t *conn; xmpp_conn_t *conn;
xmpp_server_t *srv;
fd_set rfds, wfds; fd_set rfds, wfds;
sock_t max = 0; sock_t max = 0;
int ret; int ret;
@@ -78,10 +84,11 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
int towrite; int towrite;
char buf[4096]; char buf[4096];
uint64_t next; uint64_t next;
uint64_t usec; long usec;
int tls_read_bytes = 0; int tls_read_bytes = 0;
if (ctx->loop_status == XMPP_LOOP_QUIT) return; if (ctx->loop_status == XMPP_LOOP_QUIT) return;
ctx->loop_status = XMPP_LOOP_RUNNING;
/* send queued data */ /* send queued data */
connitem = ctx->connlist; connitem = ctx->connlist;
@@ -98,8 +105,8 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
ret = tls_clear_pending_write(conn->tls); ret = tls_clear_pending_write(conn->tls);
if (ret < 0 && !tls_is_recoverable(tls_error(conn->tls))) { if (ret < 0 && !tls_is_recoverable(tls_error(conn->tls))) {
/* an error occurred */ /* an error occured */
xmpp_debug(ctx, "xmpp", "Send error occurred, disconnecting."); xmpp_debug(ctx, "xmpp", "Send error occured, disconnecting.");
conn->error = ECONNABORTED; conn->error = ECONNABORTED;
conn_disconnect(conn); conn_disconnect(conn);
} }
@@ -112,23 +119,35 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
if (conn->tls) { if (conn->tls) {
ret = tls_write(conn->tls, &sq->data[sq->written], towrite); ret = tls_write(conn->tls, &sq->data[sq->written], towrite);
if (ret < 0 && !tls_is_recoverable(tls_error(conn->tls)))
if (ret < 0 && !tls_is_recoverable(tls_error(conn->tls))) {
/* an error occured */
conn->error = tls_error(conn->tls); conn->error = tls_error(conn->tls);
break;
} else if (ret < towrite) {
/* not all data could be sent now */
if (ret >= 0) sq->written += ret;
break;
}
} else { } else {
ret = sock_write(conn->sock, &sq->data[sq->written], towrite); ret = sock_write(conn->sock, &sq->data[sq->written], towrite);
if (ret < 0 && !sock_is_recoverable(sock_error()))
if (ret < 0 && !sock_is_recoverable(sock_error())) {
/* an error occured */
conn->error = sock_error(); conn->error = sock_error();
break;
} else if (ret < towrite) {
/* not all data could be sent now */
if (ret >= 0) sq->written += ret;
break;
}
} }
if (ret > 0 && ret < towrite)
sq->written += ret; /* not all data could be sent now */
if (ret != towrite)
break; /* partial write or an error */
/* all data for this queue item written, delete and move on */ /* all data for this queue item written, delete and move on */
xmpp_free(ctx, sq->data); xmpp_free(ctx, sq->data);
tsq = sq; tsq = sq;
sq = sq->next; sq = sq->next;
conn->send_queue_len--;
xmpp_free(ctx, tsq); xmpp_free(ctx, tsq);
/* pop the top item */ /* pop the top item */
@@ -141,7 +160,7 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
if (conn->error) { if (conn->error) {
/* FIXME: need to tear down send queues and random other things /* FIXME: need to tear down send queues and random other things
* maybe this should be abstracted */ * maybe this should be abstracted */
xmpp_debug(ctx, "xmpp", "Send error occurred, disconnecting."); xmpp_debug(ctx, "xmpp", "Send error occured, disconnecting.");
conn->error = ECONNABORTED; conn->error = ECONNABORTED;
conn_disconnect(conn); conn_disconnect(conn);
} }
@@ -156,13 +175,14 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
} }
/* fire any ready timed handlers, then make sure we don't wait past /* fire any ready timed handlers, then
the time when timed handlers need to be called */ make sure we don't wait past the time when timed handlers need
to be called */
next = handler_fire_timed(ctx); next = handler_fire_timed(ctx);
usec = ((next < timeout) ? next : timeout) * 1000; usec = ((next < timeout) ? next : timeout) * 1000;
tv.tv_sec = (long)(usec / 1000000); tv.tv_sec = usec / 1000000;
tv.tv_usec = (long)(usec % 1000000); tv.tv_usec = usec % 1000000;
FD_ZERO(&rfds); FD_ZERO(&rfds);
FD_ZERO(&wfds); FD_ZERO(&wfds);
@@ -189,8 +209,6 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
break; break;
case XMPP_STATE_CONNECTED: case XMPP_STATE_CONNECTED:
FD_SET(conn->sock, &rfds); FD_SET(conn->sock, &rfds);
if (conn->send_queue_len > 0)
FD_SET(conn->sock, &wfds);
break; break;
case XMPP_STATE_DISCONNECTED: case XMPP_STATE_DISCONNECTED:
/* do nothing */ /* do nothing */
@@ -199,8 +217,9 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
} }
/* Check if there is something in the SSL buffer. */ /* Check if there is something in the SSL buffer. */
if (conn->tls) if (conn->tls) {
tls_read_bytes += tls_pending(conn->tls); tls_read_bytes += tls_pending(conn->tls);
}
if (conn->state != XMPP_STATE_DISCONNECTED && conn->sock > max) if (conn->state != XMPP_STATE_DISCONNECTED && conn->sock > max)
max = conn->sock; max = conn->sock;
@@ -208,23 +227,6 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
connitem = connitem->next; connitem = connitem->next;
} }
serveritem = ctx->serverlist;
while (serveritem) {
srv = serveritem->server;
switch (srv->state) {
case XMPP_STATE_LISTENING:
FD_SET(srv->sock, &rfds);
if (srv->sock > max) max = srv->sock;
break;
case XMPP_STATE_STOPPED:
/* do nothing */
default:
break;
}
serveritem = serveritem->next;
}
/* check for events */ /* check for events */
if (max > 0) if (max > 0)
ret = select(max + 1, &rfds, &wfds, NULL, &tv); ret = select(max + 1, &rfds, &wfds, NULL, &tv);
@@ -256,17 +258,19 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
/* connection complete */ /* connection complete */
/* check for error */ /* check for error */
ret = sock_connect_error(conn->sock); if (sock_connect_error(conn->sock) != 0) {
if (ret != 0) {
/* connection failed */ /* connection failed */
xmpp_debug(ctx, "xmpp", "connection failed, error %d", ret); xmpp_debug(ctx, "xmpp", "connection failed");
conn_disconnect(conn); conn_disconnect(conn);
break; break;
} }
conn->state = XMPP_STATE_CONNECTED; conn->state = XMPP_STATE_CONNECTED;
xmpp_debug(ctx, "xmpp", "connection successful"); xmpp_debug(ctx, "xmpp", "connection successful");
conn_established(conn);
/* send stream init */
conn_open_stream(conn);
} }
break; break;
@@ -288,7 +292,8 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
} }
} else { } else {
if (conn->tls) { if (conn->tls) {
if (!tls_is_recoverable(tls_error(conn->tls))) { if (!tls_is_recoverable(tls_error(conn->tls)))
{
xmpp_debug(ctx, "xmpp", "Unrecoverable TLS error, %d.", tls_error(conn->tls)); xmpp_debug(ctx, "xmpp", "Unrecoverable TLS error, %d.", tls_error(conn->tls));
conn->error = tls_error(conn->tls); conn->error = tls_error(conn->tls);
conn_disconnect(conn); conn_disconnect(conn);
@@ -312,24 +317,6 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
connitem = connitem->next; connitem = connitem->next;
} }
serveritem = ctx->serverlist;
while (serveritem) {
srv = serveritem->server;
switch (srv->state) {
case XMPP_STATE_LISTENING:
if (FD_ISSET(srv->sock, &rfds)) {
server_accept(srv);
}
break;
case XMPP_STATE_STOPPED:
/* do nothing */
default:
break;
}
serveritem = serveritem->next;
}
/* fire any ready handlers */ /* fire any ready handlers */
handler_fire_timed(ctx); handler_fire_timed(ctx);
} }
@@ -348,12 +335,9 @@ void xmpp_run(xmpp_ctx_t *ctx)
ctx->loop_status = XMPP_LOOP_RUNNING; ctx->loop_status = XMPP_LOOP_RUNNING;
while (ctx->loop_status == XMPP_LOOP_RUNNING) { while (ctx->loop_status == XMPP_LOOP_RUNNING) {
xmpp_run_once(ctx, ctx->timeout); xmpp_run_once(ctx, DEFAULT_TIMEOUT);
} }
/* make it possible to start event loop again */
ctx->loop_status = XMPP_LOOP_NOTSTARTED;
xmpp_debug(ctx, "event", "Event loop completed."); xmpp_debug(ctx, "event", "Event loop completed.");
} }

View File

@@ -24,31 +24,6 @@
#include "common.h" #include "common.h"
#include "ostypes.h" #include "ostypes.h"
/* Remove item from the list pointed by head, but don't free it.
* There can be a situation when user's handler deletes another handler which
* is the previous in the list. handler_fire_stanza() and handler_fire_timed()
* must handle this situation correctly. Current function helps to avoid
* list corruption in described scenario.
*
* TODO Convert handler lists to double-linked lists. Current implementation
* works for O(n).
*/
static void _handler_item_remove(xmpp_handlist_t **head,
xmpp_handlist_t *item)
{
xmpp_handlist_t *i = *head;
if (i == item)
*head = item->next;
else if (i != NULL) {
while (i->next != NULL && i->next != item)
i = i->next;
if (i->next == item) {
i->next = item->next;
}
}
}
/** Fire off all stanza handlers that match. /** Fire off all stanza handlers that match.
* This function is called internally by the event loop whenever stanzas * This function is called internally by the event loop whenever stanzas
* are received from the XMPP server. * are received from the XMPP server.
@@ -59,40 +34,36 @@ static void _handler_item_remove(xmpp_handlist_t **head,
void handler_fire_stanza(xmpp_conn_t * const conn, void handler_fire_stanza(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza) xmpp_stanza_t * const stanza)
{ {
xmpp_handlist_t *item, *next, *head, *head_old; xmpp_handlist_t *item, *prev;
const char *id, *ns, *name, *type; char *id, *ns, *name, *type;
int ret;
/* call id handlers */ /* call id handlers */
id = xmpp_stanza_get_id(stanza); id = xmpp_stanza_get_id(stanza);
if (id) { if (id) {
head = (xmpp_handlist_t *)hash_get(conn->id_handlers, id); prev = NULL;
/* enable all added handlers */ item = (xmpp_handlist_t *)hash_get(conn->id_handlers, id);
for (item = head; item; item = item->next)
item->enabled = 1;
item = head;
while (item) { while (item) {
/* don't fire user handlers until authentication succeeds and xmpp_handlist_t *next = item->next;
and skip newly added handlers */
if ((item->user_handler && !conn->authenticated) || !item->enabled) { if (item->user_handler && !conn->authenticated) {
item = item->next; item = next;
continue; continue;
} }
ret = ((xmpp_handler)(item->handler))(conn, stanza, item->userdata); if (!((xmpp_handler)(item->handler))(conn, stanza, item->userdata)) {
next = item->next;
if (!ret) {
/* handler is one-shot, so delete it */ /* handler is one-shot, so delete it */
head_old = head; if (prev)
_handler_item_remove(&head, item); prev->next = next;
if (head != head_old) { else {
/* replace old value */ hash_drop(conn->id_handlers, id);
hash_add(conn->id_handlers, id, head); hash_add(conn->id_handlers, id, next);
} }
xmpp_free(conn->ctx, item->id); xmpp_free(conn->ctx, item->id);
xmpp_free(conn->ctx, item); xmpp_free(conn->ctx, item);
item = NULL;
} }
if (item)
prev = item;
item = next; item = next;
} }
} }
@@ -106,34 +77,47 @@ void handler_fire_stanza(xmpp_conn_t * const conn,
for (item = conn->handlers; item; item = item->next) for (item = conn->handlers; item; item = item->next)
item->enabled = 1; item->enabled = 1;
prev = NULL;
item = conn->handlers; item = conn->handlers;
while (item) { while (item) {
/* don't fire user handlers until authentication succeeds and /* skip newly added handlers */
skip newly added handlers */ if (!item->enabled) {
if ((item->user_handler && !conn->authenticated) || !item->enabled) { prev = item;
item = item->next;
continue;
}
/* don't call user handlers until authentication succeeds */
if (item->user_handler && !conn->authenticated) {
prev = item;
item = item->next; item = item->next;
continue; continue;
} }
next = item->next;
if ((!item->ns || (ns && strcmp(ns, item->ns) == 0) || if ((!item->ns || (ns && strcmp(ns, item->ns) == 0) ||
xmpp_stanza_get_child_by_ns(stanza, item->ns)) && xmpp_stanza_get_child_by_ns(stanza, item->ns)) &&
(!item->name || (name && strcmp(name, item->name) == 0)) && (!item->name || (name && strcmp(name, item->name) == 0)) &&
(!item->type || (type && strcmp(type, item->type) == 0))) { (!item->type || (type && strcmp(type, item->type) == 0)))
if (!((xmpp_handler)(item->handler))(conn, stanza, item->userdata)) {
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 is one-shot, so delete it */
_handler_item_remove(&conn->handlers, item); if (prev)
prev->next = item->next;
else
conn->handlers = item->next;
if (item->ns) xmpp_free(conn->ctx, item->ns); if (item->ns) xmpp_free(conn->ctx, item->ns);
if (item->name) xmpp_free(conn->ctx, item->name); if (item->name) xmpp_free(conn->ctx, item->name);
if (item->type) xmpp_free(conn->ctx, item->type); if (item->type) xmpp_free(conn->ctx, item->type);
xmpp_free(conn->ctx, item); xmpp_free(conn->ctx, item);
item = NULL;
} }
}
item = next; if (item) {
prev = item;
item = item->next;
} else if (prev)
item = prev->next;
else
item = conn->handlers;
} }
} }
@@ -147,53 +131,54 @@ void handler_fire_stanza(xmpp_conn_t * const conn,
uint64_t handler_fire_timed(xmpp_ctx_t * const ctx) uint64_t handler_fire_timed(xmpp_ctx_t * const ctx)
{ {
xmpp_connlist_t *connitem; xmpp_connlist_t *connitem;
xmpp_handlist_t *item, *next; xmpp_handlist_t *handitem, *temp;
xmpp_conn_t *conn; int ret, fired;
uint64_t elapsed, min; uint64_t elapsed, min;
uint64_t timestamp;
int ret;
min = (uint64_t)(-1); min = (uint64_t)(-1);
connitem = ctx->connlist; connitem = ctx->connlist;
while (connitem) { while (connitem) {
conn = connitem->conn; if (connitem->conn->state != XMPP_STATE_CONNECTED) {
if (conn->state != XMPP_STATE_CONNECTED) {
connitem = connitem->next; connitem = connitem->next;
continue; continue;
} }
/* enable all handlers that were added */ /* enable all handlers that were added */
for (item = conn->timed_handlers; item; item = item->next) for (handitem = connitem->conn->timed_handlers; handitem;
item->enabled = 1; handitem = handitem->next)
handitem->enabled = 1;
item = conn->timed_handlers; handitem = connitem->conn->timed_handlers;
while (item) { while (handitem) {
/* don't fire user handlers until authentication succeeds and /* skip newly added handlers */
skip newly added handlers */ if (!handitem->enabled) {
if ((item->user_handler && !conn->authenticated) || !item->enabled) { handitem = handitem->next;
item = item->next;
continue; continue;
} }
next = item->next; /* only fire user handlers after authentication */
timestamp = time_stamp(); if (handitem->user_handler && !connitem->conn->authenticated) {
elapsed = time_elapsed(item->last_stamp, timestamp); handitem = handitem->next;
if (elapsed >= item->period) { continue;
/* 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;
item = next; 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;
/* delete handler if it returned false */
if (fired && !ret)
xmpp_timed_handler_delete(connitem->conn, temp->handler);
} }
connitem = connitem->next; connitem = connitem->next;
@@ -231,11 +216,9 @@ static void _timed_handler_add(xmpp_conn_t * const conn,
/* check if handler is already in the list */ /* check if handler is already in the list */
for (item = conn->timed_handlers; item; item = item->next) { for (item = conn->timed_handlers; item; item = item->next) {
if (item->handler == handler && item->userdata == userdata) { if (item->handler == (void *)handler)
xmpp_warn(conn->ctx, "xmpp", "Timed handler already exists.");
break; break;
} }
}
if (item) return; if (item) return;
/* build new item */ /* build new item */
@@ -243,7 +226,7 @@ static void _timed_handler_add(xmpp_conn_t * const conn,
if (!item) return; if (!item) return;
item->user_handler = user_handler; item->user_handler = user_handler;
item->handler = handler; item->handler = (void *)handler;
item->userdata = userdata; item->userdata = userdata;
item->enabled = 0; item->enabled = 0;
item->next = NULL; item->next = NULL;
@@ -279,18 +262,19 @@ void xmpp_timed_handler_delete(xmpp_conn_t * const conn,
prev = NULL; prev = NULL;
item = conn->timed_handlers; item = conn->timed_handlers;
while (item) { while (item) {
if (item->handler == handler) { if (item->handler == (void *)handler)
break;
prev = item;
item = item->next;
}
if (item) {
if (prev) if (prev)
prev->next = item->next; prev->next = item->next;
else else
conn->timed_handlers = item->next; conn->timed_handlers = item->next;
xmpp_free(conn->ctx, item); xmpp_free(conn->ctx, item);
item = prev ? prev->next : conn->timed_handlers;
} else {
prev = item;
item = item->next;
}
} }
} }
@@ -304,10 +288,8 @@ static void _id_handler_add(xmpp_conn_t * const conn,
/* check if handler is already in the list */ /* check if handler is already in the list */
item = (xmpp_handlist_t *)hash_get(conn->id_handlers, id); item = (xmpp_handlist_t *)hash_get(conn->id_handlers, id);
while (item) { while (item) {
if (item->handler == handler && item->userdata == userdata) { if (item->handler == (void *)handler)
xmpp_warn(conn->ctx, "xmpp", "Id handler already exists.");
break; break;
}
item = item->next; item = item->next;
} }
if (item) return; if (item) return;
@@ -317,7 +299,7 @@ static void _id_handler_add(xmpp_conn_t * const conn,
if (!item) return; if (!item) return;
item->user_handler = user_handler; item->user_handler = user_handler;
item->handler = handler; item->handler = (void *)handler;
item->userdata = userdata; item->userdata = userdata;
item->enabled = 0; item->enabled = 0;
item->next = NULL; item->next = NULL;
@@ -351,30 +333,29 @@ void xmpp_id_handler_delete(xmpp_conn_t * const conn,
xmpp_handler handler, xmpp_handler handler,
const char * const id) const char * const id)
{ {
xmpp_handlist_t *item, *prev, *next; xmpp_handlist_t *item, *prev;
prev = NULL; prev = NULL;
item = (xmpp_handlist_t *)hash_get(conn->id_handlers, id); item = (xmpp_handlist_t *)hash_get(conn->id_handlers, id);
if (!item) return; if (!item) return;
while (item) { while (item) {
next = item->next; if (item->handler == (void *)handler)
break;
if (item->handler == handler) { prev = item;
item = item->next;
}
if (item) {
if (prev) if (prev)
prev->next = next; prev->next = item->next;
else { else {
hash_drop(conn->id_handlers, id); hash_drop(conn->id_handlers, id);
hash_add(conn->id_handlers, id, next); hash_add(conn->id_handlers, id, item->next);
} }
xmpp_free(conn->ctx, item->id); xmpp_free(conn->ctx, item->id);
xmpp_free(conn->ctx, item); xmpp_free(conn->ctx, item);
item = next;
} else {
prev = item;
item = next;
}
} }
} }
@@ -390,13 +371,9 @@ static void _handler_add(xmpp_conn_t * const conn,
/* check if handler already in list */ /* check if handler already in list */
for (item = conn->handlers; item; item = item->next) { for (item = conn->handlers; item; item = item->next) {
/* same handler function can process different stanzas and if (item->handler == (void *)handler)
distinguish them according to userdata. */
if (item->handler == handler && item->userdata == userdata) {
xmpp_warn(conn->ctx, "xmpp", "Stanza handler already exists.");
break; break;
} }
}
if (item) return; if (item) return;
/* build new item */ /* build new item */
@@ -404,7 +381,7 @@ static void _handler_add(xmpp_conn_t * const conn,
if (!item) return; if (!item) return;
item->user_handler = user_handler; item->user_handler = user_handler;
item->handler = handler; item->handler = (void *)handler;
item->userdata = userdata; item->userdata = userdata;
item->enabled = 0; item->enabled = 0;
item->next = NULL; item->next = NULL;
@@ -464,7 +441,14 @@ void xmpp_handler_delete(xmpp_conn_t * const conn,
prev = NULL; prev = NULL;
item = conn->handlers; item = conn->handlers;
while (item) { while (item) {
if (item->handler == handler) { if (item->handler == (void *)handler)
break;
prev = item;
item = item->next;
}
if (item) {
if (prev) if (prev)
prev->next = item->next; prev->next = item->next;
else else
@@ -474,11 +458,6 @@ void xmpp_handler_delete(xmpp_conn_t * const conn,
if (item->name) xmpp_free(conn->ctx, item->name); if (item->name) xmpp_free(conn->ctx, item->name);
if (item->type) xmpp_free(conn->ctx, item->type); if (item->type) xmpp_free(conn->ctx, item->type);
xmpp_free(conn->ctx, item); xmpp_free(conn->ctx, item);
item = prev ? prev->next : conn->handlers;
} else {
prev = item;
item = item->next;
}
} }
} }
@@ -616,75 +595,3 @@ void handler_add(xmpp_conn_t * const conn,
{ {
_handler_add(conn, handler, ns, name, type, userdata, 0); _handler_add(conn, handler, ns, name, type, userdata, 0);
} }
/** Delete all system handlers.
* This function is used to reset conn object before re-connecting.
*
* @param conn a Strophe connection object
*/
void handler_system_delete_all(xmpp_conn_t *conn)
{
xmpp_handlist_t *item, *next, *head, *head_old;
hash_iterator_t *iter;
const char *key;
char *key2 = NULL;
/* TODO unify all kinds of handlers and avoid copy-paste below */
item = conn->handlers;
while (item) {
if (!item->user_handler) {
next = item->next;
_handler_item_remove(&conn->handlers, item);
if (item->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);
}

View File

@@ -47,7 +47,7 @@ struct _hash_iterator_t {
/** allocate and initialize a new hash table */ /** allocate and initialize a new hash table */
hash_t *hash_new(xmpp_ctx_t * const ctx, const int size, hash_t *hash_new(xmpp_ctx_t * const ctx, const int size,
hash_free_func free_func) hash_free_func free)
{ {
hash_t *result = NULL; hash_t *result = NULL;
@@ -62,7 +62,7 @@ hash_t *hash_new(xmpp_ctx_t * const ctx, const int size,
result->length = size; result->length = size;
result->ctx = ctx; result->ctx = ctx;
result->free = free_func; result->free = free;
result->num_keys = 0; result->num_keys = 0;
/* give the caller a reference */ /* give the caller a reference */
result->ref = 1; result->ref = 1;
@@ -106,35 +106,18 @@ void hash_release(hash_t * const table)
/** hash a key for our table lookup */ /** hash a key for our table lookup */
static int _hash_key(hash_t *table, const char *key) static int _hash_key(hash_t *table, const char *key)
{ {
unsigned hash = 0; int hash = 0;
unsigned shift = 0; int shift = 0;
const unsigned char *c = (const unsigned char *)key; const char *c = key;
while (*c != 0) { while (*c != '\0') {
/* assume 32 bit ints */ /* assume 32 bit ints */
hash ^= ((unsigned)*c++ << shift); hash ^= ((int)*c++ << shift);
shift += 8; shift += 8;
if (shift > 24) shift = 0; if (shift > 24) shift = 0;
} }
return hash % (unsigned)table->length;
}
hashentry_t *_hash_entry_find(hash_t *table, const char *key) return hash % table->length;
{
hashentry_t *entry;
int table_index = _hash_key(table, key);
/* look up the hash entry */
entry = table->entries[table_index];
while (entry != NULL) {
/* traverse the linked list looking for the key */
if (!strcmp(key, entry->key)) {
/* match */
break;
}
entry = entry->next;
}
return entry;
} }
/** add a key, value pair to a hash table. /** add a key, value pair to a hash table.
@@ -145,12 +128,11 @@ int hash_add(hash_t *table, const char * const key, void *data)
{ {
xmpp_ctx_t *ctx = table->ctx; xmpp_ctx_t *ctx = table->ctx;
hashentry_t *entry = NULL; hashentry_t *entry = NULL;
int table_index = _hash_key(table, key); int index = _hash_key(table, key);
/* find and replace existing entry, if any */ /* drop existing entry, if any */
entry = _hash_entry_find(table, key); hash_drop(table, key);
if (entry == NULL) {
/* allocate and fill a new entry */ /* allocate and fill a new entry */
entry = xmpp_alloc(ctx, sizeof(hashentry_t)); entry = xmpp_alloc(ctx, sizeof(hashentry_t));
if (!entry) return -1; if (!entry) return -1;
@@ -159,13 +141,12 @@ int hash_add(hash_t *table, const char * const key, void *data)
xmpp_free(ctx, entry); xmpp_free(ctx, entry);
return -1; 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; 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; return 0;
} }
@@ -174,9 +155,22 @@ int hash_add(hash_t *table, const char * const key, void *data)
void *hash_get(hash_t *table, const char *key) void *hash_get(hash_t *table, const char *key)
{ {
hashentry_t *entry; hashentry_t *entry;
int index = _hash_key(table, key);
void *result = NULL;
entry = _hash_entry_find(table, key); /* look up the hash entry */
return entry == NULL ? NULL : entry->value; 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;
} }
/** delete a key from a hash table */ /** delete a key from a hash table */
@@ -184,10 +178,10 @@ int hash_drop(hash_t *table, const char *key)
{ {
xmpp_ctx_t *ctx = table->ctx; xmpp_ctx_t *ctx = table->ctx;
hashentry_t *entry, *prev; hashentry_t *entry, *prev;
int table_index = _hash_key(table, key); int index = _hash_key(table, key);
/* look up the hash entry */ /* look up the hash entry */
entry = table->entries[table_index]; entry = table->entries[index];
prev = NULL; prev = NULL;
while (entry != NULL) { while (entry != NULL) {
/* traverse the linked list looking for the key */ /* traverse the linked list looking for the key */
@@ -196,7 +190,7 @@ int hash_drop(hash_t *table, const char *key)
xmpp_free(ctx, entry->key); xmpp_free(ctx, entry->key);
if (table->free) table->free(ctx, entry->value); if (table->free) table->free(ctx, entry->value);
if (prev == NULL) { if (prev == NULL) {
table->entries[table_index] = entry->next; table->entries[index] = entry->next;
} else { } else {
prev->next = entry->next; prev->next = entry->next;
} }
@@ -279,3 +273,4 @@ const char * hash_iter_next(hash_iterator_t *iter)
iter->entry = entry; iter->entry = entry;
return entry->key; return entry->key;
} }

View File

@@ -22,7 +22,7 @@ typedef void (*hash_free_func)(const xmpp_ctx_t * const ctx, void *p);
/** allocate and initialize a new hash table */ /** allocate and initialize a new hash table */
hash_t *hash_new(xmpp_ctx_t * const ctx, const int size, hash_t *hash_new(xmpp_ctx_t * const ctx, const int size,
hash_free_func free_func); hash_free_func free);
/** allocate a new reference to an existing hash table */ /** allocate a new reference to an existing hash table */
hash_t *hash_clone(hash_t * const table); hash_t *hash_clone(hash_t * const table);

View File

@@ -33,7 +33,7 @@ char *xmpp_jid_new(xmpp_ctx_t *ctx, const char *node,
const char *resource) const char *resource)
{ {
char *result; char *result;
size_t len, nlen, dlen, rlen; int len,nlen,dlen,rlen;
/* jid must at least have a domain */ /* jid must at least have a domain */
if (domain == NULL) return NULL; if (domain == NULL) return NULL;
@@ -56,7 +56,7 @@ char *xmpp_jid_new(xmpp_ctx_t *ctx, const char *node,
result[nlen+dlen] = '/'; result[nlen+dlen] = '/';
memcpy(result+nlen+dlen+1, resource, rlen - 1); memcpy(result+nlen+dlen+1, resource, rlen - 1);
} }
result[len] = '\0'; result[nlen+dlen+rlen] = '\0';
} }
return result; return result;
@@ -72,13 +72,15 @@ char *xmpp_jid_new(xmpp_ctx_t *ctx, const char *node,
char *xmpp_jid_bare(xmpp_ctx_t *ctx, const char *jid) char *xmpp_jid_bare(xmpp_ctx_t *ctx, const char *jid)
{ {
char *result; char *result;
size_t len; const char *c;
len = strcspn(jid, "/"); c = strchr(jid, '/');
result = xmpp_alloc(ctx, len + 1); if (c == NULL) return xmpp_strdup(ctx, jid);
result = xmpp_alloc(ctx, c-jid+1);
if (result != NULL) { if (result != NULL) {
memcpy(result, jid, len); memcpy(result, jid, c-jid);
result[len] = '\0'; result[c-jid] = '\0';
} }
return result; return result;
@@ -119,8 +121,7 @@ char *xmpp_jid_node(xmpp_ctx_t *ctx, const char *jid)
char *xmpp_jid_domain(xmpp_ctx_t *ctx, const char *jid) char *xmpp_jid_domain(xmpp_ctx_t *ctx, const char *jid)
{ {
char *result = NULL; char *result = NULL;
const char *c; const char *c,*s;
size_t dlen;
c = strchr(jid, '@'); c = strchr(jid, '@');
if (c == NULL) { if (c == NULL) {
@@ -130,11 +131,15 @@ char *xmpp_jid_domain(xmpp_ctx_t *ctx, const char *jid)
/* advance past the separator */ /* advance past the separator */
c++; c++;
} }
dlen = strcspn(c, "/"); /* do not include resource */ s = strchr(c, '/');
result = xmpp_alloc(ctx, dlen + 1); if (s == NULL) {
/* no resource */
s = c + strlen(c);
}
result = xmpp_alloc(ctx, (s-c) + 1);
if (result != NULL) { if (result != NULL) {
memcpy(result, c, dlen); memcpy(result, c, (s-c));
result[dlen] = '\0'; result[s-c] = '\0';
} }
return result; return result;
@@ -150,8 +155,20 @@ char *xmpp_jid_domain(xmpp_ctx_t *ctx, const char *jid)
*/ */
char *xmpp_jid_resource(xmpp_ctx_t *ctx, const char *jid) char *xmpp_jid_resource(xmpp_ctx_t *ctx, const char *jid)
{ {
char *result = NULL;
const char *c; const char *c;
int len;
c = strchr(jid, '/'); c = strchr(jid, '/');
return c != NULL ? xmpp_strdup(ctx, c + 1) : NULL; 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;
} }

View File

@@ -154,6 +154,8 @@ void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
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 */ /* The four core functions - F1 is optimized somewhat */
/* #define F1(x, y, z) (x & y | ~x & z) */ /* #define F1(x, y, z) (x & y | ~x & z) */
@@ -268,3 +270,23 @@ static void MD5Transform(uint32_t buf[4], const unsigned char inext[64],
buf[2] += c; buf[2] += c;
buf[3] += d; 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 */

View File

@@ -25,4 +25,8 @@ void MD5Update(struct MD5Context *context, unsigned char const *buf,
uint32_t len); uint32_t len);
void MD5Final(unsigned char digest[16], struct MD5Context *context); void MD5Final(unsigned char digest[16], struct MD5Context *context);
#ifdef DEBUG_MD5
void MD5DumpBytes(unsigned char *b, int len);
#endif
#endif /* !MD5_H */ #endif /* !MD5_H */

View File

@@ -82,3 +82,4 @@ void XMPP::Context::callLog(void * const userdata,
{ {
reinterpret_cast<Context *>(userdata)->log(level, area, msg); reinterpret_cast<Context *>(userdata)->log(level, area, msg);
} }

View File

@@ -75,3 +75,5 @@ Stanza *Stanza::copy()
// TODO // TODO
return NULL; return NULL;
} }

View File

@@ -17,8 +17,6 @@
#ifndef __LIBSTROPHE_OSTYPES_H__ #ifndef __LIBSTROPHE_OSTYPES_H__
#define __LIBSTROPHE_OSTYPES_H__ #define __LIBSTROPHE_OSTYPES_H__
#include <stddef.h> /* size_t */
#if defined (_MSC_VER) && _MSC_VER < 1600 #if defined (_MSC_VER) && _MSC_VER < 1600
typedef signed char int8_t; typedef signed char int8_t;
typedef short int int16_t; typedef short int int16_t;
@@ -29,17 +27,6 @@ typedef unsigned char uint8_t;
typedef unsigned short int uint16_t; typedef unsigned short int uint16_t;
typedef unsigned int uint32_t; typedef unsigned int uint32_t;
typedef unsigned __int64 uint64_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 #else
#include <stdint.h> #include <stdint.h>
#endif #endif

View File

@@ -33,7 +33,7 @@ parser_t *parser_new(xmpp_ctx_t *ctx,
parser_end_callback endcb, parser_end_callback endcb,
parser_stanza_callback stanzacb, parser_stanza_callback stanzacb,
void *userdata); void *userdata);
void parser_free(parser_t *parser); void parser_free(parser_t * const parser);
char* parser_attr_name(xmpp_ctx_t *ctx, char *nsname); char* parser_attr_name(xmpp_ctx_t *ctx, char *nsname);
int parser_reset(parser_t *parser); int parser_reset(parser_t *parser);
int parser_feed(parser_t *parser, char *chunk, int len); int parser_feed(parser_t *parser, char *chunk, int len);

View File

@@ -23,14 +23,8 @@
#include "common.h" #include "common.h"
#include "parser.h" #include "parser.h"
/* Use the Unit Separator to delimit namespace and name in our XML*/ /* ASCII FF is invalid UTF-8 and should never be present in well-formed XML */
#define NAMESPACE_SEP ('\x1F') #define NAMESPACE_SEP ('\xFF')
/* 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 { struct _parser_t {
xmpp_ctx_t *ctx; xmpp_ctx_t *ctx;
@@ -41,11 +35,6 @@ struct _parser_t {
void *userdata; void *userdata;
int depth; int depth;
xmpp_stanza_t *stanza; xmpp_stanza_t *stanza;
char* inner_text;
/* number of allocated bytes */
int inner_text_size;
/* excluding terminal '\0' */
int inner_text_used;
}; };
/* return allocated string with the name from a delimited /* return allocated string with the name from a delimited
@@ -54,7 +43,7 @@ static char *_xml_name(xmpp_ctx_t *ctx, const char *nsname)
{ {
char *result = NULL; char *result = NULL;
const char *c; const char *c;
size_t len; int len;
c = strchr(nsname, NAMESPACE_SEP); c = strchr(nsname, NAMESPACE_SEP);
if (c == NULL) return xmpp_strdup(ctx, nsname); if (c == NULL) return xmpp_strdup(ctx, nsname);
@@ -103,26 +92,6 @@ static void _set_attributes(xmpp_stanza_t *stanza, const XML_Char **attrs)
} }
} }
static void complete_inner_text(parser_t *parser)
{
xmpp_stanza_t *stanza;
if (parser->inner_text) {
/* create and populate stanza */
stanza = xmpp_stanza_new(parser->ctx);
/* FIXME: disconnect on allocation error */
if (stanza) {
xmpp_stanza_set_text(stanza, parser->inner_text);
xmpp_stanza_add_child(parser->stanza, stanza);
xmpp_stanza_release(stanza);
}
xmpp_free(parser->ctx, parser->inner_text);
parser->inner_text = NULL;
parser->inner_text_size = 0;
parser->inner_text_used = 0;
}
}
static void _start_element(void *userdata, static void _start_element(void *userdata,
const XML_Char *nsname, const XML_Char *nsname,
const XML_Char **attrs) const XML_Char **attrs)
@@ -145,7 +114,18 @@ static void _start_element(void *userdata,
/* something terrible happened */ /* something terrible happened */
/* FIXME: shutdown disconnect */ /* FIXME: shutdown disconnect */
xmpp_error(parser->ctx, "parser", "oops, where did our stanza go?"); 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 { } else {
/* starting a child of parser->stanza */
child = xmpp_stanza_new(parser->ctx); child = xmpp_stanza_new(parser->ctx);
if (!child) { if (!child) {
/* FIXME: can't allocate, disconnect */ /* FIXME: can't allocate, disconnect */
@@ -155,11 +135,13 @@ static void _start_element(void *userdata,
if (ns) if (ns)
xmpp_stanza_set_ns(child, ns); xmpp_stanza_set_ns(child, ns);
if (parser->stanza != NULL) { /* add child to parent */
complete_inner_text(parser);
xmpp_stanza_add_child(parser->stanza, child); xmpp_stanza_add_child(parser->stanza, child);
/* the child is owned by the toplevel stanza now */
xmpp_stanza_release(child); xmpp_stanza_release(child);
}
/* make child the current stanza */
parser->stanza = child; parser->stanza = child;
} }
} }
@@ -181,7 +163,6 @@ static void _end_element(void *userdata, const XML_Char *name)
if (parser->endcb) if (parser->endcb)
parser->endcb((char *)name, parser->userdata); parser->endcb((char *)name, parser->userdata);
} else { } else {
complete_inner_text(parser);
if (parser->stanza->parent) { if (parser->stanza->parent) {
/* we're finishing a child stanza, so set current to the parent */ /* we're finishing a child stanza, so set current to the parent */
parser->stanza = parser->stanza->parent; parser->stanza = parser->stanza->parent;
@@ -198,29 +179,20 @@ static void _end_element(void *userdata, const XML_Char *name)
static void _characters(void *userdata, const XML_Char *s, int len) static void _characters(void *userdata, const XML_Char *s, int len)
{ {
parser_t *parser = (parser_t *)userdata; parser_t *parser = (parser_t *)userdata;
char *p; xmpp_stanza_t *stanza;
if (parser->depth < 2) return; if (parser->depth < 2) return;
/* Join all parts to a single resulting string. Stanza is created in /* create and populate stanza */
* _start_element() and _end_element(). */ stanza = xmpp_stanza_new(parser->ctx);
if (parser->inner_text_used + len >= parser->inner_text_size) { if (!stanza) {
parser->inner_text_size = parser->inner_text_used + len + 1 + /* FIXME: allocation error, disconnect */
INNER_TEXT_PADDING;
p = xmpp_realloc(parser->ctx, parser->inner_text,
parser->inner_text_size);
if (p == NULL) {
xmpp_free(parser->ctx, parser->inner_text);
parser->inner_text = NULL;
parser->inner_text_used = 0;
parser->inner_text_size = 0;
return; return;
} }
parser->inner_text = p; xmpp_stanza_set_text_with_size(stanza, s, len);
parser->inner_text[parser->inner_text_used] = '\0';
} xmpp_stanza_add_child(parser->stanza, stanza);
parser->inner_text_used += len; xmpp_stanza_release(stanza);
strncat(parser->inner_text, s, len);
} }
parser_t *parser_new(xmpp_ctx_t *ctx, parser_t *parser_new(xmpp_ctx_t *ctx,
@@ -241,9 +213,6 @@ parser_t *parser_new(xmpp_ctx_t *ctx,
parser->userdata = userdata; parser->userdata = userdata;
parser->depth = 0; parser->depth = 0;
parser->stanza = NULL; parser->stanza = NULL;
parser->inner_text = NULL;
parser->inner_text_size = 0;
parser->inner_text_used = 0;
parser_reset(parser); parser_reset(parser);
} }
@@ -262,11 +231,6 @@ void parser_free(parser_t *parser)
if (parser->expat) if (parser->expat)
XML_ParserFree(parser->expat); XML_ParserFree(parser->expat);
if (parser->inner_text) {
xmpp_free (parser->ctx, parser->inner_text);
parser->inner_text = NULL;
}
xmpp_free(parser->ctx, parser); xmpp_free(parser->ctx, parser);
} }
@@ -285,11 +249,6 @@ int parser_reset(parser_t *parser)
parser->depth = 0; parser->depth = 0;
parser->stanza = NULL; parser->stanza = NULL;
if (parser->inner_text) {
xmpp_free (parser->ctx, parser->inner_text);
parser->inner_text = NULL;
}
XML_SetUserData(parser->expat, parser); XML_SetUserData(parser->expat, parser);
XML_SetElementHandler(parser->expat, _start_element, _end_element); XML_SetElementHandler(parser->expat, _start_element, _end_element);
XML_SetCharacterDataHandler(parser->expat, _characters); XML_SetCharacterDataHandler(parser->expat, _characters);

View File

@@ -116,12 +116,11 @@ static void _start_element(void *userdata,
if (parser->depth == 0) { if (parser->depth == 0) {
/* notify the owner */ /* notify the owner */
if (parser->startcb) { if (parser->startcb)
cbattrs = _convert_attrs(parser, nattrs, attrs); cbattrs = _convert_attrs(parser, nattrs, attrs);
parser->startcb((char *)name, cbattrs, parser->startcb((char *)name, cbattrs,
parser->userdata); parser->userdata);
_free_cbattrs(parser, cbattrs); _free_cbattrs(parser, cbattrs);
}
} else { } else {
/* build stanzas at depth 1 */ /* build stanzas at depth 1 */
if (!parser->stanza && parser->depth != 1) { if (!parser->stanza && parser->depth != 1) {
@@ -276,5 +275,9 @@ int parser_feed(parser_t *parser, char *chunk, int len)
{ {
/* xmlParseChunk API returns 0 on success which is opposite logic to /* xmlParseChunk API returns 0 on success which is opposite logic to
the status returned by parser_feed */ the status returned by parser_feed */
return !xmlParseChunk(parser->xmlctx, chunk, len, 0); if(!xmlParseChunk(parser->xmlctx, chunk, len, 0)) {
return 1;
} else {
return 0;
}
} }

View File

@@ -1,311 +0,0 @@
/* 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;
}
}

View File

@@ -1,65 +0,0 @@
/* 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__ */

View File

@@ -1,767 +0,0 @@
/* 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 */

View File

@@ -1,69 +0,0 @@
/* 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__ */

View File

@@ -23,24 +23,15 @@
#include "md5.h" #include "md5.h"
#include "sha1.h" #include "sha1.h"
#include "scram.h" #include "scram.h"
#include "rand.h"
#include "util.h"
/* strtok_s() has appeared in visual studio 2005. #ifdef _WIN32
Use own implementation for older versions. */
#ifdef _MSC_VER
# if (_MSC_VER >= 1400)
#define strtok_r strtok_s #define strtok_r strtok_s
# else
# define strtok_r xmpp_strtok_r
#endif #endif
#endif /* _MSC_VER */
/** generate authentication string for the SASL PLAIN mechanism */ /** generate authentication string for the SASL PLAIN mechanism */
char *sasl_plain(xmpp_ctx_t *ctx, const char *authid, const char *password) { char *sasl_plain(xmpp_ctx_t *ctx, const char *authid, const char *password) {
size_t idlen, passlen; int idlen, passlen;
size_t msglen;
char *result = NULL; char *result = NULL;
char *msg; char *msg;
@@ -49,14 +40,13 @@ char *sasl_plain(xmpp_ctx_t *ctx, const char *authid, const char *password) {
idlen = strlen(authid); idlen = strlen(authid);
passlen = strlen(password); passlen = strlen(password);
msglen = 2 + idlen + passlen; msg = xmpp_alloc(ctx, 2 + idlen + passlen);
msg = xmpp_alloc(ctx, msglen);
if (msg != NULL) { if (msg != NULL) {
msg[0] = '\0'; msg[0] = '\0';
memcpy(msg+1, authid, idlen); memcpy(msg+1, authid, idlen);
msg[1+idlen] = '\0'; msg[1+idlen] = '\0';
memcpy(msg+1+idlen+1, password, passlen); memcpy(msg+1+idlen+1, password, passlen);
result = xmpp_base64_encode(ctx, (unsigned char *)msg, msglen); result = base64_encode(ctx, (unsigned char *)msg, 2 + idlen + passlen);
xmpp_free(ctx, msg); xmpp_free(ctx, msg);
} }
@@ -82,7 +72,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) static char *_make_quoted(xmpp_ctx_t *ctx, const char *s)
{ {
char *result; char *result;
size_t len = strlen(s); int len = strlen(s);
result = xmpp_alloc(ctx, len + 3); result = xmpp_alloc(ctx, len + 3);
if (result != NULL) { if (result != NULL) {
@@ -102,7 +92,7 @@ static hash_t *_parse_digest_challenge(xmpp_ctx_t *ctx, const char *msg)
char *key, *value; char *key, *value;
unsigned char *s, *t; unsigned char *s, *t;
text = (unsigned char *)xmpp_base64_decode_str(ctx, msg, strlen(msg)); text = base64_decode(ctx, msg, strlen(msg));
if (text == NULL) { if (text == NULL) {
xmpp_error(ctx, "SASL", "couldn't Base64 decode challenge!"); xmpp_error(ctx, "SASL", "couldn't Base64 decode challenge!");
return NULL; return NULL;
@@ -228,7 +218,6 @@ char *sasl_digest_md5(xmpp_ctx_t *ctx, const char *challenge,
struct MD5Context MD5; struct MD5Context MD5;
unsigned char digest[16], HA1[16], HA2[16]; unsigned char digest[16], HA1[16], HA2[16];
char hex[32]; char hex[32];
char cnonce[13];
/* our digest response is /* our digest response is
Hex( KD( HEX(MD5(A1)), Hex( KD( HEX(MD5(A1)),
@@ -261,8 +250,8 @@ char *sasl_digest_md5(xmpp_ctx_t *ctx, const char *challenge,
/* add our response fields */ /* add our response fields */
hash_add(table, "username", xmpp_strdup(ctx, node)); hash_add(table, "username", xmpp_strdup(ctx, node));
xmpp_rand_nonce(ctx->rand, cnonce, sizeof(cnonce)); /* TODO: generate a random cnonce */
hash_add(table, "cnonce", xmpp_strdup(ctx, cnonce)); hash_add(table, "cnonce", xmpp_strdup(ctx, "00DEADBEEF00"));
hash_add(table, "nc", xmpp_strdup(ctx, "00000001")); hash_add(table, "nc", xmpp_strdup(ctx, "00000001"));
hash_add(table, "qop", xmpp_strdup(ctx, "auth")); hash_add(table, "qop", xmpp_strdup(ctx, "auth"));
value = xmpp_alloc(ctx, 5 + strlen(domain) + 1); value = xmpp_alloc(ctx, 5 + strlen(domain) + 1);
@@ -355,7 +344,7 @@ char *sasl_digest_md5(xmpp_ctx_t *ctx, const char *challenge,
hash_release(table); /* also frees value strings */ hash_release(table); /* also frees value strings */
/* reuse response for the base64 encode of our result */ /* reuse response for the base64 encode of our result */
response = xmpp_base64_encode(ctx, (unsigned char *)result, strlen(result)); response = base64_encode(ctx, (unsigned char *)result, strlen(result));
xmpp_free(ctx, result); xmpp_free(ctx, result);
return response; return response;
@@ -371,7 +360,7 @@ char *sasl_scram_sha1(xmpp_ctx_t *ctx, const char *challenge,
char *r = NULL; char *r = NULL;
char *s = NULL; char *s = NULL;
char *i = NULL; char *i = NULL;
unsigned char *sval; char *sval;
size_t sval_len; size_t sval_len;
long ival; long ival;
char *tmp; char *tmp;
@@ -407,10 +396,11 @@ char *sasl_scram_sha1(xmpp_ctx_t *ctx, const char *challenge,
goto out; goto out;
} }
xmpp_base64_decode_bin(ctx, s, strlen(s), &sval, &sval_len); sval = (char *)base64_decode(ctx, s, strlen(s));
if (!sval) { if (!sval) {
goto out; goto out;
} }
sval_len = base64_decoded_len(ctx, s, strlen(s));
ival = strtol(i, &saveptr, 10); ival = strtol(i, &saveptr, 10);
auth_len = 10 + strlen(r) + strlen(first_bare) + strlen(challenge); auth_len = 10 + strlen(r) + strlen(first_bare) + strlen(challenge);
@@ -436,7 +426,7 @@ char *sasl_scram_sha1(xmpp_ctx_t *ctx, const char *challenge,
sign[j] ^= key[j]; sign[j] ^= key[j];
} }
sign_b64 = xmpp_base64_encode(ctx, sign, sizeof(sign)); sign_b64 = base64_encode(ctx, sign, sizeof(sign));
if (!sign_b64) { if (!sign_b64) {
goto out_response; goto out_response;
} }
@@ -449,7 +439,7 @@ char *sasl_scram_sha1(xmpp_ctx_t *ctx, const char *challenge,
strcat(response, sign_b64); strcat(response, sign_b64);
xmpp_free(ctx, sign_b64); xmpp_free(ctx, sign_b64);
response_b64 = xmpp_base64_encode(ctx, (unsigned char *)response, response_b64 = base64_encode(ctx, (unsigned char *)response,
strlen(response)); strlen(response));
if (!response_b64) { if (!response_b64) {
goto out_response; goto out_response;
@@ -466,3 +456,257 @@ out:
xmpp_free(ctx, tmp); xmpp_free(ctx, tmp);
return result; 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 */

View File

@@ -27,4 +27,18 @@ char *sasl_scram_sha1(xmpp_ctx_t *ctx, const char *challenge,
const char *first_bare, const char *jid, const char *first_bare, const char *jid,
const char *password); 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__ */ #endif /* _LIBXMPP_SASL_H__ */

View File

@@ -24,52 +24,64 @@
#include "scram.h" #include "scram.h"
#define HMAC_BLOCK_SIZE 64 /* 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
static const uint8_t ipad = 0x36; static const uint8_t ipad = 0x36;
static const uint8_t opad = 0x5C; static const uint8_t opad = 0x5C;
static void crypto_HMAC_SHA1(const uint8_t *key, size_t key_len, static void SHA1(const uint8_t* data, size_t len,
const uint8_t *text, size_t len, uint8_t digest[SHA1_DIGEST_SIZE])
uint8_t *digest)
{ {
uint8_t key_pad[HMAC_BLOCK_SIZE]; SHA1_CTX ctx;
uint8_t key_ipad[HMAC_BLOCK_SIZE]; SHA1_Init(&ctx);
uint8_t key_opad[HMAC_BLOCK_SIZE]; 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 sha_digest[SHA1_DIGEST_SIZE]; uint8_t sha_digest[SHA1_DIGEST_SIZE];
int i; int i;
SHA1_CTX ctx; SHA1_CTX ctx;
memset(key_pad, 0, sizeof(key_pad)); memset(key_pad, 0, sizeof(key_pad));
if (key_len <= HMAC_BLOCK_SIZE) { if (key_len <= BLOCK_SIZE) {
memcpy(key_pad, key, key_len); memcpy(key_pad, key, key_len);
} else { } else {
/* according to RFC2104 */ /* according to RFC2104 */
crypto_SHA1(key, key_len, key_pad); SHA1(key, key_len, key_pad);
} }
for (i = 0; i < HMAC_BLOCK_SIZE; i++) { for (i = 0; i < BLOCK_SIZE; i++) {
key_ipad[i] = key_pad[i] ^ ipad; key_ipad[i] = key_pad[i] ^ ipad;
key_opad[i] = key_pad[i] ^ opad; key_opad[i] = key_pad[i] ^ opad;
} }
crypto_SHA1_Init(&ctx); SHA1_Init(&ctx);
crypto_SHA1_Update(&ctx, key_ipad, HMAC_BLOCK_SIZE); SHA1_Update(&ctx, key_ipad, BLOCK_SIZE);
crypto_SHA1_Update(&ctx, text, len); SHA1_Update(&ctx, text, len);
crypto_SHA1_Final(&ctx, sha_digest); SHA1_Final(&ctx, sha_digest);
crypto_SHA1_Init(&ctx); SHA1_Init(&ctx);
crypto_SHA1_Update(&ctx, key_opad, HMAC_BLOCK_SIZE); SHA1_Update(&ctx, key_opad, BLOCK_SIZE);
crypto_SHA1_Update(&ctx, sha_digest, SHA1_DIGEST_SIZE); SHA1_Update(&ctx, sha_digest, SHA1_DIGEST_SIZE);
crypto_SHA1_Final(&ctx, digest); SHA1_Final(&ctx, digest);
} }
static void SCRAM_SHA1_Hi(const uint8_t *text, size_t len, static void SCRAM_SHA1_Hi(const uint8_t *text, size_t len,
const uint8_t *salt, size_t salt_len, uint32_t i, const uint8_t *salt, size_t salt_len, uint32_t i,
uint8_t *digest) uint8_t digest[SHA1_DIGEST_SIZE])
{ {
int k; int j, k;
uint32_t j;
uint8_t tmp[128]; uint8_t tmp[128];
static uint8_t int1[] = {0x0, 0x0, 0x0, 0x1}; static uint8_t int1[] = {0x0, 0x0, 0x0, 0x1};
@@ -86,11 +98,11 @@ static void SCRAM_SHA1_Hi(const uint8_t *text, size_t len,
memcpy(&tmp[salt_len], int1, sizeof(int1)); memcpy(&tmp[salt_len], int1, sizeof(int1));
/* 'text' for Hi is a 'key' for HMAC */ /* 'text' for Hi is a 'key' for HMAC */
crypto_HMAC_SHA1(text, len, tmp, salt_len + sizeof(int1), digest); HMAC_SHA1(text, len, tmp, salt_len + sizeof(int1), digest);
memcpy(tmp, digest, SHA1_DIGEST_SIZE); memcpy(tmp, digest, SHA1_DIGEST_SIZE);
for (j = 1; j < i; j++) { for (j = 1; j < i; j++) {
crypto_HMAC_SHA1(text, len, tmp, SHA1_DIGEST_SIZE, tmp); HMAC_SHA1(text, len, tmp, SHA1_DIGEST_SIZE, tmp);
for (k = 0; k < SHA1_DIGEST_SIZE; k++) { for (k = 0; k < SHA1_DIGEST_SIZE; k++) {
digest[k] ^= tmp[k]; digest[k] ^= tmp[k];
} }
@@ -99,30 +111,30 @@ static void SCRAM_SHA1_Hi(const uint8_t *text, size_t len,
void SCRAM_SHA1_ClientKey(const uint8_t *password, 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, const uint8_t *salt, size_t salt_len, uint32_t i,
uint8_t *key) uint8_t key[SHA1_DIGEST_SIZE])
{ {
uint8_t salted[SHA1_DIGEST_SIZE]; uint8_t salted[SHA1_DIGEST_SIZE];
/* XXX: Normalize(password) is omitted */ /* XXX: Normalize(password) is omitted */
SCRAM_SHA1_Hi(password, len, salt, salt_len, i, salted); SCRAM_SHA1_Hi(password, len, salt, salt_len, i, salted);
crypto_HMAC_SHA1(salted, SHA1_DIGEST_SIZE, (uint8_t *)"Client Key", HMAC_SHA1(salted, SHA1_DIGEST_SIZE, (uint8_t *)"Client Key",
strlen("Client Key"), key); strlen("Client Key"), key);
} }
void SCRAM_SHA1_ClientSignature(const uint8_t *ClientKey, void SCRAM_SHA1_ClientSignature(const uint8_t ClientKey[SHA1_DIGEST_SIZE],
const uint8_t *AuthMessage, size_t len, const uint8_t *AuthMessage, size_t len,
uint8_t *sign) uint8_t sign[SHA1_DIGEST_SIZE])
{ {
uint8_t stored[SHA1_DIGEST_SIZE]; uint8_t stored[SHA1_DIGEST_SIZE];
crypto_SHA1(ClientKey, SHA1_DIGEST_SIZE, stored); SHA1(ClientKey, SHA1_DIGEST_SIZE, stored);
crypto_HMAC_SHA1(stored, SHA1_DIGEST_SIZE, AuthMessage, len, sign); HMAC_SHA1(stored, SHA1_DIGEST_SIZE, AuthMessage, len, sign);
} }
void SCRAM_SHA1_ClientProof(const uint8_t *ClientKey, void SCRAM_SHA1_ClientProof(const uint8_t ClientKey[SHA1_DIGEST_SIZE],
const uint8_t *ClientSignature, const uint8_t ClientSignature[SHA1_DIGEST_SIZE],
uint8_t *proof) uint8_t proof[SHA1_DIGEST_SIZE])
{ {
int i; int i;
for (i = 0; i < SHA1_DIGEST_SIZE; i++) { for (i = 0; i < SHA1_DIGEST_SIZE; i++) {

View File

@@ -23,14 +23,14 @@
void SCRAM_SHA1_ClientKey(const uint8_t *password, 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, const uint8_t *salt, size_t salt_len, uint32_t i,
uint8_t *key); uint8_t key[SHA1_DIGEST_SIZE]);
void SCRAM_SHA1_ClientSignature(const uint8_t *ClientKey, void SCRAM_SHA1_ClientSignature(const uint8_t ClientKey[SHA1_DIGEST_SIZE],
const uint8_t *AuthMessage, size_t len, const uint8_t *AuthMessage, size_t len,
uint8_t *sign); uint8_t sign[SHA1_DIGEST_SIZE]);
void SCRAM_SHA1_ClientProof(const uint8_t *ClientKey, void SCRAM_SHA1_ClientProof(const uint8_t ClientKey[SHA1_DIGEST_SIZE],
const uint8_t *ClientSignature, const uint8_t ClientSignature[SHA1_DIGEST_SIZE],
uint8_t *proof); uint8_t proof[SHA1_DIGEST_SIZE]);
#endif /* __LIBSTROPHE_SCRAM_H__ */ #endif /* __LIBSTROPHE_SCRAM_H__ */

View File

@@ -1,162 +0,0 @@
/* server.c
* strophe XMPP client library -- server object 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.
*/
/** @file
* Server management.
*/
/** @defgroup Server Server management
*/
#include <string.h>
#include "common.h"
#include "strophe.h"
static xmpp_server_t *conn2srv(xmpp_conn_t *conn);
static void _server_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_server_t *xmpp_server_new(xmpp_ctx_t * const ctx)
{
xmpp_server_t *srv;
xmpp_serverlist_t *item;
srv = xmpp_alloc(ctx, sizeof(*srv));
item = xmpp_alloc(ctx, sizeof(*item));
if (srv == NULL || item == NULL) {
xmpp_error(ctx, "xmpp", "Failed to allocate memory.");
xmpp_free(ctx, srv);
xmpp_free(ctx, item);
srv = NULL;
item = NULL;
}
if (srv != NULL) {
memset(srv, 0, sizeof(*srv));
srv->state = XMPP_STATE_STOPPED;
srv->ctx = ctx;
srv->sock = -1;
item->server = srv;
item->next = ctx->serverlist;
ctx->serverlist = item;
}
return srv;
}
void xmpp_server_free(xmpp_server_t * const srv)
{
xmpp_ctx_t *ctx = srv->ctx;
xmpp_serverlist_t *item, *prev = NULL;
item = ctx->serverlist;
while (item != NULL) {
if (item->server == srv) {
if (prev == NULL) ctx->serverlist = item->next;
if (prev != NULL) prev->next = item->next;
xmpp_free(ctx, item);
}
prev = item;
item = item->next;
}
xmpp_free(ctx, srv);
}
int xmpp_server_listen(xmpp_server_t * const srv, unsigned short port,
xmpp_server_handler callback, void * const userdata)
{
int rc = 0;
if (port == 0) port = XMPP_PORT_CLIENT;
srv->callback = callback;
srv->userdata = userdata;
srv->port = port;
srv->sock = sock_listen(port);
if (srv->sock >= 0) {
srv->state = XMPP_STATE_LISTENING;
xmpp_debug(srv->ctx, "xmpp", "Listening on port %u.", port);
} else
rc = XMPP_EINT;
return rc;
}
void xmpp_server_stop(xmpp_server_t * const srv)
{
srv->state = XMPP_STATE_STOPPED;
sock_stop_listen(srv->sock);
xmpp_debug(srv->ctx, "xmpp", "Server stopped on %u.", srv->port);
}
void server_accept(xmpp_server_t * const srv)
{
xmpp_conn_t *conn;
sock_t fd;
fd = sock_accept(srv->sock);
if (fd >= 0) {
xmpp_debug(srv->ctx, "xmpp", "New incoming connection on port %u.",
srv->port);
conn = xmpp_conn_new(srv->ctx);
conn->type = XMPP_INCOMING;
conn->state = XMPP_STATE_CONNECTED;
conn->sock = fd;
conn->conn_handler = _server_conn_handler;
conn->userdata = (void *)srv;
conn->authenticated = 1; /* don't ignore handlers */
conn_prepare_reset(conn, server_handle_open);
srv->callback(srv, conn, XMPP_SERVER_ACCEPT, 0, srv->userdata);
}
}
void server_handle_open(xmpp_conn_t * const conn)
{
xmpp_server_t *srv = conn2srv(conn);
/* XXX need to reset parser and re-open stream after authentication */
srv->callback(srv, conn, XMPP_SERVER_OPEN_STREAM, 0, srv->userdata);
}
static xmpp_server_t *conn2srv(xmpp_conn_t *conn)
{
xmpp_server_t *srv;
/* XXX dirty hack */
if (conn->ctx->serverlist != NULL)
srv = conn->ctx->serverlist->server;
else
srv = NULL;
return srv;
}
static void _server_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_server_t *srv = (xmpp_server_t *)userdata;
if (status == XMPP_CONN_DISCONNECT) {
/* remove conn from the list */
/* XXX when client sends </stream> first, server should close stream too */
srv->callback(srv, conn, XMPP_SERVER_DISCONNECT, error, srv->userdata);
}
}

View File

@@ -70,13 +70,25 @@ use SHA1_ prefix for public api
move public api to sha1.h 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> #include <string.h>
/* make sure the stdint.h types are available */
#include "ostypes.h" #include "ostypes.h"
#include "sha1.h"
/* Don't change user's data */ #include "sha1.h"
#define SHA1HANDSOFF
static uint32_t host_to_be(uint32_t i); static uint32_t host_to_be(uint32_t i);
static void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64]); static void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64]);
@@ -97,6 +109,19 @@ 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); #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) static uint32_t host_to_be(uint32_t i)
{ {
#define le_to_be(i) ((rol((i),24) & 0xFF00FF00) | (rol((i),8) & 0x00FF00FF)) #define le_to_be(i) ((rol((i),24) & 0xFF00FF00) | (rol((i),8) & 0x00FF00FF))
@@ -115,7 +140,6 @@ static uint32_t host_to_be(uint32_t i)
} check = {1}; } check = {1};
return check.c ? le_to_be(i) : i; return check.c ? le_to_be(i) : i;
#endif #endif
#undef le_to_be
} }
/* Hash a single 512-bit block. This is the core of the algorithm. */ /* Hash a single 512-bit block. This is the core of the algorithm. */
@@ -178,7 +202,7 @@ static void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64])
/* SHA1Init - Initialize new context */ /* SHA1Init - Initialize new context */
void crypto_SHA1_Init(SHA1_CTX* context) void SHA1_Init(SHA1_CTX* context)
{ {
/* SHA1 initialization constants */ /* SHA1 initialization constants */
context->state[0] = 0x67452301; context->state[0] = 0x67452301;
@@ -191,11 +215,14 @@ void crypto_SHA1_Init(SHA1_CTX* context)
/* Run your data through this. */ /* Run your data through this. */
void crypto_SHA1_Update(SHA1_CTX* context, const uint8_t* data, void SHA1_Update(SHA1_CTX* context, const uint8_t* data, const size_t len)
const size_t len)
{ {
size_t i, j; size_t i, j;
#ifdef VERBOSE
SHAPrintContext(context, "before");
#endif
j = (context->count[0] >> 3) & 63; j = (context->count[0] >> 3) & 63;
if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++; if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++;
context->count[1] += (len >> 29); context->count[1] += (len >> 29);
@@ -209,11 +236,15 @@ void crypto_SHA1_Update(SHA1_CTX* context, const uint8_t* data,
} }
else i = 0; else i = 0;
memcpy(&context->buffer[j], &data[i], len - i); memcpy(&context->buffer[j], &data[i], len - i);
#ifdef VERBOSE
SHAPrintContext(context, "after ");
#endif
} }
/* Add padding and return the message digest. */ /* Add padding and return the message digest. */
void crypto_SHA1_Final(SHA1_CTX* context, uint8_t* digest) void SHA1_Final(SHA1_CTX* context, uint8_t digest[SHA1_DIGEST_SIZE])
{ {
uint32_t i; uint32_t i;
uint8_t finalcount[8]; uint8_t finalcount[8];
@@ -222,11 +253,11 @@ void crypto_SHA1_Final(SHA1_CTX* context, uint8_t* digest)
finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)] finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
>> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */
} }
crypto_SHA1_Update(context, (uint8_t *)"\200", 1); SHA1_Update(context, (uint8_t *)"\200", 1);
while ((context->count[0] & 504) != 448) { while ((context->count[0] & 504) != 448) {
crypto_SHA1_Update(context, (uint8_t *)"\0", 1); SHA1_Update(context, (uint8_t *)"\0", 1);
} }
crypto_SHA1_Update(context, finalcount, 8); /* Should cause a SHA1_Transform() */ SHA1_Update(context, finalcount, 8); /* Should cause a SHA1_Transform() */
for (i = 0; i < SHA1_DIGEST_SIZE; i++) { for (i = 0; i < SHA1_DIGEST_SIZE; i++) {
digest[i] = (uint8_t) digest[i] = (uint8_t)
((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255); ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
@@ -244,11 +275,118 @@ void crypto_SHA1_Final(SHA1_CTX* context, uint8_t* digest)
#endif #endif
} }
/*************************************************************/
void crypto_SHA1(const uint8_t* data, size_t len, uint8_t* digest) #if 0
int main(int argc, char** argv)
{ {
SHA1_CTX ctx; int i, j;
crypto_SHA1_Init(&ctx); SHA1_CTX context;
crypto_SHA1_Update(&ctx, data, len); unsigned char digest[SHA1_DIGEST_SIZE], buffer[16384];
crypto_SHA1_Final(&ctx, digest); 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 */
}
#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 */

View File

@@ -5,8 +5,8 @@
* SHA-1 hash API. * SHA-1 hash API.
*/ */
#ifndef __LIBSTROPHE_SHA1_H__ #ifndef __SHA1_H
#define __LIBSTROPHE_SHA1_H__ #define __SHA1_H
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@@ -23,14 +23,12 @@ typedef struct {
#define SHA1_DIGEST_SIZE 20 #define SHA1_DIGEST_SIZE 20
void crypto_SHA1_Init(SHA1_CTX* context); void SHA1_Init(SHA1_CTX* context);
void crypto_SHA1_Update(SHA1_CTX* context, const uint8_t* data, void SHA1_Update(SHA1_CTX* context, const uint8_t* data, const size_t len);
const size_t len); void SHA1_Final(SHA1_CTX* context, uint8_t digest[SHA1_DIGEST_SIZE]);
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 #ifdef __cplusplus
} }
#endif #endif
#endif /* __LIBSTROPHE_SHA1_H__ */ #endif /* __SHA1_H */

View File

@@ -64,27 +64,49 @@
/* JAM: changed declarations to xmpp_snprintf and xmpp_vsnprintf to /* JAM: changed declarations to xmpp_snprintf and xmpp_vsnprintf to
avoid namespace collision. */ avoid namespace collision. */
#include "snprintf.h" #if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF)
/* 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 <string.h>
#include <ctype.h> #include <ctype.h>
#include <sys/types.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 #ifdef HAVE_LONG_DOUBLE
#define LDOUBLE long double #define LDOUBLE long double
#else #else
#define LDOUBLE double #define LDOUBLE double
#endif #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, static int dopr (char *buffer, size_t maxlen, const char *format,
va_list args); va_list args);
static int fmtstr (char *buffer, size_t *currlen, size_t maxlen, static int fmtstr (char *buffer, size_t *currlen, size_t maxlen,
@@ -286,7 +308,6 @@ static int dopr (char *buffer, size_t maxlen, const char *format, va_list args)
break; break;
case 'X': case 'X':
flags |= DP_F_UP; flags |= DP_F_UP;
//-fallthrough
case 'x': case 'x':
flags |= DP_F_UNSIGNED; flags |= DP_F_UNSIGNED;
if (cflags == DP_C_SHORT) if (cflags == DP_C_SHORT)
@@ -307,7 +328,6 @@ static int dopr (char *buffer, size_t maxlen, const char *format, va_list args)
break; break;
case 'E': case 'E':
flags |= DP_F_UP; flags |= DP_F_UP;
//-fallthrough
case 'e': case 'e':
if (cflags == DP_C_LDOUBLE) if (cflags == DP_C_LDOUBLE)
fvalue = va_arg (args, LDOUBLE); fvalue = va_arg (args, LDOUBLE);
@@ -316,7 +336,6 @@ static int dopr (char *buffer, size_t maxlen, const char *format, va_list args)
break; break;
case 'G': case 'G':
flags |= DP_F_UP; flags |= DP_F_UP;
//-fallthrough
case 'g': case 'g':
if (cflags == DP_C_LDOUBLE) if (cflags == DP_C_LDOUBLE)
fvalue = va_arg (args, LDOUBLE); fvalue = va_arg (args, LDOUBLE);
@@ -378,7 +397,7 @@ static int dopr (char *buffer, size_t maxlen, const char *format, va_list args)
break; /* some picky compilers need this */ break; /* some picky compilers need this */
} }
} }
if (buffer != NULL && maxlen > 0) if (buffer != NULL)
{ {
if (currlen < maxlen - 1) if (currlen < maxlen - 1)
buffer[currlen] = '\0'; buffer[currlen] = '\0';
@@ -706,9 +725,10 @@ static int dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c)
return 1; return 1;
} }
#ifndef HAVE_VSNPRINTF
int xmpp_vsnprintf (char *str, size_t count, const char *fmt, va_list args) int xmpp_vsnprintf (char *str, size_t count, const char *fmt, va_list args)
{ {
if (str != NULL && count > 0) if (str != NULL)
str[0] = 0; str[0] = 0;
return dopr(str, count, fmt, args); return dopr(str, count, fmt, args);
} }
@@ -716,14 +736,104 @@ int xmpp_vsnprintf (char *str, size_t count, const char *fmt, va_list args)
#ifndef HAVE_SNPRINTF #ifndef HAVE_SNPRINTF
/* VARARGS3 */ /* VARARGS3 */
#ifdef HAVE_STDARGS
int xmpp_snprintf (char *str,size_t count,const char *fmt,...) 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; VA_LOCAL_DECL;
int total; int total;
VA_START (fmt); VA_START (fmt);
VA_SHIFT (str, char *);
VA_SHIFT (count, size_t );
VA_SHIFT (fmt, char *);
total = xmpp_vsnprintf(str, count, fmt, ap); total = xmpp_vsnprintf(str, count, fmt, ap);
VA_END; VA_END;
return total; return total;
} }
#endif /* !HAVE_SNPRINTF */ #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 */

View File

@@ -1,34 +0,0 @@
/*
* 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__ */

View File

@@ -21,20 +21,24 @@
#ifdef _WIN32 #ifdef _WIN32
#include <winsock2.h> #include <winsock2.h>
#include <ws2tcpip.h> #include <ws2tcpip.h>
#include <windns.h>
#include <Iphlpapi.h> #include <Iphlpapi.h>
#include <Mstcpip.h> /* tcp_keepalive */ #define snprintf _snprintf
#else #else
#include <errno.h> #include <errno.h>
#include <unistd.h> #include <unistd.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <netinet/tcp.h>
#include <netdb.h> #include <netdb.h>
#include <fcntl.h> #include <fcntl.h>
#include <arpa/nameser.h>
#ifdef HAVE_ARPA_NAMESER_COMPAT_H
#include <arpa/nameser_compat.h>
#endif
#include <resolv.h>
#endif #endif
#include "sock.h" #include "sock.h"
#include "snprintf.h"
void sock_initialize(void) void sock_initialize(void)
{ {
@@ -65,127 +69,49 @@ static int _in_progress(int error)
#ifdef _WIN32 #ifdef _WIN32
return (error == WSAEWOULDBLOCK || error == WSAEINPROGRESS); return (error == WSAEWOULDBLOCK || error == WSAEINPROGRESS);
#else #else
return (error == EINPROGRESS); return (errno == EINPROGRESS);
#endif #endif
} }
sock_t sock_connect(const char * const host, const unsigned short port) sock_t sock_connect(const char * const host, const unsigned int port)
{ {
sock_t sock; sock_t sock;
char service[6]; char service[6];
struct addrinfo *res, *ainfo, hints; struct addrinfo *res, *ainfo, hints;
int err; int err;
xmpp_snprintf(service, 6, "%u", port); sock = -1;
snprintf(service, 6, "%u", port);
memset(&hints, 0, sizeof(struct addrinfo)); memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC; hints.ai_family = AF_INET;
#ifdef AI_ADDRCONFIG
hints.ai_flags = AI_ADDRCONFIG;
#endif /* AI_ADDRCONFIG */
hints.ai_protocol = IPPROTO_TCP; hints.ai_protocol = IPPROTO_TCP;
hints.ai_socktype = SOCK_STREAM; hints.ai_socktype = SOCK_STREAM;
err = getaddrinfo(host, service, &hints, &res); if ((err = getaddrinfo(host, service, &hints, &res)) != 0)
if (err != 0)
return -1; return -1;
for (ainfo = res; ainfo != NULL; ainfo = ainfo->ai_next) { ainfo = res;
sock = socket(ainfo->ai_family, ainfo->ai_socktype, ainfo->ai_protocol); while (ainfo) {
if (sock < 0) if ((sock = socket(ainfo->ai_family, ainfo->ai_socktype,
continue; ainfo->ai_protocol)) >= 0) {
sock_set_nonblocking(sock);
err = sock_set_nonblocking(sock);
if (err == 0) {
err = connect(sock, ainfo->ai_addr, ainfo->ai_addrlen); err = connect(sock, ainfo->ai_addr, ainfo->ai_addrlen);
if (err == 0 || _in_progress(sock_error()))
if ((err == 0) || (err < 0 && _in_progress(sock_error())))
break; break;
} }
sock_close(sock);
ainfo = ainfo->ai_next;
} }
freeaddrinfo(res);
sock = ainfo == NULL ? -1 : sock; if (res) freeaddrinfo(res);
return sock; return sock;
} }
sock_t sock_listen(const unsigned short port)
{
struct sockaddr_in addr;
sock_t sock;
int rc;
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) return -1;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = INADDR_ANY;
rc = bind(sock, (struct sockaddr *)&addr, sizeof(addr));
if (rc == 0) {
rc = listen(sock, 100);
sock_set_nonblocking(sock);
}
if (rc != 0) close(sock);
return rc == 0 ? sock : -1;
}
int sock_stop_listen(const sock_t sock)
{
return sock_close(sock);
}
sock_t sock_accept(const sock_t sock)
{
sock_t fd;
fd = accept(sock, NULL, NULL);
return fd;
}
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) int sock_close(const sock_t sock)
{ {
#ifdef _WIN32 #ifdef _WIN32
@@ -201,13 +127,7 @@ int sock_set_blocking(const sock_t sock)
u_long block = 0; u_long block = 0;
return ioctlsocket(sock, FIONBIO, &block); return ioctlsocket(sock, FIONBIO, &block);
#else #else
int rc; return fcntl(sock, F_SETFL, 0);
rc = fcntl(sock, F_GETFL, NULL);
if (rc >= 0) {
rc = fcntl(sock, F_SETFL, rc & (~O_NONBLOCK));
}
return rc;
#endif #endif
} }
@@ -217,13 +137,7 @@ int sock_set_nonblocking(const sock_t sock)
u_long nonblock = 1; u_long nonblock = 1;
return ioctlsocket(sock, FIONBIO, &nonblock); return ioctlsocket(sock, FIONBIO, &nonblock);
#else #else
int rc; return fcntl(sock, F_SETFL, O_NONBLOCK);
rc = fcntl(sock, F_GETFL, NULL);
if (rc >= 0) {
rc = fcntl(sock, F_SETFL, rc | O_NONBLOCK);
}
return rc;
#endif #endif
} }
@@ -250,11 +164,11 @@ int sock_is_recoverable(const int error)
int sock_connect_error(const sock_t sock) int sock_connect_error(const sock_t sock)
{ {
struct sockaddr sa; struct sockaddr sa;
socklen_t len; unsigned len;
char temp; char temp;
memset(&sa, 0, sizeof(sa)); sa.sa_family = AF_INET;
sa.sa_family = AF_UNSPEC;
len = sizeof(sa); len = sizeof(sa);
/* we don't actually care about the peer name, we're just checking if /* we don't actually care about the peer name, we're just checking if
@@ -277,3 +191,720 @@ int sock_connect_error(const sock_t sock)
return sock_error(); 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;
}

View File

@@ -30,11 +30,8 @@ void sock_shutdown(void);
int sock_error(void); int sock_error(void);
sock_t sock_connect(const char * const host, const unsigned short port); sock_t sock_connect(const char * const host, const unsigned int port);
int sock_close(const sock_t sock); int sock_close(const sock_t sock);
sock_t sock_listen(const unsigned short port);
int sock_stop_listen(const sock_t sock);
sock_t sock_accept(const sock_t sock);
int sock_set_blocking(const sock_t sock); int sock_set_blocking(const sock_t sock);
int sock_set_nonblocking(const sock_t sock); int sock_set_nonblocking(const sock_t sock);
@@ -43,6 +40,9 @@ int sock_write(const sock_t sock, const void * const buff, const size_t len);
int sock_is_recoverable(const int error); int sock_is_recoverable(const int error);
/* checks for an error after connect, return 0 if connect successful */ /* checks for an error after connect, return 0 if connect successful */
int sock_connect_error(const sock_t sock); int sock_connect_error(const sock_t sock);
int sock_set_keepalive(const sock_t sock, int timeout, int interval);
int sock_srv_lookup(const char *service, const char *proto,
const char *domain, char *resulttarget,
int resulttargetlength, int *resultport);
#endif /* __LIBSTROPHE_SOCK_H__ */ #endif /* __LIBSTROPHE_SOCK_H__ */

View File

@@ -23,8 +23,12 @@
#include "common.h" #include "common.h"
#include "hash.h" #include "hash.h"
#ifdef _WIN32
#define inline __inline
#endif
/** Create a stanza object. /** Create a stanza object.
* This function allocates and initializes a blank stanza object. * This function allocates and initializes and blank stanza object.
* The stanza will have a reference count of one, so the caller does not * The stanza will have a reference count of one, so the caller does not
* need to clone it. * need to clone it.
* *
@@ -70,35 +74,6 @@ xmpp_stanza_t *xmpp_stanza_clone(xmpp_stanza_t * const stanza)
return 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. /** Copy a stanza and its children.
* This function copies a stanza along with all its children and returns * 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 * the new stanza and children with a reference count of 1. The returned
@@ -114,6 +89,9 @@ static int _stanza_copy_attributes(xmpp_stanza_t * dst,
xmpp_stanza_t *xmpp_stanza_copy(const xmpp_stanza_t * const stanza) xmpp_stanza_t *xmpp_stanza_copy(const xmpp_stanza_t * const stanza)
{ {
xmpp_stanza_t *copy, *child, *copychild, *tail; xmpp_stanza_t *copy, *child, *copychild, *tail;
hash_iterator_t *iter;
const char *key;
void *val;
copy = xmpp_stanza_new(stanza->ctx); copy = xmpp_stanza_new(stanza->ctx);
if (!copy) goto copy_error; if (!copy) goto copy_error;
@@ -126,9 +104,20 @@ xmpp_stanza_t *xmpp_stanza_copy(const xmpp_stanza_t * const stanza)
} }
if (stanza->attributes) { if (stanza->attributes) {
if (_stanza_copy_attributes(copy, stanza) == -1) 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; goto copy_error;
} }
hash_iter_release(iter);
}
tail = copy->children; tail = copy->children;
for (child = stanza->children; child; child = child->next) { for (child = stanza->children; child; child = child->next) {
@@ -215,7 +204,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 /* Escape a string with for use in a XML text node or attribute. Assumes that
* the input string is encoded in UTF-8. On success, returns a pointer to a * the input string is encoded in UTF-8. On sucess, returns a pointer to a
* buffer with the resulting data which must be xmpp_free()'d by the caller. * buffer with the resulting data which must be xmpp_free()'d by the caller.
* On failure, returns NULL. * On failure, returns NULL.
*/ */
@@ -273,13 +262,13 @@ static char *_escape_xml(xmpp_ctx_t * const ctx, char *text)
} }
/* small helper function */ /* small helper function */
static void _render_update(int *written, const int length, static inline void _render_update(int *written, const int length,
const int lastwrite, const int lastwrite,
size_t *left, char **ptr) size_t *left, char **ptr)
{ {
*written += lastwrite; *written += lastwrite;
if (*written >= length) { if (*written > length) {
*left = 0; *left = 0;
*ptr = NULL; *ptr = NULL;
} else { } else {
@@ -290,7 +279,7 @@ static void _render_update(int *written, const int length,
/* always returns number of bytes written or that would have been /* always returns number of bytes written or that would have been
* written if the buffer was large enough * written if the buffer was large enough
* return values < 0 indicate some error occurred, * return values < 0 indicate some error occured,
* and return values > buflen indicate buffer was not large enough * and return values > buflen indicate buffer was not large enough
*/ */
static int _render_stanza_recursive(xmpp_stanza_t *stanza, static int _render_stanza_recursive(xmpp_stanza_t *stanza,
@@ -320,7 +309,7 @@ static int _render_stanza_recursive(xmpp_stanza_t *stanza,
} else { /* stanza->type == XMPP_STANZA_TAG */ } else { /* stanza->type == XMPP_STANZA_TAG */
if (!stanza->data) return XMPP_EINVOP; if (!stanza->data) return XMPP_EINVOP;
/* write beginning of tag and attributes */ /* write begining of tag and attributes */
ret = xmpp_snprintf(ptr, left, "<%s", stanza->data); ret = xmpp_snprintf(ptr, left, "<%s", stanza->data);
if (ret < 0) return XMPP_EMEM; if (ret < 0) return XMPP_EMEM;
_render_update(&written, buflen, ret, &left, &ptr); _render_update(&written, buflen, ret, &left, &ptr);
@@ -423,7 +412,7 @@ int xmpp_stanza_to_text(xmpp_stanza_t *stanza,
ret = _render_stanza_recursive(stanza, buffer, length); ret = _render_stanza_recursive(stanza, buffer, length);
if (ret < 0) return ret; if (ret < 0) return ret;
if ((size_t)ret > length - 1) { if (ret > length - 1) {
tmp = xmpp_realloc(stanza->ctx, buffer, ret + 1); tmp = xmpp_realloc(stanza->ctx, buffer, ret + 1);
if (!tmp) { if (!tmp) {
xmpp_free(stanza->ctx, buffer); xmpp_free(stanza->ctx, buffer);
@@ -435,7 +424,7 @@ int xmpp_stanza_to_text(xmpp_stanza_t *stanza,
buffer = tmp; buffer = tmp;
ret = _render_stanza_recursive(stanza, buffer, length); ret = _render_stanza_recursive(stanza, buffer, length);
if ((size_t)ret > length - 1) return XMPP_EMEM; if (ret > length - 1) return XMPP_EMEM;
} }
buffer[length - 1] = 0; buffer[length - 1] = 0;
@@ -466,7 +455,7 @@ int xmpp_stanza_set_name(xmpp_stanza_t *stanza,
stanza->type = XMPP_STANZA_TAG; stanza->type = XMPP_STANZA_TAG;
stanza->data = xmpp_strdup(stanza->ctx, name); stanza->data = xmpp_strdup(stanza->ctx, name);
return stanza->data == NULL ? XMPP_EMEM : XMPP_EOK; return XMPP_EOK;
} }
/** Get the stanza name. /** Get the stanza name.
@@ -479,7 +468,7 @@ int xmpp_stanza_set_name(xmpp_stanza_t *stanza,
* *
* @ingroup Stanza * @ingroup Stanza
*/ */
const char *xmpp_stanza_get_name(xmpp_stanza_t * const stanza) char *xmpp_stanza_get_name(xmpp_stanza_t * const stanza)
{ {
if (stanza->type == XMPP_STANZA_TEXT) return NULL; if (stanza->type == XMPP_STANZA_TEXT) return NULL;
return stanza->data; return stanza->data;
@@ -562,7 +551,6 @@ int xmpp_stanza_set_attribute(xmpp_stanza_t * const stanza,
const char * const value) const char * const value)
{ {
char *val; char *val;
int rc;
if (stanza->type != XMPP_STANZA_TAG) return XMPP_EINVOP; if (stanza->type != XMPP_STANZA_TAG) return XMPP_EINVOP;
@@ -572,16 +560,9 @@ int xmpp_stanza_set_attribute(xmpp_stanza_t * const stanza,
} }
val = xmpp_strdup(stanza->ctx, value); val = xmpp_strdup(stanza->ctx, value);
if (!val) { if (!val) return XMPP_EMEM;
hash_release(stanza->attributes);
return XMPP_EMEM;
}
rc = hash_add(stanza->attributes, key, val); hash_add(stanza->attributes, key, val);
if (rc < 0) {
xmpp_free(stanza->ctx, val);
return XMPP_EMEM;
}
return XMPP_EOK; return XMPP_EOK;
} }
@@ -658,11 +639,11 @@ int xmpp_stanza_set_text(xmpp_stanza_t *stanza,
if (stanza->data) xmpp_free(stanza->ctx, stanza->data); if (stanza->data) xmpp_free(stanza->ctx, stanza->data);
stanza->data = xmpp_strdup(stanza->ctx, text); stanza->data = xmpp_strdup(stanza->ctx, text);
return stanza->data == NULL ? XMPP_EMEM : XMPP_EOK; return XMPP_EOK;
} }
/** Set the text data for a text stanza. /** Set the text data for a text stanza.
* This function copies the text given and sets the stanza object's text to * This function copies the text given and sets teh stanza object's text to
* it. Attempting to use this function on a stanza that has a name will * it. Attempting to use this function on a stanza that has a name will
* fail with XMPP_EINVOP. This function takes the text as buffer and a length * fail with XMPP_EINVOP. This function takes the text as buffer and a length
* as opposed to a null-terminated string. * as opposed to a null-terminated string.
@@ -703,9 +684,15 @@ int xmpp_stanza_set_text_with_size(xmpp_stanza_t *stanza,
* *
* @ingroup Stanza * @ingroup Stanza
*/ */
const char *xmpp_stanza_get_id(xmpp_stanza_t * const stanza) char *xmpp_stanza_get_id(xmpp_stanza_t * const stanza)
{ {
return xmpp_stanza_get_attribute(stanza, "id"); if (stanza->type != XMPP_STANZA_TAG)
return NULL;
if (!stanza->attributes)
return NULL;
return (char *)hash_get(stanza->attributes, "id");
} }
/** Get the namespace attribute of the stanza object. /** Get the namespace attribute of the stanza object.
@@ -718,9 +705,15 @@ const char *xmpp_stanza_get_id(xmpp_stanza_t * const stanza)
* *
* @ingroup Stanza * @ingroup Stanza
*/ */
const char *xmpp_stanza_get_ns(xmpp_stanza_t * const stanza) char *xmpp_stanza_get_ns(xmpp_stanza_t * const stanza)
{ {
return xmpp_stanza_get_attribute(stanza, "xmlns"); if (stanza->type != XMPP_STANZA_TAG)
return NULL;
if (!stanza->attributes)
return NULL;
return (char *)hash_get(stanza->attributes, "xmlns");
} }
/** Get the 'type' attribute of the stanza object. /** Get the 'type' attribute of the stanza object.
@@ -733,39 +726,15 @@ const char *xmpp_stanza_get_ns(xmpp_stanza_t * const stanza)
* *
* @ingroup Stanza * @ingroup Stanza
*/ */
const char *xmpp_stanza_get_type(xmpp_stanza_t * const stanza) char *xmpp_stanza_get_type(xmpp_stanza_t * const stanza)
{ {
return xmpp_stanza_get_attribute(stanza, "type"); if (stanza->type != XMPP_STANZA_TAG)
} return NULL;
/** Get the 'to' attribute of the stanza object. if (!stanza->attributes)
* This is a convenience function equivalent to: return NULL;
* 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. return (char *)hash_get(stanza->attributes, "type");
* 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. /** Get the first child of stanza with name.
@@ -908,7 +877,7 @@ char *xmpp_stanza_get_text(xmpp_stanza_t * const stanza)
* *
* @ingroup Stanza * @ingroup Stanza
*/ */
const char *xmpp_stanza_get_text_ptr(xmpp_stanza_t * const stanza) char *xmpp_stanza_get_text_ptr(xmpp_stanza_t * const stanza)
{ {
if (stanza->type == XMPP_STANZA_TEXT) if (stanza->type == XMPP_STANZA_TEXT)
return stanza->data; return stanza->data;
@@ -950,42 +919,6 @@ int xmpp_stanza_set_type(xmpp_stanza_t * const stanza,
return xmpp_stanza_set_attribute(stanza, "type", type); 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. /** Get an attribute from a stanza.
* This function returns a pointer to the attribute value. If the caller * This function returns a pointer to the attribute value. If the caller
* wishes to save this value it must make its own copy. * wishes to save this value it must make its own copy.
@@ -997,7 +930,7 @@ int xmpp_stanza_set_from(xmpp_stanza_t * const stanza,
* *
* @ingroup Stanza * @ingroup Stanza
*/ */
const char *xmpp_stanza_get_attribute(xmpp_stanza_t * const stanza, char *xmpp_stanza_get_attribute(xmpp_stanza_t * const stanza,
const char * const name) const char * const name)
{ {
if (stanza->type != XMPP_STANZA_TAG) if (stanza->type != XMPP_STANZA_TAG)
@@ -1008,213 +941,3 @@ const char *xmpp_stanza_get_attribute(xmpp_stanza_t * const stanza,
return hash_get(stanza->attributes, name); 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 Normal file
View File

@@ -0,0 +1,116 @@
/* 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 Normal file
View File

@@ -0,0 +1,40 @@
/* 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__ */

View File

@@ -24,7 +24,7 @@ typedef struct _tls tls_t;
void tls_initialize(void); void tls_initialize(void);
void tls_shutdown(void); void tls_shutdown(void);
tls_t *tls_new(xmpp_conn_t *conn); tls_t *tls_new(xmpp_ctx_t *ctx, sock_t sock);
void tls_free(tls_t *tls); void tls_free(tls_t *tls);
int tls_set_credentials(tls_t *tls, const char *cafilename); int tls_set_credentials(tls_t *tls, const char *cafilename);

View File

@@ -33,7 +33,7 @@ void tls_shutdown(void)
return; return;
} }
tls_t *tls_new(xmpp_conn_t *conn) tls_t *tls_new(xmpp_ctx_t *ctx, sock_t sock)
{ {
/* always fail */ /* always fail */
return NULL; return NULL;

View File

@@ -19,15 +19,11 @@
#include "tls.h" #include "tls.h"
#include "sock.h" #include "sock.h"
/* FIXME this shouldn't be a constant string */
#define CAFILE "/etc/ssl/certs/ca-certificates.crt"
struct _tls { struct _tls {
xmpp_ctx_t *ctx; /* do we need this? */ xmpp_ctx_t *ctx; /* do we need this? */
sock_t sock; sock_t sock;
gnutls_session_t session; gnutls_session_t session;
gnutls_certificate_credentials_t cred; gnutls_certificate_credentials_t cred;
int lasterror;
}; };
void tls_initialize(void) void tls_initialize(void)
@@ -46,22 +42,25 @@ void tls_shutdown(void)
gnutls_global_deinit(); gnutls_global_deinit();
} }
tls_t *tls_new(xmpp_conn_t *conn) tls_t *tls_new(xmpp_ctx_t *ctx, sock_t sock)
{ {
tls_t *tls = xmpp_alloc(conn->ctx, sizeof(tls_t)); tls_t *tls = xmpp_alloc(ctx, sizeof(tls_t));
const int cert_type_priority[3] = { GNUTLS_CRT_X509,
GNUTLS_CRT_OPENPGP, 0 };
if (tls) { if (tls) {
tls->ctx = conn->ctx; tls->ctx = ctx;
tls->sock = conn->sock; tls->sock = sock;
gnutls_init(&tls->session, GNUTLS_CLIENT); gnutls_init(&tls->session, GNUTLS_CLIENT);
gnutls_certificate_allocate_credentials(&tls->cred); gnutls_certificate_allocate_credentials(&tls->cred);
tls_set_credentials(tls, CAFILE);
gnutls_set_default_priority(tls->session); gnutls_set_default_priority(tls->session);
gnutls_certificate_type_set_priority(tls->session, cert_type_priority);
/* fixme: this may require setting a callback on win32? */ /* fixme: this may require setting a callback on win32? */
gnutls_transport_set_int(tls->session, conn->sock); gnutls_transport_set_ptr(tls->session,
(gnutls_transport_ptr_t)sock);
} }
return tls; return tls;
@@ -81,38 +80,28 @@ int tls_set_credentials(tls_t *tls, const char *cafilename)
/* set trusted credentials -- takes a .pem filename */ /* set trusted credentials -- takes a .pem filename */
err = gnutls_certificate_set_x509_trust_file(tls->cred, err = gnutls_certificate_set_x509_trust_file(tls->cred,
cafilename, GNUTLS_X509_FMT_PEM); cafilename, GNUTLS_X509_FMT_PEM);
if (err >= 0) { if (err < 0) return err;
err = gnutls_credentials_set(tls->session, GNUTLS_CRD_CERTIFICATE, err = gnutls_credentials_set(tls->session, GNUTLS_CRD_CERTIFICATE,
tls->cred); tls->cred);
}
tls->lasterror = err;
return err == GNUTLS_E_SUCCESS; return err;
} }
int tls_start(tls_t *tls) int tls_start(tls_t *tls)
{ {
sock_set_blocking(tls->sock); return gnutls_handshake(tls->session);
tls->lasterror = gnutls_handshake(tls->session);
sock_set_nonblocking(tls->sock);
return tls->lasterror == GNUTLS_E_SUCCESS;
} }
int tls_stop(tls_t *tls) int tls_stop(tls_t *tls)
{ {
tls->lasterror = gnutls_bye(tls->session, GNUTLS_SHUT_RDWR); return gnutls_bye(tls->session, GNUTLS_SHUT_RDWR);
return tls->lasterror == GNUTLS_E_SUCCESS;
} }
int tls_error(tls_t *tls) int tls_error(tls_t *tls)
{ {
return tls->lasterror; /* todo: some kind of error polling/dump */
} return 0;
int tls_is_recoverable(int error)
{
return !gnutls_error_is_fatal(error);
} }
int tls_pending(tls_t *tls) int tls_pending(tls_t *tls)
@@ -125,7 +114,6 @@ int tls_read(tls_t *tls, void * const buff, const size_t len)
int ret; int ret;
ret = gnutls_record_recv(tls->session, buff, len); ret = gnutls_record_recv(tls->session, buff, len);
tls->lasterror = ret < 0 ? ret : 0;
return ret; return ret;
} }
@@ -135,12 +123,7 @@ int tls_write(tls_t *tls, const void * const buff, const size_t len)
int ret; int ret;
ret = gnutls_record_send(tls->session, buff, len); ret = gnutls_record_send(tls->session, buff, len);
tls->lasterror = ret < 0 ? ret : 0;
return ret; return ret;
} }
int tls_clear_pending_write(tls_t *tls)
{
return 0;
}

View File

@@ -13,7 +13,6 @@
* TLS implementation with OpenSSL. * TLS implementation with OpenSSL.
*/ */
#include <errno.h> /* EINTR */
#include <string.h> #include <string.h>
#ifndef _WIN32 #ifndef _WIN32
@@ -23,10 +22,6 @@
#endif #endif
#include <openssl/ssl.h> #include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/opensslv.h>
#include <openssl/x509v3.h>
#include "common.h" #include "common.h"
#include "tls.h" #include "tls.h"
#include "sock.h" #include "sock.h"
@@ -39,46 +34,15 @@ struct _tls {
int lasterror; 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) void tls_initialize(void)
{ {
#if OPENSSL_VERSION_NUMBER < 0x10100000L
SSL_library_init(); SSL_library_init();
SSL_load_error_strings(); SSL_load_error_strings();
#else
OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL);
#endif
} }
void tls_shutdown(void) void tls_shutdown(void)
{ {
/* return;
* FIXME: Don't free global tables, program or other libraries may use
* openssl after libstrophe finalization. Maybe better leak some fixed
* memory rather than cause random crashes of the main program.
*/
#if OPENSSL_VERSION_NUMBER < 0x10100000L
ERR_free_strings();
EVP_cleanup();
CRYPTO_cleanup_all_ex_data();
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
SSL_COMP_free_compression_methods();
#endif
#if OPENSSL_VERSION_NUMBER < 0x10000000L
ERR_remove_state(0);
#else
ERR_remove_thread_state(NULL);
#endif
#endif
} }
int tls_error(tls_t *tls) int tls_error(tls_t *tls)
@@ -86,69 +50,139 @@ int tls_error(tls_t *tls)
return tls->lasterror; return tls->lasterror;
} }
tls_t *tls_new(xmpp_conn_t *conn) int
convert_ASN1TIME(ASN1_TIME *ansi_time, char* buf, size_t len)
{ {
tls_t *tls = xmpp_alloc(conn->ctx, sizeof(*tls)); BIO *bio = BIO_new(BIO_s_mem());
int mode; int rc = ASN1_TIME_print(bio, ansi_time);
if (rc <= 0) {
BIO_free(bio);
return 0;
}
rc = BIO_gets(bio, buf, len);
if (rc <= 0) {
BIO_free(bio);
return 0;
}
BIO_free(bio);
return 1;
}
void
hex_encode(unsigned char* readbuf, void *writebuf, size_t len)
{
size_t i;
for(i=0; i < len; i++) {
char *l = (char*) (2*i + ((intptr_t) writebuf));
sprintf(l, "%02x", readbuf[i]);
}
}
static xmpp_ctx_t *xmppctx;
static void
print_certificate(X509* cert) {
char subj[1024+1];
char issuer[1024+1];
X509_NAME_oneline(X509_get_subject_name(cert), subj, 1024);
X509_NAME_oneline(X509_get_issuer_name(cert), issuer, 1024);
xmpp_debug(xmppctx, "TLS", "SUBJECT : %s", subj);
xmpp_debug(xmppctx, "TLS", "ISSUER : %s", issuer);
}
static int
verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx)
{
X509 *cert = X509_STORE_CTX_get_current_cert(x509_ctx);
const STACK_OF(X509) *sk = X509_STORE_CTX_get1_chain(x509_ctx);
int slen = sk_num((const _STACK *)sk);
unsigned i;
X509 *certsk;
xmpp_debug(xmppctx, "TLS", "STACK");
for(i=0; i<slen; i++) {
certsk = (X509*) sk_value((const _STACK *)sk, i);
print_certificate(certsk);
}
xmpp_debug(xmppctx, "TLS", "ENDSTACK");
X509_NAME *subject = X509_get_subject_name(cert);
char *nameline = X509_NAME_oneline(subject, NULL, 0);
xmpp_debug(xmppctx, "TLS", "SUBJECT : %s", nameline);
OPENSSL_free(nameline);
X509_NAME *issuer = X509_get_issuer_name(cert);
nameline = X509_NAME_oneline(issuer, NULL, 0);
xmpp_debug(xmppctx, "TLS", "ISSUER : %s", nameline);
OPENSSL_free(nameline);
ASN1_TIME *not_before = X509_get_notBefore(cert);
char not_before_str[128];
int not_before_res = convert_ASN1TIME(not_before, not_before_str, 128);
if (not_before_res) {
xmpp_debug(xmppctx, "TLS", "NOT BEFORE : %s", not_before_str);
}
ASN1_TIME *not_after = X509_get_notAfter(cert);
char not_after_str[128];
int not_after_res = convert_ASN1TIME(not_after, not_after_str, 128);
if (not_after_res) {
xmpp_debug(xmppctx, "TLS", "NOT AFTER : %s", not_after_str);
}
char buf[20];
const EVP_MD *digest = EVP_sha1();
unsigned len;
int rc = X509_digest(cert, digest, (unsigned char*) buf, &len);
if (rc != 0 && len == 20) {
char strbuf[2*20+1];
hex_encode(buf, strbuf, 20);
xmpp_debug(xmppctx, "TLS", "FINGERPRINT : %s", strbuf);
}
if (preverify_ok) {
xmpp_debug(xmppctx, "TLS", "VERIFY SUCCESS");
return 1;
} else {
xmpp_debug(xmppctx, "TLS", "VERIFY FAILED");
int err = X509_STORE_CTX_get_error(x509_ctx);
const char *errstr = X509_verify_cert_error_string(err);
xmpp_debug(xmppctx, "TLS", "ERROR: %s", errstr);
return 1;
}
}
tls_t *tls_new(xmpp_ctx_t *ctx, sock_t sock)
{
xmppctx = ctx;
tls_t *tls = xmpp_alloc(ctx, sizeof(*tls));
if (tls) { if (tls) {
int ret; int ret;
memset(tls, 0, sizeof(*tls)); memset(tls, 0, sizeof(*tls));
tls->ctx = conn->ctx; tls->ctx = ctx;
tls->sock = conn->sock; tls->sock = sock;
tls->ssl_ctx = SSL_CTX_new(SSLv23_client_method()); tls->ssl_ctx = SSL_CTX_new(SSLv23_client_method());
if (tls->ssl_ctx == NULL)
goto err;
/* Enable bug workarounds. */
SSL_CTX_set_options(tls->ssl_ctx, SSL_OP_ALL);
/* Disable insecure SSL/TLS versions. */
SSL_CTX_set_options(tls->ssl_ctx, SSL_OP_NO_SSLv2); /* DROWN */
SSL_CTX_set_options(tls->ssl_ctx, SSL_OP_NO_SSLv3); /* POODLE */
SSL_CTX_set_options(tls->ssl_ctx, SSL_OP_NO_TLSv1); /* BEAST */
SSL_CTX_set_client_cert_cb(tls->ssl_ctx, NULL); SSL_CTX_set_client_cert_cb(tls->ssl_ctx, NULL);
SSL_CTX_set_mode (tls->ssl_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE); SSL_CTX_set_mode (tls->ssl_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE);
SSL_CTX_set_default_verify_paths(tls->ssl_ctx); SSL_CTX_set_verify (tls->ssl_ctx, SSL_VERIFY_PEER, verify_callback);
tls->ssl = SSL_new(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. */ ret = SSL_set_fd(tls->ssl, sock);
mode = conn->tls_trust ? SSL_VERIFY_NONE : SSL_VERIFY_PEER; if (ret <= 0) {
SSL_set_verify(tls->ssl, mode, 0); tls->lasterror = SSL_get_error(tls->ssl, ret);
#if OPENSSL_VERSION_NUMBER >= 0x10002000L tls_error(tls);
/* Hostname verification is supported in OpenSSL 1.0.2 and newer. */ tls_free(tls);
X509_VERIFY_PARAM *param = SSL_get0_param(tls->ssl); tls = NULL;
}
/*
* 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; 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) void tls_free(tls_t *tls)
@@ -156,6 +190,7 @@ void tls_free(tls_t *tls)
SSL_free(tls->ssl); SSL_free(tls->ssl);
SSL_CTX_free(tls->ssl_ctx); SSL_CTX_free(tls->ssl_ctx);
xmpp_free(tls->ctx, tls); xmpp_free(tls->ctx, tls);
return;
} }
int tls_set_credentials(tls_t *tls, const char *cafilename) int tls_set_credentials(tls_t *tls, const char *cafilename)
@@ -165,53 +200,52 @@ int tls_set_credentials(tls_t *tls, const char *cafilename)
int tls_start(tls_t *tls) int tls_start(tls_t *tls)
{ {
int error; int ret = -1;
int ret;
long x509_res;
/* Since we're non-blocking, loop the connect call until it /* Since we're non-blocking, loop the connect call until it
succeeds or fails */ succeeds or fails */
while (1) { while (ret < 0) {
ret = SSL_connect(tls->ssl); ret = SSL_connect(tls->ssl);
error = ret <= 0 ? SSL_get_error(tls->ssl, ret) : 0; int err = SSL_get_error(tls->ssl, ret);
int recoverable = tls_is_recoverable(err);
if (ret == -1 && tls_is_recoverable(error)) { // continue if recoverable
/* wait for something to happen on the sock before looping back */ if (recoverable) {
_tls_sock_wait(tls, error); fd_set fds;
continue; struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 1000;
FD_ZERO(&fds);
FD_SET(tls->sock, &fds);
select(tls->sock + 1, &fds, &fds, NULL, &tv);
} else {
ret = 1;
}
} }
/* success or fatal error */ if (ret <= 0) {
break; tls->lasterror = SSL_get_error(tls->ssl, ret);
return 0;
} }
x509_res = SSL_get_verify_result(tls->ssl); return 1;
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 tls_stop(tls_t *tls)
{ {
int retries = 0;
int error;
int ret; int ret;
while (1) {
++retries;
ret = SSL_shutdown(tls->ssl); 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 ret <= 0 ? 0 : 1; if (ret <= 0) {
tls->lasterror = SSL_get_error(tls->ssl, ret);
return 0;
}
return 1;
} }
int tls_is_recoverable(int error) int tls_is_recoverable(int error)
@@ -229,20 +263,22 @@ int tls_pending(tls_t *tls)
int tls_read(tls_t *tls, void * const buff, const size_t len) int tls_read(tls_t *tls, void * const buff, const size_t len)
{ {
int ret; int ret = SSL_read(tls->ssl, buff, len);
ret = SSL_read(tls->ssl, buff, len); if (ret <= 0) {
_tls_set_error(tls, ret <= 0 ? SSL_get_error(tls->ssl, ret) : 0); tls->lasterror = SSL_get_error(tls->ssl, ret);
}
return ret; return ret;
} }
int tls_write(tls_t *tls, const void * const buff, const size_t len) int tls_write(tls_t *tls, const void * const buff, const size_t len)
{ {
int ret; int ret = SSL_write(tls->ssl, buff, len);
ret = SSL_write(tls->ssl, buff, len); if (ret <= 0) {
_tls_set_error(tls, ret <= 0 ? SSL_get_error(tls->ssl, ret) : 0); tls->lasterror = SSL_get_error(tls->ssl, ret);
}
return ret; return ret;
} }
@@ -251,48 +287,3 @@ int tls_clear_pending_write(tls_t *tls)
{ {
return 0; 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);
}

View File

@@ -23,7 +23,6 @@
struct _tls { struct _tls {
xmpp_ctx_t *ctx; xmpp_ctx_t *ctx;
xmpp_conn_t *conn;
sock_t sock; sock_t sock;
HANDLE hsec32; HANDLE hsec32;
@@ -61,10 +60,8 @@ void tls_shutdown(void)
return; return;
} }
tls_t *tls_new(xmpp_conn_t *conn) tls_t *tls_new(xmpp_ctx_t *ctx, sock_t sock)
{ {
xmpp_ctx_t *ctx = conn->ctx;
sock_t sock = conn->sock;
tls_t *tls; tls_t *tls;
PSecurityFunctionTable (*pInitSecurityInterface)(void); PSecurityFunctionTable (*pInitSecurityInterface)(void);
SCHANNEL_CRED scred; SCHANNEL_CRED scred;
@@ -95,7 +92,6 @@ tls_t *tls_new(xmpp_conn_t *conn)
memset(tls, 0, sizeof(*tls)); memset(tls, 0, sizeof(*tls));
tls->ctx = ctx; tls->ctx = ctx;
tls->conn = conn;
tls->sock = sock; tls->sock = sock;
if (!(tls->hsec32 = LoadLibrary ("secur32.dll"))) { if (!(tls->hsec32 = LoadLibrary ("secur32.dll"))) {
@@ -129,16 +125,10 @@ tls_t *tls_new(xmpp_conn_t *conn)
memset(&scred, 0, sizeof(scred)); memset(&scred, 0, sizeof(scred));
scred.dwVersion = SCHANNEL_CRED_VERSION; scred.dwVersion = SCHANNEL_CRED_VERSION;
/*scred.grbitEnabledProtocols = SP_PROT_TLS1_CLIENT;*/ /*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 */ /* Something down the line doesn't like AES, so force it to RC4 */
algs[0] = CALG_RC4; algs[0] = CALG_RC4;
scred.cSupportedAlgs = 1; scred.cSupportedAlgs = 1;
scred.palgSupportedAlgs = algs; scred.palgSupportedAlgs = algs;
#else
(void)algs;
#endif
ret = tls->sft->AcquireCredentialsHandleA(NULL, UNISP_NAME, ret = tls->sft->AcquireCredentialsHandleA(NULL, UNISP_NAME,
SECPKG_CRED_OUTBOUND, NULL, &scred, NULL, NULL, &(tls->hcred), NULL); SECPKG_CRED_OUTBOUND, NULL, &scred, NULL, NULL, &(tls->hcred), NULL);
@@ -220,10 +210,24 @@ int tls_start(tls_t *tls)
SecBuffer sbin[2], sbout[1]; SecBuffer sbin[2], sbout[1];
SECURITY_STATUS ret; SECURITY_STATUS ret;
int sent; int sent;
char *name; char *name = NULL;
/* use the domain there as our name */ /* search the ctx's conns for our sock, and use the domain there as our
name = tls->conn->domain; * 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;
}
}
}
ctxtreq = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT ctxtreq = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT
| ISC_REQ_CONFIDENTIALITY | ISC_RET_EXTENDED_ERROR | ISC_REQ_CONFIDENTIALITY | ISC_RET_EXTENDED_ERROR
@@ -350,7 +354,6 @@ int tls_start(tls_t *tls)
if (ret != SEC_E_OK) { if (ret != SEC_E_OK) {
tls->lasterror = ret; tls->lasterror = ret;
xmpp_error(tls->ctx, "TLSS", "Schannel error 0x%lx", (unsigned long)ret);
return 0; return 0;
} }
@@ -560,6 +563,7 @@ int tls_write(tls_t *tls, const void * const buff, const size_t len)
{ {
SecBufferDesc sbdenc; SecBufferDesc sbdenc;
SecBuffer sbenc[4]; SecBuffer sbenc[4];
unsigned char *sendbuffer;
const unsigned char *p = buff; const unsigned char *p = buff;
int sent = 0, ret, remain = len; int sent = 0, ret, remain = len;

View File

@@ -55,28 +55,6 @@ char *xmpp_strdup(const xmpp_ctx_t * const ctx, const char * const s)
return copy; 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. /** Return an integer based time stamp.
* This function uses gettimeofday or timeGetTime (on Win32 platforms) to * This function uses gettimeofday or timeGetTime (on Win32 platforms) to
* compute an integer based time stamp. This is used internally by the * compute an integer based time stamp. This is used internally by the

View File

@@ -18,12 +18,6 @@
#include "ostypes.h" #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 */ /* timing functions */
uint64_t time_stamp(void); uint64_t time_stamp(void);
uint64_t time_elapsed(uint64_t t1, uint64_t t2); uint64_t time_elapsed(uint64_t t1, uint64_t t2);

View File

@@ -1,73 +0,0 @@
/* 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;
}

180
strophe.h
View File

@@ -16,12 +16,12 @@
#ifndef __LIBSTROPHE_STROPHE_H__ #ifndef __LIBSTROPHE_STROPHE_H__
#define __LIBSTROPHE_STROPHE_H__ #define __LIBSTROPHE_STROPHE_H__
#include <stddef.h> /* size_t */
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
#include <stdio.h>
/* namespace defines */ /* namespace defines */
/** @def XMPP_NS_CLIENT /** @def XMPP_NS_CLIENT
* Namespace definition for 'jabber:client'. * Namespace definition for 'jabber:client'.
@@ -118,10 +118,6 @@ 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); 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 { struct _xmpp_mem_t {
void *(*alloc)(const size_t size, void * const userdata); void *(*alloc)(const size_t size, void * const userdata);
void (*free)(void *p, void * const userdata); void (*free)(void *p, void * const userdata);
@@ -139,8 +135,7 @@ typedef enum {
typedef enum { typedef enum {
XMPP_UNKNOWN, XMPP_UNKNOWN,
XMPP_CLIENT, XMPP_CLIENT,
XMPP_COMPONENT, XMPP_COMPONENT
XMPP_INCOMING
} xmpp_conn_type_t; } xmpp_conn_type_t;
typedef void (*xmpp_log_handler)(void * const userdata, typedef void (*xmpp_log_handler)(void * const userdata,
@@ -151,6 +146,7 @@ typedef void (*xmpp_log_handler)(void * const userdata,
struct _xmpp_log_t { struct _xmpp_log_t {
xmpp_log_handler handler; xmpp_log_handler handler;
void *userdata; void *userdata;
/* mutex_t lock; */
}; };
/* return a default logger filtering at a given level */ /* return a default logger filtering at a given level */
@@ -162,19 +158,9 @@ xmpp_log_t *xmpp_get_default_logger(xmpp_log_level_t level);
typedef struct _xmpp_conn_t xmpp_conn_t; typedef struct _xmpp_conn_t xmpp_conn_t;
typedef struct _xmpp_stanza_t xmpp_stanza_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 */ /* connect callback */
typedef enum { typedef enum {
XMPP_CONN_CONNECT, XMPP_CONN_CONNECT,
XMPP_CONN_RAW_CONNECT,
XMPP_CONN_DISCONNECT, XMPP_CONN_DISCONNECT,
XMPP_CONN_FAIL XMPP_CONN_FAIL
} xmpp_conn_event_t; } xmpp_conn_event_t;
@@ -222,8 +208,6 @@ xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t * const ctx);
xmpp_conn_t * xmpp_conn_clone(xmpp_conn_t * const conn); xmpp_conn_t * xmpp_conn_clone(xmpp_conn_t * const conn);
int xmpp_conn_release(xmpp_conn_t * const conn); int xmpp_conn_release(xmpp_conn_t * const conn);
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_jid(const xmpp_conn_t * const conn);
const char *xmpp_conn_get_bound_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); void xmpp_conn_set_jid(xmpp_conn_t * const conn, const char * const jid);
@@ -231,8 +215,6 @@ const char *xmpp_conn_get_pass(const xmpp_conn_t * const conn);
void xmpp_conn_set_pass(xmpp_conn_t * const conn, const char * const pass); void xmpp_conn_set_pass(xmpp_conn_t * const conn, const char * const pass);
xmpp_ctx_t* xmpp_conn_get_context(xmpp_conn_t * const conn); xmpp_ctx_t* xmpp_conn_get_context(xmpp_conn_t * const conn);
void xmpp_conn_disable_tls(xmpp_conn_t * const conn); void xmpp_conn_disable_tls(xmpp_conn_t * const conn);
int xmpp_conn_is_secured(xmpp_conn_t * const conn);
void xmpp_conn_set_keepalive(xmpp_conn_t * const conn, int timeout, int interval);
int xmpp_connect_client(xmpp_conn_t * const conn, int xmpp_connect_client(xmpp_conn_t * const conn,
const char * const altdomain, const char * const altdomain,
@@ -244,16 +226,6 @@ int xmpp_connect_component(xmpp_conn_t * const conn, const char * const server,
unsigned short port, xmpp_conn_handler callback, unsigned short port, xmpp_conn_handler callback,
void * const userdata); 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_disconnect(xmpp_conn_t * const conn);
void xmpp_send(xmpp_conn_t * const conn, void xmpp_send(xmpp_conn_t * const conn,
@@ -264,30 +236,6 @@ void xmpp_send_raw_string(xmpp_conn_t * const conn,
void xmpp_send_raw(xmpp_conn_t * const conn, void xmpp_send_raw(xmpp_conn_t * const conn,
const char * const data, const size_t len); const char * const data, const size_t len);
/* server */
/* opaque server object */
typedef struct _xmpp_server_t xmpp_server_t;
/* server callback */
typedef enum {
XMPP_SERVER_ACCEPT,
XMPP_SERVER_OPEN_STREAM,
XMPP_SERVER_DISCONNECT,
XMPP_SERVER_FAIL
} xmpp_server_event_t;
typedef void (*xmpp_server_handler)(xmpp_server_t * const srv,
xmpp_conn_t * const conn,
const xmpp_server_event_t event,
const int error,
void * const userdata);
xmpp_server_t *xmpp_server_new(xmpp_ctx_t * const ctx);
void xmpp_server_free(xmpp_server_t * const srv);
int xmpp_server_listen(xmpp_server_t * const srv, unsigned short port,
xmpp_server_handler callback, void * const userdata);
void xmpp_server_stop(xmpp_server_t * const srv);
/* handlers */ /* handlers */
@@ -329,24 +277,28 @@ void xmpp_id_handler_delete(xmpp_conn_t * const conn,
void xmpp_register_stanza_handler(conn, stanza, xmlns, type, handler) void xmpp_register_stanza_handler(conn, stanza, xmlns, type, handler)
*/ */
/* stanzas */ /** stanzas **/
/* allocate and initialize a blank stanza */ /** allocate an initialize a blank stanza */
xmpp_stanza_t *xmpp_stanza_new(xmpp_ctx_t *ctx); 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); xmpp_stanza_t *xmpp_stanza_clone(xmpp_stanza_t * const stanza);
/* copies a stanza and all children */ /** copies a stanza and all children */
xmpp_stanza_t * xmpp_stanza_copy(const xmpp_stanza_t * const stanza); xmpp_stanza_t * xmpp_stanza_copy(const xmpp_stanza_t * const stanza);
/* free a stanza object and it's contents */ /** free a stanza object and it's contents */
int xmpp_stanza_release(xmpp_stanza_t * const stanza); int xmpp_stanza_release(xmpp_stanza_t * const stanza);
/** 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_text(xmpp_stanza_t * const stanza);
int xmpp_stanza_is_tag(xmpp_stanza_t * const stanza); int xmpp_stanza_is_tag(xmpp_stanza_t * const stanza);
/* marshall a stanza into text for transmission or display */ /** marshall a stanza into text for transmission or display **/
int xmpp_stanza_to_text(xmpp_stanza_t *stanza, int xmpp_stanza_to_text(xmpp_stanza_t *stanza,
char ** const buf, size_t * const buflen); char ** const buf, size_t * const buflen);
@@ -356,18 +308,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, xmpp_stanza_t *xmpp_stanza_get_child_by_ns(xmpp_stanza_t * const stanza,
const char * const ns); const char * const ns);
xmpp_stanza_t *xmpp_stanza_get_next(xmpp_stanza_t * const stanza); xmpp_stanza_t *xmpp_stanza_get_next(xmpp_stanza_t * const stanza);
int xmpp_stanza_add_child(xmpp_stanza_t *stanza, xmpp_stanza_t *child); char *xmpp_stanza_get_attribute(xmpp_stanza_t * const stanza,
const char *xmpp_stanza_get_attribute(xmpp_stanza_t * const stanza,
const char * const name); const char * const name);
int xmpp_stanza_get_attribute_count(xmpp_stanza_t * const stanza); char * xmpp_stanza_get_ns(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 /* concatenate all child text nodes. this function
* returns a string that must be freed by the caller */ * returns a string that must be freed by the caller */
char *xmpp_stanza_get_text(xmpp_stanza_t * const stanza); char *xmpp_stanza_get_text(xmpp_stanza_t * const stanza);
const char *xmpp_stanza_get_text_ptr(xmpp_stanza_t * const stanza); char *xmpp_stanza_get_text_ptr(xmpp_stanza_t * const stanza);
const char *xmpp_stanza_get_name(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);
/* set_attribute adds/replaces attributes */ /* set_attribute adds/replaces attributes */
int xmpp_stanza_set_attribute(xmpp_stanza_t * const stanza, int xmpp_stanza_set_attribute(xmpp_stanza_t * const stanza,
const char * const key, const char * const key,
@@ -379,83 +331,39 @@ int xmpp_stanza_set_text(xmpp_stanza_t *stanza,
int xmpp_stanza_set_text_with_size(xmpp_stanza_t *stanza, int xmpp_stanza_set_text_with_size(xmpp_stanza_t *stanza,
const char * const text, const char * const text,
const size_t size); const size_t size);
int xmpp_stanza_del_attribute(xmpp_stanza_t * const stanza,
const char * const name);
/* common stanza helpers */ /* common stanza helpers */
const char *xmpp_stanza_get_ns(xmpp_stanza_t * const stanza); char *xmpp_stanza_get_type(xmpp_stanza_t * const stanza);
const char *xmpp_stanza_get_type(xmpp_stanza_t * const stanza); char *xmpp_stanza_get_id(xmpp_stanza_t * const stanza);
const char *xmpp_stanza_get_id(xmpp_stanza_t * const stanza); int xmpp_stanza_set_id(xmpp_stanza_t * const stanza,
const char *xmpp_stanza_get_to(xmpp_stanza_t * const stanza); const char * const id);
const char *xmpp_stanza_get_from(xmpp_stanza_t * const stanza); int xmpp_stanza_set_type(xmpp_stanza_t * const stanza,
int xmpp_stanza_set_ns(xmpp_stanza_t * const stanza, const char * const ns); const char * const type);
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(xmpp_stanza_t * const stanza, const char * const to); int xmpp_stanza_set_to();
int xmpp_stanza_set_from(xmpp_stanza_t * const stanza, const char * const from); int xmpp_stanza_set_from();
*/
/* allocate and initialize a stanza in reply to another */ /* allocate and initialize a stanza in reply to another */
xmpp_stanza_t *xmpp_stanza_reply(xmpp_stanza_t * const stanza); /* unimplemented
xmpp_stanza_t *xmpp_stanza_reply(const xmpp_stanza_t *stanza);
*/
/* stanza subclasses */ /* stanza subclasses */
xmpp_stanza_t *xmpp_message_new(xmpp_ctx_t *ctx, const char * const type, /* unimplemented
const char * const to, const char * const id); void xmpp_message_new();
char *xmpp_message_get_body(xmpp_stanza_t *msg); void xmpp_message_get_body();
int xmpp_message_set_body(xmpp_stanza_t *msg, const char * const text); void xmpp_message_set_body();
xmpp_stanza_t *xmpp_iq_new(xmpp_ctx_t *ctx, const char * const type, void xmpp_iq_new();
const char * const id); void xmpp_presence_new();
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_once(xmpp_ctx_t *ctx, const unsigned long timeout);
void xmpp_run(xmpp_ctx_t *ctx); void xmpp_run(xmpp_ctx_t *ctx);
void xmpp_stop(xmpp_ctx_t *ctx); void xmpp_stop(xmpp_ctx_t *ctx);
void xmpp_ctx_set_timeout(xmpp_ctx_t * const ctx, const unsigned long timeout);
/* UUID */
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 #ifdef __cplusplus
} }

View File

@@ -10,34 +10,26 @@
*/ */
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "strophe.h" #include <check.h>
#include <strophe.h>
#include "parser.h" #include "parser.h"
#include "test.h" #include "test.h"
#define fail_unless(expr) do { \ START_TEST(create_destroy)
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; xmpp_ctx_t *ctx;
parser_t *parser; parser_t *parser;
ctx = xmpp_ctx_new(NULL, NULL); ctx = xmpp_ctx_new(NULL, NULL);
parser = parser_new(ctx, NULL, NULL, NULL, NULL); parser = parser_new(ctx, NULL, NULL, NULL, NULL);
fail_unless(parser != NULL); fail_unless(parser != NULL, "Parser creation failed.");
parser_free(parser); parser_free(parser);
xmpp_ctx_free(ctx); xmpp_ctx_free(ctx);
} }
END_TEST
int cbtest_got_start = 0; int cbtest_got_start = 0;
void cbtest_handle_start(char *name, char **attrs, void *userdata) void cbtest_handle_start(char *name, char **attrs, void *userdata)
@@ -60,7 +52,7 @@ void cbtest_handle_stanza(xmpp_stanza_t *stanza, void *userdata)
cbtest_got_stanza = 1; cbtest_got_stanza = 1;
} }
static void callbacks(void) START_TEST(callbacks)
{ {
xmpp_ctx_t *ctx; xmpp_ctx_t *ctx;
parser_t *parser; parser_t *parser;
@@ -73,11 +65,8 @@ static void callbacks(void)
cbtest_handle_stanza, NULL); cbtest_handle_stanza, NULL);
ret = parser_feed(parser, "<stream>", 8); ret = parser_feed(parser, "<stream>", 8);
fail_unless(ret != 0);
ret = parser_feed(parser, "<message/>", 10); ret = parser_feed(parser, "<message/>", 10);
fail_unless(ret != 0); parser_feed(parser, "</stream>", 9);
ret = parser_feed(parser, "</stream>", 9);
fail_unless(ret != 0);
fail_unless(cbtest_got_start == 1); fail_unless(cbtest_got_start == 1);
fail_unless(cbtest_got_end == 1); fail_unless(cbtest_got_end == 1);
@@ -86,18 +75,16 @@ static void callbacks(void)
parser_free(parser); parser_free(parser);
xmpp_ctx_free(ctx); xmpp_ctx_free(ctx);
} }
END_TEST
int main() Suite *parser_suite(void)
{ {
printf("XML parser tests.\n"); Suite *s = suite_create("Parser");
TCase *tc_core = tcase_create("Core");
printf("create-destroy: "); tcase_add_test(tc_core, create_destroy);
create_destroy(); tcase_add_test(tc_core, callbacks);
printf("ok\n"); suite_add_tcase(s, tc_core);
return s;
printf("callbacks: ");
callbacks();
printf("ok\n");
return 0;
} }
TEST_MAIN

View File

@@ -1,90 +0,0 @@
/* 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;
}

View File

@@ -1,54 +0,0 @@
/* 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;
}

View File

@@ -1,22 +1,6 @@
/* 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__ #ifndef __LIBSTROPHE_TEST_H__
#define __LIBSTROPHE_TEST_H__ #define __LIBSTROPHE_TEST_H__
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include "ostypes.h"
#define TEST_MAIN \ #define TEST_MAIN \
int main(int argc, char **argv) {\ int main(int argc, char **argv) {\
int num_failed;\ int num_failed;\
@@ -26,44 +10,7 @@ int main(int argc, char **argv) { \
num_failed = srunner_ntests_failed(sr);\ num_failed = srunner_ntests_failed(sr);\
srunner_free(sr);\ srunner_free(sr);\
return (num_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;\ 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__ */ #endif /* __LIBSTROPHE_TEST_H__ */

View File

@@ -9,170 +9,140 @@
** This program is dual licensed under the MIT and GPLv3 licenses. ** This program is dual licensed under the MIT and GPLv3 licenses.
*/ */
#include <assert.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include "strophe.h" #include "strophe.h"
#include "common.h"
#include "sasl.h"
#include "test.h" static const unsigned char text_1[] = "How now brown cow?";
static const char base64_1[] = "SG93IG5vdyBicm93biBjb3c/";
static const unsigned char test_2_raw[] = static const unsigned char text_2[] = {0x14,0xfb,0x9c,0x03,0xd9,0x7e,0x00};
{0x14, 0xfb, 0x9c, 0x03, 0xd9, 0x7e, 0x00}; static const char base64_2[] = "FPucA9l+";
static const unsigned char test_4_raw[] = static const unsigned char text_3[] =
{0xd6, 0x2f, 0x27, 0x49, 0x7e, 0xdd, 0xf3, 0xd5,
0x41, 0xbc, 0x1b, 0xe9, 0xdf, 0xe9, 0xb3, 0x08, 0x00};
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, " "From rest and sleep, which but thy pictures be, "
"Much pleasure; then from thee much more must flow, " "Much pleasure; then from thee much more must flow, "
"And soonest our best men with thee do go, " "And soonest our best men with thee do go, "
"Rest of their bones, and soul's delivery.", "Rest of their bones, and soul's delivery.";
.base64 = static const char base64_3[] =
"RnJvbSByZXN0IGFuZCBzbGVlcCwgd2hpY2ggYnV0IHRoeSBwaWN0dXJl" "RnJvbSByZXN0IGFuZCBzbGVlcCwgd2hpY2ggYnV0IHRoeSBwaWN0dXJl"
"cyBiZSwgTXVjaCBwbGVhc3VyZTsgdGhlbiBmcm9tIHRoZWUgbXVjaCBt" "cyBiZSwgTXVjaCBwbGVhc3VyZTsgdGhlbiBmcm9tIHRoZWUgbXVjaCBt"
"b3JlIG11c3QgZmxvdywgQW5kIHNvb25lc3Qgb3VyIGJlc3QgbWVuIHdp" "b3JlIG11c3QgZmxvdywgQW5kIHNvb25lc3Qgb3VyIGJlc3QgbWVuIHdp"
"dGggdGhlZSBkbyBnbywgUmVzdCBvZiB0aGVpciBib25lcywgYW5kIHNv" "dGggdGhlZSBkbyBnbywgUmVzdCBvZiB0aGVpciBib25lcywgYW5kIHNv"
"dWwncyBkZWxpdmVyeS4=", "dWwncyBkZWxpdmVyeS4=";
}, static const unsigned char text_4[] =
{ {0xd6, 0x2f, 0x27, 0x49, 0x7e, 0xdd, 0xf3, 0xd5,
.raw = (char *)test_4_raw, 0x41, 0xbc, 0x1b, 0xe9, 0xdf, 0xe9, 0xb3, 0x08, 0x00};
.base64 = "1i8nSX7d89VBvBvp3+mzCA==", 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";
.raw = static const char base64_5[] =
"realm=\"chesspark.com\",nonce=\"b243c0d663257a9149999cef2f83"
"a22116559e93\",qop=\"auth\",charset=utf-8,algorithm=md5-sess",
.base64 =
"cmVhbG09ImNoZXNzcGFyay5jb20iLG5vbmNlPSJiMjQzYzBkNjYzMjU3" "cmVhbG09ImNoZXNzcGFyay5jb20iLG5vbmNlPSJiMjQzYzBkNjYzMjU3"
"YTkxNDk5OTljZWYyZjgzYTIyMTE2NTU5ZTkzIixxb3A9ImF1dGgiLGNo" "YTkxNDk5OTljZWYyZjgzYTIyMTE2NTU5ZTkzIixxb3A9ImF1dGgiLGNo"
"YXJzZXQ9dXRmLTgsYWxnb3JpdGhtPW1kNS1zZXNz", "YXJzZXQ9dXRmLTgsYWxnb3JpdGhtPW1kNS1zZXNz";
},
/* RFC4648 test vectors */ int test_encode(xmpp_ctx_t *ctx)
{ {
.raw = "", char *result;
.base64 = "", result = base64_encode(ctx, text_1, strlen(text_1));
}, if (result == NULL) return 2;
{ if (strlen(result) != strlen(base64_1)) return 1;
.raw = "f", if (strncmp(base64_1, result, strlen(base64_1))) return 1;
.base64 = "Zg==", xmpp_free(ctx,result);
},
{ result = base64_encode(ctx, text_2, strlen(text_2));
.raw = "fo", if (result == NULL) return 2;
.base64 = "Zm8=", if (strlen(result) != strlen(base64_2)) return 1;
}, if (strncmp(base64_2, result, strlen(base64_2))) return 1;
{ xmpp_free(ctx,result);
.raw = "foo",
.base64 = "Zm9v", result = base64_encode(ctx, text_3, strlen(text_3));
}, if (result == NULL) return 2;
{ if (strlen(result) != strlen(base64_3)) return 1;
.raw = "foob", if (strncmp(base64_3, result, strlen(base64_3))) return 1;
.base64 = "Zm9vYg==", xmpp_free(ctx,result);
},
{ result = base64_encode(ctx, text_4, strlen(text_4));
.raw = "fooba", if (result == NULL) return 2;
.base64 = "Zm9vYmE=", if (strlen(result) != strlen(base64_4)) return 1;
}, if (strncmp(base64_4, result, strlen(base64_4))) return 1;
{ xmpp_free(ctx,result);
.raw = "foobar",
.base64 = "Zm9vYmFy", 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;
}
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[]) int main(int argc, char *argv[])
{ {
xmpp_ctx_t *ctx; xmpp_ctx_t *ctx;
unsigned char *udec; int ret;
char *dec;
char *enc;
size_t len, i;
printf("BASE64 tests.\n");
printf("allocating context... ");
ctx = xmpp_ctx_new(NULL, NULL); ctx = xmpp_ctx_new(NULL, NULL);
if (ctx == NULL) { if (ctx == NULL) printf("failed to create context\n");
fprintf(stderr, "failed to create context\n"); if (ctx == NULL) return -1;
return 1; printf("ok.\n");
}
for (i = 0; i < ARRAY_SIZE(tests); ++i) { printf("testing encode... ");
printf("Test #%d: ", (int)i + 1); ret = test_encode(ctx);
enc = xmpp_base64_encode(ctx, (unsigned char *)tests[i].raw, if (ret) printf("base64_encode failed!\n");
strlen(tests[i].raw)); if (ret) return ret;
assert(enc != NULL); printf("ok.\n");
COMPARE(tests[i].base64, enc);
xmpp_free(ctx, enc);
dec = xmpp_base64_decode_str(ctx, tests[i].base64, printf("testing decode... ");
strlen(tests[i].base64)); ret = test_decode(ctx);
assert(dec != NULL); if (ret) printf("base64_decode failed!\n");
COMPARE_BUF(tests[i].raw, strlen(tests[i].raw), dec, strlen(dec)); if (ret) return ret;
xmpp_free(ctx, dec); printf("ok.\n");
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); xmpp_ctx_free(ctx);
printf("ok.\n");
return 0; return ret;
} }

View File

@@ -94,8 +94,6 @@ int main(int argc, char **argv)
if (!(log_called && mem_alloc_called && mem_realloc_called && if (!(log_called && mem_alloc_called && mem_realloc_called &&
mem_free_called)) mem_free_called))
return 1; return 1;
if (mem_alloc_called != mem_free_called)
return 1;
return 0; return 0;
} }

View File

@@ -76,18 +76,6 @@ int main(int argc, char **argv)
return 1; return 1;
} }
/* test replacing old values */
for (i = 0; i < nkeys; i++) {
err = hash_add(table, keys[0], (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 */ /* test cloning */
clone = hash_clone(table); clone = hash_clone(table);

View File

@@ -1,4 +1,4 @@
/* test_jid.c /* test_base64.c
** libstrophe XMPP client library -- test routines for the jid utils ** libstrophe XMPP client library -- test routines for the jid utils
** **
** Copyright (C) 2005-2009 Collecta, Inc. ** Copyright (C) 2005-2009 Collecta, Inc.
@@ -20,74 +20,56 @@ static const char jid2[] = "anyone@example.com/hullo";
static const char jid3[] = "manic.porter@xyz.net/frob"; static const char jid3[] = "manic.porter@xyz.net/frob";
static const char jid4[] = "domain.tld"; 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) int test_jid(xmpp_ctx_t *ctx)
{ {
char *bare;
char *node; char *node;
char *domain; char *domain;
char *resource; char *resource;
bare = xmpp_jid_bare(ctx, jid1);
node = xmpp_jid_node(ctx, jid1); node = xmpp_jid_node(ctx, jid1);
domain = xmpp_jid_domain(ctx, jid1); domain = xmpp_jid_domain(ctx, jid1);
resource = xmpp_jid_resource(ctx, jid1); resource = xmpp_jid_resource(ctx, jid1);
printf("jid '%s' parsed to %s, %s, %s\n", printf("jid '%s' parsed to %s, %s, %s\n",
jid1, _s(node), _s(domain), _s(resource)); jid1, node, domain, resource);
if (bare == NULL || strcmp(bare, "foo@bar.com")) return 1; if (strcmp(node, "foo")) return 1;
if (node == NULL || strcmp(node, "foo")) return 1; if (strcmp(domain, "bar.com")) return 1;
if (domain == NULL || strcmp(domain, "bar.com")) return 1;
if (resource != NULL) return 1; if (resource != NULL) return 1;
if (bare) xmpp_free(ctx, bare);
if (node) xmpp_free(ctx, node); if (node) xmpp_free(ctx, node);
if (domain) xmpp_free(ctx, domain); if (domain) xmpp_free(ctx, domain);
if (resource) xmpp_free(ctx, resource); if (resource) xmpp_free(ctx, resource);
bare = xmpp_jid_bare(ctx, jid2);
node = xmpp_jid_node(ctx, jid2); node = xmpp_jid_node(ctx, jid2);
domain = xmpp_jid_domain(ctx, jid2); domain = xmpp_jid_domain(ctx, jid2);
resource = xmpp_jid_resource(ctx, jid2); resource = xmpp_jid_resource(ctx, jid2);
printf("jid '%s' parsed to %s, %s, %s\n", printf("jid '%s' parsed to %s, %s, %s\n",
jid2, _s(node), _s(domain), _s(resource)); jid2, node, domain, resource);
if (bare == NULL || strcmp(bare, "anyone@example.com")) return 1; if (strcmp(node, "anyone")) return 1;
if (node == NULL || strcmp(node, "anyone")) return 1; if (strcmp(domain, "example.com")) return 1;
if (domain == NULL || strcmp(domain, "example.com")) return 1; if (strcmp(resource, "hullo")) return 1;
if (resource == NULL || strcmp(resource, "hullo")) return 1;
if (bare) xmpp_free(ctx, bare);
if (node) xmpp_free(ctx, node); if (node) xmpp_free(ctx, node);
if (domain) xmpp_free(ctx, domain); if (domain) xmpp_free(ctx, domain);
if (resource) xmpp_free(ctx, resource); if (resource) xmpp_free(ctx, resource);
bare = xmpp_jid_bare(ctx, jid3);
node = xmpp_jid_node(ctx, jid3); node = xmpp_jid_node(ctx, jid3);
domain = xmpp_jid_domain(ctx, jid3); domain = xmpp_jid_domain(ctx, jid3);
resource = xmpp_jid_resource(ctx, jid3); resource = xmpp_jid_resource(ctx, jid3);
printf("jid '%s' parsed to %s, %s, %s\n", printf("jid '%s' parsed to %s, %s, %s\n",
jid3, _s(node), _s(domain), _s(resource)); jid3, node, domain, resource);
if (bare == NULL || strcmp(bare, "manic.porter@xyz.net")) return 1; if (strcmp(node, "manic.porter")) return 1;
if (node == NULL || strcmp(node, "manic.porter")) return 1; if (strcmp(domain, "xyz.net")) return 1;
if (domain == NULL || strcmp(domain, "xyz.net")) return 1; if (strcmp(resource, "frob")) return 1;
if (resource == NULL || strcmp(resource, "frob")) return 1;
if (bare) xmpp_free(ctx, bare);
if (node) xmpp_free(ctx, node); if (node) xmpp_free(ctx, node);
if (domain) xmpp_free(ctx, domain); if (domain) xmpp_free(ctx, domain);
if (resource) xmpp_free(ctx, resource); if (resource) xmpp_free(ctx, resource);
bare = xmpp_jid_bare(ctx, jid4);
node = xmpp_jid_node(ctx, jid4); node = xmpp_jid_node(ctx, jid4);
domain = xmpp_jid_domain(ctx, jid4); domain = xmpp_jid_domain(ctx, jid4);
resource = xmpp_jid_resource(ctx, jid4); resource = xmpp_jid_resource(ctx, jid4);
printf("jid '%s' parsed to %s, %s, %s\n", printf("jid '%s' parsed to %s, %s, %s\n",
jid4, _s(node), _s(domain), _s(resource)); jid4, node, domain, resource);
if (bare == NULL || strcmp(bare, "domain.tld")) return 1;
if (node != NULL) return 1; if (node != NULL) return 1;
if (domain == NULL || strcmp(domain, "domain.tld")) return 1; if (strcmp(domain, "domain.tld")) return 1;
if (resource != NULL) return 1; if (resource != NULL) return 1;
if (bare) xmpp_free(ctx, bare);
if (node) xmpp_free(ctx, node); if (node) xmpp_free(ctx, node);
if (domain) xmpp_free(ctx, domain); if (domain) xmpp_free(ctx, domain);
if (resource) xmpp_free(ctx, resource); if (resource) xmpp_free(ctx, resource);
@@ -123,17 +105,17 @@ int main(int argc, char *argv[])
if (ctx == NULL) return -1; if (ctx == NULL) return -1;
printf("ok.\n"); printf("ok.\n");
printf("testing jid routines...\n"); printf("testing jid routines... ");
ret = test_jid(ctx); ret = test_jid(ctx);
if (ret) printf("testing jid routines... failed!\n"); if (ret) printf("failed!\n");
if (ret) return ret; if (ret) return ret;
printf("testing jid routines... ok.\n"); printf("ok.\n");
printf("testing jid new routines...\n"); printf("testing jid new routines... ");
ret = test_jid_new(ctx); ret = test_jid_new(ctx);
if (ret) printf("testing jid new routines... failed!\n"); if (ret) printf("failed!\n");
if (ret) return ret; if (ret) return ret;
printf("testing jid new routines... ok.\n"); printf("ok.\n");
printf("freeing context... "); printf("freeing context... ");
xmpp_ctx_free(ctx); xmpp_ctx_free(ctx);

View File

@@ -1,77 +0,0 @@
/* 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;
}

View File

@@ -1,145 +0,0 @@
/* 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;
}

View File

@@ -1,256 +0,0 @@
/* 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;
}

View File

@@ -1,142 +0,0 @@
/* 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;
}

View File

@@ -1,95 +0,0 @@
/* 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);
}

View File

@@ -1,91 +0,0 @@
/*
* 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;
}

View File

@@ -1,116 +0,0 @@
/* 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;
}

195
vs2008/active.vcproj Normal file
View File

@@ -0,0 +1,195 @@
<?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>

195
vs2008/basic.vcproj Normal file
View File

@@ -0,0 +1,195 @@
<?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>

195
vs2008/bot.vcproj Normal file
View File

@@ -0,0 +1,195 @@
<?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>

288
vs2008/expat.vcproj Normal file
View File

@@ -0,0 +1,288 @@
<?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>

66
vs2008/libstrophe.sln Normal file
View File

@@ -0,0 +1,66 @@

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

276
vs2008/libstrophe.vcproj Normal file
View File

@@ -0,0 +1,276 @@
<?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>

195
vs2008/roster.vcproj Normal file
View File

@@ -0,0 +1,195 @@
<?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>