1 Commits

Author SHA1 Message Date
Dmitry Podgorny
b1698f7b5d WIP Initial server support 2017-07-15 21:38:38 +03:00
96 changed files with 5281 additions and 9141 deletions

12
.gitignore vendored
View File

@@ -1,5 +1,4 @@
*.swp *.swp
*.orig
Makefile Makefile
test-driver test-driver
.libs .libs
@@ -35,8 +34,8 @@ examples/active
examples/basic examples/basic
examples/bot examples/bot
examples/component examples/component
examples/register
examples/roster examples/roster
examples/server
examples/uuid examples/uuid
examples/vcard examples/vcard
test_stamp test_stamp
@@ -55,18 +54,11 @@ tests/test_resolver
tests/test_sasl tests/test_sasl
tests/test_scram tests/test_scram
tests/test_sha1 tests/test_sha1
tests/test_sha256
tests/test_sha512
tests/test_snprintf tests/test_snprintf
tests/test_sock
tests/test_stanza
tests/test_string tests/test_string
tests/test_xmppaddr tests/test_sock
m4/ m4/
libstrophe.project libstrophe.project
libs/ libs/
obj/ obj/
expat/ expat/
.settings/
.project
.cproject

View File

@@ -1,26 +1,15 @@
language: c language: c
dist: focal
install: install:
- sudo apt-get update - sudo apt-get update
- sudo apt-get -y install libtool pkg-config libexpat1-dev libxml2-dev libssl-dev libgnutls28-dev libc-ares-dev dos2unix - sudo apt-get -y install libtool pkg-config libexpat1-dev libxml2-dev libssl-dev check
stages: before_script:
- style - ./bootstrap.sh
- test script:
- ./configure ${CONFIGURE_OPT} && make && make check-TESTS
env: env:
- CONFIGURE_OPT="--without-libxml2" - CONFIGURE_OPT="--without-libxml2"
- CONFIGURE_OPT="--with-libxml2" - CONFIGURE_OPT="--with-libxml2"
- CONFIGURE_OPT="--with-gnutls" - CONFIGURE_OPT="--disable-tls --without-libxml2"
- CONFIGURE_OPT="--disable-tls" - CONFIGURE_OPT="--disable-tls --with-libxml2"
- CONFIGURE_OPT="--enable-cares" matrix:
- CONFIGURE_OPT="PKG_CONFIG_PATH=${HOME}/libressl/lib/pkgconfig" LIBRESSL=yes LIBRESSL_COMMIT="v3.1.4" fast_finish: true
- CONFIGURE_OPT="PKG_CONFIG_PATH=${HOME}/libressl/lib/pkgconfig" LIBRESSL=yes LIBRESSL_COMMIT="v2.1.7"
before_script: ./travis/before_script.sh
script: ./bootstrap.sh && ./configure ${CONFIGURE_OPT} CFLAGS="-Werror -g3" && make && make check
jobs:
include:
- stage: style
name: "Check coding style"
env: CONFIGURE_OPT=""
script: ./bootstrap.sh && ./configure && make format && git diff --exit-code
allow_failures:
- stage: style

View File

@@ -1,63 +1,3 @@
0.11.0
- SASL EXTERNAL support (XEP-0178)
- Client certificate can be provided for TLS negotiation. If the
certificate contains a single xmppAddr and JID is not provided with
xmpp_conn_set_jid(), the xmppAddr is chosen as JID
- <stream> element contains "from" attribute over TLS connections now
- GnuTLS can be selected optionally with configure script
- Support for manual certificate verification
- New API:
- xmpp_conn_set_client_cert()
- xmpp_conn_cert_xmppaddr_num()
- xmpp_conn_cert_xmppaddr()
- xmpp_conn_set_cafile()
- xmpp_conn_set_capath()
- xmpp_conn_set_certfail_handler()
- xmpp_conn_get_peer_cert()
- xmpp_tlscert_get_ctx()
- xmpp_tlscert_get_conn()
- xmpp_tlscert_get_pem()
- xmpp_tlscert_get_dnsname()
- xmpp_tlscert_get_string()
- xmpp_tlscert_get_description()
- xmpp_tlscert_free()
0.10.1
- Fixed compilation error when LibreSSL is used
- Fixed crash when NULL is provided as password
0.10.0
- Coding style has been unified
- SCRAM-SHA-256 and SCRAM-SHA-512 support
- c-ares support
- LibreSSL support
- Introduced global timed handlers that fire periodically regardless of
connections status, such a handler can be used to implement deferred
re-connection
- examples/register implements XEP-0077
- Fixed issue with IPv6 on Windows (#153)
- Improved portability across systems such as Haiku, Windows
- New API:
- xmpp_stanza_get_child_by_name_and_ns()
- xmpp_conn_is_connecting()
- xmpp_conn_is_connected()
- xmpp_conn_is_disconnected()
- xmpp_stanza_new_from_string()
- xmpp_stanza_add_child_ex()
- xmpp_stanza_get_context()
- xmpp_stanza_reply_error()
- xmpp_global_timed_handler_add()
- xmpp_global_timed_handler_delete()
0.9.3
- PLAIN mechanism is used only when no other mechanisms are supported
- Legacy authentication is disabled by default, can be enabled with
connection flag XMPP_CONN_FLAG_LEGACY_AUTH
- Session is not established if it is optional
- Fixed a bug causing a reused connection not to cleanup properly
- Improved debug logging in OpenSSL module
- Few memory leaks fixed
0.9.2 0.9.2
- OpenSSL tls module verifies certificate by default. Set flag - OpenSSL tls module verifies certificate by default. Set flag
XMPP_CONN_FLAG_TRUST_TLS to ignore result of the verification XMPP_CONN_FLAG_TRUST_TLS to ignore result of the verification
@@ -68,12 +8,7 @@
userdata userdata
- System handlers are deleted on xmpp_conn_t reconnection. Old system - System handlers are deleted on xmpp_conn_t reconnection. Old system
handlers could cause problems handlers could cause problems
- Default timeout for xmpp_run() is increased from 1 millisecond to 1
second in order to reduce CPU consumption
- Reduced memory usage in expat module
- New functions: - New functions:
- xmpp_error_new()
- xmpp_send_error()
- xmpp_ctx_set_timeout() - xmpp_ctx_set_timeout()
- xmpp_sha1_digest() - xmpp_sha1_digest()

View File

@@ -38,7 +38,7 @@ PROJECT_NAME = Strophe
# could be handy for archiving the generated documentation or if some version # could be handy for archiving the generated documentation or if some version
# control system is used. # control system is used.
PROJECT_NUMBER = 0.11 PROJECT_NUMBER = 0.9
# Using the PROJECT_BRIEF tag one can provide an optional one line description # Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a # for a project that appears at the top of each page and should give viewer a
@@ -1047,7 +1047,7 @@ HTML_HEADER =
# that doxygen normally uses. # that doxygen normally uses.
# This tag requires that the tag GENERATE_HTML is set to YES. # This tag requires that the tag GENERATE_HTML is set to YES.
HTML_FOOTER = HTML_FOOTER = docs/footer.html
# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style # The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
# sheet that is used by each HTML page. It can be used to fine-tune the look of # sheet that is used by each HTML page. It can be used to fine-tune the look of

View File

@@ -1,29 +1,23 @@
AUTOMAKE_OPTIONS = subdir-objects AUTOMAKE_OPTIONS = subdir-objects
ACLOCAL_AMFLAGS = -I m4 ACLOCAL_AMFLAGS = -I m4
AM_CFLAGS = -g -Wall
PARSER_CFLAGS=@PARSER_CFLAGS@ PARSER_CFLAGS=@PARSER_CFLAGS@
PARSER_LIBS=@PARSER_LIBS@ PARSER_LIBS=@PARSER_LIBS@
if TLS_WITH_GNUTLS
SSL_CFLAGS = @gnutls_CFLAGS@
SSL_LIBS = @gnutls_LIBS@
else
SSL_CFLAGS = @openssl_CFLAGS@ SSL_CFLAGS = @openssl_CFLAGS@
SSL_LIBS = @openssl_LIBS@ SSL_LIBS = @openssl_LIBS@
endif
RESOLV_CFLAGS = @RESOLV_CFLAGS@
RESOLV_LIBS = @RESOLV_LIBS@ RESOLV_LIBS = @RESOLV_LIBS@
WARNING_FLAGS = @WARNING_FLAGS@ STROPHE_FLAGS = -I$(top_srcdir) -Wall -Wextra -Werror -Wno-unused-parameter
STROPHE_FLAGS = -I$(top_srcdir) $(WARNING_FLAGS)
STROPHE_LIBS = libstrophe.la STROPHE_LIBS = libstrophe.la
## Main build targets ## Main build targets
lib_LTLIBRARIES = libstrophe.la lib_LTLIBRARIES = libstrophe.la
libstrophe_la_CFLAGS = $(SSL_CFLAGS) $(STROPHE_FLAGS) $(PARSER_CFLAGS) $(RESOLV_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) $(RESOLV_LIBS) -no-undefined
# Export only public API # Export only public API
libstrophe_la_LDFLAGS += -export-symbols-regex '^xmpp_' libstrophe_la_LDFLAGS += -export-symbols-regex '^xmpp_'
@@ -42,13 +36,11 @@ libstrophe_la_SOURCES = \
src/resolver.c \ src/resolver.c \
src/sasl.c \ src/sasl.c \
src/scram.c \ src/scram.c \
src/server.c \
src/sha1.c \ src/sha1.c \
src/sha256.c \
src/sha512.c \
src/snprintf.c \ src/snprintf.c \
src/sock.c \ src/sock.c \
src/stanza.c \ src/stanza.c \
src/tls.c \
src/util.c \ src/util.c \
src/uuid.c src/uuid.c
libstrophe_la_SOURCES += \ libstrophe_la_SOURCES += \
@@ -61,10 +53,7 @@ libstrophe_la_SOURCES += \
src/resolver.h \ src/resolver.h \
src/sasl.h \ src/sasl.h \
src/scram.h \ src/scram.h \
src/sha.h \
src/sha1.h \ src/sha1.h \
src/sha256.h \
src/sha512.h \
src/snprintf.h \ src/snprintf.h \
src/sock.h \ src/sock.h \
src/tls.h \ src/tls.h \
@@ -73,12 +62,8 @@ libstrophe_la_SOURCES += \
if DISABLE_TLS if DISABLE_TLS
libstrophe_la_SOURCES += src/tls_dummy.c libstrophe_la_SOURCES += src/tls_dummy.c
else else
if TLS_WITH_GNUTLS
libstrophe_la_SOURCES += src/tls_gnutls.c
else
libstrophe_la_SOURCES += src/tls_openssl.c libstrophe_la_SOURCES += src/tls_openssl.c
endif endif
endif
if PARSER_EXPAT if PARSER_EXPAT
libstrophe_la_SOURCES += src/parser_expat.c libstrophe_la_SOURCES += src/parser_expat.c
@@ -87,29 +72,27 @@ libstrophe_la_SOURCES += src/parser_libxml2.c
endif endif
include_HEADERS = strophe.h include_HEADERS = strophe.h
noinst_HEADERS = strophepp.h
pkgconfig_DATA = libstrophe.pc pkgconfig_DATA = libstrophe.pc
EXTRA_DIST = \ EXTRA_DIST = \
_clang-format \
Doxyfile \ Doxyfile \
GPL-LICENSE.txt \ GPL-LICENSE.txt \
LICENSE.txt \ LICENSE.txt \
MIT-LICENSE.txt \ MIT-LICENSE.txt \
bootstrap.sh \ bootstrap.sh \
build-android.sh \ build-android.sh \
docs/footer.html \
examples/README.md \ examples/README.md \
jni/Android.mk \ jni/Android.mk \
jni/Application.mk \ jni/Application.mk \
rpm/README \
rpm/libstrophe.spec \
src/tls_gnutls.c \
src/tls_schannel.c \ src/tls_schannel.c \
tests/res_query_dump.c tests/res_query_dump.c
if TLS_WITH_GNUTLS
EXTRA_DIST += src/tls_openssl.c
else
EXTRA_DIST += src/tls_gnutls.c
endif
## Examples ## Examples
noinst_PROGRAMS = \ noinst_PROGRAMS = \
examples/active \ examples/active \
@@ -117,9 +100,9 @@ noinst_PROGRAMS = \
examples/bot \ examples/bot \
examples/component \ examples/component \
examples/roster \ examples/roster \
examples/server \
examples/uuid \ examples/uuid \
examples/vcard \ examples/vcard
examples/register
examples_active_SOURCES = examples/active.c examples_active_SOURCES = examples/active.c
examples_active_CFLAGS = $(STROPHE_FLAGS) examples_active_CFLAGS = $(STROPHE_FLAGS)
@@ -136,23 +119,21 @@ examples_component_LDADD = $(STROPHE_LIBS)
examples_roster_SOURCES = examples/roster.c examples_roster_SOURCES = examples/roster.c
examples_roster_CFLAGS = $(STROPHE_FLAGS) examples_roster_CFLAGS = $(STROPHE_FLAGS)
examples_roster_LDADD = $(STROPHE_LIBS) 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_SOURCES = examples/uuid.c
examples_uuid_CFLAGS = $(STROPHE_FLAGS) examples_uuid_CFLAGS = $(STROPHE_FLAGS)
examples_uuid_LDADD = $(STROPHE_LIBS) examples_uuid_LDADD = $(STROPHE_LIBS)
examples_vcard_SOURCES = examples/vcard.c examples_vcard_SOURCES = examples/vcard.c
examples_vcard_CFLAGS = $(STROPHE_FLAGS) examples_vcard_CFLAGS = $(STROPHE_FLAGS)
examples_vcard_LDADD = $(STROPHE_LIBS) examples_vcard_LDADD = $(STROPHE_LIBS)
examples_register_SOURCES = examples/register.c
examples_register_CFLAGS = $(STROPHE_FLAGS)
examples_register_LDADD = $(STROPHE_LIBS)
## Tests ## Tests
TESTS = \ TESTS = \
tests/check_parser \ tests/check_parser \
tests/test_sha1 \ tests/test_sha1 \
tests/test_sha256 \
tests/test_sha512 \
tests/test_md5 \ tests/test_md5 \
tests/test_rand \ tests/test_rand \
tests/test_scram \ tests/test_scram \
@@ -162,25 +143,10 @@ TESTS = \
tests/test_jid \ tests/test_jid \
tests/test_snprintf \ tests/test_snprintf \
tests/test_string \ tests/test_string \
tests/test_stanza \
tests/test_resolver tests/test_resolver
if !DISABLE_TLS
TESTS += tests/test_xmppaddr
endif
check_PROGRAMS = $(TESTS) check_PROGRAMS = $(TESTS)
if FUZZ
check_PROGRAMS += tests/test_fuzz
tests_test_fuzz_SOURCES = tests/test_fuzz.c
tests_test_fuzz_CFLAGS = -fsanitize=fuzzer,address $(PARSER_CFLAGS) $(STROPHE_FLAGS) \
-I$(top_srcdir)/src
tests_test_fuzz_LDADD = $(STROPHE_LIBS)
tests_test_fuzz_LDFLAGS = -static
endif
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 = $(PARSER_CFLAGS) $(STROPHE_FLAGS) \
-I$(top_srcdir)/src -I$(top_srcdir)/src
@@ -215,19 +181,12 @@ tests_test_resolver_LDFLAGS = -static
tests_test_rand_SOURCES = tests/test_rand.c tests/test.c src/sha1.c tests_test_rand_SOURCES = tests/test_rand.c tests/test.c src/sha1.c
tests_test_rand_CFLAGS = $(STROPHE_FLAGS) -I$(top_srcdir)/src tests_test_rand_CFLAGS = $(STROPHE_FLAGS) -I$(top_srcdir)/src
tests_test_scram_SOURCES = tests/test_scram.c tests/test.c src/sha1.c \ tests_test_scram_SOURCES = tests/test_scram.c tests/test.c src/sha1.c
src/sha256.c src/sha512.c
tests_test_scram_CFLAGS = $(STROPHE_FLAGS) -I$(top_srcdir)/src tests_test_scram_CFLAGS = $(STROPHE_FLAGS) -I$(top_srcdir)/src
tests_test_sha1_SOURCES = tests/test_sha1.c src/sha1.c tests_test_sha1_SOURCES = tests/test_sha1.c src/sha1.c
tests_test_sha1_CFLAGS = -I$(top_srcdir)/src tests_test_sha1_CFLAGS = -I$(top_srcdir)/src
tests_test_sha256_SOURCES = tests/test_sha256.c tests/test.c src/sha256.c
tests_test_sha256_CFLAGS = -I$(top_srcdir)/src
tests_test_sha512_SOURCES = tests/test_sha512.c tests/test.c src/sha512.c
tests_test_sha512_CFLAGS = -I$(top_srcdir)/src
tests_test_md5_SOURCES = tests/test_md5.c tests/test.c src/md5.c tests_test_md5_SOURCES = tests/test_md5.c tests/test.c src/md5.c
tests_test_md5_CFLAGS = -I$(top_srcdir)/src tests_test_md5_CFLAGS = -I$(top_srcdir)/src
@@ -238,18 +197,3 @@ tests_test_string_SOURCES = tests/test_string.c tests/test.h
tests_test_string_CFLAGS = $(STROPHE_FLAGS) -I$(top_srcdir)/src tests_test_string_CFLAGS = $(STROPHE_FLAGS) -I$(top_srcdir)/src
tests_test_string_LDADD = $(STROPHE_LIBS) tests_test_string_LDADD = $(STROPHE_LIBS)
tests_test_string_LDFLAGS = -static tests_test_string_LDFLAGS = -static
tests_test_stanza_SOURCES = tests/test_stanza.c tests/test.h
tests_test_stanza_CFLAGS = $(STROPHE_FLAGS) -I$(top_srcdir)/src
tests_test_stanza_LDADD = $(STROPHE_LIBS)
tests_test_stanza_LDFLAGS = -static
tests_test_xmppaddr_SOURCES = tests/test_xmppaddr.c
tests_test_xmppaddr_CFLAGS = $(STROPHE_FLAGS) -I$(top_srcdir)/src
tests_test_xmppaddr_LDADD = $(STROPHE_LIBS)
tests_test_xmppaddr_LDFLAGS = -static
format:
@echo " * run clang-format on all sources"
@dos2unix -q src/*.[ch] *.h tests/*.[ch] examples/*.c
@clang-format -i src/*.[ch] *.h tests/*.[ch] examples/*.c

View File

@@ -5,7 +5,11 @@ libstrophe is a lightweight XMPP client library written in C. It has
minimal dependencies and is configurable for various environments. It minimal dependencies and is configurable for various environments. It
runs well on Linux, Unix and Windows based platforms. runs well on Linux, Unix and Windows based platforms.
libstrophe is dual licensed under MIT and GPLv3. Its goals are:
- usable quickly
- well documented
- reliable
Build Instructions Build Instructions
------------------ ------------------

View File

@@ -1,18 +0,0 @@
---
AlignConsecutiveAssignments: 'false'
AlignEscapedNewlines: Left
AllowShortBlocksOnASingleLine: 'true'
AllowShortFunctionsOnASingleLine: Empty
AllowShortIfStatementsOnASingleLine: 'false'
BinPackParameters: 'false'
BreakBeforeBraces: Linux
ColumnLimit: '80'
DerivePointerAlignment: 'false'
IndentGotoLabels: false
IndentWidth: '4'
PointerAlignment: Right
SortIncludes: 'false'
TabWidth: '4'
UseTab: Never
...

View File

@@ -1,4 +1,4 @@
AC_INIT([libstrophe], [0.11.0], [jack@metajack.im]) AC_INIT([libstrophe], [0.9.1], [jack@metajack.im])
AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_MACRO_DIR([m4])
AM_INIT_AUTOMAKE([foreign]) AM_INIT_AUTOMAKE([foreign])
LT_INIT([dlopen]) LT_INIT([dlopen])
@@ -15,50 +15,14 @@ AS_CASE([$host_os],
[*nto*|*qnx*], [PLATFORM="qnx"], [*nto*|*qnx*], [PLATFORM="qnx"],
[*solaris*], [PLATFORM="solaris"], [*solaris*], [PLATFORM="solaris"],
[*android*], [PLATFORM="android"], [*android*], [PLATFORM="android"],
[*haiku*], [PLATFORM="haiku"],
[PLATFORM="nix"]) [PLATFORM="nix"])
WARNING_FLAGS="-Wall"
AS_CASE([$PLATFORM],
[haiku], [],
[WARNING_FLAGS="$WARNING_FLAGS -Wextra"])
AC_ARG_WITH([libxml2], AC_ARG_WITH([libxml2],
[AS_HELP_STRING([--with-libxml2], [use libxml2 for XML parsing, expat is the default])]) [AS_HELP_STRING([--with-libxml2], [use libxml2 for XML parsing, expat is the default])])
AC_ARG_WITH([gnutls],
[AS_HELP_STRING([--with-gnutls], [use GnuTLS for TLS support, OpenSSL is the default])])
AC_ARG_ENABLE([tls], AC_ARG_ENABLE([tls],
[AS_HELP_STRING([--disable-tls], [disable TLS support])]) [AS_HELP_STRING([--disable-tls], [disable TLS support])])
AC_ARG_ENABLE([cares],
[AS_HELP_STRING([--enable-cares], [use c-ares for DNS resolution])])
AC_ARG_ENABLE([fuzzing], if test "x$enable_tls" != xno; then
[AS_HELP_STRING([--enable-fuzzing], [turn on fuzzing test])],
[case "${enableval}" in yes) fuzzing=true ;; no) fuzzing=false ;; *) AC_MSG_ERROR([bad value ${enableval} for --enable-fuzzing]) ;; esac],[fuzzing=false])
AM_CONDITIONAL([FUZZ], [test x$fuzzing = xtrue])
if test "x$enable_fuzzing" = "xyes" ; then
if test "x$CC" != "xclang" ; then
AC_MSG_ERROR(["You need to set CC=clang to use --enable-fuzzing, used $CC"])
fi
fi
AC_SEARCH_LIBS([socket], [network socket])
AC_CHECK_FUNCS([snprintf vsnprintf])
AC_CHECK_DECLS([va_copy], [], [], [#include <stdarg.h>])
if test "x$enable_tls" != xno -a "x$with_gnutls" == xyes; then
PKG_CHECK_MODULES([gnutls], [gnutls],
[PC_REQUIRES="gnutls ${PC_REQUIRES}"],
[AC_CHECK_HEADER([gnutls/gnutls.h],
[
gnutls_LIBS="-lgnutls"
PC_LIBS="${gnutls_LIBS} ${PC_LIBS}"
],
[AC_MSG_ERROR([gnutls not found; gnutls required])]
)])
elif test "x$enable_tls" != xno; then
PKG_CHECK_MODULES([openssl], [openssl], PKG_CHECK_MODULES([openssl], [openssl],
[PC_REQUIRES="openssl ${PC_REQUIRES}"], [PC_REQUIRES="openssl ${PC_REQUIRES}"],
[AC_CHECK_HEADER([openssl/ssl.h], [AC_CHECK_HEADER([openssl/ssl.h],
@@ -98,7 +62,7 @@ if test "x$with_libxml2" != xno -a "x$with_parser" = x; then
[ [
with_parser="libxml2" with_parser="libxml2"
libxml2_CFLAGS="-I${includedir}/libxml2" libxml2_CFLAGS="-I${includedir}/libxml2"
libxml2_LIBS="-lxml2 -lm" libxml2_LIBS="-lxml2"
PC_LIBS="${libxml2_LIBS} ${PC_LIBS}" PC_LIBS="${libxml2_LIBS} ${PC_LIBS}"
PC_CFLAGS="${libxml2_CFLAGS} ${PC_CFLAGS}" PC_CFLAGS="${libxml2_CFLAGS} ${PC_CFLAGS}"
]) ])
@@ -118,24 +82,13 @@ fi
AC_MSG_NOTICE([libstrophe will use the $with_parser XML parser]) AC_MSG_NOTICE([libstrophe will use the $with_parser XML parser])
if test "x$enable_cares" = xyes; then AC_SEARCH_LIBS([socket], [socket])
PKG_CHECK_MODULES([libcares], [libcares >= 1.7.0],
[
PC_REQUIRES="libcares ${PC_REQUIRES}"
RESOLV_CFLAGS=$libcares_CFLAGS
RESOLV_LIBS=$libcares_LIBS
AC_DEFINE([HAVE_CARES])
],
[AC_MSG_ERROR([libcares not found])])
# TODO: if pkg-config doesn't find, check the library manually
else
AS_CASE([$PLATFORM], AS_CASE([$PLATFORM],
[bsd], [RESOLV_LIBS=""], [bsd], [RESOLV_LIBS=""],
[qnx], [RESOLV_LIBS="-lsocket"], [qnx], [RESOLV_LIBS="-lsocket"],
[solaris], [RESOLV_LIBS="-lresolv -lsocket -lnsl"], [solaris], [RESOLV_LIBS="-lresolv -lsocket -lnsl"],
[android], [RESOLV_LIBS=""], [android], [RESOLV_LIBS=""],
[haiku], [RESOLV_LIBS="-lnetwork"],
[RESOLV_LIBS="-lresolv"]) [RESOLV_LIBS="-lresolv"])
LIBS_TMP="${LIBS}" LIBS_TMP="${LIBS}"
@@ -157,8 +110,6 @@ AC_LINK_IFELSE([AC_LANG_SOURCE([
LIBS="${LIBS_TMP}" LIBS="${LIBS_TMP}"
PC_LIBS="${RESOLV_LIBS} ${PC_LIBS}" PC_LIBS="${RESOLV_LIBS} ${PC_LIBS}"
fi
m4_ifdef([PKG_INSTALLDIR], [PKG_INSTALLDIR], m4_ifdef([PKG_INSTALLDIR], [PKG_INSTALLDIR],
[AC_ARG_WITH([pkgconfigdir], [AC_ARG_WITH([pkgconfigdir],
[AS_HELP_STRING([--with-pkgconfigdir], [AS_HELP_STRING([--with-pkgconfigdir],
@@ -168,7 +119,6 @@ m4_ifdef([PKG_INSTALLDIR], [PKG_INSTALLDIR],
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]) AM_CONDITIONAL([DISABLE_TLS], [test x$enable_tls = xno])
AM_CONDITIONAL([TLS_WITH_GNUTLS], [test x$with_gnutls = xyes])
AC_SUBST([PC_REQUIRES], [${PC_REQUIRES}]) AC_SUBST([PC_REQUIRES], [${PC_REQUIRES}])
AC_SUBST([PC_CFLAGS], [${PC_CFLAGS}]) AC_SUBST([PC_CFLAGS], [${PC_CFLAGS}])
@@ -176,8 +126,6 @@ AC_SUBST([PC_LIBS], [${PC_LIBS}])
AC_SUBST(PARSER_CFLAGS) AC_SUBST(PARSER_CFLAGS)
AC_SUBST(PARSER_LIBS) AC_SUBST(PARSER_LIBS)
AC_SUBST(RESOLV_CFLAGS)
AC_SUBST(RESOLV_LIBS) AC_SUBST(RESOLV_LIBS)
AC_SUBST(WARNING_FLAGS)
AC_CONFIG_FILES([Makefile libstrophe.pc]) AC_CONFIG_FILES([Makefile libstrophe.pc])
AC_OUTPUT AC_OUTPUT

View File

2
docs/footer.html Normal file
View File

@@ -0,0 +1,2 @@
</body>
</html>

View File

@@ -1,7 +1,7 @@
/* active.c /* active.c
** libstrophe XMPP client library -- basic usage example ** libstrophe XMPP client library -- basic usage example
** **
** Copyright (C) 2005-2009 Collecta, Inc. ** Copyright (C) 2005-2009 Collecta, Inc.
** **
** This software is provided AS-IS with no warranty, either express ** This software is provided AS-IS with no warranty, either express
** or implied. ** or implied.
@@ -19,23 +19,23 @@
#include <strophe.h> #include <strophe.h>
int handle_reply(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata) int handle_reply(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza,
void * const userdata)
{ {
xmpp_stanza_t *query, *item; xmpp_stanza_t *query, *item;
const char *type; const char *type;
(void)userdata;
type = xmpp_stanza_get_type(stanza); type = xmpp_stanza_get_type(stanza);
if (strcmp(type, "error") == 0) if (strcmp(type, "error") == 0)
fprintf(stderr, "ERROR: query failed\n"); fprintf(stderr, "ERROR: query failed\n");
else { else {
query = xmpp_stanza_get_child_by_name(stanza, "query"); query = xmpp_stanza_get_child_by_name(stanza, "query");
printf("Active Sessions:\n"); printf("Active Sessions:\n");
for (item = xmpp_stanza_get_children(query); item; for (item = xmpp_stanza_get_children(query); item;
item = xmpp_stanza_get_next(item)) item = xmpp_stanza_get_next(item))
printf("\t %s\n", xmpp_stanza_get_attribute(item, "jid")); printf("\t %s\n", xmpp_stanza_get_attribute(item, "jid"));
printf("END OF LIST\n"); printf("END OF LIST\n");
} }
/* disconnect */ /* disconnect */
@@ -44,46 +44,41 @@ int handle_reply(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
return 0; return 0;
} }
void conn_handler(xmpp_conn_t *conn, void conn_handler(xmpp_conn_t * const conn, const xmpp_conn_event_t status,
xmpp_conn_event_t status, const int error, xmpp_stream_error_t * const stream_error,
int error, void * const userdata)
xmpp_stream_error_t *stream_error,
void *userdata)
{ {
xmpp_ctx_t *ctx = (xmpp_ctx_t *)userdata; xmpp_ctx_t *ctx = (xmpp_ctx_t *)userdata;
xmpp_stanza_t *iq, *query; xmpp_stanza_t *iq, *query;
(void)error;
(void)stream_error;
if (status == XMPP_CONN_CONNECT) { if (status == XMPP_CONN_CONNECT) {
fprintf(stderr, "DEBUG: connected\n"); fprintf(stderr, "DEBUG: connected\n");
/* create iq stanza for request */
iq = xmpp_iq_new(ctx, "get", "active1");
xmpp_stanza_set_to(iq, "xxxxxxxxx.com");
/* create iq stanza for request */ query = xmpp_stanza_new(ctx);
iq = xmpp_iq_new(ctx, "get", "active1"); xmpp_stanza_set_name(query, "query");
xmpp_stanza_set_to(iq, "xxxxxxxxx.com"); xmpp_stanza_set_ns(query, XMPP_NS_DISCO_ITEMS);
xmpp_stanza_set_attribute(query, "node", "sessions");
query = xmpp_stanza_new(ctx); xmpp_stanza_add_child(iq, query);
xmpp_stanza_set_name(query, "query");
xmpp_stanza_set_ns(query, XMPP_NS_DISCO_ITEMS);
xmpp_stanza_set_attribute(query, "node", "sessions");
xmpp_stanza_add_child(iq, query); /* we can release the stanza since it belongs to iq now */
xmpp_stanza_release(query);
/* we can release the stanza since it belongs to iq now */ /* set up reply handler */
xmpp_stanza_release(query); xmpp_id_handler_add(conn, handle_reply, "active1", ctx);
/* set up reply handler */ /* send out the stanza */
xmpp_id_handler_add(conn, handle_reply, "active1", ctx); xmpp_send(conn, iq);
/* send out the stanza */ /* release the stanza */
xmpp_send(conn, iq); xmpp_stanza_release(iq);
/* release the stanza */
xmpp_stanza_release(iq);
} else { } else {
fprintf(stderr, "DEBUG: disconnected\n"); fprintf(stderr, "DEBUG: disconnected\n");
xmpp_stop(ctx); xmpp_stop(ctx);
} }
} }
@@ -93,8 +88,8 @@ int main(int argc, char **argv)
xmpp_conn_t *conn; xmpp_conn_t *conn;
if (argc != 3) { if (argc != 3) {
fprintf(stderr, "Usage: active <jid> <pass>\n\n"); fprintf(stderr, "Usage: active <jid> <pass>\n\n");
return 1; return 1;
} }
/* initialize lib */ /* initialize lib */

View File

@@ -10,7 +10,6 @@
*/ */
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <strophe.h> #include <strophe.h>
@@ -19,149 +18,66 @@
#define KA_TIMEOUT 60 #define KA_TIMEOUT 60
#define KA_INTERVAL 1 #define KA_INTERVAL 1
static void print_tlscert(const xmpp_tlscert_t *cert)
{
const char *name;
size_t n;
for (n = 0; n < (unsigned)XMPP_CERT_ELEMENT_MAX; ++n) {
printf("\t%32s: %s\n", xmpp_tlscert_get_description(n),
xmpp_tlscert_get_string(cert, n));
}
n = 0;
while ((name = xmpp_tlscert_get_dnsname(cert, n++)) != NULL)
printf("\t%32s: %s\n", "dnsName", name);
printf("PEM:\n%s\n", xmpp_tlscert_get_pem(cert));
}
/* define a handler for connection events */ /* define a handler for connection events */
static void conn_handler(xmpp_conn_t *conn, void conn_handler(xmpp_conn_t * const conn, const xmpp_conn_event_t status,
xmpp_conn_event_t status, const int error, xmpp_stream_error_t * const stream_error,
int error, void * const userdata)
xmpp_stream_error_t *stream_error,
void *userdata)
{ {
xmpp_ctx_t *ctx = (xmpp_ctx_t *)userdata; xmpp_ctx_t *ctx = (xmpp_ctx_t *)userdata;
int secured; int secured;
(void)error;
(void)stream_error;
if (status == XMPP_CONN_CONNECT) { if (status == XMPP_CONN_CONNECT) {
fprintf(stderr, "DEBUG: connected\n"); fprintf(stderr, "DEBUG: connected\n");
secured = xmpp_conn_is_secured(conn); secured = xmpp_conn_is_secured(conn);
fprintf(stderr, "DEBUG: connection is %s.\n", fprintf(stderr, "DEBUG: connection is %s.\n",
secured ? "secured" : "NOT secured"); secured ? "secured" : "NOT secured");
if (secured) {
xmpp_tlscert_t *cert = xmpp_conn_get_peer_cert(conn);
print_tlscert(cert);
xmpp_tlscert_free(cert);
}
xmpp_disconnect(conn); xmpp_disconnect(conn);
} else { }
else {
fprintf(stderr, "DEBUG: disconnected\n"); fprintf(stderr, "DEBUG: disconnected\n");
xmpp_stop(ctx); xmpp_stop(ctx);
} }
} }
static int certfail_handler(const xmpp_tlscert_t *cert,
const char *const errormsg)
{
char read_char[16] = {0};
printf("Received certificate can't be validated!\n");
printf("Reason: %s\n", errormsg);
print_tlscert(cert);
printf("Do you agree to connect?\n[y(es)|n(o)]: ");
fflush(stdout);
if (fgets(read_char, sizeof(read_char), stdin) == NULL) {
printf("fgets() failed\n");
return 0;
}
printf("\n");
return read_char[0] == 'y' || read_char[0] == 'Y';
}
static void usage(int exit_code)
{
fprintf(stderr,
"Usage: basic [options] [<host> [<port>]]\n\n"
"Options:\n"
" --jid <jid> The JID to use to authenticate.\n"
" --pass <pass> The password of the JID.\n"
" --tls-cert <cert> Path to client certificate.\n"
" --capath <path> Path to an additional CA trust store "
"(directory).\n"
" --cafile <path> Path to an additional CA trust store "
"(single file).\n"
" --tls-key <key> Path to private key.\n\n"
" --disable-tls Disable TLS.\n"
" --mandatory-tls Deny plaintext connection.\n"
" --trust-tls Trust TLS certificate.\n"
" --enable-certfail Enable certfail handler.\n"
" --legacy-ssl Use old style SSL.\n"
" --legacy-auth Allow legacy authentication.\n"
" --verbose Increase the verbosity level.\n"
" --tcp-keepalive Configure TCP keepalive.\n\n"
"Note: --disable-tls conflicts with --mandatory-tls or "
"--legacy-ssl\n");
exit(exit_code);
}
int main(int argc, char **argv) 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 = NULL, *password = NULL, *cert = NULL, *key = NULL, *host = NULL, char *jid, *pass, *host = NULL;
*capath = NULL, *cafile = NULL;
long flags = 0; long flags = 0;
int tcp_keepalive = 0, verbosity = 0, certfail = 0; int tcp_keepalive = 0;
int i; int i;
unsigned long port = 0;
/* take a jid and password on the command line */ /* take a jid and password on the command line */
for (i = 1; i < argc; ++i) { for (i = 1; i < argc; ++i) {
if (strcmp(argv[i], "--help") == 0) if (strcmp(argv[i], "--disable-tls") == 0)
usage(0);
else if (strcmp(argv[i], "--disable-tls") == 0)
flags |= XMPP_CONN_FLAG_DISABLE_TLS; flags |= XMPP_CONN_FLAG_DISABLE_TLS;
else if (strcmp(argv[i], "--mandatory-tls") == 0) else if (strcmp(argv[i], "--mandatory-tls") == 0)
flags |= XMPP_CONN_FLAG_MANDATORY_TLS; flags |= XMPP_CONN_FLAG_MANDATORY_TLS;
else if (strcmp(argv[i], "--trust-tls") == 0)
flags |= XMPP_CONN_FLAG_TRUST_TLS;
else if (strcmp(argv[i], "--legacy-ssl") == 0) else if (strcmp(argv[i], "--legacy-ssl") == 0)
flags |= XMPP_CONN_FLAG_LEGACY_SSL; flags |= XMPP_CONN_FLAG_LEGACY_SSL;
else if (strcmp(argv[i], "--legacy-auth") == 0)
flags |= XMPP_CONN_FLAG_LEGACY_AUTH;
else if (strcmp(argv[i], "--verbose") == 0)
verbosity++;
else if (strcmp(argv[i], "--tcp-keepalive") == 0) else if (strcmp(argv[i], "--tcp-keepalive") == 0)
tcp_keepalive = 1; tcp_keepalive = 1;
else if (strcmp(argv[i], "--enable-certfail") == 0)
certfail = 1;
else if ((strcmp(argv[i], "--jid") == 0) && (++i < argc))
jid = argv[i];
else if ((strcmp(argv[i], "--pass") == 0) && (++i < argc))
password = argv[i];
else if ((strcmp(argv[i], "--tls-cert") == 0) && (++i < argc))
cert = argv[i];
else if ((strcmp(argv[i], "--tls-key") == 0) && (++i < argc))
key = argv[i];
else if ((strcmp(argv[i], "--capath") == 0) && (++i < argc))
capath = argv[i];
else if ((strcmp(argv[i], "--cafile") == 0) && (++i < argc))
cafile = argv[i];
else else
break; break;
} }
if ((!jid && (!cert || !key)) || (argc - i) > 2) { if ((argc - i) < 2 || (argc - i) > 3) {
usage(1); 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;
} }
if (i < argc) jid = argv[i];
host = argv[i]; pass = argv[i + 1];
if (i + 1 < argc) if (i + 2 < argc)
port = strtoul(argv[i + 1], NULL, 0); host = argv[i + 2];
/* /*
* Note, this example doesn't handle errors. Applications should check * Note, this example doesn't handle errors. Applications should check
@@ -171,11 +87,9 @@ int main(int argc, char **argv)
/* init library */ /* init library */
xmpp_initialize(); xmpp_initialize();
/* pass NULL instead to silence output */
log = xmpp_get_default_logger(XMPP_LEVEL_DEBUG);
/* create a context */ /* create a context */
log = xmpp_get_default_logger(XMPP_LEVEL_DEBUG); /* pass NULL instead to silence output */
ctx = xmpp_ctx_new(NULL, log); ctx = xmpp_ctx_new(NULL, log);
xmpp_ctx_set_verbosity(ctx, verbosity);
/* create a connection */ /* create a connection */
conn = xmpp_conn_new(ctx); conn = xmpp_conn_new(ctx);
@@ -183,32 +97,18 @@ int main(int argc, char **argv)
/* configure connection properties (optional) */ /* configure connection properties (optional) */
xmpp_conn_set_flags(conn, flags); xmpp_conn_set_flags(conn, flags);
/* configure TCP keepalive (optional) */ /* configure TCP keepalive (optional) */
if (tcp_keepalive) if (tcp_keepalive) xmpp_conn_set_keepalive(conn, KA_TIMEOUT, KA_INTERVAL);
xmpp_conn_set_keepalive(conn, KA_TIMEOUT, KA_INTERVAL);
/* setup authentication information */ /* setup authentication information */
if (cert && key) { xmpp_conn_set_jid(conn, jid);
xmpp_conn_set_client_cert(conn, cert, key); xmpp_conn_set_pass(conn, pass);
}
if (jid)
xmpp_conn_set_jid(conn, jid);
if (password)
xmpp_conn_set_pass(conn, password);
if (certfail)
xmpp_conn_set_certfail_handler(conn, certfail_handler);
if (capath)
xmpp_conn_set_capath(conn, capath);
if (cafile)
xmpp_conn_set_cafile(conn, cafile);
/* initiate connection */ /* initiate connection */
if (xmpp_connect_client(conn, host, port, conn_handler, ctx) == XMPP_EOK) { xmpp_connect_client(conn, host, 0, conn_handler, ctx);
/* enter the event loop - /* enter the event loop -
our connect handler will trigger an exit */ our connect handler will trigger an exit */
xmpp_run(ctx); xmpp_run(ctx);
}
/* release our connection and context */ /* release our connection and context */
xmpp_conn_release(conn); xmpp_conn_release(conn);

View File

@@ -1,7 +1,7 @@
/* bot.c /* bot.c
** libstrophe XMPP client library -- basic usage example ** libstrophe XMPP client library -- basic usage example
** **
** Copyright (C) 2005-2009 Collecta, Inc. ** Copyright (C) 2005-2009 Collecta, Inc.
** **
** This software is provided AS-IS with no warranty, either express ** This software is provided AS-IS with no warranty, either express
** or implied. ** or implied.
@@ -10,7 +10,7 @@
*/ */
/* simple bot example /* simple bot example
** **
** This example was provided by Matthew Wild <mwild1@gmail.com>. ** This example was provided by Matthew Wild <mwild1@gmail.com>.
** **
** This bot responds to basic messages and iq version requests. ** This bot responds to basic messages and iq version requests.
@@ -22,11 +22,12 @@
#include <strophe.h> #include <strophe.h>
int version_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *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; const 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_from(stanza)); printf("Received version request from %s\n", xmpp_stanza_get_from(stanza));
@@ -68,9 +69,10 @@ int version_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
return 1; return 1;
} }
int message_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
int message_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata)
{ {
xmpp_ctx_t *ctx = (xmpp_ctx_t *)userdata; xmpp_ctx_t *ctx = (xmpp_ctx_t*)userdata;
xmpp_stanza_t *body, *reply; xmpp_stanza_t *body, *reply;
const char *type; const char *type;
char *intext, *replytext; char *intext, *replytext;
@@ -85,8 +87,7 @@ int message_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
intext = xmpp_stanza_get_text(body); intext = xmpp_stanza_get_text(body);
printf("Incoming message from %s: %s\n", xmpp_stanza_get_from(stanza), printf("Incoming message from %s: %s\n", xmpp_stanza_get_from(stanza), intext);
intext);
reply = xmpp_stanza_reply(stanza); reply = xmpp_stanza_reply(stanza);
if (xmpp_stanza_get_type(reply) == NULL) if (xmpp_stanza_get_type(reply) == NULL)
@@ -96,7 +97,7 @@ int message_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
replytext = strdup("bye!"); replytext = strdup("bye!");
quit = 1; quit = 1;
} else { } else {
replytext = (char *)malloc(strlen(" to you too!") + strlen(intext) + 1); replytext = (char *) malloc(strlen(" to you too!") + strlen(intext) + 1);
strcpy(replytext, intext); strcpy(replytext, intext);
strcat(replytext, " to you too!"); strcat(replytext, " to you too!");
} }
@@ -114,29 +115,24 @@ int message_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
} }
/* define a handler for connection events */ /* define a handler for connection events */
void conn_handler(xmpp_conn_t *conn, void conn_handler(xmpp_conn_t * const conn, const xmpp_conn_event_t status,
xmpp_conn_event_t status, const int error, xmpp_stream_error_t * const stream_error,
int error, void * const userdata)
xmpp_stream_error_t *stream_error,
void *userdata)
{ {
xmpp_ctx_t *ctx = (xmpp_ctx_t *)userdata; xmpp_ctx_t *ctx = (xmpp_ctx_t *)userdata;
(void)error;
(void)stream_error;
if (status == XMPP_CONN_CONNECT) { if (status == XMPP_CONN_CONNECT) {
xmpp_stanza_t *pres; xmpp_stanza_t* pres;
fprintf(stderr, "DEBUG: connected\n"); fprintf(stderr, "DEBUG: connected\n");
xmpp_handler_add(conn, version_handler, "jabber:iq:version", "iq", NULL, xmpp_handler_add(conn, version_handler, "jabber:iq:version", "iq", NULL, ctx);
ctx);
xmpp_handler_add(conn, message_handler, NULL, "message", NULL, ctx); xmpp_handler_add(conn, message_handler, NULL, "message", NULL, ctx);
/* Send initial <presence/> so that we appear online to contacts */ /* Send initial <presence/> so that we appear online to contacts */
pres = xmpp_presence_new(ctx); pres = xmpp_presence_new(ctx);
xmpp_send(conn, pres); xmpp_send(conn, pres);
xmpp_stanza_release(pres); xmpp_stanza_release(pres);
} else { }
else {
fprintf(stderr, "DEBUG: disconnected\n"); fprintf(stderr, "DEBUG: disconnected\n");
xmpp_stop(ctx); xmpp_stop(ctx);
} }
@@ -161,9 +157,8 @@ int main(int argc, char **argv)
/* init library */ /* init library */
xmpp_initialize(); xmpp_initialize();
/* pass NULL instead to silence output */
log = xmpp_get_default_logger(XMPP_LEVEL_DEBUG);
/* create a context */ /* create a context */
log = xmpp_get_default_logger(XMPP_LEVEL_DEBUG); /* pass NULL instead to silence output */
ctx = xmpp_ctx_new(NULL, log); ctx = xmpp_ctx_new(NULL, log);
/* create a connection */ /* create a connection */
@@ -183,7 +178,7 @@ int main(int argc, char **argv)
/* initiate connection */ /* initiate connection */
xmpp_connect_client(conn, NULL, 0, conn_handler, ctx); xmpp_connect_client(conn, NULL, 0, conn_handler, ctx);
/* enter the event loop - /* enter the event loop -
our connect handler will trigger an exit */ our connect handler will trigger an exit */
xmpp_run(ctx); xmpp_run(ctx);

View File

@@ -19,22 +19,19 @@
#include <strophe.h> #include <strophe.h>
/* define a handler for connection events */ /* define a handler for connection events */
void conn_handler(xmpp_conn_t *conn, void conn_handler(xmpp_conn_t * const conn, const xmpp_conn_event_t status,
xmpp_conn_event_t status, const int error, xmpp_stream_error_t * const stream_error,
int error, void * const userdata)
xmpp_stream_error_t *stream_error,
void *userdata)
{ {
xmpp_ctx_t *ctx = (xmpp_ctx_t *)userdata; xmpp_ctx_t *ctx = (xmpp_ctx_t *)userdata;
(void)error;
(void)stream_error;
if (status == XMPP_CONN_CONNECT) { if (status == XMPP_CONN_CONNECT) {
fprintf(stderr, "DEBUG: connected\n"); fprintf(stderr, "DEBUG: connected\n");
xmpp_disconnect(conn); xmpp_disconnect(conn);
} else { }
else {
fprintf(stderr, "DEBUG: disconnected\n"); fprintf(stderr, "DEBUG: disconnected\n");
xmpp_stop(ctx); xmpp_stop(ctx);
} }
@@ -59,20 +56,19 @@ int main(int argc, char **argv)
host = argv[3]; host = argv[3];
if (argc == 5) { if (argc == 5) {
short tmp_port = (short)strtol(argv[4], &port_err, 10); short tmp_port = (short) strtol(argv[4], &port_err, 10);
if (tmp_port < 0 || *port_err != '\0') { if (tmp_port < 0 || *port_err != '\0') {
fprintf(stderr, "Invalid value of <port> [%s].\n", argv[4]); fprintf(stderr, "Invalid value of <port> [%s].\n", argv[4]);
return 1; return 1;
} }
port = (unsigned short)tmp_port; port = (unsigned short) tmp_port;
} }
/* init library */ /* init library */
xmpp_initialize(); xmpp_initialize();
/* pass NULL instead to silence output */
log = xmpp_get_default_logger(XMPP_LEVEL_DEBUG);
/* create a context */ /* create a context */
log = xmpp_get_default_logger(XMPP_LEVEL_DEBUG); /* pass NULL instead to silence output */
ctx = xmpp_ctx_new(NULL, log); ctx = xmpp_ctx_new(NULL, log);
/* create a connection */ /* create a connection */
@@ -98,3 +94,4 @@ int main(int argc, char **argv)
return 0; return 0;
} }

View File

@@ -1,363 +0,0 @@
/* register.c
* strophe XMPP client library -- In-band registration (XEP-0077)
*
* Copyright (C) 2020 Dmitry Podgorny <pasis.ua@gmail.com>
*
* This software is provided AS-IS with no warranty, either express
* or implied.
*
* This program is dual licensed under the MIT and GPLv3 licenses.
*/
/*
* This example uses a "raw" connection to establish connection to a server
* without account. Then it queries server to register new account according
* to XEP-0077.
*
* How to use it. After the application connects and receives instructions
* from the server, user will be prompted to type information such as
* username, password, etc. Press enter without typing if you want to skip
* a field and not to send it to the server.
*
* Notice, the example doesn't implement forms. Therefore, it won't work
* in complicated scenarios.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strophe.h>
typedef struct {
xmpp_ctx_t *ctx;
const char *jid;
} xmpp_reg_t;
#define FEATURES_TIMEOUT 5000 /* 5 seconds */
static void
iq_reg_send_form(xmpp_reg_t *reg, xmpp_conn_t *conn, xmpp_stanza_t *stanza)
{
xmpp_ctx_t *ctx = reg->ctx;
xmpp_stanza_t *query;
xmpp_stanza_t *next;
xmpp_stanza_t *elem;
xmpp_stanza_t *text;
xmpp_stanza_t *iq;
const char *name;
size_t len;
char buf[256];
char *s;
query = xmpp_stanza_get_child_by_name(stanza, "query");
if (!query) {
xmpp_disconnect(conn);
return;
}
next = xmpp_stanza_get_children(query);
query = xmpp_stanza_new(ctx);
xmpp_stanza_set_name(query, "query");
xmpp_stanza_set_ns(query, XMPP_NS_REGISTER);
while (next) {
name = xmpp_stanza_get_name(next);
if (name && strcmp(name, "instructions") == 0) {
s = xmpp_stanza_get_text(next);
printf("instructions: %s\n", s);
xmpp_free(ctx, s);
} else {
printf("%s: ", name);
s = fgets(buf, sizeof(buf), stdin);
if (s != NULL) {
len = strlen(s);
if (len > 0 && s[len - 1] == '\n') {
s[len - 1] = '\0';
--len;
}
if (len > 0) {
elem = xmpp_stanza_new(ctx);
text = xmpp_stanza_new(ctx);
xmpp_stanza_set_text(text, s);
xmpp_stanza_set_name(elem, name);
xmpp_stanza_add_child(elem, text);
xmpp_stanza_add_child(query, elem);
xmpp_stanza_release(text);
xmpp_stanza_release(elem);
}
}
}
next = xmpp_stanza_get_next(next);
}
if (xmpp_stanza_get_children(query) == NULL) {
fprintf(stderr, "DEBUG: nothing to send\n");
xmpp_disconnect(conn);
} else {
iq = xmpp_iq_new(ctx, "set", "reg2");
xmpp_stanza_add_child(iq, query);
xmpp_stanza_release(query);
xmpp_send(conn, iq);
xmpp_stanza_release(iq);
}
}
static int iq_reg2_cb(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
{
const char *type;
(void)userdata;
type = xmpp_stanza_get_type(stanza);
if (!type || strcmp(type, "error") == 0) {
fprintf(stderr, "DEBUG: error during registration\n");
goto quit;
}
if (strcmp(type, "result") != 0) {
fprintf(stderr, "DEBUG: expected type 'result', but got %s\n", type);
goto quit;
}
fprintf(stderr, "DEBUG: successful registration\n");
quit:
xmpp_disconnect(conn);
return 0;
}
static int iq_reg_cb(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
{
xmpp_reg_t *reg = (xmpp_reg_t *)userdata;
xmpp_stanza_t *registered = NULL;
xmpp_stanza_t *query;
const char *type;
type = xmpp_stanza_get_type(stanza);
if (!type || strcmp(type, "error") == 0) {
fprintf(stderr, "DEBUG: error during registration\n");
xmpp_disconnect(conn);
goto quit;
}
if (strcmp(type, "result") != 0) {
fprintf(stderr, "DEBUG: expected type 'result', but got %s\n", type);
xmpp_disconnect(conn);
goto quit;
}
query = xmpp_stanza_get_child_by_name(stanza, "query");
if (query)
registered = xmpp_stanza_get_child_by_name(query, "registered");
if (registered != NULL) {
fprintf(stderr, "DEBUG: already registered\n");
xmpp_disconnect(conn);
goto quit;
}
xmpp_id_handler_add(conn, iq_reg2_cb, "reg2", reg);
iq_reg_send_form(reg, conn, stanza);
quit:
return 0;
}
static int
_handle_error(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
{
(void)stanza;
(void)userdata;
fprintf(stderr, "DEBUG: received stream error\n");
xmpp_disconnect(conn);
return 0;
}
static int _handle_proceedtls_default(xmpp_conn_t *conn,
xmpp_stanza_t *stanza,
void *userdata)
{
const char *name = xmpp_stanza_get_name(stanza);
(void)userdata;
if (strcmp(name, "proceed") == 0) {
fprintf(stderr, "DEBUG: proceeding with TLS\n");
if (xmpp_conn_tls_start(conn) == 0) {
xmpp_handler_delete(conn, _handle_error);
xmpp_conn_open_stream_default(conn);
} else {
fprintf(stderr, "DEBUG: TLS failed\n");
/* failed tls spoils the connection, so disconnect */
xmpp_disconnect(conn);
}
}
return 0;
}
static int _handle_missing_features(xmpp_conn_t *conn, void *userdata)
{
(void)userdata;
fprintf(stderr, "DEBUG: timeout\n");
xmpp_disconnect(conn);
return 0;
}
static int
_handle_features(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
{
xmpp_reg_t *reg = (xmpp_reg_t *)userdata;
xmpp_ctx_t *ctx = reg->ctx;
xmpp_stanza_t *child;
xmpp_stanza_t *iq;
char *domain;
xmpp_timed_handler_delete(conn, _handle_missing_features);
/* secure connection if possible */
child = xmpp_stanza_get_child_by_name(stanza, "starttls");
if (child && (strcmp(xmpp_stanza_get_ns(child), XMPP_NS_TLS) == 0)) {
fprintf(stderr, "DEBUG: server supports TLS, try to establish\n");
child = xmpp_stanza_new(ctx);
xmpp_stanza_set_name(child, "starttls");
xmpp_stanza_set_ns(child, XMPP_NS_TLS);
xmpp_handler_add(conn, _handle_proceedtls_default, XMPP_NS_TLS, NULL,
NULL, NULL);
xmpp_send(conn, child);
xmpp_stanza_release(child);
return 0;
}
/* check whether server supports in-band registration */
child = xmpp_stanza_get_child_by_name(stanza, "register");
if (child && strcmp(xmpp_stanza_get_ns(child), XMPP_NS_REGISTER) == 0) {
fprintf(stderr, "DEBUG: server doesn't support in-band registration\n");
xmpp_disconnect(conn);
return 0;
}
fprintf(stderr, "DEBUG: server supports in-band registration\n");
domain = xmpp_jid_domain(ctx, reg->jid);
iq = xmpp_iq_new(ctx, "get", "reg1");
xmpp_stanza_set_to(iq, domain);
child = xmpp_stanza_new(ctx);
xmpp_stanza_set_name(child, "query");
xmpp_stanza_set_ns(child, XMPP_NS_REGISTER);
xmpp_stanza_add_child(iq, child);
xmpp_handler_add(conn, iq_reg_cb, XMPP_NS_REGISTER, "iq", NULL, reg);
xmpp_send(conn, iq);
xmpp_free(ctx, domain);
xmpp_stanza_release(child);
xmpp_stanza_release(iq);
return 0;
}
static void conn_handler(xmpp_conn_t *conn,
xmpp_conn_event_t status,
int error,
xmpp_stream_error_t *stream_error,
void *userdata)
{
xmpp_reg_t *reg = (xmpp_reg_t *)userdata;
int secured;
(void)error;
(void)stream_error;
if (status == XMPP_CONN_RAW_CONNECT) {
fprintf(stderr, "DEBUG: raw connection established\n");
xmpp_conn_open_stream_default(conn);
} else if (status == XMPP_CONN_CONNECT) {
fprintf(stderr, "DEBUG: stream opened\n");
secured = xmpp_conn_is_secured(conn);
fprintf(stderr, "DEBUG: connection is %s.\n",
secured ? "secured" : "NOT secured");
/* setup handler for stream:error */
xmpp_handler_add(conn, _handle_error, XMPP_NS_STREAMS, "error", NULL,
NULL);
/* setup handlers for incoming <stream:features> */
xmpp_handler_add(conn, _handle_features, XMPP_NS_STREAMS, "features",
NULL, reg);
xmpp_timed_handler_add(conn, _handle_missing_features, FEATURES_TIMEOUT,
NULL);
} else {
fprintf(stderr, "DEBUG: disconnected\n");
xmpp_stop(reg->ctx);
}
}
xmpp_reg_t *xmpp_reg_new(void)
{
xmpp_reg_t *reg;
reg = malloc(sizeof(*reg));
if (reg != NULL) {
memset(reg, 0, sizeof(*reg));
}
return reg;
}
void xmpp_reg_release(xmpp_reg_t *reg)
{
free(reg);
}
int main(int argc, char **argv)
{
xmpp_ctx_t *ctx;
xmpp_conn_t *conn;
xmpp_log_t *log;
xmpp_reg_t *reg;
const char *jid;
const char *host = NULL;
char *domain;
if (argc < 2 || argc > 3) {
fprintf(stderr, "Usage: %s <jid> [<host>]\n", argv[0]);
return 1;
}
jid = argv[1];
if (argc > 2)
host = argv[2];
/*
* Note, this example doesn't handle errors. Applications should check
* return values of non-void functions.
*/
xmpp_initialize();
log = xmpp_get_default_logger(XMPP_LEVEL_DEBUG);
ctx = xmpp_ctx_new(NULL, log);
conn = xmpp_conn_new(ctx);
/* jid can be a jid or domain for "raw" connection */
domain = xmpp_jid_domain(ctx, jid);
xmpp_conn_set_jid(conn, domain);
xmpp_free(ctx, domain);
/* private data */
reg = xmpp_reg_new();
reg->ctx = ctx;
reg->jid = jid;
xmpp_connect_raw(conn, host, 0, conn_handler, reg);
xmpp_run(ctx);
/* release private data */
xmpp_reg_release(reg);
xmpp_conn_release(conn);
xmpp_ctx_free(ctx);
xmpp_shutdown();
return 0;
}

View File

@@ -1,7 +1,7 @@
/* roster.c /* roster.c
** libstrophe XMPP client library -- handler example ** libstrophe XMPP client library -- handler example
** **
** Copyright (C) 2005-2009 Collecta, Inc. ** Copyright (C) 2005-2009 Collecta, Inc.
** **
** This software is provided AS-IS with no warranty, either express ** This software is provided AS-IS with no warranty, either express
** or implied. ** or implied.
@@ -18,29 +18,31 @@
#include <strophe.h> #include <strophe.h>
int handle_reply(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata) int handle_reply(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza,
void * const userdata)
{ {
xmpp_stanza_t *query, *item; xmpp_stanza_t *query, *item;
const char *type, *name; const char *type, *name;
(void)userdata;
type = xmpp_stanza_get_type(stanza); type = xmpp_stanza_get_type(stanza);
if (strcmp(type, "error") == 0) if (strcmp(type, "error") == 0)
fprintf(stderr, "ERROR: query failed\n"); fprintf(stderr, "ERROR: query failed\n");
else { else {
query = xmpp_stanza_get_child_by_name(stanza, "query"); query = xmpp_stanza_get_child_by_name(stanza, "query");
printf("Roster:\n"); printf("Roster:\n");
for (item = xmpp_stanza_get_children(query); item; for (item = xmpp_stanza_get_children(query); item;
item = xmpp_stanza_get_next(item)) item = xmpp_stanza_get_next(item))
if ((name = xmpp_stanza_get_attribute(item, "name"))) if ((name = xmpp_stanza_get_attribute(item, "name")))
printf("\t %s (%s) sub=%s\n", name, printf("\t %s (%s) sub=%s\n",
xmpp_stanza_get_attribute(item, "jid"), name,
xmpp_stanza_get_attribute(item, "subscription")); xmpp_stanza_get_attribute(item, "jid"),
else xmpp_stanza_get_attribute(item, "subscription"));
printf("\t %s sub=%s\n", xmpp_stanza_get_attribute(item, "jid"), else
xmpp_stanza_get_attribute(item, "subscription")); printf("\t %s sub=%s\n",
printf("END OF LIST\n"); xmpp_stanza_get_attribute(item, "jid"),
xmpp_stanza_get_attribute(item, "subscription"));
printf("END OF LIST\n");
} }
/* disconnect */ /* disconnect */
@@ -49,44 +51,39 @@ int handle_reply(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
return 0; return 0;
} }
void conn_handler(xmpp_conn_t *conn, void conn_handler(xmpp_conn_t * const conn, const xmpp_conn_event_t status,
xmpp_conn_event_t status, const int error, xmpp_stream_error_t * const stream_error,
int error, void * const userdata)
xmpp_stream_error_t *stream_error,
void *userdata)
{ {
xmpp_ctx_t *ctx = (xmpp_ctx_t *)userdata; xmpp_ctx_t *ctx = (xmpp_ctx_t *)userdata;
xmpp_stanza_t *iq, *query; xmpp_stanza_t *iq, *query;
(void)error;
(void)stream_error;
if (status == XMPP_CONN_CONNECT) { if (status == XMPP_CONN_CONNECT) {
fprintf(stderr, "DEBUG: connected\n"); fprintf(stderr, "DEBUG: connected\n");
/* create iq stanza for request */
iq = xmpp_iq_new(ctx, "get", "roster1");
/* create iq stanza for request */ query = xmpp_stanza_new(ctx);
iq = xmpp_iq_new(ctx, "get", "roster1"); xmpp_stanza_set_name(query, "query");
xmpp_stanza_set_ns(query, XMPP_NS_ROSTER);
query = xmpp_stanza_new(ctx); xmpp_stanza_add_child(iq, query);
xmpp_stanza_set_name(query, "query");
xmpp_stanza_set_ns(query, XMPP_NS_ROSTER);
xmpp_stanza_add_child(iq, query); /* we can release the stanza since it belongs to iq now */
xmpp_stanza_release(query);
/* we can release the stanza since it belongs to iq now */ /* set up reply handler */
xmpp_stanza_release(query); xmpp_id_handler_add(conn, handle_reply, "roster1", ctx);
/* set up reply handler */ /* send out the stanza */
xmpp_id_handler_add(conn, handle_reply, "roster1", ctx); xmpp_send(conn, iq);
/* send out the stanza */ /* release the stanza */
xmpp_send(conn, iq); xmpp_stanza_release(iq);
/* release the stanza */
xmpp_stanza_release(iq);
} else { } else {
fprintf(stderr, "DEBUG: disconnected\n"); fprintf(stderr, "DEBUG: disconnected\n");
xmpp_stop(ctx); xmpp_stop(ctx);
} }
} }
@@ -96,8 +93,8 @@ int main(int argc, char **argv)
xmpp_conn_t *conn; xmpp_conn_t *conn;
if (argc != 3) { if (argc != 3) {
fprintf(stderr, "Usage: roster <jid> <pass>\n\n"); fprintf(stderr, "Usage: roster <jid> <pass>\n\n");
return 1; return 1;
} }
/* initialize lib */ /* initialize lib */

83
examples/server.c Normal file
View File

@@ -0,0 +1,83 @@
#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,7 +1,7 @@
#include <stdio.h> #include <stdio.h>
#include <strophe.h> #include <strophe.h>
int main() int main(int argc, char **argv)
{ {
xmpp_ctx_t *ctx; xmpp_ctx_t *ctx;
char *uuid; char *uuid;

View File

@@ -76,8 +76,8 @@ static void vcard_photo(vcard_t *vc, xmpp_stanza_t *stanza)
xmpp_free(vc->ctx, img); xmpp_free(vc->ctx, img);
} }
static void static void vcard_print_string(vcard_t *vc, xmpp_stanza_t *stanza,
vcard_print_string(vcard_t *vc, xmpp_stanza_t *stanza, const char *info) const char *info)
{ {
char *s = xmpp_stanza_get_text(stanza); char *s = xmpp_stanza_get_text(stanza);
@@ -140,9 +140,14 @@ static vcard_cb_t vcard_cb_get(xmpp_stanza_t *stanza)
const char *tag; const char *tag;
vcard_cb_t cb; vcard_cb_t cb;
} vcard_tbl[] = { } vcard_tbl[] = {
{"PHOTO", vcard_photo}, {"BDAY", vcard_bday}, {"DESC", vcard_desc}, { "PHOTO", vcard_photo },
{"EMAIL", vcard_email}, {"FN", vcard_fn}, {"N", vcard_name}, { "BDAY", vcard_bday },
{"NICKNAME", vcard_nick}, {"URL", vcard_url}, { "DESC", vcard_desc },
{ "EMAIL", vcard_email },
{ "FN", vcard_fn },
{ "N", vcard_name },
{ "NICKNAME", vcard_nick },
{ "URL", vcard_url },
}; };
tag = xmpp_stanza_get_name(stanza); tag = xmpp_stanza_get_name(stanza);
@@ -160,17 +165,16 @@ exit:
return cb; return cb;
} }
static int timedout(xmpp_conn_t *conn, void *userdata) static int timedout(xmpp_conn_t * const conn, void * const userdata)
{ {
(void)userdata;
fprintf(stderr, "Timeout reached.\n"); fprintf(stderr, "Timeout reached.\n");
xmpp_disconnect(conn); xmpp_disconnect(conn);
return 0; return 0;
} }
static int recv_vcard(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata) static int recv_vcard(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza,
void * const userdata)
{ {
vcard_t *vc = userdata; vcard_t *vc = userdata;
vcard_cb_t cb; vcard_cb_t cb;
@@ -209,17 +213,16 @@ exit:
static void send_vcard_req(xmpp_conn_t *conn, const char *to, const char *id) static void send_vcard_req(xmpp_conn_t *conn, const char *to, const char *id)
{ {
printf("Requesting vCard from %s.\n", to); printf("Requesting vCard from %s.\n", to);
xmpp_send_raw_string(conn, xmpp_send_raw_string(conn, "<iq from='%s' to='%s' type='get' id='%s'>"
"<iq from='%s' to='%s' type='get' id='%s'>" "<vCard xmlns='vcard-temp'/></iq>",
"<vCard xmlns='vcard-temp'/></iq>", xmpp_conn_get_bound_jid(conn), to, id);
xmpp_conn_get_bound_jid(conn), to, id);
} }
static void conn_handler(xmpp_conn_t *conn, static void conn_handler(xmpp_conn_t * const conn,
xmpp_conn_event_t status, const xmpp_conn_event_t status,
int error, const int error,
xmpp_stream_error_t *stream_error, xmpp_stream_error_t * const stream_error,
void *userdata) void * const userdata)
{ {
vcard_t *vc = userdata; vcard_t *vc = userdata;
@@ -232,26 +235,25 @@ static void conn_handler(xmpp_conn_t *conn,
fprintf(stderr, "Disconnected with error=%d.\n", error); fprintf(stderr, "Disconnected with error=%d.\n", error);
if (stream_error != NULL) if (stream_error != NULL)
fprintf(stderr, "Stream error type=%d text=%s.\n", fprintf(stderr, "Stream error type=%d text=%s.\n",
stream_error->type, stream_error->text); stream_error->type, stream_error->text);
xmpp_stop(vc->ctx); xmpp_stop(vc->ctx);
} }
} }
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
xmpp_log_t *log; xmpp_log_t *log;
xmpp_ctx_t *ctx; xmpp_ctx_t *ctx;
xmpp_conn_t *conn; xmpp_conn_t *conn;
const char *jid; const char *jid;
const char *pass; const char *pass;
char *prog; char *prog;
vcard_t vcard; vcard_t vcard;
if (argc < 4 || argc > 5) { if (argc < 4 || argc > 5) {
prog = argc > 0 ? strdup(argv[0]) : NULL; prog = argc > 0 ? strdup(argv[0]) : NULL;
printf("Usage: %s <login-jid> <password> <recipient-jid> " printf("Usage: %s <login-jid> <password> <recipient-jid> "
"[image-file]\n\n", "[image-file]\n\n", prog == NULL ? "vcard" : basename(prog));
prog == NULL ? "vcard" : basename(prog));
printf("If vCard contains a photo it will be stored to " printf("If vCard contains a photo it will be stored to "
"image-file. If you don't provide the image-file " "image-file. If you don't provide the image-file "
"default filename will be generated.\n"); "default filename will be generated.\n");
@@ -279,3 +281,4 @@ int main(int argc, char **argv)
return 0; return 0;
} }

View File

@@ -23,7 +23,7 @@ include $(BUILD_EXECUTABLE)
include $(CLEAR_VARS) include $(CLEAR_VARS)
LOCAL_MODULE := libstrophe LOCAL_MODULE := libstrophe
LOCAL_CFLAGS := -DHAVE_DECL_VA_COPY LOCAL_CFLAGS :=
LOCAL_C_INCLUDES := \ LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/.. \ $(LOCAL_PATH)/.. \
$(LOCAL_PATH)/../src \ $(LOCAL_PATH)/../src \
@@ -44,9 +44,8 @@ LOCAL_SRC_FILES := \
../src/resolver.c \ ../src/resolver.c \
../src/sasl.c \ ../src/sasl.c \
../src/scram.c \ ../src/scram.c \
../src/server.c \
../src/sha1.c \ ../src/sha1.c \
../src/sha256.c \
../src/sha512.c \
../src/snprintf.c \ ../src/snprintf.c \
../src/sock.c \ ../src/sock.c \
../src/stanza.c \ ../src/stanza.c \
@@ -64,7 +63,7 @@ include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS) include $(CLEAR_VARS)
LOCAL_MODULE := libexpat LOCAL_MODULE := libexpat
LOCAL_CFLAGS := -DHAVE_MEMMOVE -DXML_DEV_URANDOM LOCAL_CFLAGS := -DHAVE_MEMMOVE
#LOCAL_C_INCLUDES := \ #LOCAL_C_INCLUDES := \
# $(LOCAL_PATH)/expat # $(LOCAL_PATH)/expat

View File

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

31
rpm/README Normal file
View File

@@ -0,0 +1,31 @@
1. Setup
yum install gcc make autoconf automake expat-devel openssl-devel
Fedora:
yum install fedora-packager
cd ~
rpmdev-setuptree
CentOS:
mkdir -p ~/rpmbuild/{BUILD,RPMS,SOURCES,SPECS,SRPMS}
Then make a tarball of sources:
tar czf libstrophe_git.tar.gz libstrophe
2. Build
cp libstrophe.spec ~/rpmbuild/SPECS
cp libstrophe_git.tar.gz ~/rpmbuild/SOURCES
rpmbuild -bb ~/rpmbuild/SPECS/libstrophe.spec
3. Install
yum localinstall ~/rpmbuild/RPMS/<arch>/libstrophe-1.1<dist>.<arch>.rpm
Or, if localinstall is not recognised:
rpm -i ~/rpmbuild/RPMS/<arch>/libstrophe-1.1<dist>.<arch>.rpm

59
rpm/libstrophe.spec Normal file
View File

@@ -0,0 +1,59 @@
Name: libstrophe
Version: 1
Release: 1%{?dist}_git
Summary: xmpp library in C
Group: Application/System
License: MIT/GPLv3
URL: http://strophe.im/libstrophe/
Source0: libstrophe_git.tar.gz
BuildRequires: autoconf
BuildRequires: automake
BuildRequires: libtool
BuildRequires: openssl-devel
BuildRequires: expat-devel
Requires: openssl
Requires: expat
%description
XMPP library in C
%package devel
Summary: Headers and libraries for building apps that use libstrophe
Group: Development/Libraries
Requires: %{name} = %{version}-%{release}
%description devel
This package contains headers and libraries required to build applications that
use the strophe XMPP library.
%prep
%setup -n libstrophe
./bootstrap.sh
%build
%configure
make %{?_smp_mflags}
%install
make install DESTDIR=%{buildroot}
%post -p /sbin/ldconfig
%postun -p /sbin/ldconfig
%files
%defattr(-,root,root,-)
%{_libdir}/libstrophe.so*
%doc
%files devel
%defattr(-,root,root,-)
%{_libdir}/libstrophe.a
%{_libdir}/libstrophe.la
%{_libdir}/pkgconfig/libstrophe.pc
%{_includedir}/strophe.h
%doc
%changelog

1344
src/auth.c

File diff suppressed because it is too large Load Diff

View File

@@ -19,6 +19,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdarg.h> #include <stdarg.h>
#include "strophe.h" #include "strophe.h"
#include "ostypes.h" #include "ostypes.h"
#include "sock.h" #include "sock.h"
@@ -29,7 +30,84 @@
#include "rand.h" #include "rand.h"
#include "snprintf.h" #include "snprintf.h"
/** handlers **/ /** run-time context **/
typedef enum {
XMPP_LOOP_NOTSTARTED,
XMPP_LOOP_RUNNING,
XMPP_LOOP_QUIT
} xmpp_loop_status_t;
typedef struct _xmpp_connlist_t {
xmpp_conn_t *conn;
struct _xmpp_connlist_t *next;
} xmpp_connlist_t;
typedef struct _xmpp_serverlist_t {
xmpp_server_t *server;
struct _xmpp_serverlist_t *next;
} xmpp_serverlist_t;
struct _xmpp_ctx_t {
const xmpp_mem_t *mem;
const xmpp_log_t *log;
xmpp_rand_t *rand;
xmpp_loop_status_t loop_status;
xmpp_connlist_t *connlist;
xmpp_serverlist_t *serverlist;
unsigned long timeout;
};
/* convenience functions for accessing the context */
void *xmpp_alloc(const xmpp_ctx_t * const ctx, const size_t size);
void *xmpp_realloc(const xmpp_ctx_t * const ctx, void *p,
const size_t size);
char *xmpp_strdup(const xmpp_ctx_t * const ctx, const char * const s);
void xmpp_log(const xmpp_ctx_t * const ctx,
const xmpp_log_level_t level,
const char * const area,
const char * const fmt,
va_list ap);
/* wrappers for xmpp_log at specific levels */
void xmpp_error(const xmpp_ctx_t * const ctx,
const char * const area,
const char * const fmt,
...);
void xmpp_warn(const xmpp_ctx_t * const ctx,
const char * const area,
const char * const fmt,
...);
void xmpp_info(const xmpp_ctx_t * const ctx,
const char * const area,
const char * const fmt,
...);
void xmpp_debug(const xmpp_ctx_t * const ctx,
const char * const area,
const char * const fmt,
...);
/** connection **/
/* opaque connection object */
typedef enum {
XMPP_STATE_DISCONNECTED,
XMPP_STATE_CONNECTING,
XMPP_STATE_CONNECTED
} xmpp_conn_state_t;
typedef struct _xmpp_send_queue_t xmpp_send_queue_t;
struct _xmpp_send_queue_t {
char *data;
size_t len;
size_t written;
xmpp_send_queue_t *next;
};
typedef struct _xmpp_handlist_t xmpp_handlist_t; typedef struct _xmpp_handlist_t xmpp_handlist_t;
struct _xmpp_handlist_t { struct _xmpp_handlist_t {
@@ -58,87 +136,15 @@ struct _xmpp_handlist_t {
char *name; char *name;
char *type; char *type;
}; };
} u; };
}; };
/** run-time context **/
typedef enum {
XMPP_LOOP_NOTSTARTED,
XMPP_LOOP_RUNNING,
XMPP_LOOP_QUIT
} xmpp_loop_status_t;
typedef struct _xmpp_connlist_t {
xmpp_conn_t *conn;
struct _xmpp_connlist_t *next;
} xmpp_connlist_t;
struct _xmpp_ctx_t {
const xmpp_mem_t *mem;
const xmpp_log_t *log;
int verbosity;
xmpp_rand_t *rand;
xmpp_loop_status_t loop_status;
xmpp_connlist_t *connlist;
xmpp_handlist_t *timed_handlers;
unsigned long timeout;
};
/* convenience functions for accessing the context */
void *xmpp_alloc(const xmpp_ctx_t *ctx, size_t size);
void *xmpp_realloc(const xmpp_ctx_t *ctx, void *p, size_t size);
char *xmpp_strdup(const xmpp_ctx_t *ctx, const char *s);
char *xmpp_strndup(const xmpp_ctx_t *ctx, const char *s, size_t len);
void xmpp_log(const xmpp_ctx_t *ctx,
const xmpp_log_level_t level,
const char *area,
const char *fmt,
va_list ap);
/* wrappers for xmpp_log at specific levels */
void xmpp_error(const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...);
void xmpp_warn(const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...);
void xmpp_info(const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...);
void xmpp_debug(const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...);
void xmpp_debug_verbose(
int level, const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...);
/** connection **/
/* opaque connection object */
typedef enum {
XMPP_STATE_DISCONNECTED,
XMPP_STATE_CONNECTING,
XMPP_STATE_CONNECTED
} xmpp_conn_state_t;
typedef struct _xmpp_send_queue_t xmpp_send_queue_t;
struct _xmpp_send_queue_t {
char *data;
size_t len;
size_t written;
xmpp_send_queue_t *next;
};
#define UNUSED(x) ((void)(x))
#define MAX_DOMAIN_LEN 256 #define MAX_DOMAIN_LEN 256
#define SASL_MASK_PLAIN (1 << 0) #define SASL_MASK_PLAIN (1 << 0)
#define SASL_MASK_DIGESTMD5 (1 << 1) #define SASL_MASK_DIGESTMD5 (1 << 1)
#define SASL_MASK_ANONYMOUS (1 << 2) #define SASL_MASK_ANONYMOUS (1 << 2)
#define SASL_MASK_SCRAMSHA1 (1 << 3) #define SASL_MASK_SCRAMSHA1 (1 << 3)
#define SASL_MASK_SCRAMSHA256 (1 << 4)
#define SASL_MASK_SCRAMSHA512 (1 << 5)
#define SASL_MASK_EXTERNAL (1 << 6)
#define SASL_MASK_SCRAM \
(SASL_MASK_SCRAMSHA1 | SASL_MASK_SCRAMSHA256 | SASL_MASK_SCRAMSHA512)
enum { enum {
XMPP_PORT_CLIENT = 5222, XMPP_PORT_CLIENT = 5222,
@@ -146,7 +152,7 @@ enum {
XMPP_PORT_COMPONENT = 5347, XMPP_PORT_COMPONENT = 5347,
}; };
typedef void (*xmpp_open_handler)(xmpp_conn_t *conn); typedef void (*xmpp_open_handler)(xmpp_conn_t * const conn);
struct _xmpp_conn_t { struct _xmpp_conn_t {
unsigned int ref; unsigned int ref;
@@ -160,7 +166,7 @@ struct _xmpp_conn_t {
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_timeout; /* TCP keepalive timeout */
int ka_interval; /* TCP keepalive interval */ int ka_interval; /* TCP keepalive interval */
tls_t *tls; tls_t *tls;
@@ -169,16 +175,10 @@ struct _xmpp_conn_t {
int tls_mandatory; int tls_mandatory;
int tls_legacy_ssl; int tls_legacy_ssl;
int tls_trust; int tls_trust;
char *tls_cafile; int tls_failed; /* set when tls fails, so we don't try again */
char *tls_capath; int sasl_support; /* if true, field is a bitfield of supported
char *tls_client_cert;
char *tls_client_key;
int tls_failed; /* set when tls fails, so we don't try again */
int sasl_support; /* if true, field is a bitfield of supported
mechanisms */ mechanisms */
int auth_legacy_enabled;
int secured; /* set when stream is secured with TLS */ int secured; /* set when stream is secured with TLS */
xmpp_certfail_handler certfail_handler;
/* if server returns <bind/> or <session/> we must do them */ /* if server returns <bind/> or <session/> we must do them */
int bind_required; int bind_required;
@@ -212,7 +212,7 @@ struct _xmpp_conn_t {
/* user handlers only get called after authentication */ /* user handlers only get called after authentication */
int authenticated; int authenticated;
/* connection events handler */ /* connection events handler */
xmpp_conn_handler conn_handler; xmpp_conn_handler conn_handler;
void *userdata; void *userdata;
@@ -223,13 +223,32 @@ struct _xmpp_conn_t {
xmpp_handlist_t *handlers; xmpp_handlist_t *handlers;
}; };
void conn_disconnect(xmpp_conn_t *conn); void conn_disconnect(xmpp_conn_t * const conn);
void conn_disconnect_clean(xmpp_conn_t *conn); void conn_disconnect_clean(xmpp_conn_t * const conn);
void conn_established(xmpp_conn_t *conn); void conn_established(xmpp_conn_t * const conn);
void conn_open_stream(xmpp_conn_t *conn); void conn_open_stream(xmpp_conn_t * const conn);
int conn_tls_start(xmpp_conn_t *conn); int conn_tls_start(xmpp_conn_t * const conn);
void conn_prepare_reset(xmpp_conn_t *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 *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,
@@ -242,7 +261,7 @@ struct _xmpp_stanza_t {
xmpp_ctx_t *ctx; xmpp_ctx_t *ctx;
xmpp_stanza_type_t type; xmpp_stanza_type_t type;
xmpp_stanza_t *prev; xmpp_stanza_t *prev;
xmpp_stanza_t *next; xmpp_stanza_t *next;
xmpp_stanza_t *children; xmpp_stanza_t *children;
@@ -254,32 +273,33 @@ struct _xmpp_stanza_t {
}; };
/* handler management */ /* handler management */
void handler_fire_stanza(xmpp_conn_t *conn, xmpp_stanza_t *stanza); void handler_fire_stanza(xmpp_conn_t * const conn,
uint64_t handler_fire_timed(xmpp_ctx_t *ctx); xmpp_stanza_t * const stanza);
uint64_t handler_fire_timed(xmpp_ctx_t * const ctx);
void handler_reset_timed(xmpp_conn_t *conn, int user_only); void handler_reset_timed(xmpp_conn_t *conn, int user_only);
void handler_add_timed(xmpp_conn_t *conn, void handler_add_timed(xmpp_conn_t * const conn,
xmpp_timed_handler handler, xmpp_timed_handler handler,
unsigned long period, const unsigned long period,
void *userdata); void * const userdata);
void handler_add_id(xmpp_conn_t *conn, void handler_add_id(xmpp_conn_t * const conn,
xmpp_handler handler, xmpp_handler handler,
const char *id, const char * const id,
void *userdata); void * const userdata);
void handler_add(xmpp_conn_t *conn, void handler_add(xmpp_conn_t * const conn,
xmpp_handler handler, xmpp_handler handler,
const char *ns, const char * const ns,
const char *name, const char * const name,
const char *type, const char * const type,
void *userdata); void * const userdata);
void handler_system_delete_all(xmpp_conn_t *conn); void handler_system_delete_all(xmpp_conn_t *conn);
/* utility functions */ /* utility functions */
void disconnect_mem_error(xmpp_conn_t *conn); void disconnect_mem_error(xmpp_conn_t * const conn);
/* auth functions */ /* auth functions */
void auth_handle_open(xmpp_conn_t *conn); void auth_handle_open(xmpp_conn_t * const conn);
void auth_handle_component_open(xmpp_conn_t *conn); void auth_handle_component_open(xmpp_conn_t * const conn);
void auth_handle_open_raw(xmpp_conn_t *conn); void auth_handle_open_raw(xmpp_conn_t * const conn);
void auth_handle_open_stub(xmpp_conn_t *conn); void auth_handle_open_stub(xmpp_conn_t * const conn);
#endif /* __LIBSTROPHE_COMMON_H__ */ #endif /* __LIBSTROPHE_COMMON_H__ */

File diff suppressed because it is too large Load Diff

View File

@@ -20,13 +20,13 @@
*/ */
#include <assert.h> #include <assert.h>
#include <string.h> /* memset, memcpy */ #include <string.h> /* memset, memcpy */
#include "common.h" /* xmpp_alloc */ #include "common.h" /* xmpp_alloc */
#include "ostypes.h" /* uint8_t, size_t */ #include "ostypes.h" /* uint8_t, size_t */
#include "sha1.h" #include "sha1.h"
#include "snprintf.h" /* xmpp_snprintf */ #include "snprintf.h" /* xmpp_snprintf */
#include "strophe.h" /* xmpp_ctx_t, xmpp_free */ #include "strophe.h" /* xmpp_ctx_t, xmpp_free */
struct _xmpp_sha1_t { struct _xmpp_sha1_t {
xmpp_ctx_t *xmpp_ctx; xmpp_ctx_t *xmpp_ctx;
@@ -61,7 +61,7 @@ static char *digest_to_string_alloc(xmpp_ctx_t *ctx, const uint8_t *digest)
return s; return s;
} }
/** Compute SHA1 message digest. /** Compute SHA1 message digest
* Returns an allocated string which represents SHA1 message digest in * Returns an allocated string which represents SHA1 message digest in
* hexadecimal notation. The string must be freed with xmpp_free(). * hexadecimal notation. The string must be freed with xmpp_free().
* *
@@ -81,7 +81,7 @@ char *xmpp_sha1(xmpp_ctx_t *ctx, const unsigned char *data, size_t len)
return digest_to_string_alloc(ctx, digest); return digest_to_string_alloc(ctx, digest);
} }
/** Compute SHA1 message digest. /** Compute SHA1 message digest
* Stores digest in user's buffer which must be at least XMPP_SHA1_DIGEST_SIZE * Stores digest in user's buffer which must be at least XMPP_SHA1_DIGEST_SIZE
* bytes long. * bytes long.
* *
@@ -91,14 +91,13 @@ char *xmpp_sha1(xmpp_ctx_t *ctx, const unsigned char *data, size_t len)
* *
* @ingroup Digests * @ingroup Digests
*/ */
void xmpp_sha1_digest(const unsigned char *data, void xmpp_sha1_digest(const unsigned char *data, size_t len,
size_t len,
unsigned char *digest) unsigned char *digest)
{ {
crypto_SHA1((const uint8_t *)data, len, digest); crypto_SHA1((const uint8_t *)data, len, digest);
} }
/** Create new SHA1 object. /** Create new SHA1 object
* SHA1 object is used to compute SHA1 digest of a buffer that is split * 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 * in multiple chunks or provided in stream mode. A single buffer can be
* processed by short functions xmpp_sha1() and xmpp_sha1_digest(). * processed by short functions xmpp_sha1() and xmpp_sha1_digest().
@@ -112,7 +111,7 @@ void xmpp_sha1_digest(const unsigned char *data,
* xmpp_sha1_free(sha1); * xmpp_sha1_free(sha1);
* @endcode * @endcode
* *
* @param ctx a Strophe context object * @param ctx a Strophe context onject
* *
* @return new SHA1 object * @return new SHA1 object
* *
@@ -131,7 +130,7 @@ xmpp_sha1_t *xmpp_sha1_new(xmpp_ctx_t *ctx)
return sha1; return sha1;
} }
/** Destroy SHA1 object. /** Destroy SHA1 object
* *
* @param sha1 a SHA1 object * @param sha1 a SHA1 object
* *
@@ -142,7 +141,7 @@ void xmpp_sha1_free(xmpp_sha1_t *sha1)
xmpp_free(sha1->xmpp_ctx, sha1); xmpp_free(sha1->xmpp_ctx, sha1);
} }
/** Update SHA1 context with the next portion of data. /** Update SHA1 context with the next portion of data
* Can be called repeatedly. * Can be called repeatedly.
* *
* @param sha1 a SHA1 object * @param sha1 a SHA1 object
@@ -156,7 +155,7 @@ void xmpp_sha1_update(xmpp_sha1_t *sha1, const unsigned char *data, size_t len)
crypto_SHA1_Update(&sha1->ctx, data, len); crypto_SHA1_Update(&sha1->ctx, data, len);
} }
/** Finish SHA1 computation. /** Finish SHA1 computation
* Don't call xmpp_sha1_update() after this function. Retrieve resulting * Don't call xmpp_sha1_update() after this function. Retrieve resulting
* message digest with xmpp_sha1_to_string() or xmpp_sha1_to_digest(). * message digest with xmpp_sha1_to_string() or xmpp_sha1_to_digest().
* *
@@ -169,7 +168,7 @@ void xmpp_sha1_final(xmpp_sha1_t *sha1)
crypto_SHA1_Final(&sha1->ctx, sha1->digest); crypto_SHA1_Final(&sha1->ctx, sha1->digest);
} }
/** Return message digest rendered as a string. /** Return message digest rendered as a string
* Stores the string to a user's buffer and returns the buffer. Call this * Stores the string to a user's buffer and returns the buffer. Call this
* function after xmpp_sha1_final(). * function after xmpp_sha1_final().
* *
@@ -186,7 +185,7 @@ char *xmpp_sha1_to_string(xmpp_sha1_t *sha1, char *s, size_t slen)
return digest_to_string(sha1->digest, s, slen); return digest_to_string(sha1->digest, s, slen);
} }
/** Return message digest rendered as a string. /** Return message digest rendered as a string
* Returns an allocated string. Free the string using the Strophe context * Returns an allocated string. Free the string using the Strophe context
* which is passed to xmpp_sha1_new(). Call this function after * which is passed to xmpp_sha1_new(). Call this function after
* xmpp_sha1_final(). * xmpp_sha1_final().
@@ -202,7 +201,7 @@ char *xmpp_sha1_to_string_alloc(xmpp_sha1_t *sha1)
return digest_to_string_alloc(sha1->xmpp_ctx, sha1->digest); return digest_to_string_alloc(sha1->xmpp_ctx, sha1->digest);
} }
/** Stores message digest to a user's buffer. /** Stores message digest to a user's buffer
* *
* @param sha1 a SHA1 object * @param sha1 a SHA1 object
* @param digest output buffer of XMPP_SHA1_DIGEST_SIZE bytes * @param digest output buffer of XMPP_SHA1_DIGEST_SIZE bytes
@@ -215,43 +214,52 @@ void xmpp_sha1_to_digest(xmpp_sha1_t *sha1, unsigned char *digest)
memcpy(digest, sha1->digest, SHA1_DIGEST_SIZE); memcpy(digest, sha1->digest, SHA1_DIGEST_SIZE);
} }
/* Base64 encoding routines. Implemented according to RFC 3548. */ /* Base64 encoding routines. Implemented according to RFC 3548. */
/* map of all byte values to the base64 values, or to /* map of all byte values to the base64 values, or to
'65' which indicates an invalid character. '=' is '64' */ '65' which indicates an invalid character. '=' is '64' */
static const unsigned char _base64_invcharmap[256] = { static const unsigned char _base64_invcharmap[256] = {
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65,
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65,
65, 65, 65, 65, 65, 62, 65, 65, 65, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 65,65,65,65, 65,65,65,65, 65,65,65,62, 65,65,65,63,
61, 65, 65, 65, 64, 65, 65, 65, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 52,53,54,55, 56,57,58,59, 60,61,65,65, 65,64,65,65,
11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 65, 65, 65, 65, 65, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14,
65, 65, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 15,16,17,18, 19,20,21,22, 23,24,25,65, 65,65,65,65,
43, 44, 45, 46, 47, 48, 49, 50, 51, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 41,42,43,44, 45,46,47,48, 49,50,51,65, 65,65,65,65,
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65,
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65,
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65,
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65,
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65,
65, 65, 65, 65, 65, 65, 65, 65, 65}; 65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65,
65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65,
65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65
};
/* map of all 6-bit values to their corresponding byte /* map of all 6-bit values to their corresponding byte
in the base64 alphabet. Padding char is the value '64' */ in the base64 alphabet. Padding char is the value '64' */
static const char _base64_charmap[65] = { static const char _base64_charmap[65] = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'A','B','C','D', 'E','F','G','H',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'I','J','K','L', 'M','N','O','P',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'Q','R','S','T', 'U','V','W','X',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'Y','Z','a','b', 'c','d','e','f',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', '='}; '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(size_t len) static size_t base64_encoded_len(const size_t len)
{ {
/* encoded steam is 4 bytes for every three, rounded up */ /* encoded steam is 4 bytes for every three, rounded up */
return ((len + 2) / 3) << 2; return ((len + 2)/3) << 2;
} }
static char * static char *base64_encode(xmpp_ctx_t *ctx,
base64_encode(xmpp_ctx_t *ctx, const unsigned char *buffer, size_t len) const unsigned char * const buffer, const size_t len)
{ {
size_t clen; size_t clen;
char *cbuf, *c; char *cbuf, *c;
@@ -264,7 +272,7 @@ base64_encode(xmpp_ctx_t *ctx, const unsigned char *buffer, size_t len)
c = cbuf; c = cbuf;
/* loop over data, turning every 3 bytes into 4 characters */ /* loop over data, turning every 3 bytes into 4 characters */
for (i = 0; i + 2 < len; i += 3) { for (i = 0; i + 2 < len; i += 3) {
word = buffer[i] << 16 | buffer[i + 1] << 8 | buffer[i + 2]; word = buffer[i] << 16 | buffer[i+1] << 8 | buffer[i+2];
hextet = (word & 0x00FC0000) >> 18; hextet = (word & 0x00FC0000) >> 18;
*c++ = _base64_charmap[hextet]; *c++ = _base64_charmap[hextet];
hextet = (word & 0x0003F000) >> 12; hextet = (word & 0x0003F000) >> 12;
@@ -276,26 +284,26 @@ base64_encode(xmpp_ctx_t *ctx, const unsigned char *buffer, size_t len)
} }
/* zero, one or two bytes left */ /* zero, one or two bytes left */
switch (len - i) { switch (len - i) {
case 0: case 0:
break; break;
case 1: case 1:
hextet = (buffer[len - 1] & 0xFC) >> 2; hextet = (buffer[len-1] & 0xFC) >> 2;
*c++ = _base64_charmap[hextet]; *c++ = _base64_charmap[hextet];
hextet = (buffer[len - 1] & 0x03) << 4; hextet = (buffer[len-1] & 0x03) << 4;
*c++ = _base64_charmap[hextet]; *c++ = _base64_charmap[hextet];
*c++ = _base64_charmap[64]; /* pad */ *c++ = _base64_charmap[64]; /* pad */
*c++ = _base64_charmap[64]; /* pad */ *c++ = _base64_charmap[64]; /* pad */
break; break;
case 2: case 2:
hextet = (buffer[len - 2] & 0xFC) >> 2; hextet = (buffer[len-2] & 0xFC) >> 2;
*c++ = _base64_charmap[hextet]; *c++ = _base64_charmap[hextet];
hextet = ((buffer[len - 2] & 0x03) << 4) | hextet = ((buffer[len-2] & 0x03) << 4) |
((buffer[len - 1] & 0xF0) >> 4); ((buffer[len-1] & 0xF0) >> 4);
*c++ = _base64_charmap[hextet]; *c++ = _base64_charmap[hextet];
hextet = (buffer[len - 1] & 0x0F) << 2; hextet = (buffer[len-1] & 0x0F) << 2;
*c++ = _base64_charmap[hextet]; *c++ = _base64_charmap[hextet];
*c++ = _base64_charmap[64]; /* pad */ *c++ = _base64_charmap[64]; /* pad */
break; break;
} }
/* add a terminal null */ /* add a terminal null */
*c = '\0'; *c = '\0';
@@ -303,37 +311,30 @@ base64_encode(xmpp_ctx_t *ctx, const unsigned char *buffer, size_t len)
return cbuf; return cbuf;
} }
static size_t base64_decoded_len(const char *buffer, size_t len) static size_t base64_decoded_len(const char * const buffer, const size_t len)
{ {
size_t nudge = 0; size_t nudge = 0;
unsigned char c; unsigned char c;
size_t i; size_t i;
if (len < 4) if (len < 4) return 0;
return 0;
/* count the padding characters for the remainder */ /* count the padding characters for the remainder */
for (i = len; i > 0; --i) { for (i = len; i > 0; --i) {
c = _base64_invcharmap[(unsigned char)buffer[i - 1]]; c = _base64_invcharmap[(unsigned char)buffer[i-1]];
if (c < 64) if (c < 64) break;
break; if (c == 64) ++nudge;
if (c == 64) if (c > 64) return 0;
++nudge;
if (c > 64)
return 0;
} }
if (nudge > 2) if (nudge > 2) return 0;
return 0;
/* decoded steam is 3 bytes for every four */ /* decoded steam is 3 bytes for every four */
return 3 * (len >> 2) - nudge; return 3 * (len >> 2) - nudge;
} }
static void base64_decode(xmpp_ctx_t *ctx, static void base64_decode(xmpp_ctx_t *ctx,
const char *buffer, const char * const buffer, const size_t len,
size_t len, unsigned char **out, size_t *outlen)
unsigned char **out,
size_t *outlen)
{ {
size_t dlen; size_t dlen;
unsigned char *dbuf, *d; unsigned char *dbuf, *d;
@@ -341,12 +342,10 @@ static void base64_decode(xmpp_ctx_t *ctx,
size_t i; size_t i;
/* len must be a multiple of 4 */ /* len must be a multiple of 4 */
if (len & 0x03) if (len & 0x03) goto _base64_error;
goto _base64_error;
dlen = base64_decoded_len(buffer, len); dlen = base64_decoded_len(buffer, len);
if (dlen == 0) if (dlen == 0) goto _base64_error;
goto _base64_error;
dbuf = xmpp_alloc(ctx, dlen + 1); dbuf = xmpp_alloc(ctx, dlen + 1);
if (dbuf != NULL) { if (dbuf != NULL) {
@@ -354,70 +353,57 @@ static void base64_decode(xmpp_ctx_t *ctx,
/* loop over each set of 4 characters, decoding 3 bytes */ /* loop over each set of 4 characters, decoding 3 bytes */
for (i = 0; i + 3 < len; i += 4) { for (i = 0; i + 3 < len; i += 4) {
hextet = _base64_invcharmap[(unsigned char)buffer[i]]; hextet = _base64_invcharmap[(unsigned char)buffer[i]];
if (hextet & 0xC0) if (hextet & 0xC0) break;
break;
word = hextet << 18; word = hextet << 18;
hextet = _base64_invcharmap[(unsigned char)buffer[i + 1]]; hextet = _base64_invcharmap[(unsigned char)buffer[i+1]];
if (hextet & 0xC0) if (hextet & 0xC0) break;
break;
word |= hextet << 12; word |= hextet << 12;
hextet = _base64_invcharmap[(unsigned char)buffer[i + 2]]; hextet = _base64_invcharmap[(unsigned char)buffer[i+2]];
if (hextet & 0xC0) if (hextet & 0xC0) break;
break;
word |= hextet << 6; word |= hextet << 6;
hextet = _base64_invcharmap[(unsigned char)buffer[i + 3]]; hextet = _base64_invcharmap[(unsigned char)buffer[i+3]];
if (hextet & 0xC0) if (hextet & 0xC0) break;
break;
word |= hextet; word |= hextet;
*d++ = (word & 0x00FF0000) >> 16; *d++ = (word & 0x00FF0000) >> 16;
*d++ = (word & 0x0000FF00) >> 8; *d++ = (word & 0x0000FF00) >> 8;
*d++ = (word & 0x000000FF); *d++ = (word & 0x000000FF);
} }
if (hextet > 64) if (hextet > 64) goto _base64_decode_error;
goto _base64_decode_error;
/* handle the remainder */ /* handle the remainder */
switch (dlen % 3) { switch (dlen % 3) {
case 0: case 0:
/* nothing to do */ /* nothing to do */
break; break;
case 1: case 1:
/* redo the last quartet, checking for correctness */ /* redo the last quartet, checking for correctness */
hextet = _base64_invcharmap[(unsigned char)buffer[len - 4]]; hextet = _base64_invcharmap[(unsigned char)buffer[len-4]];
if (hextet & 0xC0) if (hextet & 0xC0) goto _base64_decode_error;
goto _base64_decode_error; word = hextet << 2;
word = hextet << 2; hextet = _base64_invcharmap[(unsigned char)buffer[len-3]];
hextet = _base64_invcharmap[(unsigned char)buffer[len - 3]]; if (hextet & 0xC0) goto _base64_decode_error;
if (hextet & 0xC0) word |= hextet >> 4;
goto _base64_decode_error; *d++ = word & 0xFF;
word |= hextet >> 4; hextet = _base64_invcharmap[(unsigned char)buffer[len-2]];
*d++ = word & 0xFF; if (hextet != 64) goto _base64_decode_error;
hextet = _base64_invcharmap[(unsigned char)buffer[len - 2]]; hextet = _base64_invcharmap[(unsigned char)buffer[len-1]];
if (hextet != 64) if (hextet != 64) goto _base64_decode_error;
goto _base64_decode_error; break;
hextet = _base64_invcharmap[(unsigned char)buffer[len - 1]]; case 2:
if (hextet != 64) /* redo the last quartet, checking for correctness */
goto _base64_decode_error; hextet = _base64_invcharmap[(unsigned char)buffer[len-4]];
break; if (hextet & 0xC0) goto _base64_decode_error;
case 2: word = hextet << 10;
/* redo the last quartet, checking for correctness */ hextet = _base64_invcharmap[(unsigned char)buffer[len-3]];
hextet = _base64_invcharmap[(unsigned char)buffer[len - 4]]; if (hextet & 0xC0) goto _base64_decode_error;
if (hextet & 0xC0) word |= hextet << 4;
goto _base64_decode_error; hextet = _base64_invcharmap[(unsigned char)buffer[len-2]];
word = hextet << 10; if (hextet & 0xC0) goto _base64_decode_error;
hextet = _base64_invcharmap[(unsigned char)buffer[len - 3]]; word |= hextet >> 2;
if (hextet & 0xC0) *d++ = (word & 0xFF00) >> 8;
goto _base64_decode_error; *d++ = (word & 0x00FF);
word |= hextet << 4; hextet = _base64_invcharmap[(unsigned char)buffer[len-1]];
hextet = _base64_invcharmap[(unsigned char)buffer[len - 2]]; if (hextet != 64) goto _base64_decode_error;
if (hextet & 0xC0) break;
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'; *d = '\0';
} }
@@ -433,7 +419,7 @@ _base64_error:
*outlen = 0; *outlen = 0;
} }
/** Base64 encoding routine. /** Base64 encoding routine
* Returns an allocated string which must be freed with xmpp_free(). * Returns an allocated string which must be freed with xmpp_free().
* *
* @param ctx a Strophe context * @param ctx a Strophe context
@@ -449,7 +435,7 @@ char *xmpp_base64_encode(xmpp_ctx_t *ctx, const unsigned char *data, size_t len)
return base64_encode(ctx, data, len); return base64_encode(ctx, data, len);
} }
/** Base64 decoding routine. /** Base64 decoding routine
* Returns an allocated string which must be freed with xmpp_free(). User * Returns an allocated string which must be freed with xmpp_free(). User
* calls this function when the result must be a string. When decoded buffer * calls this function when the result must be a string. When decoded buffer
* contains '\0' NULL is returned. * contains '\0' NULL is returned.
@@ -485,7 +471,7 @@ char *xmpp_base64_decode_str(xmpp_ctx_t *ctx, const char *base64, size_t len)
return (char *)buf; return (char *)buf;
} }
/** Base64 decoding routine. /** Base64 decoding routine
* Returns an allocated buffer which must be freed with xmpp_free(). * Returns an allocated buffer which must be freed with xmpp_free().
* *
* @param ctx a Strophe context * @param ctx a Strophe context
@@ -498,11 +484,8 @@ char *xmpp_base64_decode_str(xmpp_ctx_t *ctx, const char *base64, size_t len)
* *
* @ingroup Encodings * @ingroup Encodings
*/ */
void xmpp_base64_decode_bin(xmpp_ctx_t *ctx, void xmpp_base64_decode_bin(xmpp_ctx_t *ctx, const char *base64, size_t len,
const char *base64, unsigned char **out, size_t *outlen)
size_t len,
unsigned char **out,
size_t *outlen)
{ {
base64_decode(ctx, base64, len, out, outlen); base64_decode(ctx, base64, len, out, outlen);
} }

159
src/ctx.c
View File

@@ -47,13 +47,11 @@
#include "strophe.h" #include "strophe.h"
#include "common.h" #include "common.h"
#include "resolver.h"
#include "util.h" #include "util.h"
/* Workaround for systems without va_copy support. */ /* Workaround for visual studio without va_copy support. */
#if defined(_MSC_VER) && _MSC_VER < 1800 || \ #if defined(_MSC_VER) && _MSC_VER < 1800
!defined(_MSC_VER) && !defined(HAVE_DECL_VA_COPY) #define va_copy(d,s) ((d) = (s))
#define va_copy(d, s) (memcpy(&d, &s, sizeof(va_list)))
#endif #endif
/** Initialize the Strophe library. /** Initialize the Strophe library.
@@ -62,10 +60,9 @@
* *
* @ingroup Init * @ingroup Init
*/ */
void xmpp_initialize(void) void xmpp_initialize(void)
{ {
sock_initialize(); sock_initialize();
resolver_initialize();
tls_initialize(); tls_initialize();
} }
@@ -76,7 +73,6 @@ void xmpp_initialize(void)
void xmpp_shutdown(void) void xmpp_shutdown(void)
{ {
tls_shutdown(); tls_shutdown();
resolver_shutdown();
sock_shutdown(); sock_shutdown();
} }
@@ -114,41 +110,44 @@ void xmpp_shutdown(void)
*/ */
int xmpp_version_check(int major, int minor) int xmpp_version_check(int major, int minor)
{ {
return (major == LIBXMPP_VERSION_MAJOR) && (minor >= LIBXMPP_VERSION_MINOR); return (major == LIBXMPP_VERSION_MAJOR) &&
(minor >= LIBXMPP_VERSION_MINOR);
} }
/* We define the global default allocator, logger, and context here. */ /* We define the global default allocator, logger, and context here. */
/* Wrap stdlib routines malloc, free, and realloc for default memory /* Wrap stdlib routines malloc, free, and realloc for default memory
* management. * management.
*/ */
static void *_malloc(size_t size, void *userdata) static void *_malloc(const size_t size, void * const userdata)
{ {
UNUSED(userdata);
return malloc(size); return malloc(size);
} }
static void _free(void *p, void *userdata) static void _free(void *p, void * const userdata)
{ {
UNUSED(userdata);
free(p); free(p);
} }
static void *_realloc(void *p, size_t size, void *userdata) static void *_realloc(void *p, const size_t size, void * const userdata)
{ {
UNUSED(userdata);
return realloc(p, size); return realloc(p, size);
} }
/* default memory function map */ /* default memory function map */
static xmpp_mem_t xmpp_default_mem = { static xmpp_mem_t xmpp_default_mem = {
_malloc, /* use the thinly wrapped stdlib routines by default */ _malloc, /* use the thinly wrapped stdlib routines by default */
_free, _realloc, NULL}; _free,
_realloc,
NULL
};
/* log levels and names */ /* log levels and names */
static const char *_xmpp_log_level_name[4] = {"DEBUG", "INFO", "WARN", "ERROR"}; static const char * const _xmpp_log_level_name[4] = {"DEBUG", "INFO", "WARN", "ERROR"};
static const xmpp_log_level_t _xmpp_default_logger_levels[] = { static const xmpp_log_level_t _xmpp_default_logger_levels[] = {XMPP_LEVEL_DEBUG,
XMPP_LEVEL_DEBUG, XMPP_LEVEL_INFO, XMPP_LEVEL_WARN, XMPP_LEVEL_ERROR}; XMPP_LEVEL_INFO,
XMPP_LEVEL_WARN,
XMPP_LEVEL_ERROR};
/** Log a message. /** Log a message.
* The default logger writes to stderr. * The default logger writes to stderr.
@@ -159,25 +158,22 @@ static const xmpp_log_level_t _xmpp_default_logger_levels[] = {
* @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 *userdata, static void xmpp_default_logger(void * const userdata,
xmpp_log_level_t level, const xmpp_log_level_t level,
const char *area, const char * const area,
const char *msg) const char * const msg)
{ {
xmpp_log_level_t filter_level = *(xmpp_log_level_t *)userdata; xmpp_log_level_t filter_level = * (xmpp_log_level_t*)userdata;
if (level >= filter_level) if (level >= filter_level)
fprintf(stderr, "%s %s %s\n", area, _xmpp_log_level_name[level], msg); fprintf(stderr, "%s %s %s\n", area, _xmpp_log_level_name[level], msg);
} }
static const xmpp_log_t _xmpp_default_loggers[] = { static const xmpp_log_t _xmpp_default_loggers[] = {
{&xmpp_default_logger, {&xmpp_default_logger, (void*)&_xmpp_default_logger_levels[XMPP_LEVEL_DEBUG]},
(void *)&_xmpp_default_logger_levels[XMPP_LEVEL_DEBUG]}, {&xmpp_default_logger, (void*)&_xmpp_default_logger_levels[XMPP_LEVEL_INFO]},
{&xmpp_default_logger, {&xmpp_default_logger, (void*)&_xmpp_default_logger_levels[XMPP_LEVEL_WARN]},
(void *)&_xmpp_default_logger_levels[XMPP_LEVEL_INFO]}, {&xmpp_default_logger, (void*)&_xmpp_default_logger_levels[XMPP_LEVEL_ERROR]}
{&xmpp_default_logger, };
(void *)&_xmpp_default_logger_levels[XMPP_LEVEL_WARN]},
{&xmpp_default_logger,
(void *)&_xmpp_default_logger_levels[XMPP_LEVEL_ERROR]}};
/** Get a default logger with filtering. /** Get a default logger with filtering.
* The default logger provides a basic logging setup which writes log * The default logger provides a basic logging setup which writes log
@@ -193,13 +189,12 @@ static const xmpp_log_t _xmpp_default_loggers[] = {
xmpp_log_t *xmpp_get_default_logger(xmpp_log_level_t level) xmpp_log_t *xmpp_get_default_logger(xmpp_log_level_t level)
{ {
/* clamp to the known range */ /* clamp to the known range */
if (level > XMPP_LEVEL_ERROR) if (level > XMPP_LEVEL_ERROR) level = XMPP_LEVEL_ERROR;
level = XMPP_LEVEL_ERROR;
return (xmpp_log_t *)&_xmpp_default_loggers[level]; return (xmpp_log_t*)&_xmpp_default_loggers[level];
} }
static xmpp_log_t xmpp_default_log = {NULL, NULL}; static xmpp_log_t xmpp_default_log = { NULL, NULL };
/* convenience functions for accessing the context */ /* convenience functions for accessing the context */
@@ -211,7 +206,7 @@ static xmpp_log_t xmpp_default_log = {NULL, NULL};
* *
* @return a pointer to the allocated memory or NULL on an error * @return a pointer to the allocated memory or NULL on an error
*/ */
void *xmpp_alloc(const xmpp_ctx_t *ctx, size_t size) void *xmpp_alloc(const xmpp_ctx_t * const ctx, const size_t size)
{ {
return ctx->mem->alloc(size, ctx->mem->userdata); return ctx->mem->alloc(size, ctx->mem->userdata);
} }
@@ -222,7 +217,7 @@ void *xmpp_alloc(const xmpp_ctx_t *ctx, size_t size)
* @param ctx a Strophe context object * @param ctx a Strophe context object
* @param p a pointer referencing memory to be freed * @param p a pointer referencing memory to be freed
*/ */
void xmpp_free(const xmpp_ctx_t *ctx, void *p) void xmpp_free(const xmpp_ctx_t * const ctx, void *p)
{ {
ctx->mem->free(p, ctx->mem->userdata); ctx->mem->free(p, ctx->mem->userdata);
} }
@@ -236,7 +231,8 @@ void xmpp_free(const xmpp_ctx_t *ctx, void *p)
* *
* @return a pointer to the reallocated memory or NULL on an error * @return a pointer to the reallocated memory or NULL on an error
*/ */
void *xmpp_realloc(const xmpp_ctx_t *ctx, void *p, size_t size) void *xmpp_realloc(const xmpp_ctx_t * const ctx, void *p,
const size_t size)
{ {
return ctx->mem->realloc(p, size, ctx->mem->userdata); return ctx->mem->realloc(p, size, ctx->mem->userdata);
} }
@@ -254,10 +250,10 @@ void *xmpp_realloc(const xmpp_ctx_t *ctx, void *p, size_t size)
* @param fmt a printf-style format string for the message * @param fmt a printf-style format string for the message
* @param ap variable argument list supplied for the format string * @param ap variable argument list supplied for the format string
*/ */
void xmpp_log(const xmpp_ctx_t *ctx, void xmpp_log(const xmpp_ctx_t * const ctx,
xmpp_log_level_t level, const xmpp_log_level_t level,
const char *area, const char * const area,
const char *fmt, const char * const fmt,
va_list ap) va_list ap)
{ {
int oldret, ret; int oldret, ret;
@@ -265,13 +261,6 @@ void xmpp_log(const xmpp_ctx_t *ctx,
char *buf; char *buf;
va_list copy; va_list copy;
if (!ctx->log->handler)
return;
if (ctx->log->handler == xmpp_default_logger &&
level < *(xmpp_log_level_t *)ctx->log->userdata)
return;
va_copy(copy, ap); va_copy(copy, ap);
ret = xmpp_vsnprintf(smbuf, sizeof(smbuf), fmt, ap); ret = xmpp_vsnprintf(smbuf, sizeof(smbuf), fmt, ap);
if (ret >= (int)sizeof(smbuf)) { if (ret >= (int)sizeof(smbuf)) {
@@ -295,7 +284,8 @@ void xmpp_log(const xmpp_ctx_t *ctx,
} }
va_end(copy); va_end(copy);
ctx->log->handler(ctx->log->userdata, level, area, buf); if (ctx->log->handler)
ctx->log->handler(ctx->log->userdata, level, area, buf);
if (buf != smbuf) if (buf != smbuf)
xmpp_free(ctx, buf); xmpp_free(ctx, buf);
@@ -311,7 +301,10 @@ void xmpp_log(const xmpp_ctx_t *ctx,
* @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
*/ */
void xmpp_error(const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...) void xmpp_error(const xmpp_ctx_t * const ctx,
const char * const area,
const char * const fmt,
...)
{ {
va_list ap; va_list ap;
@@ -330,7 +323,10 @@ void xmpp_error(const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...)
* @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
*/ */
void xmpp_warn(const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...) void xmpp_warn(const xmpp_ctx_t * const ctx,
const char * const area,
const char * const fmt,
...)
{ {
va_list ap; va_list ap;
@@ -349,7 +345,10 @@ void xmpp_warn(const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...)
* @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
*/ */
void xmpp_info(const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...) void xmpp_info(const xmpp_ctx_t * const ctx,
const char * const area,
const char * const fmt,
...)
{ {
va_list ap; va_list ap;
@@ -368,7 +367,10 @@ void xmpp_info(const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...)
* @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
*/ */
void xmpp_debug(const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...) void xmpp_debug(const xmpp_ctx_t * const ctx,
const char * const area,
const char * const fmt,
...)
{ {
va_list ap; va_list ap;
@@ -377,30 +379,6 @@ void xmpp_debug(const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...)
va_end(ap); va_end(ap);
} }
/** Write to the log at the DEBUG level if verbosity is enabled.
* This is a convenience function for writing to the log at the DEBUG level.
* It takes a printf-style format string followed by a variable list of
* arguments for formatting.
*
* @param level the verbosity level
* @param ctx a Strophe context object
* @param area the area to log for
* @param fmt a printf-style format string followed by a variable list of
* arguments to format
*/
void xmpp_debug_verbose(
int level, const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...)
{
va_list ap;
if (ctx->verbosity < level)
return;
va_start(ap, fmt);
xmpp_log(ctx, XMPP_LEVEL_DEBUG, area, fmt, ap);
va_end(ap);
}
/** Create and initialize a Strophe context object. /** Create and initialize a Strophe context object.
* If mem is NULL, a default allocation setup will be used which * If mem is NULL, a default allocation setup will be used which
* wraps malloc(), free(), and realloc() from the standard library. * wraps malloc(), free(), and realloc() from the standard library.
@@ -415,7 +393,8 @@ void xmpp_debug_verbose(
* *
* @ingroup Context * @ingroup Context
*/ */
xmpp_ctx_t *xmpp_ctx_new(const xmpp_mem_t *mem, const xmpp_log_t *log) xmpp_ctx_t *xmpp_ctx_new(const xmpp_mem_t * const mem,
const xmpp_log_t * const log)
{ {
xmpp_ctx_t *ctx = NULL; xmpp_ctx_t *ctx = NULL;
@@ -436,7 +415,7 @@ xmpp_ctx_t *xmpp_ctx_new(const xmpp_mem_t *mem, const xmpp_log_t *log)
ctx->log = log; ctx->log = log;
ctx->connlist = NULL; ctx->connlist = NULL;
ctx->timed_handlers = NULL; ctx->serverlist = NULL;
ctx->loop_status = XMPP_LOOP_NOTSTARTED; ctx->loop_status = XMPP_LOOP_NOTSTARTED;
ctx->rand = xmpp_rand_new(ctx); ctx->rand = xmpp_rand_new(ctx);
ctx->timeout = EVENT_LOOP_DEFAULT_TIMEOUT; ctx->timeout = EVENT_LOOP_DEFAULT_TIMEOUT;
@@ -455,7 +434,7 @@ xmpp_ctx_t *xmpp_ctx_new(const xmpp_mem_t *mem, const xmpp_log_t *log)
* *
* @ingroup Context * @ingroup Context
*/ */
void xmpp_ctx_free(xmpp_ctx_t *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_rand_free(ctx, ctx->rand);
@@ -469,19 +448,7 @@ void xmpp_ctx_free(xmpp_ctx_t *ctx)
* *
* @ingroup Context * @ingroup Context
*/ */
void xmpp_ctx_set_timeout(xmpp_ctx_t *ctx, unsigned long timeout) void xmpp_ctx_set_timeout(xmpp_ctx_t * const ctx, const unsigned long timeout)
{ {
ctx->timeout = timeout; ctx->timeout = timeout;
} }
/** Set the verbosity level of a Strophe context.
*
* @param ctx a Strophe context object
* @param level the verbosity level
*
* @ingroup Context
*/
void xmpp_ctx_set_verbosity(xmpp_ctx_t *ctx, int level)
{
ctx->verbosity = level;
}

View File

@@ -1,7 +1,7 @@
/* event.c /* event.c
** strophe XMPP client library -- event loop and management ** strophe XMPP client library -- event loop and management
** **
** Copyright (C) 2005-2009 Collecta, Inc. ** Copyright (C) 2005-2009 Collecta, Inc.
** **
** This software is provided AS-IS with no warranty, either express ** This software is provided AS-IS with no warranty, either express
** or implied. ** or implied.
@@ -38,28 +38,19 @@
#include <sys/select.h> #include <sys/select.h>
#include <errno.h> #include <errno.h>
#include <unistd.h> #include <unistd.h>
#define _sleep(x) usleep((x)*1000) #define _sleep(x) usleep((x) * 1000)
#else #else
#include <winsock2.h> #include <winsock2.h>
#ifndef ETIMEDOUT
#define ETIMEDOUT WSAETIMEDOUT #define ETIMEDOUT WSAETIMEDOUT
#endif
#ifndef ECONNRESET
#define ECONNRESET WSAECONNRESET #define ECONNRESET WSAECONNRESET
#endif
#ifndef ECONNABORTED
#define ECONNABORTED WSAECONNABORTED #define ECONNABORTED WSAECONNABORTED
#endif
#define _sleep(x) Sleep(x) #define _sleep(x) Sleep(x)
#endif #endif
#include "strophe.h" #include <strophe.h>
#include "common.h" #include "common.h"
#include "parser.h" #include "parser.h"
/** Max buffer size for receiving messages. */
#define STROPE_MESSAGE_BUFFER_SIZE 4096
/** 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
@@ -73,23 +64,24 @@
* *
* @ingroup EventLoop * @ingroup EventLoop
*/ */
void xmpp_run_once(xmpp_ctx_t *ctx, 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;
struct timeval tv; struct timeval tv;
xmpp_send_queue_t *sq, *tsq; xmpp_send_queue_t *sq, *tsq;
int towrite; int towrite;
char buf[STROPE_MESSAGE_BUFFER_SIZE]; char buf[4096];
uint64_t next; uint64_t next;
uint64_t usec; uint64_t usec;
int tls_read_bytes = 0; int tls_read_bytes = 0;
if (ctx->loop_status == XMPP_LOOP_QUIT) if (ctx->loop_status == XMPP_LOOP_QUIT) return;
return;
/* send queued data */ /* send queued data */
connitem = ctx->connlist; connitem = ctx->connlist;
@@ -110,7 +102,6 @@ void xmpp_run_once(xmpp_ctx_t *ctx, unsigned long timeout)
xmpp_debug(ctx, "xmpp", "Send error occurred, disconnecting."); xmpp_debug(ctx, "xmpp", "Send error occurred, disconnecting.");
conn->error = ECONNABORTED; conn->error = ECONNABORTED;
conn_disconnect(conn); conn_disconnect(conn);
goto NEXT_ITEM;
} }
} }
@@ -134,9 +125,6 @@ void xmpp_run_once(xmpp_ctx_t *ctx, unsigned long timeout)
break; /* partial write or an error */ 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_debug(conn->ctx, "conn", "SENT: %s", sq->data);
xmpp_debug_verbose(1, ctx, "xmpp",
"Finished writing queue element: %p.", sq);
xmpp_free(ctx, sq->data); xmpp_free(ctx, sq->data);
tsq = sq; tsq = sq;
sq = sq->next; sq = sq->next;
@@ -146,8 +134,7 @@ void xmpp_run_once(xmpp_ctx_t *ctx, unsigned long timeout)
/* pop the top item */ /* pop the top item */
conn->send_queue_head = sq; conn->send_queue_head = sq;
/* if we've sent everything update the tail */ /* if we've sent everything update the tail */
if (!sq) if (!sq) conn->send_queue_tail = NULL;
conn->send_queue_tail = NULL;
} }
/* tear down connection on error */ /* tear down connection on error */
@@ -158,7 +145,7 @@ void xmpp_run_once(xmpp_ctx_t *ctx, unsigned long timeout)
conn->error = ECONNABORTED; conn->error = ECONNABORTED;
conn_disconnect(conn); conn_disconnect(conn);
} }
NEXT_ITEM:
connitem = connitem->next; connitem = connitem->next;
} }
@@ -168,6 +155,7 @@ NEXT_ITEM:
conn_parser_reset(connitem->conn); conn_parser_reset(connitem->conn);
} }
/* fire any ready timed handlers, then make sure we don't wait past /* fire any ready timed handlers, then make sure we don't wait past
the time when timed handlers need to be called */ the time when timed handlers need to be called */
next = handler_fire_timed(ctx); next = handler_fire_timed(ctx);
@@ -220,9 +208,26 @@ NEXT_ITEM:
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);
else { else {
if (timeout > 0) if (timeout > 0)
_sleep(timeout); _sleep(timeout);
@@ -238,8 +243,7 @@ NEXT_ITEM:
} }
/* no events happened */ /* no events happened */
if (ret == 0 && tls_read_bytes == 0) if (ret == 0 && tls_read_bytes == 0) return;
return;
/* process events */ /* process events */
connitem = ctx->connlist; connitem = ctx->connlist;
@@ -267,35 +271,31 @@ NEXT_ITEM:
break; break;
case XMPP_STATE_CONNECTED: case XMPP_STATE_CONNECTED:
if (FD_ISSET(conn->sock, &rfds) || if (FD_ISSET(conn->sock, &rfds) || (conn->tls && tls_pending(conn->tls))) {
(conn->tls && tls_pending(conn->tls))) {
if (conn->tls) { if (conn->tls) {
ret = tls_read(conn->tls, buf, STROPE_MESSAGE_BUFFER_SIZE); ret = tls_read(conn->tls, buf, 4096);
} else { } else {
ret = ret = sock_read(conn->sock, buf, 4096);
sock_read(conn->sock, buf, STROPE_MESSAGE_BUFFER_SIZE);
} }
if (ret > 0) { if (ret > 0) {
ret = parser_feed(conn->parser, buf, ret); ret = parser_feed(conn->parser, buf, ret);
if (!ret) { if (!ret) {
xmpp_debug(ctx, "xmpp", "parse error [%s]", buf); /* parse error, we need to shut down */
xmpp_send_error(conn, XMPP_SE_INVALID_XML, /* FIXME */
"parse error"); xmpp_debug(ctx, "xmpp", "parse error, disconnecting");
conn_disconnect(conn);
} }
} else { } else {
if (conn->tls) { if (conn->tls) {
if (!tls_is_recoverable(tls_error(conn->tls))) { if (!tls_is_recoverable(tls_error(conn->tls))) {
xmpp_debug(ctx, "xmpp", xmpp_debug(ctx, "xmpp", "Unrecoverable TLS error, %d.", tls_error(conn->tls));
"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);
} }
} else { } else {
/* return of 0 means socket closed by server */ /* return of 0 means socket closed by server */
xmpp_debug(ctx, "xmpp", xmpp_debug(ctx, "xmpp", "Socket closed by remote host.");
"Socket closed by remote host.");
conn->error = ECONNRESET; conn->error = ECONNRESET;
conn_disconnect(conn); conn_disconnect(conn);
} }
@@ -312,6 +312,24 @@ NEXT_ITEM:
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);
} }
@@ -326,8 +344,7 @@ NEXT_ITEM:
*/ */
void xmpp_run(xmpp_ctx_t *ctx) void xmpp_run(xmpp_ctx_t *ctx)
{ {
if (ctx->loop_status != XMPP_LOOP_NOTSTARTED) if (ctx->loop_status != XMPP_LOOP_NOTSTARTED) return;
return;
ctx->loop_status = XMPP_LOOP_RUNNING; ctx->loop_status = XMPP_LOOP_RUNNING;
while (ctx->loop_status == XMPP_LOOP_RUNNING) { while (ctx->loop_status == XMPP_LOOP_RUNNING) {

View File

@@ -24,8 +24,6 @@
#include "common.h" #include "common.h"
#include "ostypes.h" #include "ostypes.h"
typedef int (*xmpp_void_handler)();
/* Remove item from the list pointed by head, but don't free it. /* Remove item from the list pointed by head, but don't free it.
* There can be a situation when user's handler deletes another handler which * There can be a situation when user's handler deletes another handler which
* is the previous in the list. handler_fire_stanza() and handler_fire_timed() * is the previous in the list. handler_fire_stanza() and handler_fire_timed()
@@ -35,14 +33,19 @@ typedef int (*xmpp_void_handler)();
* TODO Convert handler lists to double-linked lists. Current implementation * TODO Convert handler lists to double-linked lists. Current implementation
* works for O(n). * works for O(n).
*/ */
static void _handler_item_remove(xmpp_handlist_t **head, xmpp_handlist_t *item) static void _handler_item_remove(xmpp_handlist_t **head,
xmpp_handlist_t *item)
{ {
while (*head) { xmpp_handlist_t *i = *head;
if (*head == item) {
*head = item->next; if (i == item)
break; *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;
} }
head = &(*head)->next;
} }
} }
@@ -53,7 +56,8 @@ static void _handler_item_remove(xmpp_handlist_t **head, xmpp_handlist_t *item)
* @param conn a Strophe connection object * @param conn a Strophe connection object
* @param stanza a Strophe stanza object * @param stanza a Strophe stanza object
*/ */
void handler_fire_stanza(xmpp_conn_t *conn, xmpp_stanza_t *stanza) void handler_fire_stanza(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza)
{ {
xmpp_handlist_t *item, *next, *head, *head_old; xmpp_handlist_t *item, *next, *head, *head_old;
const char *id, *ns, *name, *type; const char *id, *ns, *name, *type;
@@ -71,8 +75,7 @@ void handler_fire_stanza(xmpp_conn_t *conn, xmpp_stanza_t *stanza)
while (item) { while (item) {
/* don't fire user handlers until authentication succeeds and /* don't fire user handlers until authentication succeeds and
and skip newly added handlers */ and skip newly added handlers */
if ((item->user_handler && !conn->authenticated) || if ((item->user_handler && !conn->authenticated) || !item->enabled) {
!item->enabled) {
item = item->next; item = item->next;
continue; continue;
} }
@@ -87,7 +90,7 @@ void handler_fire_stanza(xmpp_conn_t *conn, xmpp_stanza_t *stanza)
/* replace old value */ /* replace old value */
hash_add(conn->id_handlers, id, head); hash_add(conn->id_handlers, id, head);
} }
xmpp_free(conn->ctx, item->u.id); xmpp_free(conn->ctx, item->id);
xmpp_free(conn->ctx, item); xmpp_free(conn->ctx, item);
} }
item = next; item = next;
@@ -113,10 +116,10 @@ void handler_fire_stanza(xmpp_conn_t *conn, xmpp_stanza_t *stanza)
} }
next = item->next; next = item->next;
if ((!item->u.ns || (ns && strcmp(ns, item->u.ns) == 0) || if ((!item->ns || (ns && strcmp(ns, item->ns) == 0) ||
xmpp_stanza_get_child_by_ns(stanza, item->u.ns)) && xmpp_stanza_get_child_by_ns(stanza, item->ns)) &&
(!item->u.name || (name && strcmp(name, item->u.name) == 0)) && (!item->name || (name && strcmp(name, item->name) == 0)) &&
(!item->u.type || (type && strcmp(type, item->u.type) == 0))) { (!item->type || (type && strcmp(type, item->type) == 0))) {
ret = ((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 */ /* list may be changed during execution of a handler */
@@ -124,12 +127,9 @@ void handler_fire_stanza(xmpp_conn_t *conn, xmpp_stanza_t *stanza)
if (!ret) { if (!ret) {
/* handler is one-shot, so delete it */ /* handler is one-shot, so delete it */
_handler_item_remove(&conn->handlers, item); _handler_item_remove(&conn->handlers, item);
if (item->u.ns) if (item->ns) xmpp_free(conn->ctx, item->ns);
xmpp_free(conn->ctx, item->u.ns); if (item->name) xmpp_free(conn->ctx, item->name);
if (item->u.name) if (item->type) xmpp_free(conn->ctx, item->type);
xmpp_free(conn->ctx, item->u.name);
if (item->u.type)
xmpp_free(conn->ctx, item->u.type);
xmpp_free(conn->ctx, item); xmpp_free(conn->ctx, item);
} }
} }
@@ -144,7 +144,7 @@ void handler_fire_stanza(xmpp_conn_t *conn, xmpp_stanza_t *stanza)
* *
* @return the time in milliseconds until the next handler will be ready * @return the time in milliseconds until the next handler will be ready
*/ */
uint64_t handler_fire_timed(xmpp_ctx_t *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 *item, *next;
@@ -171,28 +171,27 @@ uint64_t handler_fire_timed(xmpp_ctx_t *ctx)
while (item) { while (item) {
/* don't fire user handlers until authentication succeeds and /* don't fire user handlers until authentication succeeds and
skip newly added handlers */ skip newly added handlers */
if ((item->user_handler && !conn->authenticated) || if ((item->user_handler && !conn->authenticated) || !item->enabled) {
!item->enabled) {
item = item->next; item = item->next;
continue; continue;
} }
next = item->next; next = item->next;
timestamp = time_stamp(); timestamp = time_stamp();
elapsed = time_elapsed(item->u.last_stamp, timestamp); elapsed = time_elapsed(item->last_stamp, timestamp);
if (elapsed >= item->u.period) { if (elapsed >= item->period) {
/* fire! */ /* fire! */
item->u.last_stamp = timestamp; item->last_stamp = timestamp;
ret = ((xmpp_timed_handler)item->handler)(conn, item->userdata); ret = ((xmpp_timed_handler)item->handler)(conn, item->userdata);
/* list may be changed during execution of a handler */ /* list may be changed during execution of a handler */
next = item->next; next = item->next;
if (!ret) { if (!ret) {
/* delete handler if it returned false */ /* delete handler if it returned false */
_handler_item_remove(&conn->timed_handlers, item); _handler_item_remove(&conn->timed_handlers, item);
xmpp_free(ctx, item); xmpp_free(conn->ctx, item);
} }
} else if (min > (item->u.period - elapsed)) } else if (min > (item->period - elapsed))
min = item->u.period - elapsed; min = item->period - elapsed;
item = next; item = next;
} }
@@ -200,34 +199,6 @@ uint64_t handler_fire_timed(xmpp_ctx_t *ctx)
connitem = connitem->next; connitem = connitem->next;
} }
/*
* Check timed handlers in context. These handlers fire periodically
* regardless of connections state.
* TODO Reduce copy-paste.
*/
item = ctx->timed_handlers;
while (item) {
next = item->next;
timestamp = time_stamp();
elapsed = time_elapsed(item->u.last_stamp, timestamp);
if (elapsed >= item->u.period) {
/* fire! */
item->u.last_stamp = timestamp;
ret =
((xmpp_global_timed_handler)item->handler)(ctx, item->userdata);
/* list may be changed during execution of a handler */
next = item->next;
if (!ret) {
/* delete handler if it returned false */
_handler_item_remove(&ctx->timed_handlers, item);
xmpp_free(ctx, item);
}
} else if (min > (item->u.period - elapsed))
min = item->u.period - elapsed;
item = next;
}
return min; return min;
} }
@@ -244,63 +215,50 @@ void handler_reset_timed(xmpp_conn_t *conn, int user_only)
handitem = conn->timed_handlers; handitem = conn->timed_handlers;
while (handitem) { while (handitem) {
if ((user_only && handitem->user_handler) || !user_only) if ((user_only && handitem->user_handler) || !user_only)
handitem->u.last_stamp = time_stamp(); handitem->last_stamp = time_stamp();
handitem = handitem->next; handitem = handitem->next;
} }
} }
static void _timed_handler_add(xmpp_ctx_t *ctx, static void _timed_handler_add(xmpp_conn_t * const conn,
xmpp_handlist_t **handlers_list, xmpp_timed_handler handler,
xmpp_void_handler handler, const unsigned long period,
unsigned long period, void * const userdata,
void *userdata, const int user_handler)
int user_handler)
{ {
xmpp_handlist_t *item; xmpp_handlist_t *item, *tail;
/* check if handler is already in the list */ /* check if handler is already in the list */
for (item = *handlers_list; item; item = item->next) { for (item = conn->timed_handlers; item; item = item->next) {
if (item->handler == handler && item->userdata == userdata) { if (item->handler == handler && item->userdata == userdata) {
xmpp_warn(ctx, "xmpp", "Timed handler already exists."); xmpp_warn(conn->ctx, "xmpp", "Timed handler already exists.");
break; break;
} }
} }
if (item) if (item) return;
return;
/* build new item */ /* build new item */
item = xmpp_alloc(ctx, sizeof(xmpp_handlist_t)); item = xmpp_alloc(conn->ctx, sizeof(xmpp_handlist_t));
if (!item) if (!item) return;
return;
item->user_handler = user_handler; item->user_handler = user_handler;
item->handler = handler; item->handler = handler;
item->userdata = userdata; item->userdata = userdata;
item->enabled = 0; item->enabled = 0;
item->next = NULL;
item->u.period = period; item->period = period;
item->u.last_stamp = time_stamp(); item->last_stamp = time_stamp();
/* append item to list */ /* append item to list */
item->next = *handlers_list; if (!conn->timed_handlers)
*handlers_list = item; conn->timed_handlers = item;
} else {
tail = conn->timed_handlers;
static void _timed_handler_delete(xmpp_ctx_t *ctx, while (tail->next)
xmpp_handlist_t **handlers_list, tail = tail->next;
xmpp_void_handler handler) tail->next = item;
{
xmpp_handlist_t *item;
while (*handlers_list) {
item = *handlers_list;
if (item->handler == handler) {
*handlers_list = item->next;
xmpp_free(ctx, item);
} else {
handlers_list = &item->next;
}
} }
} }
@@ -311,16 +269,35 @@ static void _timed_handler_delete(xmpp_ctx_t *ctx,
* *
* @ingroup Handlers * @ingroup Handlers
*/ */
void xmpp_timed_handler_delete(xmpp_conn_t *conn, xmpp_timed_handler handler) void xmpp_timed_handler_delete(xmpp_conn_t * const conn,
xmpp_timed_handler handler)
{ {
_timed_handler_delete(conn->ctx, &conn->timed_handlers, handler); xmpp_handlist_t *item, *prev;
if (!conn->timed_handlers) return;
prev = NULL;
item = conn->timed_handlers;
while (item) {
if (item->handler == handler) {
if (prev)
prev->next = item->next;
else
conn->timed_handlers = item->next;
xmpp_free(conn->ctx, item);
item = prev ? prev->next : conn->timed_handlers;
} else {
prev = item;
item = item->next;
}
}
} }
static void _id_handler_add(xmpp_conn_t *conn, static void _id_handler_add(xmpp_conn_t * const conn,
xmpp_handler handler, xmpp_handler handler,
const char *id, const char * const id,
void *userdata, void * const userdata, int user_handler)
int user_handler)
{ {
xmpp_handlist_t *item, *tail; xmpp_handlist_t *item, *tail;
@@ -333,13 +310,11 @@ static void _id_handler_add(xmpp_conn_t *conn,
} }
item = item->next; item = item->next;
} }
if (item) if (item) return;
return;
/* build new item */ /* build new item */
item = xmpp_alloc(conn->ctx, sizeof(xmpp_handlist_t)); item = xmpp_alloc(conn->ctx, sizeof(xmpp_handlist_t));
if (!item) if (!item) return;
return;
item->user_handler = user_handler; item->user_handler = user_handler;
item->handler = handler; item->handler = handler;
@@ -347,8 +322,8 @@ static void _id_handler_add(xmpp_conn_t *conn,
item->enabled = 0; item->enabled = 0;
item->next = NULL; item->next = NULL;
item->u.id = xmpp_strdup(conn->ctx, id); item->id = xmpp_strdup(conn->ctx, id);
if (!item->u.id) { if (!item->id) {
xmpp_free(conn->ctx, item); xmpp_free(conn->ctx, item);
return; return;
} }
@@ -372,16 +347,15 @@ static void _id_handler_add(xmpp_conn_t *conn,
* *
* @ingroup Handlers * @ingroup Handlers
*/ */
void xmpp_id_handler_delete(xmpp_conn_t *conn, void xmpp_id_handler_delete(xmpp_conn_t * const conn,
xmpp_handler handler, xmpp_handler handler,
const char *id) const char * const id)
{ {
xmpp_handlist_t *item, *prev, *next; xmpp_handlist_t *item, *prev, *next;
prev = NULL; prev = NULL;
item = (xmpp_handlist_t *)hash_get(conn->id_handlers, id); item = (xmpp_handlist_t *)hash_get(conn->id_handlers, id);
if (!item) if (!item) return;
return;
while (item) { while (item) {
next = item->next; next = item->next;
@@ -394,7 +368,7 @@ void xmpp_id_handler_delete(xmpp_conn_t *conn,
hash_add(conn->id_handlers, id, next); hash_add(conn->id_handlers, id, next);
} }
xmpp_free(conn->ctx, item->u.id); xmpp_free(conn->ctx, item->id);
xmpp_free(conn->ctx, item); xmpp_free(conn->ctx, item);
item = next; item = next;
} else { } else {
@@ -405,13 +379,12 @@ void xmpp_id_handler_delete(xmpp_conn_t *conn,
} }
/* add a stanza handler */ /* add a stanza handler */
static void _handler_add(xmpp_conn_t *conn, static void _handler_add(xmpp_conn_t * const conn,
xmpp_handler handler, xmpp_handler handler,
const char *ns, const char * const ns,
const char *name, const char * const name,
const char *type, const char * const type,
void *userdata, void * const userdata, int user_handler)
int user_handler)
{ {
xmpp_handlist_t *item, *tail; xmpp_handlist_t *item, *tail;
@@ -424,13 +397,11 @@ static void _handler_add(xmpp_conn_t *conn,
break; break;
} }
} }
if (item) if (item) return;
return;
/* build new item */ /* build new item */
item = (xmpp_handlist_t *)xmpp_alloc(conn->ctx, sizeof(xmpp_handlist_t)); item = (xmpp_handlist_t *)xmpp_alloc(conn->ctx, sizeof(xmpp_handlist_t));
if (!item) if (!item) return;
return;
item->user_handler = user_handler; item->user_handler = user_handler;
item->handler = handler; item->handler = handler;
@@ -439,36 +410,31 @@ static void _handler_add(xmpp_conn_t *conn,
item->next = NULL; item->next = NULL;
if (ns) { if (ns) {
item->u.ns = xmpp_strdup(conn->ctx, ns); item->ns = xmpp_strdup(conn->ctx, ns);
if (!item->u.ns) { if (!item->ns) {
xmpp_free(conn->ctx, item); xmpp_free(conn->ctx, item);
return; return;
} }
} else } else
item->u.ns = NULL; item->ns = NULL;
if (name) { if (name) {
item->u.name = xmpp_strdup(conn->ctx, name); item->name = xmpp_strdup(conn->ctx, name);
if (!item->u.name) { if (!item->name) {
if (item->u.ns) if (item->ns) xmpp_free(conn->ctx, item->ns);
xmpp_free(conn->ctx, item->u.ns);
xmpp_free(conn->ctx, item); xmpp_free(conn->ctx, item);
return; return;
} }
} else } else
item->u.name = NULL; item->name = NULL;
if (type) { if (type) {
item->u.type = xmpp_strdup(conn->ctx, type); item->type = xmpp_strdup(conn->ctx, type);
if (!item->u.type) { if (!item->type) {
if (item->u.ns) if (item->ns) xmpp_free(conn->ctx, item->ns);
xmpp_free(conn->ctx, item->u.ns); if (item->name) xmpp_free(conn->ctx, item->name);
if (item->u.name)
xmpp_free(conn->ctx, item->u.name);
xmpp_free(conn->ctx, item); xmpp_free(conn->ctx, item);
} }
} else } else
item->u.type = NULL; item->type = NULL;
/* append to list */ /* append to list */
if (!conn->handlers) if (!conn->handlers)
@@ -488,12 +454,12 @@ static void _handler_add(xmpp_conn_t *conn,
* *
* @ingroup Handlers * @ingroup Handlers
*/ */
void xmpp_handler_delete(xmpp_conn_t *conn, xmpp_handler handler) void xmpp_handler_delete(xmpp_conn_t * const conn,
xmpp_handler handler)
{ {
xmpp_handlist_t *prev, *item; xmpp_handlist_t *prev, *item;
if (!conn->handlers) if (!conn->handlers) return;
return;
prev = NULL; prev = NULL;
item = conn->handlers; item = conn->handlers;
@@ -504,12 +470,9 @@ void xmpp_handler_delete(xmpp_conn_t *conn, xmpp_handler handler)
else else
conn->handlers = item->next; conn->handlers = item->next;
if (item->u.ns) if (item->ns) xmpp_free(conn->ctx, item->ns);
xmpp_free(conn->ctx, item->u.ns); if (item->name) xmpp_free(conn->ctx, item->name);
if (item->u.name) if (item->type) xmpp_free(conn->ctx, item->type);
xmpp_free(conn->ctx, item->u.name);
if (item->u.type)
xmpp_free(conn->ctx, item->u.type);
xmpp_free(conn->ctx, item); xmpp_free(conn->ctx, item);
item = prev ? prev->next : conn->handlers; item = prev ? prev->next : conn->handlers;
} else { } else {
@@ -535,13 +498,12 @@ void xmpp_handler_delete(xmpp_conn_t *conn, xmpp_handler handler)
* *
* @ingroup Handlers * @ingroup Handlers
*/ */
void xmpp_timed_handler_add(xmpp_conn_t *conn, void xmpp_timed_handler_add(xmpp_conn_t * const conn,
xmpp_timed_handler handler, xmpp_timed_handler handler,
unsigned long period, const unsigned long period,
void *userdata) void * const userdata)
{ {
_timed_handler_add(conn->ctx, &conn->timed_handlers, handler, period, _timed_handler_add(conn, handler, period, userdata, 1);
userdata, 1);
} }
/** Add a timed system handler. /** Add a timed system handler.
@@ -553,13 +515,12 @@ void xmpp_timed_handler_add(xmpp_conn_t *conn,
* @param period the time in milliseconds between firings * @param period the time in milliseconds between firings
* @param userdata an opaque data pointer that will be passed to the handler * @param userdata an opaque data pointer that will be passed to the handler
*/ */
void handler_add_timed(xmpp_conn_t *conn, void handler_add_timed(xmpp_conn_t * const conn,
xmpp_timed_handler handler, xmpp_timed_handler handler,
unsigned long period, const unsigned long period,
void *userdata) void * const userdata)
{ {
_timed_handler_add(conn->ctx, &conn->timed_handlers, handler, period, _timed_handler_add(conn, handler, period, userdata, 0);
userdata, 0);
} }
/** Add an id based stanza handler. /** Add an id based stanza handler.
@@ -578,10 +539,10 @@ void handler_add_timed(xmpp_conn_t *conn,
* *
* @ingroup Handlers * @ingroup Handlers
*/ */
void xmpp_id_handler_add(xmpp_conn_t *conn, void xmpp_id_handler_add(xmpp_conn_t * const conn,
xmpp_handler handler, xmpp_handler handler,
const char *id, const char * const id,
void *userdata) void * const userdata)
{ {
_id_handler_add(conn, handler, id, userdata, 1); _id_handler_add(conn, handler, id, userdata, 1);
} }
@@ -595,10 +556,10 @@ void xmpp_id_handler_add(xmpp_conn_t *conn,
* @param id a string with the id * @param id a string with the id
* @param userdata an opaque data pointer that will be passed to the handler * @param userdata an opaque data pointer that will be passed to the handler
*/ */
void handler_add_id(xmpp_conn_t *conn, void handler_add_id(xmpp_conn_t * const conn,
xmpp_handler handler, xmpp_handler handler,
const char *id, const char * const id,
void *userdata) void * const userdata)
{ {
_id_handler_add(conn, handler, id, userdata, 0); _id_handler_add(conn, handler, id, userdata, 0);
} }
@@ -625,12 +586,12 @@ void handler_add_id(xmpp_conn_t *conn,
* *
* @ingroup Handlers * @ingroup Handlers
*/ */
void xmpp_handler_add(xmpp_conn_t *conn, void xmpp_handler_add(xmpp_conn_t * const conn,
xmpp_handler handler, xmpp_handler handler,
const char *ns, const char * const ns,
const char *name, const char * const name,
const char *type, const char * const type,
void *userdata) void * const userdata)
{ {
_handler_add(conn, handler, ns, name, type, userdata, 1); _handler_add(conn, handler, ns, name, type, userdata, 1);
} }
@@ -646,12 +607,12 @@ void xmpp_handler_add(xmpp_conn_t *conn,
* @param type a string with the 'type' attribute value to match * @param type a string with the 'type' attribute value to match
* @param userdata an opaque data pointer that will be passed to the handler * @param userdata an opaque data pointer that will be passed to the handler
*/ */
void handler_add(xmpp_conn_t *conn, void handler_add(xmpp_conn_t * const conn,
xmpp_handler handler, xmpp_handler handler,
const char *ns, const char * const ns,
const char *name, const char * const name,
const char *type, const char * const type,
void *userdata) void * const userdata)
{ {
_handler_add(conn, handler, ns, name, type, userdata, 0); _handler_add(conn, handler, ns, name, type, userdata, 0);
} }
@@ -675,12 +636,9 @@ void handler_system_delete_all(xmpp_conn_t *conn)
if (!item->user_handler) { if (!item->user_handler) {
next = item->next; next = item->next;
_handler_item_remove(&conn->handlers, item); _handler_item_remove(&conn->handlers, item);
if (item->u.ns) if (item->ns) xmpp_free(conn->ctx, item->ns);
xmpp_free(conn->ctx, item->u.ns); if (item->name) xmpp_free(conn->ctx, item->name);
if (item->u.name) if (item->type) xmpp_free(conn->ctx, item->type);
xmpp_free(conn->ctx, item->u.name);
if (item->u.type)
xmpp_free(conn->ctx, item->u.type);
xmpp_free(conn->ctx, item); xmpp_free(conn->ctx, item);
item = next; item = next;
} else } else
@@ -707,7 +665,7 @@ void handler_system_delete_all(xmpp_conn_t *conn)
if (!item->user_handler) { if (!item->user_handler) {
next = item->next; next = item->next;
_handler_item_remove(&head, item); _handler_item_remove(&head, item);
xmpp_free(conn->ctx, item->u.id); xmpp_free(conn->ctx, item->id);
xmpp_free(conn->ctx, item); xmpp_free(conn->ctx, item);
item = next; item = next;
} else } else
@@ -728,56 +686,5 @@ void handler_system_delete_all(xmpp_conn_t *conn)
xmpp_free(conn->ctx, key2); xmpp_free(conn->ctx, key2);
} }
} }
if (iter) if (iter) hash_iter_release(iter);
hash_iter_release(iter);
}
/** Add a global timed handler.
* The handler will fire for the first time once the period has elapsed,
* and continue firing regularly after that. Strophe will try its best
* to fire handlers as close to the period times as it can, but accuracy
* will vary depending on the resolution of the event loop.
*
* The main difference between global and ordinary handlers:
* - Ordinary handler is related to a connection, fires only when the
* connection is in connected state and is removed once the connection is
* destroyed.
* - Global handler fires regardless of connections state and is related to
* a Strophe context.
*
* The handler is executed in context of the respective event loop.
*
* If the handler function returns true, it will be kept, and if it
* returns false, it will be deleted from the list of handlers.
*
* Notice, the same handler pointer may be added multiple times with different
* userdata pointers. However, xmpp_global_timed_handler_delete() deletes
* all occurrences.
*
* @param ctx a Strophe context object
* @param handler a function pointer to a timed handler
* @param period the time in milliseconds between firings
* @param userdata an opaque data pointer that will be passed to the handler
*
* @ingroup Handlers
*/
void xmpp_global_timed_handler_add(xmpp_ctx_t *ctx,
xmpp_global_timed_handler handler,
unsigned long period,
void *userdata)
{
_timed_handler_add(ctx, &ctx->timed_handlers, handler, period, userdata, 1);
}
/** Delete a global timed handler.
*
* @param ctx a Strophe context object
* @param handler function pointer to the handler
*
* @ingroup Handlers
*/
void xmpp_global_timed_handler_delete(xmpp_ctx_t *ctx,
xmpp_global_timed_handler handler)
{
_timed_handler_delete(ctx, &ctx->timed_handlers, handler);
} }

View File

@@ -1,7 +1,7 @@
/* hash.c /* hash.c
** strophe XMPP client library -- hash table implementation ** strophe XMPP client library -- hash table implementation
** **
** Copyright (C) 2005-2009 Collecta, Inc. ** Copyright (C) 2005-2009 Collecta, Inc.
** **
** This software is provided AS-IS with no warranty, either express ** This software is provided AS-IS with no warranty, either express
** or implied. ** or implied.
@@ -44,177 +44,171 @@ struct _hash_iterator_t {
hashentry_t *entry; hashentry_t *entry;
int index; int index;
}; };
/** allocate and initialize a new hash table */ /** allocate and initialize a new hash table */
hash_t *hash_new(xmpp_ctx_t *ctx, int size, hash_free_func free_func) hash_t *hash_new(xmpp_ctx_t * const ctx, const int size,
hash_free_func free_func)
{ {
hash_t *result = NULL; hash_t *result = NULL;
result = xmpp_alloc(ctx, sizeof(hash_t)); result = xmpp_alloc(ctx, sizeof(hash_t));
if (result != NULL) { if (result != NULL) {
result->entries = xmpp_alloc(ctx, size * sizeof(hashentry_t *)); result->entries = xmpp_alloc(ctx, size * sizeof(hashentry_t *));
if (result->entries == NULL) { if (result->entries == NULL) {
xmpp_free(ctx, result); xmpp_free(ctx, result);
return NULL; return NULL;
} }
memset(result->entries, 0, size * sizeof(hashentry_t *)); memset(result->entries, 0, size * sizeof(hashentry_t *));
result->length = size; result->length = size;
result->ctx = ctx; result->ctx = ctx;
result->free = free_func; result->free = free_func;
result->num_keys = 0; result->num_keys = 0;
/* give the caller a reference */ /* give the caller a reference */
result->ref = 1; result->ref = 1;
} }
return result; return result;
} }
/** obtain a new reference to an existing hash table */ /** obtain a new reference to an existing hash table */
hash_t *hash_clone(hash_t *table) hash_t *hash_clone(hash_t * const table)
{ {
table->ref++; table->ref++;
return table; return table;
} }
/** release a hash table that is no longer needed */ /** release a hash table that is no longer needed */
void hash_release(hash_t *table) void hash_release(hash_t * const table)
{ {
xmpp_ctx_t *ctx = table->ctx; xmpp_ctx_t *ctx = table->ctx;
hashentry_t *entry, *next; hashentry_t *entry, *next;
int i; int i;
if (table->ref > 1) if (table->ref > 1)
table->ref--; table->ref--;
else { else {
for (i = 0; i < table->length; i++) { for (i = 0; i < table->length; i++) {
entry = table->entries[i]; entry = table->entries[i];
while (entry != NULL) { while (entry != NULL) {
next = entry->next; next = entry->next;
xmpp_free(ctx, entry->key); xmpp_free(ctx, entry->key);
if (table->free) if (table->free) table->free(ctx, entry->value);
table->free(ctx, entry->value); xmpp_free(ctx, entry);
xmpp_free(ctx, entry); entry = next;
entry = next; }
} }
} xmpp_free(ctx, table->entries);
xmpp_free(ctx, table->entries); xmpp_free(ctx, table);
xmpp_free(ctx, 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; unsigned hash = 0;
unsigned shift = 0; unsigned shift = 0;
const unsigned char *c = (const unsigned char *)key; const unsigned char *c = (const unsigned char *)key;
while (*c != 0) { while (*c != 0) {
/* assume 32 bit ints */ /* assume 32 bit ints */
hash ^= ((unsigned)*c++ << shift); hash ^= ((unsigned)*c++ << shift);
shift += 8; shift += 8;
if (shift > 24) if (shift > 24) shift = 0;
shift = 0; }
} return hash % (unsigned)table->length;
return hash % (unsigned)table->length;
} }
hashentry_t *_hash_entry_find(hash_t *table, const char *key) hashentry_t *_hash_entry_find(hash_t *table, const char *key)
{ {
hashentry_t *entry; hashentry_t *entry;
int table_index = _hash_key(table, key); int table_index = _hash_key(table, key);
/* look up the hash entry */ /* look up the hash entry */
entry = table->entries[table_index]; entry = table->entries[table_index];
while (entry != NULL) { while (entry != NULL) {
/* traverse the linked list looking for the key */ /* traverse the linked list looking for the key */
if (!strcmp(key, entry->key)) { if (!strcmp(key, entry->key)) {
/* match */ /* match */
break; break;
} }
entry = entry->next; entry = entry->next;
} }
return entry; return entry;
} }
/** add a key, value pair to a hash table. /** add a key, value pair to a hash table.
* each key can appear only once; the value of any * each key can appear only once; the value of any
* identical key will be replaced * identical key will be replaced
*/ */
int hash_add(hash_t *table, const char *key, void *data) 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 table_index = _hash_key(table, key);
/* find and replace existing entry, if any */ /* find and replace existing entry, if any */
entry = _hash_entry_find(table, key); entry = _hash_entry_find(table, key);
if (entry == NULL) { 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) if (!entry) return -1;
return -1; entry->key = xmpp_strdup(ctx, key);
entry->key = xmpp_strdup(ctx, key); if (!entry->key) {
if (!entry->key) { xmpp_free(ctx, entry);
xmpp_free(ctx, entry); return -1;
return -1; }
} /* insert ourselves in the linked list */
/* insert ourselves in the linked list */ entry->next = table->entries[table_index];
entry->next = table->entries[table_index]; table->entries[table_index] = entry;
table->entries[table_index] = entry; table->num_keys++;
table->num_keys++; }
} else {
if (table->free)
table->free(ctx, entry->value);
}
entry->value = data; entry->value = data;
return 0; return 0;
} }
/** look up a key in a hash table */ /** look up a key in a hash table */
void *hash_get(hash_t *table, const char *key) void *hash_get(hash_t *table, const char *key)
{ {
hashentry_t *entry; hashentry_t *entry;
entry = _hash_entry_find(table, key); entry = _hash_entry_find(table, key);
return entry == NULL ? NULL : entry->value; return entry == NULL ? NULL : entry->value;
} }
/** delete a key from a hash table */ /** delete a key from a hash table */
int hash_drop(hash_t *table, const char *key) 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 table_index = _hash_key(table, key);
/* look up the hash entry */ /* look up the hash entry */
entry = table->entries[table_index]; entry = table->entries[table_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 */
if (!strcmp(key, entry->key)) { if (!strcmp(key, entry->key)) {
/* match, remove the entry */ /* match, remove the entry */
xmpp_free(ctx, entry->key); xmpp_free(ctx, entry->key);
if (table->free) if (table->free) table->free(ctx, entry->value);
table->free(ctx, entry->value); if (prev == NULL) {
if (prev == NULL) { table->entries[table_index] = entry->next;
table->entries[table_index] = entry->next; } else {
} else { prev->next = entry->next;
prev->next = entry->next; }
} xmpp_free(ctx, entry);
xmpp_free(ctx, entry); table->num_keys--;
table->num_keys--; return 0;
return 0; }
} prev = entry;
prev = entry; entry = entry->next;
entry = entry->next; }
} /* no match */
/* no match */ return -1;
return -1;
} }
int hash_num_keys(hash_t *table) int hash_num_keys(hash_t *table)
@@ -230,15 +224,16 @@ hash_iterator_t *hash_iter_new(hash_t *table)
iter = xmpp_alloc(ctx, sizeof(*iter)); iter = xmpp_alloc(ctx, sizeof(*iter));
if (iter != NULL) { if (iter != NULL) {
iter->ref = 1; iter->ref = 1;
iter->table = hash_clone(table); iter->table = hash_clone(table);
iter->entry = NULL; iter->entry = NULL;
iter->index = -1; iter->index = -1;
} }
return iter; return iter;
} }
/** release an iterator that is no longer needed */ /** release an iterator that is no longer needed */
void hash_iter_release(hash_iterator_t *iter) void hash_iter_release(hash_iterator_t *iter)
{ {
@@ -246,39 +241,38 @@ void hash_iter_release(hash_iterator_t *iter)
iter->ref--; iter->ref--;
if (iter->ref == 0) { // ref is unsigned!!! if (iter->ref <= 0) {
hash_release(iter->table); hash_release(iter->table);
xmpp_free(ctx, iter); xmpp_free(ctx, iter);
} }
} }
/** return the next hash table key from the iterator. /** return the next hash table key from the iterator.
the returned key should not be freed */ the returned key should not be freed */
const char *hash_iter_next(hash_iterator_t *iter) const char * hash_iter_next(hash_iterator_t *iter)
{ {
hash_t *table = iter->table; hash_t *table = iter->table;
hashentry_t *entry = iter->entry; hashentry_t *entry = iter->entry;
int i; int i;
/* advance until we find the next entry */ /* advance until we find the next entry */
if (entry != NULL) if (entry != NULL) entry = entry->next;
entry = entry->next;
if (entry == NULL) { if (entry == NULL) {
/* we're off the end of list, search for a new entry */ /* we're off the end of list, search for a new entry */
i = iter->index + 1; i = iter->index + 1;
while (i < iter->table->length) { while (i < iter->table->length) {
entry = table->entries[i]; entry = table->entries[i];
if (entry != NULL) { if (entry != NULL) {
iter->index = i; iter->index = i;
break; break;
} }
i++; i++;
} }
} }
if (entry == NULL) { if (entry == NULL) {
/* no more keys! */ /* no more keys! */
return NULL; return NULL;
} }
/* remember our current match */ /* remember our current match */

View File

@@ -1,7 +1,7 @@
/* hash.h /* hash.h
** strophe XMPP client library -- hash table interface ** strophe XMPP client library -- hash table interface
** **
** Copyright (C) 2005-2009 Collecta, Inc. ** Copyright (C) 2005-2009 Collecta, Inc.
** **
** This software is provided AS-IS with no warranty, either express ** This software is provided AS-IS with no warranty, either express
** or implied. ** or implied.
@@ -18,22 +18,23 @@
typedef struct _hash_t hash_t; typedef struct _hash_t hash_t;
typedef void (*hash_free_func)(const xmpp_ctx_t *ctx, void *p); typedef void (*hash_free_func)(const xmpp_ctx_t * const ctx, void *p);
/** allocate and initialize a new hash table */ /** allocate and initialize a new hash table */
hash_t *hash_new(xmpp_ctx_t *ctx, int size, hash_free_func free_func); hash_t *hash_new(xmpp_ctx_t * const ctx, const int size,
hash_free_func free_func);
/** allocate a new reference to an existing hash table */ /** allocate a new reference to an existing hash table */
hash_t *hash_clone(hash_t *table); hash_t *hash_clone(hash_t * const table);
/** release a hash table when no longer needed */ /** release a hash table when no longer needed */
void hash_release(hash_t *table); void hash_release(hash_t * const table);
/** add a key, value pair to a hash table. /** add a key, value pair to a hash table.
* each key can appear only once; the value of any * each key can appear only once; the value of any
* identical key will be replaced * identical key will be replaced
*/ */
int hash_add(hash_t *table, const char *key, void *data); int hash_add(hash_t *table, const char * const key, void *data);
/** look up a key in a hash table */ /** look up a key in a hash table */
void *hash_get(hash_t *table, const char *key); void *hash_get(hash_t *table, const char *key);
@@ -55,6 +56,6 @@ void hash_iter_release(hash_iterator_t *iter);
/** return the next hash table key from the iterator. /** return the next hash table key from the iterator.
the returned key should not be freed */ the returned key should not be freed */
const char *hash_iter_next(hash_iterator_t *iter); const char * hash_iter_next(hash_iterator_t *iter);
#endif /* __LIBXMPPP_HASH_H__ */ #endif /* __LIBXMPPP_HASH_H__ */

View File

@@ -1,7 +1,7 @@
/* jid.c /* jid.c
** strophe XMPP client library -- helper functions for parsing JIDs ** strophe XMPP client library -- helper functions for parsing JIDs
** **
** Copyright (C) 2005-2009 Collecta, Inc. ** Copyright (C) 2005-2009 Collecta, Inc.
** **
** This software is provided AS-IS with no warranty, either express ** This software is provided AS-IS with no warranty, either express
** or implied. ** or implied.
@@ -28,17 +28,15 @@
* @return an allocated string with the full JID or NULL if no domain * @return an allocated string with the full JID or NULL if no domain
* is specified * is specified
*/ */
char *xmpp_jid_new(xmpp_ctx_t *ctx, char *xmpp_jid_new(xmpp_ctx_t *ctx, const char *node,
const char *node, const char *domain,
const char *domain, const char *resource)
const char *resource)
{ {
char *result; char *result;
size_t len, nlen, dlen, rlen; size_t len, nlen, dlen, rlen;
/* jid must at least have a domain */ /* jid must at least have a domain */
if (domain == NULL) if (domain == NULL) return NULL;
return NULL;
/* accumulate lengths */ /* accumulate lengths */
dlen = strlen(domain); dlen = strlen(domain);
@@ -49,23 +47,23 @@ char *xmpp_jid_new(xmpp_ctx_t *ctx,
/* concat components */ /* concat components */
result = xmpp_alloc(ctx, len + 1); result = xmpp_alloc(ctx, len + 1);
if (result != NULL) { if (result != NULL) {
if (node != NULL) { if (node != NULL) {
memcpy(result, node, nlen - 1); memcpy(result, node, nlen - 1);
result[nlen - 1] = '@'; result[nlen-1] = '@';
} }
memcpy(result + nlen, domain, dlen); memcpy(result + nlen, domain, dlen);
if (resource != NULL) { if (resource != NULL) {
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[len] = '\0';
} }
return result; return result;
} }
/** Create a bare JID from a JID. /** Create a bare JID from a JID.
* *
* @param ctx the Strophe context object * @param ctx the Strophe context object
* @param jid the JID * @param jid the JID
* *
@@ -79,15 +77,15 @@ char *xmpp_jid_bare(xmpp_ctx_t *ctx, const char *jid)
len = strcspn(jid, "/"); len = strcspn(jid, "/");
result = xmpp_alloc(ctx, len + 1); result = xmpp_alloc(ctx, len + 1);
if (result != NULL) { if (result != NULL) {
memcpy(result, jid, len); memcpy(result, jid, len);
result[len] = '\0'; result[len] = '\0';
} }
return result; return result;
} }
/** Create a node string from a JID. /** Create a node string from a JID.
* *
* @param ctx a Strophe context object * @param ctx a Strophe context object
* @param jid the JID * @param jid the JID
* *
@@ -101,11 +99,11 @@ char *xmpp_jid_node(xmpp_ctx_t *ctx, const char *jid)
c = strchr(jid, '@'); c = strchr(jid, '@');
if (c != NULL) { if (c != NULL) {
result = xmpp_alloc(ctx, (c - jid) + 1); result = xmpp_alloc(ctx, (c-jid) + 1);
if (result != NULL) { if (result != NULL) {
memcpy(result, jid, (c - jid)); memcpy(result, jid, (c-jid));
result[c - jid] = '\0'; result[c-jid] = '\0';
} }
} }
return result; return result;
@@ -126,17 +124,17 @@ char *xmpp_jid_domain(xmpp_ctx_t *ctx, const char *jid)
c = strchr(jid, '@'); c = strchr(jid, '@');
if (c == NULL) { if (c == NULL) {
/* no node, assume domain */ /* no node, assume domain */
c = jid; c = jid;
} else { } else {
/* advance past the separator */ /* advance past the separator */
c++; c++;
} }
dlen = strcspn(c, "/"); /* do not include resource */ dlen = strcspn(c, "/"); /* do not include resource */
result = xmpp_alloc(ctx, dlen + 1); result = xmpp_alloc(ctx, dlen + 1);
if (result != NULL) { if (result != NULL) {
memcpy(result, c, dlen); memcpy(result, c, dlen);
result[dlen] = '\0'; result[dlen] = '\0';
} }
return result; return result;
@@ -147,7 +145,7 @@ char *xmpp_jid_domain(xmpp_ctx_t *ctx, const char *jid)
* @param ctx a Strophe context object * @param ctx a Strophe context object
* @param jid the JID * @param jid the JID
* *
* @return an allocated string with the resource or NULL if no resource * @return an allocated string with the resource or NULL if no resource
* is found or an error occurs * is found or an error occurs
*/ */
char *xmpp_jid_resource(xmpp_ctx_t *ctx, const char *jid) char *xmpp_jid_resource(xmpp_ctx_t *ctx, const char *jid)

View File

@@ -29,21 +29,22 @@
#include "md5.h" #include "md5.h"
/* little-endian word access macros */ /* little-endian word access macros */
#define GET_32BIT_LSB_FIRST(cp) \ #define GET_32BIT_LSB_FIRST(cp) \
(((uint32_t)(unsigned char)(cp)[0]) | \ (((uint32_t)(unsigned char)(cp)[0]) | \
((uint32_t)(unsigned char)(cp)[1] << 8) | \ ((uint32_t)(unsigned char)(cp)[1] << 8 ) | \
((uint32_t)(unsigned char)(cp)[2] << 16) | \ ((uint32_t)(unsigned char)(cp)[2] << 16) | \
((uint32_t)(unsigned char)(cp)[3] << 24)) ((uint32_t)(unsigned char)(cp)[3] << 24))
#define PUT_32BIT_LSB_FIRST(cp, value) \ #define PUT_32BIT_LSB_FIRST(cp, value) \
do { \ do { \
(cp)[0] = (value)&0xFF; \ (cp)[0] = (value) & 0xFF; \
(cp)[1] = ((value) >> 8) & 0xFF; \ (cp)[1] = ((value) >> 8) & 0xFF; \
(cp)[2] = ((value) >> 16) & 0xFF; \ (cp)[2] = ((value) >> 16) & 0xFF; \
(cp)[3] = ((value) >> 24) & 0xFF; \ (cp)[3] = ((value) >> 24) & 0xFF; \
} while (0) } while(0)
static void MD5Transform(uint32_t buf[4], const unsigned char inext[64]); static void MD5Transform(uint32_t buf[4], const unsigned char inext[64],
struct MD5Context *ctx);
/* /*
* Start MD5 accumulation. Set bit count to 0 and buffer to mysterious * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
@@ -74,10 +75,10 @@ void MD5Update(struct MD5Context *ctx, unsigned char const *buf, uint32_t len)
t = ctx->bits[0]; t = ctx->bits[0];
if ((ctx->bits[0] = (t + ((uint32_t)len << 3)) & 0xffffffff) < t) if ((ctx->bits[0] = (t + ((uint32_t)len << 3)) & 0xffffffff) < t)
ctx->bits[1]++; /* Carry from low to high */ ctx->bits[1]++; /* Carry from low to high */
ctx->bits[1] += len >> 29; ctx->bits[1] += len >> 29;
t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
/* Handle any leading odd-sized chunks */ /* Handle any leading odd-sized chunks */
@@ -90,7 +91,7 @@ void MD5Update(struct MD5Context *ctx, unsigned char const *buf, uint32_t len)
return; return;
} }
memcpy(p, buf, t); memcpy(p, buf, t);
MD5Transform(ctx->buf, ctx->in); MD5Transform(ctx->buf, ctx->in, ctx);
buf += t; buf += t;
len -= t; len -= t;
} }
@@ -98,7 +99,7 @@ void MD5Update(struct MD5Context *ctx, unsigned char const *buf, uint32_t len)
while (len >= 64) { while (len >= 64) {
memcpy(ctx->in, buf, 64); memcpy(ctx->in, buf, 64);
MD5Transform(ctx->buf, ctx->in); MD5Transform(ctx->buf, ctx->in, ctx);
buf += 64; buf += 64;
len -= 64; len -= 64;
} }
@@ -109,7 +110,7 @@ void MD5Update(struct MD5Context *ctx, unsigned char const *buf, uint32_t len)
} }
/* /*
* Final wrapup - pad to 64-byte boundary with the bit pattern * Final wrapup - pad to 64-byte boundary with the bit pattern
* 1 0* (64-bit count of bits processed, MSB-first) * 1 0* (64-bit count of bits processed, MSB-first)
*/ */
void MD5Final(unsigned char digest[16], struct MD5Context *ctx) void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
@@ -132,7 +133,7 @@ void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
if (count < 8) { if (count < 8) {
/* Two lots of padding: Pad the first block to 64 bytes */ /* Two lots of padding: Pad the first block to 64 bytes */
memset(p, 0, count); memset(p, 0, count);
MD5Transform(ctx->buf, ctx->in); MD5Transform(ctx->buf, ctx->in, ctx);
/* Now fill the next block with 56 bytes */ /* Now fill the next block with 56 bytes */
memset(ctx->in, 0, 56); memset(ctx->in, 0, 56);
@@ -145,12 +146,12 @@ void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
PUT_32BIT_LSB_FIRST(ctx->in + 56, ctx->bits[0]); PUT_32BIT_LSB_FIRST(ctx->in + 56, ctx->bits[0]);
PUT_32BIT_LSB_FIRST(ctx->in + 60, ctx->bits[1]); PUT_32BIT_LSB_FIRST(ctx->in + 60, ctx->bits[1]);
MD5Transform(ctx->buf, ctx->in); MD5Transform(ctx->buf, ctx->in, ctx);
PUT_32BIT_LSB_FIRST(digest, ctx->buf[0]); PUT_32BIT_LSB_FIRST(digest, ctx->buf[0]);
PUT_32BIT_LSB_FIRST(digest + 4, ctx->buf[1]); PUT_32BIT_LSB_FIRST(digest + 4, ctx->buf[1]);
PUT_32BIT_LSB_FIRST(digest + 8, ctx->buf[2]); PUT_32BIT_LSB_FIRST(digest + 8, ctx->buf[2]);
PUT_32BIT_LSB_FIRST(digest + 12, ctx->buf[3]); PUT_32BIT_LSB_FIRST(digest + 12, ctx->buf[3]);
memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */ memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */
} }
/* The four core functions - F1 is optimized somewhat */ /* The four core functions - F1 is optimized somewhat */
@@ -172,20 +173,21 @@ void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
w = w<<s | w>>(32-s), printf(" - w: %x\n", w), w += x ) w = w<<s | w>>(32-s), printf(" - w: %x\n", w), w += x )
*/ */
#define MD5STEP(f, w, x, y, z, data, s) \ #define MD5STEP(f, w, x, y, z, data, s) \
(w += f(x, y, z) + data, w = w << s | w >> (32 - s), w += x) ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
/* /*
* The core of the MD5 algorithm, this alters an existing MD5 hash to * The core of the MD5 algorithm, this alters an existing MD5 hash to
* reflect the addition of 16 longwords of new data. MD5Update blocks * reflect the addition of 16 longwords of new data. MD5Update blocks
* the data and converts bytes into longwords for this routine. * the data and converts bytes into longwords for this routine.
*/ */
static void MD5Transform(uint32_t buf[4], const unsigned char inext[64]) static void MD5Transform(uint32_t buf[4], const unsigned char inext[64],
struct MD5Context *ctx)
{ {
register uint32_t a, b, c, d, i; register uint32_t a, b, c, d, i;
uint32_t in[16]; uint32_t in[16];
for (i = 0; i < 16; i++) for (i = 0; i < 16; i++)
in[i] = GET_32BIT_LSB_FIRST(inext + 4 * i); in[i] = GET_32BIT_LSB_FIRST(inext + 4 * i);
a = buf[0]; a = buf[0];
b = buf[1]; b = buf[1];

View File

@@ -21,8 +21,7 @@ struct MD5Context {
}; };
void MD5Init(struct MD5Context *context); void MD5Init(struct MD5Context *context);
void MD5Update(struct MD5Context *context, void MD5Update(struct MD5Context *context, unsigned char const *buf,
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);

84
src/oocontext.cpp Normal file
View File

@@ -0,0 +1,84 @@
/* oocontext.cpp
** strophe XMPP client library -- C++ context implementation
**
** Copyright (C) 2005-2009 Collecta, Inc.
**
** This software is provided AS-IS with no warranty, either express
** or implied.
**
** This program is dual licensed under the MIT and GPLv3 licenses.
*/
#include <stdlib.h>
#include "strophe.h"
#include "strophepp.h"
XMPP::Context::Context()
{
m_mem.alloc = callAlloc;
m_mem.realloc = callRealloc;
m_mem.free = callFree;
m_mem.userdata = (void *)this;
m_log.handler = callLog;
m_log.userdata = (void *)this;
m_ctx = ::xmpp_ctx_new(&m_mem, &m_log);
}
XMPP::Context::~Context()
{
::xmpp_ctx_free(m_ctx);
}
void *XMPP::Context::alloc(const size_t size)
{
return ::malloc(size);
}
void *XMPP::Context::realloc(void *p, const size_t size)
{
return ::realloc(p, size);
}
void XMPP::Context::free(void *p)
{
::free(p);
}
void XMPP::Context::log(const xmpp_log_level_t level,
const char * const area,
const char * const msg)
{
/* do nothing by default */
}
xmpp_ctx_t *XMPP::Context::getContext()
{
return m_ctx;
}
void *XMPP::Context::callAlloc(const size_t size, void * const userdata)
{
return reinterpret_cast<Context *>(userdata)->alloc(size);
}
void *XMPP::Context::callRealloc(void *p, const size_t size,
void * const userdata)
{
return reinterpret_cast<Context *>(userdata)->realloc(p, size);
}
void XMPP::Context::callFree(void *p, void * const userdata)
{
reinterpret_cast<Context *>(userdata)->free(p);
}
void XMPP::Context::callLog(void * const userdata,
const xmpp_log_level_t level,
const char * const area,
const char * const msg)
{
reinterpret_cast<Context *>(userdata)->log(level, area, msg);
}

77
src/oostanza.cpp Normal file
View File

@@ -0,0 +1,77 @@
/* oostanza.cpp
** strophe XMPP client library -- C++ context implementation
**
** Copyright (C) 2005-2009 Collecta, Inc.
**
** This software is provided AS-IS with no warranty, either express
** or implied.
**
** This program is dual licensed under the MIT and GPLv3 licenses.
*/
#include "strophe.h"
#include "strophepp.h"
using namespace XMPP;
void *Stanza::operator new(size_t size, Context *ctx)
{
void *p;
/* we must allocate extra room for the Context object so that the
destructor can access it to free the object. C++ does not allow
us to access normal members in the destructor, so we have to hide
it. This must be prepended as well, since C++ will add stuff to
the end in subclasses. */
p = ctx->alloc(size + sizeof(Context *));
if (!p) return p;
*reinterpret_cast<Context **>(p) = ctx;
p = reinterpret_cast<void *>(reinterpret_cast<char *>(p) +
sizeof(Context *));
return p;
}
void Stanza::operator delete(void *p)
{
Context *ctx;
ctx = *reinterpret_cast<Context **>(reinterpret_cast<char *>(p) - 4);
ctx->free(reinterpret_cast<char *>(p) - 4);
}
Stanza::Stanza(Context *ctx)
{
m_ctx = ctx;
m_stanza = ::xmpp_stanza_new(ctx->getContext());
// TODO: check for errors
}
Stanza::~Stanza()
{
}
Stanza *Stanza::create(Context *ctx)
{
return new (ctx) Stanza(ctx);
}
void Stanza::release()
{
if (::xmpp_stanza_release(m_stanza))
delete this;
}
Stanza *Stanza::clone()
{
::xmpp_stanza_clone(m_stanza);
return this;
}
Stanza *Stanza::copy()
{
// TODO
return NULL;
}

View File

@@ -1,8 +1,8 @@
/* ostypes.h /* ostypes.h
** strophe XMPP client library -- type definitions for platforms ** strophe XMPP client library -- type definitions for platforms
** without stdint.h ** without stdint.h
** **
** Copyright (C) 2005-2009 Collecta, Inc. ** Copyright (C) 2005-2009 Collecta, Inc.
** **
** This software is provided AS-IS with no warranty, either express ** This software is provided AS-IS with no warranty, either express
** or implied. ** or implied.
@@ -17,9 +17,9 @@
#ifndef __LIBSTROPHE_OSTYPES_H__ #ifndef __LIBSTROPHE_OSTYPES_H__
#define __LIBSTROPHE_OSTYPES_H__ #define __LIBSTROPHE_OSTYPES_H__
#include <stddef.h> /* size_t */ #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;
typedef int int32_t; typedef int int32_t;
@@ -28,7 +28,7 @@ typedef __int64 int64_t;
typedef unsigned char uint8_t; 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 #ifndef UINT16_MAX
#define UINT16_MAX ((uint16_t)0xffff) #define UINT16_MAX ((uint16_t)0xffff)

View File

@@ -1,7 +1,7 @@
/* parser.h /* parser.h
** strophe XMPP client library -- parser structures and functions ** strophe XMPP client library -- parser structures and functions
** **
** Copyright (C) 2005-2009 Collecta, Inc. ** Copyright (C) 2005-2009 Collecta, Inc.
** **
** This software is provided AS-IS with no warranty, either express or ** This software is provided AS-IS with no warranty, either express or
** implied. ** implied.
@@ -20,17 +20,21 @@
typedef struct _parser_t parser_t; typedef struct _parser_t parser_t;
typedef void (*parser_start_callback)(char *name, char **attrs, void *userdata); typedef void (*parser_start_callback)(char *name,
typedef void (*parser_end_callback)(char *name, void *userdata); char **attrs,
typedef void (*parser_stanza_callback)(xmpp_stanza_t *stanza, void *userdata); void * const userdata);
typedef void (*parser_end_callback)(char *name, void * const userdata);
typedef void (*parser_stanza_callback)(xmpp_stanza_t *stanza,
void * const userdata);
parser_t *parser_new(xmpp_ctx_t *ctx,
parser_t *parser_new(xmpp_ctx_t *ctx,
parser_start_callback startcb, parser_start_callback startcb,
parser_end_callback endcb, parser_end_callback endcb,
parser_stanza_callback stanzacb, parser_stanza_callback stanzacb,
void *userdata); void *userdata);
void parser_free(parser_t *parser); void parser_free(parser_t *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

@@ -1,7 +1,7 @@
/* parser.c /* parser.c
** strophe XMPP client library -- xml parser handlers and utility functions ** strophe XMPP client library -- xml parser handlers and utility functions
** **
** Copyright (C) 2005-2009 Collecta, Inc. ** Copyright (C) 2005-2009 Collecta, Inc.
** **
** This software is provided AS-IS with no warranty, either express ** This software is provided AS-IS with no warranty, either express
** or implied. ** or implied.
@@ -19,10 +19,13 @@
#include <expat.h> #include <expat.h>
#include "strophe.h" #include <strophe.h>
#include "common.h" #include "common.h"
#include "parser.h" #include "parser.h"
/* Use the Unit Separator to delimit namespace and name in our XML*/
#define NAMESPACE_SEP ('\x1F')
/* Allocate inner text by this number bytes more. Expat splits string /* Allocate inner text by this number bytes more. Expat splits string
* "new\nline" into 3 strings: "new" "\n" "line". Expecting this pattern, * "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 * we can leave few bytes in the inner_text for "\n". It should reduce
@@ -38,53 +41,13 @@ struct _parser_t {
void *userdata; void *userdata;
int depth; int depth;
xmpp_stanza_t *stanza; xmpp_stanza_t *stanza;
char *inner_text; char* inner_text;
/* number of allocated bytes */ /* number of allocated bytes */
int inner_text_size; int inner_text_size;
/* excluding terminal '\0' */ /* excluding terminal '\0' */
int inner_text_used; int inner_text_used;
}; };
/* Use the Unit Separator to delimit namespace and name in our XML */
const XML_Char namespace_sep = '\x1F';
/*
* Cached strophe ctx. It is used for memory suite.
* Note, expat doesn't support userdata in memory suite, therefore,
* we can support only one strophe context. If user creates more than one
* context, this module will fallback to default library allocator for all
* contexts other than mem_ctx.
*/
static xmpp_ctx_t *mem_ctx = NULL;
static void *parser_mem_malloc(size_t size)
{
if (mem_ctx != NULL)
return xmpp_alloc(mem_ctx, size);
else
return NULL;
}
static void *parser_mem_realloc(void *ptr, size_t size)
{
if (mem_ctx != NULL)
return xmpp_realloc(mem_ctx, ptr, size);
else
return NULL;
}
static void parser_mem_free(void *ptr)
{
if (mem_ctx != NULL)
xmpp_free(mem_ctx, ptr);
}
static const XML_Memory_Handling_Suite parser_mem_suite = {
.malloc_fcn = &parser_mem_malloc,
.realloc_fcn = &parser_mem_realloc,
.free_fcn = &parser_mem_free,
};
/* return allocated string with the name from a delimited /* return allocated string with the name from a delimited
* namespace/name string */ * namespace/name string */
static char *_xml_name(xmpp_ctx_t *ctx, const char *nsname) static char *_xml_name(xmpp_ctx_t *ctx, const char *nsname)
@@ -93,16 +56,15 @@ static char *_xml_name(xmpp_ctx_t *ctx, const char *nsname)
const char *c; const char *c;
size_t len; size_t len;
c = strchr(nsname, namespace_sep); c = strchr(nsname, NAMESPACE_SEP);
if (c == NULL) if (c == NULL) return xmpp_strdup(ctx, nsname);
return xmpp_strdup(ctx, nsname);
c++; c++;
len = strlen(c); len = strlen(c);
result = xmpp_alloc(ctx, len + 1); result = xmpp_alloc(ctx, len + 1);
if (result != NULL) { if (result != NULL) {
memcpy(result, c, len); memcpy(result, c, len);
result[len] = '\0'; result[len] = '\0';
} }
return result; return result;
@@ -114,13 +76,13 @@ static char *_xml_namespace(xmpp_ctx_t *ctx, const char *nsname)
char *result = NULL; char *result = NULL;
const char *c; const char *c;
c = strchr(nsname, namespace_sep); c = strchr(nsname, NAMESPACE_SEP);
if (c != NULL) { if (c != NULL) {
result = xmpp_alloc(ctx, (c - nsname) + 1); result = xmpp_alloc(ctx, (c-nsname) + 1);
if (result != NULL) { if (result != NULL) {
memcpy(result, nsname, (c - nsname)); memcpy(result, nsname, (c-nsname));
result[c - nsname] = '\0'; result[c-nsname] = '\0';
} }
} }
return result; return result;
@@ -131,13 +93,12 @@ static void _set_attributes(xmpp_stanza_t *stanza, const XML_Char **attrs)
char *attr; char *attr;
int i; int i;
if (!attrs) if (!attrs) return;
return;
for (i = 0; attrs[i]; i += 2) { for (i = 0; attrs[i]; i += 2) {
/* namespaced attributes aren't used in xmpp, discard namespace */ /* namespaced attributes aren't used in xmpp, discard namespace */
attr = _xml_name(stanza->ctx, attrs[i]); attr = _xml_name(stanza->ctx, attrs[i]);
xmpp_stanza_set_attribute(stanza, attr, attrs[i + 1]); xmpp_stanza_set_attribute(stanza, attr, attrs[i+1]);
xmpp_free(stanza->ctx, attr); xmpp_free(stanza->ctx, attr);
} }
} }
@@ -162,8 +123,9 @@ static void complete_inner_text(parser_t *parser)
} }
} }
static void static void _start_element(void *userdata,
_start_element(void *userdata, const XML_Char *nsname, const XML_Char **attrs) const XML_Char *nsname,
const XML_Char **attrs)
{ {
parser_t *parser = (parser_t *)userdata; parser_t *parser = (parser_t *)userdata;
xmpp_stanza_t *child; xmpp_stanza_t *child;
@@ -175,7 +137,8 @@ _start_element(void *userdata, const XML_Char *nsname, const XML_Char **attrs)
if (parser->depth == 0) { if (parser->depth == 0) {
/* notify the owner */ /* notify the owner */
if (parser->startcb) if (parser->startcb)
parser->startcb(name, (char **)attrs, parser->userdata); parser->startcb((char *)name, (char **)attrs,
parser->userdata);
} else { } else {
/* build stanzas at depth 1 */ /* build stanzas at depth 1 */
if (!parser->stanza && parser->depth != 1) { if (!parser->stanza && parser->depth != 1) {
@@ -201,10 +164,8 @@ _start_element(void *userdata, const XML_Char *nsname, const XML_Char **attrs)
} }
} }
if (ns) if (ns) xmpp_free(parser->ctx, ns);
xmpp_free(parser->ctx, ns); if (name) xmpp_free(parser->ctx, name);
if (name)
xmpp_free(parser->ctx, name);
parser->depth++; parser->depth++;
} }
@@ -226,7 +187,8 @@ static void _end_element(void *userdata, const XML_Char *name)
parser->stanza = parser->stanza->parent; parser->stanza = parser->stanza->parent;
} else { } else {
if (parser->stanzacb) if (parser->stanzacb)
parser->stanzacb(parser->stanza, parser->userdata); parser->stanzacb(parser->stanza,
parser->userdata);
xmpp_stanza_release(parser->stanza); xmpp_stanza_release(parser->stanza);
parser->stanza = NULL; parser->stanza = NULL;
} }
@@ -238,14 +200,13 @@ 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; char *p;
if (parser->depth < 2) if (parser->depth < 2) return;
return;
/* Join all parts to a single resulting string. Stanza is created in /* Join all parts to a single resulting string. Stanza is created in
* _start_element() and _end_element(). */ * _start_element() and _end_element(). */
if (parser->inner_text_used + len >= parser->inner_text_size) { if (parser->inner_text_used + len >= parser->inner_text_size) {
parser->inner_text_size = parser->inner_text_size = parser->inner_text_used + len + 1 +
parser->inner_text_used + len + 1 + INNER_TEXT_PADDING; INNER_TEXT_PADDING;
p = xmpp_realloc(parser->ctx, parser->inner_text, p = xmpp_realloc(parser->ctx, parser->inner_text,
parser->inner_text_size); parser->inner_text_size);
if (p == NULL) { if (p == NULL) {
@@ -290,33 +251,19 @@ parser_t *parser_new(xmpp_ctx_t *ctx,
return parser; return parser;
} }
char *parser_attr_name(xmpp_ctx_t *ctx, char *nsname) char* parser_attr_name(xmpp_ctx_t *ctx, char *nsname)
{ {
return _xml_name(ctx, nsname); return _xml_name(ctx, nsname);
} }
static void _free_parent_stanza(xmpp_stanza_t *stanza)
{
xmpp_stanza_t *parent;
for (parent = stanza; parent->parent != NULL; parent = parent->parent)
;
xmpp_stanza_release(parent);
}
/* free a parser */ /* free a parser */
void parser_free(parser_t *parser) void parser_free(parser_t *parser)
{ {
if (parser->expat) if (parser->expat)
XML_ParserFree(parser->expat); XML_ParserFree(parser->expat);
if (parser->stanza) {
_free_parent_stanza(parser->stanza);
parser->stanza = NULL;
}
if (parser->inner_text) { if (parser->inner_text) {
xmpp_free(parser->ctx, parser->inner_text); xmpp_free (parser->ctx, parser->inner_text);
parser->inner_text = NULL; parser->inner_text = NULL;
} }
@@ -326,37 +273,22 @@ void parser_free(parser_t *parser)
/* shuts down and restarts XML parser. true on success */ /* shuts down and restarts XML parser. true on success */
int parser_reset(parser_t *parser) int parser_reset(parser_t *parser)
{ {
XML_Bool ret; if (parser->expat)
const XML_Memory_Handling_Suite *mem = NULL; XML_ParserFree(parser->expat);
if (parser->expat) { if (parser->stanza)
ret = XML_ParserReset(parser->expat, NULL); xmpp_stanza_release(parser->stanza);
if (ret != XML_TRUE) {
XML_ParserFree(parser->expat);
parser->expat = NULL;
}
} else {
if (mem_ctx == NULL)
mem_ctx = parser->ctx;
if (parser->ctx == mem_ctx)
mem = &parser_mem_suite;
parser->expat = XML_ParserCreate_MM(NULL, mem, &namespace_sep);
}
if (parser->stanza) { parser->expat = XML_ParserCreateNS(NULL, NAMESPACE_SEP);
_free_parent_stanza(parser->stanza); if (!parser->expat) return 0;
parser->stanza = NULL;
}
if (parser->inner_text) {
xmpp_free(parser->ctx, parser->inner_text);
parser->inner_text = NULL;
}
if (!parser->expat)
return 0;
parser->depth = 0; parser->depth = 0;
parser->stanza = NULL;
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);

View File

@@ -1,7 +1,7 @@
/* parser.c /* parser.c
** strophe XMPP client library -- xml parser handlers and utility functions ** strophe XMPP client library -- xml parser handlers and utility functions
** **
** Copyright (C) 2005-2009 Collecta, Inc. ** Copyright (C) 2005-2009 Collecta, Inc.
** **
** This software is provided AS-IS with no warranty, either express ** This software is provided AS-IS with no warranty, either express
** or implied. ** or implied.
@@ -20,7 +20,7 @@
#include <libxml/parser.h> #include <libxml/parser.h>
#include <libxml/tree.h> #include <libxml/tree.h>
#include "strophe.h" #include <strophe.h>
#include "common.h" #include "common.h"
#include "parser.h" #include "parser.h"
@@ -36,56 +36,53 @@ struct _parser_t {
xmpp_stanza_t *stanza; xmpp_stanza_t *stanza;
}; };
static void static void _set_attributes(xmpp_stanza_t *stanza, int nattrs,
_set_attributes(xmpp_stanza_t *stanza, int nattrs, const xmlChar **attrs) const xmlChar **attrs)
{ {
int i, len; int i, len;
char *value; char *value;
if (!attrs) if (!attrs) return;
return;
/* SAX2 uses array of localname/prefix/uri/value_begin/value_end */ /* SAX2 uses array of localname/prefix/uri/value_begin/value_end */
for (i = 0; i < nattrs * 5; i += 5) { for (i = 0; i < nattrs*5; i += 5) {
len = attrs[i + 4] - attrs[i + 3]; len = attrs[i+4] - attrs[i+3];
value = xmpp_alloc(stanza->ctx, len + 1); value = xmpp_alloc(stanza->ctx, len + 1);
if (value) { if (value) {
memcpy(value, attrs[i + 3], len); memcpy(value, attrs[i+3], len);
value[len] = '\0'; value[len] = '\0';
xmpp_stanza_set_attribute(stanza, (const char *)attrs[i], value); xmpp_stanza_set_attribute(stanza, (const char *)attrs[i], value);
xmpp_free(stanza->ctx, value); xmpp_free(stanza->ctx, value);
} }
} }
} }
/* SAX2 gives us the attrs in an incredibly inconvenient array, /* SAX2 gives us the attrs in an incredibly inconvenient array,
* convert it to what the start callback is expecting */ * convert it to what the start callback is expecting */
static char ** static char **_convert_attrs(parser_t *parser, int nattrs,
_convert_attrs(parser_t *parser, int nattrs, const xmlChar **attrs) const xmlChar **attrs)
{ {
int c, i, o, len; int c, i, o, len;
char *value; char *value;
char **ret; char **ret;
if (!attrs) if (!attrs) return NULL;
return NULL;
ret = xmpp_alloc(parser->ctx, (nattrs + 1) * 2 * sizeof(char *)); ret = xmpp_alloc(parser->ctx, (nattrs+1)*2*sizeof(char*));
if (!ret) if (!ret) return NULL;
return NULL; memset(ret, 0, (nattrs+1)*2*sizeof(char*));
memset(ret, 0, (nattrs + 1) * 2 * sizeof(char *));
for (c = 0; c < nattrs; c++) { for (c = 0; c < nattrs; c++) {
i = c * 5; i = c * 5;
o = c * 2; o = c * 2;
len = attrs[i + 4] - attrs[i + 3]; len = attrs[i+4] - attrs[i+3];
value = xmpp_alloc(parser->ctx, len + 1); value = xmpp_alloc(parser->ctx, len + 1);
if (value) { if (value) {
memcpy(value, attrs[i + 3], len); memcpy(value, attrs[i+3], len);
value[len] = '\0'; value[len] = '\0';
ret[o] = xmpp_strdup(parser->ctx, (char *)attrs[i]); ret[o] = xmpp_strdup(parser->ctx, (char*)attrs[i]);
ret[o + 1] = value; ret[o+1] = value;
} }
} }
@@ -100,92 +97,77 @@ static void _free_cbattrs(parser_t *parser, char **attrs)
return; return;
for (i = 0; attrs[i]; i += 2) { for (i = 0; attrs[i]; i += 2) {
if (attrs[i]) if (attrs[i]) xmpp_free(parser->ctx, attrs[i]);
xmpp_free(parser->ctx, attrs[i]); if (attrs[i+1]) xmpp_free(parser->ctx, attrs[i+1]);
if (attrs[i + 1])
xmpp_free(parser->ctx, attrs[i + 1]);
} }
xmpp_free(parser->ctx, attrs); xmpp_free(parser->ctx, attrs);
} }
static void _start_element(void *userdata, static void _start_element(void *userdata,
const xmlChar *name, const xmlChar *name, const xmlChar *prefix,
const xmlChar *prefix, const xmlChar *uri, int nnamespaces,
const xmlChar *uri, const xmlChar **namespaces, int nattrs,
int nnamespaces, int ndefaulted, const xmlChar **attrs)
const xmlChar **namespaces,
int nattrs,
int ndefaulted,
const xmlChar **attrs)
{ {
parser_t *parser = (parser_t *)userdata; parser_t *parser = (parser_t *)userdata;
xmpp_stanza_t *child; xmpp_stanza_t *child;
char **cbattrs; char **cbattrs;
UNUSED(prefix);
UNUSED(nnamespaces);
UNUSED(namespaces);
UNUSED(ndefaulted);
if (parser->depth == 0) { if (parser->depth == 0) {
/* notify the owner */ /* notify the owner */
if (parser->startcb) { if (parser->startcb) {
cbattrs = _convert_attrs(parser, nattrs, attrs); cbattrs = _convert_attrs(parser, nattrs, attrs);
parser->startcb((char *)name, cbattrs, parser->userdata); parser->startcb((char *)name, cbattrs,
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) {
/* something terrible happened */ /* something terrible happened */
/* FIXME: we should probably trigger a disconnect */ /* FIXME: we should probably trigger a 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) { } else if (!parser->stanza) {
/* starting a new toplevel stanza */ /* starting a new toplevel stanza */
parser->stanza = xmpp_stanza_new(parser->ctx); parser->stanza = xmpp_stanza_new(parser->ctx);
if (!parser->stanza) { if (!parser->stanza) {
/* FIXME: can't allocate, disconnect */ /* FIXME: can't allocate, disconnect */
} }
xmpp_stanza_set_name(parser->stanza, (char *)name); xmpp_stanza_set_name(parser->stanza, (char *)name);
_set_attributes(parser->stanza, nattrs, attrs); _set_attributes(parser->stanza, nattrs, attrs);
if (uri) if (uri)
xmpp_stanza_set_ns(parser->stanza, (char *)uri); xmpp_stanza_set_ns(parser->stanza, (char *)uri);
} else { } else {
/* starting a child of conn->stanza */ /* starting a child of conn->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 */
} }
xmpp_stanza_set_name(child, (char *)name); xmpp_stanza_set_name(child, (char *)name);
_set_attributes(child, nattrs, attrs); _set_attributes(child, nattrs, attrs);
if (uri) if (uri)
xmpp_stanza_set_ns(child, (char *)uri); xmpp_stanza_set_ns(child, (char *)uri);
/* add child to parent */ /* add child to parent */
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);
/* the child is owned by the toplevel stanza now */ /* make child the current stanza */
xmpp_stanza_release(child); parser->stanza = child;
}
/* make child the current stanza */
parser->stanza = child;
}
} }
parser->depth++; parser->depth++;
} }
static void _end_element(void *userdata, static void _end_element(void *userdata, const xmlChar *name,
const xmlChar *name, const xmlChar *prefix, const xmlChar *uri)
const xmlChar *prefix,
const xmlChar *uri)
{ {
parser_t *parser = (parser_t *)userdata; parser_t *parser = (parser_t *)userdata;
UNUSED(prefix);
UNUSED(uri);
parser->depth--; parser->depth--;
if (parser->depth == 0) { if (parser->depth == 0) {
@@ -193,15 +175,16 @@ static void _end_element(void *userdata,
if (parser->endcb) if (parser->endcb)
parser->endcb((char *)name, parser->userdata); parser->endcb((char *)name, parser->userdata);
} else { } else {
if (parser->stanza->parent) { if (parser->stanza->parent) {
/* we're finishing a child stanza, so set current to the parent */ /* we're finishing a child stanza, so set current to the parent */
parser->stanza = parser->stanza->parent; parser->stanza = parser->stanza->parent;
} else { } else {
if (parser->stanzacb) if (parser->stanzacb)
parser->stanzacb(parser->stanza, parser->userdata); parser->stanzacb(parser->stanza,
parser->userdata);
xmpp_stanza_release(parser->stanza); xmpp_stanza_release(parser->stanza);
parser->stanza = NULL; parser->stanza = NULL;
} }
} }
} }
@@ -211,14 +194,13 @@ static void _characters(void *userdata, const xmlChar *chr, int len)
xmpp_stanza_t *stanza; xmpp_stanza_t *stanza;
/* skip unimportant whitespace, etc */ /* skip unimportant whitespace, etc */
if (parser->depth < 2) if (parser->depth < 2) return;
return;
/* create and populate stanza */ /* create and populate stanza */
stanza = xmpp_stanza_new(parser->ctx); stanza = xmpp_stanza_new(parser->ctx);
if (!stanza) { if (!stanza) {
/* FIXME: allocation error, disconnect */ /* FIXME: allocation error, disconnect */
return; return;
} }
xmpp_stanza_set_text_with_size(stanza, (char *)chr, len); xmpp_stanza_set_text_with_size(stanza, (char *)chr, len);
@@ -257,27 +239,16 @@ parser_t *parser_new(xmpp_ctx_t *ctx,
return parser; return parser;
} }
char *parser_attr_name(xmpp_ctx_t *ctx, char *nsname) char* parser_attr_name(xmpp_ctx_t *ctx, char *nsname)
{ {
return xmpp_strdup(ctx, nsname); return xmpp_strdup(ctx, nsname);
} }
static void _free_parent_stanza(xmpp_stanza_t *stanza)
{
xmpp_stanza_t *parent;
for (parent = stanza; parent->parent != NULL; parent = parent->parent)
;
xmpp_stanza_release(parent);
}
/* free a parser */ /* free a parser */
void parser_free(parser_t *parser) void parser_free(parser_t *parser)
{ {
if (parser->xmlctx) if (parser->xmlctx)
xmlFreeParserCtxt(parser->xmlctx); xmlFreeParserCtxt(parser->xmlctx);
if (parser->stanza)
_free_parent_stanza(parser->stanza);
xmpp_free(parser->ctx, parser); xmpp_free(parser->ctx, parser);
} }
@@ -286,16 +257,18 @@ int parser_reset(parser_t *parser)
{ {
if (parser->xmlctx) if (parser->xmlctx)
xmlFreeParserCtxt(parser->xmlctx); xmlFreeParserCtxt(parser->xmlctx);
if (parser->stanza)
_free_parent_stanza(parser->stanza);
parser->stanza = NULL; if (parser->stanza)
xmpp_stanza_release(parser->stanza);
parser->xmlctx = xmlCreatePushParserCtxt(&parser->handlers,
parser, NULL, 0, NULL);
if (!parser->xmlctx) return 0;
parser->depth = 0; parser->depth = 0;
parser->stanza = NULL;
parser->xmlctx = return 1;
xmlCreatePushParserCtxt(&parser->handlers, parser, NULL, 0, NULL);
return parser->xmlctx ? 1 : 0;
} }
/* feed a chunk of data to the parser */ /* feed a chunk of data to the parser */

View File

@@ -20,15 +20,15 @@
*/ */
#include <assert.h> #include <assert.h>
#include <string.h> /* memeset */ #include <string.h> /* memeset */
#include <time.h> /* clock, time */ #include <time.h> /* clock, time */
#include "common.h" /* xmpp_alloc, xmpp_free */ #include "common.h" /* xmpp_alloc, xmpp_free */
#include "ostypes.h" /* uint8_t, uint32_t, size_t */ #include "ostypes.h" /* uint8_t, uint32_t, size_t */
#include "sha1.h" #include "sha1.h"
#include "snprintf.h" /* xmpp_snprintf */ #include "snprintf.h" /* xmpp_snprintf */
#include "rand.h" /* xmpp_rand_t */ #include "rand.h" /* xmpp_rand_t */
#define outlen SHA1_DIGEST_SIZE #define outlen SHA1_DIGEST_SIZE
#define seedlen (440 / 8) #define seedlen (440 / 8)
@@ -55,15 +55,15 @@ struct _xmpp_rand_t {
}; };
/* returns smallest number mupliple of y that not less than x */ /* returns smallest number mupliple of y that not less than x */
#define round_up(x, y) (((x) + (y)-1) / (y) * (y)) #define round_up(x, y) (((x) + (y) - 1) / (y) * (y))
/* returns smallest integer number that not less than x/y */ /* returns smallest integer number that not less than x/y */
#define div_round_up(x, y) (((x) + (y)-1) / (y)) #define div_round_up(x, y) (((x) + (y) - 1) / (y))
/* adds two arrays as numbers in big-endian representation and stores /* adds two arrays as numbers in big-endian representation and stores
* result in the first one. * result in the first one.
*/ */
static void static void arr_add(uint8_t *arr1, size_t arr1_len,
arr_add(uint8_t *arr1, size_t arr1_len, uint8_t *arr2, size_t arr2_len) uint8_t *arr2, size_t arr2_len)
{ {
size_t i; size_t i;
uint32_t acc; uint32_t acc;
@@ -89,10 +89,8 @@ static void store_be32(uint32_t val, uint8_t be[4])
be[3] = (uint8_t)(val & 0xff); be[3] = (uint8_t)(val & 0xff);
} }
static void Hash_df(uint8_t *input_string, static void Hash_df(uint8_t *input_string, size_t input_string_len,
size_t input_string_len, uint8_t *output_string, size_t no_of_bytes_to_return)
uint8_t *output_string,
size_t no_of_bytes_to_return)
{ {
uint8_t counter; uint8_t counter;
uint8_t temp[round_up(seedlen, outlen)]; uint8_t temp[round_up(seedlen, outlen)];
@@ -121,8 +119,7 @@ static void Hash_df(uint8_t *input_string,
static void Hash_DRBG_Instantiate(Hash_DRBG_CTX *ctx, static void Hash_DRBG_Instantiate(Hash_DRBG_CTX *ctx,
uint8_t *entropy_input, uint8_t *entropy_input,
size_t entropy_input_len, size_t entropy_input_len,
uint8_t *nonce, uint8_t *nonce, size_t nonce_len)
size_t nonce_len)
{ {
uint8_t seed_material[ENTROPY_MAX + NONCE_MAX]; uint8_t seed_material[ENTROPY_MAX + NONCE_MAX];
uint8_t seed0[seedlen + 1]; uint8_t seed0[seedlen + 1];
@@ -130,11 +127,9 @@ static void Hash_DRBG_Instantiate(Hash_DRBG_CTX *ctx,
assert(entropy_input_len <= ENTROPY_MAX); assert(entropy_input_len <= ENTROPY_MAX);
assert(nonce_len <= NONCE_MAX); assert(nonce_len <= NONCE_MAX);
assert(nonce != NULL || nonce_len == 0);
memcpy(seed_material, entropy_input, entropy_input_len); memcpy(seed_material, entropy_input, entropy_input_len);
if (nonce != NULL) memcpy(seed_material + entropy_input_len, nonce, nonce_len);
memcpy(seed_material + entropy_input_len, nonce, nonce_len);
Hash_df(seed_material, entropy_input_len + nonce_len, seed, seedlen); Hash_df(seed_material, entropy_input_len + nonce_len, seed, seedlen);
seed0[0] = 0; seed0[0] = 0;
@@ -165,8 +160,8 @@ static void Hash_DRBG_Reseed(Hash_DRBG_CTX *ctx,
ctx->reseed_counter = 1; ctx->reseed_counter = 1;
} }
static void static void Hashgen(uint8_t *V, uint8_t *output,
Hashgen(uint8_t *V, uint8_t *output, size_t requested_number_of_bytes) size_t requested_number_of_bytes)
{ {
uint8_t data[seedlen]; uint8_t data[seedlen];
uint8_t W[GENERATE_MAX]; uint8_t W[GENERATE_MAX];
@@ -190,8 +185,7 @@ Hashgen(uint8_t *V, uint8_t *output, size_t requested_number_of_bytes)
} }
/* assume additional_input is zero length string */ /* assume additional_input is zero length string */
static int Hash_DRBG_Generate(Hash_DRBG_CTX *ctx, static int Hash_DRBG_Generate(Hash_DRBG_CTX *ctx, uint8_t *output,
uint8_t *output,
size_t requested_number_of_bytes) size_t requested_number_of_bytes)
{ {
uint8_t H[outlen]; uint8_t H[outlen];
@@ -215,14 +209,14 @@ static int Hash_DRBG_Generate(Hash_DRBG_CTX *ctx,
return 0; return 0;
} }
#define ENTROPY_ACCUMULATE(ptr, last, type, arg) \ #define ENTROPY_ACCUMULATE(ptr, last, type, arg) \
do { \ do { \
type __arg = (type)(arg); \ type __arg = (type)(arg); \
if ((char *)ptr + sizeof(__arg) < (char *)last) { \ if ((char*)ptr + sizeof(__arg) < (char*)last) { \
*(type *)ptr = __arg; \ *(type*)ptr = __arg; \
ptr = (void *)((char *)ptr + sizeof(__arg)); \ ptr = (void*)((char*)ptr + sizeof(__arg)); \
} \ } \
} while (0) } while (0)
static void xmpp_rand_reseed(xmpp_rand_t *rand) static void xmpp_rand_reseed(xmpp_rand_t *rand)
{ {
@@ -293,32 +287,25 @@ int xmpp_rand(xmpp_rand_t *rand)
return result; return result;
} }
static void rand_byte2hex(unsigned char byte, char *hex)
{
static const char hex_tbl[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
hex[0] = hex_tbl[(byte >> 4) & 0x0f];
hex[1] = hex_tbl[byte & 0x0f];
}
void xmpp_rand_nonce(xmpp_rand_t *rand, char *output, size_t len) void xmpp_rand_nonce(xmpp_rand_t *rand, char *output, size_t len)
{ {
size_t i; size_t i;
const size_t rand_len = len / 2; 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
* We don't want to use any allocation here, because this function * a random buffer, however base64 encoding can be used instead;
* can't fail. Also we want to avoid VLA. * the only problem is that base64_encode() allocates memory and
* Current implementation uses half of the output buffer for random buffer * as result can fail.
* generation and then converts it to HEX representation.
*/ */
if (rand_len > 0) { xmpp_rand_bytes(rand, rand_buf, rand_len);
xmpp_rand_bytes(rand, (unsigned char *)output, rand_len); for (i = 0; i < rand_len; ++i) {
for (i = rand_len; i > 0; --i) xmpp_snprintf(output + i * 2, len, "%02x", rand_buf[i]);
rand_byte2hex(output[i - 1], &output[(i - 1) * 2]); len -= 2;
} }
if (len > 0)
output[len - 1] = '\0';
} }

View File

@@ -16,8 +16,8 @@
#ifndef __LIBSTROPHE_RAND_H__ #ifndef __LIBSTROPHE_RAND_H__
#define __LIBSTROPHE_RAND_H__ #define __LIBSTROPHE_RAND_H__
#include <stddef.h> /* size_t */ #include <stddef.h> /* size_t */
#include "strophe.h" /* xmpp_ctx_t */ #include "strophe.h" /* xmpp_ctx_t */
typedef struct _xmpp_rand_t xmpp_rand_t; typedef struct _xmpp_rand_t xmpp_rand_t;
@@ -36,7 +36,7 @@ xmpp_rand_t *xmpp_rand_new(xmpp_ctx_t *ctx);
*/ */
void xmpp_rand_free(xmpp_ctx_t *ctx, xmpp_rand_t *rand); void xmpp_rand_free(xmpp_ctx_t *ctx, xmpp_rand_t *rand);
/** Generate random integer. /** Generate random integer
* Analogue of rand(3). * Analogue of rand(3).
* *
* @ingroup Random * @ingroup Random

File diff suppressed because it is too large Load Diff

View File

@@ -33,9 +33,6 @@ typedef struct resolver_srv_rr_struc {
struct resolver_srv_rr_struc *next; struct resolver_srv_rr_struc *next;
} resolver_srv_rr_t; } resolver_srv_rr_t;
void resolver_initialize(void);
void resolver_shutdown(void);
/** Perform lookup for RFC1035 message format. /** Perform lookup for RFC1035 message format.
* This function allocates all elements. * This function allocates all elements.
* *
@@ -46,10 +43,8 @@ void resolver_shutdown(void);
* *
* @return XMPP_DOMAIN_FOUND on success or XMPP_DOMAIN_NOT_FOUND on fail * @return XMPP_DOMAIN_FOUND on success or XMPP_DOMAIN_NOT_FOUND on fail
*/ */
int resolver_srv_lookup_buf(xmpp_ctx_t *ctx, int resolver_srv_lookup_buf(xmpp_ctx_t *ctx, const unsigned char *buf,
const unsigned char *buf, size_t len, resolver_srv_rr_t **srv_rr_list);
size_t len,
resolver_srv_rr_t **srv_rr_list);
/** Resolve SRV record. /** Resolve SRV record.
* *
* @param ctx a Strophe context object * @param ctx a Strophe context object
@@ -60,11 +55,8 @@ int resolver_srv_lookup_buf(xmpp_ctx_t *ctx,
* *
* @return XMPP_DOMAIN_FOUND on success or XMPP_DOMAIN_NOT_FOUND on fail * @return XMPP_DOMAIN_FOUND on success or XMPP_DOMAIN_NOT_FOUND on fail
*/ */
int resolver_srv_lookup(xmpp_ctx_t *ctx, int resolver_srv_lookup(xmpp_ctx_t *ctx, const char *service, const char *proto,
const char *service, const char *domain, resolver_srv_rr_t **srv_rr_list);
const char *proto,
const char *domain,
resolver_srv_rr_t **srv_rr_list);
/** Release a list returned by resolver_srv_lookup() or /** Release a list returned by resolver_srv_lookup() or
* resolver_srv_lookup_buf(). * resolver_srv_lookup_buf().

View File

@@ -1,7 +1,7 @@
/* sasl.c /* sasl.c
** strophe XMPP client library -- SASL authentication helpers ** strophe XMPP client library -- SASL authentication helpers
** **
** Copyright (C) 2005-2009 Collecta, Inc. ** Copyright (C) 2005-2009 Collecta, Inc.
** **
** This software is provided AS-IS with no warranty, either express ** This software is provided AS-IS with no warranty, either express
** or implied. ** or implied.
@@ -21,6 +21,7 @@
#include "ostypes.h" #include "ostypes.h"
#include "sasl.h" #include "sasl.h"
#include "md5.h" #include "md5.h"
#include "sha1.h"
#include "scram.h" #include "scram.h"
#include "rand.h" #include "rand.h"
#include "util.h" #include "util.h"
@@ -28,21 +29,21 @@
/* strtok_s() has appeared in visual studio 2005. /* strtok_s() has appeared in visual studio 2005.
Use own implementation for older versions. */ Use own implementation for older versions. */
#ifdef _MSC_VER #ifdef _MSC_VER
#if (_MSC_VER >= 1400) # if (_MSC_VER >= 1400)
#define strtok_r strtok_s # define strtok_r strtok_s
#else # else
#define strtok_r xmpp_strtok_r # define strtok_r xmpp_strtok_r
#endif # endif
#endif /* _MSC_VER */ #endif /* _MSC_VER */
/** generate authentication string for the SASL PLAIN mechanism */ /** generate authentication string for the SASL PLAIN mechanism */
char *sasl_plain(xmpp_ctx_t *ctx, const char *authid, const char *password) char *sasl_plain(xmpp_ctx_t *ctx, const char *authid, const char *password) {
{
size_t idlen, passlen; size_t idlen, passlen;
size_t msglen; size_t msglen;
char *result = NULL; char *result = NULL;
char *msg; char *msg;
/* our message is Base64(authzid,\0,authid,\0,password) /* our message is Base64(authzid,\0,authid,\0,password)
if there is no authzid, that field is left empty */ if there is no authzid, that field is left empty */
@@ -51,12 +52,12 @@ char *sasl_plain(xmpp_ctx_t *ctx, const char *authid, const char *password)
msglen = 2 + idlen + passlen; msglen = 2 + idlen + passlen;
msg = xmpp_alloc(ctx, msglen); 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 = xmpp_base64_encode(ctx, (unsigned char *)msg, msglen);
xmpp_free(ctx, msg); xmpp_free(ctx, msg);
} }
return result; return result;
@@ -65,14 +66,14 @@ char *sasl_plain(xmpp_ctx_t *ctx, const char *authid, const char *password)
/** helpers for digest auth */ /** helpers for digest auth */
/* create a new, null-terminated string from a substring */ /* create a new, null-terminated string from a substring */
static char *_make_string(xmpp_ctx_t *ctx, const char *s, unsigned len) static char *_make_string(xmpp_ctx_t *ctx, const char *s, const unsigned len)
{ {
char *result; char *result;
result = xmpp_alloc(ctx, len + 1); result = xmpp_alloc(ctx, len + 1);
if (result != NULL) { if (result != NULL) {
memcpy(result, s, len); memcpy(result, s, len);
result[len] = '\0'; result[len] = '\0';
} }
return result; return result;
} }
@@ -85,10 +86,10 @@ static char *_make_quoted(xmpp_ctx_t *ctx, const char *s)
result = xmpp_alloc(ctx, len + 3); result = xmpp_alloc(ctx, len + 3);
if (result != NULL) { if (result != NULL) {
result[0] = '"'; result[0] = '"';
memcpy(result + 1, s, len); memcpy(result+1, s, len);
result[len + 1] = '"'; result[len+1] = '"';
result[len + 2] = '\0'; result[len+2] = '\0';
} }
return result; return result;
} }
@@ -103,56 +104,51 @@ static hash_t *_parse_digest_challenge(xmpp_ctx_t *ctx, const char *msg)
text = (unsigned char *)xmpp_base64_decode_str(ctx, msg, strlen(msg)); text = (unsigned char *)xmpp_base64_decode_str(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;
} }
result = hash_new(ctx, 10, xmpp_free); result = hash_new(ctx, 10, xmpp_free);
if (result != NULL) { if (result != NULL) {
s = text; s = text;
while (*s != '\0') { while (*s != '\0') {
/* skip any leading commas and spaces */ /* skip any leading commas and spaces */
while ((*s == ',') || (*s == ' ')) while ((*s == ',') || (*s == ' ')) s++;
s++; /* accumulate a key ending at '=' */
/* accumulate a key ending at '=' */ t = s;
t = s; while ((*t != '=') && (*t != '\0')) t++;
while ((*t != '=') && (*t != '\0')) if (*t == '\0') break; /* bad string */
t++; key = _make_string(ctx, (char *)s, (t-s));
if (*t == '\0') if (key == NULL) break;
break; /* bad string */
key = _make_string(ctx, (char *)s, (t - s));
if (key == NULL)
break;
/* advance our start pointer past the key */ /* advance our start pointer past the key */
s = t + 1; s = t + 1;
t = s; t = s;
/* if we see quotes, grab the string in between */ /* if we see quotes, grab the string in between */
if ((*s == '\'') || (*s == '"')) { if ((*s == '\'') || (*s == '"')) {
t++; t++;
while ((*t != *s) && (*t != '\0')) while ((*t != *s) && (*t != '\0'))
t++; t++;
value = _make_string(ctx, (char *)s + 1, (t - s - 1)); value = _make_string(ctx, (char *)s+1, (t-s-1));
if (*t == *s) { if (*t == *s) {
s = t + 1; s = t + 1;
} else { } else {
s = t; s = t;
} }
/* otherwise, accumulate a value ending in ',' or '\0' */ /* otherwise, accumulate a value ending in ',' or '\0' */
} else { } else {
while ((*t != ',') && (*t != '\0')) while ((*t != ',') && (*t != '\0')) t++;
t++; value = _make_string(ctx, (char *)s, (t-s));
value = _make_string(ctx, (char *)s, (t - s)); s = t;
s = t; }
} if (value == NULL) {
if (value == NULL) { xmpp_free(ctx, key);
xmpp_free(ctx, key); break;
break; }
} /* TODO: check for collisions per spec */
/* TODO: check for collisions per spec */ hash_add(result, key, value);
hash_add(result, key, value); /* hash table now owns the value, free the key */
/* hash table now owns the value, free the key */ xmpp_free(ctx, key);
xmpp_free(ctx, key); }
}
} }
xmpp_free(ctx, text); xmpp_free(ctx, text);
@@ -166,97 +162,90 @@ static void _digest_to_hex(const char *digest, char *hex)
const char hexdigit[] = "0123456789abcdef"; const char hexdigit[] = "0123456789abcdef";
for (i = 0; i < 16; i++) { for (i = 0; i < 16; i++) {
*hex++ = hexdigit[(digest[i] >> 4) & 0x0F]; *hex++ = hexdigit[ (digest[i] >> 4) & 0x0F ];
*hex++ = hexdigit[digest[i] & 0x0F]; *hex++ = hexdigit[ digest[i] & 0x0F ];
} }
} }
/** append 'key="value"' to a buffer, growing as necessary */ /** append 'key="value"' to a buffer, growing as necessary */
static char * static char *_add_key(xmpp_ctx_t *ctx, hash_t *table, const char *key,
_add_key(xmpp_ctx_t *ctx, hash_t *table, const char *key, char *buf, int quote) char *buf, int *len, int quote)
{ {
int olen, nlen; int olen,nlen;
int keylen, valuelen; int keylen, valuelen;
const char *value, *qvalue; const char *value, *qvalue;
char *c; char *c;
/* allocate a zero-length string if necessary */ /* allocate a zero-length string if necessary */
if (buf == NULL) { if (buf == NULL) {
buf = xmpp_alloc(ctx, 1); buf = xmpp_alloc(ctx, 1);
buf[0] = '\0'; buf[0] = '\0';
} }
if (buf == NULL) if (buf == NULL) return NULL;
return NULL;
/* get current string length */ /* get current string length */
olen = strlen(buf); olen = strlen(buf);
value = hash_get(table, key); value = hash_get(table, key);
if (value == NULL) { if (value == NULL) {
xmpp_error(ctx, "SASL", "couldn't retrieve value for '%s'", key); xmpp_error(ctx, "SASL", "couldn't retrieve value for '%s'", key);
value = ""; value = "";
} }
if (quote) { if (quote) {
qvalue = _make_quoted(ctx, value); qvalue = _make_quoted(ctx, value);
} else { } else {
qvalue = value; qvalue = value;
} }
/* added length is key + '=' + value */ /* added length is key + '=' + value */
/* (+ ',' if we're not the first entry */ /* (+ ',' if we're not the first entry */
keylen = strlen(key); keylen = strlen(key);
valuelen = strlen(qvalue); valuelen = strlen(qvalue);
nlen = (olen ? 1 : 0) + keylen + 1 + valuelen + 1; nlen = (olen ? 1 : 0) + keylen + 1 + valuelen + 1;
buf = xmpp_realloc(ctx, buf, olen + nlen); buf = xmpp_realloc(ctx, buf, olen+nlen);
if (buf != NULL) { if (buf != NULL) {
c = buf + olen; c = buf + olen;
if (olen) if (olen) *c++ = ',';
*c++ = ','; memcpy(c, key, keylen); c += keylen;
memcpy(c, key, keylen); *c++ = '=';
c += keylen; memcpy(c, qvalue, valuelen); c += valuelen;
*c++ = '='; *c++ = '\0';
memcpy(c, qvalue, valuelen);
c += valuelen;
*c++ = '\0';
} }
if (quote) if (quote) xmpp_free(ctx, (char *)qvalue);
xmpp_free(ctx, (char *)qvalue);
return buf; return buf;
} }
/** generate auth response string for the SASL DIGEST-MD5 mechanism */ /** generate auth response string for the SASL DIGEST-MD5 mechanism */
char *sasl_digest_md5(xmpp_ctx_t *ctx, char *sasl_digest_md5(xmpp_ctx_t *ctx, const char *challenge,
const char *challenge, const char *jid, const char *password) {
const char *jid,
const char *password)
{
hash_t *table; hash_t *table;
char *result = NULL; char *result = NULL;
char *node, *domain, *realm; char *node, *domain, *realm;
char *value; char *value;
char *response; char *response;
int rlen;
struct MD5Context MD5; struct MD5Context MD5;
unsigned char digest[16], HA1[16], HA2[16]; unsigned char digest[16], HA1[16], HA2[16];
char hex[32]; char hex[32];
char cnonce[13]; char cnonce[13];
/* our digest response is /* our digest response is
Hex( KD( HEX(MD5(A1)), Hex( KD( HEX(MD5(A1)),
nonce ':' nc ':' cnonce ':' qop ':' HEX(MD5(A2)) nonce ':' nc ':' cnonce ':' qop ':' HEX(MD5(A2))
)) ))
where KD(k, s) = MD5(k ':' s), where KD(k, s) = MD5(k ':' s),
A1 = MD5( node ':' realm ':' password ) ':' nonce ':' cnonce A1 = MD5( node ':' realm ':' password ) ':' nonce ':' cnonce
A2 = "AUTHENTICATE" ':' "xmpp/" domain A2 = "AUTHENTICATE" ':' "xmpp/" domain
If there is an authzid it is ':'-appended to A1 */ If there is an authzid it is ':'-appended to A1 */
/* parse the challenge */ /* parse the challenge */
table = _parse_digest_challenge(ctx, challenge); table = _parse_digest_challenge(ctx, challenge);
if (table == NULL) { if (table == NULL) {
xmpp_error(ctx, "SASL", "couldn't parse digest challenge"); xmpp_error(ctx, "SASL", "couldn't parse digest challenge");
return NULL; return NULL;
} }
node = xmpp_jid_node(ctx, jid); node = xmpp_jid_node(ctx, jid);
@@ -266,8 +255,8 @@ char *sasl_digest_md5(xmpp_ctx_t *ctx,
server */ server */
realm = hash_get(table, "realm"); realm = hash_get(table, "realm");
if (realm == NULL || strlen(realm) == 0) { if (realm == NULL || strlen(realm) == 0) {
hash_add(table, "realm", xmpp_strdup(ctx, domain)); hash_add(table, "realm", xmpp_strdup(ctx, domain));
realm = hash_get(table, "realm"); realm = hash_get(table, "realm");
} }
/* add our response fields */ /* add our response fields */
@@ -275,14 +264,13 @@ char *sasl_digest_md5(xmpp_ctx_t *ctx,
xmpp_rand_nonce(ctx->rand, cnonce, sizeof(cnonce)); xmpp_rand_nonce(ctx->rand, cnonce, sizeof(cnonce));
hash_add(table, "cnonce", xmpp_strdup(ctx, cnonce)); hash_add(table, "cnonce", xmpp_strdup(ctx, cnonce));
hash_add(table, "nc", xmpp_strdup(ctx, "00000001")); hash_add(table, "nc", xmpp_strdup(ctx, "00000001"));
if (hash_get(table, "qop") == NULL) hash_add(table, "qop", xmpp_strdup(ctx, "auth"));
hash_add(table, "qop", xmpp_strdup(ctx, "auth"));
value = xmpp_alloc(ctx, 5 + strlen(domain) + 1); value = xmpp_alloc(ctx, 5 + strlen(domain) + 1);
memcpy(value, "xmpp/", 5); memcpy(value, "xmpp/", 5);
memcpy(value + 5, domain, strlen(domain)); memcpy(value+5, domain, strlen(domain));
value[5 + strlen(domain)] = '\0'; value[5+strlen(domain)] = '\0';
hash_add(table, "digest-uri", value); hash_add(table, "digest-uri", value);
/* generate response */ /* generate response */
/* construct MD5(node : realm : password) */ /* construct MD5(node : realm : password) */
@@ -315,8 +303,8 @@ char *sasl_digest_md5(xmpp_ctx_t *ctx,
value = hash_get(table, "digest-uri"); value = hash_get(table, "digest-uri");
MD5Update(&MD5, (unsigned char *)value, strlen(value)); MD5Update(&MD5, (unsigned char *)value, strlen(value));
if (strcmp(hash_get(table, "qop"), "auth") != 0) { if (strcmp(hash_get(table, "qop"), "auth") != 0) {
MD5Update(&MD5, (unsigned char *)":00000000000000000000000000000000", MD5Update(&MD5, (unsigned char *)":00000000000000000000000000000000",
33); 33);
} }
MD5Final(digest, &MD5); MD5Final(digest, &MD5);
@@ -343,7 +331,7 @@ char *sasl_digest_md5(xmpp_ctx_t *ctx,
MD5Update(&MD5, (unsigned char *)hex, 32); MD5Update(&MD5, (unsigned char *)hex, 32);
MD5Final(digest, &MD5); MD5Final(digest, &MD5);
response = xmpp_alloc(ctx, 32 + 1); response = xmpp_alloc(ctx, 32+1);
_digest_to_hex((char *)digest, hex); _digest_to_hex((char *)digest, hex);
memcpy(response, hex, 32); memcpy(response, hex, 32);
response[32] = '\0'; response[32] = '\0';
@@ -351,16 +339,17 @@ char *sasl_digest_md5(xmpp_ctx_t *ctx,
/* construct reply */ /* construct reply */
result = NULL; result = NULL;
result = _add_key(ctx, table, "username", result, 1); rlen = 0;
result = _add_key(ctx, table, "realm", result, 1); result = _add_key(ctx, table, "username", result, &rlen, 1);
result = _add_key(ctx, table, "nonce", result, 1); result = _add_key(ctx, table, "realm", result, &rlen, 1);
result = _add_key(ctx, table, "cnonce", result, 1); result = _add_key(ctx, table, "nonce", result, &rlen, 1);
result = _add_key(ctx, table, "nc", result, 0); result = _add_key(ctx, table, "cnonce", result, &rlen, 1);
result = _add_key(ctx, table, "qop", result, 0); result = _add_key(ctx, table, "nc", result, &rlen, 0);
result = _add_key(ctx, table, "digest-uri", result, 1); result = _add_key(ctx, table, "qop", result, &rlen, 0);
result = _add_key(ctx, table, "response", result, 0); result = _add_key(ctx, table, "digest-uri", result, &rlen, 1);
result = _add_key(ctx, table, "charset", result, 0); result = _add_key(ctx, table, "response", result, &rlen, 0);
result = _add_key(ctx, table, "charset", result, &rlen, 0);
xmpp_free(ctx, node); xmpp_free(ctx, node);
xmpp_free(ctx, domain); xmpp_free(ctx, domain);
hash_release(table); /* also frees value strings */ hash_release(table); /* also frees value strings */
@@ -372,16 +361,13 @@ char *sasl_digest_md5(xmpp_ctx_t *ctx,
return response; return response;
} }
/** generate auth response string for the SASL SCRAM mechanism */ /** generate auth response string for the SASL SCRAM-SHA-1 mechanism */
char *sasl_scram(xmpp_ctx_t *ctx, char *sasl_scram_sha1(xmpp_ctx_t *ctx, const char *challenge,
const struct hash_alg *alg, const char *first_bare, const char *jid,
const char *challenge, const char *password)
const char *first_bare,
const char *jid,
const char *password)
{ {
uint8_t key[SCRAM_DIGEST_SIZE]; uint8_t key[SHA1_DIGEST_SIZE];
uint8_t sign[SCRAM_DIGEST_SIZE]; uint8_t sign[SHA1_DIGEST_SIZE];
char *r = NULL; char *r = NULL;
char *s = NULL; char *s = NULL;
char *i = NULL; char *i = NULL;
@@ -398,8 +384,7 @@ char *sasl_scram(xmpp_ctx_t *ctx,
char *result = NULL; char *result = NULL;
size_t response_len; size_t response_len;
size_t auth_len; size_t auth_len;
int j;
UNUSED(jid);
tmp = xmpp_strdup(ctx, challenge); tmp = xmpp_strdup(ctx, challenge);
if (!tmp) { if (!tmp) {
@@ -434,8 +419,7 @@ char *sasl_scram(xmpp_ctx_t *ctx,
goto out_sval; goto out_sval;
} }
/* "c=biws," + r + ",p=" + sign_b64 + '\0' */ response_len = 39 + strlen(r);
response_len = 7 + strlen(r) + 3 + ((alg->digest_size + 2) / 3 * 4) + 1;
response = xmpp_alloc(ctx, response_len); response = xmpp_alloc(ctx, response_len);
if (!response) { if (!response) {
goto out_auth; goto out_auth;
@@ -445,17 +429,18 @@ char *sasl_scram(xmpp_ctx_t *ctx,
xmpp_snprintf(auth, auth_len, "%s,%s,%s", first_bare + 3, challenge, xmpp_snprintf(auth, auth_len, "%s,%s,%s", first_bare + 3, challenge,
response); response);
SCRAM_ClientKey(alg, (uint8_t *)password, strlen(password), (uint8_t *)sval, SCRAM_SHA1_ClientKey((uint8_t *)password, strlen(password),
sval_len, (uint32_t)ival, key); (uint8_t *)sval, sval_len, (uint32_t)ival, key);
SCRAM_ClientSignature(alg, key, (uint8_t *)auth, strlen(auth), sign); SCRAM_SHA1_ClientSignature(key, (uint8_t *)auth, strlen(auth), sign);
SCRAM_ClientProof(alg, sign, key, sign); for (j = 0; j < SHA1_DIGEST_SIZE; j++) {
sign[j] ^= key[j];
}
sign_b64 = xmpp_base64_encode(ctx, sign, alg->digest_size); sign_b64 = xmpp_base64_encode(ctx, sign, sizeof(sign));
if (!sign_b64) { if (!sign_b64) {
goto out_response; goto out_response;
} }
/* Check for buffer overflow */
if (strlen(response) + strlen(sign_b64) + 3 + 1 > response_len) { if (strlen(response) + strlen(sign_b64) + 3 + 1 > response_len) {
xmpp_free(ctx, sign_b64); xmpp_free(ctx, sign_b64);
goto out_response; goto out_response;
@@ -464,8 +449,8 @@ char *sasl_scram(xmpp_ctx_t *ctx,
strcat(response, sign_b64); strcat(response, sign_b64);
xmpp_free(ctx, sign_b64); xmpp_free(ctx, sign_b64);
response_b64 = response_b64 = xmpp_base64_encode(ctx, (unsigned char *)response,
xmpp_base64_encode(ctx, (unsigned char *)response, strlen(response)); strlen(response));
if (!response_b64) { if (!response_b64) {
goto out_response; goto out_response;
} }

View File

@@ -1,7 +1,7 @@
/* sasl.h /* sasl.h
** strophe XMPP client library -- SASL authentication helpers ** strophe XMPP client library -- SASL authentication helpers
** **
** Copyright (C) 2005-2009 Collecta, Inc. ** Copyright (C) 2005-2009 Collecta, Inc.
** **
** This software is provided AS-IS with no warranty, either express ** This software is provided AS-IS with no warranty, either express
** or implied. ** or implied.
@@ -17,20 +17,14 @@
#define __LIBSTROPHE_SASL_H__ #define __LIBSTROPHE_SASL_H__
#include "strophe.h" #include "strophe.h"
#include "scram.h"
/** low-level sasl routines */ /** low-level sasl routines */
char *sasl_plain(xmpp_ctx_t *ctx, const char *authid, const char *password); char *sasl_plain(xmpp_ctx_t *ctx, const char *authid, const char *password);
char *sasl_digest_md5(xmpp_ctx_t *ctx, char *sasl_digest_md5(xmpp_ctx_t *ctx, const char *challenge,
const char *challenge, const char *jid, const char *password);
const char *jid, char *sasl_scram_sha1(xmpp_ctx_t *ctx, const char *challenge,
const char *first_bare, const char *jid,
const char *password); const char *password);
char *sasl_scram(xmpp_ctx_t *ctx,
const struct hash_alg *alg,
const char *challenge,
const char *first_bare,
const char *jid,
const char *password);
#endif /* _LIBXMPP_SASL_H__ */ #endif /* _LIBXMPP_SASL_H__ */

View File

@@ -19,103 +19,56 @@
#include <assert.h> #include <assert.h>
#include <string.h> #include <string.h>
#include "common.h"
#include "sha1.h" #include "sha1.h"
#include "sha256.h"
#include "sha512.h"
#include "ostypes.h" #include "ostypes.h"
#include "scram.h" #include "scram.h"
#define HMAC_BLOCK_SIZE_MAX 128 #define HMAC_BLOCK_SIZE 64
static const uint8_t ipad = 0x36; static const uint8_t ipad = 0x36;
static const uint8_t opad = 0x5C; static const uint8_t opad = 0x5C;
const struct hash_alg scram_sha1 = { static void crypto_HMAC_SHA1(const uint8_t *key, size_t key_len,
"SCRAM-SHA-1", const uint8_t *text, size_t len,
SASL_MASK_SCRAMSHA1, uint8_t *digest)
SHA1_DIGEST_SIZE,
(void (*)(const uint8_t *, size_t, uint8_t *))crypto_SHA1,
(void (*)(void *))crypto_SHA1_Init,
(void (*)(void *, const uint8_t *, size_t))crypto_SHA1_Update,
(void (*)(void *, uint8_t *))crypto_SHA1_Final};
const struct hash_alg scram_sha256 = {
"SCRAM-SHA-256",
SASL_MASK_SCRAMSHA256,
SHA256_DIGEST_SIZE,
(void (*)(const uint8_t *, size_t, uint8_t *))sha256_hash,
(void (*)(void *))sha256_init,
(void (*)(void *, const uint8_t *, size_t))sha256_process,
(void (*)(void *, uint8_t *))sha256_done};
const struct hash_alg scram_sha512 = {
"SCRAM-SHA-512",
SASL_MASK_SCRAMSHA512,
SHA512_DIGEST_SIZE,
(void (*)(const uint8_t *, size_t, uint8_t *))sha512_hash,
(void (*)(void *))sha512_init,
(void (*)(void *, const uint8_t *, size_t))sha512_process,
(void (*)(void *, uint8_t *))sha512_done};
union common_hash_ctx {
SHA1_CTX sha1;
sha256_context sha256;
sha512_context sha512;
};
static void crypto_HMAC(const struct hash_alg *alg,
const uint8_t *key,
size_t key_len,
const uint8_t *text,
size_t len,
uint8_t *digest)
{ {
uint8_t key_pad[HMAC_BLOCK_SIZE_MAX]; uint8_t key_pad[HMAC_BLOCK_SIZE];
uint8_t key_ipad[HMAC_BLOCK_SIZE_MAX]; uint8_t key_ipad[HMAC_BLOCK_SIZE];
uint8_t key_opad[HMAC_BLOCK_SIZE_MAX]; uint8_t key_opad[HMAC_BLOCK_SIZE];
uint8_t sha_digest[SCRAM_DIGEST_SIZE]; uint8_t sha_digest[SHA1_DIGEST_SIZE];
size_t blocksize; int i;
size_t i; SHA1_CTX ctx;
union common_hash_ctx ctx;
assert(alg->digest_size <= HMAC_BLOCK_SIZE_MAX); memset(key_pad, 0, sizeof(key_pad));
blocksize = alg->digest_size < 48 ? 64 : 128; if (key_len <= HMAC_BLOCK_SIZE) {
memset(key_pad, 0, blocksize);
if (key_len <= blocksize) {
memcpy(key_pad, key, key_len); memcpy(key_pad, key, key_len);
} else { } else {
/* according to RFC2104 */ /* according to RFC2104 */
alg->hash(key, key_len, key_pad); crypto_SHA1(key, key_len, key_pad);
} }
for (i = 0; i < blocksize; i++) { for (i = 0; i < HMAC_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;
} }
alg->init((void *)&ctx); crypto_SHA1_Init(&ctx);
alg->update((void *)&ctx, key_ipad, blocksize); crypto_SHA1_Update(&ctx, key_ipad, HMAC_BLOCK_SIZE);
alg->update((void *)&ctx, text, len); crypto_SHA1_Update(&ctx, text, len);
alg->final((void *)&ctx, sha_digest); crypto_SHA1_Final(&ctx, sha_digest);
alg->init((void *)&ctx); crypto_SHA1_Init(&ctx);
alg->update((void *)&ctx, key_opad, blocksize); crypto_SHA1_Update(&ctx, key_opad, HMAC_BLOCK_SIZE);
alg->update((void *)&ctx, sha_digest, alg->digest_size); crypto_SHA1_Update(&ctx, sha_digest, SHA1_DIGEST_SIZE);
alg->final((void *)&ctx, digest); crypto_SHA1_Final(&ctx, digest);
} }
static void SCRAM_Hi(const struct hash_alg *alg, static void SCRAM_SHA1_Hi(const uint8_t *text, size_t len,
const uint8_t *text, const uint8_t *salt, size_t salt_len, uint32_t i,
size_t len, uint8_t *digest)
const uint8_t *salt,
size_t salt_len,
uint32_t i,
uint8_t *digest)
{ {
size_t k; int k;
uint32_t j; uint32_t j;
uint8_t tmp[128]; uint8_t tmp[128];
@@ -124,7 +77,7 @@ static void SCRAM_Hi(const struct hash_alg *alg,
/* assume salt + INT(1) isn't longer than sizeof(tmp) */ /* assume salt + INT(1) isn't longer than sizeof(tmp) */
assert(salt_len <= sizeof(tmp) - sizeof(int1)); assert(salt_len <= sizeof(tmp) - sizeof(int1));
memset(digest, 0, alg->digest_size); memset(digest, 0, SHA1_DIGEST_SIZE);
if (i == 0) { if (i == 0) {
return; return;
} }
@@ -133,53 +86,46 @@ static void SCRAM_Hi(const struct hash_alg *alg,
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(alg, text, len, tmp, salt_len + sizeof(int1), digest); crypto_HMAC_SHA1(text, len, tmp, salt_len + sizeof(int1), digest);
memcpy(tmp, digest, alg->digest_size); memcpy(tmp, digest, SHA1_DIGEST_SIZE);
for (j = 1; j < i; j++) { for (j = 1; j < i; j++) {
crypto_HMAC(alg, text, len, tmp, alg->digest_size, tmp); crypto_HMAC_SHA1(text, len, tmp, SHA1_DIGEST_SIZE, tmp);
for (k = 0; k < alg->digest_size; k++) { for (k = 0; k < SHA1_DIGEST_SIZE; k++) {
digest[k] ^= tmp[k]; digest[k] ^= tmp[k];
} }
} }
} }
void SCRAM_ClientKey(const struct hash_alg *alg, void SCRAM_SHA1_ClientKey(const uint8_t *password, size_t len,
const uint8_t *password, const uint8_t *salt, size_t salt_len, uint32_t i,
size_t len, uint8_t *key)
const uint8_t *salt,
size_t salt_len,
uint32_t i,
uint8_t *key)
{ {
uint8_t salted[SCRAM_DIGEST_SIZE]; uint8_t salted[SHA1_DIGEST_SIZE];
/* XXX: Normalize(password) is omitted */ /* XXX: Normalize(password) is omitted */
SCRAM_Hi(alg, password, len, salt, salt_len, i, salted); SCRAM_SHA1_Hi(password, len, salt, salt_len, i, salted);
crypto_HMAC(alg, salted, alg->digest_size, (uint8_t *)"Client Key", crypto_HMAC_SHA1(salted, SHA1_DIGEST_SIZE, (uint8_t *)"Client Key",
strlen("Client Key"), key); strlen("Client Key"), key);
} }
void SCRAM_ClientSignature(const struct hash_alg *alg, void SCRAM_SHA1_ClientSignature(const uint8_t *ClientKey,
const uint8_t *ClientKey, const uint8_t *AuthMessage, size_t len,
const uint8_t *AuthMessage, uint8_t *sign)
size_t len,
uint8_t *sign)
{ {
uint8_t stored[SCRAM_DIGEST_SIZE]; uint8_t stored[SHA1_DIGEST_SIZE];
alg->hash(ClientKey, alg->digest_size, stored); crypto_SHA1(ClientKey, SHA1_DIGEST_SIZE, stored);
crypto_HMAC(alg, stored, alg->digest_size, AuthMessage, len, sign); crypto_HMAC_SHA1(stored, SHA1_DIGEST_SIZE, AuthMessage, len, sign);
} }
void SCRAM_ClientProof(const struct hash_alg *alg, void SCRAM_SHA1_ClientProof(const uint8_t *ClientKey,
const uint8_t *ClientKey, const uint8_t *ClientSignature,
const uint8_t *ClientSignature, uint8_t *proof)
uint8_t *proof)
{ {
size_t i; int i;
for (i = 0; i < alg->digest_size; i++) { for (i = 0; i < SHA1_DIGEST_SIZE; i++) {
proof[i] = ClientKey[i] ^ ClientSignature[i]; proof[i] = ClientKey[i] ^ ClientSignature[i];
} }
} }

View File

@@ -1,5 +1,5 @@
/* scram.h /* scram.h
* strophe XMPP client library -- SCRAM helper functions * strophe XMPP client library -- SCRAM-SHA1 helper functions
* *
* Copyright (C) 2013 Dmitry Podgorny <pasis.ua@gmail.com> * Copyright (C) 2013 Dmitry Podgorny <pasis.ua@gmail.com>
* *
@@ -10,7 +10,7 @@
*/ */
/** @file /** @file
* SCRAM helper functions. * SCRAM-SHA1 helper functions.
*/ */
#ifndef __LIBSTROPHE_SCRAM_H__ #ifndef __LIBSTROPHE_SCRAM_H__
@@ -19,41 +19,18 @@
/* make sure the stdint.h types are available */ /* make sure the stdint.h types are available */
#include "ostypes.h" #include "ostypes.h"
/* Maximum possible digest size. Used for buffers allocation. */ #include "sha1.h"
#include "sha512.h"
#define SCRAM_DIGEST_SIZE SHA512_DIGEST_SIZE
struct hash_alg { void SCRAM_SHA1_ClientKey(const uint8_t *password, size_t len,
const char *scram_name; const uint8_t *salt, size_t salt_len, uint32_t i,
int mask; uint8_t *key);
size_t digest_size;
void (*hash)(const uint8_t *, size_t, uint8_t *);
void (*init)(void *);
void (*update)(void *, const uint8_t *, size_t);
void (*final)(void *, uint8_t *);
};
extern const struct hash_alg scram_sha1; void SCRAM_SHA1_ClientSignature(const uint8_t *ClientKey,
extern const struct hash_alg scram_sha256; const uint8_t *AuthMessage, size_t len,
extern const struct hash_alg scram_sha512; uint8_t *sign);
void SCRAM_ClientKey(const struct hash_alg *alg, void SCRAM_SHA1_ClientProof(const uint8_t *ClientKey,
const uint8_t *password, const uint8_t *ClientSignature,
size_t len, uint8_t *proof);
const uint8_t *salt,
size_t salt_len,
uint32_t i,
uint8_t *key);
void SCRAM_ClientSignature(const struct hash_alg *alg,
const uint8_t *ClientKey,
const uint8_t *AuthMessage,
size_t len,
uint8_t *sign);
void SCRAM_ClientProof(const struct hash_alg *alg,
const uint8_t *ClientKey,
const uint8_t *ClientSignature,
uint8_t *proof);
#endif /* __LIBSTROPHE_SCRAM_H__ */ #endif /* __LIBSTROPHE_SCRAM_H__ */

162
src/server.c Normal file
View File

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

112
src/sha.h
View File

@@ -1,112 +0,0 @@
/* public api for steve reid's public domain SHA-1 implementation */
/* this file is in the public domain */
/** @file
* SHA-1 hash API.
*/
#ifndef __LIBSTROPHE_SHA_H__
#define __LIBSTROPHE_SHA_H__
#include <string.h>
#ifdef __cplusplus
extern "C" {
#endif
/* make sure the stdint.h types are available */
#include "ostypes.h"
#if defined(__BIG_ENDIAN__) || \
(defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && \
__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
#define STORE32H(x, y) \
do { \
uint32_t __t = (x); \
memcpy(y, &__t, 4); \
} while (0)
#define LOAD32H(x, y) \
do { \
memcpy(&(x), y, 4); \
x &= 0xFFFFFFFF; \
} while (0)
#define STORE64H(x, y) \
do { \
uint64_t __t = (x); \
memcpy(y, &__t, 8); \
} while (0)
#define LOAD64H(x, y) \
do { \
memcpy(&(x), y, 8); \
} while (0)
#elif defined(__LITTLE_ENDIAN__) || \
(defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \
__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
#define STORE32H(x, y) \
do { \
(y)[0] = (uint8_t)(((x) >> 24) & 255); \
(y)[1] = (uint8_t)(((x) >> 16) & 255); \
(y)[2] = (uint8_t)(((x) >> 8) & 255); \
(y)[3] = (uint8_t)((x)&255); \
} while (0)
#define LOAD32H(x, y) \
do { \
x = ((uint32_t)((y)[0] & 255) << 24) | \
((uint32_t)((y)[1] & 255) << 16) | \
((uint32_t)((y)[2] & 255) << 8) | ((uint32_t)((y)[3] & 255)); \
} while (0)
#define STORE64H(x, y) \
do { \
(y)[0] = (uint8_t)(((x) >> 56) & 255); \
(y)[1] = (uint8_t)(((x) >> 48) & 255); \
(y)[2] = (uint8_t)(((x) >> 40) & 255); \
(y)[3] = (uint8_t)(((x) >> 32) & 255); \
(y)[4] = (uint8_t)(((x) >> 24) & 255); \
(y)[5] = (uint8_t)(((x) >> 16) & 255); \
(y)[6] = (uint8_t)(((x) >> 8) & 255); \
(y)[7] = (uint8_t)((x)&255); \
} while (0)
#define LOAD64H(x, y) \
do { \
x = (((uint64_t)((y)[0] & 255)) << 56) | \
(((uint64_t)((y)[1] & 255)) << 48) | \
(((uint64_t)((y)[2] & 255)) << 40) | \
(((uint64_t)((y)[3] & 255)) << 32) | \
(((uint64_t)((y)[4] & 255)) << 24) | \
(((uint64_t)((y)[5] & 255)) << 16) | \
(((uint64_t)((y)[6] & 255)) << 8) | (((uint64_t)((y)[7] & 255))); \
} while (0)
#else
#error Unknown endianness not supported
#endif
#ifdef _MSC_VER
#define CONST64(n) n##ui64
#else
#define CONST64(n) n##ULL
#endif
#define RORc(x, y) \
(((((uint32_t)(x)&0xFFFFFFFFUL) >> (uint32_t)((y)&31)) | \
((uint32_t)(x) << (uint32_t)((32 - ((y)&31)) & 31))) & \
0xFFFFFFFFUL)
#define ROR64c(x, y) \
(((((x)&CONST64(0xFFFFFFFFFFFFFFFF)) >> ((uint64_t)(y)&CONST64(63))) | \
((x) << (((uint64_t)64 - ((y)&63)) & 63))) & \
CONST64(0xFFFFFFFFFFFFFFFF))
#ifdef __cplusplus
}
#endif
#endif /* __LIBSTROPHE_SHA_H__ */

View File

@@ -8,16 +8,16 @@ By Steve Reid <sreid@sea-to-sky.net>
100% Public Domain 100% Public Domain
----------------- -----------------
Modified 7/98 Modified 7/98
By James H. Brown <jbrown@burgoyne.com> By James H. Brown <jbrown@burgoyne.com>
Still 100% Public Domain Still 100% Public Domain
Corrected a problem which generated improper hash values on 16 bit machines Corrected a problem which generated improper hash values on 16 bit machines
Routine SHA1Update changed from Routine SHA1Update changed from
void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int
len) len)
to to
void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned
long len) long len)
The 'len' parameter was declared an int which works fine on 32 bit machines. The 'len' parameter was declared an int which works fine on 32 bit machines.
@@ -30,7 +30,7 @@ Since the file IO in main() reads 16K at a time, any file 8K or larger would
be guaranteed to generate the wrong hash (e.g. Test Vector #3, a million be guaranteed to generate the wrong hash (e.g. Test Vector #3, a million
"a"s). "a"s).
I also changed the declaration of variables i & j in SHA1Update to I also changed the declaration of variables i & j in SHA1Update to
unsigned long from unsigned int for the same reason. unsigned long from unsigned int for the same reason.
These changes should make no difference to any 32 bit implementations since These changes should make no difference to any 32 bit implementations since
@@ -57,7 +57,7 @@ Still 100% public domain
Modified 4/01 Modified 4/01
By Saul Kravitz <Saul.Kravitz@celera.com> By Saul Kravitz <Saul.Kravitz@celera.com>
Still 100% PD Still 100% PD
Modified to run on Compaq Alpha hardware. Modified to run on Compaq Alpha hardware.
----------------- -----------------
Modified 07/2002 Modified 07/2002
@@ -75,6 +75,9 @@ move public api to sha1.h
#include "ostypes.h" #include "ostypes.h"
#include "sha1.h" #include "sha1.h"
/* Don't change user's data */
#define SHA1HANDSOFF
static uint32_t host_to_be(uint32_t i); static uint32_t host_to_be(uint32_t i);
static void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64]); static void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64]);
@@ -83,38 +86,27 @@ static void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64]);
/* blk0() and blk() perform the initial expand. */ /* blk0() and blk() perform the initial expand. */
/* I got the idea of expanding during the round function from SSLeay */ /* I got the idea of expanding during the round function from SSLeay */
#define blk0(i) (block->l[i] = host_to_be(block->l[i])) #define blk0(i) (block->l[i] = host_to_be(block->l[i]))
#define blk(i) \ #define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
(block->l[i & 15] = rol(block->l[(i + 13) & 15] ^ block->l[(i + 8) & 15] ^ \ ^block->l[(i+2)&15]^block->l[i&15],1))
block->l[(i + 2) & 15] ^ block->l[i & 15], \
1))
/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ /* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
#define R0(v, w, x, y, z, i) \ #define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
z += ((w & (x ^ y)) ^ y) + blk0(i) + 0x5A827999 + rol(v, 5); \ #define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
w = rol(w, 30); #define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
#define R1(v, w, x, y, z, i) \ #define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
z += ((w & (x ^ y)) ^ y) + blk(i) + 0x5A827999 + rol(v, 5); \ #define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
w = rol(w, 30);
#define R2(v, w, x, y, z, i) \
z += (w ^ x ^ y) + blk(i) + 0x6ED9EBA1 + rol(v, 5); \
w = rol(w, 30);
#define R3(v, w, x, y, z, i) \
z += (((w | x) & y) | (w & x)) + blk(i) + 0x8F1BBCDC + rol(v, 5); \
w = rol(w, 30);
#define R4(v, w, x, y, z, i) \
z += (w ^ x ^ y) + blk(i) + 0xCA62C1D6 + rol(v, 5); \
w = rol(w, 30);
static uint32_t host_to_be(uint32_t i) static uint32_t host_to_be(uint32_t i)
{ {
#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))
#if defined(__BIG_ENDIAN__) || \ #if defined(__BIG_ENDIAN__) || \
(defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && \ (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && \
__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
return i; return i;
#elif defined(__LITTLE_ENDIAN__) || \ #elif defined(__LITTLE_ENDIAN__) || \
(defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \ (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \
__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
return le_to_be(i); return le_to_be(i);
#else /* fallback to run-time check */ #else /* fallback to run-time check */
static const union { static const union {
@@ -126,13 +118,6 @@ static uint32_t host_to_be(uint32_t i)
#undef le_to_be #undef le_to_be
} }
static void *(*volatile SHA1_explicit_memset)(void *, int, size_t) = &memset;
static void SHA1_cleanse(void *p, size_t len)
{
SHA1_explicit_memset(p, 0, len);
}
/* Hash a single 512-bit block. This is the core of the algorithm. */ /* Hash a single 512-bit block. This is the core of the algorithm. */
static void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64]) static void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64])
{ {
@@ -141,11 +126,15 @@ static void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64])
uint8_t c[64]; uint8_t c[64];
uint32_t l[16]; uint32_t l[16];
} CHAR64LONG16; } CHAR64LONG16;
CHAR64LONG16 *block; CHAR64LONG16* block;
#ifdef SHA1HANDSOFF
static uint8_t workspace[64]; static uint8_t workspace[64];
block = (CHAR64LONG16 *)workspace; block = (CHAR64LONG16*)workspace;
memcpy(block, buffer, 64); memcpy(block, buffer, 64);
#else
block = (CHAR64LONG16*)buffer;
#endif
/* Copy context->state[] to working vars */ /* Copy context->state[] to working vars */
a = state[0]; a = state[0];
@@ -155,7 +144,6 @@ static void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64])
e = state[4]; e = state[4];
/* 4 rounds of 20 operations each. Loop unrolled. */ /* 4 rounds of 20 operations each. Loop unrolled. */
/* clang-format off */
R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
@@ -176,7 +164,6 @@ static void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64])
R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
/* clang-format on */
/* Add the working vars back into context.state[] */ /* Add the working vars back into context.state[] */
state[0] += a; state[0] += a;
@@ -186,15 +173,12 @@ static void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64])
state[4] += e; state[4] += e;
/* Wipe variables */ /* Wipe variables */
SHA1_cleanse(&a, sizeof(a)); a = b = c = d = e = 0;
SHA1_cleanse(&b, sizeof(b));
SHA1_cleanse(&c, sizeof(c));
SHA1_cleanse(&d, sizeof(d));
SHA1_cleanse(&e, sizeof(e));
} }
/* SHA1Init - Initialize new context */ /* SHA1Init - Initialize new context */
void crypto_SHA1_Init(SHA1_CTX *context) void crypto_SHA1_Init(SHA1_CTX* context)
{ {
/* SHA1 initialization constants */ /* SHA1 initialization constants */
context->state[0] = 0x67452301; context->state[0] = 0x67452301;
@@ -205,59 +189,63 @@ void crypto_SHA1_Init(SHA1_CTX *context)
context->count[0] = context->count[1] = 0; context->count[0] = context->count[1] = 0;
} }
/* Run your data through this. */ /* Run your data through this. */
void crypto_SHA1_Update(SHA1_CTX *context, const uint8_t *data, size_t len) void crypto_SHA1_Update(SHA1_CTX* context, const uint8_t* data,
const size_t len)
{ {
size_t i, j; size_t i, j;
j = (context->count[0] >> 3) & 63; j = (context->count[0] >> 3) & 63;
if ((context->count[0] += (uint32_t)len << 3) < ((uint32_t)len << 3)) if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++;
context->count[1]++; context->count[1] += (len >> 29);
context->count[1] += (uint32_t)(len >> 29);
if ((j + len) > 63) { if ((j + len) > 63) {
memcpy(&context->buffer[j], data, (i = 64 - j)); memcpy(&context->buffer[j], data, (i = 64-j));
SHA1_Transform(context->state, context->buffer); SHA1_Transform(context->state, context->buffer);
for (; i + 63 < len; i += 64) { for ( ; i + 63 < len; i += 64) {
SHA1_Transform(context->state, data + i); SHA1_Transform(context->state, data + i);
} }
j = 0; j = 0;
} else }
i = 0; else i = 0;
memcpy(&context->buffer[j], &data[i], len - i); memcpy(&context->buffer[j], &data[i], len - i);
} }
/* Add padding and return the message digest. */ /* Add padding and return the message digest. */
void crypto_SHA1_Final(SHA1_CTX *context, uint8_t *digest) void crypto_SHA1_Final(SHA1_CTX* context, uint8_t* digest)
{ {
uint32_t i; uint32_t i;
uint8_t finalcount[8]; uint8_t finalcount[8];
for (i = 0; i < 8; i++) { for (i = 0; i < 8; i++) {
finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)] >> finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
((3 - (i & 3)) * 8)) & >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */
255); /* Endian independent */
} }
crypto_SHA1_Update(context, (uint8_t *)"\200", 1); crypto_SHA1_Update(context, (uint8_t *)"\200", 1);
while ((context->count[0] & 504) != 448) { while ((context->count[0] & 504) != 448) {
crypto_SHA1_Update(context, (uint8_t *)"\0", 1); crypto_SHA1_Update(context, (uint8_t *)"\0", 1);
} }
/* Should cause a SHA1_Transform() */ crypto_SHA1_Update(context, finalcount, 8); /* Should cause a SHA1_Transform() */
crypto_SHA1_Update(context, finalcount, 8);
for (i = 0; i < SHA1_DIGEST_SIZE; i++) { for (i = 0; i < SHA1_DIGEST_SIZE; i++) {
digest[i] = digest[i] = (uint8_t)
(uint8_t)((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255); ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
} }
/* Wipe variables */ /* Wipe variables */
SHA1_cleanse(context->buffer, 64); i = 0;
SHA1_cleanse(context->state, 20); memset(context->buffer, 0, 64);
SHA1_cleanse(context->count, 8); memset(context->state, 0, 20);
SHA1_cleanse(finalcount, 8); /* SWR */ memset(context->count, 0, 8);
memset(finalcount, 0, 8); /* SWR */
#ifdef SHA1HANDSOFF /* make SHA1Transform overwrite its own static vars */
SHA1_Transform(context->state, context->buffer); SHA1_Transform(context->state, context->buffer);
#endif
} }
void crypto_SHA1(const uint8_t *data, size_t len, uint8_t *digest)
void crypto_SHA1(const uint8_t* data, size_t len, uint8_t* digest)
{ {
SHA1_CTX ctx; SHA1_CTX ctx;
crypto_SHA1_Init(&ctx); crypto_SHA1_Init(&ctx);

View File

@@ -18,15 +18,16 @@ extern "C" {
typedef struct { typedef struct {
uint32_t state[5]; uint32_t state[5];
uint32_t count[2]; uint32_t count[2];
uint8_t buffer[64]; uint8_t buffer[64];
} SHA1_CTX; } SHA1_CTX;
#define SHA1_DIGEST_SIZE 20 #define SHA1_DIGEST_SIZE 20
void crypto_SHA1_Init(SHA1_CTX *context); void crypto_SHA1_Init(SHA1_CTX* context);
void crypto_SHA1_Update(SHA1_CTX *context, const uint8_t *data, size_t len); void crypto_SHA1_Update(SHA1_CTX* context, const uint8_t* data,
void crypto_SHA1_Final(SHA1_CTX *context, uint8_t *digest); const size_t len);
void crypto_SHA1(const uint8_t *data, size_t len, uint8_t *digest); void crypto_SHA1_Final(SHA1_CTX* context, uint8_t* digest);
void crypto_SHA1(const uint8_t* data, size_t len, uint8_t* digest);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@@ -1,210 +0,0 @@
/*
* Code originally from LibTomCrypt -- Licensed under the Public Domain/WTFPL2.0
*/
#include "sha256.h"
#include "sha.h"
/* Various logical functions */
#define Ch(x, y, z) (z ^ (x & (y ^ z)))
#define Maj(x, y, z) (((x | y) & z) | (x & y))
#define S(x, n) RORc((x), (n))
#define R(x, n) (((x)&0xFFFFFFFFUL) >> (n))
#define Sigma0(x) (S(x, 2) ^ S(x, 13) ^ S(x, 22))
#define Sigma1(x) (S(x, 6) ^ S(x, 11) ^ S(x, 25))
#define Gamma0(x) (S(x, 7) ^ S(x, 18) ^ R(x, 3))
#define Gamma1(x) (S(x, 17) ^ S(x, 19) ^ R(x, 10))
static void sha256_compress(sha256_context *md, const uint8_t *buf)
{
uint32_t S[8], W[64], t0, t1;
int i;
/* copy state into S */
for (i = 0; i < 8; i++) {
S[i] = md->state[i];
}
/* copy the state into 512-bits into W[0..15] */
for (i = 0; i < 16; i++) {
LOAD32H(W[i], buf + (4 * i));
}
/* fill W[16..63] */
for (i = 16; i < 64; i++) {
W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16];
}
/* Compress */
#define RND(a, b, c, d, e, f, g, h, i, ki) \
t0 = h + Sigma1(e) + Ch(e, f, g) + ki + W[i]; \
t1 = Sigma0(a) + Maj(a, b, c); \
d += t0; \
h = t0 + t1;
RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], 0, 0x428a2f98);
RND(S[7], S[0], S[1], S[2], S[3], S[4], S[5], S[6], 1, 0x71374491);
RND(S[6], S[7], S[0], S[1], S[2], S[3], S[4], S[5], 2, 0xb5c0fbcf);
RND(S[5], S[6], S[7], S[0], S[1], S[2], S[3], S[4], 3, 0xe9b5dba5);
RND(S[4], S[5], S[6], S[7], S[0], S[1], S[2], S[3], 4, 0x3956c25b);
RND(S[3], S[4], S[5], S[6], S[7], S[0], S[1], S[2], 5, 0x59f111f1);
RND(S[2], S[3], S[4], S[5], S[6], S[7], S[0], S[1], 6, 0x923f82a4);
RND(S[1], S[2], S[3], S[4], S[5], S[6], S[7], S[0], 7, 0xab1c5ed5);
RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], 8, 0xd807aa98);
RND(S[7], S[0], S[1], S[2], S[3], S[4], S[5], S[6], 9, 0x12835b01);
RND(S[6], S[7], S[0], S[1], S[2], S[3], S[4], S[5], 10, 0x243185be);
RND(S[5], S[6], S[7], S[0], S[1], S[2], S[3], S[4], 11, 0x550c7dc3);
RND(S[4], S[5], S[6], S[7], S[0], S[1], S[2], S[3], 12, 0x72be5d74);
RND(S[3], S[4], S[5], S[6], S[7], S[0], S[1], S[2], 13, 0x80deb1fe);
RND(S[2], S[3], S[4], S[5], S[6], S[7], S[0], S[1], 14, 0x9bdc06a7);
RND(S[1], S[2], S[3], S[4], S[5], S[6], S[7], S[0], 15, 0xc19bf174);
RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], 16, 0xe49b69c1);
RND(S[7], S[0], S[1], S[2], S[3], S[4], S[5], S[6], 17, 0xefbe4786);
RND(S[6], S[7], S[0], S[1], S[2], S[3], S[4], S[5], 18, 0x0fc19dc6);
RND(S[5], S[6], S[7], S[0], S[1], S[2], S[3], S[4], 19, 0x240ca1cc);
RND(S[4], S[5], S[6], S[7], S[0], S[1], S[2], S[3], 20, 0x2de92c6f);
RND(S[3], S[4], S[5], S[6], S[7], S[0], S[1], S[2], 21, 0x4a7484aa);
RND(S[2], S[3], S[4], S[5], S[6], S[7], S[0], S[1], 22, 0x5cb0a9dc);
RND(S[1], S[2], S[3], S[4], S[5], S[6], S[7], S[0], 23, 0x76f988da);
RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], 24, 0x983e5152);
RND(S[7], S[0], S[1], S[2], S[3], S[4], S[5], S[6], 25, 0xa831c66d);
RND(S[6], S[7], S[0], S[1], S[2], S[3], S[4], S[5], 26, 0xb00327c8);
RND(S[5], S[6], S[7], S[0], S[1], S[2], S[3], S[4], 27, 0xbf597fc7);
RND(S[4], S[5], S[6], S[7], S[0], S[1], S[2], S[3], 28, 0xc6e00bf3);
RND(S[3], S[4], S[5], S[6], S[7], S[0], S[1], S[2], 29, 0xd5a79147);
RND(S[2], S[3], S[4], S[5], S[6], S[7], S[0], S[1], 30, 0x06ca6351);
RND(S[1], S[2], S[3], S[4], S[5], S[6], S[7], S[0], 31, 0x14292967);
RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], 32, 0x27b70a85);
RND(S[7], S[0], S[1], S[2], S[3], S[4], S[5], S[6], 33, 0x2e1b2138);
RND(S[6], S[7], S[0], S[1], S[2], S[3], S[4], S[5], 34, 0x4d2c6dfc);
RND(S[5], S[6], S[7], S[0], S[1], S[2], S[3], S[4], 35, 0x53380d13);
RND(S[4], S[5], S[6], S[7], S[0], S[1], S[2], S[3], 36, 0x650a7354);
RND(S[3], S[4], S[5], S[6], S[7], S[0], S[1], S[2], 37, 0x766a0abb);
RND(S[2], S[3], S[4], S[5], S[6], S[7], S[0], S[1], 38, 0x81c2c92e);
RND(S[1], S[2], S[3], S[4], S[5], S[6], S[7], S[0], 39, 0x92722c85);
RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], 40, 0xa2bfe8a1);
RND(S[7], S[0], S[1], S[2], S[3], S[4], S[5], S[6], 41, 0xa81a664b);
RND(S[6], S[7], S[0], S[1], S[2], S[3], S[4], S[5], 42, 0xc24b8b70);
RND(S[5], S[6], S[7], S[0], S[1], S[2], S[3], S[4], 43, 0xc76c51a3);
RND(S[4], S[5], S[6], S[7], S[0], S[1], S[2], S[3], 44, 0xd192e819);
RND(S[3], S[4], S[5], S[6], S[7], S[0], S[1], S[2], 45, 0xd6990624);
RND(S[2], S[3], S[4], S[5], S[6], S[7], S[0], S[1], 46, 0xf40e3585);
RND(S[1], S[2], S[3], S[4], S[5], S[6], S[7], S[0], 47, 0x106aa070);
RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], 48, 0x19a4c116);
RND(S[7], S[0], S[1], S[2], S[3], S[4], S[5], S[6], 49, 0x1e376c08);
RND(S[6], S[7], S[0], S[1], S[2], S[3], S[4], S[5], 50, 0x2748774c);
RND(S[5], S[6], S[7], S[0], S[1], S[2], S[3], S[4], 51, 0x34b0bcb5);
RND(S[4], S[5], S[6], S[7], S[0], S[1], S[2], S[3], 52, 0x391c0cb3);
RND(S[3], S[4], S[5], S[6], S[7], S[0], S[1], S[2], 53, 0x4ed8aa4a);
RND(S[2], S[3], S[4], S[5], S[6], S[7], S[0], S[1], 54, 0x5b9cca4f);
RND(S[1], S[2], S[3], S[4], S[5], S[6], S[7], S[0], 55, 0x682e6ff3);
RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], 56, 0x748f82ee);
RND(S[7], S[0], S[1], S[2], S[3], S[4], S[5], S[6], 57, 0x78a5636f);
RND(S[6], S[7], S[0], S[1], S[2], S[3], S[4], S[5], 58, 0x84c87814);
RND(S[5], S[6], S[7], S[0], S[1], S[2], S[3], S[4], 59, 0x8cc70208);
RND(S[4], S[5], S[6], S[7], S[0], S[1], S[2], S[3], 60, 0x90befffa);
RND(S[3], S[4], S[5], S[6], S[7], S[0], S[1], S[2], 61, 0xa4506ceb);
RND(S[2], S[3], S[4], S[5], S[6], S[7], S[0], S[1], 62, 0xbef9a3f7);
RND(S[1], S[2], S[3], S[4], S[5], S[6], S[7], S[0], 63, 0xc67178f2);
#undef RND
/* feedback */
for (i = 0; i < 8; i++) {
md->state[i] = md->state[i] + S[i];
}
}
void sha256_init(sha256_context *md)
{
md->curlen = 0;
md->length = 0;
md->state[0] = 0x6A09E667UL;
md->state[1] = 0xBB67AE85UL;
md->state[2] = 0x3C6EF372UL;
md->state[3] = 0xA54FF53AUL;
md->state[4] = 0x510E527FUL;
md->state[5] = 0x9B05688CUL;
md->state[6] = 0x1F83D9ABUL;
md->state[7] = 0x5BE0CD19UL;
}
void sha256_process(sha256_context *md, const uint8_t *in, size_t inlen)
{
size_t n;
if (md->curlen > sizeof(md->buf)) {
return;
}
if ((md->length + inlen) < md->length) {
return;
}
while (inlen > 0) {
if (md->curlen == 0 && inlen >= 64) {
sha256_compress(md, in);
md->length += 64 * 8;
in += 64;
inlen -= 64;
} else {
n = (((inlen) < ((64 - md->curlen))) ? (inlen)
: ((64 - md->curlen)));
memcpy(md->buf + md->curlen, in, (size_t)n);
md->curlen += n;
in += n;
inlen -= n;
if (md->curlen == 64) {
sha256_compress(md, md->buf);
md->length += 8 * 64;
md->curlen = 0;
}
}
}
}
void sha256_done(sha256_context *md, uint8_t *out)
{
int i;
if (md->curlen >= sizeof(md->buf)) {
return;
}
/* increase the length of the message */
md->length += md->curlen * 8;
/* append the '1' bit */
md->buf[md->curlen++] = (uint8_t)0x80;
/* if the length is currently above 56 bytes we append zeros
* then compress. Then we can fall back to padding zeros and length
* encoding like normal.
*/
if (md->curlen > 56) {
while (md->curlen < 64) {
md->buf[md->curlen++] = (uint8_t)0;
}
sha256_compress(md, md->buf);
md->curlen = 0;
}
/* pad upto 56 bytes of zeroes */
while (md->curlen < 56) {
md->buf[md->curlen++] = (uint8_t)0;
}
/* store length */
STORE64H(md->length, md->buf + 56);
sha256_compress(md, md->buf);
/* copy output */
for (i = 0; i < 8; i++) {
STORE32H(md->state[i], out + (4 * i));
}
}
void sha256_hash(const uint8_t *data, size_t len, uint8_t *digest)
{
sha256_context md;
sha256_init(&md);
sha256_process(&md, data, len);
sha256_done(&md, digest);
}

View File

@@ -1,34 +0,0 @@
/* public api for LibTomCrypt SHA-256 implementation */
/** @file
* SHA-256 hash API.
*/
#ifndef __LIBSTROPHE_SHA256_H__
#define __LIBSTROPHE_SHA256_H__
#ifdef __cplusplus
extern "C" {
#endif
/* make sure the stdint.h types are available */
#include "ostypes.h"
typedef struct {
uint64_t length;
uint32_t state[8], curlen;
uint8_t buf[64];
} sha256_context;
#define SHA256_DIGEST_SIZE 32
void sha256_init(sha256_context *md);
void sha256_process(sha256_context *md, const uint8_t *in, size_t inlen);
void sha256_done(sha256_context *md, uint8_t *out);
void sha256_hash(const uint8_t *data, size_t len, uint8_t *digest);
#ifdef __cplusplus
}
#endif
#endif /* __LIBSTROPHE_SHA256_H__ */

View File

@@ -1,201 +0,0 @@
/*
* Code originally from LibTomCrypt -- Licensed under the Public Domain/WTFPL2.0
*/
#include "sha512.h"
#include "sha.h"
/* the K array */
static const uint64_t K[80] = {
CONST64(0x428a2f98d728ae22), CONST64(0x7137449123ef65cd),
CONST64(0xb5c0fbcfec4d3b2f), CONST64(0xe9b5dba58189dbbc),
CONST64(0x3956c25bf348b538), CONST64(0x59f111f1b605d019),
CONST64(0x923f82a4af194f9b), CONST64(0xab1c5ed5da6d8118),
CONST64(0xd807aa98a3030242), CONST64(0x12835b0145706fbe),
CONST64(0x243185be4ee4b28c), CONST64(0x550c7dc3d5ffb4e2),
CONST64(0x72be5d74f27b896f), CONST64(0x80deb1fe3b1696b1),
CONST64(0x9bdc06a725c71235), CONST64(0xc19bf174cf692694),
CONST64(0xe49b69c19ef14ad2), CONST64(0xefbe4786384f25e3),
CONST64(0x0fc19dc68b8cd5b5), CONST64(0x240ca1cc77ac9c65),
CONST64(0x2de92c6f592b0275), CONST64(0x4a7484aa6ea6e483),
CONST64(0x5cb0a9dcbd41fbd4), CONST64(0x76f988da831153b5),
CONST64(0x983e5152ee66dfab), CONST64(0xa831c66d2db43210),
CONST64(0xb00327c898fb213f), CONST64(0xbf597fc7beef0ee4),
CONST64(0xc6e00bf33da88fc2), CONST64(0xd5a79147930aa725),
CONST64(0x06ca6351e003826f), CONST64(0x142929670a0e6e70),
CONST64(0x27b70a8546d22ffc), CONST64(0x2e1b21385c26c926),
CONST64(0x4d2c6dfc5ac42aed), CONST64(0x53380d139d95b3df),
CONST64(0x650a73548baf63de), CONST64(0x766a0abb3c77b2a8),
CONST64(0x81c2c92e47edaee6), CONST64(0x92722c851482353b),
CONST64(0xa2bfe8a14cf10364), CONST64(0xa81a664bbc423001),
CONST64(0xc24b8b70d0f89791), CONST64(0xc76c51a30654be30),
CONST64(0xd192e819d6ef5218), CONST64(0xd69906245565a910),
CONST64(0xf40e35855771202a), CONST64(0x106aa07032bbd1b8),
CONST64(0x19a4c116b8d2d0c8), CONST64(0x1e376c085141ab53),
CONST64(0x2748774cdf8eeb99), CONST64(0x34b0bcb5e19b48a8),
CONST64(0x391c0cb3c5c95a63), CONST64(0x4ed8aa4ae3418acb),
CONST64(0x5b9cca4f7763e373), CONST64(0x682e6ff3d6b2b8a3),
CONST64(0x748f82ee5defb2fc), CONST64(0x78a5636f43172f60),
CONST64(0x84c87814a1f0ab72), CONST64(0x8cc702081a6439ec),
CONST64(0x90befffa23631e28), CONST64(0xa4506cebde82bde9),
CONST64(0xbef9a3f7b2c67915), CONST64(0xc67178f2e372532b),
CONST64(0xca273eceea26619c), CONST64(0xd186b8c721c0c207),
CONST64(0xeada7dd6cde0eb1e), CONST64(0xf57d4f7fee6ed178),
CONST64(0x06f067aa72176fba), CONST64(0x0a637dc5a2c898a6),
CONST64(0x113f9804bef90dae), CONST64(0x1b710b35131c471b),
CONST64(0x28db77f523047d84), CONST64(0x32caab7b40c72493),
CONST64(0x3c9ebe0a15c9bebc), CONST64(0x431d67c49c100d4c),
CONST64(0x4cc5d4becb3e42b6), CONST64(0x597f299cfc657e2a),
CONST64(0x5fcb6fab3ad6faec), CONST64(0x6c44198c4a475817)};
/* Various logical functions */
#define Ch(x, y, z) (z ^ (x & (y ^ z)))
#define Maj(x, y, z) (((x | y) & z) | (x & y))
#define S(x, n) ROR64c(x, n)
#define R(x, n) (((x)&CONST64(0xFFFFFFFFFFFFFFFF)) >> ((uint64_t)n))
#define Sigma0(x) (S(x, 28) ^ S(x, 34) ^ S(x, 39))
#define Sigma1(x) (S(x, 14) ^ S(x, 18) ^ S(x, 41))
#define Gamma0(x) (S(x, 1) ^ S(x, 8) ^ R(x, 7))
#define Gamma1(x) (S(x, 19) ^ S(x, 61) ^ R(x, 6))
/* compress 1024-bits */
static void sha512_compress(sha512_context *md, const uint8_t *buf)
{
uint64_t S[8], W[80], t0, t1;
int i;
/* copy state into S */
for (i = 0; i < 8; i++) {
S[i] = md->state[i];
}
/* copy the state into 1024-bits into W[0..15] */
for (i = 0; i < 16; i++) {
LOAD64H(W[i], buf + (8 * i));
}
/* fill W[16..79] */
for (i = 16; i < 80; i++) {
W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16];
}
/* Compress */
#define RND(a, b, c, d, e, f, g, h, i) \
t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \
t1 = Sigma0(a) + Maj(a, b, c); \
d += t0; \
h = t0 + t1;
for (i = 0; i < 80; i += 8) {
RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], i + 0);
RND(S[7], S[0], S[1], S[2], S[3], S[4], S[5], S[6], i + 1);
RND(S[6], S[7], S[0], S[1], S[2], S[3], S[4], S[5], i + 2);
RND(S[5], S[6], S[7], S[0], S[1], S[2], S[3], S[4], i + 3);
RND(S[4], S[5], S[6], S[7], S[0], S[1], S[2], S[3], i + 4);
RND(S[3], S[4], S[5], S[6], S[7], S[0], S[1], S[2], i + 5);
RND(S[2], S[3], S[4], S[5], S[6], S[7], S[0], S[1], i + 6);
RND(S[1], S[2], S[3], S[4], S[5], S[6], S[7], S[0], i + 7);
}
/* feedback */
for (i = 0; i < 8; i++) {
md->state[i] = md->state[i] + S[i];
}
}
void sha512_init(sha512_context *md)
{
md->curlen = 0;
md->length = 0;
md->state[0] = CONST64(0x6a09e667f3bcc908);
md->state[1] = CONST64(0xbb67ae8584caa73b);
md->state[2] = CONST64(0x3c6ef372fe94f82b);
md->state[3] = CONST64(0xa54ff53a5f1d36f1);
md->state[4] = CONST64(0x510e527fade682d1);
md->state[5] = CONST64(0x9b05688c2b3e6c1f);
md->state[6] = CONST64(0x1f83d9abfb41bd6b);
md->state[7] = CONST64(0x5be0cd19137e2179);
}
void sha512_process(sha512_context *md, const uint8_t *in, size_t inlen)
{
size_t n;
if (md->curlen > sizeof(md->buf)) {
return;
}
if ((md->length + inlen) < md->length) {
return;
}
while (inlen > 0) {
if (md->curlen == 0 && inlen >= 128) {
sha512_compress(md, in);
md->length += 128 * 8;
in += 128;
inlen -= 128;
} else {
n = (((inlen) < ((128u - md->curlen))) ? (inlen)
: ((128u - md->curlen)));
memcpy(md->buf + md->curlen, in, (size_t)n);
md->curlen += n;
in += n;
inlen -= n;
if (md->curlen == 128) {
sha512_compress(md, md->buf);
md->length += 8 * 128;
md->curlen = 0;
}
}
}
}
void sha512_done(sha512_context *md, uint8_t *out)
{
int i;
if (md->curlen >= sizeof(md->buf)) {
return;
}
/* increase the length of the message */
md->length += md->curlen * CONST64(8);
/* append the '1' bit */
md->buf[md->curlen++] = (uint8_t)0x80;
/* if the length is currently above 112 bytes we append zeros
* then compress. Then we can fall back to padding zeros and length
* encoding like normal.
*/
if (md->curlen > 112) {
while (md->curlen < 128) {
md->buf[md->curlen++] = (uint8_t)0;
}
sha512_compress(md, md->buf);
md->curlen = 0;
}
/* pad upto 120 bytes of zeroes
* note: that from 112 to 120 is the 64 MSB of the length. We assume that
* you won't hash > 2^64 bits of data... :-)
*/
while (md->curlen < 120) {
md->buf[md->curlen++] = (uint8_t)0;
}
/* store length */
STORE64H(md->length, md->buf + 120);
sha512_compress(md, md->buf);
/* copy output */
for (i = 0; i < 8; i++) {
STORE64H(md->state[i], out + (8 * i));
}
}
void sha512_hash(const uint8_t *data, size_t len, uint8_t *digest)
{
sha512_context md;
sha512_init(&md);
sha512_process(&md, data, len);
sha512_done(&md, digest);
}

View File

@@ -1,34 +0,0 @@
/* public api for LibTomCrypt SHA-512 implementation */
/** @file
* SHA-512 hash API.
*/
#ifndef __LIBSTROPHE_SHA512_H__
#define __LIBSTROPHE_SHA512_H__
#ifdef __cplusplus
extern "C" {
#endif
/* make sure the stdint.h types are available */
#include "ostypes.h"
typedef struct {
uint64_t length, state[8];
uint8_t curlen;
uint8_t buf[128];
} sha512_context;
#define SHA512_DIGEST_SIZE 64
void sha512_init(sha512_context *cc);
void sha512_process(sha512_context *cc, const uint8_t *data, size_t len);
void sha512_done(sha512_context *cc, uint8_t *dst);
void sha512_hash(const uint8_t *data, size_t len, uint8_t *digest);
#ifdef __cplusplus
}
#endif
#endif /* __LIBSTROPHE_SHA512_H__ */

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
/* sock.c /* sock.c
** strophe XMPP client library -- socket abstraction implementation ** strophe XMPP client library -- socket abstraction implementation
** **
** Copyright (C) 2005-2009 Collecta, Inc. ** Copyright (C) 2005-2009 Collecta, Inc.
** **
** This software is provided AS-IS with no warranty, either express ** This software is provided AS-IS with no warranty, either express
** or implied. ** or implied.
@@ -21,8 +21,8 @@
#ifdef _WIN32 #ifdef _WIN32
#include <winsock2.h> #include <winsock2.h>
#include <ws2tcpip.h> #include <ws2tcpip.h>
#include <iphlpapi.h> #include <Iphlpapi.h>
#include <mstcpip.h> /* tcp_keepalive */ #include <Mstcpip.h> /* tcp_keepalive */
#else #else
#include <errno.h> #include <errno.h>
#include <unistd.h> #include <unistd.h>
@@ -69,7 +69,7 @@ static int _in_progress(int error)
#endif #endif
} }
sock_t sock_connect(const char *host, unsigned short port) sock_t sock_connect(const char * const host, const unsigned short port)
{ {
sock_t sock; sock_t sock;
char service[6]; char service[6];
@@ -109,7 +109,44 @@ sock_t sock_connect(const char *host, unsigned short port)
return sock; return sock;
} }
int sock_set_keepalive(sock_t sock, int timeout, int interval) 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 ret;
int optval = (timeout && interval) ? 1 : 0; int optval = (timeout && interval) ? 1 : 0;
@@ -123,8 +160,7 @@ int sock_set_keepalive(sock_t sock, int timeout, int interval)
ka.onoff = optval; ka.onoff = optval;
ka.keepalivetime = timeout * 1000; ka.keepalivetime = timeout * 1000;
ka.keepaliveinterval = interval * 1000; ka.keepaliveinterval = interval * 1000;
ret = WSAIoctl(sock, SIO_KEEPALIVE_VALS, &ka, sizeof(ka), NULL, 0, &dw, ret = WSAIoctl(sock, SIO_KEEPALIVE_VALS, &ka, sizeof(ka), NULL, 0, &dw, NULL, NULL);
NULL, NULL);
#else #else
ret = setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval)); ret = setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval));
if (ret < 0) if (ret < 0)
@@ -132,19 +168,15 @@ int sock_set_keepalive(sock_t sock, int timeout, int interval)
if (optval) { if (optval) {
#ifdef TCP_KEEPIDLE #ifdef TCP_KEEPIDLE
ret = setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, &timeout, ret = setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, &timeout, sizeof(timeout));
sizeof(timeout));
#elif defined(TCP_KEEPALIVE) #elif defined(TCP_KEEPALIVE)
/* QNX receives `struct timeval' as argument, but it seems OSX does int /* QNX receives `struct timeval' as argument, but it seems OSX does int */
*/ ret = setsockopt(sock, IPPROTO_TCP, TCP_KEEPALIVE, &timeout, sizeof(timeout));
ret = setsockopt(sock, IPPROTO_TCP, TCP_KEEPALIVE, &timeout,
sizeof(timeout));
#endif /* TCP_KEEPIDLE */ #endif /* TCP_KEEPIDLE */
if (ret < 0) if (ret < 0)
return ret; return ret;
#ifdef TCP_KEEPINTVL #ifdef TCP_KEEPINTVL
ret = setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, &interval, ret = setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, &interval, sizeof(interval));
sizeof(interval));
if (ret < 0) if (ret < 0)
return ret; return ret;
#endif /* TCP_KEEPINTVL */ #endif /* TCP_KEEPINTVL */
@@ -154,7 +186,7 @@ int sock_set_keepalive(sock_t sock, int timeout, int interval)
return ret; return ret;
} }
int sock_close(sock_t sock) int sock_close(const sock_t sock)
{ {
#ifdef _WIN32 #ifdef _WIN32
return closesocket(sock); return closesocket(sock);
@@ -163,78 +195,81 @@ int sock_close(sock_t sock)
#endif #endif
} }
static int _sock_set_blocking_mode(sock_t sock, int blocking) int sock_set_blocking(const sock_t sock)
{ {
#ifdef _WIN32 #ifdef _WIN32
u_long nonblock = blocking ? 0 : 1; u_long block = 0;
return ioctlsocket(sock, FIONBIO, &block);
#else
int rc;
rc = fcntl(sock, F_GETFL, NULL);
if (rc >= 0) {
rc = fcntl(sock, F_SETFL, rc & (~O_NONBLOCK));
}
return rc;
#endif
}
int sock_set_nonblocking(const sock_t sock)
{
#ifdef _WIN32
u_long nonblock = 1;
return ioctlsocket(sock, FIONBIO, &nonblock); return ioctlsocket(sock, FIONBIO, &nonblock);
#else #else
int rc; int rc;
rc = fcntl(sock, F_GETFL, NULL); rc = fcntl(sock, F_GETFL, NULL);
if (rc >= 0) { if (rc >= 0) {
rc = blocking ? rc & (~O_NONBLOCK) : rc | O_NONBLOCK; rc = fcntl(sock, F_SETFL, rc | O_NONBLOCK);
rc = fcntl(sock, F_SETFL, rc);
} }
return rc; return rc;
#endif #endif
} }
int sock_set_blocking(sock_t sock) int sock_read(const sock_t sock, void * const buff, const size_t len)
{
return _sock_set_blocking_mode(sock, 1);
}
int sock_set_nonblocking(sock_t sock)
{
return _sock_set_blocking_mode(sock, 0);
}
int sock_read(sock_t sock, void *buff, size_t len)
{ {
return recv(sock, buff, len, 0); return recv(sock, buff, len, 0);
} }
int sock_write(sock_t sock, const void *buff, size_t len) int sock_write(const sock_t sock, const void * const buff, const size_t len)
{ {
return send(sock, buff, len, 0); return send(sock, buff, len, 0);
} }
int sock_is_recoverable(int error) int sock_is_recoverable(const int error)
{ {
#ifdef _WIN32 #ifdef _WIN32
return (error == WSAEINTR || error == WSAEWOULDBLOCK || return (error == WSAEINTR || error == WSAEWOULDBLOCK ||
error == WSAEINPROGRESS); error == WSAEINPROGRESS);
#else #else
return (error == EAGAIN || error == EINTR); return (error == EAGAIN || error == EINTR);
#endif #endif
} }
int sock_connect_error(sock_t sock) int sock_connect_error(const sock_t sock)
{ {
struct sockaddr_storage ss; struct sockaddr sa;
struct sockaddr *sa = (struct sockaddr *)&ss;
socklen_t len; socklen_t len;
char temp; char temp;
memset(&ss, 0, sizeof(ss)); memset(&sa, 0, sizeof(sa));
len = sizeof(ss); sa.sa_family = AF_UNSPEC;
sa->sa_family = AF_UNSPEC; 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
* we're connected or not */ * we're connected or not */
if (getpeername(sock, sa, &len) == 0) { if (getpeername(sock, &sa, &len) == 0)
{
return 0; return 0;
} }
/* it's possible that the error wasn't ENOTCONN, so if it wasn't, /* it's possible that the error wasn't ENOTCONN, so if it wasn't,
* return that */ * return that */
#ifdef _WIN32 #ifdef _WIN32
if (sock_error() != WSAENOTCONN) if (sock_error() != WSAENOTCONN) return sock_error();
return sock_error();
#else #else
if (sock_error() != ENOTCONN) if (sock_error() != ENOTCONN) return sock_error();
return sock_error();
#endif #endif
/* load the correct error into errno through error slippage */ /* load the correct error into errno through error slippage */

View File

@@ -1,7 +1,7 @@
/* sock.h /* sock.h
** strophe XMPP client library -- socket abstraction header ** strophe XMPP client library -- socket abstraction header
** **
** Copyright (C) 2005-2009 Collecta, Inc. ** Copyright (C) 2005-2009 Collecta, Inc.
** **
** This software is provided AS-IS with no warranty, either express ** This software is provided AS-IS with no warranty, either express
** or implied. ** or implied.
@@ -30,16 +30,19 @@ void sock_shutdown(void);
int sock_error(void); int sock_error(void);
sock_t sock_connect(const char *host, unsigned short port); sock_t sock_connect(const char * const host, const unsigned short port);
int sock_close(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(sock_t sock); int sock_set_blocking(const sock_t sock);
int sock_set_nonblocking(sock_t sock); int sock_set_nonblocking(const sock_t sock);
int sock_read(sock_t sock, void *buff, size_t len); int sock_read(const sock_t sock, void * const buff, const size_t len);
int sock_write(sock_t sock, const void *buff, size_t len); int sock_write(const sock_t sock, const void * const buff, const size_t len);
int sock_is_recoverable(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(sock_t sock); int sock_connect_error(const sock_t sock);
int sock_set_keepalive(sock_t sock, int timeout, int interval); int sock_set_keepalive(const sock_t sock, int timeout, int interval);
#endif /* __LIBSTROPHE_SOCK_H__ */ #endif /* __LIBSTROPHE_SOCK_H__ */

File diff suppressed because it is too large Load Diff

214
src/tls.c
View File

@@ -1,214 +0,0 @@
/* tls.c
** strophe XMPP client library -- generic TLS functions
**
** Copyright (C) 2021 Steffen Jaeckel <jaeckel-floss@eyet-services.de>
**
** This software is provided AS-IS with no warranty, either express
** or implied.
**
** This program is dual licensed under the MIT and GPLv3 licenses.
*/
/** @file
* Generic TLS functionality.
*/
/** @defgroup TLS SSL/TLS specific functionality
* These functions provide SSL/TLS specific functionality.
*/
#include <errno.h>
#include <stdarg.h>
#include <string.h>
#include "strophe.h"
#include "common.h"
struct _dnsname_t {
char **data;
size_t cur, max;
};
const size_t tlscert_dnsnames_increment = 4;
/** Get the Strophe context which is assigned to this certificate.
*
* @param cert a Strophe TLS certificate object
*
* @return the Strophe context object where this certificate originates from
*
* @ingroup TLS
*/
xmpp_ctx_t *xmpp_tlscert_get_ctx(const xmpp_tlscert_t *cert)
{
return cert->ctx;
}
/** Get the Strophe connection which is assigned to this certificate.
*
* @param cert a Strophe TLS certificate object
*
* @return the Strophe connection object where this certificate originates from
*
* @ingroup TLS
*/
xmpp_conn_t *xmpp_tlscert_get_conn(const xmpp_tlscert_t *cert)
{
return cert->conn;
}
/** Get the complete PEM of this certificate.
*
* @param cert a Strophe TLS certificate object
*
* @return a string containing the PEM of this certificate
*
* @ingroup TLS
*/
const char *xmpp_tlscert_get_pem(const xmpp_tlscert_t *cert)
{
return cert->pem;
}
/** Get the dnsName entries out of the SubjectAlternativeNames.
*
* Note: Max. `MAX_NUM_DNSNAMES` are supported.
*
* @param cert a Strophe TLS certificate object
* @param n which dnsName entry
*
* @return a string with the n'th dnsName
*
* @ingroup TLS
*/
const char *xmpp_tlscert_get_dnsname(const xmpp_tlscert_t *cert, size_t n)
{
if (n >= cert->dnsnames->cur)
return NULL;
return cert->dnsnames->data[n];
}
/** Get various parts of the certificate as String.
*
* c.f. \ref xmpp_cert_element_t for details.
*
* @param cert a Strophe TLS certificate object
* @param elmnt which part of the certificate
*
* @return a string with the part of the certificate
*
* @ingroup TLS
*/
const char *xmpp_tlscert_get_string(const xmpp_tlscert_t *cert,
xmpp_cert_element_t elmnt)
{
if (elmnt >= XMPP_CERT_ELEMENT_MAX)
return NULL;
return cert->elements[elmnt];
}
/** Get a descriptive string for each xmpp_cert_element_t.
*
* c.f. \ref xmpp_cert_element_t for details.
*
* @param cert a Strophe TLS certificate object
* @param elmnt which element
*
* @return a string with the description
*
* @ingroup TLS
*/
const char *xmpp_tlscert_get_description(xmpp_cert_element_t elmnt)
{
static const char *descriptions[] = {
"X.509 Version",
"SerialNumber",
"Subject",
"Issuer",
"Issued On",
"Expires On",
"Public Key Algorithm",
"Certificate Signature Algorithm",
"Fingerprint SHA-1",
"Fingerprint SHA-256",
};
if (elmnt >= XMPP_CERT_ELEMENT_MAX)
return NULL;
return descriptions[elmnt];
}
/** Allocate and initialize a Strophe TLS certificate object.
*
* @param ctx a Strophe context object
*
* @return a certificate object or NULL
*/
xmpp_tlscert_t *tlscert_new(xmpp_ctx_t *ctx)
{
xmpp_tlscert_t *tlscert = xmpp_alloc(ctx, sizeof(*tlscert));
if (!tlscert)
return NULL;
memset(tlscert, 0, sizeof(*tlscert));
tlscert->dnsnames = xmpp_alloc(ctx, sizeof(*tlscert->dnsnames));
if (!tlscert->dnsnames) {
xmpp_free(ctx, tlscert);
return NULL;
}
memset(tlscert->dnsnames, 0, sizeof(*tlscert->dnsnames));
tlscert->ctx = ctx;
return tlscert;
}
/** Free a certificate object.
*
* @param cert a Strophe TLS certificate object
*
* @ingroup TLS
*/
void xmpp_tlscert_free(xmpp_tlscert_t *cert)
{
size_t n;
for (n = 0; n < ARRAY_SIZE(cert->elements); ++n) {
if (cert->elements[n])
xmpp_free(cert->ctx, cert->elements[n]);
}
if (cert->dnsnames->data) {
for (n = 0; n < cert->dnsnames->cur; ++n) {
if (cert->dnsnames->data[n])
xmpp_free(cert->ctx, cert->dnsnames->data[n]);
}
}
xmpp_free(cert->ctx, cert->dnsnames->data);
xmpp_free(cert->ctx, cert->dnsnames);
if (cert->pem)
xmpp_free(cert->ctx, cert->pem);
xmpp_free(cert->ctx, cert);
}
/** Add a dnsName to the Strophe TLS certificate object.
*
* @param cert a Strophe TLS certificate object
* @param dnsname dnsName that shall be stored
*
* @return classic Unix style - 0=success, 1=error
*/
int tlscert_add_dnsname(xmpp_tlscert_t *cert, const char *dnsname)
{
if ((cert->dnsnames->cur + 1) >= cert->dnsnames->max) {
char **dnsnames =
xmpp_realloc(cert->ctx, cert->dnsnames->data,
(cert->dnsnames->max + tlscert_dnsnames_increment) *
sizeof(char **));
if (!dnsnames)
return 1;
cert->dnsnames->data = dnsnames;
cert->dnsnames->max += tlscert_dnsnames_increment;
}
cert->dnsnames->data[cert->dnsnames->cur++] =
xmpp_strdup(cert->ctx, dnsname);
return 0;
}

View File

@@ -1,7 +1,7 @@
/* tls.h /* tls.h
** strophe XMPP client library -- TLS abstraction header ** strophe XMPP client library -- TLS abstraction header
** **
** Copyright (C) 2005-2009 Collecta, Inc. ** Copyright (C) 2005-2009 Collecta, Inc.
** **
** This software is provided AS-IS with no warranty, either express ** This software is provided AS-IS with no warranty, either express
** or implied. ** or implied.
@@ -21,28 +21,12 @@
typedef struct _tls tls_t; typedef struct _tls tls_t;
typedef struct _dnsname_t dnsname_t;
struct _xmpp_tlscert_t {
xmpp_ctx_t *ctx;
xmpp_conn_t *conn;
char *pem;
char *elements[XMPP_CERT_ELEMENT_MAX];
dnsname_t *dnsnames;
};
/* provided by the real TLS implementation */
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_conn_t *conn);
void tls_free(tls_t *tls); void tls_free(tls_t *tls);
char *tls_id_on_xmppaddr(xmpp_conn_t *conn, unsigned int n);
unsigned int tls_id_on_xmppaddr_num(xmpp_conn_t *conn);
xmpp_tlscert_t *tls_peer_cert(xmpp_conn_t *conn);
int tls_set_credentials(tls_t *tls, const char *cafilename); int tls_set_credentials(tls_t *tls, const char *cafilename);
int tls_start(tls_t *tls); int tls_start(tls_t *tls);
@@ -51,15 +35,10 @@ int tls_stop(tls_t *tls);
int tls_error(tls_t *tls); int tls_error(tls_t *tls);
int tls_pending(tls_t *tls); int tls_pending(tls_t *tls);
int tls_read(tls_t *tls, void *buff, size_t len); int tls_read(tls_t *tls, void * const buff, const size_t len);
int tls_write(tls_t *tls, const void *buff, size_t len); int tls_write(tls_t *tls, const void * const buff, const size_t len);
int tls_clear_pending_write(tls_t *tls); int tls_clear_pending_write(tls_t *tls);
int tls_is_recoverable(int error); int tls_is_recoverable(int error);
/* provided by tls.c */
xmpp_tlscert_t *tlscert_new(xmpp_ctx_t *ctx);
int tlscert_add_dnsname(xmpp_tlscert_t *cert, const char *dnsname);
#endif /* __LIBSTROPHE_TLS_H__ */ #endif /* __LIBSTROPHE_TLS_H__ */

View File

@@ -1,7 +1,7 @@
/* tls_dummy.c /* tls_dummy.c
** strophe XMPP client library -- TLS abstraction dummy impl. ** strophe XMPP client library -- TLS abstraction dummy impl.
** **
** Copyright (C) 2005-2009 Collecta, Inc. ** Copyright (C) 2005-2009 Collecta, Inc.
** **
** This software is provided AS-IS with no warranty, either express ** This software is provided AS-IS with no warranty, either express
** or implied. ** or implied.
@@ -33,96 +33,59 @@ void tls_shutdown(void)
return; return;
} }
char *tls_id_on_xmppaddr(xmpp_conn_t *conn, unsigned int n)
{
UNUSED(conn);
UNUSED(n);
/* always fail */
return NULL;
}
unsigned int tls_id_on_xmppaddr_num(xmpp_conn_t *conn)
{
UNUSED(conn);
/* always fail */
return 0;
}
tls_t *tls_new(xmpp_conn_t *conn) tls_t *tls_new(xmpp_conn_t *conn)
{ {
UNUSED(conn);
/* always fail */ /* always fail */
return NULL; return NULL;
} }
void tls_free(tls_t *tls) void tls_free(tls_t *tls)
{ {
UNUSED(tls);
return; return;
} }
xmpp_tlscert_t *tls_peer_cert(xmpp_conn_t *conn)
{
UNUSED(conn);
return NULL;
}
int tls_set_credentials(tls_t *tls, const char *cafilename) int tls_set_credentials(tls_t *tls, const char *cafilename)
{ {
UNUSED(tls);
UNUSED(cafilename);
return -1; return -1;
} }
int tls_start(tls_t *tls) int tls_start(tls_t *tls)
{ {
UNUSED(tls);
return -1; return -1;
} }
int tls_stop(tls_t *tls) int tls_stop(tls_t *tls)
{ {
UNUSED(tls);
return -1; return -1;
} }
int tls_error(tls_t *tls) int tls_error(tls_t *tls)
{ {
UNUSED(tls);
/* todo: some kind of error polling/dump */ /* todo: some kind of error polling/dump */
return 0; return 0;
} }
int tls_pending(tls_t *tls) int tls_pending(tls_t *tls)
{ {
UNUSED(tls);
return 0; return 0;
} }
int tls_read(tls_t *tls, void *buff, size_t len) int tls_read(tls_t *tls, void * const buff, const size_t len)
{ {
UNUSED(tls);
UNUSED(buff);
UNUSED(len);
return -1; return -1;
} }
int tls_write(tls_t *tls, const void *buff, size_t len) int tls_write(tls_t *tls, const void * const buff, const size_t len)
{ {
UNUSED(tls);
UNUSED(buff);
UNUSED(len);
return -1; return -1;
} }
int tls_clear_pending_write(tls_t *tls) int tls_clear_pending_write(tls_t *tls)
{ {
UNUSED(tls);
return -1; return -1;
} }
int tls_is_recoverable(int error) int tls_is_recoverable(int error)
{ {
UNUSED(error);
return 0; return 0;
} }

View File

@@ -1,7 +1,7 @@
/* tls.c /* tls.c
** strophe XMPP client library -- TLS abstraction header ** strophe XMPP client library -- TLS abstraction header
** **
** Copyright (C) 2005-2009 Collecta, Inc. ** Copyright (C) 2005-2009 Collecta, Inc.
** **
** This software is provided AS-IS with no warranty, either express ** This software is provided AS-IS with no warranty, either express
** or implied. ** or implied.
@@ -13,21 +13,20 @@
* TLS implementation with GNUTLS * TLS implementation with GNUTLS
*/ */
#include <string.h>
#include <gnutls/gnutls.h> #include <gnutls/gnutls.h>
#include <gnutls/x509.h>
#include <gnutls/x509-ext.h>
#include "common.h" #include "common.h"
#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? */
xmpp_conn_t *conn; sock_t sock;
gnutls_session_t session; gnutls_session_t session;
gnutls_certificate_credentials_t cred; gnutls_certificate_credentials_t cred;
gnutls_x509_crt_t client_cert;
int lasterror; int lasterror;
}; };
@@ -47,299 +46,19 @@ void tls_shutdown(void)
gnutls_global_deinit(); gnutls_global_deinit();
} }
static gnutls_x509_crt_t _tls_load_cert(xmpp_conn_t *conn)
{
if (conn->tls && conn->tls->client_cert)
return conn->tls->client_cert;
gnutls_x509_crt_t cert;
gnutls_datum_t data;
int res;
if (gnutls_x509_crt_init(&cert) < 0)
return NULL;
if (gnutls_load_file(conn->tls_client_cert, &data) < 0)
goto LBL_ERR;
res = gnutls_x509_crt_import(cert, &data, GNUTLS_X509_FMT_PEM);
gnutls_free(data.data);
if (res < 0)
goto LBL_ERR;
return cert;
LBL_ERR:
gnutls_x509_crt_deinit(cert);
return NULL;
}
static void _tls_free_cert(xmpp_conn_t *conn, gnutls_x509_crt_t cert)
{
if (conn->tls && conn->tls->client_cert == cert)
return;
gnutls_x509_crt_deinit(cert);
}
static int _tls_get_id_on_xmppaddr(xmpp_conn_t *conn,
gnutls_x509_crt_t cert,
unsigned int n,
char **ret)
{
gnutls_datum_t san;
size_t name_len, oid_len;
char oid[128], name[128];
name_len = oid_len = 128;
int res =
gnutls_x509_crt_get_subject_alt_name(cert, n, name, &name_len, NULL);
if (res == GNUTLS_SAN_OTHERNAME_XMPP) {
/* This is the happy flow path with fixed GnuTLS.
* While implementing this I stumbled over an issue in GnuTLS
* which lead to
* https://gitlab.com/gnutls/gnutls/-/merge_requests/1397
*/
if (ret) {
*ret = xmpp_strdup(conn->ctx, name);
}
return GNUTLS_SAN_OTHERNAME_XMPP;
}
if (res == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
if (res != GNUTLS_SAN_OTHERNAME)
return GNUTLS_E_X509_UNKNOWN_SAN;
res = gnutls_x509_crt_get_subject_alt_othername_oid(cert, n, oid, &oid_len);
if (res == GNUTLS_SAN_OTHERNAME_XMPP) {
gnutls_datum_t xmpp_addr;
san.data = (unsigned char *)name;
san.size = name_len;
res = gnutls_x509_othername_to_virtual(oid, &san, NULL, &xmpp_addr);
if (res < 0) {
gnutls_free(xmpp_addr.data);
return GNUTLS_E_MEMORY_ERROR;
}
if (ret) {
*ret = xmpp_strdup(conn->ctx, (char *)xmpp_addr.data);
}
gnutls_free(xmpp_addr.data);
return GNUTLS_SAN_OTHERNAME_XMPP;
}
return GNUTLS_E_X509_UNKNOWN_SAN;
}
static int _tls_id_on_xmppaddr(xmpp_conn_t *conn,
gnutls_x509_crt_t cert,
unsigned int n,
char **ret)
{
int res = GNUTLS_E_SUCCESS;
unsigned int i, j;
for (i = j = 0; res != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; ++i) {
res = _tls_get_id_on_xmppaddr(conn, cert, i, NULL);
if (res == GNUTLS_SAN_OTHERNAME_XMPP) {
if (j == n) {
res = _tls_get_id_on_xmppaddr(conn, cert, i, ret);
break;
}
j++;
}
}
return res;
}
/** Search through the SubjectAlternativeNames and return the next
* id-on-xmppAddr element starting from `n`.
*/
char *tls_id_on_xmppaddr(xmpp_conn_t *conn, unsigned int n)
{
char *ret = NULL;
gnutls_x509_crt_t cert = _tls_load_cert(conn);
if (cert == NULL)
return NULL;
_tls_id_on_xmppaddr(conn, cert, n, &ret);
_tls_free_cert(conn, cert);
return ret;
}
unsigned int tls_id_on_xmppaddr_num(xmpp_conn_t *conn)
{
unsigned int ret = 0, n;
int res = GNUTLS_E_SUCCESS;
gnutls_x509_crt_t cert = _tls_load_cert(conn);
if (cert == NULL)
return 0;
for (n = 0; res != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; ++n) {
res = _tls_id_on_xmppaddr(conn, cert, n, NULL);
if (res == GNUTLS_SAN_OTHERNAME_XMPP)
ret++;
}
_tls_free_cert(conn, cert);
return ret;
}
static xmpp_tlscert_t *_x509_to_tlscert(xmpp_ctx_t *ctx, gnutls_x509_crt_t cert)
{
int res;
char buf[512], smallbuf[64];
size_t size, m;
unsigned int algo, n;
gnutls_datum_t data;
time_t time_val;
xmpp_tlscert_t *tlscert = tlscert_new(ctx);
gnutls_x509_crt_export2(cert, GNUTLS_X509_FMT_PEM, &data);
tlscert->pem = xmpp_alloc(ctx, data.size + 1);
memcpy(tlscert->pem, data.data, data.size);
tlscert->pem[data.size] = '\0';
gnutls_free(data.data);
size = sizeof(buf);
gnutls_x509_crt_get_dn(cert, buf, &size);
tlscert->elements[XMPP_CERT_SUBJECT] = xmpp_strdup(ctx, buf);
size = sizeof(buf);
gnutls_x509_crt_get_issuer_dn(cert, buf, &size);
tlscert->elements[XMPP_CERT_ISSUER] = xmpp_strdup(ctx, buf);
time_val = gnutls_x509_crt_get_activation_time(cert);
tlscert->elements[XMPP_CERT_NOTBEFORE] = xmpp_strdup(ctx, ctime(&time_val));
tlscert->elements[XMPP_CERT_NOTBEFORE]
[strlen(tlscert->elements[XMPP_CERT_NOTBEFORE]) - 1] =
'\0';
time_val = gnutls_x509_crt_get_expiration_time(cert);
tlscert->elements[XMPP_CERT_NOTAFTER] = xmpp_strdup(ctx, ctime(&time_val));
tlscert->elements[XMPP_CERT_NOTAFTER]
[strlen(tlscert->elements[XMPP_CERT_NOTAFTER]) - 1] = '\0';
size = sizeof(smallbuf);
gnutls_x509_crt_get_fingerprint(cert, GNUTLS_DIG_SHA1, smallbuf, &size);
hex_encode(buf, smallbuf, size);
tlscert->elements[XMPP_CERT_FINGERPRINT_SHA1] = xmpp_strdup(ctx, buf);
size = sizeof(smallbuf);
gnutls_x509_crt_get_fingerprint(cert, GNUTLS_DIG_SHA256, smallbuf, &size);
hex_encode(buf, smallbuf, size);
tlscert->elements[XMPP_CERT_FINGERPRINT_SHA256] = xmpp_strdup(ctx, buf);
xmpp_snprintf(buf, sizeof(buf), "%d", gnutls_x509_crt_get_version(cert));
tlscert->elements[XMPP_CERT_VERSION] = xmpp_strdup(ctx, buf);
algo = gnutls_x509_crt_get_pk_algorithm(cert, NULL);
tlscert->elements[XMPP_CERT_KEYALG] =
xmpp_strdup(ctx, gnutls_pk_algorithm_get_name(algo));
algo = gnutls_x509_crt_get_signature_algorithm(cert);
tlscert->elements[XMPP_CERT_SIGALG] =
xmpp_strdup(ctx, gnutls_sign_get_name(algo));
size = sizeof(smallbuf);
gnutls_x509_crt_get_serial(cert, smallbuf, &size);
hex_encode(buf, smallbuf, size);
tlscert->elements[XMPP_CERT_SERIALNUMBER] = xmpp_strdup(ctx, buf);
for (n = 0, m = 0, res = 0; res != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
++n) {
size = sizeof(buf);
res = gnutls_x509_crt_get_subject_alt_name(cert, n, buf, &size, NULL);
if (res == GNUTLS_SAN_DNSNAME) {
if (tlscert_add_dnsname(tlscert, buf))
xmpp_debug(ctx, "tls", "Can't store dnsName(%zu): %s", m, buf);
m++;
}
}
return tlscert;
}
static int _tls_verify(gnutls_session_t session)
{
tls_t *tls = gnutls_session_get_ptr(session);
const gnutls_datum_t *cert_list;
gnutls_certificate_type_t type;
gnutls_datum_t out;
unsigned int cert_list_size = 0, status;
gnutls_x509_crt_t cert;
if (gnutls_certificate_type_get(session) != GNUTLS_CRT_X509)
return -1;
if (gnutls_certificate_verify_peers2(session, &status) < 0) {
xmpp_error(tls->ctx, "tls", "Verify peers failed");
return -1;
}
type = gnutls_certificate_type_get(session);
if (gnutls_certificate_verification_status_print(status, type, &out, 0) <
0) {
xmpp_error(tls->ctx, "tls", "Status print failed");
return -1;
}
/* Return early if the Certificate is trusted
* OR if we trust all Certificates */
if (status == 0 || tls->conn->tls_trust)
return 0;
if (!tls->conn->certfail_handler) {
xmpp_error(tls->ctx, "tls",
"No certfail handler set, canceling connection attempt");
return -1;
}
cert_list = gnutls_certificate_get_peers(session, &cert_list_size);
/* OpenSSL displays the certificate chain in reverse order than GnuTLS.
* To show consistent behavior to the user, traverse the list from the
* end.
*/
while (cert_list_size--) {
gnutls_x509_crt_init(&cert);
gnutls_x509_crt_import(cert, &cert_list[cert_list_size],
GNUTLS_X509_FMT_DER);
xmpp_tlscert_t *tlscert = _x509_to_tlscert(tls->ctx, cert);
if (!tlscert) {
gnutls_x509_crt_deinit(cert);
gnutls_free(out.data);
return -1;
}
if (tls->conn->certfail_handler(tlscert, (char *)out.data) == 0) {
xmpp_tlscert_free(tlscert);
gnutls_x509_crt_deinit(cert);
gnutls_free(out.data);
return -1;
}
xmpp_tlscert_free(tlscert);
gnutls_x509_crt_deinit(cert);
}
gnutls_free(out.data);
return 0;
}
tls_t *tls_new(xmpp_conn_t *conn) tls_t *tls_new(xmpp_conn_t *conn)
{ {
tls_t *tls = xmpp_alloc(conn->ctx, sizeof(tls_t)); tls_t *tls = xmpp_alloc(conn->ctx, sizeof(tls_t));
if (tls) { if (tls) {
memset(tls, 0, sizeof(*tls));
tls->ctx = conn->ctx; tls->ctx = conn->ctx;
tls->conn = conn; tls->sock = conn->sock;
gnutls_init(&tls->session, GNUTLS_CLIENT); gnutls_init(&tls->session, GNUTLS_CLIENT);
gnutls_certificate_allocate_credentials(&tls->cred); gnutls_certificate_allocate_credentials(&tls->cred);
tls_set_credentials(tls, NULL); tls_set_credentials(tls, CAFILE);
if (conn->tls_client_cert && conn->tls_client_key) {
tls->client_cert = _tls_load_cert(conn);
if (!tls->client_cert) {
xmpp_error(tls->ctx, "tls",
"could not read client certificate");
gnutls_certificate_free_credentials(tls->cred);
gnutls_deinit(tls->session);
xmpp_free(tls->ctx, tls);
return NULL;
}
gnutls_certificate_set_x509_key_file(
tls->cred, conn->tls_client_cert, conn->tls_client_key,
GNUTLS_X509_FMT_PEM);
}
gnutls_certificate_set_verify_function(tls->cred, _tls_verify);
gnutls_set_default_priority(tls->session); gnutls_set_default_priority(tls->session);
gnutls_session_set_ptr(tls->session, tls);
/* 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_int(tls->session, conn->sock);
@@ -350,45 +69,18 @@ tls_t *tls_new(xmpp_conn_t *conn)
void tls_free(tls_t *tls) void tls_free(tls_t *tls)
{ {
if (tls->client_cert)
gnutls_x509_crt_deinit(tls->client_cert);
gnutls_deinit(tls->session); gnutls_deinit(tls->session);
gnutls_certificate_free_credentials(tls->cred); gnutls_certificate_free_credentials(tls->cred);
xmpp_free(tls->ctx, tls); xmpp_free(tls->ctx, tls);
} }
xmpp_tlscert_t *tls_peer_cert(xmpp_conn_t *conn)
{
xmpp_tlscert_t *tlscert = NULL;
if (conn && conn->tls && conn->tls->session) {
unsigned int list_size = 0;
const gnutls_datum_t *der_cert =
gnutls_certificate_get_peers(conn->tls->session, &list_size);
if (der_cert && list_size) {
gnutls_x509_crt_t cert;
if (gnutls_x509_crt_init(&cert) < 0)
return NULL;
if (gnutls_x509_crt_import(cert, der_cert, GNUTLS_X509_FMT_DER) ==
0)
tlscert = _x509_to_tlscert(conn->ctx, cert);
gnutls_x509_crt_deinit(cert);
}
}
return tlscert;
}
int tls_set_credentials(tls_t *tls, const char *cafilename) int tls_set_credentials(tls_t *tls, const char *cafilename)
{ {
UNUSED(cafilename); int err;
/* set trusted credentials -- takes a .pem filename */ /* set trusted credentials -- takes a .pem filename */
int err = gnutls_certificate_set_x509_system_trust(tls->cred); err = gnutls_certificate_set_x509_trust_file(tls->cred,
if (err >= 0 && tls->conn->tls_cafile) cafilename, GNUTLS_X509_FMT_PEM);
err = gnutls_certificate_set_x509_trust_file(
tls->cred, tls->conn->tls_cafile, GNUTLS_X509_FMT_PEM);
if (err >= 0 && tls->conn->tls_capath)
err = gnutls_certificate_set_x509_trust_dir(
tls->cred, tls->conn->tls_capath, GNUTLS_X509_FMT_PEM);
if (err >= 0) { if (err >= 0) {
err = gnutls_credentials_set(tls->session, GNUTLS_CRD_CERTIFICATE, err = gnutls_credentials_set(tls->session, GNUTLS_CRD_CERTIFICATE,
tls->cred); tls->cred);
@@ -400,9 +92,9 @@ int tls_set_credentials(tls_t *tls, const char *cafilename)
int tls_start(tls_t *tls) int tls_start(tls_t *tls)
{ {
sock_set_blocking(tls->conn->sock); sock_set_blocking(tls->sock);
tls->lasterror = gnutls_handshake(tls->session); tls->lasterror = gnutls_handshake(tls->session);
sock_set_nonblocking(tls->conn->sock); sock_set_nonblocking(tls->sock);
return tls->lasterror == GNUTLS_E_SUCCESS; return tls->lasterror == GNUTLS_E_SUCCESS;
} }
@@ -425,10 +117,10 @@ int tls_is_recoverable(int error)
int tls_pending(tls_t *tls) int tls_pending(tls_t *tls)
{ {
return gnutls_record_check_pending(tls->session); return gnutls_record_check_pending (tls->session);
} }
int tls_read(tls_t *tls, void *buff, size_t len) int tls_read(tls_t *tls, void * const buff, const size_t len)
{ {
int ret; int ret;
@@ -438,7 +130,7 @@ int tls_read(tls_t *tls, void *buff, size_t len)
return ret; return ret;
} }
int tls_write(tls_t *tls, const void *buff, size_t len) int tls_write(tls_t *tls, const void * const buff, const size_t len)
{ {
int ret; int ret;
@@ -450,6 +142,5 @@ int tls_write(tls_t *tls, const void *buff, size_t len)
int tls_clear_pending_write(tls_t *tls) int tls_clear_pending_write(tls_t *tls)
{ {
UNUSED(tls);
return 0; return 0;
} }

View File

@@ -1,7 +1,7 @@
/* tls_openssl.c /* tls_openssl.c
** strophe XMPP client library -- TLS abstraction openssl impl. ** strophe XMPP client library -- TLS abstraction openssl impl.
** **
** Copyright (C) 2005-008 Collecta, Inc. ** Copyright (C) 2005-008 Collecta, Inc.
** **
** This software is provided AS-IS with no warranty, either express ** This software is provided AS-IS with no warranty, either express
** or implied. ** or implied.
@@ -13,7 +13,7 @@
* TLS implementation with OpenSSL. * TLS implementation with OpenSSL.
*/ */
#include <errno.h> /* EINTR */ #include <errno.h> /* EINTR */
#include <string.h> #include <string.h>
#ifndef _WIN32 #ifndef _WIN32
@@ -31,50 +31,11 @@
#include "tls.h" #include "tls.h"
#include "sock.h" #include "sock.h"
/*
* Redefine OPENSSL_VERSION_NUMBER for LibreSSL.
* LibreSSL and OpenSSL use different and incompatible version schemes. Solve
* this issue in the way how nginx project did.
*/
#if (defined LIBRESSL_VERSION_NUMBER && OPENSSL_VERSION_NUMBER == 0x20000000L)
#undef OPENSSL_VERSION_NUMBER
#if (LIBRESSL_VERSION_NUMBER >= 0x2080000fL)
#define OPENSSL_VERSION_NUMBER 0x1010000fL
#elif (LIBRESSL_VERSION_NUMBER >= 0x2070000fL)
#define OPENSSL_VERSION_NUMBER 0x1000200fL
#else
#define OPENSSL_VERSION_NUMBER 0x1000107fL
#endif
#endif
#if OPENSSL_VERSION_NUMBER < 0x10100000L
static const unsigned char *ASN1_STRING_get0_data(ASN1_STRING *asn1)
{
return ASN1_STRING_data(asn1);
}
#endif
#if OPENSSL_VERSION_NUMBER < 0x10000000L
static int GENERAL_NAME_get0_otherName(const GENERAL_NAME *gen,
ASN1_OBJECT **poid,
ASN1_TYPE **pvalue)
{
if (gen->type != GEN_OTHERNAME)
return 0;
if (poid)
*poid = gen->d.otherName->type_id;
if (pvalue)
*pvalue = gen->d.otherName->value;
return 1;
}
#endif
struct _tls { struct _tls {
xmpp_ctx_t *ctx; xmpp_ctx_t *ctx;
sock_t sock; sock_t sock;
SSL_CTX *ssl_ctx; SSL_CTX *ssl_ctx;
SSL *ssl; SSL *ssl;
X509 *client_cert;
int lasterror; int lasterror;
}; };
@@ -85,130 +46,8 @@ enum {
}; };
static void _tls_sock_wait(tls_t *tls, int error); static void _tls_sock_wait(tls_t *tls, int error);
static const char *_tls_error_str(int error, const char **tbl, size_t tbl_size);
static void _tls_set_error(tls_t *tls, int error); static void _tls_set_error(tls_t *tls, int error);
static void _tls_log_error(xmpp_ctx_t *ctx); static void _tls_log_error(xmpp_ctx_t *ctx);
static void _tls_dump_cert_info(tls_t *tls);
static X509 *_tls_cert_read(xmpp_conn_t *conn);
static int _tls_xaddr_nid(void);
static int _tls_xmppaddr_to_string(GENERAL_NAME *name, char **res);
static int _tls_dnsname_to_string(GENERAL_NAME *name, char **res);
static GENERAL_NAMES *_tls_conn_get_names(xmpp_conn_t *conn);
static GENERAL_NAMES *_tls_cert_get_names(X509 *client_cert);
#define TLS_ERROR_STR(error, table) \
_tls_error_str(error, table, ARRAY_SIZE(table))
#define TLS_ERROR_FIELD(x) [x] = #x
const char *tls_errors[] = {
TLS_ERROR_FIELD(SSL_ERROR_NONE),
TLS_ERROR_FIELD(SSL_ERROR_SSL),
TLS_ERROR_FIELD(SSL_ERROR_WANT_READ),
TLS_ERROR_FIELD(SSL_ERROR_WANT_WRITE),
TLS_ERROR_FIELD(SSL_ERROR_WANT_X509_LOOKUP),
TLS_ERROR_FIELD(SSL_ERROR_SYSCALL),
TLS_ERROR_FIELD(SSL_ERROR_ZERO_RETURN),
TLS_ERROR_FIELD(SSL_ERROR_WANT_CONNECT),
TLS_ERROR_FIELD(SSL_ERROR_WANT_ACCEPT),
#ifndef LIBRESSL_VERSION_NUMBER
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
TLS_ERROR_FIELD(SSL_ERROR_WANT_ASYNC),
TLS_ERROR_FIELD(SSL_ERROR_WANT_ASYNC_JOB),
#endif
#if OPENSSL_VERSION_NUMBER >= 0x10101000L
TLS_ERROR_FIELD(SSL_ERROR_WANT_CLIENT_HELLO_CB),
#endif
#endif /* !LIBRESSL_VERSION_NUMBER */
};
const char *cert_errors[] = {
TLS_ERROR_FIELD(X509_V_OK),
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
TLS_ERROR_FIELD(X509_V_ERR_UNSPECIFIED),
#endif
TLS_ERROR_FIELD(X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT),
TLS_ERROR_FIELD(X509_V_ERR_UNABLE_TO_GET_CRL),
TLS_ERROR_FIELD(X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE),
TLS_ERROR_FIELD(X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE),
TLS_ERROR_FIELD(X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY),
TLS_ERROR_FIELD(X509_V_ERR_CERT_SIGNATURE_FAILURE),
TLS_ERROR_FIELD(X509_V_ERR_CRL_SIGNATURE_FAILURE),
TLS_ERROR_FIELD(X509_V_ERR_CERT_NOT_YET_VALID),
TLS_ERROR_FIELD(X509_V_ERR_CERT_HAS_EXPIRED),
TLS_ERROR_FIELD(X509_V_ERR_CRL_NOT_YET_VALID),
TLS_ERROR_FIELD(X509_V_ERR_CRL_HAS_EXPIRED),
TLS_ERROR_FIELD(X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD),
TLS_ERROR_FIELD(X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD),
TLS_ERROR_FIELD(X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD),
TLS_ERROR_FIELD(X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD),
TLS_ERROR_FIELD(X509_V_ERR_OUT_OF_MEM),
TLS_ERROR_FIELD(X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT),
TLS_ERROR_FIELD(X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN),
TLS_ERROR_FIELD(X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY),
TLS_ERROR_FIELD(X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE),
TLS_ERROR_FIELD(X509_V_ERR_CERT_CHAIN_TOO_LONG),
TLS_ERROR_FIELD(X509_V_ERR_CERT_REVOKED),
TLS_ERROR_FIELD(X509_V_ERR_INVALID_CA),
TLS_ERROR_FIELD(X509_V_ERR_PATH_LENGTH_EXCEEDED),
TLS_ERROR_FIELD(X509_V_ERR_INVALID_PURPOSE),
TLS_ERROR_FIELD(X509_V_ERR_CERT_UNTRUSTED),
TLS_ERROR_FIELD(X509_V_ERR_CERT_REJECTED),
TLS_ERROR_FIELD(X509_V_ERR_SUBJECT_ISSUER_MISMATCH),
TLS_ERROR_FIELD(X509_V_ERR_AKID_SKID_MISMATCH),
TLS_ERROR_FIELD(X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH),
TLS_ERROR_FIELD(X509_V_ERR_KEYUSAGE_NO_CERTSIGN),
TLS_ERROR_FIELD(X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER),
TLS_ERROR_FIELD(X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION),
TLS_ERROR_FIELD(X509_V_ERR_KEYUSAGE_NO_CRL_SIGN),
TLS_ERROR_FIELD(X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION),
TLS_ERROR_FIELD(X509_V_ERR_INVALID_NON_CA),
TLS_ERROR_FIELD(X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED),
TLS_ERROR_FIELD(X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE),
TLS_ERROR_FIELD(X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED),
TLS_ERROR_FIELD(X509_V_ERR_INVALID_EXTENSION),
TLS_ERROR_FIELD(X509_V_ERR_INVALID_POLICY_EXTENSION),
TLS_ERROR_FIELD(X509_V_ERR_NO_EXPLICIT_POLICY),
TLS_ERROR_FIELD(X509_V_ERR_APPLICATION_VERIFICATION),
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
TLS_ERROR_FIELD(X509_V_ERR_DIFFERENT_CRL_SCOPE),
TLS_ERROR_FIELD(X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE),
TLS_ERROR_FIELD(X509_V_ERR_UNNESTED_RESOURCE),
TLS_ERROR_FIELD(X509_V_ERR_PERMITTED_VIOLATION),
TLS_ERROR_FIELD(X509_V_ERR_EXCLUDED_VIOLATION),
TLS_ERROR_FIELD(X509_V_ERR_SUBTREE_MINMAX),
TLS_ERROR_FIELD(X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE),
TLS_ERROR_FIELD(X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX),
TLS_ERROR_FIELD(X509_V_ERR_UNSUPPORTED_NAME_SYNTAX),
TLS_ERROR_FIELD(X509_V_ERR_CRL_PATH_VALIDATION_ERROR),
#ifndef LIBRESSL_VERSION_NUMBER
TLS_ERROR_FIELD(X509_V_ERR_SUITE_B_INVALID_VERSION),
TLS_ERROR_FIELD(X509_V_ERR_SUITE_B_INVALID_ALGORITHM),
TLS_ERROR_FIELD(X509_V_ERR_SUITE_B_INVALID_CURVE),
TLS_ERROR_FIELD(X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM),
TLS_ERROR_FIELD(X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED),
TLS_ERROR_FIELD(X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256),
#endif /* !LIBRESSL_VERSION_NUMBER */
TLS_ERROR_FIELD(X509_V_ERR_HOSTNAME_MISMATCH),
TLS_ERROR_FIELD(X509_V_ERR_EMAIL_MISMATCH),
TLS_ERROR_FIELD(X509_V_ERR_IP_ADDRESS_MISMATCH),
#endif /* OPENSSL_VERSION_NUMBER >= 0x10002000L */
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
TLS_ERROR_FIELD(X509_V_ERR_INVALID_CALL),
TLS_ERROR_FIELD(X509_V_ERR_STORE_LOOKUP),
#ifndef LIBRESSL_VERSION_NUMBER
TLS_ERROR_FIELD(X509_V_ERR_PATH_LOOP),
TLS_ERROR_FIELD(X509_V_ERR_DANE_NO_MATCH),
TLS_ERROR_FIELD(X509_V_ERR_EE_KEY_TOO_SMALL),
TLS_ERROR_FIELD(X509_V_ERR_CA_KEY_TOO_SMALL),
TLS_ERROR_FIELD(X509_V_ERR_CA_MD_TOO_WEAK),
TLS_ERROR_FIELD(X509_V_ERR_NO_VALID_SCTS),
TLS_ERROR_FIELD(X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION),
TLS_ERROR_FIELD(X509_V_ERR_OCSP_VERIFY_NEEDED),
TLS_ERROR_FIELD(X509_V_ERR_OCSP_VERIFY_FAILED),
TLS_ERROR_FIELD(X509_V_ERR_OCSP_CERT_UNKNOWN),
#endif /* !LIBRESSL_VERSION_NUMBER */
#endif /* OPENSSL_VERSION_NUMBER >= 0x10100000L */
};
#undef TLS_ERROR_FIELD
void tls_initialize(void) void tls_initialize(void)
{ {
@@ -218,8 +57,6 @@ void tls_initialize(void)
#else #else
OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL); OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL);
#endif #endif
/* init xmppAddr OID */
_tls_xaddr_nid();
} }
void tls_shutdown(void) void tls_shutdown(void)
@@ -230,7 +67,6 @@ void tls_shutdown(void)
* memory rather than cause random crashes of the main program. * memory rather than cause random crashes of the main program.
*/ */
#if OPENSSL_VERSION_NUMBER < 0x10100000L #if OPENSSL_VERSION_NUMBER < 0x10100000L
OBJ_cleanup();
ERR_free_strings(); ERR_free_strings();
EVP_cleanup(); EVP_cleanup();
CRYPTO_cleanup_all_ex_data(); CRYPTO_cleanup_all_ex_data();
@@ -250,281 +86,18 @@ int tls_error(tls_t *tls)
return tls->lasterror; return tls->lasterror;
} }
/** Search through the SubjectAlternativeNames and return the next
* id-on-xmppAddr element starting from `n`.
*/
char *tls_id_on_xmppaddr(xmpp_conn_t *conn, unsigned int n)
{
char *ret = NULL;
int i, j;
GENERAL_NAMES *names = _tls_conn_get_names(conn);
if (!names)
return NULL;
int num_names = sk_GENERAL_NAME_num(names);
for (i = j = 0; i < num_names; ++i) {
char *res;
GENERAL_NAME *name = sk_GENERAL_NAME_value(names, i);
if (name == NULL)
break;
if (_tls_xmppaddr_to_string(name, &res))
continue;
if (j == (int)n) {
xmpp_debug(conn->ctx, "tls", "extracted jid %s from id-on-xmppAddr",
res);
ret = xmpp_strdup(conn->ctx, res);
OPENSSL_free(res);
break;
}
j++;
OPENSSL_free(res);
}
GENERAL_NAMES_free(names);
return ret;
}
unsigned int tls_id_on_xmppaddr_num(xmpp_conn_t *conn)
{
unsigned int ret = 0;
GENERAL_NAMES *names = _tls_conn_get_names(conn);
if (!names)
return 0;
int j, num_names = sk_GENERAL_NAME_num(names);
for (j = 0; j < num_names; ++j) {
GENERAL_NAME *name = sk_GENERAL_NAME_value(names, j);
if (_tls_xmppaddr_to_string(name, NULL))
continue;
ret++;
}
GENERAL_NAMES_free(names);
return ret;
}
static int _convert_ASN1TIME(ASN1_TIME *ansi_time, char *buf, size_t len)
{
BIO *bio = BIO_new(BIO_s_mem());
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;
}
static char *_asn1_time_to_str(const xmpp_ctx_t *ctx, ASN1_TIME *t)
{
char buf[128];
int res = _convert_ASN1TIME(t, buf, sizeof(buf));
if (res) {
return xmpp_strdup(ctx, buf);
}
return NULL;
}
static char *
_get_fingerprint(const xmpp_ctx_t *ctx, X509 *err_cert, xmpp_cert_element_t el)
{
unsigned char buf[EVP_MAX_MD_SIZE];
unsigned int len;
const EVP_MD *digest;
switch (el) {
case XMPP_CERT_FINGERPRINT_SHA1:
digest = EVP_sha1();
break;
case XMPP_CERT_FINGERPRINT_SHA256:
digest = EVP_sha256();
break;
default:
return NULL;
}
if (X509_digest(err_cert, digest, buf, &len) != 0) {
char fingerprint[4 * EVP_MAX_MD_SIZE];
hex_encode(fingerprint, buf, len);
return xmpp_strdup(ctx, fingerprint);
}
return NULL;
}
static char *
_get_alg(const xmpp_ctx_t *ctx, X509 *err_cert, xmpp_cert_element_t el)
{
int rc, alg_nid = NID_undef;
switch (el) {
case XMPP_CERT_KEYALG: {
#if OPENSSL_VERSION_NUMBER < 0x10100000L
alg_nid = OBJ_obj2nid(err_cert->cert_info->key->algor->algorithm);
#else
X509_PUBKEY *pubkey = X509_get_X509_PUBKEY(err_cert);
ASN1_OBJECT *ppkalg = NULL;
rc = X509_PUBKEY_get0_param(&ppkalg, NULL, NULL, NULL, pubkey);
if (rc) {
alg_nid = OBJ_obj2nid(ppkalg);
}
#endif
} break;
case XMPP_CERT_SIGALG: {
#if OPENSSL_VERSION_NUMBER < 0x10100000L
alg_nid = OBJ_obj2nid(err_cert->sig_alg->algorithm);
#else
const X509_ALGOR *palg;
X509_get0_signature(NULL, &palg, err_cert);
alg_nid = OBJ_obj2nid(palg->algorithm);
#endif
} break;
default:
break;
}
if (alg_nid != NID_undef) {
const char *alg = OBJ_nid2ln(alg_nid);
if (alg) {
return xmpp_strdup(ctx, alg);
}
}
return NULL;
}
static xmpp_tlscert_t *_x509_to_tlscert(xmpp_ctx_t *ctx, X509 *cert)
{
char *subject, *issuer, buf[32];
xmpp_tlscert_t *tlscert = tlscert_new(ctx);
if (!tlscert)
return NULL;
BIO *b = BIO_new(BIO_s_mem());
if (!b)
goto ERR_OUT;
PEM_write_bio_X509(b, cert);
BUF_MEM *bptr;
BIO_get_mem_ptr(b, &bptr);
tlscert->pem = xmpp_alloc(ctx, bptr->length + 1);
if (!tlscert->pem)
goto ERR_OUT;
memcpy(tlscert->pem, bptr->data, bptr->length);
tlscert->pem[bptr->length] = '\0';
BIO_free(b);
subject = X509_NAME_oneline(X509_get_subject_name(cert), NULL, 0);
if (!subject)
goto ERR_OUT;
tlscert->elements[XMPP_CERT_SUBJECT] = xmpp_strdup(ctx, subject);
OPENSSL_free(subject);
issuer = X509_NAME_oneline(X509_get_issuer_name(cert), NULL, 0);
if (!issuer)
goto ERR_OUT;
tlscert->elements[XMPP_CERT_ISSUER] = xmpp_strdup(ctx, issuer);
OPENSSL_free(issuer);
tlscert->elements[XMPP_CERT_NOTBEFORE] =
_asn1_time_to_str(ctx, X509_get_notBefore(cert));
tlscert->elements[XMPP_CERT_NOTAFTER] =
_asn1_time_to_str(ctx, X509_get_notAfter(cert));
tlscert->elements[XMPP_CERT_FINGERPRINT_SHA1] =
_get_fingerprint(ctx, cert, XMPP_CERT_FINGERPRINT_SHA1);
tlscert->elements[XMPP_CERT_FINGERPRINT_SHA256] =
_get_fingerprint(ctx, cert, XMPP_CERT_FINGERPRINT_SHA256);
xmpp_snprintf(buf, sizeof(buf), "%ld", X509_get_version(cert) + 1);
tlscert->elements[XMPP_CERT_VERSION] = xmpp_strdup(ctx, buf);
tlscert->elements[XMPP_CERT_KEYALG] = _get_alg(ctx, cert, XMPP_CERT_KEYALG);
tlscert->elements[XMPP_CERT_SIGALG] = _get_alg(ctx, cert, XMPP_CERT_SIGALG);
ASN1_INTEGER *serial = X509_get_serialNumber(cert);
BIGNUM *bn = ASN1_INTEGER_to_BN(serial, NULL);
if (bn) {
char *serialnumber = BN_bn2hex(bn);
if (serialnumber) {
tlscert->elements[XMPP_CERT_SERIALNUMBER] =
xmpp_strdup(ctx, serialnumber);
OPENSSL_free(serialnumber);
}
BN_free(bn);
}
GENERAL_NAMES *names = _tls_cert_get_names(cert);
if (names) {
int j, num_names = sk_GENERAL_NAME_num(names);
size_t n = 0;
for (j = 0; j < num_names; ++j) {
char *res;
GENERAL_NAME *name = sk_GENERAL_NAME_value(names, j);
if (_tls_dnsname_to_string(name, &res))
continue;
if (tlscert_add_dnsname(tlscert, res))
xmpp_debug(ctx, "tls", "Can't store dnsName(%zu): %s", n, res);
n++;
OPENSSL_free(res);
}
GENERAL_NAMES_free(names);
}
return tlscert;
ERR_OUT:
xmpp_tlscert_free(tlscert);
return NULL;
}
static int _tls_verify(int preverify_ok, X509_STORE_CTX *x509_ctx)
{
if (preverify_ok == 1)
return 1;
SSL *ssl = X509_STORE_CTX_get_ex_data(x509_ctx,
SSL_get_ex_data_X509_STORE_CTX_idx());
xmpp_conn_t *conn = SSL_get_app_data(ssl);
if (!conn->certfail_handler) {
xmpp_error(conn->ctx, "tls",
"No certfail handler set, canceling connection attempt");
return 0;
}
X509 *err_cert = X509_STORE_CTX_get_current_cert(x509_ctx);
xmpp_tlscert_t *tlscert = _x509_to_tlscert(conn->ctx, err_cert);
if (!tlscert)
return 0;
xmpp_debug(conn->ctx, "tls", "preverify_ok:%d\nSubject: %s\nIssuer: %s",
preverify_ok, tlscert->elements[XMPP_CERT_SUBJECT],
tlscert->elements[XMPP_CERT_ISSUER]);
int ret = conn->certfail_handler(
tlscert,
X509_verify_cert_error_string(X509_STORE_CTX_get_error(x509_ctx)));
xmpp_tlscert_free(tlscert);
return ret;
}
tls_t *tls_new(xmpp_conn_t *conn) tls_t *tls_new(xmpp_conn_t *conn)
{ {
tls_t *tls = xmpp_alloc(conn->ctx, sizeof(*tls)); tls_t *tls = xmpp_alloc(conn->ctx, sizeof(*tls));
int mode;
if (tls) { if (tls) {
int ret; int ret;
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
/* Hostname verification is supported in OpenSSL 1.0.2 and newer. */
X509_VERIFY_PARAM *param;
#endif
memset(tls, 0, sizeof(*tls)); memset(tls, 0, sizeof(*tls));
tls->ctx = conn->ctx; tls->ctx = conn->ctx;
tls->sock = conn->sock; tls->sock = conn->sock;
#if OPENSSL_VERSION_NUMBER < 0x10100000L
tls->ssl_ctx = SSL_CTX_new(SSLv23_client_method()); tls->ssl_ctx = SSL_CTX_new(SSLv23_client_method());
#else
tls->ssl_ctx = SSL_CTX_new(TLS_client_method());
#endif
if (tls->ssl_ctx == NULL) if (tls->ssl_ctx == NULL)
goto err; goto err;
@@ -536,76 +109,28 @@ tls_t *tls_new(xmpp_conn_t *conn)
SSL_CTX_set_options(tls->ssl_ctx, SSL_OP_NO_SSLv3); /* POODLE */ 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_options(tls->ssl_ctx, SSL_OP_NO_TLSv1); /* BEAST */
if (conn->tls_client_cert && conn->tls_client_key) { SSL_CTX_set_client_cert_cb(tls->ssl_ctx, NULL);
tls->client_cert = _tls_cert_read(conn);
if (!tls->client_cert) {
xmpp_error(tls->ctx, "tls",
"could not read client certificate");
goto err_free_ctx;
}
SSL_CTX_use_certificate_file(tls->ssl_ctx, conn->tls_client_cert,
SSL_FILETYPE_PEM);
SSL_CTX_use_PrivateKey_file(tls->ssl_ctx, conn->tls_client_key,
SSL_FILETYPE_PEM);
} else {
/* If the server asks for a client certificate, don't send one. */
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);
ret = SSL_CTX_set_default_verify_paths(tls->ssl_ctx);
if (ret == 0 && !conn->tls_trust) {
/*
* Returns 1 on success and 0 on failure. A missing default
* location is still treated as a success.
* Ignore errors when XMPP_CONN_FLAG_TRUST_TLS is set.
*/
xmpp_error(tls->ctx, "tls",
"SSL_CTX_set_default_verify_paths() failed");
goto err_free_cert;
}
if (conn->tls_cafile || conn->tls_capath) {
if (SSL_CTX_load_verify_locations(tls->ssl_ctx, conn->tls_cafile,
conn->tls_capath) == 0) {
xmpp_error(tls->ctx, "tls",
"SSL_CTX_load_verify_locations() failed");
_tls_log_error(tls->ctx);
goto err_free_cert;
}
}
tls->ssl = SSL_new(tls->ssl_ctx); tls->ssl = SSL_new(tls->ssl_ctx);
if (tls->ssl == NULL) if (tls->ssl == NULL)
goto err_free_cert; goto err_free_ctx;
#if OPENSSL_VERSION_NUMBER >= 0x0908060L && !defined(OPENSSL_NO_TLSEXT) /* Trust server's certificate when user sets the flag explicitly. */
/* Enable SNI. */ mode = conn->tls_trust ? SSL_VERIFY_NONE : SSL_VERIFY_PEER;
SSL_set_tlsext_host_name(tls->ssl, conn->domain); SSL_set_verify(tls->ssl, mode, 0);
#endif
/* Trust server's certificate when user sets the flag explicitly.
* Otherwise call the verification callback */
if (conn->tls_trust)
SSL_set_verify(tls->ssl, SSL_VERIFY_NONE, NULL);
else
SSL_set_verify(tls->ssl, SSL_VERIFY_PEER, _tls_verify);
SSL_set_app_data(tls->ssl, conn);
#if OPENSSL_VERSION_NUMBER >= 0x10002000L #if OPENSSL_VERSION_NUMBER >= 0x10002000L
/* Hostname verification is supported in OpenSSL 1.0.2 and newer. */ /* Hostname verification is supported in OpenSSL 1.0.2 and newer. */
param = SSL_get0_param(tls->ssl); X509_VERIFY_PARAM *param = SSL_get0_param(tls->ssl);
/* /*
* Allow only complete wildcards. RFC 6125 discourages wildcard usage * Allow only complete wildcards. RFC 6125 discourages wildcard usage
* completely, and lists internationalized domain names as a reason * completely, and lists internationalized domain names as a reason
* against partial wildcards. * against partial wildcards.
* See https://tools.ietf.org/html/rfc6125#section-7.2 for more * See https://tools.ietf.org/html/rfc6125#section-7.2 for more information.
* information.
*/ */
X509_VERIFY_PARAM_set_hostflags(param, X509_VERIFY_PARAM_set_hostflags(param, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
X509_VERIFY_PARAM_set1_host(param, conn->domain, 0); X509_VERIFY_PARAM_set1_host(param, conn->domain, 0);
#endif #endif
@@ -618,8 +143,6 @@ tls_t *tls_new(xmpp_conn_t *conn)
err_free_ssl: err_free_ssl:
SSL_free(tls->ssl); SSL_free(tls->ssl);
err_free_cert:
X509_free(tls->client_cert);
err_free_ctx: err_free_ctx:
SSL_CTX_free(tls->ssl_ctx); SSL_CTX_free(tls->ssl_ctx);
err: err:
@@ -631,28 +154,12 @@ err:
void tls_free(tls_t *tls) void tls_free(tls_t *tls)
{ {
SSL_free(tls->ssl); SSL_free(tls->ssl);
X509_free(tls->client_cert);
SSL_CTX_free(tls->ssl_ctx); SSL_CTX_free(tls->ssl_ctx);
xmpp_free(tls->ctx, tls); xmpp_free(tls->ctx, tls);
} }
xmpp_tlscert_t *tls_peer_cert(xmpp_conn_t *conn)
{
if (conn && conn->tls && conn->tls->ssl) {
X509 *cert = SSL_get_peer_certificate(conn->tls->ssl);
if (cert) {
xmpp_tlscert_t *tlscert = _x509_to_tlscert(conn->ctx, cert);
X509_free(cert);
return tlscert;
}
}
return NULL;
}
int tls_set_credentials(tls_t *tls, const char *cafilename) int tls_set_credentials(tls_t *tls, const char *cafilename)
{ {
UNUSED(tls);
UNUSED(cafilename);
return -1; return -1;
} }
@@ -679,16 +186,8 @@ int tls_start(tls_t *tls)
} }
x509_res = SSL_get_verify_result(tls->ssl); x509_res = SSL_get_verify_result(tls->ssl);
if (x509_res == X509_V_OK) { xmpp_debug(tls->ctx, "tls", "Certificate verification %s",
xmpp_debug(tls->ctx, "tls", "Certificate verification passed"); x509_res == X509_V_OK ? "passed" : "FAILED");
} else {
xmpp_debug(tls->ctx, "tls",
"Certificate verification FAILED, result=%s(%ld)",
TLS_ERROR_STR((int)x509_res, cert_errors), x509_res);
if (ret > 0)
xmpp_debug(tls->ctx, "tls", "User decided to connect anyways");
}
_tls_dump_cert_info(tls);
_tls_set_error(tls, error); _tls_set_error(tls, error);
return ret <= 0 ? 0 : 1; return ret <= 0 ? 0 : 1;
@@ -700,11 +199,6 @@ int tls_stop(tls_t *tls)
int error; int error;
int ret; int ret;
/* According to OpenSSL.org, we must not call SSL_shutdown(3)
if a previous fatal error has occurred on a connection. */
if (tls->lasterror == SSL_ERROR_SYSCALL || tls->lasterror == SSL_ERROR_SSL)
return 1;
while (1) { while (1) {
++retries; ++retries;
ret = SSL_shutdown(tls->ssl); ret = SSL_shutdown(tls->ssl);
@@ -715,14 +209,6 @@ int tls_stop(tls_t *tls)
} }
_tls_sock_wait(tls, error); _tls_sock_wait(tls, error);
} }
if (error == SSL_ERROR_SYSCALL && errno == 0) {
/*
* Handle special case when peer closes connection instead of
* proper shutdown.
*/
error = 0;
ret = 1;
}
_tls_set_error(tls, error); _tls_set_error(tls, error);
return ret <= 0 ? 0 : 1; return ret <= 0 ? 0 : 1;
@@ -730,9 +216,10 @@ int tls_stop(tls_t *tls)
int tls_is_recoverable(int error) int tls_is_recoverable(int error)
{ {
return (error == SSL_ERROR_NONE || error == SSL_ERROR_WANT_READ || return (error == SSL_ERROR_NONE || error == SSL_ERROR_WANT_READ
error == SSL_ERROR_WANT_WRITE || error == SSL_ERROR_WANT_CONNECT || || error == SSL_ERROR_WANT_WRITE
error == SSL_ERROR_WANT_ACCEPT); || error == SSL_ERROR_WANT_CONNECT
|| error == SSL_ERROR_WANT_ACCEPT);
} }
int tls_pending(tls_t *tls) int tls_pending(tls_t *tls)
@@ -740,7 +227,7 @@ int tls_pending(tls_t *tls)
return SSL_pending(tls->ssl); return SSL_pending(tls->ssl);
} }
int tls_read(tls_t *tls, void *buff, size_t len) int tls_read(tls_t *tls, void * const buff, const size_t len)
{ {
int ret; int ret;
@@ -750,7 +237,7 @@ int tls_read(tls_t *tls, void *buff, size_t len)
return ret; return ret;
} }
int tls_write(tls_t *tls, const void *buff, size_t len) int tls_write(tls_t *tls, const void * const buff, const size_t len)
{ {
int ret; int ret;
@@ -762,7 +249,6 @@ int tls_write(tls_t *tls, const void *buff, size_t len)
int tls_clear_pending_write(tls_t *tls) int tls_clear_pending_write(tls_t *tls)
{ {
UNUSED(tls);
return 0; return 0;
} }
@@ -774,18 +260,14 @@ static void _tls_sock_wait(tls_t *tls, int error)
int nfds; int nfds;
int ret; int ret;
if (error == SSL_ERROR_NONE)
return;
FD_ZERO(&rfds); FD_ZERO(&rfds);
FD_ZERO(&wfds); FD_ZERO(&wfds);
if (error == SSL_ERROR_WANT_READ) if (error == SSL_ERROR_WANT_READ)
FD_SET(tls->sock, &rfds); FD_SET(tls->sock, &rfds);
if (error == SSL_ERROR_WANT_WRITE) if (error == SSL_ERROR_WANT_WRITE)
FD_SET(tls->sock, &wfds); FD_SET(tls->sock, &wfds);
nfds = (error == SSL_ERROR_WANT_READ || error == SSL_ERROR_WANT_WRITE) nfds = (error == SSL_ERROR_WANT_READ || error == SSL_ERROR_WANT_WRITE) ?
? tls->sock + 1 tls->sock + 1 : 0;
: 0;
do { do {
tv.tv_sec = TLS_TIMEOUT_SEC; tv.tv_sec = TLS_TIMEOUT_SEC;
tv.tv_usec = TLS_TIMEOUT_USEC; tv.tv_usec = TLS_TIMEOUT_USEC;
@@ -793,16 +275,9 @@ static void _tls_sock_wait(tls_t *tls, int error)
} while (ret == -1 && errno == EINTR); } while (ret == -1 && errno == EINTR);
} }
static const char *_tls_error_str(int error, const char **tbl, size_t tbl_size)
{
return (error >= 0 && (size_t)error < tbl_size) ? tbl[error] : "UNKNOWN";
}
static void _tls_set_error(tls_t *tls, int error) static void _tls_set_error(tls_t *tls, int error)
{ {
if (error != 0 && !tls_is_recoverable(error)) { if (error != 0 && !tls_is_recoverable(error)) {
xmpp_debug(tls->ctx, "tls", "error=%s(%d) errno=%d",
TLS_ERROR_STR(error, tls_errors), error, errno);
_tls_log_error(tls->ctx); _tls_log_error(tls->ctx);
} }
tls->lasterror = error; tls->lasterror = error;
@@ -821,134 +296,3 @@ static void _tls_log_error(xmpp_ctx_t *ctx)
} }
} while (e != 0); } while (e != 0);
} }
static void _tls_dump_cert_info(tls_t *tls)
{
X509 *cert;
char *name;
cert = SSL_get_peer_certificate(tls->ssl);
if (cert == NULL)
xmpp_debug(tls->ctx, "tls", "Certificate was not presented by peer");
else {
name = X509_NAME_oneline(X509_get_subject_name(cert), NULL, 0);
if (name != NULL) {
xmpp_debug(tls->ctx, "tls", "Subject=%s", name);
OPENSSL_free(name);
}
name = X509_NAME_oneline(X509_get_issuer_name(cert), NULL, 0);
if (name != NULL) {
xmpp_debug(tls->ctx, "tls", "Issuer=%s", name);
OPENSSL_free(name);
}
X509_free(cert);
}
}
static X509 *_tls_cert_read(xmpp_conn_t *conn)
{
if (conn->tls && conn->tls->client_cert)
return conn->tls->client_cert;
BIO *f = BIO_new_file(conn->tls_client_cert, "r");
if (!f) {
xmpp_debug(conn->ctx, "tls", "f == NULL");
return NULL;
}
X509 *c = PEM_read_bio_X509(f, NULL, NULL, NULL);
BIO_free(f);
if (!c) {
unsigned long error;
while ((error = ERR_get_error()) != 0) {
xmpp_debug(conn->ctx, "tls", "c == NULL: %s",
ERR_error_string(error, NULL));
}
}
return c;
}
static int _tls_xaddr_nid(void)
{
static int xaddr_nid = NID_undef;
if (xaddr_nid == NID_undef) {
xaddr_nid = OBJ_sn2nid("id-on-xmppAddr");
}
if (xaddr_nid == NID_undef) {
xaddr_nid = OBJ_create("1.3.6.1.5.5.7.8.5", "id-on-xmppAddr",
"XmppAddr Identifier");
}
return xaddr_nid;
}
static GENERAL_NAMES *_tls_conn_get_names(xmpp_conn_t *conn)
{
X509 *client_cert;
GENERAL_NAMES *names = NULL;
client_cert = _tls_cert_read(conn);
if (!client_cert)
return NULL;
names = _tls_cert_get_names(client_cert);
if (!conn->tls || !conn->tls->client_cert)
X509_free(client_cert);
return names;
}
static GENERAL_NAMES *_tls_cert_get_names(X509 *client_cert)
{
int san = X509_get_ext_by_NID(client_cert, NID_subject_alt_name, 0);
X509_EXTENSION *san_ext = X509_get_ext(client_cert, san);
if (!san_ext)
return NULL;
ASN1_OCTET_STRING *data = X509_EXTENSION_get_data(san_ext);
if (!data)
return NULL;
const unsigned char *d = ASN1_STRING_get0_data(data);
if (!d)
return NULL;
return d2i_GENERAL_NAMES(NULL, &d, ASN1_STRING_length(data));
}
/** Convert GENERAL_NAME* to a string
*
* This checks whether the GENERAL_NAME* that is given has the
* correct id-on-xmppAddr set and then optionally converts this
* form ASN.1 to a string/char*.
*
* When `res` pointer is set to NULL this method doesn't allocate
* the result but only checks whether it is in the correct format.
*
* @param name Pointer to the GENERAL_NAME that shall be converted
* @param res Result-pointer (optional, can be NULL)
*
* @return classic Unix style - 0=success, 1=error
*/
static int _tls_xmppaddr_to_string(GENERAL_NAME *name, char **res)
{
ASN1_OBJECT *oid;
ASN1_TYPE *val;
if (!name || name->type != GEN_OTHERNAME)
return 1;
if (GENERAL_NAME_get0_otherName(name, &oid, &val) == 0)
return 1;
if (OBJ_obj2nid(oid) != _tls_xaddr_nid() || !val)
return 1;
if (!res)
return 0;
if (ASN1_STRING_to_UTF8((unsigned char **)res, val->value.asn1_string) < 0)
return 1;
return 0;
}
static int _tls_dnsname_to_string(GENERAL_NAME *name, char **res)
{
ASN1_STRING *str;
if (!name || name->type != GEN_DNS)
return 1;
str = GENERAL_NAME_get0_value(name, NULL);
if (str == NULL)
return 1;
if (!res)
return 0;
if (ASN1_STRING_to_UTF8((unsigned char **)res, str) < 0)
return 1;
return 0;
}

View File

@@ -1,7 +1,7 @@
/* tls_schannel.c /* tls_schannel.c
** strophe XMPP client library -- TLS abstraction schannel impl. ** strophe XMPP client library -- TLS abstraction schannel impl.
** **
** Copyright (C) 2005-2009 Collecta, Inc. ** Copyright (C) 2005-2009 Collecta, Inc.
** **
** This software is provided AS-IS with no warranty, either express ** This software is provided AS-IS with no warranty, either express
** or implied. ** or implied.
@@ -61,21 +61,6 @@ void tls_shutdown(void)
return; return;
} }
char *tls_id_on_xmppaddr(xmpp_conn_t *conn, unsigned int n)
{
UNUSED(n);
/* always fail */
xmpp_error(conn->ctx, "tls", "Client-Authentication not implemented");
return NULL;
}
unsigned int tls_id_on_xmppaddr_num(xmpp_conn_t *conn)
{
/* always fail */
xmpp_error(conn->ctx, "tls", "Client-Authentication not implemented");
return 0;
}
tls_t *tls_new(xmpp_conn_t *conn) tls_t *tls_new(xmpp_conn_t *conn)
{ {
xmpp_ctx_t *ctx = conn->ctx; xmpp_ctx_t *ctx = conn->ctx;
@@ -99,13 +84,13 @@ tls_t *tls_new(xmpp_conn_t *conn)
/* no TLS support on win9x/me, despite what anyone says */ /* no TLS support on win9x/me, despite what anyone says */
if (osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) { if (osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
return NULL; return NULL;
} }
tls = xmpp_alloc(ctx, sizeof(*tls)); tls = xmpp_alloc(ctx, sizeof(*tls));
if (!tls) { if (!tls) {
return NULL; return NULL;
} }
memset(tls, 0, sizeof(*tls)); memset(tls, 0, sizeof(*tls));
@@ -113,29 +98,30 @@ tls_t *tls_new(xmpp_conn_t *conn)
tls->conn = conn; tls->conn = conn;
tls->sock = sock; tls->sock = sock;
if (!(tls->hsec32 = LoadLibrary("secur32.dll"))) { if (!(tls->hsec32 = LoadLibrary ("secur32.dll"))) {
tls_free(tls); tls_free(tls);
return NULL; return NULL;
} }
if (!(pInitSecurityInterface = if (!(pInitSecurityInterface =
(void *)GetProcAddress(tls->hsec32, "InitSecurityInterfaceA"))) { (void *)GetProcAddress(tls->hsec32, "InitSecurityInterfaceA"))) {
tls_free(tls); tls_free(tls);
return NULL; return NULL;
} }
tls->sft = pInitSecurityInterface(); tls->sft = pInitSecurityInterface();
if (!tls->sft) { if (!tls->sft) {
tls_free(tls); tls_free(tls);
return NULL; return NULL;
} }
ret = tls->sft->QuerySecurityPackageInfo(UNISP_NAME, &(tls->spi)); ret = tls->sft->QuerySecurityPackageInfo(UNISP_NAME, &(tls->spi));
if (ret != SEC_E_OK) { if (ret != SEC_E_OK)
tls_free(tls); {
return NULL; tls_free(tls);
return NULL;
} }
xmpp_debug(ctx, "TLSS", "QuerySecurityPackageInfo() success"); xmpp_debug(ctx, "TLSS", "QuerySecurityPackageInfo() success");
@@ -154,13 +140,13 @@ tls_t *tls_new(xmpp_conn_t *conn)
(void)algs; (void)algs;
#endif #endif
ret = tls->sft->AcquireCredentialsHandleA( ret = tls->sft->AcquireCredentialsHandleA(NULL, UNISP_NAME,
NULL, UNISP_NAME, SECPKG_CRED_OUTBOUND, NULL, &scred, NULL, NULL, SECPKG_CRED_OUTBOUND, NULL, &scred, NULL, NULL, &(tls->hcred), NULL);
&(tls->hcred), NULL);
if (ret != SEC_E_OK) { if (ret != SEC_E_OK)
tls_free(tls); {
return NULL; tls_free(tls);
return NULL;
} }
xmpp_debug(ctx, "TLSS", "AcquireCredentialsHandle() success"); xmpp_debug(ctx, "TLSS", "AcquireCredentialsHandle() success");
@@ -169,25 +155,25 @@ tls_t *tls_new(xmpp_conn_t *conn)
/* This bunch of queries should trip up wine until someone fixes /* This bunch of queries should trip up wine until someone fixes
* schannel support there */ * schannel support there */
ret = tls->sft->QueryCredentialsAttributes( ret = tls->sft->QueryCredentialsAttributes(&(tls->hcred), SECPKG_ATTR_SUPPORTED_ALGS, &spc_sa);
&(tls->hcred), SECPKG_ATTR_SUPPORTED_ALGS, &spc_sa); if (ret != SEC_E_OK)
if (ret != SEC_E_OK) { {
tls_free(tls); tls_free(tls);
return NULL; return NULL;
} }
ret = tls->sft->QueryCredentialsAttributes( ret = tls->sft->QueryCredentialsAttributes(&(tls->hcred), SECPKG_ATTR_CIPHER_STRENGTHS, &spc_cs);
&(tls->hcred), SECPKG_ATTR_CIPHER_STRENGTHS, &spc_cs); if (ret != SEC_E_OK)
if (ret != SEC_E_OK) { {
tls_free(tls); tls_free(tls);
return NULL; return NULL;
} }
ret = tls->sft->QueryCredentialsAttributes( ret = tls->sft->QueryCredentialsAttributes(&(tls->hcred), SECPKG_ATTR_SUPPORTED_PROTOCOLS, &spc_sp);
&(tls->hcred), SECPKG_ATTR_SUPPORTED_PROTOCOLS, &spc_sp); if (ret != SEC_E_OK)
if (ret != SEC_E_OK) { {
tls_free(tls); tls_free(tls);
return NULL; return NULL;
} }
return tls; return tls;
@@ -196,43 +182,34 @@ tls_t *tls_new(xmpp_conn_t *conn)
void tls_free(tls_t *tls) void tls_free(tls_t *tls)
{ {
if (tls->recvbuffer) { if (tls->recvbuffer) {
xmpp_free(tls->ctx, tls->recvbuffer); xmpp_free(tls->ctx, tls->recvbuffer);
} }
if (tls->readybuffer) { if (tls->readybuffer) {
xmpp_free(tls->ctx, tls->readybuffer); xmpp_free(tls->ctx, tls->readybuffer);
} }
if (tls->sendbuffer) { if (tls->sendbuffer) {
xmpp_free(tls->ctx, tls->sendbuffer); xmpp_free(tls->ctx, tls->sendbuffer);
} }
if (tls->init) { if (tls->init) {
tls->sft->FreeCredentialsHandle(&(tls->hcred)); tls->sft->FreeCredentialsHandle(&(tls->hcred));
} }
tls->sft = NULL; tls->sft = NULL;
if (tls->hsec32) { if (tls->hsec32) {
FreeLibrary(tls->hsec32); FreeLibrary(tls->hsec32);
tls->hsec32 = NULL; tls->hsec32 = NULL;
} }
xmpp_free(tls->ctx, tls); xmpp_free(tls->ctx, tls);
return; return;
} }
xmpp_tlscert_t *tls_peer_cert(xmpp_conn_t *conn)
{
/* always fail */
xmpp_error(conn->ctx, "tls", "tls_peer_cert() not implemented");
return NULL;
}
int tls_set_credentials(tls_t *tls, const char *cafilename) int tls_set_credentials(tls_t *tls, const char *cafilename)
{ {
UNUSED(tls);
UNUSED(cafilename);
return -1; return -1;
} }
@@ -248,10 +225,10 @@ int tls_start(tls_t *tls)
/* use the domain there as our name */ /* use the domain there as our name */
name = tls->conn->domain; name = tls->conn->domain;
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
ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM | | ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM
ISC_REQ_MANUAL_CRED_VALIDATION | ISC_REQ_INTEGRITY; | ISC_REQ_MANUAL_CRED_VALIDATION | ISC_REQ_INTEGRITY;
memset(&(sbout[0]), 0, sizeof(sbout[0])); memset(&(sbout[0]), 0, sizeof(sbout[0]));
sbout[0].BufferType = SECBUFFER_TOKEN; sbout[0].BufferType = SECBUFFER_TOKEN;
@@ -274,134 +251,132 @@ int tls_start(tls_t *tls)
sbdin.cBuffers = 2; sbdin.cBuffers = 2;
sbdin.pBuffers = sbin; sbdin.pBuffers = sbin;
ret = tls->sft->InitializeSecurityContextA( ret = tls->sft->InitializeSecurityContextA(&(tls->hcred), NULL, name, ctxtreq, 0, 0,
&(tls->hcred), NULL, name, ctxtreq, 0, 0, NULL, 0, &(tls->hctxt), NULL, 0, &(tls->hctxt), &sbdout,
&sbdout, &ctxtattr, NULL); &ctxtattr, NULL);
unsigned char *p = sbin[0].pvBuffer; while (ret == SEC_I_CONTINUE_NEEDED
int len = 0; || ret == SEC_I_INCOMPLETE_CREDENTIALS) {
unsigned char *p = sbin[0].pvBuffer;
int len = 0, inbytes = 0;
while (ret == SEC_I_CONTINUE_NEEDED || if (sbdout.pBuffers[0].cbBuffer) {
ret == SEC_I_INCOMPLETE_CREDENTIALS || unsigned char *writebuff = sbdout.pBuffers[0].pvBuffer;
ret == SEC_E_INCOMPLETE_MESSAGE) { unsigned int writelen = sbdout.pBuffers[0].cbBuffer;
int inbytes = 0;
if (ret != SEC_E_INCOMPLETE_MESSAGE) { sent = sock_write(tls->sock, writebuff, writelen);
len = 0; if (sent == -1) {
p = sbin[0].pvBuffer; tls->lasterror = sock_error();
} }
else
{
writebuff += sent;
writelen -= sent;
}
tls->sft->FreeContextBuffer(sbdout.pBuffers[0].pvBuffer);
sbdout.pBuffers[0].pvBuffer = NULL;
sbdout.pBuffers[0].cbBuffer = 0;
}
if (sbdout.pBuffers[0].cbBuffer) { /* poll for a bit until the remote server stops sending data, ie it
unsigned char *writebuff = sbdout.pBuffers[0].pvBuffer; * finishes sending the token */
unsigned int writelen = sbdout.pBuffers[0].cbBuffer; inbytes = 1;
{
fd_set fds;
struct timeval tv;
sent = sock_write(tls->sock, writebuff, writelen); tv.tv_sec = 2;
if (sent == -1) { tv.tv_usec = 0;
tls->lasterror = sock_error();
} else {
writebuff += sent;
writelen -= sent;
}
tls->sft->FreeContextBuffer(sbdout.pBuffers[0].pvBuffer);
sbdout.pBuffers[0].pvBuffer = NULL;
sbdout.pBuffers[0].cbBuffer = 0;
}
/* poll for a bit until the remote server stops sending data, ie it FD_ZERO(&fds);
* finishes sending the token */ FD_SET(tls->sock, &fds);
inbytes = 1;
{ select(tls->sock, &fds, NULL, NULL, &tv);
fd_set fds; }
struct timeval tv;
tv.tv_sec = 2; while (inbytes > 0) {
tv.tv_usec = 0; fd_set fds;
struct timeval tv;
FD_ZERO(&fds); tv.tv_sec = 0;
FD_SET(tls->sock, &fds); tv.tv_usec = 1000;
select(tls->sock, &fds, NULL, NULL, &tv); FD_ZERO(&fds);
} FD_SET(tls->sock, &fds);
select(tls->sock, &fds, NULL, NULL, &tv);
while (inbytes > 0) { inbytes = sock_read(tls->sock, p, tls->spi->cbMaxToken - len);
fd_set fds;
struct timeval tv;
tv.tv_sec = 0; if (inbytes > 0) {
tv.tv_usec = 1000; len += inbytes;
p += inbytes;
}
else
{
tls->lasterror = sock_error();
}
FD_ZERO(&fds); }
FD_SET(tls->sock, &fds);
select(tls->sock, &fds, NULL, NULL, &tv); sbin[0].cbBuffer = len;
inbytes = sock_read(tls->sock, p, tls->spi->cbMaxToken - len); ret = tls->sft->InitializeSecurityContextA(&(tls->hcred), &(tls->hctxt), name,
ctxtreq, 0, 0, &sbdin, 0,
if (inbytes > 0) { &(tls->hctxt), &sbdout,
len += inbytes; &ctxtattr, NULL);
p += inbytes;
} else {
tls->lasterror = sock_error();
}
}
sbin[0].cbBuffer = len;
ret = tls->sft->InitializeSecurityContextA(
&(tls->hcred), &(tls->hctxt), name, ctxtreq, 0, 0, &sbdin, 0,
&(tls->hctxt), &sbdout, &ctxtattr, NULL);
} }
if (ret == SEC_E_OK) { if (ret == SEC_E_OK) {
if (sbdout.pBuffers[0].cbBuffer) { if (sbdout.pBuffers[0].cbBuffer) {
unsigned char *writebuff = sbdout.pBuffers[0].pvBuffer; unsigned char *writebuff = sbdout.pBuffers[0].pvBuffer;
unsigned int writelen = sbdout.pBuffers[0].cbBuffer; unsigned int writelen = sbdout.pBuffers[0].cbBuffer;
sent = sock_write(tls->sock, writebuff, writelen); sent = sock_write(tls->sock, writebuff, writelen);
if (sent == -1) { if (sent == -1) {
tls->lasterror = sock_error(); tls->lasterror = sock_error();
} else { }
writebuff += sent; else
writelen -= sent; {
} writebuff += sent;
tls->sft->FreeContextBuffer(sbdout.pBuffers[0].pvBuffer); writelen -= sent;
sbdout.pBuffers[0].pvBuffer = NULL; }
sbdout.pBuffers[0].cbBuffer = 0; tls->sft->FreeContextBuffer(sbdout.pBuffers[0].pvBuffer);
} sbdout.pBuffers[0].pvBuffer = NULL;
sbdout.pBuffers[0].cbBuffer = 0;
}
} }
xmpp_free(tls->ctx, sbin[0].pvBuffer); xmpp_free(tls->ctx, sbin[0].pvBuffer);
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", xmpp_error(tls->ctx, "TLSS", "Schannel error 0x%lx", (unsigned long)ret);
(unsigned long)ret); return 0;
return 0;
} }
tls->sft->QueryContextAttributes(&(tls->hctxt), SECPKG_ATTR_STREAM_SIZES, tls->sft->QueryContextAttributes(&(tls->hctxt), SECPKG_ATTR_STREAM_SIZES,
&(tls->spcss)); &(tls->spcss));
tls->recvbuffermaxlen = tls->spcss.cbHeader + tls->spcss.cbMaximumMessage + tls->recvbuffermaxlen = tls->spcss.cbHeader + tls->spcss.cbMaximumMessage
tls->spcss.cbTrailer; + tls->spcss.cbTrailer;
tls->recvbuffer = xmpp_alloc(tls->ctx, tls->recvbuffermaxlen); tls->recvbuffer = xmpp_alloc(tls->ctx, tls->recvbuffermaxlen);
tls->recvbufferpos = 0; tls->recvbufferpos = 0;
tls->sendbuffermaxlen = tls->spcss.cbHeader + tls->spcss.cbMaximumMessage + tls->sendbuffermaxlen = tls->spcss.cbHeader + tls->spcss.cbMaximumMessage
tls->spcss.cbTrailer; + tls->spcss.cbTrailer;
tls->sendbuffer = xmpp_alloc(tls->ctx, tls->sendbuffermaxlen); tls->sendbuffer = xmpp_alloc(tls->ctx, tls->sendbuffermaxlen);
tls->sendbufferpos = 0; tls->sendbufferpos = 0;
tls->sendbufferlen = 0; tls->sendbufferlen = 0;
tls->readybuffer = xmpp_alloc(tls->ctx, tls->spcss.cbMaximumMessage); tls->readybuffer = xmpp_alloc(tls->ctx, tls->spcss.cbMaximumMessage);
tls->readybufferpos = 0; tls->readybufferpos = 0;
tls->readybufferlen = 0; tls->readybufferlen = 0;
return 1; return 1;
} }
int tls_stop(tls_t *tls) int tls_stop(tls_t *tls)
{ {
UNUSED(tls);
return -1; return -1;
} }
@@ -412,67 +387,67 @@ int tls_error(tls_t *tls)
int tls_is_recoverable(int error) int tls_is_recoverable(int error)
{ {
return (error == SEC_E_OK || error == SEC_E_INCOMPLETE_MESSAGE || return (error == SEC_E_OK || error == SEC_E_INCOMPLETE_MESSAGE
error == WSAEWOULDBLOCK || error == WSAEMSGSIZE || || error == WSAEWOULDBLOCK || error == WSAEMSGSIZE
error == WSAEINPROGRESS); || error == WSAEINPROGRESS);
} }
int tls_pending(tls_t *tls) int tls_pending(tls_t *tls) {
{ // There are 3 cases:
// There are 3 cases: // - there is data in ready buffer, so it is by default pending
// - there is data in ready buffer, so it is by default pending // - there is data in recv buffer. If it is not decrypted yet, means it
// - there is data in recv buffer. If it is not decrypted yet, means it // was incomplete. This should be processed again only if there is data
// was incomplete. This should be processed again only if there is data // on the physical connection
// on the physical connection // - there is data on the physical connection. This case is treated
// - there is data on the physical connection. This case is treated // outside the tls (in event.c)
// outside the tls (in event.c)
if (tls->readybufferpos < tls->readybufferlen) { if (tls->readybufferpos < tls->readybufferlen) {
return tls->readybufferlen - tls->readybufferpos; return tls->readybufferlen - tls->readybufferpos;
} }
return 0; return 0;
} }
int tls_read(tls_t *tls, void *buff, size_t len) int tls_read(tls_t *tls, void * const buff, const size_t len)
{ {
int bytes; int bytes;
/* first, if we've got some ready data, put that in the buffer */ /* first, if we've got some ready data, put that in the buffer */
if (tls->readybufferpos < tls->readybufferlen) { if (tls->readybufferpos < tls->readybufferlen)
if (len < tls->readybufferlen - tls->readybufferpos) { {
bytes = len; if (len < tls->readybufferlen - tls->readybufferpos) {
} else { bytes = len;
bytes = tls->readybufferlen - tls->readybufferpos; } else {
} bytes = tls->readybufferlen - tls->readybufferpos;
}
memcpy(buff, tls->readybuffer + tls->readybufferpos, bytes); memcpy(buff, tls->readybuffer + tls->readybufferpos, bytes);
if (len < tls->readybufferlen - tls->readybufferpos) { if (len < tls->readybufferlen - tls->readybufferpos) {
tls->readybufferpos += bytes; tls->readybufferpos += bytes;
return bytes; return bytes;
} else { } else {
unsigned char *newbuff = buff; unsigned char *newbuff = buff;
int read; int read;
tls->readybufferpos += bytes; tls->readybufferpos += bytes;
newbuff += bytes; newbuff += bytes;
read = tls_read(tls, newbuff, len - bytes); read = tls_read(tls, newbuff, len - bytes);
if (read == -1) { if (read == -1) {
if (tls_is_recoverable(tls->lasterror)) { if (tls_is_recoverable(tls->lasterror)) {
return bytes; return bytes;
} }
return -1; return -1;
} }
return bytes + read; return bytes + read;
} }
} }
/* next, top up our recv buffer */ /* next, top up our recv buffer */
bytes = sock_read(tls->sock, tls->recvbuffer + tls->recvbufferpos, bytes = sock_read(tls->sock, tls->recvbuffer + tls->recvbufferpos,
tls->recvbuffermaxlen - tls->recvbufferpos); tls->recvbuffermaxlen - tls->recvbufferpos);
if (bytes == 0) { if (bytes == 0) {
tls->lasterror = WSAECONNRESET; tls->lasterror = WSAECONNRESET;
@@ -480,75 +455,76 @@ int tls_read(tls_t *tls, void *buff, size_t len)
} }
if (bytes == -1) { if (bytes == -1) {
if (!tls_is_recoverable(sock_error())) { if (!tls_is_recoverable(sock_error())) {
tls->lasterror = sock_error(); tls->lasterror = sock_error();
return -1; return -1;
} }
} }
if (bytes > 0) { if (bytes > 0) {
tls->recvbufferpos += bytes; tls->recvbufferpos += bytes;
} }
/* next, try to decrypt the recv buffer */ /* next, try to decrypt the recv buffer */
if (tls->recvbufferpos > 0) { if (tls->recvbufferpos > 0) {
SecBufferDesc sbddec; SecBufferDesc sbddec;
SecBuffer sbdec[4]; SecBuffer sbdec[4];
int ret; int ret;
memset(&sbddec, 0, sizeof(sbddec)); memset(&sbddec, 0, sizeof(sbddec));
sbddec.ulVersion = SECBUFFER_VERSION; sbddec.ulVersion = SECBUFFER_VERSION;
sbddec.cBuffers = 4; sbddec.cBuffers = 4;
sbddec.pBuffers = sbdec; sbddec.pBuffers = sbdec;
memset(&(sbdec[0]), 0, sizeof(sbdec[0])); memset(&(sbdec[0]), 0, sizeof(sbdec[0]));
sbdec[0].BufferType = SECBUFFER_DATA; sbdec[0].BufferType = SECBUFFER_DATA;
sbdec[0].pvBuffer = tls->recvbuffer; sbdec[0].pvBuffer = tls->recvbuffer;
sbdec[0].cbBuffer = tls->recvbufferpos; sbdec[0].cbBuffer = tls->recvbufferpos;
memset(&(sbdec[1]), 0, sizeof(sbdec[1])); memset(&(sbdec[1]), 0, sizeof(sbdec[1]));
sbdec[1].BufferType = SECBUFFER_EMPTY; sbdec[1].BufferType = SECBUFFER_EMPTY;
memset(&(sbdec[2]), 0, sizeof(sbdec[2])); memset(&(sbdec[2]), 0, sizeof(sbdec[2]));
sbdec[2].BufferType = SECBUFFER_EMPTY; sbdec[2].BufferType = SECBUFFER_EMPTY;
memset(&(sbdec[3]), 0, sizeof(sbdec[3])); memset(&(sbdec[3]), 0, sizeof(sbdec[3]));
sbdec[3].BufferType = SECBUFFER_EMPTY; sbdec[3].BufferType = SECBUFFER_EMPTY;
ret = tls->sft->DecryptMessage(&(tls->hctxt), &sbddec, 0, NULL); ret = tls->sft->DecryptMessage(&(tls->hctxt), &sbddec, 0, NULL);
if (ret == SEC_E_OK) { if (ret == SEC_E_OK) {
memcpy(tls->readybuffer, sbdec[1].pvBuffer, sbdec[1].cbBuffer); memcpy(tls->readybuffer, sbdec[1].pvBuffer, sbdec[1].cbBuffer);
tls->readybufferpos = 0; tls->readybufferpos = 0;
tls->readybufferlen = sbdec[1].cbBuffer; tls->readybufferlen = sbdec[1].cbBuffer;
/* have we got some data left over? If so, copy it to the start /* have we got some data left over? If so, copy it to the start
* of the recv buffer */ * of the recv buffer */
if (sbdec[3].BufferType == SECBUFFER_EXTRA) { if (sbdec[3].BufferType == SECBUFFER_EXTRA) {
memcpy(tls->recvbuffer, sbdec[3].pvBuffer, sbdec[3].cbBuffer); memcpy(tls->recvbuffer, sbdec[3].pvBuffer, sbdec[3].cbBuffer);
tls->recvbufferpos = sbdec[3].cbBuffer; tls->recvbufferpos = sbdec[3].cbBuffer;
} else { } else {
tls->recvbufferpos = 0; tls->recvbufferpos = 0;
} }
return tls_read(tls, buff, len); return tls_read(tls, buff, len);
} else if (ret == SEC_E_INCOMPLETE_MESSAGE) { } else if (ret == SEC_E_INCOMPLETE_MESSAGE) {
tls->lasterror = SEC_E_INCOMPLETE_MESSAGE; tls->lasterror = SEC_E_INCOMPLETE_MESSAGE;
return -1; return -1;
} else if (ret == SEC_I_RENEGOTIATE) { } else if (ret == SEC_I_RENEGOTIATE) {
ret = tls_start(tls); ret = tls_start(tls);
if (!ret) { if (!ret)
return -1; {
} return -1;
}
/* fake an incomplete message so we're called again */ /* fake an incomplete message so we're called again */
tls->lasterror = SEC_E_INCOMPLETE_MESSAGE; tls->lasterror = SEC_E_INCOMPLETE_MESSAGE;
return -1; return -1;
} }
/* something bad happened, so we bail */ /* something bad happened, so we bail */
tls->lasterror = ret; tls->lasterror = ret;
return -1; return -1;
} }
tls->lasterror = SEC_E_INCOMPLETE_MESSAGE; tls->lasterror = SEC_E_INCOMPLETE_MESSAGE;
@@ -558,28 +534,29 @@ int tls_read(tls_t *tls, void *buff, size_t len)
int tls_clear_pending_write(tls_t *tls) int tls_clear_pending_write(tls_t *tls)
{ {
if (tls->sendbufferpos < tls->sendbufferlen) { if (tls->sendbufferpos < tls->sendbufferlen)
int bytes; {
int bytes;
bytes = sock_write(tls->sock, tls->sendbuffer + tls->sendbufferpos, bytes = sock_write(tls->sock, tls->sendbuffer + tls->sendbufferpos,
tls->sendbufferlen - tls->sendbufferpos); tls->sendbufferlen - tls->sendbufferpos);
if (bytes == -1) { if (bytes == -1) {
tls->lasterror = sock_error(); tls->lasterror = sock_error();
return -1; return -1;
} else if (bytes > 0) { } else if (bytes > 0) {
tls->sendbufferpos += bytes; tls->sendbufferpos += bytes;
} }
if (tls->sendbufferpos < tls->sendbufferlen) { if (tls->sendbufferpos < tls->sendbufferlen) {
return 0; return 0;
} }
} }
return 1; return 1;
} }
int tls_write(tls_t *tls, const void *buff, size_t len) int tls_write(tls_t *tls, const void * const buff, const size_t len)
{ {
SecBufferDesc sbdenc; SecBufferDesc sbdenc;
SecBuffer sbenc[4]; SecBuffer sbenc[4];
@@ -588,7 +565,7 @@ int tls_write(tls_t *tls, const void *buff, size_t len)
ret = tls_clear_pending_write(tls); ret = tls_clear_pending_write(tls);
if (ret <= 0) { if (ret <= 0) {
return ret; return ret;
} }
tls->sendbufferpos = 0; tls->sendbufferpos = 0;
@@ -616,49 +593,51 @@ int tls_write(tls_t *tls, const void *buff, size_t len)
sbenc[1].pvBuffer = tls->sendbuffer + tls->spcss.cbHeader; sbenc[1].pvBuffer = tls->sendbuffer + tls->spcss.cbHeader;
while (remain > 0) { while (remain > 0)
if (remain > tls->spcss.cbMaximumMessage) { {
sbenc[1].cbBuffer = tls->spcss.cbMaximumMessage; if (remain > tls->spcss.cbMaximumMessage) {
} else { sbenc[1].cbBuffer = tls->spcss.cbMaximumMessage;
sbenc[1].cbBuffer = remain; } else {
} sbenc[1].cbBuffer = remain;
}
sbenc[2].pvBuffer = sbenc[2].pvBuffer = (unsigned char *)sbenc[1].pvBuffer
(unsigned char *)sbenc[1].pvBuffer + sbenc[1].cbBuffer; + sbenc[1].cbBuffer;
sbenc[2].cbBuffer = tls->spcss.cbTrailer; sbenc[2].cbBuffer = tls->spcss.cbTrailer;
memcpy(sbenc[1].pvBuffer, p, sbenc[1].cbBuffer); memcpy(sbenc[1].pvBuffer, p, sbenc[1].cbBuffer);
p += tls->spcss.cbMaximumMessage; p += tls->spcss.cbMaximumMessage;
tls->sendbufferlen = tls->sendbufferlen = sbenc[0].cbBuffer + sbenc[1].cbBuffer
sbenc[0].cbBuffer + sbenc[1].cbBuffer + sbenc[2].cbBuffer; + sbenc[2].cbBuffer;
ret = tls->sft->EncryptMessage(&(tls->hctxt), 0, &sbdenc, 0); ret = tls->sft->EncryptMessage(&(tls->hctxt), 0, &sbdenc, 0);
if (ret != SEC_E_OK) { if (ret != SEC_E_OK) {
tls->lasterror = ret; tls->lasterror = ret;
return -1; return -1;
} }
tls->sendbufferpos = 0; tls->sendbufferpos = 0;
ret = tls_clear_pending_write(tls); ret = tls_clear_pending_write(tls);
if (ret == -1 && !tls_is_recoverable(tls_error(tls))) { if (ret == -1 && !tls_is_recoverable(tls_error(tls))) {
return -1; return -1;
} }
if (remain > tls->spcss.cbMaximumMessage) { if (remain > tls->spcss.cbMaximumMessage) {
sent += tls->spcss.cbMaximumMessage; sent += tls->spcss.cbMaximumMessage;
remain -= tls->spcss.cbMaximumMessage; remain -= tls->spcss.cbMaximumMessage;
} else { } else {
sent += remain; sent += remain;
remain = 0; remain = 0;
} }
if (ret == 0 || (ret == -1 && tls_is_recoverable(tls_error(tls)))) {
return sent;
}
if (ret == 0 || (ret == -1 && tls_is_recoverable(tls_error(tls)))) {
return sent;
}
} }
return sent; return sent;

View File

@@ -1,7 +1,7 @@
/* util.c /* util.c
** strophe XMPP client library -- various utility functions ** strophe XMPP client library -- various utility functions
** **
** Copyright (C) 2005-2009 Collecta, Inc. ** Copyright (C) 2005-2009 Collecta, Inc.
** **
** This software is provided AS-IS with no warranty, either express ** This software is provided AS-IS with no warranty, either express
** or implied. ** or implied.
@@ -36,41 +36,21 @@
* @param ctx a Strophe context object * @param ctx a Strophe context object
* @param s a string * @param s a string
* *
* @return a newly allocated string with the same data as s or NULL on error * @return a new allocates string with the same data as s or NULL on error
*/ */
char *xmpp_strdup(const xmpp_ctx_t *ctx, const char *s) char *xmpp_strdup(const xmpp_ctx_t * const ctx, const char * const s)
{
return xmpp_strndup(ctx, s, SIZE_MAX);
}
/** Duplicate a string with a maximum length.
* This function replaces the standard strndup library call with a version
* that uses the Strophe context object's allocator.
*
* @param ctx a Strophe context object
* @param s a string
* @param len the maximum length of the string to copy
*
* @return a newly allocated string that contains at most `len` symbols
* of the original string or NULL on error
*/
char *xmpp_strndup(const xmpp_ctx_t *ctx, const char *s, size_t len)
{ {
size_t len;
char *copy; char *copy;
size_t l;
l = strlen(s); len = strlen(s);
if (l > len) copy = xmpp_alloc(ctx, len + 1);
l = len;
copy = xmpp_alloc(ctx, l + 1);
if (!copy) { if (!copy) {
xmpp_error(ctx, "xmpp", "failed to allocate required memory"); xmpp_error(ctx, "xmpp", "failed to allocate required memory");
return NULL; return NULL;
} }
memcpy(copy, s, l); memcpy(copy, s, len + 1);
copy[l] = '\0';
return copy; return copy;
} }
@@ -106,24 +86,8 @@ char *xmpp_strtok_r(char *s, const char *delim, char **saveptr)
*/ */
uint64_t time_stamp(void) uint64_t time_stamp(void)
{ {
#if defined(_WIN32) || defined(_XBOX_ONE) #ifdef _WIN32
return timeGetTime();
#ifndef __GNUC__
#define EPOCHFILETIME (116444736000000000i64)
#else
#define EPOCHFILETIME (116444736000000000LL)
#endif
FILETIME ft;
LARGE_INTEGER li;
__int64 t;
GetSystemTimeAsFileTime(&ft);
li.LowPart = ft.dwLowDateTime;
li.HighPart = ft.dwHighDateTime;
t = li.QuadPart; /* In 100-nanosecond intervals */
t -= EPOCHFILETIME; /* Offset to the Epoch time */
return (uint64_t)(t / 10000); /* Convert to milliseconds */
#else #else
struct timeval tv; struct timeval tv;
@@ -150,22 +114,13 @@ uint64_t time_elapsed(uint64_t t1, uint64_t t2)
/** Disconnect the stream with a memory error. /** Disconnect the stream with a memory error.
* This is a convenience function used internally by various parts of * This is a convenience function used internally by various parts of
* the Strophe library for terminating the connection because of a * the Strophe library for terminating the connection because of a
* memory error. * memory error.
* *
* @param conn a Strophe connection object * @param conn a Strophe connection object
*/ */
void disconnect_mem_error(xmpp_conn_t *conn) void disconnect_mem_error(xmpp_conn_t * const conn)
{ {
xmpp_error(conn->ctx, "xmpp", "Memory allocation error"); xmpp_error(conn->ctx, "xmpp", "Memory allocation error");
xmpp_disconnect(conn); xmpp_disconnect(conn);
} }
void hex_encode(char *writebuf, void *readbuf, size_t len)
{
size_t i;
for (i = 0; i < len; i++) {
sprintf(writebuf, "%02x", ((unsigned char *)readbuf)[i]);
writebuf += 2;
}
}

View File

@@ -1,7 +1,7 @@
/* util.h /* util.h
** strophe XMPP client library -- various utility functions ** strophe XMPP client library -- various utility functions
** **
** Copyright (C) 2005-2009 Collecta, Inc. ** Copyright (C) 2005-2009 Collecta, Inc.
** **
** This software is provided AS-IS with no warranty, either express ** This software is provided AS-IS with no warranty, either express
** or implied. ** or implied.
@@ -18,10 +18,6 @@
#include "ostypes.h" #include "ostypes.h"
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
#endif /* ARRAY_SIZE */
/* TODO evaluate x and y only once */ /* TODO evaluate x and y only once */
#define xmpp_min(x, y) ((x) < (y) ? (x) : (y)) #define xmpp_min(x, y) ((x) < (y) ? (x) : (y))
@@ -32,7 +28,4 @@ char *xmpp_strtok_r(char *s, const char *delim, char **saveptr);
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);
/* misc functions */
void hex_encode(char *writebuf, void *readbuf, size_t len);
#endif /* __LIBSTROPHE_UTIL_H__ */ #endif /* __LIBSTROPHE_UTIL_H__ */

419
strophe.h
View File

@@ -16,7 +16,7 @@
#ifndef __LIBSTROPHE_STROPHE_H__ #ifndef __LIBSTROPHE_STROPHE_H__
#define __LIBSTROPHE_STROPHE_H__ #define __LIBSTROPHE_STROPHE_H__
#include <stddef.h> /* size_t */ #include <stddef.h> /* size_t */
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@@ -39,10 +39,6 @@ extern "C" {
* Namespace definition for 'urn:ietf:params:xml:ns:xmpp-streams'. * Namespace definition for 'urn:ietf:params:xml:ns:xmpp-streams'.
*/ */
#define XMPP_NS_STREAMS_IETF "urn:ietf:params:xml:ns:xmpp-streams" #define XMPP_NS_STREAMS_IETF "urn:ietf:params:xml:ns:xmpp-streams"
/** @def XMPP_NS_STANZAS_IETF
* Namespace definition for 'urn:ietf:params:xml:ns:xmpp-stanzas'.
*/
#define XMPP_NS_STANZAS_IETF "urn:ietf:params:xml:ns:xmpp-stanzas"
/** @def XMPP_NS_TLS /** @def XMPP_NS_TLS
* Namespace definition for 'url:ietf:params:xml:ns:xmpp-tls'. * Namespace definition for 'url:ietf:params:xml:ns:xmpp-tls'.
*/ */
@@ -75,10 +71,6 @@ extern "C" {
* Namespace definition for 'jabber:iq:roster'. * Namespace definition for 'jabber:iq:roster'.
*/ */
#define XMPP_NS_ROSTER "jabber:iq:roster" #define XMPP_NS_ROSTER "jabber:iq:roster"
/** @def XMPP_NS_REGISTER
* Namespace definition for 'jabber:iq:register'.
*/
#define XMPP_NS_REGISTER "jabber:iq:register"
/* error defines */ /* error defines */
/** @def XMPP_EOK /** @def XMPP_EOK
@@ -87,7 +79,7 @@ extern "C" {
#define XMPP_EOK 0 #define XMPP_EOK 0
/** @def XMPP_EMEM /** @def XMPP_EMEM
* Memory related failure error code. * Memory related failure error code.
* *
* This is returned on allocation errors and signals that the host may * This is returned on allocation errors and signals that the host may
* be out of memory. * be out of memory.
*/ */
@@ -122,22 +114,18 @@ typedef struct _xmpp_log_t xmpp_log_t;
/* opaque run time context containing the above hooks */ /* opaque run time context containing the above hooks */
typedef struct _xmpp_ctx_t xmpp_ctx_t; typedef struct _xmpp_ctx_t xmpp_ctx_t;
typedef struct _xmpp_tlscert_t xmpp_tlscert_t; xmpp_ctx_t *xmpp_ctx_new(const xmpp_mem_t * const mem,
const xmpp_log_t * const log);
xmpp_ctx_t *xmpp_ctx_new(const xmpp_mem_t *mem, const xmpp_log_t *log); void xmpp_ctx_free(xmpp_ctx_t * const ctx);
void xmpp_ctx_free(xmpp_ctx_t *ctx);
/* set the verbosity level of the ctx */
void xmpp_ctx_set_verbosity(xmpp_ctx_t *ctx, int level);
/* free some blocks returned by other APIs, for example the /* free some blocks returned by other APIs, for example the
buffer you get from xmpp_stanza_to_text */ buffer you get from xmpp_stanza_to_text */
void xmpp_free(const xmpp_ctx_t *ctx, void *p); void xmpp_free(const xmpp_ctx_t * const ctx, void *p);
struct _xmpp_mem_t { struct _xmpp_mem_t {
void *(*alloc)(size_t size, void *userdata); void *(*alloc)(const size_t size, void * const userdata);
void (*free)(void *p, void *userdata); void (*free)(void *p, void * const userdata);
void *(*realloc)(void *p, size_t size, void *userdata); void *(*realloc)(void *p, const size_t size, void * const userdata);
void *userdata; void *userdata;
}; };
@@ -148,12 +136,17 @@ typedef enum {
XMPP_LEVEL_ERROR XMPP_LEVEL_ERROR
} xmpp_log_level_t; } xmpp_log_level_t;
typedef enum { XMPP_UNKNOWN, XMPP_CLIENT, XMPP_COMPONENT } xmpp_conn_type_t; typedef enum {
XMPP_UNKNOWN,
XMPP_CLIENT,
XMPP_COMPONENT,
XMPP_INCOMING
} xmpp_conn_type_t;
typedef void (*xmpp_log_handler)(void *userdata, typedef void (*xmpp_log_handler)(void * const userdata,
xmpp_log_level_t level, const xmpp_log_level_t level,
const char *area, const char * const area,
const char *msg); const char * const msg);
struct _xmpp_log_t { struct _xmpp_log_t {
xmpp_log_handler handler; xmpp_log_handler handler;
@@ -170,17 +163,13 @@ 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 */ /* connection flags */
#define XMPP_CONN_FLAG_DISABLE_TLS (1UL << 0) #define XMPP_CONN_FLAG_DISABLE_TLS (1UL << 0)
#define XMPP_CONN_FLAG_MANDATORY_TLS (1UL << 1) #define XMPP_CONN_FLAG_MANDATORY_TLS (1UL << 1)
#define XMPP_CONN_FLAG_LEGACY_SSL (1UL << 2) #define XMPP_CONN_FLAG_LEGACY_SSL (1UL << 2)
/** @def XMPP_CONN_FLAG_TRUST_TLS /** @def XMPP_CONN_FLAG_TRUST_TLS
* Trust server's certificate even if it is invalid. * Trust server's certificate even if it is invalid.
*/ */
#define XMPP_CONN_FLAG_TRUST_TLS (1UL << 3) #define XMPP_CONN_FLAG_TRUST_TLS (1UL << 3)
/** @def XMPP_CONN_FLAG_LEGACY_AUTH
* Enable legacy authentication support.
*/
#define XMPP_CONN_FLAG_LEGACY_AUTH (1UL << 4)
/* connect callback */ /* connect callback */
typedef enum { typedef enum {
@@ -217,159 +206,124 @@ typedef enum {
XMPP_SE_XML_NOT_WELL_FORMED XMPP_SE_XML_NOT_WELL_FORMED
} xmpp_error_type_t; } xmpp_error_type_t;
/** Certificate Elements
*
* @ingroup TLS
*/
typedef enum {
XMPP_CERT_VERSION, /**< X.509 Version */
XMPP_CERT_SERIALNUMBER, /**< SerialNumber */
XMPP_CERT_SUBJECT, /**< Subject */
XMPP_CERT_ISSUER, /**< Issuer */
XMPP_CERT_NOTBEFORE, /**< Issued on */
XMPP_CERT_NOTAFTER, /**< Expires on */
XMPP_CERT_KEYALG, /**< Public Key Algorithm */
XMPP_CERT_SIGALG, /**< Certificate Signature Algorithm */
XMPP_CERT_FINGERPRINT_SHA1, /**< Fingerprint SHA-1 */
XMPP_CERT_FINGERPRINT_SHA256, /**< Fingerprint SHA-256 */
XMPP_CERT_ELEMENT_MAX /**< Last element of the enum */
} xmpp_cert_element_t;
typedef struct { typedef struct {
xmpp_error_type_t type; xmpp_error_type_t type;
char *text; char *text;
xmpp_stanza_t *stanza; xmpp_stanza_t *stanza;
} xmpp_stream_error_t; } xmpp_stream_error_t;
typedef void (*xmpp_conn_handler)(xmpp_conn_t *conn, typedef void (*xmpp_conn_handler)(xmpp_conn_t * const conn,
xmpp_conn_event_t event, const xmpp_conn_event_t event,
int error, const int error,
xmpp_stream_error_t *stream_error, xmpp_stream_error_t * const stream_error,
void *userdata); void * const userdata);
/** The Handler function which will be called when the TLS stack can't xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t * const ctx);
* verify the authenticity of a Certificate that gets presented by xmpp_conn_t *xmpp_conn_clone(xmpp_conn_t * const conn);
* the server we're trying to connect to. int xmpp_conn_release(xmpp_conn_t * const conn);
*
* When this function is called and details of the `cert` have to be
* kept, please copy them yourself. The `cert` object will be free'd
* automatically when this function returns.
*
* NB: `errormsg` is specific per certificate on OpenSSL and the same
* for all certificates on GnuTLS.
*
* @param cert a Strophe certificate object
* @param errormsg The error that caused this.
*
* @return 0 if the connection attempt should be terminated,
* 1 if the connection should be established.
*
* @ingroup TLS
*/
typedef int (*xmpp_certfail_handler)(const xmpp_tlscert_t *cert,
const char *const errormsg);
void xmpp_send_error(xmpp_conn_t *conn, xmpp_error_type_t type, char *text); long xmpp_conn_get_flags(const xmpp_conn_t * const conn);
xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t *ctx); int xmpp_conn_set_flags(xmpp_conn_t * const conn, long flags);
xmpp_conn_t *xmpp_conn_clone(xmpp_conn_t *conn); const char *xmpp_conn_get_jid(const xmpp_conn_t * const conn);
int xmpp_conn_release(xmpp_conn_t *conn); const char *xmpp_conn_get_bound_jid(const xmpp_conn_t * const conn);
void xmpp_conn_set_jid(xmpp_conn_t * const conn, const char * const jid);
const char *xmpp_conn_get_pass(const xmpp_conn_t * const conn);
void xmpp_conn_set_pass(xmpp_conn_t * const conn, const char * const pass);
xmpp_ctx_t *xmpp_conn_get_context(xmpp_conn_t * const conn);
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);
long xmpp_conn_get_flags(const xmpp_conn_t *conn); int xmpp_connect_client(xmpp_conn_t * const conn,
int xmpp_conn_set_flags(xmpp_conn_t *conn, long flags); const char * const altdomain,
const char *xmpp_conn_get_jid(const xmpp_conn_t *conn); unsigned short altport,
const char *xmpp_conn_get_bound_jid(const xmpp_conn_t *conn); xmpp_conn_handler callback,
void xmpp_conn_set_jid(xmpp_conn_t *conn, const char *jid); void * const userdata);
void xmpp_conn_set_cafile(xmpp_conn_t *const conn, const char *path);
void xmpp_conn_set_capath(xmpp_conn_t *const conn, const char *path);
void xmpp_conn_set_certfail_handler(xmpp_conn_t *const conn,
xmpp_certfail_handler hndl);
xmpp_tlscert_t *xmpp_conn_get_peer_cert(xmpp_conn_t *const conn);
void xmpp_conn_set_client_cert(xmpp_conn_t *conn,
const char *cert,
const char *key);
unsigned int xmpp_conn_cert_xmppaddr_num(xmpp_conn_t *conn);
char *xmpp_conn_cert_xmppaddr(xmpp_conn_t *conn, unsigned int n);
const char *xmpp_conn_get_pass(const xmpp_conn_t *conn);
void xmpp_conn_set_pass(xmpp_conn_t *conn, const char *pass);
xmpp_ctx_t *xmpp_conn_get_context(xmpp_conn_t *conn);
void xmpp_conn_disable_tls(xmpp_conn_t *conn);
int xmpp_conn_is_secured(xmpp_conn_t *conn);
void xmpp_conn_set_keepalive(xmpp_conn_t *conn, int timeout, int interval);
int xmpp_conn_is_connecting(xmpp_conn_t *conn);
int xmpp_conn_is_connected(xmpp_conn_t *conn);
int xmpp_conn_is_disconnected(xmpp_conn_t *conn);
int xmpp_connect_client(xmpp_conn_t *conn, int xmpp_connect_component(xmpp_conn_t * const conn, const char * const server,
const char *altdomain, unsigned short port, xmpp_conn_handler callback,
unsigned short altport, void * const userdata);
xmpp_conn_handler callback,
void *userdata);
int xmpp_connect_component(xmpp_conn_t *conn, int xmpp_connect_raw(xmpp_conn_t * const conn,
const char *server, const char * const altdomain,
unsigned short port,
xmpp_conn_handler callback,
void *userdata);
int xmpp_connect_raw(xmpp_conn_t *conn,
const char *altdomain,
unsigned short altport, unsigned short altport,
xmpp_conn_handler callback, xmpp_conn_handler callback,
void *userdata); void * const userdata);
int xmpp_conn_open_stream_default(xmpp_conn_t *conn); int xmpp_conn_open_stream_default(xmpp_conn_t * const conn);
int xmpp_conn_open_stream(xmpp_conn_t *conn, int xmpp_conn_open_stream(xmpp_conn_t * const conn, char **attributes,
char **attributes,
size_t attributes_len); size_t attributes_len);
int xmpp_conn_tls_start(xmpp_conn_t *conn); int xmpp_conn_tls_start(xmpp_conn_t * const conn);
void xmpp_disconnect(xmpp_conn_t *conn); void xmpp_disconnect(xmpp_conn_t * const conn);
void xmpp_send(xmpp_conn_t *conn, xmpp_stanza_t *stanza); void xmpp_send(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza);
void xmpp_send_raw_string(xmpp_conn_t *conn, const char *fmt, ...); void xmpp_send_raw_string(xmpp_conn_t * const conn,
void xmpp_send_raw(xmpp_conn_t *conn, const char *data, size_t len); const char * const fmt, ...);
void xmpp_send_raw(xmpp_conn_t * const conn,
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 */
/* if the handler returns false it is removed */ /* if the handle returns false it is removed */
typedef int (*xmpp_timed_handler)(xmpp_conn_t *conn, void *userdata); typedef int (*xmpp_timed_handler)(xmpp_conn_t * const conn,
void * const userdata);
void xmpp_timed_handler_add(xmpp_conn_t * const conn,
xmpp_timed_handler handler,
const unsigned long period,
void * const userdata);
void xmpp_timed_handler_delete(xmpp_conn_t * const conn,
xmpp_timed_handler handler);
void xmpp_timed_handler_add(xmpp_conn_t *conn,
xmpp_timed_handler handler,
unsigned long period,
void *userdata);
void xmpp_timed_handler_delete(xmpp_conn_t *conn, xmpp_timed_handler handler);
/* if the handler returns false it is removed */ /* if the handler returns false it is removed */
typedef int (*xmpp_global_timed_handler)(xmpp_ctx_t *ctx, void *userdata); typedef int (*xmpp_handler)(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza,
void * const userdata);
void xmpp_global_timed_handler_add(xmpp_ctx_t *ctx, void xmpp_handler_add(xmpp_conn_t * const conn,
xmpp_global_timed_handler handler, xmpp_handler handler,
unsigned long period, const char * const ns,
void *userdata); const char * const name,
void xmpp_global_timed_handler_delete(xmpp_ctx_t *ctx, const char * const type,
xmpp_global_timed_handler handler); void * const userdata);
void xmpp_handler_delete(xmpp_conn_t * const conn,
xmpp_handler handler);
/* if the handler returns false it is removed */ void xmpp_id_handler_add(xmpp_conn_t * const conn,
typedef int (*xmpp_handler)(xmpp_conn_t *conn, xmpp_handler handler,
xmpp_stanza_t *stanza, const char * const id,
void *userdata); void * const userdata);
void xmpp_id_handler_delete(xmpp_conn_t * const conn,
void xmpp_handler_add(xmpp_conn_t *conn, xmpp_handler handler,
xmpp_handler handler, const char * const id);
const char *ns,
const char *name,
const char *type,
void *userdata);
void xmpp_handler_delete(xmpp_conn_t *conn, xmpp_handler handler);
void xmpp_id_handler_add(xmpp_conn_t *conn,
xmpp_handler handler,
const char *id,
void *userdata);
void xmpp_id_handler_delete(xmpp_conn_t *conn,
xmpp_handler handler,
const char *id);
/* /*
void xmpp_register_stanza_handler(conn, stanza, xmlns, type, handler) void xmpp_register_stanza_handler(conn, stanza, xmlns, type, handler)
@@ -379,99 +333,86 @@ void xmpp_register_stanza_handler(conn, stanza, xmlns, type, handler)
/* allocate and initialize a blank stanza */ /* allocate and initialize a blank stanza */
xmpp_stanza_t *xmpp_stanza_new(xmpp_ctx_t *ctx); xmpp_stanza_t *xmpp_stanza_new(xmpp_ctx_t *ctx);
xmpp_stanza_t *xmpp_stanza_new_from_string(xmpp_ctx_t *ctx, const char *str);
/* clone a stanza */ /* clone a stanza */
xmpp_stanza_t *xmpp_stanza_clone(xmpp_stanza_t *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 *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 *stanza); int xmpp_stanza_release(xmpp_stanza_t * const stanza);
xmpp_ctx_t *xmpp_stanza_get_context(const xmpp_stanza_t *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_text(xmpp_stanza_t *stanza);
int xmpp_stanza_is_tag(xmpp_stanza_t *stanza);
/* marshall a stanza into text for transmission or display */ /* marshall a stanza into text for transmission or display */
int xmpp_stanza_to_text(xmpp_stanza_t *stanza, char **buf, size_t *buflen); int xmpp_stanza_to_text(xmpp_stanza_t *stanza,
char ** const buf, size_t * const buflen);
xmpp_stanza_t *xmpp_stanza_get_children(xmpp_stanza_t *stanza); xmpp_stanza_t *xmpp_stanza_get_children(xmpp_stanza_t * const stanza);
xmpp_stanza_t *xmpp_stanza_get_child_by_name(xmpp_stanza_t *stanza, xmpp_stanza_t *xmpp_stanza_get_child_by_name(xmpp_stanza_t * const stanza,
const char *name); const char * const name);
xmpp_stanza_t *xmpp_stanza_get_child_by_ns(xmpp_stanza_t *stanza, xmpp_stanza_t *xmpp_stanza_get_child_by_ns(xmpp_stanza_t * const stanza,
const char *ns); const char * const ns);
xmpp_stanza_t *xmpp_stanza_get_child_by_name_and_ns(xmpp_stanza_t *stanza, xmpp_stanza_t *xmpp_stanza_get_next(xmpp_stanza_t * const stanza);
const char *name,
const char *ns);
xmpp_stanza_t *xmpp_stanza_get_next(xmpp_stanza_t *stanza);
int xmpp_stanza_add_child(xmpp_stanza_t *stanza, xmpp_stanza_t *child); int xmpp_stanza_add_child(xmpp_stanza_t *stanza, xmpp_stanza_t *child);
int xmpp_stanza_add_child_ex(xmpp_stanza_t *stanza,
xmpp_stanza_t *child,
int do_clone);
const char *xmpp_stanza_get_attribute(xmpp_stanza_t *stanza, const char *name); const char *xmpp_stanza_get_attribute(xmpp_stanza_t * const stanza,
int xmpp_stanza_get_attribute_count(xmpp_stanza_t *stanza); const char * const name);
int xmpp_stanza_get_attributes(xmpp_stanza_t *stanza, int xmpp_stanza_get_attribute_count(xmpp_stanza_t * const stanza);
const char **attr, int xmpp_stanza_get_attributes(xmpp_stanza_t * const stanza,
int attrlen); const char **attr, int attrlen);
/* concatenate all child text nodes. this function /* concatenate all child text nodes. this function
* returns a string that must be freed by the caller */ * returns a string that must be freed by the caller */
char *xmpp_stanza_get_text(xmpp_stanza_t *stanza); char *xmpp_stanza_get_text(xmpp_stanza_t * const stanza);
const char *xmpp_stanza_get_text_ptr(xmpp_stanza_t *stanza); const char *xmpp_stanza_get_text_ptr(xmpp_stanza_t * const stanza);
const char *xmpp_stanza_get_name(xmpp_stanza_t *stanza); const char *xmpp_stanza_get_name(xmpp_stanza_t * const stanza);
/* set_attribute adds/replaces attributes */ /* set_attribute adds/replaces attributes */
int xmpp_stanza_set_attribute(xmpp_stanza_t *stanza, int xmpp_stanza_set_attribute(xmpp_stanza_t * const stanza,
const char *key, const char * const key,
const char *value); const char * const value);
int xmpp_stanza_set_name(xmpp_stanza_t *stanza, const char *name); int xmpp_stanza_set_name(xmpp_stanza_t *stanza,
int xmpp_stanza_set_text(xmpp_stanza_t *stanza, const char *text); const char * const name);
int xmpp_stanza_set_text(xmpp_stanza_t *stanza,
const char * const text);
int xmpp_stanza_set_text_with_size(xmpp_stanza_t *stanza, int xmpp_stanza_set_text_with_size(xmpp_stanza_t *stanza,
const char *text, const char * const text,
size_t size); const size_t size);
int xmpp_stanza_del_attribute(xmpp_stanza_t *stanza, const char *name); 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 *stanza); const char *xmpp_stanza_get_ns(xmpp_stanza_t * const stanza);
const char *xmpp_stanza_get_type(xmpp_stanza_t *stanza); const char *xmpp_stanza_get_type(xmpp_stanza_t * const stanza);
const char *xmpp_stanza_get_id(xmpp_stanza_t *stanza); const char *xmpp_stanza_get_id(xmpp_stanza_t * const stanza);
const char *xmpp_stanza_get_to(xmpp_stanza_t *stanza); const char *xmpp_stanza_get_to(xmpp_stanza_t * const stanza);
const char *xmpp_stanza_get_from(xmpp_stanza_t *stanza); const char *xmpp_stanza_get_from(xmpp_stanza_t * const stanza);
int xmpp_stanza_set_ns(xmpp_stanza_t *stanza, const char *ns); int xmpp_stanza_set_ns(xmpp_stanza_t * const stanza, const char * const ns);
int xmpp_stanza_set_id(xmpp_stanza_t *stanza, const char *id); int xmpp_stanza_set_id(xmpp_stanza_t * const stanza, const char * const id);
int xmpp_stanza_set_type(xmpp_stanza_t *stanza, const char *type); int xmpp_stanza_set_type(xmpp_stanza_t * const stanza, const char * const type);
int xmpp_stanza_set_to(xmpp_stanza_t *stanza, const char *to); int xmpp_stanza_set_to(xmpp_stanza_t * const stanza, const char * const to);
int xmpp_stanza_set_from(xmpp_stanza_t *stanza, const char *from); int xmpp_stanza_set_from(xmpp_stanza_t * const stanza, const char * const from);
/* allocate and initialize a stanza in reply to another */ /* allocate and initialize a stanza in reply to another */
xmpp_stanza_t *xmpp_stanza_reply(xmpp_stanza_t *stanza); xmpp_stanza_t *xmpp_stanza_reply(xmpp_stanza_t * const stanza);
xmpp_stanza_t *xmpp_stanza_reply_error(xmpp_stanza_t *stanza,
const char *error_type,
const char *condition,
const char *text);
/* stanza subclasses */ /* stanza subclasses */
xmpp_stanza_t *xmpp_message_new(xmpp_ctx_t *ctx, xmpp_stanza_t *xmpp_message_new(xmpp_ctx_t *ctx, const char * const type,
const char *type, const char * const to, const char * const id);
const char *to,
const char *id);
char *xmpp_message_get_body(xmpp_stanza_t *msg); char *xmpp_message_get_body(xmpp_stanza_t *msg);
int xmpp_message_set_body(xmpp_stanza_t *msg, const char *text); int xmpp_message_set_body(xmpp_stanza_t *msg, const char * const text);
xmpp_stanza_t *xmpp_iq_new(xmpp_ctx_t *ctx, const char *type, const char *id); xmpp_stanza_t *xmpp_iq_new(xmpp_ctx_t *ctx, const char * const type,
const char * const id);
xmpp_stanza_t *xmpp_presence_new(xmpp_ctx_t *ctx); xmpp_stanza_t *xmpp_presence_new(xmpp_ctx_t *ctx);
xmpp_stanza_t *
xmpp_error_new(xmpp_ctx_t *ctx, xmpp_error_type_t type, const char *text);
/* jid */ /* jid */
/* these return new strings that must be xmpp_free()'d */ /* these return new strings that must be xmpp_free()'d */
char *xmpp_jid_new(xmpp_ctx_t *ctx, char *xmpp_jid_new(xmpp_ctx_t *ctx, const char *node,
const char *node, const char *domain,
const char *domain, const char *resource);
const char *resource);
char *xmpp_jid_bare(xmpp_ctx_t *ctx, const char *jid); char *xmpp_jid_bare(xmpp_ctx_t *ctx, const char *jid);
char *xmpp_jid_node(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_domain(xmpp_ctx_t *ctx, const char *jid);
@@ -479,21 +420,10 @@ char *xmpp_jid_resource(xmpp_ctx_t *ctx, const char *jid);
/* event loop */ /* event loop */
void xmpp_run_once(xmpp_ctx_t *ctx, 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 *ctx, unsigned long timeout); void xmpp_ctx_set_timeout(xmpp_ctx_t * const ctx, const unsigned long timeout);
/* TLS certificates */
xmpp_ctx_t *xmpp_tlscert_get_ctx(const xmpp_tlscert_t *cert);
xmpp_conn_t *xmpp_tlscert_get_conn(const xmpp_tlscert_t *cert);
const char *xmpp_tlscert_get_pem(const xmpp_tlscert_t *cert);
const char *xmpp_tlscert_get_dnsname(const xmpp_tlscert_t *cert, size_t n);
const char *xmpp_tlscert_get_string(const xmpp_tlscert_t *cert,
xmpp_cert_element_t elmnt);
const char *xmpp_tlscert_get_description(xmpp_cert_element_t elmnt);
void xmpp_tlscert_free(xmpp_tlscert_t *cert);
/* UUID */ /* UUID */
@@ -509,8 +439,7 @@ char *xmpp_uuid_gen(xmpp_ctx_t *ctx);
typedef struct _xmpp_sha1_t xmpp_sha1_t; typedef struct _xmpp_sha1_t xmpp_sha1_t;
char *xmpp_sha1(xmpp_ctx_t *ctx, const unsigned char *data, size_t len); char *xmpp_sha1(xmpp_ctx_t *ctx, const unsigned char *data, size_t len);
void xmpp_sha1_digest(const unsigned char *data, void xmpp_sha1_digest(const unsigned char *data, size_t len,
size_t len,
unsigned char *digest); unsigned char *digest);
xmpp_sha1_t *xmpp_sha1_new(xmpp_ctx_t *ctx); xmpp_sha1_t *xmpp_sha1_new(xmpp_ctx_t *ctx);
@@ -523,14 +452,10 @@ void xmpp_sha1_to_digest(xmpp_sha1_t *sha1, unsigned char *digest);
/* Base64 */ /* Base64 */
char * char *xmpp_base64_encode(xmpp_ctx_t *ctx, const unsigned char *data, size_t len);
xmpp_base64_encode(xmpp_ctx_t *ctx, const unsigned char *data, size_t len);
char *xmpp_base64_decode_str(xmpp_ctx_t *ctx, const char *base64, size_t len); char *xmpp_base64_decode_str(xmpp_ctx_t *ctx, const char *base64, size_t len);
void xmpp_base64_decode_bin(xmpp_ctx_t *ctx, void xmpp_base64_decode_bin(xmpp_ctx_t *ctx, const char *base64, size_t len,
const char *base64, unsigned char **out, size_t *outlen);
size_t len,
unsigned char **out,
size_t *outlen);
#ifdef __cplusplus #ifdef __cplusplus
} }

133
strophepp.h Normal file
View File

@@ -0,0 +1,133 @@
/* strophepp.h
** strophe XMPP client library C++ API
**
** Copyright (C) 2005-2009 Collecta, Inc.
**
** This software is provided AS-IS with no warranty, either express or
** implied.
**
** This program is dual licensed under the MIT and GPLv3 licenses.
*/
/** @file
* Strophe public C++ API definitions.
*/
#ifndef __LIBSTROPHE_STROPHEPP_H__
#define __LIBSTROPHE_STROPHEPP_H__
#include "strophe.h"
namespace XMPP {
class Context {
private:
xmpp_mem_t m_mem;
xmpp_log_t m_log;
xmpp_ctx_t *m_ctx;
public:
Context();
virtual ~Context();
virtual void *alloc(const size_t size);
virtual void *realloc(void *p, const size_t size);
virtual void free(void *p);
virtual void log(const xmpp_log_level_t level,
const char * const area,
const char * const msg);
xmpp_ctx_t *getContext();
private:
static void *callAlloc(const size_t size, void * const userdata);
static void *callRealloc(void *p, const size_t size,
void * const userdata);
static void callFree(void *p, void * const userdata);
static void callLog(void * const userdata,
const xmpp_log_level_t level,
const char * const area,
const char * const msg);
};
class Stanza {
private:
Context *m_ctx;
xmpp_stanza_t *m_stanza;
void *operator new(size_t size, Context *ctx);
void operator delete(void *p);
Stanza(Context *ctx);
virtual ~Stanza();
public:
static Stanza *create(Context *ctx);
void release();
Stanza *clone();
Stanza *copy();
int toText(const char ** const buf, size_t * const buflen);
Stanza *getChildren();
Stanza *getChildByName(const char * const name);
Stanza *getNext();
char *getAttribute(const char * const name);
char *getNamespace();
char *getText();
char *getName();
void addChild(Stanza *child);
void setNamespace(const char * const ns);
void setAttribute(const char * const key, const char * const value);
void setName(const char * const name);
void setText(const char * const text);
void setText(const char * const text, const size_t size);
char *getType();
char *getId();
char *getTo();
char *getFrom();
void setType(const char * const type);
void setId(const char * const id);
void setTo(const char * const to);
void setFrom(const char * const from);
};
class Connection {
private:
Context *m_ctx;
xmpp_conn_t *conn;
void *operator new(size_t size, Context *ctx);
Connection(Context *ctx);
public:
static Connection *create(Context *ctx);
virtual ~Connection();
Connection *clone();
void operator delete(void *p);
const char *getJID();
void setJID(const char * const jid);
const char *getPass();
void setPass(const char * const pass);
bool connectClient(const char * const domain,
xmpp_conn_handler callback,
void * const userdata);
void disconnect();
void send(Stanza *stanza);
void addTimedHandler(xmpp_timed_handler handler,
const unsigned long perdio,
void * const userdata);
void deleteTimedHandler(xmpp_timed_handler handler);
void addHandler(xmpp_handler handler,
const char * const ns,
const char * const name,
const char * const type,
void * const userdata);
void deleteHandler(xmpp_handler handler);
void addIdHandler(xmpp_handler handler,
const char * const id,
void * const userdata);
void deleteIdHandler(xmpp_handler handler);
};
}
#endif /* __LIBSTROPHE_STROPHEPP_H__ */

View File

@@ -1,16 +0,0 @@
-----BEGIN CERTIFICATE-----
MIICfjCCAjSgAwIBAgIIW5u5Vwn2Mv0wCgYIKoZIzj0EAwIwSzFJMEcGA1UEAwxA
dmVyeS5sb25nLnVzZXJuYW1lQHNvLnRoZS5hc24xLmxlbmd0aC5pcy5hLnZhbGlk
LmFzY2lpLmNoYXJhY3RlcjAgFw0yMTAzMDExOTExMDBaGA8yMTIxMDMwMTE5MTEw
MFowSzFJMEcGA1UEAwxAdmVyeS5sb25nLnVzZXJuYW1lQHNvLnRoZS5hc24xLmxl
bmd0aC5pcy5hLnZhbGlkLmFzY2lpLmNoYXJhY3RlcjBJMBMGByqGSM49AgEGCCqG
SM49AwEBAzIABI/tSR5cZ9iHCVw0JwmKLvV3TbxPg3kDdouB0R2WKEdEWwXMIHkE
85RReISg+9/JDaOCAQ4wggEKMAkGA1UdEwQCMAAwHQYDVR0OBBYEFPjLGyHxqlOV
nXJQ9YBrnureO8LiMB8GA1UdIwQYMBaAFPjLGyHxqlOVnXJQ9YBrnureO8LiMAsG
A1UdDwQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAjCBmgYDVR0RBIGSMIGPoE4G
CCsGAQUFBwgFoEIMQHZlcnkubG9uZy51c2VybmFtZUBzby50aGUuYXNuMS5sZW5n
dGguaXMuYS52YWxpZC5hc2NpaS5jaGFyYWN0ZXKBDnlldEBub3RoZXIuc2Fugg53
d3cuc3Ryb3BoZS5pbaAdBggrBgEFBQcIBaARDA9zZWNvbmRAeG1wcC5qaWQwCgYI
KoZIzj0EAwIDOAAwNQIZAJmfqBhBMdaKCiWEuXu84K4+lznfzlRfmwIYCGRD1xk0
9cRa3V6PVwYWz6HcdRdMUBUj
-----END CERTIFICATE-----

View File

@@ -1,7 +1,7 @@
/* check_parser.h /* check_parser.h
** strophe XMPP client library -- parser tests ** strophe XMPP client library -- parser tests
** **
** Copyright (C) 2005-2009 Collecta, Inc. ** Copyright (C) 2005-2009 Collecta, Inc.
** **
** This software is provided AS-IS with no warranty, either express or ** This software is provided AS-IS with no warranty, either express or
** implied. ** implied.
@@ -18,15 +18,14 @@
#include "test.h" #include "test.h"
#define fail_unless(expr) \ #define fail_unless(expr) do { \
do { \ int result = (expr); \
int result = (expr); \ if (!result) { \
if (!result) { \ printf("%s:%d: Assertion failed: %s\n", \
printf("%s:%d: Assertion failed: %s\n", __FILE__, __LINE__, \ __FILE__, __LINE__, #expr); \
#expr); \ exit(1); \
exit(1); \ } \
} \ } while (0)
} while (0)
static void create_destroy(void) static void create_destroy(void)
{ {
@@ -43,9 +42,6 @@ static void create_destroy(void)
int cbtest_got_start = 0; int cbtest_got_start = 0;
void cbtest_handle_start(char *name, char **attrs, void *userdata) void cbtest_handle_start(char *name, char **attrs, void *userdata)
{ {
(void)attrs;
(void)userdata;
if (strcmp(name, "stream") == 0) if (strcmp(name, "stream") == 0)
cbtest_got_start = 1; cbtest_got_start = 1;
} }
@@ -53,8 +49,6 @@ void cbtest_handle_start(char *name, char **attrs, void *userdata)
int cbtest_got_end = 0; int cbtest_got_end = 0;
void cbtest_handle_end(char *name, void *userdata) void cbtest_handle_end(char *name, void *userdata)
{ {
(void)userdata;
if (strcmp(name, "stream") == 0) if (strcmp(name, "stream") == 0)
cbtest_got_end = 1; cbtest_got_end = 1;
} }
@@ -62,8 +56,6 @@ void cbtest_handle_end(char *name, void *userdata)
int cbtest_got_stanza = 0; int cbtest_got_stanza = 0;
void cbtest_handle_stanza(xmpp_stanza_t *stanza, void *userdata) void cbtest_handle_stanza(xmpp_stanza_t *stanza, void *userdata)
{ {
(void)userdata;
if (strcmp(xmpp_stanza_get_name(stanza), "message") == 0) if (strcmp(xmpp_stanza_get_name(stanza), "message") == 0)
cbtest_got_stanza = 1; cbtest_got_stanza = 1;
} }
@@ -75,7 +67,9 @@ static void callbacks(void)
int ret; int ret;
ctx = xmpp_ctx_new(NULL, NULL); ctx = xmpp_ctx_new(NULL, NULL);
parser = parser_new(ctx, cbtest_handle_start, cbtest_handle_end, parser = parser_new(ctx,
cbtest_handle_start,
cbtest_handle_end,
cbtest_handle_stanza, NULL); cbtest_handle_stanza, NULL);
ret = parser_feed(parser, "<stream>", 8); ret = parser_feed(parser, "<stream>", 8);

View File

@@ -1,5 +0,0 @@
-----BEGIN EC PRIVATE KEY-----
MF8CAQEEGF7SsbTSOjzb97nFc7Qbt4sic+1nZk+ETqAKBggqhkjOPQMBAaE0AzIA
BI/tSR5cZ9iHCVw0JwmKLvV3TbxPg3kDdouB0R2WKEdEWwXMIHkE85RReISg+9/J
DQ==
-----END EC PRIVATE KEY-----

View File

@@ -55,8 +55,8 @@ int main(int argc, char **argv)
} }
domain = argv[1]; domain = argv[1];
snprintf(fulldomain, sizeof(fulldomain), "_%s._%s.%s", service, proto, snprintf(fulldomain, sizeof(fulldomain), "_%s._%s.%s",
domain); service, proto, domain);
errno = 0; errno = 0;
len = res_query(fulldomain, C_IN, T_SRV, buf, sizeof(buf)); len = res_query(fulldomain, C_IN, T_SRV, buf, sizeof(buf));

View File

@@ -16,9 +16,9 @@
static uint8_t char_to_bin(char c) static uint8_t char_to_bin(char c)
{ {
return c <= '9' ? (uint8_t)(c - '0') return c <= '9' ? (uint8_t)(c - '0') :
: c <= 'Z' ? (uint8_t)(c - 'A' + 10) c <= 'Z' ? (uint8_t)(c - 'A' + 10) :
: (uint8_t)(c - 'a' + 10); (uint8_t)(c - 'a' + 10);
} }
void test_hex_to_bin(const char *hex, uint8_t *bin, size_t *bin_len) void test_hex_to_bin(const char *hex, uint8_t *bin, size_t *bin_len)

View File

@@ -14,52 +14,54 @@
#include <stddef.h> #include <stddef.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h>
#include <string.h> #include <string.h>
#include "ostypes.h" #include "ostypes.h"
#define TEST_MAIN \ #define TEST_MAIN \
int main(int argc, char **argv) \ int main(int argc, char **argv) { \
{ \ int num_failed; \
int num_failed; \ Suite *s = parser_suite(); \
Suite *s = parser_suite(); \ SRunner *sr = srunner_create(s); \
SRunner *sr = srunner_create(s); \ srunner_run_all(sr, CK_NORMAL); \
srunner_run_all(sr, CK_NORMAL); \ 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 #ifndef ARRAY_SIZE
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
#endif #endif
#define COMPARE(v1, v2) \ #define COMPARE(v1, v2) \
do { \ do { \
const char *__v1 = v1; \ const char *__v1 = v1; \
const char *__v2 = v2; \ const char *__v2 = v2; \
if (strcmp(__v1, __v2) != 0) { \ if (strcmp(__v1, __v2) != 0) { \
printf("Error: %s\n" \ printf("%s differs!\n" \
"Expected: %s\n" \ "expected: %s\n" \
"Got: %s\n", \ "got: %s\n", \
#v1 " != " #v2, __v1, __v2); \ #v1, __v1, __v2); \
exit(1); \ exit(1); \
} \ } \
} while (0) } while (0)
#define COMPARE_BUF(v1, len1, v2, len2) \ #define COMPARE_BUF(v1, len1, v2, len2) \
do { \ do { \
const uint8_t *__v1 = (uint8_t *)(v1); \ const uint8_t *__v1 = (uint8_t *)(v1); \
const uint8_t *__v2 = (uint8_t *)(v2); \ const uint8_t *__v2 = (uint8_t *)(v2); \
size_t __len1 = len1; \ size_t __len1 = len1; \
size_t __len2 = len2; \ size_t __len2 = len2; \
if (__len1 != __len2 || memcmp(__v1, __v2, __len1) != 0) { \ if (__len1 != __len2 || \
printf("Error: %s\n", #v1 " != " #v2); \ memcmp(__v1, __v2, __len1) != 0) \
printf("Expected: 0x%s\n", test_bin_to_hex(__v1, __len1)); \ { \
printf("Got: 0x%s\n", test_bin_to_hex(__v2, __len2)); \ printf("%s differs!\n", #v1); \
exit(1); \ printf("expected: 0x%s\n", \
} \ test_bin_to_hex(__v1, __len1)); \
} while (0) 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); 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); const char *test_bin_to_hex(const uint8_t *bin, size_t len);

View File

@@ -17,11 +17,11 @@
#include "test.h" #include "test.h"
static const unsigned char test_2_raw[] = {0x14, 0xfb, 0x9c, 0x03, static const unsigned char test_2_raw[] =
0xd9, 0x7e, 0x00}; {0x14, 0xfb, 0x9c, 0x03, 0xd9, 0x7e, 0x00};
static const unsigned char test_4_raw[] = {0xd6, 0x2f, 0x27, 0x49, 0x7e, 0xdd, static const unsigned char test_4_raw[] =
0xf3, 0xd5, 0x41, 0xbc, 0x1b, 0xe9, {0xd6, 0x2f, 0x27, 0x49, 0x7e, 0xdd, 0xf3, 0xd5,
0xdf, 0xe9, 0xb3, 0x08, 0x00}; 0x41, 0xbc, 0x1b, 0xe9, 0xdf, 0xe9, 0xb3, 0x08, 0x00};
static const struct { static const struct {
char *raw; char *raw;
@@ -36,26 +36,30 @@ static const struct {
.base64 = "FPucA9l+", .base64 = "FPucA9l+",
}, },
{ {
.raw = "From rest and sleep, which but thy pictures be, " .raw =
"Much pleasure; then from thee much more must flow, " "From rest and sleep, which but thy pictures be, "
"And soonest our best men with thee do go, " "Much pleasure; then from thee much more must flow, "
"Rest of their bones, and soul's delivery.", "And soonest our best men with thee do go, "
.base64 = "RnJvbSByZXN0IGFuZCBzbGVlcCwgd2hpY2ggYnV0IHRoeSBwaWN0dXJl" "Rest of their bones, and soul's delivery.",
"cyBiZSwgTXVjaCBwbGVhc3VyZTsgdGhlbiBmcm9tIHRoZWUgbXVjaCBt" .base64 =
"b3JlIG11c3QgZmxvdywgQW5kIHNvb25lc3Qgb3VyIGJlc3QgbWVuIHdp" "RnJvbSByZXN0IGFuZCBzbGVlcCwgd2hpY2ggYnV0IHRoeSBwaWN0dXJl"
"dGggdGhlZSBkbyBnbywgUmVzdCBvZiB0aGVpciBib25lcywgYW5kIHNv" "cyBiZSwgTXVjaCBwbGVhc3VyZTsgdGhlbiBmcm9tIHRoZWUgbXVjaCBt"
"dWwncyBkZWxpdmVyeS4=", "b3JlIG11c3QgZmxvdywgQW5kIHNvb25lc3Qgb3VyIGJlc3QgbWVuIHdp"
"dGggdGhlZSBkbyBnbywgUmVzdCBvZiB0aGVpciBib25lcywgYW5kIHNv"
"dWwncyBkZWxpdmVyeS4=",
}, },
{ {
.raw = (char *)test_4_raw, .raw = (char *)test_4_raw,
.base64 = "1i8nSX7d89VBvBvp3+mzCA==", .base64 = "1i8nSX7d89VBvBvp3+mzCA==",
}, },
{ {
.raw = "realm=\"chesspark.com\",nonce=\"b243c0d663257a9149999cef2f83" .raw =
"a22116559e93\",qop=\"auth\",charset=utf-8,algorithm=md5-sess", "realm=\"chesspark.com\",nonce=\"b243c0d663257a9149999cef2f83"
.base64 = "cmVhbG09ImNoZXNzcGFyay5jb20iLG5vbmNlPSJiMjQzYzBkNjYzMjU3" "a22116559e93\",qop=\"auth\",charset=utf-8,algorithm=md5-sess",
"YTkxNDk5OTljZWYyZjgzYTIyMTE2NTU5ZTkzIixxb3A9ImF1dGgiLGNo" .base64 =
"YXJzZXQ9dXRmLTgsYWxnb3JpdGhtPW1kNS1zZXNz", "cmVhbG09ImNoZXNzcGFyay5jb20iLG5vbmNlPSJiMjQzYzBkNjYzMjU3"
"YTkxNDk5OTljZWYyZjgzYTIyMTE2NTU5ZTkzIixxb3A9ImF1dGgiLGNo"
"YXJzZXQ9dXRmLTgsYWxnb3JpdGhtPW1kNS1zZXNz",
}, },
/* RFC4648 test vectors */ /* RFC4648 test vectors */
@@ -90,30 +94,41 @@ static const struct {
}; };
static const unsigned char bin_data[] = { static const unsigned char bin_data[] = {
0xda, 0xa8, 0x81, 0x80, 0x00, 0x01, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0xda, 0xa8, 0x81, 0x80, 0x00, 0x01, 0x00, 0x05,
0x0c, 0x5f, 0x78, 0x6d, 0x70, 0x70, 0x2d, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x5f, 0x78, 0x6d,
0x74, 0x04, 0x5f, 0x74, 0x63, 0x70, 0x05, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x70, 0x70, 0x2d, 0x63, 0x6c, 0x69, 0x65, 0x6e,
0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x21, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x74, 0x04, 0x5f, 0x74, 0x63, 0x70, 0x05, 0x67,
0x21, 0x00, 0x01, 0x00, 0x00, 0x02, 0x43, 0x00, 0x1e, 0x00, 0x14, 0x00, 0x6d, 0x61, 0x69, 0x6c, 0x03, 0x63, 0x6f, 0x6d,
0x00, 0x14, 0x66, 0x04, 0x61, 0x6c, 0x74, 0x31, 0x04, 0x78, 0x6d, 0x70, 0x00, 0x00, 0x21, 0x00, 0x01, 0xc0, 0x0c, 0x00,
0x70, 0x01, 0x6c, 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63, 0x21, 0x00, 0x01, 0x00, 0x00, 0x02, 0x43, 0x00,
0x6f, 0x6d, 0x00, 0xc0, 0x0c, 0x00, 0x21, 0x00, 0x01, 0x00, 0x00, 0x02, 0x1e, 0x00, 0x14, 0x00, 0x00, 0x14, 0x66, 0x04,
0x43, 0x00, 0x1e, 0x00, 0x14, 0x00, 0x00, 0x14, 0x66, 0x04, 0x61, 0x6c, 0x61, 0x6c, 0x74, 0x31, 0x04, 0x78, 0x6d, 0x70,
0x74, 0x34, 0x04, 0x78, 0x6d, 0x70, 0x70, 0x01, 0x6c, 0x06, 0x67, 0x6f, 0x70, 0x01, 0x6c, 0x06, 0x67, 0x6f, 0x6f, 0x67,
0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0xc0, 0x0c, 0x00, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0xc0,
0x21, 0x00, 0x01, 0x00, 0x00, 0x02, 0x43, 0x00, 0x1e, 0x00, 0x14, 0x00, 0x0c, 0x00, 0x21, 0x00, 0x01, 0x00, 0x00, 0x02,
0x00, 0x14, 0x66, 0x04, 0x61, 0x6c, 0x74, 0x32, 0x04, 0x78, 0x6d, 0x70, 0x43, 0x00, 0x1e, 0x00, 0x14, 0x00, 0x00, 0x14,
0x70, 0x01, 0x6c, 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63, 0x66, 0x04, 0x61, 0x6c, 0x74, 0x34, 0x04, 0x78,
0x6f, 0x6d, 0x00, 0xc0, 0x0c, 0x00, 0x21, 0x00, 0x01, 0x00, 0x00, 0x02, 0x6d, 0x70, 0x70, 0x01, 0x6c, 0x06, 0x67, 0x6f,
0x43, 0x00, 0x19, 0x00, 0x05, 0x00, 0x00, 0x14, 0x66, 0x04, 0x78, 0x6d, 0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d,
0x70, 0x70, 0x01, 0x6c, 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, 0x00, 0xc0, 0x0c, 0x00, 0x21, 0x00, 0x01, 0x00,
0x63, 0x6f, 0x6d, 0x00, 0xc0, 0x0c, 0x00, 0x21, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x43, 0x00, 0x1e, 0x00, 0x14, 0x00,
0x02, 0x43, 0x00, 0x1e, 0x00, 0x14, 0x00, 0x00, 0x14, 0x66, 0x04, 0x61, 0x00, 0x14, 0x66, 0x04, 0x61, 0x6c, 0x74, 0x32,
0x6c, 0x74, 0x33, 0x04, 0x78, 0x6d, 0x70, 0x70, 0x01, 0x6c, 0x06, 0x67, 0x04, 0x78, 0x6d, 0x70, 0x70, 0x01, 0x6c, 0x06,
0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00, 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 main(int argc, char *argv[])
{ {
xmpp_ctx_t *ctx; xmpp_ctx_t *ctx;
unsigned char *udec; unsigned char *udec;

View File

@@ -1,8 +1,7 @@
/* test_ctx.c /* test_ctx.c
** libstrophe XMPP client library -- test routines for the library run-time ** libstrophe XMPP client library -- test routines for the library run-time context
*context
** **
** Copyright (C) 2005-2009 Collecta, Inc. ** Copyright (C) 2005-2009 Collecta, Inc.
** **
** This software is provided AS-IS with no warranty, either express ** This software is provided AS-IS with no warranty, either express
** or implied. ** or implied.
@@ -22,41 +21,33 @@ static int mem_alloc_called = 0;
static int mem_free_called = 0; static int mem_free_called = 0;
static int mem_realloc_called = 0; static int mem_realloc_called = 0;
void *my_alloc(size_t size, void *userdata) void *my_alloc(const size_t size, void * const userdata)
{ {
(void)userdata;
mem_alloc_called++; mem_alloc_called++;
return malloc(size); return malloc(size);
} }
void my_free(void *p, void *userdata) void my_free(void *p, void * const userdata)
{ {
(void)userdata;
mem_free_called++; mem_free_called++;
return free(p); return free(p);
} }
void *my_realloc(void *p, size_t size, void *userdata) void *my_realloc(void *p, const size_t size, void * const userdata)
{ {
(void)userdata;
mem_realloc_called++; mem_realloc_called++;
return realloc(p, size); return realloc(p, size);
} }
void my_logger(void *userdata, void my_logger(void * const userdata, const xmpp_log_level_t level,
xmpp_log_level_t level, const char * const area, const char * const msg)
const char *area,
const char *msg)
{ {
if (strcmp((char *)userdata, "asdf") == 0 && level == XMPP_LEVEL_DEBUG && if (strcmp((char *)userdata, "asdf") == 0 && level == XMPP_LEVEL_DEBUG
strcmp(area, "test") == 0 && strcmp(msg, "hello") == 0) && strcmp(area, "test") == 0 && strcmp(msg, "hello") == 0)
log_called++; log_called++;
} }
int main() int main(int argc, char **argv)
{ {
xmpp_ctx_t *ctx; xmpp_ctx_t *ctx;
xmpp_mem_t mymem; xmpp_mem_t mymem;
@@ -65,8 +56,7 @@ int main()
void *testptr1, *testptr2; void *testptr1, *testptr2;
ctx = xmpp_ctx_new(NULL, NULL); ctx = xmpp_ctx_new(NULL, NULL);
if (ctx == NULL) if (ctx == NULL) return 1;
return 1;
/* destroy context */ /* destroy context */
xmpp_ctx_free(ctx); xmpp_ctx_free(ctx);
@@ -85,15 +75,15 @@ int main()
testptr1 = xmpp_alloc(ctx, 1024); testptr1 = xmpp_alloc(ctx, 1024);
if (testptr1 == NULL) { if (testptr1 == NULL) {
xmpp_ctx_free(ctx); xmpp_ctx_free(ctx);
return 1; return 1;
} }
testptr2 = xmpp_realloc(ctx, testptr1, 2048); testptr2 = xmpp_realloc(ctx, testptr1, 2048);
if (testptr2 == NULL) { if (testptr2 == NULL) {
xmpp_free(ctx, testptr1); xmpp_free(ctx, testptr1);
xmpp_ctx_free(ctx); xmpp_ctx_free(ctx);
return 1; return 1;
} }
xmpp_free(ctx, testptr2); xmpp_free(ctx, testptr2);
@@ -101,11 +91,11 @@ int main()
xmpp_ctx_free(ctx); xmpp_ctx_free(ctx);
/* check for test failure */ /* check for test failure */
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) if (mem_alloc_called != mem_free_called)
return 1; return 1;
return 0; return 0;
} }

View File

@@ -1,49 +0,0 @@
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "strophe.h"
#include "parser.h"
void xmpp_initialize(void);
void cbtest_handle_start(char *name, char **attrs, void *userdata)
{
(void)name;
(void)attrs;
(void)userdata;
}
void cbtest_handle_end(char *name, void *userdata)
{
(void)name;
(void)userdata;
}
void cbtest_handle_stanza(xmpp_stanza_t *stanza, void *userdata)
{
(void)stanza;
(void)userdata;
}
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size)
{
xmpp_ctx_t *ctx;
parser_t *parser;
char *dup = malloc(Size);
memcpy(dup, Data, Size);
ctx = xmpp_ctx_new(NULL, NULL);
parser = parser_new(ctx, cbtest_handle_start, cbtest_handle_end,
cbtest_handle_stanza, NULL);
parser_feed(parser, dup, Size);
free(dup);
parser_free(parser);
xmpp_ctx_free(ctx);
return 0;
}

View File

@@ -1,7 +1,7 @@
/* test_hash.c /* test_hash.c
** libstrophe XMPP client library -- self-test for the hash-table implementation ** libstrophe XMPP client library -- self-test for the hash-table implementation
** **
** Copyright (C) 2005-2009 Collecta, Inc. ** Copyright (C) 2005-2009 Collecta, Inc.
** **
** This software is provided AS-IS with no warranty, either express ** This software is provided AS-IS with no warranty, either express
** or implied. ** or implied.
@@ -16,15 +16,18 @@
#include "strophe.h" #include "strophe.h"
#include "common.h" #include "common.h"
#include "hash.h" #include "hash.h"
#include "test.h"
#define TABLESIZE 100 #define TABLESIZE 100
#define TESTSIZE 500 #define TESTSIZE 500
/* static test data */ /* static test data */
const char *keys[] = {"foo", "bar", "baz", "quux", "xyzzy"}; const int nkeys = 5;
const char *values[] = {"wuzzle", "mug", "canonical", "rosebud", "lottery"}; const char *keys[] = {
const int nkeys = ARRAY_SIZE(keys); "foo", "bar", "baz", "quux", "xyzzy"
};
const char *values[] = {
"wuzzle", "mug", "canonical", "rosebud", "lottery"
};
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
@@ -39,10 +42,10 @@ int main(int argc, char **argv)
/* initialize random numbers */ /* initialize random numbers */
if (argc > 2) { if (argc > 2) {
/* use a seed from the command line */ /* use a seed from the command line */
seed = (unsigned int)atoi(argv[1]); seed = (unsigned int)atoi(argv[1]);
} else { } else {
seed = (unsigned int)clock(); seed = (unsigned int)clock();
} }
/* using random seed 'seed' */ /* using random seed 'seed' */
srand(seed); srand(seed);
@@ -50,81 +53,76 @@ int main(int argc, char **argv)
/* allocate a default context */ /* allocate a default context */
ctx = xmpp_ctx_new(NULL, NULL); ctx = xmpp_ctx_new(NULL, NULL);
if (ctx == NULL) { if (ctx == NULL) {
/* ctx allocation failed! */ /* ctx allocation failed! */
return -1; return -1;
} }
/* allocate a hash table */ /* allocate a hash table */
table = hash_new(ctx, TABLESIZE, xmpp_free); table = hash_new(ctx, TABLESIZE, NULL);
if (table == NULL) { if (table == NULL) {
/* table allocation failed! */ /* table allocation failed! */
return 1; return 1;
} }
/* test insertion */ /* test insertion */
for (i = 0; i < nkeys; i++) { for (i = 0; i < nkeys; i++) {
err = hash_add(table, keys[i], xmpp_strdup(ctx, values[i])); err = hash_add(table, keys[i], (void*)values[i]);
if (err) if (err) return err;
return err;
} }
/* test key count */ /* test key count */
if (hash_num_keys(table) != nkeys) { if (hash_num_keys(table) != nkeys) {
/* wrong number of keys in table! */ /* wrong number of keys in table! */
return 1; return 1;
} }
/* test replacing old values */ /* test replacing old values */
for (i = 0; i < nkeys; i++) { for (i = 0; i < nkeys; i++) {
err = hash_add(table, keys[0], xmpp_strdup(ctx, values[i])); err = hash_add(table, keys[0], (void*)values[i]);
if (err) if (err) return err;
return err; if (hash_num_keys(table) != nkeys) return 1;
if (hash_num_keys(table) != nkeys)
return 1;
result = hash_get(table, keys[0]); result = hash_get(table, keys[0]);
if (result == NULL) if (result == NULL) return 1;
return 1; if (strcmp(result, values[i]) != 0) return 1;
if (strcmp(result, values[i]) != 0)
return 1;
} }
/* restore value for the 1st key */ /* restore value for the 1st key */
hash_add(table, keys[0], xmpp_strdup(ctx, values[0])); hash_add(table, keys[0], (void*)values[0]);
/* test cloning */ /* test cloning */
clone = hash_clone(table); clone = hash_clone(table);
/* test lookup */ /* test lookup */
for (i = 0; i < nkeys; i++) { for (i = 0; i < nkeys; i++) {
result = hash_get(clone, keys[i]); result = hash_get(clone, keys[i]);
if (result == NULL) { if (result == NULL) {
/* lookup failed! */ /* lookup failed! */
return 1; return 1;
} }
if (strcmp(values[i], result)) { if (strcmp(values[i], result)) {
/* lookup returned incorrect value! */ /* lookup returned incorrect value! */
return 1; return 1;
} }
} }
/* test key iterator */ /* test key iterator */
iter = hash_iter_new(clone); iter = hash_iter_new(clone);
if (iter == NULL) { if (iter == NULL) {
/* iterator allocation failed! */ /* iterator allocation failed! */
return 1; return 1;
} }
for (i = 0; i < nkeys; i++) { for (i = 0; i < nkeys; i++) {
key = hash_iter_next(iter); key = hash_iter_next(iter);
printf("key: '%s'\n", key); printf("key: '%s'\n", key);
} }
key = hash_iter_next(iter); key = hash_iter_next(iter);
if (key != NULL) { if (key != NULL) {
/* extra keys returned! */ /* extra keys returned! */
return 1; return 1;
} }
key = hash_iter_next(iter); key = hash_iter_next(iter);
if (key != NULL) { if (key != NULL) {
/* extra keys returned! */ /* extra keys returned! */
return 1; return 1;
} }
hash_iter_release(iter); hash_iter_release(iter);
@@ -133,19 +131,14 @@ int main(int argc, char **argv)
/* test drops */ /* test drops */
hash_drop(clone, keys[2]); hash_drop(clone, keys[2]);
if (hash_get(clone, keys[2]) != NULL) if (hash_get(clone, keys[2]) != NULL) return 1;
return 1;
hash_drop(clone, keys[1]); hash_drop(clone, keys[1]);
hash_drop(clone, keys[4]); hash_drop(clone, keys[4]);
if (hash_get(clone, keys[4]) != NULL) if (hash_get(clone, keys[4]) != NULL) return 1;
return 1; if (hash_get(clone, keys[1]) != NULL) return 1;
if (hash_get(clone, keys[1]) != NULL)
return 1;
/* keys 0,3 should still be available */ /* keys 0,3 should still be available */
if (hash_get(clone, keys[0]) == NULL) if (hash_get(clone, keys[0]) == NULL) return 1;
return 1; if (hash_get(clone, keys[3]) == NULL) return 1;
if (hash_get(clone, keys[3]) == NULL)
return 1;
/* release our clone */ /* release our clone */
hash_release(clone); hash_release(clone);

View File

@@ -36,93 +36,61 @@ int test_jid(xmpp_ctx_t *ctx)
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", jid1, _s(node), _s(domain), printf("jid '%s' parsed to %s, %s, %s\n",
_s(resource)); jid1, _s(node), _s(domain), _s(resource));
if (bare == NULL || strcmp(bare, "foo@bar.com")) if (bare == NULL || strcmp(bare, "foo@bar.com")) return 1;
return 1; if (node == NULL || strcmp(node, "foo")) return 1;
if (node == NULL || strcmp(node, "foo")) if (domain == NULL || strcmp(domain, "bar.com")) return 1;
return 1; if (resource != NULL) return 1;
if (domain == NULL || strcmp(domain, "bar.com")) if (bare) xmpp_free(ctx, bare);
return 1; if (node) xmpp_free(ctx, node);
if (resource != NULL) if (domain) xmpp_free(ctx, domain);
return 1; if (resource) xmpp_free(ctx, resource);
if (bare)
xmpp_free(ctx, bare);
if (node)
xmpp_free(ctx, node);
if (domain)
xmpp_free(ctx, domain);
if (resource)
xmpp_free(ctx, resource);
bare = xmpp_jid_bare(ctx, jid2); 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", jid2, _s(node), _s(domain), printf("jid '%s' parsed to %s, %s, %s\n",
_s(resource)); jid2, _s(node), _s(domain), _s(resource));
if (bare == NULL || strcmp(bare, "anyone@example.com")) if (bare == NULL || strcmp(bare, "anyone@example.com")) return 1;
return 1; if (node == NULL || strcmp(node, "anyone")) return 1;
if (node == NULL || strcmp(node, "anyone")) if (domain == NULL || strcmp(domain, "example.com")) return 1;
return 1; if (resource == NULL || strcmp(resource, "hullo")) return 1;
if (domain == NULL || strcmp(domain, "example.com")) if (bare) xmpp_free(ctx, bare);
return 1; if (node) xmpp_free(ctx, node);
if (resource == NULL || strcmp(resource, "hullo")) if (domain) xmpp_free(ctx, domain);
return 1; if (resource) xmpp_free(ctx, resource);
if (bare)
xmpp_free(ctx, bare);
if (node)
xmpp_free(ctx, node);
if (domain)
xmpp_free(ctx, domain);
if (resource)
xmpp_free(ctx, resource);
bare = xmpp_jid_bare(ctx, jid3); 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", jid3, _s(node), _s(domain), printf("jid '%s' parsed to %s, %s, %s\n",
_s(resource)); jid3, _s(node), _s(domain), _s(resource));
if (bare == NULL || strcmp(bare, "manic.porter@xyz.net")) if (bare == NULL || strcmp(bare, "manic.porter@xyz.net")) return 1;
return 1; if (node == NULL || strcmp(node, "manic.porter")) return 1;
if (node == NULL || strcmp(node, "manic.porter")) if (domain == NULL || strcmp(domain, "xyz.net")) return 1;
return 1; if (resource == NULL || strcmp(resource, "frob")) return 1;
if (domain == NULL || strcmp(domain, "xyz.net")) if (bare) xmpp_free(ctx, bare);
return 1; if (node) xmpp_free(ctx, node);
if (resource == NULL || strcmp(resource, "frob")) if (domain) xmpp_free(ctx, domain);
return 1; if (resource) xmpp_free(ctx, resource);
if (bare)
xmpp_free(ctx, bare);
if (node)
xmpp_free(ctx, node);
if (domain)
xmpp_free(ctx, domain);
if (resource)
xmpp_free(ctx, resource);
bare = xmpp_jid_bare(ctx, jid4); 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", jid4, _s(node), _s(domain), printf("jid '%s' parsed to %s, %s, %s\n",
_s(resource)); jid4, _s(node), _s(domain), _s(resource));
if (bare == NULL || strcmp(bare, "domain.tld")) if (bare == NULL || strcmp(bare, "domain.tld")) return 1;
return 1; if (node != NULL) return 1;
if (node != NULL) if (domain == NULL || strcmp(domain, "domain.tld")) return 1;
return 1; if (resource != NULL) return 1;
if (domain == NULL || strcmp(domain, "domain.tld")) if (bare) xmpp_free(ctx, bare);
return 1; if (node) xmpp_free(ctx, node);
if (resource != NULL) if (domain) xmpp_free(ctx, domain);
return 1; if (resource) xmpp_free(ctx, resource);
if (bare)
xmpp_free(ctx, bare);
if (node)
xmpp_free(ctx, node);
if (domain)
xmpp_free(ctx, domain);
if (resource)
xmpp_free(ctx, resource);
return 0; return 0;
} }
@@ -133,46 +101,38 @@ int test_jid_new(xmpp_ctx_t *ctx)
jid = xmpp_jid_new(ctx, "node", "domain", "resource"); jid = xmpp_jid_new(ctx, "node", "domain", "resource");
printf("new jid: '%s'\n", jid); printf("new jid: '%s'\n", jid);
if (strcmp(jid, "node@domain/resource")) if (strcmp(jid, "node@domain/resource")) return 1;
return 1;
xmpp_free(ctx, jid); xmpp_free(ctx, jid);
jid = xmpp_jid_new(ctx, "foo", "bar.com", NULL); jid = xmpp_jid_new(ctx, "foo", "bar.com", NULL);
printf("new jid: '%s'\n", jid); printf("new jid: '%s'\n", jid);
if (strcmp(jid, "foo@bar.com")) if (strcmp(jid, "foo@bar.com")) return 1;
return 1;
xmpp_free(ctx, jid); xmpp_free(ctx, jid);
return 0; return 0;
} }
int main() int main(int argc, char *argv[])
{ {
xmpp_ctx_t *ctx; xmpp_ctx_t *ctx;
int ret; int ret;
printf("allocating context... "); printf("allocating context... ");
ctx = xmpp_ctx_new(NULL, NULL); ctx = xmpp_ctx_new(NULL, NULL);
if (ctx == NULL) if (ctx == NULL) printf("failed to create context\n");
printf("failed to create context\n"); 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...\n");
ret = test_jid(ctx); ret = test_jid(ctx);
if (ret) if (ret) printf("testing jid routines... failed!\n");
printf("testing jid routines... failed!\n"); if (ret) return ret;
if (ret)
return ret;
printf("testing jid routines... ok.\n"); printf("testing jid routines... ok.\n");
printf("testing jid new routines...\n"); printf("testing jid new routines...\n");
ret = test_jid_new(ctx); ret = test_jid_new(ctx);
if (ret) if (ret) printf("testing jid new routines... failed!\n");
printf("testing jid new routines... failed!\n"); if (ret) return ret;
if (ret)
return ret;
printf("testing jid new routines... ok.\n"); printf("testing jid new routines... ok.\n");
printf("freeing context... "); printf("freeing context... ");

View File

@@ -57,7 +57,7 @@ static const struct {
}, },
}; };
int main() int main(int argc, char **argv)
{ {
struct MD5Context ctx; struct MD5Context ctx;
unsigned char digest[16]; unsigned char digest[16];

View File

@@ -21,31 +21,14 @@
#include "rand.c" #include "rand.c"
/* stubs to build test without whole libstrophe */ /* stubs to build test without whole libstrophe */
void *xmpp_alloc(const xmpp_ctx_t *ctx, size_t size) void *xmpp_alloc(const xmpp_ctx_t * const ctx, const size_t size) {
{
(void)ctx;
(void)size;
return NULL; return NULL;
} }
void xmpp_free(const xmpp_ctx_t * const ctx, void *p) { }
void xmpp_free(const xmpp_ctx_t *ctx, void *p) int xmpp_snprintf (char *str, size_t count, const char *fmt, ...) {
{
(void)ctx;
(void)p;
}
#ifndef HAVE_SNPRINTF
int xmpp_snprintf(char *str, size_t count, const char *fmt, ...)
{
(void)str;
(void)count;
(void)fmt;
return 0; return 0;
} }
#endif /* HAVE_SNPRINTF */ uint64_t time_stamp(void) {
uint64_t time_stamp(void)
{
return 0; return 0;
} }
@@ -138,8 +121,8 @@ int main()
&entropy_input_len); &entropy_input_len);
test_hex_to_bin(test_vectors[i].nonce, nonce, &nonce_len); test_hex_to_bin(test_vectors[i].nonce, nonce, &nonce_len);
Hash_DRBG_Instantiate(&ctx, entropy_input, entropy_input_len, nonce, Hash_DRBG_Instantiate(&ctx, entropy_input, entropy_input_len,
nonce_len); nonce, nonce_len);
COMPARE(test_vectors[i].V1, test_bin_to_hex(ctx.V, sizeof(ctx.V))); COMPARE(test_vectors[i].V1, test_bin_to_hex(ctx.V, sizeof(ctx.V)));
COMPARE(test_vectors[i].C1, test_bin_to_hex(ctx.C, sizeof(ctx.C))); COMPARE(test_vectors[i].C1, test_bin_to_hex(ctx.C, sizeof(ctx.C)));
assert(ctx.reseed_counter == 1); assert(ctx.reseed_counter == 1);

View File

@@ -19,94 +19,117 @@
/* res_query("_xmpp-client._tcp.jabber.kiev.ua", C_IN, T_SRV, ...) */ /* res_query("_xmpp-client._tcp.jabber.kiev.ua", C_IN, T_SRV, ...) */
static const unsigned char data1[] = { static const unsigned char data1[] = {
0x95, 0xf3, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x95, 0xf3, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
0x0c, 0x5f, 0x78, 0x6d, 0x70, 0x70, 0x2d, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x5f, 0x78, 0x6d,
0x74, 0x04, 0x5f, 0x74, 0x63, 0x70, 0x06, 0x6a, 0x61, 0x62, 0x62, 0x65, 0x70, 0x70, 0x2d, 0x63, 0x6c, 0x69, 0x65, 0x6e,
0x72, 0x04, 0x6b, 0x69, 0x65, 0x76, 0x02, 0x75, 0x61, 0x00, 0x00, 0x21, 0x74, 0x04, 0x5f, 0x74, 0x63, 0x70, 0x06, 0x6a,
0x00, 0x01, 0xc0, 0x0c, 0x00, 0x21, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3b, 0x61, 0x62, 0x62, 0x65, 0x72, 0x04, 0x6b, 0x69,
0x00, 0x16, 0x00, 0x01, 0x00, 0x00, 0x14, 0x66, 0x06, 0x6a, 0x61, 0x62, 0x65, 0x76, 0x02, 0x75, 0x61, 0x00, 0x00, 0x21,
0x62, 0x65, 0x72, 0x04, 0x6b, 0x69, 0x65, 0x76, 0x02, 0x75, 0x61, 0x00, 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, ...) */ /* res_query("_xmpp-client._tcp.jabber.org", C_IN, T_SRV, ...) */
static const unsigned char data2[] = { static const unsigned char data2[] = {
0xf2, 0x98, 0x81, 0x80, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0xf2, 0x98, 0x81, 0x80, 0x00, 0x01, 0x00, 0x02,
0x0c, 0x5f, 0x78, 0x6d, 0x70, 0x70, 0x2d, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x5f, 0x78, 0x6d,
0x74, 0x04, 0x5f, 0x74, 0x63, 0x70, 0x06, 0x6a, 0x61, 0x62, 0x62, 0x65, 0x70, 0x70, 0x2d, 0x63, 0x6c, 0x69, 0x65, 0x6e,
0x72, 0x03, 0x6f, 0x72, 0x67, 0x00, 0x00, 0x21, 0x00, 0x01, 0xc0, 0x0c, 0x74, 0x04, 0x5f, 0x74, 0x63, 0x70, 0x06, 0x6a,
0x00, 0x21, 0x00, 0x01, 0x00, 0x00, 0x03, 0x83, 0x00, 0x1a, 0x00, 0x1e, 0x61, 0x62, 0x62, 0x65, 0x72, 0x03, 0x6f, 0x72,
0x00, 0x1e, 0x14, 0x66, 0x07, 0x68, 0x65, 0x72, 0x6d, 0x65, 0x73, 0x32, 0x67, 0x00, 0x00, 0x21, 0x00, 0x01, 0xc0, 0x0c,
0x06, 0x6a, 0x61, 0x62, 0x62, 0x65, 0x72, 0x03, 0x6f, 0x72, 0x67, 0x00, 0x00, 0x21, 0x00, 0x01, 0x00, 0x00, 0x03, 0x83,
0xc0, 0x0c, 0x00, 0x21, 0x00, 0x01, 0x00, 0x00, 0x03, 0x83, 0x00, 0x1c, 0x00, 0x1a, 0x00, 0x1e, 0x00, 0x1e, 0x14, 0x66,
0x00, 0x1f, 0x00, 0x1e, 0x14, 0x66, 0x09, 0x68, 0x65, 0x72, 0x6d, 0x65, 0x07, 0x68, 0x65, 0x72, 0x6d, 0x65, 0x73, 0x32,
0x73, 0x32, 0x76, 0x36, 0x06, 0x6a, 0x61, 0x62, 0x62, 0x65, 0x72, 0x03, 0x06, 0x6a, 0x61, 0x62, 0x62, 0x65, 0x72, 0x03,
0x6f, 0x72, 0x67, 0x00, 0xc0, 0x0c, 0x00, 0x21,
0x00, 0x01, 0x00, 0x00, 0x03, 0x83, 0x00, 0x1c,
0x00, 0x1f, 0x00, 0x1e, 0x14, 0x66, 0x09, 0x68,
0x65, 0x72, 0x6d, 0x65, 0x73, 0x32, 0x76, 0x36,
0x06, 0x6a, 0x61, 0x62, 0x62, 0x65, 0x72, 0x03,
0x6f, 0x72, 0x67, 0x00, 0x6f, 0x72, 0x67, 0x00,
}; };
/* res_query("_xmpp-client._tcp.gmail.com", C_IN, T_SRV, ...) */ /* res_query("_xmpp-client._tcp.gmail.com", C_IN, T_SRV, ...) */
static const unsigned char data3[] = { static const unsigned char data3[] = {
0xda, 0xa8, 0x81, 0x80, 0x00, 0x01, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0xda, 0xa8, 0x81, 0x80, 0x00, 0x01, 0x00, 0x05,
0x0c, 0x5f, 0x78, 0x6d, 0x70, 0x70, 0x2d, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x5f, 0x78, 0x6d,
0x74, 0x04, 0x5f, 0x74, 0x63, 0x70, 0x05, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x70, 0x70, 0x2d, 0x63, 0x6c, 0x69, 0x65, 0x6e,
0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x21, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x74, 0x04, 0x5f, 0x74, 0x63, 0x70, 0x05, 0x67,
0x21, 0x00, 0x01, 0x00, 0x00, 0x02, 0x43, 0x00, 0x1e, 0x00, 0x14, 0x00, 0x6d, 0x61, 0x69, 0x6c, 0x03, 0x63, 0x6f, 0x6d,
0x00, 0x14, 0x66, 0x04, 0x61, 0x6c, 0x74, 0x31, 0x04, 0x78, 0x6d, 0x70, 0x00, 0x00, 0x21, 0x00, 0x01, 0xc0, 0x0c, 0x00,
0x70, 0x01, 0x6c, 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63, 0x21, 0x00, 0x01, 0x00, 0x00, 0x02, 0x43, 0x00,
0x6f, 0x6d, 0x00, 0xc0, 0x0c, 0x00, 0x21, 0x00, 0x01, 0x00, 0x00, 0x02, 0x1e, 0x00, 0x14, 0x00, 0x00, 0x14, 0x66, 0x04,
0x43, 0x00, 0x1e, 0x00, 0x14, 0x00, 0x00, 0x14, 0x66, 0x04, 0x61, 0x6c, 0x61, 0x6c, 0x74, 0x31, 0x04, 0x78, 0x6d, 0x70,
0x74, 0x34, 0x04, 0x78, 0x6d, 0x70, 0x70, 0x01, 0x6c, 0x06, 0x67, 0x6f, 0x70, 0x01, 0x6c, 0x06, 0x67, 0x6f, 0x6f, 0x67,
0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0xc0, 0x0c, 0x00, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0xc0,
0x21, 0x00, 0x01, 0x00, 0x00, 0x02, 0x43, 0x00, 0x1e, 0x00, 0x14, 0x00, 0x0c, 0x00, 0x21, 0x00, 0x01, 0x00, 0x00, 0x02,
0x00, 0x14, 0x66, 0x04, 0x61, 0x6c, 0x74, 0x32, 0x04, 0x78, 0x6d, 0x70, 0x43, 0x00, 0x1e, 0x00, 0x14, 0x00, 0x00, 0x14,
0x70, 0x01, 0x6c, 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63, 0x66, 0x04, 0x61, 0x6c, 0x74, 0x34, 0x04, 0x78,
0x6f, 0x6d, 0x00, 0xc0, 0x0c, 0x00, 0x21, 0x00, 0x01, 0x00, 0x00, 0x02, 0x6d, 0x70, 0x70, 0x01, 0x6c, 0x06, 0x67, 0x6f,
0x43, 0x00, 0x19, 0x00, 0x05, 0x00, 0x00, 0x14, 0x66, 0x04, 0x78, 0x6d, 0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d,
0x70, 0x70, 0x01, 0x6c, 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, 0x00, 0xc0, 0x0c, 0x00, 0x21, 0x00, 0x01, 0x00,
0x63, 0x6f, 0x6d, 0x00, 0xc0, 0x0c, 0x00, 0x21, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x43, 0x00, 0x1e, 0x00, 0x14, 0x00,
0x02, 0x43, 0x00, 0x1e, 0x00, 0x14, 0x00, 0x00, 0x14, 0x66, 0x04, 0x61, 0x00, 0x14, 0x66, 0x04, 0x61, 0x6c, 0x74, 0x32,
0x6c, 0x74, 0x33, 0x04, 0x78, 0x6d, 0x70, 0x70, 0x01, 0x6c, 0x06, 0x67, 0x04, 0x78, 0x6d, 0x70, 0x70, 0x01, 0x6c, 0x06,
0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00, 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, ...) */ /* res_query("_xmpp-client._tcp.jabber.calyxinstitute.org", C_IN, T_SRV, ...) */
static const unsigned char data4[] = { static const unsigned char data4[] = {
0x8d, 0x58, 0x81, 0x80, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, // .X........ 0x8d, 0x58, 0x81, 0x80, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, // .X........
0x00, 0x00, 0x0c, 0x5f, 0x78, 0x6d, 0x70, 0x70, 0x2d, 0x63, // ..._xmpp-c 0x00, 0x00, 0x0c, 0x5f, 0x78, 0x6d, 0x70, 0x70, 0x2d, 0x63, // ..._xmpp-c
0x6c, 0x69, 0x65, 0x6e, 0x74, 0x04, 0x5f, 0x74, 0x63, 0x70, // lient._tcp 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x04, 0x5f, 0x74, 0x63, 0x70, // lient._tcp
0x06, 0x6a, 0x61, 0x62, 0x62, 0x65, 0x72, 0x0e, 0x63, 0x61, // .jabber.ca 0x06, 0x6a, 0x61, 0x62, 0x62, 0x65, 0x72, 0x0e, 0x63, 0x61, // .jabber.ca
0x6c, 0x79, 0x78, 0x69, 0x6e, 0x73, 0x74, 0x69, 0x74, 0x75, // lyxinstitu 0x6c, 0x79, 0x78, 0x69, 0x6e, 0x73, 0x74, 0x69, 0x74, 0x75, // lyxinstitu
0x74, 0x65, 0x03, 0x6f, 0x72, 0x67, 0x00, 0x00, 0x21, 0x00, // te.org..!. 0x74, 0x65, 0x03, 0x6f, 0x72, 0x67, 0x00, 0x00, 0x21, 0x00, // te.org..!.
0x01, 0xc0, 0x0c, 0x00, 0x21, 0x00, 0x01, 0x00, 0x00, 0x03, // ....!..... 0x01, 0xc0, 0x0c, 0x00, 0x21, 0x00, 0x01, 0x00, 0x00, 0x03, // ....!.....
0x83, 0x00, 0x1e, 0x00, 0x04, 0x00, 0x00, 0x14, 0x66, 0x10, // ........f. 0x83, 0x00, 0x1e, 0x00, 0x04, 0x00, 0x00, 0x14, 0x66, 0x10, // ........f.
0x69, 0x6a, 0x65, 0x65, 0x79, 0x6e, 0x72, 0x63, 0x36, 0x78, // ijeeynrc6x 0x69, 0x6a, 0x65, 0x65, 0x79, 0x6e, 0x72, 0x63, 0x36, 0x78, // ijeeynrc6x
0x32, 0x75, 0x79, 0x35, 0x6f, 0x62, 0x05, 0x6f, 0x6e, 0x69, // 2uy5ob.oni 0x32, 0x75, 0x79, 0x35, 0x6f, 0x62, 0x05, 0x6f, 0x6e, 0x69, // 2uy5ob.oni
0x6f, 0x6e, 0x00, 0xc0, 0x0c, 0x00, 0x21, 0x00, 0x01, 0x00, // on....!... 0x6f, 0x6e, 0x00, 0xc0, 0x0c, 0x00, 0x21, 0x00, 0x01, 0x00, // on....!...
0x00, 0x03, 0x83, 0x00, 0x21, 0x00, 0x05, 0x00, 0x01, 0x14, // ....!..... 0x00, 0x03, 0x83, 0x00, 0x21, 0x00, 0x05, 0x00, 0x01, 0x14, // ....!.....
0x66, 0x06, 0x6a, 0x61, 0x62, 0x62, 0x65, 0x72, 0x0e, 0x63, // f.jabber.c 0x66, 0x06, 0x6a, 0x61, 0x62, 0x62, 0x65, 0x72, 0x0e, 0x63, // f.jabber.c
0x61, 0x6c, 0x79, 0x78, 0x69, 0x6e, 0x73, 0x74, 0x69, 0x74, // alyxinstit 0x61, 0x6c, 0x79, 0x78, 0x69, 0x6e, 0x73, 0x74, 0x69, 0x74, // alyxinstit
0x75, 0x74, 0x65, 0x03, 0x6f, 0x72, 0x67, 0x00, // ute.org. 0x75, 0x74, 0x65, 0x03, 0x6f, 0x72, 0x67, 0x00, // ute.org.
}; };
/* res_query("_xmpp-client._tcp.jabber.org", C_IN, T_SRV, ...) with pointers */ /* res_query("_xmpp-client._tcp.jabber.org", C_IN, T_SRV, ...) with pointers */
static const unsigned char data5[] = { static const unsigned char data5[] = {
0x00, 0x00, 0x81, 0x80, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, // .......... 0x00, 0x00, 0x81, 0x80, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, // ..........
0x00, 0x00, 0x0c, 0x5f, 0x78, 0x6d, 0x70, 0x70, 0x2d, 0x63, // ..._xmpp-c 0x00, 0x00, 0x0c, 0x5f, 0x78, 0x6d, 0x70, 0x70, 0x2d, 0x63, // ..._xmpp-c
0x6c, 0x69, 0x65, 0x6e, 0x74, 0x04, 0x5f, 0x74, 0x63, 0x70, // lient._tcp 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x04, 0x5f, 0x74, 0x63, 0x70, // lient._tcp
0x06, 0x6a, 0x61, 0x62, 0x62, 0x65, 0x72, 0x03, 0x6f, 0x72, // .jabber.or 0x06, 0x6a, 0x61, 0x62, 0x62, 0x65, 0x72, 0x03, 0x6f, 0x72, // .jabber.or
0x67, 0x00, 0x00, 0x21, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x21, // g..!.....! 0x67, 0x00, 0x00, 0x21, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x21, // g..!.....!
0x00, 0x01, 0x00, 0x00, 0x01, 0x9e, 0x00, 0x12, 0x00, 0x1f, // .......... 0x00, 0x01, 0x00, 0x00, 0x01, 0x9e, 0x00, 0x12, 0x00, 0x1f, // ..........
0x00, 0x1e, 0x14, 0x66, 0x09, 0x68, 0x65, 0x72, 0x6d, 0x65, // ...f.herme 0x00, 0x1e, 0x14, 0x66, 0x09, 0x68, 0x65, 0x72, 0x6d, 0x65, // ...f.herme
0x73, 0x32, 0x76, 0x36, 0xc0, 0x1e, 0xc0, 0x0c, 0x00, 0x21, // s2v6.....! 0x73, 0x32, 0x76, 0x36, 0xc0, 0x1e, 0xc0, 0x0c, 0x00, 0x21, // s2v6.....!
0x00, 0x01, 0x00, 0x00, 0x01, 0x9e, 0x00, 0x10, 0x00, 0x1e, // .......... 0x00, 0x01, 0x00, 0x00, 0x01, 0x9e, 0x00, 0x10, 0x00, 0x1e, // ..........
0x00, 0x1e, 0x14, 0x66, 0x07, 0x68, 0x65, 0x72, 0x6d, 0x65, // ...f.herme 0x00, 0x1e, 0x14, 0x66, 0x07, 0x68, 0x65, 0x72, 0x6d, 0x65, // ...f.herme
0x73, 0x32, 0xc0, 0x1e, // s2.. 0x73, 0x32, 0xc0, 0x1e, // s2..
}; };
/* hacked data2 with two empty-string targets. */ /* hacked data2 with two empty-string targets. */
static const unsigned char data6[] = { static const unsigned char data6[] = {
0xf2, 0x98, 0x81, 0x80, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0xf2, 0x98, 0x81, 0x80, 0x00, 0x01, 0x00, 0x02,
0x00, 0x0c, 0x5f, 0x78, 0x6d, 0x70, 0x70, 0x2d, 0x63, 0x6c, 0x69, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x5f, 0x78, 0x6d,
0x65, 0x6e, 0x74, 0x04, 0x5f, 0x74, 0x63, 0x70, 0x06, 0x6a, 0x61, 0x70, 0x70, 0x2d, 0x63, 0x6c, 0x69, 0x65, 0x6e,
0x62, 0x62, 0x65, 0x72, 0x03, 0x6f, 0x72, 0x67, 0x00, 0x00, 0x21, 0x74, 0x04, 0x5f, 0x74, 0x63, 0x70, 0x06, 0x6a,
0x00, 0x01, 0xc0, 0x0c, 0x00, 0x21, 0x00, 0x01, 0x00, 0x00, 0x03, 0x61, 0x62, 0x62, 0x65, 0x72, 0x03, 0x6f, 0x72,
0x83, 0x00, 0x07, 0x00, 0x1e, 0x00, 0x1e, 0x14, 0x66, 0x00, 0xc0, 0x67, 0x00, 0x00, 0x21, 0x00, 0x01, 0xc0, 0x0c,
0x0c, 0x00, 0x21, 0x00, 0x01, 0x00, 0x00, 0x03, 0x83, 0x00, 0x08, 0x00, 0x21, 0x00, 0x01, 0x00, 0x00, 0x03, 0x83,
0x00, 0x1f, 0x00, 0x1e, 0x14, 0x66, 0xc0, 0x40, 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 { static const struct {
@@ -164,13 +187,12 @@ static int srv_rr_list_len(resolver_srv_rr_t *list)
{ {
int nr; int nr;
for (nr = 0; list != NULL; ++nr, list = list->next) for (nr = 0; list != NULL; ++nr, list = list->next);
;
return nr; return nr;
} }
int main() int main(int argc, char **argv)
{ {
xmpp_ctx_t *ctx; xmpp_ctx_t *ctx;
xmpp_rand_t *rand; xmpp_rand_t *rand;
@@ -201,8 +223,8 @@ int main()
port = srv_rr_list->port; port = srv_rr_list->port;
COMPARE(tests[i].target, domain); COMPARE(tests[i].target, domain);
if (tests[i].port != port) { if (tests[i].port != port) {
printf("fail! got port=%u, but should be %u\n", (unsigned)port, printf("fail! got port=%u, but should be %u\n",
(unsigned)tests[i].port); (unsigned)port, (unsigned)tests[i].port);
return 1; return 1;
} }
printf("ok\n"); printf("ok\n");

View File

@@ -1,7 +1,7 @@
/* test_sasl.c /* test_sasl.c
** libstrophe XMPP client library -- test routines for the SASL implementation ** libstrophe XMPP client library -- test routines for the SASL implementation
** **
** Copyright (C) 2005-2009 Collecta, Inc. ** Copyright (C) 2005-2009 Collecta, Inc.
** **
** This software is provided AS-IS with no warranty, either express ** This software is provided AS-IS with no warranty, either express
** or implied. ** or implied.
@@ -20,32 +20,32 @@ static const unsigned char jid[] = "foo@bar.com";
static const char password[] = "secret"; static const char password[] = "secret";
static const char response_plain[] = "AGZvb0BiYXIuY29tAHNlY3JldA=="; static const char response_plain[] = "AGZvb0BiYXIuY29tAHNlY3JldA==";
static const char challenge_md5[] = static const char challenge_md5[] =
"cmVhbG09InNvbWVyZWFsbSIsbm9uY2U9Ik9BNk1HOXRFUUdtMmhoIixxb3A9ImF1dGgi" "cmVhbG09InNvbWVyZWFsbSIsbm9uY2U9Ik9BNk1HOXRFUUdtMmhoIixxb3A9ImF1dGgi"
"LGNoYXJzZXQ9dXRmLTgsYWxnb3JpdGhtPW1kNS1zZXNzCg=="; "LGNoYXJzZXQ9dXRmLTgsYWxnb3JpdGhtPW1kNS1zZXNzCg==";
static const char response_md5[] = static const char response_md5[] =
"dXNlcm5hbWU9InNvbWVub2RlIixyZWFsbT0ic29tZXJlYWxtIixub25jZT0i" "dXNlcm5hbWU9InNvbWVub2RlIixyZWFsbT0ic29tZXJlYWxtIixub25jZT0i"
"T0E2TUc5dEVRR20yaGgiLGNub25jZT0iMDBERUFEQkVFRjAwIixuYz0wMDAw" "T0E2TUc5dEVRR20yaGgiLGNub25jZT0iMDBERUFEQkVFRjAwIixuYz0wMDAw"
"MDAwMSxxb3A9YXV0aCxkaWdlc3QtdXJpPSJ4bXBwL3NvbWVyZWFsbSIscmVz" "MDAwMSxxb3A9YXV0aCxkaWdlc3QtdXJpPSJ4bXBwL3NvbWVyZWFsbSIscmVz"
"cG9uc2U9NGVhNmU4N2JjMDkzMzUwNzQzZGIyOGQ3MDIwOGNhZmIsY2hhcnNl" "cG9uc2U9NGVhNmU4N2JjMDkzMzUwNzQzZGIyOGQ3MDIwOGNhZmIsY2hhcnNl"
"dD11dGYtOA=="; "dD11dGYtOA==";
static const char response_md5_rfc[] = static const char response_md5_rfc[] =
"dXNlcm5hbWU9InNvbWVub2RlIixyZWFsbT0ic29tZXJlYWxtIixub25jZT0i" "dXNlcm5hbWU9InNvbWVub2RlIixyZWFsbT0ic29tZXJlYWxtIixub25jZT0i"
"T0E2TUc5dEVRR20yaGgiLGNub25jZT0iT0E2TUhYaDZWcVRyUmsiLG5jPTAw" "T0E2TUc5dEVRR20yaGgiLGNub25jZT0iT0E2TUhYaDZWcVRyUmsiLG5jPTAw"
"MDAwMDAxLHFvcD1hdXRoLGRpZ2VzdC11cmk9InhtcHAvZXhhbXBsZS5jb20i" "MDAwMDAxLHFvcD1hdXRoLGRpZ2VzdC11cmk9InhtcHAvZXhhbXBsZS5jb20i"
"LHJlc3BvbnNlPWQzODhkYWQ5MGQ0YmJkNzYwYTE1MjMyMWYyMTQzYWY3LGNo" "LHJlc3BvbnNlPWQzODhkYWQ5MGQ0YmJkNzYwYTE1MjMyMWYyMTQzYWY3LGNo"
"YXJzZXQ9dXRmLTgK"; "YXJzZXQ9dXRmLTgK";
static const char challenge_md5_2[] = static const char challenge_md5_2[] =
"cmVhbG09ImVsd29vZC5pbm5vc29mdC5jb20iLG5vbmNlPSJPQTZNRzl0" "cmVhbG09ImVsd29vZC5pbm5vc29mdC5jb20iLG5vbmNlPSJPQTZNRzl0"
"RVFHbTJoaCIscW9wPSJhdXRoIixhbGdvcml0aG09bWQ1LXNlc3MsY2hh" "RVFHbTJoaCIscW9wPSJhdXRoIixhbGdvcml0aG09bWQ1LXNlc3MsY2hh"
"cnNldD11dGYtOA=="; "cnNldD11dGYtOA==";
static const char response_md5_2[] = static const char response_md5_2[] =
"Y2hhcnNldD11dGYtOCx1c2VybmFtZT0iY2hyaXMiLHJlYWxtPSJlbHdvb2" "Y2hhcnNldD11dGYtOCx1c2VybmFtZT0iY2hyaXMiLHJlYWxtPSJlbHdvb2"
"QuaW5ub3NvZnQuY29tIixub25jZT0iT0E2TUc5dEVRR20yaGgiLG5jPTAw" "QuaW5ub3NvZnQuY29tIixub25jZT0iT0E2TUc5dEVRR20yaGgiLG5jPTAw"
"MDAwMDAxLGNub25jZT0iT0E2TUhYaDZWcVRyUmsiLGRpZ2VzdC11cmk9Im" "MDAwMDAxLGNub25jZT0iT0E2TUhYaDZWcVRyUmsiLGRpZ2VzdC11cmk9Im"
"ltYXAvZWx3b29kLmlubm9zb2Z0LmNvbSIscmVzcG9uc2U9ZDM4OGRhZDkw" "ltYXAvZWx3b29kLmlubm9zb2Z0LmNvbSIscmVzcG9uc2U9ZDM4OGRhZDkw"
"ZDRiYmQ3NjBhMTUyMzIxZjIxNDNhZjcscW9wPWF1dGg="; "ZDRiYmQ3NjBhMTUyMzIxZjIxNDNhZjcscW9wPWF1dGg=";
int test_plain(xmpp_ctx_t *ctx) int test_plain(xmpp_ctx_t *ctx)
{ {
@@ -53,12 +53,12 @@ int test_plain(xmpp_ctx_t *ctx)
result = sasl_plain(ctx, jid, password); result = sasl_plain(ctx, jid, password);
if (result == NULL) { if (result == NULL) {
/* SASL PLAIN internal failure! */ /* SASL PLAIN internal failure! */
return 1; return 1;
} }
if (strncmp(response_plain, result, strlen(response_plain))) { if (strncmp(response_plain, result, strlen(response_plain))) {
/* SASL PLAIN returned incorrect string! */ /* SASL PLAIN returned incorrect string! */
return 2; return 2;
} }
xmpp_free(ctx, result); xmpp_free(ctx, result);
@@ -69,44 +69,38 @@ int test_digest_md5(xmpp_ctx_t *ctx)
{ {
char *result; char *result;
result = result = sasl_digest_md5(ctx, challenge_md5,
sasl_digest_md5(ctx, challenge_md5, "somenode@somerealm", "secret"); "somenode@somerealm", "secret");
printf("response:\n%s\n", result); printf("response:\n%s\n", result);
if (strcmp(response_md5, result)) { if (strcmp(response_md5, result)) {
/* generated incorrect response to challenge */ /* generated incorrect response to challenge */
return 1; return 1;
} }
return 0; return 0;
} }
int main() int main(int argc, char *argv[])
{ {
xmpp_ctx_t *ctx; xmpp_ctx_t *ctx;
int ret; int ret;
printf("allocating context... "); printf("allocating context... ");
ctx = xmpp_ctx_new(NULL, NULL); ctx = xmpp_ctx_new(NULL, NULL);
if (ctx == NULL) if (ctx == NULL) printf("failed to create context\n");
printf("failed to create context\n"); if (ctx == NULL) return -1;
if (ctx == NULL)
return -1;
printf("ok.\n"); printf("ok.\n");
printf("testing SASL PLAIN... "); printf("testing SASL PLAIN... ");
ret = test_plain(ctx); ret = test_plain(ctx);
if (ret) if (ret) printf("failed!\n");
printf("failed!\n"); if (ret) return ret;
if (ret)
return ret;
printf("ok.\n"); printf("ok.\n");
printf("testing SASL DIGEST-MD5... "); printf("testing SASL DIGEST-MD5... ");
ret = test_digest_md5(ctx); ret = test_digest_md5(ctx);
if (ret) if (ret) printf("failed!\n");
printf("failed!\n"); if (ret) return ret;
if (ret)
return ret;
printf("ok.\n"); printf("ok.\n");
printf("freeing context... "); printf("freeing context... ");

View File

@@ -25,12 +25,12 @@
* Test vectors for derivation function (RFC6070). * Test vectors for derivation function (RFC6070).
*/ */
static const struct { static const struct {
char *P; /* text */ char *P; /* text */
char *S; /* salt */ char *S; /* salt */
size_t P_len; size_t P_len;
size_t S_len; size_t S_len;
uint32_t c; /* i */ uint32_t c; /* i */
char *DK; /* resulting digest */ char *DK; /* resulting digest */
} df_vectors[] = { } df_vectors[] = {
{ {
.P = "password", .P = "password",
@@ -58,19 +58,19 @@ static const struct {
}, },
}; };
static void test_df(const struct hash_alg *alg) static void test_df(void)
{ {
size_t i; size_t i;
const char *s; const char *s;
uint8_t dk[SCRAM_DIGEST_SIZE]; uint8_t dk[SHA1_DIGEST_SIZE];
printf("Derivation function SCRAM_Hi tests for %s.\n", alg->scram_name); printf("Derivation function tests (SCRAM_SHA1_Hi).\n");
for (i = 0; i < ARRAY_SIZE(df_vectors); ++i) { for (i = 0; i < ARRAY_SIZE(df_vectors); ++i) {
printf("Test #%d: ", (int)i + 1); printf("Test #%d: ", (int)i + 1);
SCRAM_Hi(alg, (uint8_t *)df_vectors[i].P, df_vectors[i].P_len, 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, (uint8_t *)df_vectors[i].S, df_vectors[i].S_len,
df_vectors[i].c, dk); df_vectors[i].c, dk);
s = test_bin_to_hex(dk, alg->digest_size); s = test_bin_to_hex(dk, sizeof(dk));
COMPARE(df_vectors[i].DK, s); COMPARE(df_vectors[i].DK, s);
printf("ok\n"); printf("ok\n");
} }
@@ -101,115 +101,42 @@ static const struct {
}, },
}; };
static void test_scram(const struct hash_alg *alg) static void test_scram(void)
{ {
uint8_t key[SCRAM_DIGEST_SIZE]; uint8_t key[SHA1_DIGEST_SIZE];
uint8_t sign[SCRAM_DIGEST_SIZE]; uint8_t sign[SHA1_DIGEST_SIZE];
uint8_t salt[256]; uint8_t salt[256];
size_t salt_len; size_t salt_len;
char auth[512]; char auth[512];
const char *s; const char *s;
size_t i; size_t i;
size_t j; int j;
printf("SCRAM_ClientKey and SCRAM_ClientSignature tests for %s.\n", printf("SCRAM_SHA1_ClientKey and SCRAM_SHA1_ClientSignature tests.\n");
alg->scram_name);
for (i = 0; i < ARRAY_SIZE(scram_vectors); ++i) { for (i = 0; i < ARRAY_SIZE(scram_vectors); ++i) {
printf("Test #%d: ", (int)i + 1); printf("Test #%d: ", (int)i + 1);
snprintf(auth, sizeof(auth), "%s,%s,%s", scram_vectors[i].initial + 3, snprintf(auth, sizeof(auth), "%s,%s,%s",
scram_vectors[i].challenge, scram_vectors[i].response); scram_vectors[i].initial + 3, scram_vectors[i].challenge,
scram_vectors[i].response);
test_hex_to_bin(scram_vectors[i].salt, salt, &salt_len); test_hex_to_bin(scram_vectors[i].salt, salt, &salt_len);
SCRAM_ClientKey(alg, (uint8_t *)scram_vectors[i].password, SCRAM_SHA1_ClientKey((uint8_t *)scram_vectors[i].password,
strlen(scram_vectors[i].password), salt, salt_len, strlen(scram_vectors[i].password),
scram_vectors[i].i, key); salt, salt_len, scram_vectors[i].i, key);
SCRAM_ClientSignature(alg, key, (uint8_t *)auth, strlen(auth), sign); SCRAM_SHA1_ClientSignature(key, (uint8_t *)auth, strlen(auth), sign);
for (j = 0; j < alg->digest_size; j++) { for (j = 0; j < SHA1_DIGEST_SIZE; j++) {
sign[j] ^= key[j]; sign[j] ^= key[j];
} }
s = test_bin_to_hex(sign, alg->digest_size); s = test_bin_to_hex(sign, SHA1_DIGEST_SIZE);
COMPARE(scram_vectors[i].sign, s); COMPARE(scram_vectors[i].sign, s);
printf("ok\n"); printf("ok\n");
} }
} }
/* int main(int argc, char **argv)
* Test vectors for HMAC (RFC2202, RFC4231).
*/
static const uint8_t hmac_key1[] = {0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b};
static const uint8_t hmac_data1[] = {0x48, 0x69, 0x20, 0x54,
0x68, 0x65, 0x72, 0x65};
static const struct {
const uint8_t *key;
size_t key_len;
const uint8_t *data;
size_t data_len;
const uint8_t sha1[SHA1_DIGEST_SIZE];
const uint8_t sha256[SHA256_DIGEST_SIZE];
const uint8_t sha512[SHA512_DIGEST_SIZE];
} hmac_vectors[] = {
{
.key = hmac_key1,
.key_len = sizeof(hmac_key1),
.data = hmac_data1,
.data_len = sizeof(hmac_data1),
.sha1 = {0xb6, 0x17, 0x31, 0x86, 0x55, 0x05, 0x72, 0x64, 0xe2, 0x8b,
0xc0, 0xb6, 0xfb, 0x37, 0x8c, 0x8e, 0xf1, 0x46, 0xbe, 0x00},
.sha256 = {0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53,
0x5c, 0xa8, 0xaf, 0xce, 0xaf, 0x0b, 0xf1, 0x2b,
0x88, 0x1d, 0xc2, 0x00, 0xc9, 0x83, 0x3d, 0xa7,
0x26, 0xe9, 0x37, 0x6c, 0x2e, 0x32, 0xcf, 0xf7},
.sha512 = {0x87, 0xaa, 0x7c, 0xde, 0xa5, 0xef, 0x61, 0x9d, 0x4f, 0xf0,
0xb4, 0x24, 0x1a, 0x1d, 0x6c, 0xb0, 0x23, 0x79, 0xf4, 0xe2,
0xce, 0x4e, 0xc2, 0x78, 0x7a, 0xd0, 0xb3, 0x05, 0x45, 0xe1,
0x7c, 0xde, 0xda, 0xa8, 0x33, 0xb7, 0xd6, 0xb8, 0xa7, 0x02,
0x03, 0x8b, 0x27, 0x4e, 0xae, 0xa3, 0xf4, 0xe4, 0xbe, 0x9d,
0x91, 0x4e, 0xeb, 0x61, 0xf1, 0x70, 0x2e, 0x69, 0x6c, 0x20,
0x3a, 0x12, 0x68, 0x54},
},
};
static void test_hmac(const struct hash_alg *alg)
{ {
size_t i; test_df();
uint8_t digest[SCRAM_DIGEST_SIZE]; test_scram();
printf("HMAC tests for %s.\n", alg->scram_name);
for (i = 0; i < ARRAY_SIZE(hmac_vectors); ++i) {
printf("Test #%d: ", (int)i + 1);
memset(digest, 0, sizeof(digest));
crypto_HMAC(alg, hmac_vectors[i].key, hmac_vectors[i].key_len,
hmac_vectors[i].data, hmac_vectors[i].data_len, digest);
switch (alg->digest_size) {
case SHA1_DIGEST_SIZE:
COMPARE_BUF(hmac_vectors[i].sha1, alg->digest_size, digest,
alg->digest_size);
break;
case SHA256_DIGEST_SIZE:
COMPARE_BUF(hmac_vectors[i].sha256, alg->digest_size, digest,
alg->digest_size);
break;
case SHA512_DIGEST_SIZE:
COMPARE_BUF(hmac_vectors[i].sha512, alg->digest_size, digest,
alg->digest_size);
break;
default:
printf("Unknown digest size: %zu\n", alg->digest_size);
exit(1);
}
printf("ok\n");
}
}
int main()
{
test_df(&scram_sha1);
test_scram(&scram_sha1);
test_hmac(&scram_sha1);
test_hmac(&scram_sha256);
test_hmac(&scram_sha512);
return 0; return 0;
} }

View File

@@ -12,23 +12,25 @@
/* Test Vectors (from FIPS PUB 180-1) */ /* Test Vectors (from FIPS PUB 180-1) */
static char *test_data[] = { static char *test_data[] = {
"abc", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", "abc",
"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
"A million repetitions of 'a'", "A million repetitions of 'a'",
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}; "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"};
static char *test_results[] = {"A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D", static char *test_results[] = {
"84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1", "A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D",
"34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F", "84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1",
"AD5B3FDB CB526778 C2839D2F 151EA753 995E26A0"}; "34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F",
"AD5B3FDB CB526778 C2839D2F 151EA753 995E26A0"};
static void digest_to_hex(const uint8_t *digest, char *output) static void digest_to_hex(const uint8_t *digest, char *output)
{ {
int i, j; int i,j;
char *c = output; char *c = output;
for (i = 0; i < SHA1_DIGEST_SIZE / 4; i++) { for (i = 0; i < SHA1_DIGEST_SIZE/4; i++) {
for (j = 0; j < 4; j++) { for (j = 0; j < 4; j++) {
sprintf(c, "%02X", digest[i * 4 + j]); sprintf(c,"%02X", digest[i*4+j]);
c += 2; c += 2;
} }
sprintf(c, " "); sprintf(c, " ");
@@ -37,9 +39,9 @@ static void digest_to_hex(const uint8_t *digest, char *output)
*(c - 1) = '\0'; *(c - 1) = '\0';
} }
int main() int main(int argc, char** argv)
{ {
size_t k; int k;
SHA1_CTX context; SHA1_CTX context;
uint8_t digest[20]; uint8_t digest[20];
char output[80]; char output[80];
@@ -47,23 +49,23 @@ int main()
fprintf(stdout, "verifying SHA-1 implementation... "); fprintf(stdout, "verifying SHA-1 implementation... ");
for (k = 0; k < ARRAY_SIZE(test_data); k++) { for (k = 0; k < ARRAY_SIZE(test_data); k++){
if (k == 2) { if (k == 2) {
/* this case will be checked below */ /* this case will be checked below */
continue; continue;
} }
copy = strdup(test_data[k]); copy = strdup(test_data[k]);
crypto_SHA1_Init(&context); crypto_SHA1_Init(&context);
crypto_SHA1_Update(&context, (uint8_t *)test_data[k], crypto_SHA1_Update(&context, (uint8_t*)test_data[k],
strlen(test_data[k])); strlen(test_data[k]));
crypto_SHA1_Final(&context, digest); crypto_SHA1_Final(&context, digest);
digest_to_hex(digest, output); digest_to_hex(digest, output);
if (strcmp(output, test_results[k])) { if (strcmp(output, test_results[k])) {
fprintf(stdout, "FAIL\n"); fprintf(stdout, "FAIL\n");
fprintf(stderr, "* hash of \"%s\" incorrect:\n", test_data[k]); fprintf(stderr,"* hash of \"%s\" incorrect:\n", test_data[k]);
fprintf(stderr, "\t%s returned\n", output); fprintf(stderr,"\t%s returned\n", output);
fprintf(stderr, "\t%s is correct\n", test_results[k]); fprintf(stderr,"\t%s is correct\n", test_results[k]);
return (1); return (1);
} }
if (strcmp(copy, test_data[k])) { if (strcmp(copy, test_data[k])) {
@@ -76,18 +78,18 @@ int main()
/* million 'a' vector we feed separately */ /* million 'a' vector we feed separately */
crypto_SHA1_Init(&context); crypto_SHA1_Init(&context);
for (k = 0; k < 1000000; k++) for (k = 0; k < 1000000; k++)
crypto_SHA1_Update(&context, (uint8_t *)"a", 1); crypto_SHA1_Update(&context, (uint8_t*)"a", 1);
crypto_SHA1_Final(&context, digest); crypto_SHA1_Final(&context, digest);
digest_to_hex(digest, output); digest_to_hex(digest, output);
if (strcmp(output, test_results[2])) { if (strcmp(output, test_results[2])) {
fprintf(stdout, "FAIL\n"); fprintf(stdout, "FAIL\n");
fprintf(stderr, "* hash of \"%s\" incorrect:\n", test_data[2]); fprintf(stderr,"* hash of \"%s\" incorrect:\n", test_data[2]);
fprintf(stderr, "\t%s returned\n", output); fprintf(stderr,"\t%s returned\n", output);
fprintf(stderr, "\t%s is correct\n", test_results[2]); fprintf(stderr,"\t%s is correct\n", test_results[2]);
return (1); return (1);
} }
/* success */ /* success */
fprintf(stdout, "ok\n"); fprintf(stdout, "ok\n");
return (0); return(0);
} }

View File

@@ -1,44 +0,0 @@
/* Tests for SHA-256 from LibTomCrypt */
/* This file is in the public domain */
/* gcc -o test_sha256 -I./src tests/test_sha256.c tests/test.c src/sha256.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "sha256.h"
#include "test.h"
int main()
{
static const struct {
const char *msg;
unsigned char hash[SHA256_DIGEST_SIZE];
} tests[] = {
{"abc",
{0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40,
0xde, 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17,
0x7a, 0x9c, 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad}},
{"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
{0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8, 0xe5, 0xc0, 0x26,
0x93, 0x0c, 0x3e, 0x60, 0x39, 0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff,
0x21, 0x67, 0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1}},
};
int i;
unsigned char tmp[SHA256_DIGEST_SIZE];
sha256_context md;
for (i = 0; i < (int)(sizeof(tests) / sizeof(tests[0])); i++) {
sha256_init(&md);
sha256_process(&md, (unsigned char *)tests[i].msg,
(unsigned long)strlen(tests[i].msg));
sha256_done(&md, tmp);
COMPARE_BUF(tmp, sizeof(tmp), tests[i].hash, sizeof(tests[i].hash));
}
/* success */
fprintf(stdout, "ok\n");
return (0);
}

View File

@@ -1,65 +0,0 @@
/* Tests for SHA-512 from LibTomCrypt */
/* This file is in the public domain */
/* gcc -o test_sha512 -I./src tests/test_sha512.c tests/test.c src/sha512.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "sha512.h"
#include "test.h"
static const uint8_t hash_1m_a[SHA512_DIGEST_SIZE] = {
0xe7, 0x18, 0x48, 0x3d, 0x0c, 0xe7, 0x69, 0x64, 0x4e, 0x2e, 0x42,
0xc7, 0xbc, 0x15, 0xb4, 0x63, 0x8e, 0x1f, 0x98, 0xb1, 0x3b, 0x20,
0x44, 0x28, 0x56, 0x32, 0xa8, 0x03, 0xaf, 0xa9, 0x73, 0xeb, 0xde,
0x0f, 0xf2, 0x44, 0x87, 0x7e, 0xa6, 0x0a, 0x4c, 0xb0, 0x43, 0x2c,
0xe5, 0x77, 0xc3, 0x1b, 0xeb, 0x00, 0x9c, 0x5c, 0x2c, 0x49, 0xaa,
0x2e, 0x4e, 0xad, 0xb2, 0x17, 0xad, 0x8c, 0xc0, 0x9b};
int main()
{
static const struct {
const char *msg;
uint8_t hash[SHA512_DIGEST_SIZE];
} tests[] = {
{"abc",
{0xdd, 0xaf, 0x35, 0xa1, 0x93, 0x61, 0x7a, 0xba, 0xcc, 0x41, 0x73,
0x49, 0xae, 0x20, 0x41, 0x31, 0x12, 0xe6, 0xfa, 0x4e, 0x89, 0xa9,
0x7e, 0xa2, 0x0a, 0x9e, 0xee, 0xe6, 0x4b, 0x55, 0xd3, 0x9a, 0x21,
0x92, 0x99, 0x2a, 0x27, 0x4f, 0xc1, 0xa8, 0x36, 0xba, 0x3c, 0x23,
0xa3, 0xfe, 0xeb, 0xbd, 0x45, 0x4d, 0x44, 0x23, 0x64, 0x3c, 0xe8,
0x0e, 0x2a, 0x9a, 0xc9, 0x4f, 0xa5, 0x4c, 0xa4, 0x9f}},
{"abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklm"
"nopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu",
{0x8e, 0x95, 0x9b, 0x75, 0xda, 0xe3, 0x13, 0xda, 0x8c, 0xf4, 0xf7,
0x28, 0x14, 0xfc, 0x14, 0x3f, 0x8f, 0x77, 0x79, 0xc6, 0xeb, 0x9f,
0x7f, 0xa1, 0x72, 0x99, 0xae, 0xad, 0xb6, 0x88, 0x90, 0x18, 0x50,
0x1d, 0x28, 0x9e, 0x49, 0x00, 0xf7, 0xe4, 0x33, 0x1b, 0x99, 0xde,
0xc4, 0xb5, 0x43, 0x3a, 0xc7, 0xd3, 0x29, 0xee, 0xb6, 0xdd, 0x26,
0x54, 0x5e, 0x96, 0xe5, 0x5b, 0x87, 0x4b, 0xe9, 0x09}},
};
size_t i;
uint8_t tmp[SHA512_DIGEST_SIZE];
sha512_context md;
for (i = 0; i < ARRAY_SIZE(tests); i++) {
sha512_init(&md);
sha512_process(&md, (uint8_t *)tests[i].msg, strlen(tests[i].msg));
sha512_done(&md, tmp);
COMPARE_BUF(tests[i].hash, sizeof(tests[i].hash), tmp, sizeof(tmp));
}
/* special case: one million repetitions of the character 'a' */
sha512_init(&md);
for (i = 0; i < 1000000U; ++i)
sha512_process(&md, (uint8_t *)"a", 1);
sha512_done(&md, tmp);
COMPARE_BUF(hash_1m_a, sizeof(hash_1m_a), tmp, sizeof(tmp));
/* success */
fprintf(stdout, "ok\n");
return 0;
}

View File

@@ -16,50 +16,76 @@
#define LONG_STRING 1024 #define LONG_STRING 1024
#endif #endif
int main(void) int main (void)
{ {
char buf1[LONG_STRING]; char buf1[LONG_STRING];
char buf2[LONG_STRING]; char buf2[LONG_STRING];
char *fp_fmt[] = {"%-1.5f", "%1.5f", "%123.9f", "%10.5f", "% 10.5f", char *fp_fmt[] = {
"%+22.9f", "%+4.9f", "%01.3f", "%4f", "%3.1f", "%-1.5f",
"%3.2f", "%.0f", "%.1f", NULL}; "%1.5f",
double fp_nums[] = {-1.5, 134.21, 91340.2, 341.1234, 0203.9, 0.96, "%123.9f",
0.996, 0.9996, 1.996, 4.136, 0}; "%10.5f",
char *int_fmt[] = {"%-1.5d", "%1.5d", "%123.9d", "%5.5d", "% 10.5f",
"%10.5d", "% 10.5d", "%+22.33d", "%01.3d", "%+22.9f",
"%4d", "0x%x", "0x%04x", NULL}; "%+4.9f",
long int_nums[] = {-1, 134, 91340, 341, 0203, 0x76543210, 0}; "%01.3f",
int x, y; "%4f",
int fail = 0; "%3.1f",
int num = 0; "%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"); printf ("Testing xmpp_snprintf format codes against system sprintf...\n");
for (x = 0; fp_fmt[x] != NULL; x++) for (x = 0; fp_fmt[x] != NULL ; x++)
for (y = 0; fp_nums[y] != 0; y++) { for (y = 0; fp_nums[y] != 0 ; y++)
xmpp_snprintf(buf1, sizeof(buf1), fp_fmt[x], fp_nums[y]); {
sprintf(buf2, fp_fmt[x], fp_nums[y]); xmpp_snprintf (buf1, sizeof (buf1), fp_fmt[x], fp_nums[y]);
if (strcmp(buf1, buf2)) { sprintf (buf2, fp_fmt[x], fp_nums[y]);
printf("xmpp_snprintf doesn't match Format: " if (strcmp (buf1, buf2))
"%s\n\txmpp_snprintf = %s\n\tsprintf = %s\n", {
fp_fmt[x], buf1, buf2); printf("xmpp_snprintf doesn't match Format: %s\n\txmpp_snprintf = %s\n\tsprintf = %s\n",
fail++; fp_fmt[x], buf1, buf2);
} fail++;
num++; }
} num++;
}
for (x = 0; int_fmt[x] != NULL; x++) for (x = 0; int_fmt[x] != NULL ; x++)
for (y = 0; int_nums[y] != 0; y++) { for (y = 0; int_nums[y] != 0 ; y++)
xmpp_snprintf(buf1, sizeof(buf1), int_fmt[x], int_nums[y]); {
sprintf(buf2, int_fmt[x], int_nums[y]); xmpp_snprintf (buf1, sizeof (buf1), int_fmt[x], int_nums[y]);
if (strcmp(buf1, buf2)) { sprintf (buf2, int_fmt[x], int_nums[y]);
printf("xmpp_snprintf doesn't match Format: " if (strcmp (buf1, buf2))
"%s\n\txmpp_snprintf = %s\n\tsprintf = %s\n", {
int_fmt[x], buf1, buf2); printf("xmpp_snprintf doesn't match Format: %s\n\txmpp_snprintf = %s\n\tsprintf = %s\n",
fail++; int_fmt[x], buf1, buf2);
} fail++;
num++; }
} num++;
printf("%d tests failed out of %d.\n", fail, num); }
return fail != 0 ? 1 : 0; printf ("%d tests failed out of %d.\n", fail, num);
return fail != 0 ? 1 : 0;
} }

View File

@@ -1,7 +1,7 @@
/* test_sock.c /* test_sock.c
** libstrophe XMPP client library -- test routines for the socket abstraction ** libstrophe XMPP client library -- test routines for the socket abstraction
** **
** Copyright (C) 2005-2009 Collecta, Inc. ** Copyright (C) 2005-2009 Collecta, Inc.
** **
** This software is provided AS-IS with no warranty, either express ** This software is provided AS-IS with no warranty, either express
** or implied. ** or implied.
@@ -23,24 +23,19 @@ int wait_for_connect(sock_t sock)
fd_set wfds, efds; fd_set wfds, efds;
int ret; int ret;
FD_ZERO(&wfds); FD_ZERO(&wfds); FD_SET(sock, &wfds);
FD_SET(sock, &wfds); FD_ZERO(&efds); FD_SET(sock, &efds);
FD_ZERO(&efds);
FD_SET(sock, &efds);
ret = select(sock + 1, NULL, &wfds, &efds, NULL); ret = select(sock + 1, NULL, &wfds, &efds, NULL);
if (ret <= 0) if (ret <= 0) return -1;
return -1;
if (FD_ISSET(sock, &efds)) if (FD_ISSET(sock, &efds)) return 0;
return 0; if (FD_ISSET(sock, &wfds)) return 1;
if (FD_ISSET(sock, &wfds))
return 1;
return -1; return -1;
} }
int main() int main(int argc, char **argv)
{ {
sock_t sock; sock_t sock;
int err; int err;
@@ -50,15 +45,15 @@ int main()
sock = sock_connect("www.google.com", 80); sock = sock_connect("www.google.com", 80);
if (sock < 0) { if (sock < 0) {
sock_shutdown(); sock_shutdown();
return 1; return 1;
} }
err = wait_for_connect(sock); err = wait_for_connect(sock);
if (err < 0) { if (err < 0) {
sock_close(sock); sock_close(sock);
sock_shutdown(); sock_shutdown();
return 1; return 1;
} }
sock_close(sock); sock_close(sock);

View File

@@ -1,187 +0,0 @@
/* test_stanza.c
* libstrophe XMPP client library -- test routines for stanza functions
*
* Copyright (C) 2020 Dmitry Podgorny <pasis.ua@gmail.com>
*
* This software is provided AS-IS with no warranty, either express
* or implied.
*
* This program is dual licensed under the MIT and GPLv3 licenses.
*/
/* gcc -o test_stanza -I./src tests/test_stanza.c -lstrophe */
#include <strophe.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "test.h"
#define MAGICPTR ((void *)0xfeedbeef)
static unsigned long used_blocks = 0;
static void *stanza_alloc(size_t size, void *userdata)
{
assert(userdata == MAGICPTR);
++used_blocks;
return malloc(size);
}
static void stanza_free(void *ptr, void *userdata)
{
assert(userdata == MAGICPTR);
if (ptr != NULL) {
assert(used_blocks > 0);
--used_blocks;
}
free(ptr);
}
static void *stanza_realloc(void *ptr, size_t size, void *userdata)
{
assert(userdata == MAGICPTR);
if (ptr != NULL && size == 0) {
/* equivalent to free(ptr) */
assert(used_blocks > 0);
--used_blocks;
} else if (ptr == NULL) {
/* equivalent to malloc(size) */
++used_blocks;
}
return realloc(ptr, size);
}
static const xmpp_mem_t stanza_mem = {
.alloc = &stanza_alloc,
.free = &stanza_free,
.realloc = &stanza_realloc,
.userdata = MAGICPTR,
};
static void test_stanza_add_child(xmpp_ctx_t *ctx)
{
xmpp_stanza_t *stanza;
xmpp_stanza_t *child;
unsigned long baseline = used_blocks;
/* xmpp_stanza_add_child */
stanza = xmpp_stanza_new(ctx);
child = xmpp_stanza_new(ctx);
assert(stanza != NULL);
assert(child != NULL);
xmpp_stanza_add_child(stanza, child);
xmpp_stanza_release(stanza);
assert(used_blocks > baseline);
xmpp_stanza_release(child);
assert(used_blocks == baseline);
/* xmpp_stanza_add_child_ex */
stanza = xmpp_stanza_new(ctx);
child = xmpp_stanza_new(ctx);
assert(stanza != NULL);
assert(child != NULL);
xmpp_stanza_add_child_ex(stanza, child, 0);
xmpp_stanza_release(stanza);
assert(used_blocks == baseline);
}
static void test_stanza_from_string(xmpp_ctx_t *ctx)
{
xmpp_stanza_t *stanza;
char *buf;
size_t buflen;
int ret;
static const char *str =
"<signcrypt xmlns=\"urn:xmpp:openpgp:0\"><to "
"jid=\"user@domain.com\"/><time "
"stamp=\"2020-06-03T21:26:24+0200\"/><rpad/><payload><body "
"xmlns=\"jabber:client\">Hello World!</body></payload></signcrypt>";
stanza = xmpp_stanza_new_from_string(ctx, str);
assert(stanza != NULL);
ret = xmpp_stanza_to_text(stanza, &buf, &buflen);
assert(ret == XMPP_EOK);
COMPARE(str, buf);
xmpp_free(ctx, buf);
xmpp_stanza_release(stanza);
/* Error path. */
stanza = xmpp_stanza_new_from_string(ctx, "<uu><uu>tt");
assert(stanza == NULL);
}
static void test_stanza_error(xmpp_ctx_t *ctx)
{
xmpp_stanza_t *stanza;
xmpp_stanza_t *error;
xmpp_stanza_t *item;
char *buf;
size_t buflen;
const char *attr[10];
int attrlen = ARRAY_SIZE(attr);
int ret;
static const char *str =
"<iq from='romeo@montague.lit/home' to='juliet@capulet.lit/chamber' "
"type='get' id='e2e1'><ping xmlns='urn:xmpp:ping'/></iq>";
static const char *str_error =
"<error type=\"cancel\"><service-unavailable "
"xmlns=\"urn:ietf:params:xml:ns:xmpp-stanzas\"/></error>";
stanza = xmpp_stanza_new_from_string(ctx, str);
assert(stanza != NULL);
error =
xmpp_stanza_reply_error(stanza, "cancel", "service-unavailable", NULL);
assert(error != NULL);
assert(xmpp_stanza_get_to(error) != NULL);
COMPARE("romeo@montague.lit/home", xmpp_stanza_get_to(error));
assert(xmpp_stanza_get_from(error) != NULL);
COMPARE("juliet@capulet.lit/chamber", xmpp_stanza_get_from(error));
assert(xmpp_stanza_get_id(error) != NULL);
COMPARE("e2e1", xmpp_stanza_get_id(error));
assert(xmpp_stanza_get_type(error) != NULL);
COMPARE("error", xmpp_stanza_get_type(error));
ret = xmpp_stanza_get_attributes(error, attr, attrlen);
/* attr contains both attribute name and value. */
assert(ret == 8);
item = xmpp_stanza_get_child_by_name(error, "error");
assert(item != NULL);
ret = xmpp_stanza_to_text(item, &buf, &buflen);
assert(ret == XMPP_EOK);
COMPARE(str_error, buf);
xmpp_free(ctx, buf);
xmpp_stanza_release(stanza);
xmpp_stanza_release(error);
}
int main()
{
xmpp_ctx_t *ctx;
xmpp_initialize();
ctx = xmpp_ctx_new(&stanza_mem, NULL);
assert(ctx != NULL);
test_stanza_add_child(ctx);
test_stanza_from_string(ctx);
test_stanza_error(ctx);
xmpp_ctx_free(ctx);
xmpp_shutdown();
/* All allocated blocks must be freed. */
assert(used_blocks == 0);
}

View File

@@ -20,16 +20,6 @@
#include "test.h" /* ARRAY_SIZE */ #include "test.h" /* ARRAY_SIZE */
/* strtok_s() has appeared in visual studio 2005.
Use own implementation for older versions. */
#ifdef _MSC_VER
#if (_MSC_VER >= 1400)
#define strtok_r strtok_s
#else
#define strtok_r xmpp_strtok_r
#endif
#endif /* _MSC_VER */
static int test_strtok_r(void) static int test_strtok_r(void)
{ {
const char *test = "-abc-=-def--"; const char *test = "-abc-=-def--";
@@ -75,8 +65,8 @@ static int test_strdup_one(xmpp_ctx_t *ctx, const char *s)
if (!s1 || !s2 || strcmp(s1, s2) != 0) { if (!s1 || !s2 || strcmp(s1, s2) != 0) {
rc = -1; rc = -1;
printf("strdup: '%s', xmpp_strdup: '%s'\n", s1 ? s1 : "<NULL>", printf("strdup: '%s', xmpp_strdup: '%s'\n",
s2 ? s2 : "<NULL>"); s1 ? s1 : "<NULL>", s2 ? s2 : "<NULL>");
} }
free(s1); free(s1);
@@ -92,7 +82,7 @@ static int test_strdup(void)
size_t i; size_t i;
int rc = 0; int rc = 0;
static const char *tests[] = {"", "\0", "test", "s p a c e", "\n\r"}; static const char *tests[] = { "", "\0", "test", "s p a c e", "\n\r" };
ctx = xmpp_ctx_new(NULL, NULL); ctx = xmpp_ctx_new(NULL, NULL);
assert(ctx != NULL); assert(ctx != NULL);

View File

@@ -1,69 +0,0 @@
/* test_xmppaddr.c
** libstrophe XMPP client library -- test routines for the xmppaddr
** certificate API's
**
** Copyright (C) 2021 Steffen Jaeckel
**
** 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 <string.h>
#include "strophe.h"
#include "test.h"
int main()
{
xmpp_ctx_t *ctx;
xmpp_conn_t *conn;
xmpp_log_t *log;
char xmppaddr_num[] = "0";
unsigned int n;
xmpp_initialize();
log = xmpp_get_default_logger(XMPP_LEVEL_DEBUG);
ctx = xmpp_ctx_new(NULL, log);
conn = xmpp_conn_new(ctx);
xmpp_conn_set_client_cert(conn, "tests/cert.pem", "tests/key.pem");
xmppaddr_num[0] = xmppaddr_num[0] + xmpp_conn_cert_xmppaddr_num(conn);
COMPARE("2", xmppaddr_num);
for (n = 0; n < 3; ++n) {
char *r = xmpp_conn_cert_xmppaddr(conn, n);
switch (n) {
case 0:
COMPARE("very.long.username@so.the.asn1.length.is.a.valid.ascii."
"character",
r);
break;
case 1:
COMPARE("second@xmpp.jid", r);
break;
default:
if (r != NULL) {
printf("\nThere shall only be two id-on-xmppAddr SANs!\nFound "
"another one: %s\n",
r);
exit(1);
}
break;
}
free(r);
}
xmpp_conn_release(conn);
xmpp_ctx_free(ctx);
xmpp_shutdown();
return 0;
}

View File

@@ -1,14 +0,0 @@
#!/bin/sh
if [ "x$LIBRESSL" = "xyes" ]; then
cd "$HOME"
git clone https://github.com/libressl-portable/portable.git libressl-git
cd libressl-git
if [ -n "$LIBRESSL_COMMIT" ]; then
git checkout "$LIBRESSL_COMMIT"
fi
./autogen.sh
./configure --prefix="$HOME/libressl"
make -j"$(nproc)"
make install
fi