Compare commits
46 Commits
server
...
conn-addri
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
87d40d23db | ||
|
|
484e971323 | ||
|
|
038404cb99 | ||
|
|
6f075bfc71 | ||
|
|
7aed036896 | ||
|
|
0e8c88a5e4 | ||
|
|
a13847d994 | ||
|
|
18b67d6eaf | ||
|
|
886f45584c | ||
|
|
4f915d7515 | ||
|
|
e25ca7719f | ||
|
|
2bf5cc0e41 | ||
|
|
30f3cc9263 | ||
|
|
e120109644 | ||
|
|
b4f13205d8 | ||
|
|
4797522d88 | ||
|
|
5ee06776ee | ||
|
|
c40b4c12c1 | ||
|
|
d8329960c5 | ||
|
|
94ece33f16 | ||
|
|
b179c2d277 | ||
|
|
ab568a2666 | ||
|
|
c10c930e8f | ||
|
|
6ddf424192 | ||
|
|
6aff44184e | ||
|
|
9cc9ea86bb | ||
|
|
13a0bc463c | ||
|
|
8ff510a3af | ||
|
|
633d1e9b52 | ||
|
|
a13ba65cfb | ||
|
|
0e6b0ef84d | ||
|
|
9a86efabe5 | ||
|
|
a4b05cf156 | ||
|
|
06da6d5125 | ||
|
|
1bcf77608d | ||
|
|
aab0cc3e3e | ||
|
|
822f95071a | ||
|
|
27f613bc84 | ||
|
|
af1ef3855b | ||
|
|
7ede9c6d03 | ||
|
|
20c6f225b9 | ||
|
|
5b204b0938 | ||
|
|
6e6093ee7b | ||
|
|
f12d43989f | ||
|
|
032e8ec89d | ||
|
|
d0644c5e95 |
@@ -1,15 +1,15 @@
|
|||||||
language: c
|
language: c
|
||||||
install:
|
install:
|
||||||
- sudo apt-get update
|
- sudo apt-get update
|
||||||
- sudo apt-get -y install libtool pkg-config libexpat1-dev libxml2-dev libssl-dev check
|
- sudo apt-get -y install libtool pkg-config libexpat1-dev libxml2-dev libssl-dev libc-ares-dev
|
||||||
before_script:
|
before_script:
|
||||||
- ./bootstrap.sh
|
- ./bootstrap.sh
|
||||||
script:
|
script:
|
||||||
- ./configure ${CONFIGURE_OPT} && make && make check-TESTS
|
- ./configure ${CONFIGURE_OPT} CFLAGS="-Werror" && make && make check
|
||||||
env:
|
env:
|
||||||
- CONFIGURE_OPT="--without-libxml2"
|
- CONFIGURE_OPT="--without-libxml2"
|
||||||
- CONFIGURE_OPT="--with-libxml2"
|
- CONFIGURE_OPT="--with-libxml2"
|
||||||
- CONFIGURE_OPT="--disable-tls --without-libxml2"
|
- CONFIGURE_OPT="--disable-tls"
|
||||||
- CONFIGURE_OPT="--disable-tls --with-libxml2"
|
- CONFIGURE_OPT="--enable-cares"
|
||||||
matrix:
|
matrix:
|
||||||
fast_finish: true
|
fast_finish: true
|
||||||
|
|||||||
14
ChangeLog
14
ChangeLog
@@ -1,3 +1,12 @@
|
|||||||
|
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
|
||||||
@@ -8,7 +17,12 @@
|
|||||||
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()
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
AUTOMAKE_OPTIONS = subdir-objects
|
AUTOMAKE_OPTIONS = subdir-objects
|
||||||
|
|
||||||
ACLOCAL_AMFLAGS = -I m4
|
ACLOCAL_AMFLAGS = -I m4
|
||||||
AM_CFLAGS = -g -Wall
|
|
||||||
|
|
||||||
PARSER_CFLAGS=@PARSER_CFLAGS@
|
PARSER_CFLAGS=@PARSER_CFLAGS@
|
||||||
PARSER_LIBS=@PARSER_LIBS@
|
PARSER_LIBS=@PARSER_LIBS@
|
||||||
@@ -9,15 +8,16 @@ PARSER_LIBS=@PARSER_LIBS@
|
|||||||
SSL_CFLAGS = @openssl_CFLAGS@
|
SSL_CFLAGS = @openssl_CFLAGS@
|
||||||
SSL_LIBS = @openssl_LIBS@
|
SSL_LIBS = @openssl_LIBS@
|
||||||
|
|
||||||
|
RESOLV_CFLAGS = @RESOLV_CFLAGS@
|
||||||
RESOLV_LIBS = @RESOLV_LIBS@
|
RESOLV_LIBS = @RESOLV_LIBS@
|
||||||
|
|
||||||
STROPHE_FLAGS = -I$(top_srcdir) -Wall -Wextra -Werror -Wno-unused-parameter
|
STROPHE_FLAGS = -I$(top_srcdir) -Wall -Wextra -Wno-unused-parameter
|
||||||
STROPHE_LIBS = libstrophe.la
|
STROPHE_LIBS = libstrophe.la
|
||||||
|
|
||||||
## Main build targets
|
## Main build targets
|
||||||
lib_LTLIBRARIES = libstrophe.la
|
lib_LTLIBRARIES = libstrophe.la
|
||||||
|
|
||||||
libstrophe_la_CFLAGS = $(SSL_CFLAGS) $(STROPHE_FLAGS) $(PARSER_CFLAGS)
|
libstrophe_la_CFLAGS = $(SSL_CFLAGS) $(STROPHE_FLAGS) $(PARSER_CFLAGS) $(RESOLV_CFLAGS)
|
||||||
libstrophe_la_LDFLAGS = $(SSL_LIBS) $(PARSER_LIBS) $(RESOLV_LIBS) -no-undefined
|
libstrophe_la_LDFLAGS = $(SSL_LIBS) $(PARSER_LIBS) $(RESOLV_LIBS) -no-undefined
|
||||||
# Export only public API
|
# Export only public API
|
||||||
libstrophe_la_LDFLAGS += -export-symbols-regex '^xmpp_'
|
libstrophe_la_LDFLAGS += -export-symbols-regex '^xmpp_'
|
||||||
|
|||||||
19
configure.ac
19
configure.ac
@@ -1,4 +1,4 @@
|
|||||||
AC_INIT([libstrophe], [0.9.1], [jack@metajack.im])
|
AC_INIT([libstrophe], [0.9.3], [jack@metajack.im])
|
||||||
AC_CONFIG_MACRO_DIR([m4])
|
AC_CONFIG_MACRO_DIR([m4])
|
||||||
AM_INIT_AUTOMAKE([foreign])
|
AM_INIT_AUTOMAKE([foreign])
|
||||||
LT_INIT([dlopen])
|
LT_INIT([dlopen])
|
||||||
@@ -21,6 +21,8 @@ AC_ARG_WITH([libxml2],
|
|||||||
[AS_HELP_STRING([--with-libxml2], [use libxml2 for XML parsing, expat is the default])])
|
[AS_HELP_STRING([--with-libxml2], [use libxml2 for XML parsing, expat is the default])])
|
||||||
AC_ARG_ENABLE([tls],
|
AC_ARG_ENABLE([tls],
|
||||||
[AS_HELP_STRING([--disable-tls], [disable TLS support])])
|
[AS_HELP_STRING([--disable-tls], [disable TLS support])])
|
||||||
|
AC_ARG_ENABLE([cares],
|
||||||
|
[AS_HELP_STRING([--enable-cares], [use c-ares for DNS resolution])])
|
||||||
|
|
||||||
if test "x$enable_tls" != xno; then
|
if test "x$enable_tls" != xno; then
|
||||||
PKG_CHECK_MODULES([openssl], [openssl],
|
PKG_CHECK_MODULES([openssl], [openssl],
|
||||||
@@ -84,6 +86,18 @@ AC_MSG_NOTICE([libstrophe will use the $with_parser XML parser])
|
|||||||
|
|
||||||
AC_SEARCH_LIBS([socket], [socket])
|
AC_SEARCH_LIBS([socket], [socket])
|
||||||
|
|
||||||
|
if test "x$enable_cares" = xyes; then
|
||||||
|
PKG_CHECK_MODULES([libcares], [libcares >= 1.7.0],
|
||||||
|
[
|
||||||
|
PC_REQUIRES="libcares ${PC_REQUIRES}"
|
||||||
|
RESOLV_CFLAGS=$libcares_CFLAGS
|
||||||
|
RESOLV_LIBS=$libcares_LIBS
|
||||||
|
AC_DEFINE([HAVE_CARES])
|
||||||
|
],
|
||||||
|
[AC_MSG_ERROR([libcares not found])])
|
||||||
|
# TODO: if pkg-config doesn't find, check the library manually
|
||||||
|
else
|
||||||
|
|
||||||
AS_CASE([$PLATFORM],
|
AS_CASE([$PLATFORM],
|
||||||
[bsd], [RESOLV_LIBS=""],
|
[bsd], [RESOLV_LIBS=""],
|
||||||
[qnx], [RESOLV_LIBS="-lsocket"],
|
[qnx], [RESOLV_LIBS="-lsocket"],
|
||||||
@@ -110,6 +124,8 @@ AC_LINK_IFELSE([AC_LANG_SOURCE([
|
|||||||
LIBS="${LIBS_TMP}"
|
LIBS="${LIBS_TMP}"
|
||||||
PC_LIBS="${RESOLV_LIBS} ${PC_LIBS}"
|
PC_LIBS="${RESOLV_LIBS} ${PC_LIBS}"
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
m4_ifdef([PKG_INSTALLDIR], [PKG_INSTALLDIR],
|
m4_ifdef([PKG_INSTALLDIR], [PKG_INSTALLDIR],
|
||||||
[AC_ARG_WITH([pkgconfigdir],
|
[AC_ARG_WITH([pkgconfigdir],
|
||||||
[AS_HELP_STRING([--with-pkgconfigdir],
|
[AS_HELP_STRING([--with-pkgconfigdir],
|
||||||
@@ -126,6 +142,7 @@ 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_CONFIG_FILES([Makefile libstrophe.pc])
|
AC_CONFIG_FILES([Makefile libstrophe.pc])
|
||||||
AC_OUTPUT
|
AC_OUTPUT
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ include $(BUILD_STATIC_LIBRARY)
|
|||||||
|
|
||||||
include $(CLEAR_VARS)
|
include $(CLEAR_VARS)
|
||||||
LOCAL_MODULE := libexpat
|
LOCAL_MODULE := libexpat
|
||||||
LOCAL_CFLAGS := -DHAVE_MEMMOVE
|
LOCAL_CFLAGS := -DHAVE_MEMMOVE -DXML_DEV_URANDOM
|
||||||
#LOCAL_C_INCLUDES := \
|
#LOCAL_C_INCLUDES := \
|
||||||
# $(LOCAL_PATH)/expat
|
# $(LOCAL_PATH)/expat
|
||||||
|
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
APP_ABI := armeabi armeabi-v7a mips x86
|
APP_ABI := armeabi-v7a arm64-v8a
|
||||||
APP_PLATFORM := android-19
|
APP_PLATFORM := android-19
|
||||||
|
|||||||
259
src/auth.c
259
src/auth.c
@@ -61,6 +61,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void _auth(xmpp_conn_t * const conn);
|
static void _auth(xmpp_conn_t * const conn);
|
||||||
|
static void _auth_legacy(xmpp_conn_t *conn);
|
||||||
static void _handle_open_sasl(xmpp_conn_t * const conn);
|
static void _handle_open_sasl(xmpp_conn_t * const conn);
|
||||||
static void _handle_open_tls(xmpp_conn_t * const conn);
|
static void _handle_open_tls(xmpp_conn_t * const conn);
|
||||||
|
|
||||||
@@ -69,11 +70,6 @@ static int _handle_component_hs_response(xmpp_conn_t * const conn,
|
|||||||
xmpp_stanza_t * const stanza,
|
xmpp_stanza_t * const stanza,
|
||||||
void * const userdata);
|
void * const userdata);
|
||||||
|
|
||||||
static int _handle_missing_legacy(xmpp_conn_t * const conn,
|
|
||||||
void * const userdata);
|
|
||||||
static int _handle_legacy(xmpp_conn_t * const conn,
|
|
||||||
xmpp_stanza_t * const stanza,
|
|
||||||
void * const userdata);
|
|
||||||
static int _handle_features_sasl(xmpp_conn_t * const conn,
|
static int _handle_features_sasl(xmpp_conn_t * const conn,
|
||||||
xmpp_stanza_t * const stanza,
|
xmpp_stanza_t * const stanza,
|
||||||
void * const userdata);
|
void * const userdata);
|
||||||
@@ -219,6 +215,7 @@ static int _handle_features(xmpp_conn_t * const conn,
|
|||||||
void * const userdata)
|
void * const userdata)
|
||||||
{
|
{
|
||||||
xmpp_stanza_t *child, *mech;
|
xmpp_stanza_t *child, *mech;
|
||||||
|
const char *ns;
|
||||||
char *text;
|
char *text;
|
||||||
|
|
||||||
/* remove the handler that detects missing stream:features */
|
/* remove the handler that detects missing stream:features */
|
||||||
@@ -228,8 +225,10 @@ static int _handle_features(xmpp_conn_t * const conn,
|
|||||||
if (!conn->secured) {
|
if (!conn->secured) {
|
||||||
if (!conn->tls_disabled) {
|
if (!conn->tls_disabled) {
|
||||||
child = xmpp_stanza_get_child_by_name(stanza, "starttls");
|
child = xmpp_stanza_get_child_by_name(stanza, "starttls");
|
||||||
if (child && (strcmp(xmpp_stanza_get_ns(child), XMPP_NS_TLS) == 0))
|
if (child) {
|
||||||
conn->tls_support = 1;
|
ns = xmpp_stanza_get_ns(child);
|
||||||
|
conn->tls_support = ns != NULL && strcmp(ns, XMPP_NS_TLS) == 0;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
conn->tls_support = 0;
|
conn->tls_support = 0;
|
||||||
}
|
}
|
||||||
@@ -237,11 +236,15 @@ static int _handle_features(xmpp_conn_t * const conn,
|
|||||||
|
|
||||||
/* check for SASL */
|
/* check for SASL */
|
||||||
child = xmpp_stanza_get_child_by_name(stanza, "mechanisms");
|
child = xmpp_stanza_get_child_by_name(stanza, "mechanisms");
|
||||||
if (child && (strcmp(xmpp_stanza_get_ns(child), XMPP_NS_SASL) == 0)) {
|
ns = child ? xmpp_stanza_get_ns(child) : NULL;
|
||||||
|
if (child && ns && strcmp(ns, XMPP_NS_SASL) == 0) {
|
||||||
for (mech = xmpp_stanza_get_children(child); mech;
|
for (mech = xmpp_stanza_get_children(child); mech;
|
||||||
mech = xmpp_stanza_get_next(mech)) {
|
mech = xmpp_stanza_get_next(mech)) {
|
||||||
if (xmpp_stanza_get_name(mech) && strcmp(xmpp_stanza_get_name(mech), "mechanism") == 0) {
|
if (xmpp_stanza_get_name(mech) && strcmp(xmpp_stanza_get_name(mech), "mechanism") == 0) {
|
||||||
text = xmpp_stanza_get_text(mech);
|
text = xmpp_stanza_get_text(mech);
|
||||||
|
if (text == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
if (strcasecmp(text, "PLAIN") == 0)
|
if (strcasecmp(text, "PLAIN") == 0)
|
||||||
conn->sasl_support |= SASL_MASK_PLAIN;
|
conn->sasl_support |= SASL_MASK_PLAIN;
|
||||||
else if (strcasecmp(text, "DIGEST-MD5") == 0)
|
else if (strcasecmp(text, "DIGEST-MD5") == 0)
|
||||||
@@ -256,6 +259,10 @@ static int _handle_features(xmpp_conn_t * const conn,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Disable PLAIN when other secure mechanisms are supported */
|
||||||
|
if (conn->sasl_support & ~(SASL_MASK_PLAIN | SASL_MASK_ANONYMOUS))
|
||||||
|
conn->sasl_support &= ~SASL_MASK_PLAIN;
|
||||||
|
|
||||||
_auth(conn);
|
_auth(conn);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -550,9 +557,11 @@ static xmpp_stanza_t *_make_sasl_auth(xmpp_conn_t * const conn,
|
|||||||
*/
|
*/
|
||||||
static void _auth(xmpp_conn_t * const conn)
|
static void _auth(xmpp_conn_t * const conn)
|
||||||
{
|
{
|
||||||
xmpp_stanza_t *auth, *authdata, *query, *child, *iq;
|
xmpp_stanza_t *auth;
|
||||||
char *str, *authid;
|
xmpp_stanza_t *authdata;
|
||||||
|
char *authid;
|
||||||
char *scram_init;
|
char *scram_init;
|
||||||
|
char *str;
|
||||||
int anonjid;
|
int anonjid;
|
||||||
|
|
||||||
/* if there is no node in conn->jid, we assume anonymous connect */
|
/* if there is no node in conn->jid, we assume anonymous connect */
|
||||||
@@ -719,105 +728,12 @@ static void _auth(xmpp_conn_t * const conn)
|
|||||||
|
|
||||||
/* SASL PLAIN was tried */
|
/* SASL PLAIN was tried */
|
||||||
conn->sasl_support &= ~SASL_MASK_PLAIN;
|
conn->sasl_support &= ~SASL_MASK_PLAIN;
|
||||||
} else if (conn->type == XMPP_CLIENT) {
|
} else if (conn->type == XMPP_CLIENT && conn->auth_legacy_enabled) {
|
||||||
/* legacy client authentication */
|
/* legacy client authentication */
|
||||||
|
_auth_legacy(conn);
|
||||||
iq = xmpp_iq_new(conn->ctx, "set", "_xmpp_auth1");
|
} else {
|
||||||
if (!iq) {
|
xmpp_error(conn->ctx, "auth", "Cannot authenticate with known methods");
|
||||||
disconnect_mem_error(conn);
|
xmpp_disconnect(conn);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
query = xmpp_stanza_new(conn->ctx);
|
|
||||||
if (!query) {
|
|
||||||
xmpp_stanza_release(iq);
|
|
||||||
disconnect_mem_error(conn);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
xmpp_stanza_set_name(query, "query");
|
|
||||||
xmpp_stanza_set_ns(query, XMPP_NS_AUTH);
|
|
||||||
xmpp_stanza_add_child(iq, query);
|
|
||||||
xmpp_stanza_release(query);
|
|
||||||
|
|
||||||
child = xmpp_stanza_new(conn->ctx);
|
|
||||||
if (!child) {
|
|
||||||
xmpp_stanza_release(iq);
|
|
||||||
disconnect_mem_error(conn);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
xmpp_stanza_set_name(child, "username");
|
|
||||||
xmpp_stanza_add_child(query, child);
|
|
||||||
xmpp_stanza_release(child);
|
|
||||||
|
|
||||||
authdata = xmpp_stanza_new(conn->ctx);
|
|
||||||
if (!authdata) {
|
|
||||||
xmpp_stanza_release(iq);
|
|
||||||
disconnect_mem_error(conn);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
str = xmpp_jid_node(conn->ctx, conn->jid);
|
|
||||||
xmpp_stanza_set_text(authdata, str);
|
|
||||||
xmpp_free(conn->ctx, str);
|
|
||||||
xmpp_stanza_add_child(child, authdata);
|
|
||||||
xmpp_stanza_release(authdata);
|
|
||||||
|
|
||||||
child = xmpp_stanza_new(conn->ctx);
|
|
||||||
if (!child) {
|
|
||||||
xmpp_stanza_release(iq);
|
|
||||||
disconnect_mem_error(conn);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
xmpp_stanza_set_name(child, "password");
|
|
||||||
xmpp_stanza_add_child(query, child);
|
|
||||||
xmpp_stanza_release(child);
|
|
||||||
|
|
||||||
authdata = xmpp_stanza_new(conn->ctx);
|
|
||||||
if (!authdata) {
|
|
||||||
xmpp_stanza_release(iq);
|
|
||||||
disconnect_mem_error(conn);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
xmpp_stanza_set_text(authdata, conn->pass);
|
|
||||||
xmpp_stanza_add_child(child, authdata);
|
|
||||||
xmpp_stanza_release(authdata);
|
|
||||||
|
|
||||||
child = xmpp_stanza_new(conn->ctx);
|
|
||||||
if (!child) {
|
|
||||||
xmpp_stanza_release(iq);
|
|
||||||
disconnect_mem_error(conn);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
xmpp_stanza_set_name(child, "resource");
|
|
||||||
xmpp_stanza_add_child(query, child);
|
|
||||||
xmpp_stanza_release(child);
|
|
||||||
|
|
||||||
authdata = xmpp_stanza_new(conn->ctx);
|
|
||||||
if (!authdata) {
|
|
||||||
xmpp_stanza_release(iq);
|
|
||||||
disconnect_mem_error(conn);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
str = xmpp_jid_resource(conn->ctx, conn->jid);
|
|
||||||
if (str) {
|
|
||||||
xmpp_stanza_set_text(authdata, str);
|
|
||||||
xmpp_free(conn->ctx, str);
|
|
||||||
} else {
|
|
||||||
xmpp_stanza_release(authdata);
|
|
||||||
xmpp_stanza_release(iq);
|
|
||||||
xmpp_error(conn->ctx, "auth",
|
|
||||||
"Cannot authenticate without resource");
|
|
||||||
xmpp_disconnect(conn);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
xmpp_stanza_add_child(child, authdata);
|
|
||||||
xmpp_stanza_release(authdata);
|
|
||||||
|
|
||||||
handler_add_id(conn, _handle_legacy, "_xmpp_auth1", NULL);
|
|
||||||
handler_add_timed(conn, _handle_missing_legacy,
|
|
||||||
LEGACY_TIMEOUT, NULL);
|
|
||||||
|
|
||||||
xmpp_send(conn, iq);
|
|
||||||
xmpp_stanza_release(iq);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -871,7 +787,8 @@ static int _handle_features_sasl(xmpp_conn_t * const conn,
|
|||||||
xmpp_stanza_t * const stanza,
|
xmpp_stanza_t * const stanza,
|
||||||
void * const userdata)
|
void * const userdata)
|
||||||
{
|
{
|
||||||
xmpp_stanza_t *bind, *session, *iq, *res, *text;
|
xmpp_stanza_t *bind, *session, *iq, *res, *text, *opt;
|
||||||
|
const char *ns;
|
||||||
char *resource;
|
char *resource;
|
||||||
|
|
||||||
/* remove missing features handler */
|
/* remove missing features handler */
|
||||||
@@ -880,16 +797,21 @@ static int _handle_features_sasl(xmpp_conn_t * const conn,
|
|||||||
/* we are expecting <bind/> and <session/> since this is a
|
/* we are expecting <bind/> and <session/> since this is a
|
||||||
XMPP style connection */
|
XMPP style connection */
|
||||||
|
|
||||||
|
/* check whether resource binding is required */
|
||||||
bind = xmpp_stanza_get_child_by_name(stanza, "bind");
|
bind = xmpp_stanza_get_child_by_name(stanza, "bind");
|
||||||
if (bind && strcmp(xmpp_stanza_get_ns(bind), XMPP_NS_BIND) == 0) {
|
if (bind) {
|
||||||
/* resource binding is required */
|
ns = xmpp_stanza_get_ns(bind);
|
||||||
conn->bind_required = 1;
|
conn->bind_required = ns != NULL && strcmp(ns, XMPP_NS_BIND) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* check whether session establishment is required */
|
||||||
session = xmpp_stanza_get_child_by_name(stanza, "session");
|
session = xmpp_stanza_get_child_by_name(stanza, "session");
|
||||||
if (session && strcmp(xmpp_stanza_get_ns(session), XMPP_NS_SESSION) == 0) {
|
if (session) {
|
||||||
/* session establishment required */
|
ns = xmpp_stanza_get_ns(session);
|
||||||
conn->session_required = 1;
|
opt = xmpp_stanza_get_child_by_name(session, "optional");
|
||||||
|
if (!opt)
|
||||||
|
conn->session_required = ns != NULL &&
|
||||||
|
strcmp(ns, XMPP_NS_SESSION) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if bind is required, go ahead and start it */
|
/* if bind is required, go ahead and start it */
|
||||||
@@ -1092,6 +1014,15 @@ static int _handle_missing_session(xmpp_conn_t * const conn,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int _handle_missing_legacy(xmpp_conn_t * const conn,
|
||||||
|
void * const userdata)
|
||||||
|
{
|
||||||
|
xmpp_error(conn->ctx, "xmpp", "Server did not reply to legacy "\
|
||||||
|
"authentication request.");
|
||||||
|
xmpp_disconnect(conn);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int _handle_legacy(xmpp_conn_t * const conn,
|
static int _handle_legacy(xmpp_conn_t * const conn,
|
||||||
xmpp_stanza_t * const stanza,
|
xmpp_stanza_t * const stanza,
|
||||||
void * const userdata)
|
void * const userdata)
|
||||||
@@ -1128,13 +1059,97 @@ static int _handle_legacy(xmpp_conn_t * const conn,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _handle_missing_legacy(xmpp_conn_t * const conn,
|
static void _auth_legacy(xmpp_conn_t *conn)
|
||||||
void * const userdata)
|
|
||||||
{
|
{
|
||||||
xmpp_error(conn->ctx, "xmpp", "Server did not reply to legacy "\
|
xmpp_stanza_t *iq;
|
||||||
"authentication request.");
|
xmpp_stanza_t *authdata;
|
||||||
xmpp_disconnect(conn);
|
xmpp_stanza_t *query;
|
||||||
return 0;
|
xmpp_stanza_t *child;
|
||||||
|
char *str;
|
||||||
|
|
||||||
|
xmpp_debug(conn->ctx, "auth", "Legacy authentication request");
|
||||||
|
|
||||||
|
iq = xmpp_iq_new(conn->ctx, "set", "_xmpp_auth1");
|
||||||
|
if (!iq)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
query = xmpp_stanza_new(conn->ctx);
|
||||||
|
if (!query)
|
||||||
|
goto err_free;
|
||||||
|
xmpp_stanza_set_name(query, "query");
|
||||||
|
xmpp_stanza_set_ns(query, XMPP_NS_AUTH);
|
||||||
|
xmpp_stanza_add_child(iq, query);
|
||||||
|
xmpp_stanza_release(query);
|
||||||
|
|
||||||
|
child = xmpp_stanza_new(conn->ctx);
|
||||||
|
if (!child)
|
||||||
|
goto err_free;
|
||||||
|
xmpp_stanza_set_name(child, "username");
|
||||||
|
xmpp_stanza_add_child(query, child);
|
||||||
|
xmpp_stanza_release(child);
|
||||||
|
|
||||||
|
authdata = xmpp_stanza_new(conn->ctx);
|
||||||
|
if (!authdata)
|
||||||
|
goto err_free;
|
||||||
|
str = xmpp_jid_node(conn->ctx, conn->jid);
|
||||||
|
if (!str) {
|
||||||
|
xmpp_stanza_release(authdata);
|
||||||
|
goto err_free;
|
||||||
|
}
|
||||||
|
xmpp_stanza_set_text(authdata, str);
|
||||||
|
xmpp_free(conn->ctx, str);
|
||||||
|
xmpp_stanza_add_child(child, authdata);
|
||||||
|
xmpp_stanza_release(authdata);
|
||||||
|
|
||||||
|
child = xmpp_stanza_new(conn->ctx);
|
||||||
|
if (!child)
|
||||||
|
goto err_free;
|
||||||
|
xmpp_stanza_set_name(child, "password");
|
||||||
|
xmpp_stanza_add_child(query, child);
|
||||||
|
xmpp_stanza_release(child);
|
||||||
|
|
||||||
|
authdata = xmpp_stanza_new(conn->ctx);
|
||||||
|
if (!authdata)
|
||||||
|
goto err_free;
|
||||||
|
xmpp_stanza_set_text(authdata, conn->pass);
|
||||||
|
xmpp_stanza_add_child(child, authdata);
|
||||||
|
xmpp_stanza_release(authdata);
|
||||||
|
|
||||||
|
child = xmpp_stanza_new(conn->ctx);
|
||||||
|
if (!child)
|
||||||
|
goto err_free;
|
||||||
|
xmpp_stanza_set_name(child, "resource");
|
||||||
|
xmpp_stanza_add_child(query, child);
|
||||||
|
xmpp_stanza_release(child);
|
||||||
|
|
||||||
|
authdata = xmpp_stanza_new(conn->ctx);
|
||||||
|
if (!authdata)
|
||||||
|
goto err_free;
|
||||||
|
str = xmpp_jid_resource(conn->ctx, conn->jid);
|
||||||
|
if (str) {
|
||||||
|
xmpp_stanza_set_text(authdata, str);
|
||||||
|
xmpp_free(conn->ctx, str);
|
||||||
|
} else {
|
||||||
|
xmpp_stanza_release(authdata);
|
||||||
|
xmpp_stanza_release(iq);
|
||||||
|
xmpp_error(conn->ctx, "auth", "Cannot authenticate without resource");
|
||||||
|
xmpp_disconnect(conn);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
xmpp_stanza_add_child(child, authdata);
|
||||||
|
xmpp_stanza_release(authdata);
|
||||||
|
|
||||||
|
handler_add_id(conn, _handle_legacy, "_xmpp_auth1", NULL);
|
||||||
|
handler_add_timed(conn, _handle_missing_legacy, LEGACY_TIMEOUT, NULL);
|
||||||
|
|
||||||
|
xmpp_send(conn, iq);
|
||||||
|
xmpp_stanza_release(iq);
|
||||||
|
return;
|
||||||
|
|
||||||
|
err_free:
|
||||||
|
xmpp_stanza_release(iq);
|
||||||
|
err:
|
||||||
|
disconnect_mem_error(conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
void auth_handle_component_open(xmpp_conn_t * const conn)
|
void auth_handle_component_open(xmpp_conn_t * const conn)
|
||||||
|
|||||||
@@ -160,6 +160,7 @@ struct _xmpp_conn_t {
|
|||||||
xmpp_stream_error_t *stream_error;
|
xmpp_stream_error_t *stream_error;
|
||||||
|
|
||||||
sock_t sock;
|
sock_t sock;
|
||||||
|
xmpp_sock_t *xsock;
|
||||||
int ka_timeout; /* TCP keepalive timeout */
|
int ka_timeout; /* TCP keepalive timeout */
|
||||||
int ka_interval; /* TCP keepalive interval */
|
int ka_interval; /* TCP keepalive interval */
|
||||||
|
|
||||||
@@ -172,6 +173,7 @@ struct _xmpp_conn_t {
|
|||||||
int tls_failed; /* set when tls fails, so we don't try again */
|
int tls_failed; /* set when tls fails, so we don't try again */
|
||||||
int sasl_support; /* if true, field is a bitfield of supported
|
int sasl_support; /* if true, field is a bitfield of supported
|
||||||
mechanisms */
|
mechanisms */
|
||||||
|
int auth_legacy_enabled;
|
||||||
int secured; /* set when stream is secured with TLS */
|
int secured; /* set when stream is secured with TLS */
|
||||||
|
|
||||||
/* if server returns <bind/> or <session/> we must do them */
|
/* if server returns <bind/> or <session/> we must do them */
|
||||||
|
|||||||
34
src/conn.c
34
src/conn.c
@@ -73,6 +73,15 @@ static int _conn_connect(xmpp_conn_t * const conn,
|
|||||||
xmpp_conn_handler callback,
|
xmpp_conn_handler callback,
|
||||||
void * const userdata);
|
void * const userdata);
|
||||||
|
|
||||||
|
void xmpp_send_error(xmpp_conn_t * const conn, xmpp_error_type_t const type, char * const text)
|
||||||
|
{
|
||||||
|
xmpp_stanza_t *error = xmpp_error_new(conn->ctx, type, text);
|
||||||
|
|
||||||
|
xmpp_send(conn, error);
|
||||||
|
|
||||||
|
xmpp_stanza_release(error);
|
||||||
|
}
|
||||||
|
|
||||||
/** Create a new Strophe connection object.
|
/** Create a new Strophe connection object.
|
||||||
*
|
*
|
||||||
* @param ctx a Strophe context object
|
* @param ctx a Strophe context object
|
||||||
@@ -131,6 +140,7 @@ xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t * const ctx)
|
|||||||
conn->tls_trust = 0;
|
conn->tls_trust = 0;
|
||||||
conn->tls_failed = 0;
|
conn->tls_failed = 0;
|
||||||
conn->sasl_support = 0;
|
conn->sasl_support = 0;
|
||||||
|
conn->auth_legacy_enabled = 0;
|
||||||
conn->secured = 0;
|
conn->secured = 0;
|
||||||
|
|
||||||
conn->bind_required = 0;
|
conn->bind_required = 0;
|
||||||
@@ -679,7 +689,8 @@ void conn_disconnect(xmpp_conn_t * const conn)
|
|||||||
tls_free(conn->tls);
|
tls_free(conn->tls);
|
||||||
conn->tls = NULL;
|
conn->tls = NULL;
|
||||||
}
|
}
|
||||||
sock_close(conn->sock);
|
if (conn->sock >= 0)
|
||||||
|
sock_close(conn->sock);
|
||||||
|
|
||||||
/* fire off connection handler */
|
/* fire off connection handler */
|
||||||
conn->conn_handler(conn, XMPP_CONN_DISCONNECT, conn->error,
|
conn->conn_handler(conn, XMPP_CONN_DISCONNECT, conn->error,
|
||||||
@@ -704,7 +715,7 @@ void conn_parser_reset(xmpp_conn_t * const conn)
|
|||||||
/** Initiate termination of the connection to the XMPP server.
|
/** Initiate termination of the connection to the XMPP server.
|
||||||
* This function starts the disconnection sequence by sending
|
* This function starts the disconnection sequence by sending
|
||||||
* </stream:stream> to the XMPP server. This function will do nothing
|
* </stream:stream> to the XMPP server. This function will do nothing
|
||||||
* if the connection state is CONNECTING or CONNECTED.
|
* if the connection state is different from CONNECTING or CONNECTED.
|
||||||
*
|
*
|
||||||
* @param conn a Strophe connection object
|
* @param conn a Strophe connection object
|
||||||
*
|
*
|
||||||
@@ -746,10 +757,10 @@ void xmpp_send_raw_string(xmpp_conn_t * const conn,
|
|||||||
char *bigbuf;
|
char *bigbuf;
|
||||||
|
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
len = xmpp_vsnprintf(buf, 1024, fmt, ap);
|
len = xmpp_vsnprintf(buf, sizeof(buf), fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|
||||||
if (len >= 1024) {
|
if (len >= sizeof(buf)) {
|
||||||
/* we need more space for this data, so we allocate a big
|
/* we need more space for this data, so we allocate a big
|
||||||
* enough buffer and print to that */
|
* enough buffer and print to that */
|
||||||
len++; /* account for trailing \0 */
|
len++; /* account for trailing \0 */
|
||||||
@@ -770,7 +781,6 @@ void xmpp_send_raw_string(xmpp_conn_t * const conn,
|
|||||||
xmpp_free(conn->ctx, bigbuf);
|
xmpp_free(conn->ctx, bigbuf);
|
||||||
} else {
|
} else {
|
||||||
xmpp_debug(conn->ctx, "conn", "SENT: %s", buf);
|
xmpp_debug(conn->ctx, "conn", "SENT: %s", buf);
|
||||||
|
|
||||||
xmpp_send_raw(conn, buf, len);
|
xmpp_send_raw(conn, buf, len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -835,10 +845,9 @@ void xmpp_send(xmpp_conn_t * const conn,
|
|||||||
{
|
{
|
||||||
char *buf;
|
char *buf;
|
||||||
size_t len;
|
size_t len;
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (conn->state == XMPP_STATE_CONNECTED) {
|
if (conn->state == XMPP_STATE_CONNECTED) {
|
||||||
if ((ret = xmpp_stanza_to_text(stanza, &buf, &len)) == 0) {
|
if (xmpp_stanza_to_text(stanza, &buf, &len) == 0) {
|
||||||
xmpp_send_raw(conn, buf, len);
|
xmpp_send_raw(conn, buf, len);
|
||||||
xmpp_debug(conn->ctx, "conn", "SENT: %s", buf);
|
xmpp_debug(conn->ctx, "conn", "SENT: %s", buf);
|
||||||
xmpp_free(conn->ctx, buf);
|
xmpp_free(conn->ctx, buf);
|
||||||
@@ -913,7 +922,8 @@ long xmpp_conn_get_flags(const xmpp_conn_t * const conn)
|
|||||||
flags = XMPP_CONN_FLAG_DISABLE_TLS * conn->tls_disabled |
|
flags = XMPP_CONN_FLAG_DISABLE_TLS * conn->tls_disabled |
|
||||||
XMPP_CONN_FLAG_MANDATORY_TLS * conn->tls_mandatory |
|
XMPP_CONN_FLAG_MANDATORY_TLS * conn->tls_mandatory |
|
||||||
XMPP_CONN_FLAG_LEGACY_SSL * conn->tls_legacy_ssl |
|
XMPP_CONN_FLAG_LEGACY_SSL * conn->tls_legacy_ssl |
|
||||||
XMPP_CONN_FLAG_TRUST_TLS * conn->tls_trust;
|
XMPP_CONN_FLAG_TRUST_TLS * conn->tls_trust |
|
||||||
|
XMPP_CONN_FLAG_LEGACY_AUTH * conn->auth_legacy_enabled;;
|
||||||
|
|
||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
@@ -931,6 +941,7 @@ long xmpp_conn_get_flags(const xmpp_conn_t * const conn)
|
|||||||
* - XMPP_CONN_FLAG_MANDATORY_TLS
|
* - XMPP_CONN_FLAG_MANDATORY_TLS
|
||||||
* - XMPP_CONN_FLAG_LEGACY_SSL
|
* - XMPP_CONN_FLAG_LEGACY_SSL
|
||||||
* - XMPP_CONN_FLAG_TRUST_TLS
|
* - XMPP_CONN_FLAG_TRUST_TLS
|
||||||
|
* - XMPP_CONN_FLAG_LEGACY_AUTH
|
||||||
*
|
*
|
||||||
* @param conn a Strophe connection object
|
* @param conn a Strophe connection object
|
||||||
* @param flags ORed connection flags
|
* @param flags ORed connection flags
|
||||||
@@ -957,6 +968,7 @@ int xmpp_conn_set_flags(xmpp_conn_t * const conn, long flags)
|
|||||||
conn->tls_mandatory = (flags & XMPP_CONN_FLAG_MANDATORY_TLS) ? 1 : 0;
|
conn->tls_mandatory = (flags & XMPP_CONN_FLAG_MANDATORY_TLS) ? 1 : 0;
|
||||||
conn->tls_legacy_ssl = (flags & XMPP_CONN_FLAG_LEGACY_SSL) ? 1 : 0;
|
conn->tls_legacy_ssl = (flags & XMPP_CONN_FLAG_LEGACY_SSL) ? 1 : 0;
|
||||||
conn->tls_trust = (flags & XMPP_CONN_FLAG_TRUST_TLS) ? 1 : 0;
|
conn->tls_trust = (flags & XMPP_CONN_FLAG_TRUST_TLS) ? 1 : 0;
|
||||||
|
conn->auth_legacy_enabled = (flags & XMPP_CONN_FLAG_LEGACY_AUTH) ? 1 : 0;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1202,6 +1214,9 @@ static void _conn_reset(xmpp_conn_t * const conn)
|
|||||||
xmpp_free(ctx, tsq->data);
|
xmpp_free(ctx, tsq->data);
|
||||||
xmpp_free(ctx, tsq);
|
xmpp_free(ctx, tsq);
|
||||||
}
|
}
|
||||||
|
conn->send_queue_head = NULL;
|
||||||
|
conn->send_queue_tail = NULL;
|
||||||
|
conn->send_queue_len = 0;
|
||||||
|
|
||||||
if (conn->stream_error) {
|
if (conn->stream_error) {
|
||||||
xmpp_stanza_release(conn->stream_error->stanza);
|
xmpp_stanza_release(conn->stream_error->stanza);
|
||||||
@@ -1249,7 +1264,8 @@ static int _conn_connect(xmpp_conn_t * const conn,
|
|||||||
conn->domain = xmpp_strdup(conn->ctx, domain);
|
conn->domain = xmpp_strdup(conn->ctx, domain);
|
||||||
if (!conn->domain) return XMPP_EMEM;
|
if (!conn->domain) return XMPP_EMEM;
|
||||||
|
|
||||||
conn->sock = sock_connect(host, port);
|
conn->xsock = sock_new(conn->ctx, host, port);
|
||||||
|
conn->sock = sock_connect(conn->xsock);
|
||||||
xmpp_debug(conn->ctx, "xmpp", "sock_connect() to %s:%u returned %d",
|
xmpp_debug(conn->ctx, "xmpp", "sock_connect() to %s:%u returned %d",
|
||||||
host, port, conn->sock);
|
host, port, conn->sock);
|
||||||
if (conn->sock == -1) return XMPP_EINT;
|
if (conn->sock == -1) return XMPP_EINT;
|
||||||
|
|||||||
26
src/crypto.c
26
src/crypto.c
@@ -61,7 +61,7 @@ static char *digest_to_string_alloc(xmpp_ctx_t *ctx, const uint8_t *digest)
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Compute SHA1 message digest
|
/** Compute SHA1 message digest.
|
||||||
* Returns an allocated string which represents SHA1 message digest in
|
* Returns an allocated string which represents SHA1 message digest in
|
||||||
* hexadecimal notation. The string must be freed with xmpp_free().
|
* hexadecimal notation. The string must be freed with xmpp_free().
|
||||||
*
|
*
|
||||||
@@ -81,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.
|
||||||
*
|
*
|
||||||
@@ -97,7 +97,7 @@ void xmpp_sha1_digest(const unsigned char *data, size_t len,
|
|||||||
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().
|
||||||
@@ -111,7 +111,7 @@ void xmpp_sha1_digest(const unsigned char *data, size_t len,
|
|||||||
* xmpp_sha1_free(sha1);
|
* xmpp_sha1_free(sha1);
|
||||||
* @endcode
|
* @endcode
|
||||||
*
|
*
|
||||||
* @param ctx a Strophe context onject
|
* @param ctx a Strophe context object
|
||||||
*
|
*
|
||||||
* @return new SHA1 object
|
* @return new SHA1 object
|
||||||
*
|
*
|
||||||
@@ -130,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
|
||||||
*
|
*
|
||||||
@@ -141,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
|
||||||
@@ -155,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().
|
||||||
*
|
*
|
||||||
@@ -168,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().
|
||||||
*
|
*
|
||||||
@@ -185,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().
|
||||||
@@ -201,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
|
||||||
@@ -419,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
|
||||||
@@ -435,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.
|
||||||
@@ -471,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
|
||||||
|
|||||||
@@ -47,6 +47,7 @@
|
|||||||
|
|
||||||
#include "strophe.h"
|
#include "strophe.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
#include "resolver.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
/* Workaround for visual studio without va_copy support. */
|
/* Workaround for visual studio without va_copy support. */
|
||||||
@@ -63,6 +64,7 @@
|
|||||||
void xmpp_initialize(void)
|
void xmpp_initialize(void)
|
||||||
{
|
{
|
||||||
sock_initialize();
|
sock_initialize();
|
||||||
|
resolver_initialize();
|
||||||
tls_initialize();
|
tls_initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,6 +75,7 @@
|
|||||||
void xmpp_shutdown(void)
|
void xmpp_shutdown(void)
|
||||||
{
|
{
|
||||||
tls_shutdown();
|
tls_shutdown();
|
||||||
|
resolver_shutdown();
|
||||||
sock_shutdown();
|
sock_shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
28
src/event.c
28
src/event.c
@@ -51,6 +51,18 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
|
|
||||||
|
static int _connect_next(xmpp_conn_t *conn)
|
||||||
|
{
|
||||||
|
sock_close(conn->sock);
|
||||||
|
conn->sock = sock_connect(conn->xsock);
|
||||||
|
if (conn->sock < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
conn->timeout_stamp = time_stamp();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/** 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
|
||||||
@@ -180,6 +192,11 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
|
|||||||
conn->connect_timeout)
|
conn->connect_timeout)
|
||||||
FD_SET(conn->sock, &wfds);
|
FD_SET(conn->sock, &wfds);
|
||||||
else {
|
else {
|
||||||
|
ret = _connect_next(conn);
|
||||||
|
if (ret == 0) {
|
||||||
|
FD_SET(conn->sock, &wfds);
|
||||||
|
break;
|
||||||
|
}
|
||||||
conn->error = ETIMEDOUT;
|
conn->error = ETIMEDOUT;
|
||||||
xmpp_info(ctx, "xmpp", "Connection attempt timed out.");
|
xmpp_info(ctx, "xmpp", "Connection attempt timed out.");
|
||||||
conn_disconnect(conn);
|
conn_disconnect(conn);
|
||||||
@@ -238,6 +255,11 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
|
|||||||
|
|
||||||
/* check for error */
|
/* check for error */
|
||||||
ret = sock_connect_error(conn->sock);
|
ret = sock_connect_error(conn->sock);
|
||||||
|
if (ret != 0) {
|
||||||
|
ret = _connect_next(conn);
|
||||||
|
if (ret == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
/* connection failed */
|
/* connection failed */
|
||||||
xmpp_debug(ctx, "xmpp", "connection failed, error %d", ret);
|
xmpp_debug(ctx, "xmpp", "connection failed, error %d", ret);
|
||||||
@@ -262,10 +284,8 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
|
|||||||
if (ret > 0) {
|
if (ret > 0) {
|
||||||
ret = parser_feed(conn->parser, buf, ret);
|
ret = parser_feed(conn->parser, buf, ret);
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
/* parse error, we need to shut down */
|
xmpp_debug(ctx, "xmpp", "parse error [%s]", buf);
|
||||||
/* FIXME */
|
xmpp_send_error(conn, XMPP_SE_INVALID_XML, "parse error");
|
||||||
xmpp_debug(ctx, "xmpp", "parse error, disconnecting");
|
|
||||||
conn_disconnect(conn);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (conn->tls) {
|
if (conn->tls) {
|
||||||
|
|||||||
@@ -163,6 +163,8 @@ int hash_add(hash_t *table, const char * const key, void *data)
|
|||||||
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;
|
||||||
@@ -241,7 +243,7 @@ void hash_iter_release(hash_iterator_t *iter)
|
|||||||
|
|
||||||
iter->ref--;
|
iter->ref--;
|
||||||
|
|
||||||
if (iter->ref <= 0) {
|
if (iter->ref == 0) { // ref is unsigned!!!
|
||||||
hash_release(iter->table);
|
hash_release(iter->table);
|
||||||
xmpp_free(ctx, iter);
|
xmpp_free(ctx, iter);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -137,7 +137,7 @@ static void _start_element(void *userdata,
|
|||||||
if (parser->depth == 0) {
|
if (parser->depth == 0) {
|
||||||
/* notify the owner */
|
/* notify the owner */
|
||||||
if (parser->startcb)
|
if (parser->startcb)
|
||||||
parser->startcb((char *)name, (char **)attrs,
|
parser->startcb(name, (char **)attrs,
|
||||||
parser->userdata);
|
parser->userdata);
|
||||||
} else {
|
} else {
|
||||||
/* build stanzas at depth 1 */
|
/* build stanzas at depth 1 */
|
||||||
|
|||||||
@@ -249,6 +249,8 @@ void parser_free(parser_t *parser)
|
|||||||
{
|
{
|
||||||
if (parser->xmlctx)
|
if (parser->xmlctx)
|
||||||
xmlFreeParserCtxt(parser->xmlctx);
|
xmlFreeParserCtxt(parser->xmlctx);
|
||||||
|
if (parser->stanza)
|
||||||
|
xmpp_stanza_release(parser->stanza);
|
||||||
xmpp_free(parser->ctx, parser);
|
xmpp_free(parser->ctx, parser);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -257,18 +259,16 @@ int parser_reset(parser_t *parser)
|
|||||||
{
|
{
|
||||||
if (parser->xmlctx)
|
if (parser->xmlctx)
|
||||||
xmlFreeParserCtxt(parser->xmlctx);
|
xmlFreeParserCtxt(parser->xmlctx);
|
||||||
|
|
||||||
if (parser->stanza)
|
if (parser->stanza)
|
||||||
xmpp_stanza_release(parser->stanza);
|
xmpp_stanza_release(parser->stanza);
|
||||||
|
|
||||||
|
parser->stanza = NULL;
|
||||||
|
parser->depth = 0;
|
||||||
|
|
||||||
parser->xmlctx = xmlCreatePushParserCtxt(&parser->handlers,
|
parser->xmlctx = xmlCreatePushParserCtxt(&parser->handlers,
|
||||||
parser, NULL, 0, NULL);
|
parser, NULL, 0, NULL);
|
||||||
if (!parser->xmlctx) return 0;
|
|
||||||
|
|
||||||
parser->depth = 0;
|
return parser->xmlctx ? 1 : 0;
|
||||||
parser->stanza = NULL;
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* feed a chunk of data to the parser */
|
/* feed a chunk of data to the parser */
|
||||||
|
|||||||
@@ -127,9 +127,11 @@ 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);
|
||||||
memcpy(seed_material + entropy_input_len, nonce, nonce_len);
|
if (nonce != NULL)
|
||||||
|
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;
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
401
src/resolver.c
401
src/resolver.c
@@ -1,4 +1,4 @@
|
|||||||
/* resolver.h
|
/* resolver.c
|
||||||
* strophe XMPP client library -- DNS resolver
|
* strophe XMPP client library -- DNS resolver
|
||||||
*
|
*
|
||||||
* Copyright (C) 2015 Dmitry Podgorny <pasis.ua@gmail.com>
|
* Copyright (C) 2015 Dmitry Podgorny <pasis.ua@gmail.com>
|
||||||
@@ -13,11 +13,15 @@
|
|||||||
* DNS resolver.
|
* DNS resolver.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _WIN32
|
#if !defined(_WIN32) && !defined(HAVE_CARES)
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <arpa/nameser.h>
|
#include <arpa/nameser.h>
|
||||||
#include <resolv.h> /* res_query */
|
#include <resolv.h> /* res_query */
|
||||||
#endif /* _WIN32 */
|
#endif /* _WIN32 && HAVE_CARES */
|
||||||
|
|
||||||
|
#ifdef HAVE_CARES
|
||||||
|
#include <ares.h>
|
||||||
|
#endif /* HAVE_CARES */
|
||||||
|
|
||||||
#include <string.h> /* strncpy */
|
#include <string.h> /* strncpy */
|
||||||
|
|
||||||
@@ -31,6 +35,189 @@
|
|||||||
#define MESSAGE_T_SRV 33
|
#define MESSAGE_T_SRV 33
|
||||||
#define MESSAGE_C_IN 1
|
#define MESSAGE_C_IN 1
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Forward declarations.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#ifdef HAVE_CARES
|
||||||
|
static int resolver_ares_srv_lookup_buf(xmpp_ctx_t *ctx,
|
||||||
|
const unsigned char *buf,
|
||||||
|
size_t len,
|
||||||
|
resolver_srv_rr_t **srv_rr_list);
|
||||||
|
static int resolver_ares_srv_lookup(xmpp_ctx_t *ctx, const char *fulldomain,
|
||||||
|
resolver_srv_rr_t **srv_rr_list);
|
||||||
|
#endif /* HAVE_CARES */
|
||||||
|
|
||||||
|
#ifndef HAVE_CARES
|
||||||
|
static int resolver_raw_srv_lookup_buf(xmpp_ctx_t *ctx,
|
||||||
|
const unsigned char *buf,
|
||||||
|
size_t len,
|
||||||
|
resolver_srv_rr_t **srv_rr_list);
|
||||||
|
#endif /* !HAVE_CARES */
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
static int resolver_win32_srv_lookup(xmpp_ctx_t *ctx, const char *fulldomain,
|
||||||
|
resolver_srv_rr_t **srv_rr_list);
|
||||||
|
static int resolver_win32_srv_query(const char *fulldomain,
|
||||||
|
unsigned char *buf, size_t len);
|
||||||
|
#endif /* _WIN32 */
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Implementation.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
void resolver_initialize(void)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_CARES
|
||||||
|
ares_library_init(ARES_LIB_INIT_ALL);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void resolver_shutdown(void)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_CARES
|
||||||
|
ares_library_cleanup();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void resolver_srv_list_sort(resolver_srv_rr_t **srv_rr_list)
|
||||||
|
{
|
||||||
|
resolver_srv_rr_t *rr_head;
|
||||||
|
resolver_srv_rr_t *rr_current;
|
||||||
|
resolver_srv_rr_t *rr_next;
|
||||||
|
resolver_srv_rr_t *rr_prev;
|
||||||
|
int swap;
|
||||||
|
|
||||||
|
rr_head = *srv_rr_list;
|
||||||
|
|
||||||
|
if ((rr_head == NULL) || (rr_head->next == NULL)) {
|
||||||
|
/* Empty or single record list */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
rr_prev = NULL;
|
||||||
|
rr_current = rr_head;
|
||||||
|
rr_next = rr_head->next;
|
||||||
|
swap = 0;
|
||||||
|
while (rr_next != NULL) {
|
||||||
|
/*
|
||||||
|
* RFC2052: A client MUST attempt to contact the target host
|
||||||
|
* with the lowest-numbered priority it can reach.
|
||||||
|
* RFC2052: When selecting a target host among the
|
||||||
|
* those that have the same priority, the chance of trying
|
||||||
|
* this one first SHOULD be proportional to its weight.
|
||||||
|
*/
|
||||||
|
if ((rr_current->priority > rr_next->priority) ||
|
||||||
|
(rr_current->priority == rr_next->priority &&
|
||||||
|
rr_current->weight < rr_next->weight))
|
||||||
|
{
|
||||||
|
/* Swap node */
|
||||||
|
swap = 1;
|
||||||
|
if (rr_prev != NULL) {
|
||||||
|
rr_prev->next = rr_next;
|
||||||
|
} else {
|
||||||
|
/* Swap head node */
|
||||||
|
rr_head = rr_next;
|
||||||
|
}
|
||||||
|
rr_current->next = rr_next->next;
|
||||||
|
rr_next->next = rr_current;
|
||||||
|
|
||||||
|
rr_prev = rr_next;
|
||||||
|
rr_next = rr_current->next;
|
||||||
|
} else {
|
||||||
|
/* Next node */
|
||||||
|
rr_prev = rr_current;
|
||||||
|
rr_current = rr_next;
|
||||||
|
rr_next = rr_next->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (swap != 0);
|
||||||
|
|
||||||
|
*srv_rr_list = rr_head;
|
||||||
|
}
|
||||||
|
|
||||||
|
int resolver_srv_lookup_buf(xmpp_ctx_t *ctx, const unsigned char *buf,
|
||||||
|
size_t len, resolver_srv_rr_t **srv_rr_list)
|
||||||
|
{
|
||||||
|
int set;
|
||||||
|
|
||||||
|
#ifdef HAVE_CARES
|
||||||
|
set = resolver_ares_srv_lookup_buf(ctx, buf, len, srv_rr_list);
|
||||||
|
#else
|
||||||
|
set = resolver_raw_srv_lookup_buf(ctx, buf, len, srv_rr_list);
|
||||||
|
#endif
|
||||||
|
resolver_srv_list_sort(srv_rr_list);
|
||||||
|
|
||||||
|
return set;
|
||||||
|
}
|
||||||
|
|
||||||
|
int resolver_srv_lookup(xmpp_ctx_t *ctx, const char *service, const char *proto,
|
||||||
|
const char *domain, resolver_srv_rr_t **srv_rr_list)
|
||||||
|
{
|
||||||
|
#define RESOLVER_BUF_MAX 65536
|
||||||
|
unsigned char *buf;
|
||||||
|
char fulldomain[2048];
|
||||||
|
int len;
|
||||||
|
int set = XMPP_DOMAIN_NOT_FOUND;
|
||||||
|
|
||||||
|
(void)buf;
|
||||||
|
(void)len;
|
||||||
|
|
||||||
|
xmpp_snprintf(fulldomain, sizeof(fulldomain),
|
||||||
|
"_%s._%s.%s", service, proto, domain);
|
||||||
|
|
||||||
|
*srv_rr_list = NULL;
|
||||||
|
|
||||||
|
#ifdef HAVE_CARES
|
||||||
|
set = resolver_ares_srv_lookup(ctx, fulldomain, srv_rr_list);
|
||||||
|
#else /* HAVE_CARES */
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
set = resolver_win32_srv_lookup(ctx, fulldomain, srv_rr_list);
|
||||||
|
if (set == XMPP_DOMAIN_FOUND)
|
||||||
|
return set;
|
||||||
|
#endif /* _WIN32 */
|
||||||
|
|
||||||
|
buf = xmpp_alloc(ctx, RESOLVER_BUF_MAX);
|
||||||
|
if (buf == NULL)
|
||||||
|
return XMPP_DOMAIN_NOT_FOUND;
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
len = resolver_win32_srv_query(fulldomain, buf, RESOLVER_BUF_MAX);
|
||||||
|
#else /* _WIN32 */
|
||||||
|
len = res_query(fulldomain, MESSAGE_C_IN, MESSAGE_T_SRV, buf,
|
||||||
|
RESOLVER_BUF_MAX);
|
||||||
|
#endif /* _WIN32 */
|
||||||
|
|
||||||
|
if (len > 0)
|
||||||
|
set = resolver_srv_lookup_buf(ctx, buf, (size_t)len, srv_rr_list);
|
||||||
|
|
||||||
|
xmpp_free(ctx, buf);
|
||||||
|
|
||||||
|
#endif /* HAVE_CARES */
|
||||||
|
|
||||||
|
return set;
|
||||||
|
}
|
||||||
|
|
||||||
|
void resolver_srv_free(xmpp_ctx_t *ctx, resolver_srv_rr_t *srv_rr_list)
|
||||||
|
{
|
||||||
|
resolver_srv_rr_t *rr;
|
||||||
|
|
||||||
|
while (srv_rr_list != NULL) {
|
||||||
|
rr = srv_rr_list->next;
|
||||||
|
xmpp_free(ctx, srv_rr_list);
|
||||||
|
srv_rr_list = rr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef HAVE_CARES
|
||||||
|
/*******************************************************************************
|
||||||
|
* Resolver raw implementation.
|
||||||
|
*
|
||||||
|
* This code is common for both unix and win32.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
struct message_header {
|
struct message_header {
|
||||||
uint16_t id;
|
uint16_t id;
|
||||||
uint8_t octet2;
|
uint8_t octet2;
|
||||||
@@ -41,13 +228,6 @@ struct message_header {
|
|||||||
uint16_t arcount;
|
uint16_t arcount;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
static int resolver_win32_srv_lookup(xmpp_ctx_t *ctx, const char *fulldomain,
|
|
||||||
resolver_srv_rr_t **srv_rr_list);
|
|
||||||
static int resolver_win32_srv_query(const char *fulldomain,
|
|
||||||
unsigned char *buf, size_t len);
|
|
||||||
#endif /* _WIN32 */
|
|
||||||
|
|
||||||
/* the same as ntohs(), but receives pointer to the value */
|
/* the same as ntohs(), but receives pointer to the value */
|
||||||
static uint16_t xmpp_ntohs_ptr(const void *ptr)
|
static uint16_t xmpp_ntohs_ptr(const void *ptr)
|
||||||
{
|
{
|
||||||
@@ -80,7 +260,7 @@ static size_t message_name_append_safe(char *name, size_t name_len,
|
|||||||
copy_len = name_max > name_len ? name_max - name_len : 0;
|
copy_len = name_max > name_len ? name_max - name_len : 0;
|
||||||
copy_len = xmpp_min(tail_len, copy_len);
|
copy_len = xmpp_min(tail_len, copy_len);
|
||||||
if (copy_len > 0)
|
if (copy_len > 0)
|
||||||
strncpy(&name[name_len], tail, copy_len);
|
memcpy(&name[name_len], tail, copy_len);
|
||||||
|
|
||||||
return name_len + tail_len;
|
return name_len + tail_len;
|
||||||
}
|
}
|
||||||
@@ -160,63 +340,6 @@ static unsigned message_name_len(const unsigned char *buf, size_t buf_len,
|
|||||||
return message_name_get(buf, buf_len, buf_offset, NULL, SIZE_MAX);
|
return message_name_get(buf, buf_len, buf_offset, NULL, SIZE_MAX);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void resolver_srv_list_sort(resolver_srv_rr_t **srv_rr_list)
|
|
||||||
{
|
|
||||||
resolver_srv_rr_t * rr_head;
|
|
||||||
resolver_srv_rr_t * rr_current;
|
|
||||||
resolver_srv_rr_t * rr_next;
|
|
||||||
resolver_srv_rr_t * rr_prev;
|
|
||||||
int swap;
|
|
||||||
|
|
||||||
rr_head = *srv_rr_list;
|
|
||||||
|
|
||||||
if ((rr_head == NULL) || (rr_head->next == NULL)) {
|
|
||||||
/* Empty or single record list */
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
do {
|
|
||||||
rr_prev = NULL;
|
|
||||||
rr_current = rr_head;
|
|
||||||
rr_next = rr_head->next;
|
|
||||||
swap = 0;
|
|
||||||
while (rr_next != NULL) {
|
|
||||||
/*
|
|
||||||
* RFC2052: A client MUST attempt to contact the target host
|
|
||||||
* with the lowest-numbered priority it can reach.
|
|
||||||
* RFC2052: When selecting a target host among the
|
|
||||||
* those that have the same priority, the chance of trying
|
|
||||||
* this one first SHOULD be proportional to its weight.
|
|
||||||
*/
|
|
||||||
if ((rr_current->priority > rr_next->priority) ||
|
|
||||||
(rr_current->priority == rr_next->priority &&
|
|
||||||
rr_current->weight < rr_next->weight))
|
|
||||||
{
|
|
||||||
/* Swap node */
|
|
||||||
swap = 1;
|
|
||||||
if (rr_prev != NULL) {
|
|
||||||
rr_prev->next = rr_next;
|
|
||||||
} else {
|
|
||||||
/* Swap head node */
|
|
||||||
rr_head = rr_next;
|
|
||||||
}
|
|
||||||
rr_current->next = rr_next->next;
|
|
||||||
rr_next->next = rr_current;
|
|
||||||
|
|
||||||
rr_prev = rr_next;
|
|
||||||
rr_next = rr_current->next;
|
|
||||||
} else {
|
|
||||||
/* Next node */
|
|
||||||
rr_prev = rr_current;
|
|
||||||
rr_current = rr_next;
|
|
||||||
rr_next = rr_next->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while (swap != 0);
|
|
||||||
|
|
||||||
*srv_rr_list = rr_head;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define BUF_OVERFLOW_CHECK(ptr, len) do { \
|
#define BUF_OVERFLOW_CHECK(ptr, len) do { \
|
||||||
if ((ptr) >= (len)) { \
|
if ((ptr) >= (len)) { \
|
||||||
if (*srv_rr_list != NULL) \
|
if (*srv_rr_list != NULL) \
|
||||||
@@ -226,8 +349,10 @@ static void resolver_srv_list_sort(resolver_srv_rr_t **srv_rr_list)
|
|||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
int resolver_srv_lookup_buf(xmpp_ctx_t *ctx, const unsigned char *buf,
|
static int resolver_raw_srv_lookup_buf(xmpp_ctx_t *ctx,
|
||||||
size_t len, resolver_srv_rr_t **srv_rr_list)
|
const unsigned char *buf,
|
||||||
|
size_t len,
|
||||||
|
resolver_srv_rr_t **srv_rr_list)
|
||||||
{
|
{
|
||||||
unsigned i;
|
unsigned i;
|
||||||
unsigned j;
|
unsigned j;
|
||||||
@@ -292,52 +417,110 @@ int resolver_srv_lookup_buf(xmpp_ctx_t *ctx, const unsigned char *buf,
|
|||||||
}
|
}
|
||||||
j += rdlength;
|
j += rdlength;
|
||||||
}
|
}
|
||||||
resolver_srv_list_sort(srv_rr_list);
|
|
||||||
|
|
||||||
return *srv_rr_list != NULL ? XMPP_DOMAIN_FOUND : XMPP_DOMAIN_NOT_FOUND;
|
return *srv_rr_list != NULL ? XMPP_DOMAIN_FOUND : XMPP_DOMAIN_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
int resolver_srv_lookup(xmpp_ctx_t *ctx, const char *service, const char *proto,
|
#endif /* !HAVE_CARES */
|
||||||
const char *domain, resolver_srv_rr_t **srv_rr_list)
|
|
||||||
{
|
|
||||||
char fulldomain[2048];
|
|
||||||
unsigned char buf[65535];
|
|
||||||
int len;
|
|
||||||
int set = XMPP_DOMAIN_NOT_FOUND;
|
|
||||||
|
|
||||||
xmpp_snprintf(fulldomain, sizeof(fulldomain),
|
#ifdef HAVE_CARES
|
||||||
"_%s._%s.%s", service, proto, domain);
|
/*******************************************************************************
|
||||||
|
* Resolver implementation using c-ares library.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
struct resolver_ares_ctx {
|
||||||
|
xmpp_ctx_t *ctx;
|
||||||
|
int result;
|
||||||
|
resolver_srv_rr_t *srv_rr_list;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int resolver_ares_srv_lookup_buf(xmpp_ctx_t *ctx,
|
||||||
|
const unsigned char *buf,
|
||||||
|
size_t len,
|
||||||
|
resolver_srv_rr_t **srv_rr_list)
|
||||||
|
{
|
||||||
|
struct ares_srv_reply *srv;
|
||||||
|
struct ares_srv_reply *item;
|
||||||
|
resolver_srv_rr_t *rr;
|
||||||
|
int rc;
|
||||||
|
|
||||||
*srv_rr_list = NULL;
|
*srv_rr_list = NULL;
|
||||||
|
|
||||||
#ifdef _WIN32
|
rc = ares_parse_srv_reply(buf, len, &srv);
|
||||||
set = resolver_win32_srv_lookup(ctx, fulldomain, srv_rr_list);
|
if (rc != ARES_SUCCESS)
|
||||||
if (set == XMPP_DOMAIN_FOUND)
|
return XMPP_DOMAIN_NOT_FOUND;
|
||||||
return set;
|
|
||||||
len = resolver_win32_srv_query(fulldomain, buf, sizeof(buf));
|
|
||||||
#else /* _WIN32 */
|
|
||||||
len = res_query(fulldomain, MESSAGE_C_IN, MESSAGE_T_SRV, buf, sizeof(buf));
|
|
||||||
#endif /* _WIN32 */
|
|
||||||
|
|
||||||
if (len > 0)
|
item = srv;
|
||||||
set = resolver_srv_lookup_buf(ctx, buf, (size_t)len, srv_rr_list);
|
while (item != NULL) {
|
||||||
|
rr = xmpp_alloc(ctx, sizeof(*rr));
|
||||||
return set;
|
if (rr == NULL)
|
||||||
}
|
break;
|
||||||
|
rr->next = *srv_rr_list;
|
||||||
void resolver_srv_free(xmpp_ctx_t *ctx, resolver_srv_rr_t *srv_rr_list)
|
rr->priority = item->priority;
|
||||||
{
|
rr->weight = item->weight;
|
||||||
resolver_srv_rr_t *rr;
|
rr->port = item->port;
|
||||||
|
strncpy(rr->target, item->host, sizeof(rr->target) - 1);
|
||||||
while (srv_rr_list != NULL) {
|
rr->target[sizeof(rr->target) - 1] = '\0';
|
||||||
rr = srv_rr_list->next;
|
*srv_rr_list = rr;
|
||||||
xmpp_free(ctx, srv_rr_list);
|
item = item->next;
|
||||||
srv_rr_list = rr;
|
|
||||||
}
|
}
|
||||||
|
ares_free_data(srv);
|
||||||
|
|
||||||
|
return *srv_rr_list == NULL ? XMPP_DOMAIN_NOT_FOUND : XMPP_DOMAIN_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef _WIN32
|
static void ares_srv_lookup_callback(void *arg, int status, int timeouts,
|
||||||
|
unsigned char *buf, int len)
|
||||||
|
{
|
||||||
|
struct resolver_ares_ctx *actx = arg;
|
||||||
|
|
||||||
|
if (status != ARES_SUCCESS)
|
||||||
|
actx->result = XMPP_DOMAIN_NOT_FOUND;
|
||||||
|
else
|
||||||
|
actx->result = resolver_ares_srv_lookup_buf(actx->ctx, buf, len,
|
||||||
|
&actx->srv_rr_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int resolver_ares_srv_lookup(xmpp_ctx_t *ctx, const char *fulldomain,
|
||||||
|
resolver_srv_rr_t **srv_rr_list)
|
||||||
|
{
|
||||||
|
struct resolver_ares_ctx actx;
|
||||||
|
ares_channel chan;
|
||||||
|
struct timeval tv;
|
||||||
|
struct timeval *tvp;
|
||||||
|
fd_set rfds;
|
||||||
|
fd_set wfds;
|
||||||
|
int nfds;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
actx.ctx = ctx;
|
||||||
|
actx.result = XMPP_DOMAIN_NOT_FOUND;
|
||||||
|
actx.srv_rr_list = NULL;
|
||||||
|
|
||||||
|
rc = ares_init(&chan);
|
||||||
|
if (rc == ARES_SUCCESS) {
|
||||||
|
ares_query(chan, fulldomain, MESSAGE_C_IN, MESSAGE_T_SRV,
|
||||||
|
ares_srv_lookup_callback, &actx);
|
||||||
|
while (1) {
|
||||||
|
FD_ZERO(&rfds);
|
||||||
|
FD_ZERO(&wfds);
|
||||||
|
nfds = ares_fds(chan, &rfds, &wfds);
|
||||||
|
if (nfds == 0)
|
||||||
|
break;
|
||||||
|
tvp = ares_timeout(chan, NULL, &tv);
|
||||||
|
select(nfds, &rfds, &wfds, NULL, tvp);
|
||||||
|
ares_process(chan, &rfds, &wfds);
|
||||||
|
}
|
||||||
|
ares_destroy(chan);
|
||||||
|
}
|
||||||
|
|
||||||
|
*srv_rr_list = actx.srv_rr_list;
|
||||||
|
return actx.result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* HAVE_CARES */
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Next part was copied from sock.c and contains old win32 code.
|
* Next part was copied from sock.c and contains old win32 code.
|
||||||
*
|
*
|
||||||
@@ -470,21 +653,21 @@ static int resolver_win32_srv_lookup(xmpp_ctx_t *ctx, const char *fulldomain,
|
|||||||
resolver_srv_rr_t *rr;
|
resolver_srv_rr_t *rr;
|
||||||
HINSTANCE hdnsapi = NULL;
|
HINSTANCE hdnsapi = NULL;
|
||||||
|
|
||||||
DNS_STATUS (WINAPI * pDnsQuery_A)(PCSTR, WORD, DWORD, PIP4_ARRAY, PDNS_RECORD*, PVOID*);
|
DNS_STATUS (WINAPI * pDnsQuery_A)(PCSTR, WORD, DWORD, PIP4_ARRAY, DNS_RECORDA**, PVOID*);
|
||||||
void (WINAPI * pDnsRecordListFree)(PDNS_RECORD, DNS_FREE_TYPE);
|
void (WINAPI * pDnsRecordListFree)(DNS_RECORDA*, DNS_FREE_TYPE);
|
||||||
|
|
||||||
if (hdnsapi = LoadLibrary("dnsapi.dll")) {
|
if (hdnsapi = LoadLibrary("dnsapi.dll")) {
|
||||||
pDnsQuery_A = (void *)GetProcAddress(hdnsapi, "DnsQuery_A");
|
pDnsQuery_A = (void *)GetProcAddress(hdnsapi, "DnsQuery_A");
|
||||||
pDnsRecordListFree = (void *)GetProcAddress(hdnsapi, "DnsRecordListFree");
|
pDnsRecordListFree = (void *)GetProcAddress(hdnsapi, "DnsRecordListFree");
|
||||||
|
|
||||||
if (pDnsQuery_A && pDnsRecordListFree) {
|
if (pDnsQuery_A && pDnsRecordListFree) {
|
||||||
PDNS_RECORD dnsrecords = NULL;
|
DNS_RECORDA *dnsrecords = NULL;
|
||||||
DNS_STATUS error;
|
DNS_STATUS error;
|
||||||
|
|
||||||
error = pDnsQuery_A(fulldomain, DNS_TYPE_SRV, DNS_QUERY_STANDARD, NULL, &dnsrecords, NULL);
|
error = pDnsQuery_A(fulldomain, DNS_TYPE_SRV, DNS_QUERY_STANDARD, NULL, &dnsrecords, NULL);
|
||||||
|
|
||||||
if (error == 0) {
|
if (error == 0) {
|
||||||
PDNS_RECORD current = dnsrecords;
|
DNS_RECORDA *current = dnsrecords;
|
||||||
|
|
||||||
while (current) {
|
while (current) {
|
||||||
if (current->wType == DNS_TYPE_SRV) {
|
if (current->wType == DNS_TYPE_SRV) {
|
||||||
@@ -517,7 +700,7 @@ static int resolver_win32_srv_query(const char *fulldomain,
|
|||||||
unsigned char *buf, size_t len)
|
unsigned char *buf, size_t len)
|
||||||
{
|
{
|
||||||
int set = 0;
|
int set = 0;
|
||||||
int insize;
|
int insize = 0;
|
||||||
|
|
||||||
/* if dnsapi didn't work/isn't there, try querying the dns server manually */
|
/* if dnsapi didn't work/isn't there, try querying the dns server manually */
|
||||||
if (!set)
|
if (!set)
|
||||||
@@ -550,7 +733,7 @@ static int resolver_win32_srv_query(const char *fulldomain,
|
|||||||
char buffer[65535];
|
char buffer[65535];
|
||||||
|
|
||||||
len = 65535;
|
len = 65535;
|
||||||
fi = buffer;
|
fi = (FIXED_INFO *)buffer;
|
||||||
|
|
||||||
if ((error = pGetNetworkParams(fi, &len)) == ERROR_SUCCESS)
|
if ((error = pGetNetworkParams(fi, &len)) == ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -33,6 +33,9 @@ typedef struct resolver_srv_rr_struc {
|
|||||||
struct resolver_srv_rr_struc *next;
|
struct resolver_srv_rr_struc *next;
|
||||||
} resolver_srv_rr_t;
|
} resolver_srv_rr_t;
|
||||||
|
|
||||||
|
void resolver_initialize(void);
|
||||||
|
void resolver_shutdown(void);
|
||||||
|
|
||||||
/** Perform lookup for RFC1035 message format.
|
/** Perform lookup for RFC1035 message format.
|
||||||
* This function allocates all elements.
|
* This function allocates all elements.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -264,7 +264,8 @@ char *sasl_digest_md5(xmpp_ctx_t *ctx, const char *challenge,
|
|||||||
xmpp_rand_nonce(ctx->rand, cnonce, sizeof(cnonce));
|
xmpp_rand_nonce(ctx->rand, cnonce, sizeof(cnonce));
|
||||||
hash_add(table, "cnonce", xmpp_strdup(ctx, cnonce));
|
hash_add(table, "cnonce", xmpp_strdup(ctx, cnonce));
|
||||||
hash_add(table, "nc", xmpp_strdup(ctx, "00000001"));
|
hash_add(table, "nc", xmpp_strdup(ctx, "00000001"));
|
||||||
hash_add(table, "qop", xmpp_strdup(ctx, "auth"));
|
if (hash_get(table, "qop") == NULL)
|
||||||
|
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));
|
||||||
|
|||||||
@@ -197,8 +197,9 @@ void crypto_SHA1_Update(SHA1_CTX* context, const uint8_t* data,
|
|||||||
size_t i, j;
|
size_t i, j;
|
||||||
|
|
||||||
j = (context->count[0] >> 3) & 63;
|
j = (context->count[0] >> 3) & 63;
|
||||||
if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++;
|
if ((context->count[0] += (uint32_t)len << 3) < ((uint32_t)len << 3))
|
||||||
context->count[1] += (len >> 29);
|
context->count[1]++;
|
||||||
|
context->count[1] += (uint32_t)(len >> 29);
|
||||||
if ((j + len) > 63) {
|
if ((j + len) > 63) {
|
||||||
memcpy(&context->buffer[j], data, (i = 64-j));
|
memcpy(&context->buffer[j], data, (i = 64-j));
|
||||||
SHA1_Transform(context->state, context->buffer);
|
SHA1_Transform(context->state, context->buffer);
|
||||||
|
|||||||
95
src/sock.c
95
src/sock.c
@@ -33,9 +33,17 @@
|
|||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
#include "sock.h"
|
#include "sock.h"
|
||||||
#include "snprintf.h"
|
#include "snprintf.h"
|
||||||
|
|
||||||
|
struct _xmpp_sock_t {
|
||||||
|
xmpp_ctx_t *ctx;
|
||||||
|
struct addrinfo *ainfo_list;
|
||||||
|
struct addrinfo *current;
|
||||||
|
sock_t sock;
|
||||||
|
};
|
||||||
|
|
||||||
void sock_initialize(void)
|
void sock_initialize(void)
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
@@ -69,13 +77,23 @@ static int _in_progress(int error)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
sock_t sock_connect(const char * const host, const unsigned short port)
|
xmpp_sock_t *sock_new(xmpp_ctx_t *ctx, const char *host, unsigned short port)
|
||||||
{
|
{
|
||||||
sock_t sock;
|
xmpp_sock_t *xsock;
|
||||||
char service[6];
|
char service[6];
|
||||||
struct addrinfo *res, *ainfo, hints;
|
struct addrinfo hints;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
xsock = xmpp_alloc(ctx, sizeof *xsock);
|
||||||
|
if (xsock == NULL) {
|
||||||
|
xmpp_error(ctx, "sock", "Memory allocation error.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
xsock->ctx = ctx;
|
||||||
|
xsock->ainfo_list = NULL;
|
||||||
|
xsock->current = NULL;
|
||||||
|
xsock->sock = -1;
|
||||||
|
|
||||||
xmpp_snprintf(service, 6, "%u", port);
|
xmpp_snprintf(service, 6, "%u", port);
|
||||||
|
|
||||||
memset(&hints, 0, sizeof(struct addrinfo));
|
memset(&hints, 0, sizeof(struct addrinfo));
|
||||||
@@ -86,11 +104,33 @@ sock_t sock_connect(const char * const host, const unsigned short port)
|
|||||||
hints.ai_protocol = IPPROTO_TCP;
|
hints.ai_protocol = IPPROTO_TCP;
|
||||||
hints.ai_socktype = SOCK_STREAM;
|
hints.ai_socktype = SOCK_STREAM;
|
||||||
|
|
||||||
err = getaddrinfo(host, service, &hints, &res);
|
err = getaddrinfo(host, service, &hints, &xsock->ainfo_list);
|
||||||
if (err != 0)
|
if (err != 0) {
|
||||||
return -1;
|
xmpp_free(ctx, xsock);
|
||||||
|
xsock = NULL;
|
||||||
|
}
|
||||||
|
return xsock;
|
||||||
|
}
|
||||||
|
|
||||||
for (ainfo = res; ainfo != NULL; ainfo = ainfo->ai_next) {
|
void sock_free(xmpp_sock_t *xsock)
|
||||||
|
{
|
||||||
|
if (xsock->ainfo_list != NULL)
|
||||||
|
freeaddrinfo(xsock->ainfo_list);
|
||||||
|
xmpp_free(xsock->ctx, xsock);
|
||||||
|
}
|
||||||
|
|
||||||
|
sock_t sock_connect(xmpp_sock_t *xsock)
|
||||||
|
{
|
||||||
|
struct addrinfo *ainfo;
|
||||||
|
sock_t sock = -1;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (xsock->current == NULL)
|
||||||
|
ainfo = xsock->ainfo_list;
|
||||||
|
else
|
||||||
|
ainfo = xsock->current->ai_next;
|
||||||
|
|
||||||
|
for (; ainfo != NULL; ainfo = ainfo->ai_next) {
|
||||||
sock = socket(ainfo->ai_family, ainfo->ai_socktype, ainfo->ai_protocol);
|
sock = socket(ainfo->ai_family, ainfo->ai_socktype, ainfo->ai_protocol);
|
||||||
if (sock < 0)
|
if (sock < 0)
|
||||||
continue;
|
continue;
|
||||||
@@ -103,9 +143,13 @@ sock_t sock_connect(const char * const host, const unsigned short port)
|
|||||||
}
|
}
|
||||||
sock_close(sock);
|
sock_close(sock);
|
||||||
}
|
}
|
||||||
freeaddrinfo(res);
|
|
||||||
sock = ainfo == NULL ? -1 : sock;
|
|
||||||
|
|
||||||
|
xsock->sock = sock;
|
||||||
|
xsock->current = ainfo;
|
||||||
|
if (ainfo == NULL) {
|
||||||
|
freeaddrinfo(xsock->ainfo_list);
|
||||||
|
xsock->ainfo_list = NULL;
|
||||||
|
}
|
||||||
return sock;
|
return sock;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,38 +202,33 @@ int sock_close(const sock_t sock)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int sock_set_blocking(const sock_t sock)
|
static int _sock_set_blocking_mode(sock_t sock, int blocking)
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
u_long block = 0;
|
u_long nonblock = blocking ? 0 : 1;
|
||||||
return ioctlsocket(sock, FIONBIO, &block);
|
|
||||||
#else
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
rc = fcntl(sock, F_GETFL, NULL);
|
|
||||||
if (rc >= 0) {
|
|
||||||
rc = fcntl(sock, F_SETFL, rc & (~O_NONBLOCK));
|
|
||||||
}
|
|
||||||
return rc;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
int sock_set_nonblocking(const sock_t sock)
|
|
||||||
{
|
|
||||||
#ifdef _WIN32
|
|
||||||
u_long nonblock = 1;
|
|
||||||
return ioctlsocket(sock, FIONBIO, &nonblock);
|
return ioctlsocket(sock, FIONBIO, &nonblock);
|
||||||
#else
|
#else
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
rc = fcntl(sock, F_GETFL, NULL);
|
rc = fcntl(sock, F_GETFL, NULL);
|
||||||
if (rc >= 0) {
|
if (rc >= 0) {
|
||||||
rc = fcntl(sock, F_SETFL, rc | O_NONBLOCK);
|
rc = blocking ? rc & (~O_NONBLOCK) : rc | O_NONBLOCK;
|
||||||
|
rc = fcntl(sock, F_SETFL, rc);
|
||||||
}
|
}
|
||||||
return rc;
|
return rc;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int sock_set_blocking(const sock_t sock)
|
||||||
|
{
|
||||||
|
return _sock_set_blocking_mode(sock, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int sock_set_nonblocking(const sock_t sock)
|
||||||
|
{
|
||||||
|
return _sock_set_blocking_mode(sock, 0);
|
||||||
|
}
|
||||||
|
|
||||||
int sock_read(const sock_t sock, void * const buff, const size_t len)
|
int sock_read(const sock_t sock, void * const buff, const size_t len)
|
||||||
{
|
{
|
||||||
return recv(sock, buff, len, 0);
|
return recv(sock, buff, len, 0);
|
||||||
|
|||||||
@@ -25,12 +25,16 @@ typedef int sock_t;
|
|||||||
typedef SOCKET sock_t;
|
typedef SOCKET sock_t;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
typedef struct _xmpp_sock_t xmpp_sock_t;
|
||||||
|
|
||||||
void sock_initialize(void);
|
void sock_initialize(void);
|
||||||
void sock_shutdown(void);
|
void sock_shutdown(void);
|
||||||
|
|
||||||
int sock_error(void);
|
int sock_error(void);
|
||||||
|
|
||||||
sock_t sock_connect(const char * const host, const unsigned short port);
|
xmpp_sock_t *sock_new(xmpp_ctx_t *ctx, const char *host, unsigned short port);
|
||||||
|
void sock_free(xmpp_sock_t *xsock);
|
||||||
|
sock_t sock_connect(xmpp_sock_t *xsock);
|
||||||
int sock_close(const sock_t sock);
|
int sock_close(const sock_t sock);
|
||||||
|
|
||||||
int sock_set_blocking(const sock_t sock);
|
int sock_set_blocking(const sock_t sock);
|
||||||
|
|||||||
487
src/stanza.c
487
src/stanza.c
@@ -1,7 +1,7 @@
|
|||||||
/* stanza.c
|
/* stanza.c
|
||||||
** strophe XMPP client library -- XMPP stanza object and utilities
|
** strophe XMPP client library -- XMPP stanza object and utilities
|
||||||
**
|
**
|
||||||
** 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.
|
||||||
@@ -40,15 +40,15 @@ xmpp_stanza_t *xmpp_stanza_new(xmpp_ctx_t *ctx)
|
|||||||
|
|
||||||
stanza = xmpp_alloc(ctx, sizeof(xmpp_stanza_t));
|
stanza = xmpp_alloc(ctx, sizeof(xmpp_stanza_t));
|
||||||
if (stanza != NULL) {
|
if (stanza != NULL) {
|
||||||
stanza->ref = 1;
|
stanza->ref = 1;
|
||||||
stanza->ctx = ctx;
|
stanza->ctx = ctx;
|
||||||
stanza->type = XMPP_STANZA_UNKNOWN;
|
stanza->type = XMPP_STANZA_UNKNOWN;
|
||||||
stanza->prev = NULL;
|
stanza->prev = NULL;
|
||||||
stanza->next = NULL;
|
stanza->next = NULL;
|
||||||
stanza->children = NULL;
|
stanza->children = NULL;
|
||||||
stanza->parent = NULL;
|
stanza->parent = NULL;
|
||||||
stanza->data = NULL;
|
stanza->data = NULL;
|
||||||
stanza->attributes = NULL;
|
stanza->attributes = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return stanza;
|
return stanza;
|
||||||
@@ -121,27 +121,27 @@ xmpp_stanza_t *xmpp_stanza_copy(const xmpp_stanza_t * const stanza)
|
|||||||
copy->type = stanza->type;
|
copy->type = stanza->type;
|
||||||
|
|
||||||
if (stanza->data) {
|
if (stanza->data) {
|
||||||
copy->data = xmpp_strdup(stanza->ctx, stanza->data);
|
copy->data = xmpp_strdup(stanza->ctx, stanza->data);
|
||||||
if (!copy->data) goto copy_error;
|
if (!copy->data) goto copy_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stanza->attributes) {
|
if (stanza->attributes) {
|
||||||
if (_stanza_copy_attributes(copy, stanza) == -1)
|
if (_stanza_copy_attributes(copy, stanza) == -1)
|
||||||
goto copy_error;
|
goto copy_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
tail = copy->children;
|
tail = copy->children;
|
||||||
for (child = stanza->children; child; child = child->next) {
|
for (child = stanza->children; child; child = child->next) {
|
||||||
copychild = xmpp_stanza_copy(child);
|
copychild = xmpp_stanza_copy(child);
|
||||||
if (!copychild) goto copy_error;
|
if (!copychild) goto copy_error;
|
||||||
copychild->parent = copy;
|
copychild->parent = copy;
|
||||||
|
|
||||||
if (tail) {
|
if (tail) {
|
||||||
copychild->prev = tail;
|
copychild->prev = tail;
|
||||||
tail->next = copychild;
|
tail->next = copychild;
|
||||||
} else
|
} else
|
||||||
copy->children = copychild;
|
copy->children = copychild;
|
||||||
tail = copychild;
|
tail = copychild;
|
||||||
}
|
}
|
||||||
|
|
||||||
return copy;
|
return copy;
|
||||||
@@ -153,7 +153,7 @@ copy_error:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Release a stanza object and all of its children.
|
/** Release a stanza object and all of its children.
|
||||||
* This function releases a stanza object and potentially all of its
|
* This function releases a stanza object and potentially all of its
|
||||||
* children, which may cause the object(s) to be freed.
|
* children, which may cause the object(s) to be freed.
|
||||||
*
|
*
|
||||||
* @param stanza a Strophe stanza object
|
* @param stanza a Strophe stanza object
|
||||||
@@ -169,20 +169,20 @@ int xmpp_stanza_release(xmpp_stanza_t * const stanza)
|
|||||||
|
|
||||||
/* release stanza */
|
/* release stanza */
|
||||||
if (stanza->ref > 1)
|
if (stanza->ref > 1)
|
||||||
stanza->ref--;
|
stanza->ref--;
|
||||||
else {
|
else {
|
||||||
/* release all children */
|
/* release all children */
|
||||||
child = stanza->children;
|
child = stanza->children;
|
||||||
while (child) {
|
while (child) {
|
||||||
tchild = child;
|
tchild = child;
|
||||||
child = child->next;
|
child = child->next;
|
||||||
xmpp_stanza_release(tchild);
|
xmpp_stanza_release(tchild);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stanza->attributes) hash_release(stanza->attributes);
|
if (stanza->attributes) hash_release(stanza->attributes);
|
||||||
if (stanza->data) xmpp_free(stanza->ctx, stanza->data);
|
if (stanza->data) xmpp_free(stanza->ctx, stanza->data);
|
||||||
xmpp_free(stanza->ctx, stanza);
|
xmpp_free(stanza->ctx, stanza);
|
||||||
released = 1;
|
released = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return released;
|
return released;
|
||||||
@@ -274,17 +274,17 @@ static char *_escape_xml(xmpp_ctx_t * const ctx, char *text)
|
|||||||
|
|
||||||
/* small helper function */
|
/* small helper function */
|
||||||
static void _render_update(int *written, const int length,
|
static void _render_update(int *written, const int length,
|
||||||
const int lastwrite,
|
const int lastwrite,
|
||||||
size_t *left, char **ptr)
|
size_t *left, char **ptr)
|
||||||
{
|
{
|
||||||
*written += lastwrite;
|
*written += lastwrite;
|
||||||
|
|
||||||
if (*written >= length) {
|
if (*written >= length) {
|
||||||
*left = 0;
|
*left = 0;
|
||||||
*ptr = NULL;
|
*ptr = NULL;
|
||||||
} else {
|
} else {
|
||||||
*left -= lastwrite;
|
*left -= lastwrite;
|
||||||
*ptr = &(*ptr)[lastwrite];
|
*ptr = &(*ptr)[lastwrite];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -294,7 +294,7 @@ static void _render_update(int *written, const int length,
|
|||||||
* and return values > buflen indicate buffer was not large enough
|
* and return values > buflen indicate buffer was not large enough
|
||||||
*/
|
*/
|
||||||
static int _render_stanza_recursive(xmpp_stanza_t *stanza,
|
static int _render_stanza_recursive(xmpp_stanza_t *stanza,
|
||||||
char * const buf, size_t const buflen)
|
char * const buf, size_t const buflen)
|
||||||
{
|
{
|
||||||
char *ptr = buf;
|
char *ptr = buf;
|
||||||
size_t left = buflen;
|
size_t left = buflen;
|
||||||
@@ -309,80 +309,86 @@ static int _render_stanza_recursive(xmpp_stanza_t *stanza,
|
|||||||
if (stanza->type == XMPP_STANZA_UNKNOWN) return XMPP_EINVOP;
|
if (stanza->type == XMPP_STANZA_UNKNOWN) return XMPP_EINVOP;
|
||||||
|
|
||||||
if (stanza->type == XMPP_STANZA_TEXT) {
|
if (stanza->type == XMPP_STANZA_TEXT) {
|
||||||
if (!stanza->data) return XMPP_EINVOP;
|
if (!stanza->data) return XMPP_EINVOP;
|
||||||
|
|
||||||
tmp = _escape_xml(stanza->ctx, stanza->data);
|
tmp = _escape_xml(stanza->ctx, stanza->data);
|
||||||
if (tmp == NULL) return XMPP_EMEM;
|
if (tmp == NULL) return XMPP_EMEM;
|
||||||
ret = xmpp_snprintf(ptr, left, "%s", tmp);
|
ret = xmpp_snprintf(ptr, left, "%s", tmp);
|
||||||
xmpp_free(stanza->ctx, tmp);
|
xmpp_free(stanza->ctx, tmp);
|
||||||
if (ret < 0) return XMPP_EMEM;
|
if (ret < 0) return XMPP_EMEM;
|
||||||
_render_update(&written, buflen, ret, &left, &ptr);
|
_render_update(&written, buflen, ret, &left, &ptr);
|
||||||
} else { /* stanza->type == XMPP_STANZA_TAG */
|
} else { /* stanza->type == XMPP_STANZA_TAG */
|
||||||
if (!stanza->data) return XMPP_EINVOP;
|
if (!stanza->data) return XMPP_EINVOP;
|
||||||
|
|
||||||
/* write beginning of tag and attributes */
|
/* write beginning of tag and attributes */
|
||||||
ret = xmpp_snprintf(ptr, left, "<%s", stanza->data);
|
ret = xmpp_snprintf(ptr, left, "<%s", stanza->data);
|
||||||
if (ret < 0) return XMPP_EMEM;
|
if (ret < 0) return XMPP_EMEM;
|
||||||
_render_update(&written, buflen, ret, &left, &ptr);
|
_render_update(&written, buflen, ret, &left, &ptr);
|
||||||
|
|
||||||
if (stanza->attributes && hash_num_keys(stanza->attributes) > 0) {
|
if (stanza->attributes && hash_num_keys(stanza->attributes) > 0) {
|
||||||
iter = hash_iter_new(stanza->attributes);
|
iter = hash_iter_new(stanza->attributes);
|
||||||
while ((key = hash_iter_next(iter))) {
|
while ((key = hash_iter_next(iter))) {
|
||||||
if (!strcmp(key, "xmlns")) {
|
if (!strcmp(key, "xmlns")) {
|
||||||
/* don't output namespace if parent stanza is the same */
|
/* don't output namespace if parent stanza is the same */
|
||||||
if (stanza->parent &&
|
if (stanza->parent &&
|
||||||
stanza->parent->attributes &&
|
stanza->parent->attributes &&
|
||||||
hash_get(stanza->parent->attributes, key) &&
|
hash_get(stanza->parent->attributes, key) &&
|
||||||
!strcmp((char*)hash_get(stanza->attributes, key),
|
!strcmp((char*)hash_get(stanza->attributes, key),
|
||||||
(char*)hash_get(stanza->parent->attributes, key)))
|
(char*)hash_get(stanza->parent->attributes, key)))
|
||||||
continue;
|
continue;
|
||||||
/* or if this is the stream namespace */
|
/* or if this is the stream namespace */
|
||||||
if (!stanza->parent &&
|
if (!stanza->parent &&
|
||||||
!strcmp((char*)hash_get(stanza->attributes, key),
|
!strcmp((char*)hash_get(stanza->attributes, key),
|
||||||
XMPP_NS_CLIENT))
|
XMPP_NS_CLIENT))
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
tmp = _escape_xml(stanza->ctx,
|
tmp = _escape_xml(stanza->ctx,
|
||||||
(char *)hash_get(stanza->attributes, key));
|
(char *)hash_get(stanza->attributes, key));
|
||||||
if (tmp == NULL) return XMPP_EMEM;
|
if (tmp == NULL) {
|
||||||
ret = xmpp_snprintf(ptr, left, " %s=\"%s\"", key, tmp);
|
hash_iter_release(iter);
|
||||||
xmpp_free(stanza->ctx, tmp);
|
return XMPP_EMEM;
|
||||||
if (ret < 0) return XMPP_EMEM;
|
}
|
||||||
_render_update(&written, buflen, ret, &left, &ptr);
|
ret = xmpp_snprintf(ptr, left, " %s=\"%s\"", key, tmp);
|
||||||
}
|
xmpp_free(stanza->ctx, tmp);
|
||||||
hash_iter_release(iter);
|
if (ret < 0) {
|
||||||
}
|
hash_iter_release(iter);
|
||||||
|
return XMPP_EMEM;
|
||||||
|
}
|
||||||
|
_render_update(&written, buflen, ret, &left, &ptr);
|
||||||
|
}
|
||||||
|
hash_iter_release(iter);
|
||||||
|
}
|
||||||
|
|
||||||
if (!stanza->children) {
|
if (!stanza->children) {
|
||||||
/* write end if singleton tag */
|
/* write end if singleton tag */
|
||||||
ret = xmpp_snprintf(ptr, left, "/>");
|
ret = xmpp_snprintf(ptr, left, "/>");
|
||||||
if (ret < 0) return XMPP_EMEM;
|
if (ret < 0) return XMPP_EMEM;
|
||||||
_render_update(&written, buflen, ret, &left, &ptr);
|
_render_update(&written, buflen, ret, &left, &ptr);
|
||||||
} else {
|
} else {
|
||||||
/* this stanza has child stanzas */
|
/* this stanza has child stanzas */
|
||||||
|
|
||||||
/* write end of start tag */
|
/* write end of start tag */
|
||||||
ret = xmpp_snprintf(ptr, left, ">");
|
ret = xmpp_snprintf(ptr, left, ">");
|
||||||
if (ret < 0) return XMPP_EMEM;
|
if (ret < 0) return XMPP_EMEM;
|
||||||
_render_update(&written, buflen, ret, &left, &ptr);
|
_render_update(&written, buflen, ret, &left, &ptr);
|
||||||
|
|
||||||
/* iterate and recurse over child stanzas */
|
|
||||||
child = stanza->children;
|
|
||||||
while (child) {
|
|
||||||
ret = _render_stanza_recursive(child, ptr, left);
|
|
||||||
if (ret < 0) return ret;
|
|
||||||
|
|
||||||
_render_update(&written, buflen, ret, &left, &ptr);
|
/* iterate and recurse over child stanzas */
|
||||||
|
child = stanza->children;
|
||||||
|
while (child) {
|
||||||
|
ret = _render_stanza_recursive(child, ptr, left);
|
||||||
|
if (ret < 0) return ret;
|
||||||
|
|
||||||
child = child->next;
|
_render_update(&written, buflen, ret, &left, &ptr);
|
||||||
}
|
|
||||||
|
|
||||||
/* write end tag */
|
child = child->next;
|
||||||
ret = xmpp_snprintf(ptr, left, "</%s>", stanza->data);
|
}
|
||||||
if (ret < 0) return XMPP_EMEM;
|
|
||||||
|
/* write end tag */
|
||||||
_render_update(&written, buflen, ret, &left, &ptr);
|
ret = xmpp_snprintf(ptr, left, "</%s>", stanza->data);
|
||||||
}
|
if (ret < 0) return XMPP_EMEM;
|
||||||
|
|
||||||
|
_render_update(&written, buflen, ret, &left, &ptr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return written;
|
return written;
|
||||||
@@ -415,27 +421,37 @@ int xmpp_stanza_to_text(xmpp_stanza_t *stanza,
|
|||||||
length = 1024;
|
length = 1024;
|
||||||
buffer = xmpp_alloc(stanza->ctx, length);
|
buffer = xmpp_alloc(stanza->ctx, length);
|
||||||
if (!buffer) {
|
if (!buffer) {
|
||||||
*buf = NULL;
|
*buf = NULL;
|
||||||
*buflen = 0;
|
*buflen = 0;
|
||||||
return XMPP_EMEM;
|
return XMPP_EMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = _render_stanza_recursive(stanza, buffer, length);
|
ret = _render_stanza_recursive(stanza, buffer, length);
|
||||||
if (ret < 0) return ret;
|
if (ret < 0) {
|
||||||
|
xmpp_free(stanza->ctx, buffer);
|
||||||
|
*buf = NULL;
|
||||||
|
*buflen = 0;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
if ((size_t)ret > length - 1) {
|
if ((size_t)ret > length - 1) {
|
||||||
tmp = xmpp_realloc(stanza->ctx, buffer, ret + 1);
|
tmp = xmpp_realloc(stanza->ctx, buffer, ret + 1);
|
||||||
if (!tmp) {
|
if (!tmp) {
|
||||||
xmpp_free(stanza->ctx, buffer);
|
xmpp_free(stanza->ctx, buffer);
|
||||||
*buf = NULL;
|
*buf = NULL;
|
||||||
*buflen = 0;
|
*buflen = 0;
|
||||||
return XMPP_EMEM;
|
return XMPP_EMEM;
|
||||||
}
|
}
|
||||||
length = ret + 1;
|
length = ret + 1;
|
||||||
buffer = tmp;
|
buffer = tmp;
|
||||||
|
|
||||||
ret = _render_stanza_recursive(stanza, buffer, length);
|
ret = _render_stanza_recursive(stanza, buffer, length);
|
||||||
if ((size_t)ret > length - 1) return XMPP_EMEM;
|
if ((size_t)ret > length - 1) {
|
||||||
|
xmpp_free(stanza->ctx, buffer);
|
||||||
|
*buf = NULL;
|
||||||
|
*buflen = 0;
|
||||||
|
return XMPP_EMEM;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer[length - 1] = 0;
|
buffer[length - 1] = 0;
|
||||||
@@ -457,7 +473,7 @@ int xmpp_stanza_to_text(xmpp_stanza_t *stanza,
|
|||||||
* @ingroup Stanza
|
* @ingroup Stanza
|
||||||
*/
|
*/
|
||||||
int xmpp_stanza_set_name(xmpp_stanza_t *stanza,
|
int xmpp_stanza_set_name(xmpp_stanza_t *stanza,
|
||||||
const char * const name)
|
const char * const name)
|
||||||
{
|
{
|
||||||
if (stanza->type == XMPP_STANZA_TEXT) return XMPP_EINVOP;
|
if (stanza->type == XMPP_STANZA_TEXT) return XMPP_EINVOP;
|
||||||
|
|
||||||
@@ -496,7 +512,7 @@ const char *xmpp_stanza_get_name(xmpp_stanza_t * const stanza)
|
|||||||
int xmpp_stanza_get_attribute_count(xmpp_stanza_t * const stanza)
|
int xmpp_stanza_get_attribute_count(xmpp_stanza_t * const stanza)
|
||||||
{
|
{
|
||||||
if (stanza->attributes == NULL) {
|
if (stanza->attributes == NULL) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return hash_num_keys(stanza->attributes);
|
return hash_num_keys(stanza->attributes);
|
||||||
@@ -517,30 +533,30 @@ int xmpp_stanza_get_attribute_count(xmpp_stanza_t * const stanza)
|
|||||||
* @ingroup Stanza
|
* @ingroup Stanza
|
||||||
*/
|
*/
|
||||||
int xmpp_stanza_get_attributes(xmpp_stanza_t * const stanza,
|
int xmpp_stanza_get_attributes(xmpp_stanza_t * const stanza,
|
||||||
const char **attr, int attrlen)
|
const char **attr, int attrlen)
|
||||||
{
|
{
|
||||||
hash_iterator_t *iter;
|
hash_iterator_t *iter;
|
||||||
const char *key;
|
const char *key;
|
||||||
int num = 0;
|
int num = 0;
|
||||||
|
|
||||||
if (stanza->attributes == NULL) {
|
if (stanza->attributes == NULL) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
iter = hash_iter_new(stanza->attributes);
|
iter = hash_iter_new(stanza->attributes);
|
||||||
while ((key = hash_iter_next(iter)) != NULL && attrlen) {
|
while ((key = hash_iter_next(iter)) != NULL && attrlen) {
|
||||||
attr[num++] = key;
|
attr[num++] = key;
|
||||||
attrlen--;
|
attrlen--;
|
||||||
if (attrlen == 0) {
|
if (attrlen == 0) {
|
||||||
hash_iter_release(iter);
|
hash_iter_release(iter);
|
||||||
return num;
|
return num;
|
||||||
}
|
}
|
||||||
attr[num++] = hash_get(stanza->attributes, key);
|
attr[num++] = hash_get(stanza->attributes, key);
|
||||||
attrlen--;
|
attrlen--;
|
||||||
if (attrlen == 0) {
|
if (attrlen == 0) {
|
||||||
hash_iter_release(iter);
|
hash_iter_release(iter);
|
||||||
return num;
|
return num;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hash_iter_release(iter);
|
hash_iter_release(iter);
|
||||||
@@ -558,8 +574,8 @@ int xmpp_stanza_get_attributes(xmpp_stanza_t * const stanza,
|
|||||||
* @ingroup Stanza
|
* @ingroup Stanza
|
||||||
*/
|
*/
|
||||||
int xmpp_stanza_set_attribute(xmpp_stanza_t * const stanza,
|
int xmpp_stanza_set_attribute(xmpp_stanza_t * const stanza,
|
||||||
const char * const key,
|
const char * const key,
|
||||||
const char * const value)
|
const char * const value)
|
||||||
{
|
{
|
||||||
char *val;
|
char *val;
|
||||||
int rc;
|
int rc;
|
||||||
@@ -567,13 +583,12 @@ int xmpp_stanza_set_attribute(xmpp_stanza_t * const stanza,
|
|||||||
if (stanza->type != XMPP_STANZA_TAG) return XMPP_EINVOP;
|
if (stanza->type != XMPP_STANZA_TAG) return XMPP_EINVOP;
|
||||||
|
|
||||||
if (!stanza->attributes) {
|
if (!stanza->attributes) {
|
||||||
stanza->attributes = hash_new(stanza->ctx, 8, xmpp_free);
|
stanza->attributes = hash_new(stanza->ctx, 8, xmpp_free);
|
||||||
if (!stanza->attributes) return XMPP_EMEM;
|
if (!stanza->attributes) return XMPP_EMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
val = xmpp_strdup(stanza->ctx, value);
|
val = xmpp_strdup(stanza->ctx, value);
|
||||||
if (!val) {
|
if (!val) {
|
||||||
hash_release(stanza->attributes);
|
|
||||||
return XMPP_EMEM;
|
return XMPP_EMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -598,7 +613,7 @@ int xmpp_stanza_set_attribute(xmpp_stanza_t * const stanza,
|
|||||||
* @ingroup Stanza
|
* @ingroup Stanza
|
||||||
*/
|
*/
|
||||||
int xmpp_stanza_set_ns(xmpp_stanza_t * const stanza,
|
int xmpp_stanza_set_ns(xmpp_stanza_t * const stanza,
|
||||||
const char * const ns)
|
const char * const ns)
|
||||||
{
|
{
|
||||||
return xmpp_stanza_set_attribute(stanza, "xmlns", ns);
|
return xmpp_stanza_set_attribute(stanza, "xmlns", ns);
|
||||||
}
|
}
|
||||||
@@ -624,12 +639,12 @@ int xmpp_stanza_add_child(xmpp_stanza_t *stanza, xmpp_stanza_t *child)
|
|||||||
child->parent = stanza;
|
child->parent = stanza;
|
||||||
|
|
||||||
if (!stanza->children)
|
if (!stanza->children)
|
||||||
stanza->children = child;
|
stanza->children = child;
|
||||||
else {
|
else {
|
||||||
s = stanza->children;
|
s = stanza->children;
|
||||||
while (s->next) s = s->next;
|
while (s->next) s = s->next;
|
||||||
s->next = child;
|
s->next = child;
|
||||||
child->prev = s;
|
child->prev = s;
|
||||||
}
|
}
|
||||||
|
|
||||||
return XMPP_EOK;
|
return XMPP_EOK;
|
||||||
@@ -649,7 +664,7 @@ int xmpp_stanza_add_child(xmpp_stanza_t *stanza, xmpp_stanza_t *child)
|
|||||||
* @ingroup Stanza
|
* @ingroup Stanza
|
||||||
*/
|
*/
|
||||||
int xmpp_stanza_set_text(xmpp_stanza_t *stanza,
|
int xmpp_stanza_set_text(xmpp_stanza_t *stanza,
|
||||||
const char * const text)
|
const char * const text)
|
||||||
{
|
{
|
||||||
if (stanza->type == XMPP_STANZA_TAG) return XMPP_EINVOP;
|
if (stanza->type == XMPP_STANZA_TAG) return XMPP_EINVOP;
|
||||||
|
|
||||||
@@ -676,8 +691,8 @@ int xmpp_stanza_set_text(xmpp_stanza_t *stanza,
|
|||||||
* @ingroup Stanza
|
* @ingroup Stanza
|
||||||
*/
|
*/
|
||||||
int xmpp_stanza_set_text_with_size(xmpp_stanza_t *stanza,
|
int xmpp_stanza_set_text_with_size(xmpp_stanza_t *stanza,
|
||||||
const char * const text,
|
const char * const text,
|
||||||
const size_t size)
|
const size_t size)
|
||||||
{
|
{
|
||||||
if (stanza->type == XMPP_STANZA_TAG) return XMPP_EINVOP;
|
if (stanza->type == XMPP_STANZA_TAG) return XMPP_EINVOP;
|
||||||
|
|
||||||
@@ -780,14 +795,14 @@ const char *xmpp_stanza_get_from(xmpp_stanza_t * const stanza)
|
|||||||
* @ingroup Stanza
|
* @ingroup Stanza
|
||||||
*/
|
*/
|
||||||
xmpp_stanza_t *xmpp_stanza_get_child_by_name(xmpp_stanza_t * const stanza,
|
xmpp_stanza_t *xmpp_stanza_get_child_by_name(xmpp_stanza_t * const stanza,
|
||||||
const char * const name)
|
const char * const name)
|
||||||
{
|
{
|
||||||
xmpp_stanza_t *child;
|
xmpp_stanza_t *child;
|
||||||
|
|
||||||
for (child = stanza->children; child; child = child->next) {
|
for (child = stanza->children; child; child = child->next) {
|
||||||
if (child->type == XMPP_STANZA_TAG &&
|
if (child->type == XMPP_STANZA_TAG &&
|
||||||
(strcmp(name, xmpp_stanza_get_name(child)) == 0))
|
(strcmp(name, xmpp_stanza_get_name(child)) == 0))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return child;
|
return child;
|
||||||
@@ -806,14 +821,15 @@ xmpp_stanza_t *xmpp_stanza_get_child_by_name(xmpp_stanza_t * const stanza,
|
|||||||
* @ingroup Stanza
|
* @ingroup Stanza
|
||||||
*/
|
*/
|
||||||
xmpp_stanza_t *xmpp_stanza_get_child_by_ns(xmpp_stanza_t * const stanza,
|
xmpp_stanza_t *xmpp_stanza_get_child_by_ns(xmpp_stanza_t * const stanza,
|
||||||
const char * const ns)
|
const char * const ns)
|
||||||
{
|
{
|
||||||
xmpp_stanza_t *child;
|
xmpp_stanza_t *child;
|
||||||
|
const char *child_ns;
|
||||||
|
|
||||||
for (child = stanza->children; child; child = child->next) {
|
for (child = stanza->children; child; child = child->next) {
|
||||||
if (xmpp_stanza_get_ns(child) &&
|
child_ns = xmpp_stanza_get_ns(child);
|
||||||
strcmp(ns, xmpp_stanza_get_ns(child)) == 0)
|
if (child_ns && strcmp(ns, child_ns) == 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return child;
|
return child;
|
||||||
@@ -866,16 +882,16 @@ char *xmpp_stanza_get_text(xmpp_stanza_t * const stanza)
|
|||||||
char *text;
|
char *text;
|
||||||
|
|
||||||
if (stanza->type == XMPP_STANZA_TEXT) {
|
if (stanza->type == XMPP_STANZA_TEXT) {
|
||||||
if (stanza->data)
|
if (stanza->data)
|
||||||
return xmpp_strdup(stanza->ctx, stanza->data);
|
return xmpp_strdup(stanza->ctx, stanza->data);
|
||||||
else
|
else
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
len = 0;
|
len = 0;
|
||||||
for (child = stanza->children; child; child = child->next)
|
for (child = stanza->children; child; child = child->next)
|
||||||
if (child->type == XMPP_STANZA_TEXT)
|
if (child->type == XMPP_STANZA_TEXT)
|
||||||
len += strlen(child->data);
|
len += strlen(child->data);
|
||||||
|
|
||||||
if (len == 0) return NULL;
|
if (len == 0) return NULL;
|
||||||
|
|
||||||
@@ -884,11 +900,11 @@ char *xmpp_stanza_get_text(xmpp_stanza_t * const stanza)
|
|||||||
|
|
||||||
len = 0;
|
len = 0;
|
||||||
for (child = stanza->children; child; child = child->next)
|
for (child = stanza->children; child; child = child->next)
|
||||||
if (child->type == XMPP_STANZA_TEXT) {
|
if (child->type == XMPP_STANZA_TEXT) {
|
||||||
clen = strlen(child->data);
|
clen = strlen(child->data);
|
||||||
memcpy(&text[len], child->data, clen);
|
memcpy(&text[len], child->data, clen);
|
||||||
len += clen;
|
len += clen;
|
||||||
}
|
}
|
||||||
|
|
||||||
text[len] = 0;
|
text[len] = 0;
|
||||||
|
|
||||||
@@ -911,7 +927,7 @@ char *xmpp_stanza_get_text(xmpp_stanza_t * const stanza)
|
|||||||
const char *xmpp_stanza_get_text_ptr(xmpp_stanza_t * const stanza)
|
const char *xmpp_stanza_get_text_ptr(xmpp_stanza_t * const stanza)
|
||||||
{
|
{
|
||||||
if (stanza->type == XMPP_STANZA_TEXT)
|
if (stanza->type == XMPP_STANZA_TEXT)
|
||||||
return stanza->data;
|
return stanza->data;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -928,7 +944,7 @@ const char *xmpp_stanza_get_text_ptr(xmpp_stanza_t * const stanza)
|
|||||||
* @ingroup Stanza
|
* @ingroup Stanza
|
||||||
*/
|
*/
|
||||||
int xmpp_stanza_set_id(xmpp_stanza_t * const stanza,
|
int xmpp_stanza_set_id(xmpp_stanza_t * const stanza,
|
||||||
const char * const id)
|
const char * const id)
|
||||||
{
|
{
|
||||||
return xmpp_stanza_set_attribute(stanza, "id", id);
|
return xmpp_stanza_set_attribute(stanza, "id", id);
|
||||||
}
|
}
|
||||||
@@ -945,7 +961,7 @@ int xmpp_stanza_set_id(xmpp_stanza_t * const stanza,
|
|||||||
* @ingroup Stanza
|
* @ingroup Stanza
|
||||||
*/
|
*/
|
||||||
int xmpp_stanza_set_type(xmpp_stanza_t * const stanza,
|
int xmpp_stanza_set_type(xmpp_stanza_t * const stanza,
|
||||||
const char * const type)
|
const char * const type)
|
||||||
{
|
{
|
||||||
return xmpp_stanza_set_attribute(stanza, "type", type);
|
return xmpp_stanza_set_attribute(stanza, "type", type);
|
||||||
}
|
}
|
||||||
@@ -1001,10 +1017,10 @@ const char *xmpp_stanza_get_attribute(xmpp_stanza_t * const stanza,
|
|||||||
const char * const name)
|
const char * const name)
|
||||||
{
|
{
|
||||||
if (stanza->type != XMPP_STANZA_TAG)
|
if (stanza->type != XMPP_STANZA_TAG)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (!stanza->attributes)
|
if (!stanza->attributes)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
return hash_get(stanza->attributes, name);
|
return hash_get(stanza->attributes, name);
|
||||||
}
|
}
|
||||||
@@ -1218,3 +1234,122 @@ xmpp_stanza_t *xmpp_presence_new(xmpp_ctx_t *ctx)
|
|||||||
{
|
{
|
||||||
return _stanza_new_with_attrs(ctx, "presence", NULL, NULL, NULL);
|
return _stanza_new_with_attrs(ctx, "presence", NULL, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Create an <stream:error/> stanza object with given type and error text.
|
||||||
|
* The error text is optional and may be NULL.
|
||||||
|
*
|
||||||
|
* @param ctx a Strophe context object
|
||||||
|
* @param type enum of xmpp_error_type_t
|
||||||
|
* @param text content of a 'text'
|
||||||
|
*
|
||||||
|
* @return a new Strophe stanza object
|
||||||
|
*
|
||||||
|
* @todo Handle errors in this function
|
||||||
|
*
|
||||||
|
* @ingroup Stanza
|
||||||
|
*/
|
||||||
|
xmpp_stanza_t *xmpp_error_new(xmpp_ctx_t *ctx, xmpp_error_type_t const type,
|
||||||
|
const char * const text)
|
||||||
|
{
|
||||||
|
xmpp_stanza_t *error = _stanza_new_with_attrs(ctx, "stream:error", NULL, NULL, NULL);
|
||||||
|
xmpp_stanza_t *error_type = xmpp_stanza_new(ctx);
|
||||||
|
|
||||||
|
switch(type) {
|
||||||
|
case XMPP_SE_BAD_FORMAT:
|
||||||
|
xmpp_stanza_set_name(error_type, "bad-format");
|
||||||
|
break;
|
||||||
|
case XMPP_SE_BAD_NS_PREFIX:
|
||||||
|
xmpp_stanza_set_name(error_type, "bad-namespace-prefix");
|
||||||
|
break;
|
||||||
|
case XMPP_SE_CONFLICT:
|
||||||
|
xmpp_stanza_set_name(error_type, "conflict");
|
||||||
|
break;
|
||||||
|
case XMPP_SE_CONN_TIMEOUT:
|
||||||
|
xmpp_stanza_set_name(error_type, "connection-timeout");
|
||||||
|
break;
|
||||||
|
case XMPP_SE_HOST_GONE:
|
||||||
|
xmpp_stanza_set_name(error_type, "host-gone");
|
||||||
|
break;
|
||||||
|
case XMPP_SE_HOST_UNKNOWN:
|
||||||
|
xmpp_stanza_set_name(error_type, "host-unknown");
|
||||||
|
break;
|
||||||
|
case XMPP_SE_IMPROPER_ADDR:
|
||||||
|
xmpp_stanza_set_name(error_type, "improper-addressing");
|
||||||
|
break;
|
||||||
|
case XMPP_SE_INTERNAL_SERVER_ERROR:
|
||||||
|
xmpp_stanza_set_name(error_type, "internal-server-error");
|
||||||
|
break;
|
||||||
|
case XMPP_SE_INVALID_FROM:
|
||||||
|
xmpp_stanza_set_name(error_type, "invalid-from");
|
||||||
|
break;
|
||||||
|
case XMPP_SE_INVALID_ID:
|
||||||
|
xmpp_stanza_set_name(error_type, "invalid-id");
|
||||||
|
break;
|
||||||
|
case XMPP_SE_INVALID_NS:
|
||||||
|
xmpp_stanza_set_name(error_type, "invalid-namespace");
|
||||||
|
break;
|
||||||
|
case XMPP_SE_INVALID_XML:
|
||||||
|
xmpp_stanza_set_name(error_type, "invalid-xml");
|
||||||
|
break;
|
||||||
|
case XMPP_SE_NOT_AUTHORIZED:
|
||||||
|
xmpp_stanza_set_name(error_type, "not-authorized");
|
||||||
|
break;
|
||||||
|
case XMPP_SE_POLICY_VIOLATION:
|
||||||
|
xmpp_stanza_set_name(error_type, "policy-violation");
|
||||||
|
break;
|
||||||
|
case XMPP_SE_REMOTE_CONN_FAILED:
|
||||||
|
xmpp_stanza_set_name(error_type, "remote-connection-failed");
|
||||||
|
break;
|
||||||
|
case XMPP_SE_RESOURCE_CONSTRAINT:
|
||||||
|
xmpp_stanza_set_name(error_type, "resource-constraint");
|
||||||
|
break;
|
||||||
|
case XMPP_SE_RESTRICTED_XML:
|
||||||
|
xmpp_stanza_set_name(error_type, "restricted-xml");
|
||||||
|
break;
|
||||||
|
case XMPP_SE_SEE_OTHER_HOST:
|
||||||
|
xmpp_stanza_set_name(error_type, "see-other-host");
|
||||||
|
break;
|
||||||
|
case XMPP_SE_SYSTEM_SHUTDOWN:
|
||||||
|
xmpp_stanza_set_name(error_type, "system-shutdown");
|
||||||
|
break;
|
||||||
|
case XMPP_SE_UNDEFINED_CONDITION:
|
||||||
|
xmpp_stanza_set_name(error_type, "undefined-condition");
|
||||||
|
break;
|
||||||
|
case XMPP_SE_UNSUPPORTED_ENCODING:
|
||||||
|
xmpp_stanza_set_name(error_type, "unsupported-encoding");
|
||||||
|
break;
|
||||||
|
case XMPP_SE_UNSUPPORTED_STANZA_TYPE:
|
||||||
|
xmpp_stanza_set_name(error_type, "unsupported-stanza-type");
|
||||||
|
break;
|
||||||
|
case XMPP_SE_UNSUPPORTED_VERSION:
|
||||||
|
xmpp_stanza_set_name(error_type, "unsupported-version");
|
||||||
|
break;
|
||||||
|
case XMPP_SE_XML_NOT_WELL_FORMED:
|
||||||
|
xmpp_stanza_set_name(error_type, "xml-not-well-formed");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
xmpp_stanza_set_name(error_type, "internal-server-error");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
xmpp_stanza_set_ns(error_type, XMPP_NS_STREAMS_IETF);
|
||||||
|
xmpp_stanza_add_child(error, error_type);
|
||||||
|
xmpp_stanza_release(error_type);
|
||||||
|
|
||||||
|
if (text) {
|
||||||
|
xmpp_stanza_t *error_text = xmpp_stanza_new(ctx);
|
||||||
|
xmpp_stanza_t *content = xmpp_stanza_new(ctx);
|
||||||
|
|
||||||
|
xmpp_stanza_set_name(error_text, "text");
|
||||||
|
xmpp_stanza_set_ns(error_text, XMPP_NS_STREAMS_IETF);
|
||||||
|
|
||||||
|
xmpp_stanza_set_text(content, text);
|
||||||
|
xmpp_stanza_add_child(error_text, content);
|
||||||
|
xmpp_stanza_release(content);
|
||||||
|
|
||||||
|
xmpp_stanza_add_child(error, error_text);
|
||||||
|
xmpp_stanza_release(error_text);
|
||||||
|
}
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|||||||
@@ -31,6 +31,22 @@
|
|||||||
#include "tls.h"
|
#include "tls.h"
|
||||||
#include "sock.h"
|
#include "sock.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Redefine OPENSSL_VERSION_NUMBER for LibreSSL.
|
||||||
|
* LibreSSL and OpenSSL use different and incompatible version schemes. Solve
|
||||||
|
* this issue in the way how nginx project did.
|
||||||
|
*/
|
||||||
|
#if (defined LIBRESSL_VERSION_NUMBER && OPENSSL_VERSION_NUMBER == 0x20000000L)
|
||||||
|
#undef OPENSSL_VERSION_NUMBER
|
||||||
|
#if (LIBRESSL_VERSION_NUMBER >= 0x2080000fL)
|
||||||
|
#define OPENSSL_VERSION_NUMBER 0x1010000fL
|
||||||
|
#elif (LIBRESSL_VERSION_NUMBER >= 0x2070000fL)
|
||||||
|
#define OPENSSL_VERSION_NUMBER 0x1000200fL
|
||||||
|
#else
|
||||||
|
#define OPENSSL_VERSION_NUMBER 0x1000107fL
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
struct _tls {
|
struct _tls {
|
||||||
xmpp_ctx_t *ctx;
|
xmpp_ctx_t *ctx;
|
||||||
sock_t sock;
|
sock_t sock;
|
||||||
@@ -48,6 +64,7 @@ enum {
|
|||||||
static void _tls_sock_wait(tls_t *tls, int error);
|
static void _tls_sock_wait(tls_t *tls, int error);
|
||||||
static void _tls_set_error(tls_t *tls, int error);
|
static void _tls_set_error(tls_t *tls, int error);
|
||||||
static void _tls_log_error(xmpp_ctx_t *ctx);
|
static void _tls_log_error(xmpp_ctx_t *ctx);
|
||||||
|
static void _tls_dump_cert_info(tls_t *tls);
|
||||||
|
|
||||||
void tls_initialize(void)
|
void tls_initialize(void)
|
||||||
{
|
{
|
||||||
@@ -188,6 +205,7 @@ int tls_start(tls_t *tls)
|
|||||||
x509_res = SSL_get_verify_result(tls->ssl);
|
x509_res = SSL_get_verify_result(tls->ssl);
|
||||||
xmpp_debug(tls->ctx, "tls", "Certificate verification %s",
|
xmpp_debug(tls->ctx, "tls", "Certificate verification %s",
|
||||||
x509_res == X509_V_OK ? "passed" : "FAILED");
|
x509_res == X509_V_OK ? "passed" : "FAILED");
|
||||||
|
_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;
|
||||||
@@ -199,6 +217,11 @@ int tls_stop(tls_t *tls)
|
|||||||
int error;
|
int error;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
/* According to OpenSSL.org, we must not call SSL_shutdown(3)
|
||||||
|
if a previous fatal error has occurred on a connection. */
|
||||||
|
if (tls->lasterror == SSL_ERROR_SYSCALL || tls->lasterror == SSL_ERROR_SSL)
|
||||||
|
return 1;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
++retries;
|
++retries;
|
||||||
ret = SSL_shutdown(tls->ssl);
|
ret = SSL_shutdown(tls->ssl);
|
||||||
@@ -209,6 +232,14 @@ int tls_stop(tls_t *tls)
|
|||||||
}
|
}
|
||||||
_tls_sock_wait(tls, error);
|
_tls_sock_wait(tls, error);
|
||||||
}
|
}
|
||||||
|
if (error == SSL_ERROR_SYSCALL && errno == 0) {
|
||||||
|
/*
|
||||||
|
* Handle special case when peer closes connection instead of
|
||||||
|
* proper shutdown.
|
||||||
|
*/
|
||||||
|
error = 0;
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
_tls_set_error(tls, error);
|
_tls_set_error(tls, error);
|
||||||
|
|
||||||
return ret <= 0 ? 0 : 1;
|
return ret <= 0 ? 0 : 1;
|
||||||
@@ -260,6 +291,8 @@ static void _tls_sock_wait(tls_t *tls, int error)
|
|||||||
int nfds;
|
int nfds;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
if (error == SSL_ERROR_NONE) return;
|
||||||
|
|
||||||
FD_ZERO(&rfds);
|
FD_ZERO(&rfds);
|
||||||
FD_ZERO(&wfds);
|
FD_ZERO(&wfds);
|
||||||
if (error == SSL_ERROR_WANT_READ)
|
if (error == SSL_ERROR_WANT_READ)
|
||||||
@@ -278,6 +311,7 @@ static void _tls_sock_wait(tls_t *tls, int error)
|
|||||||
static void _tls_set_error(tls_t *tls, int error)
|
static void _tls_set_error(tls_t *tls, int error)
|
||||||
{
|
{
|
||||||
if (error != 0 && !tls_is_recoverable(error)) {
|
if (error != 0 && !tls_is_recoverable(error)) {
|
||||||
|
xmpp_debug(tls->ctx, "tls", "error=%d errno=%d", error, errno);
|
||||||
_tls_log_error(tls->ctx);
|
_tls_log_error(tls->ctx);
|
||||||
}
|
}
|
||||||
tls->lasterror = error;
|
tls->lasterror = error;
|
||||||
@@ -296,3 +330,26 @@ static void _tls_log_error(xmpp_ctx_t *ctx)
|
|||||||
}
|
}
|
||||||
} while (e != 0);
|
} while (e != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void _tls_dump_cert_info(tls_t *tls)
|
||||||
|
{
|
||||||
|
X509 *cert;
|
||||||
|
char *name;
|
||||||
|
|
||||||
|
cert = SSL_get_peer_certificate(tls->ssl);
|
||||||
|
if (cert == NULL)
|
||||||
|
xmpp_debug(tls->ctx, "tls", "Certificate was not presented by peer");
|
||||||
|
else {
|
||||||
|
name = X509_NAME_oneline(X509_get_subject_name(cert), NULL, 0);
|
||||||
|
if (name != NULL) {
|
||||||
|
xmpp_debug(tls->ctx, "tls", "Subject=%s", name);
|
||||||
|
OPENSSL_free(name);
|
||||||
|
}
|
||||||
|
name = X509_NAME_oneline(X509_get_issuer_name(cert), NULL, 0);
|
||||||
|
if (name != NULL) {
|
||||||
|
xmpp_debug(tls->ctx, "tls", "Issuer=%s", name);
|
||||||
|
OPENSSL_free(name);
|
||||||
|
}
|
||||||
|
X509_free(cert);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -255,10 +255,18 @@ int tls_start(tls_t *tls)
|
|||||||
NULL, 0, &(tls->hctxt), &sbdout,
|
NULL, 0, &(tls->hctxt), &sbdout,
|
||||||
&ctxtattr, NULL);
|
&ctxtattr, NULL);
|
||||||
|
|
||||||
|
unsigned char *p = sbin[0].pvBuffer;
|
||||||
|
int len = 0;
|
||||||
|
|
||||||
while (ret == SEC_I_CONTINUE_NEEDED
|
while (ret == SEC_I_CONTINUE_NEEDED
|
||||||
|| ret == SEC_I_INCOMPLETE_CREDENTIALS) {
|
|| ret == SEC_I_INCOMPLETE_CREDENTIALS
|
||||||
unsigned char *p = sbin[0].pvBuffer;
|
|| ret == SEC_E_INCOMPLETE_MESSAGE) {
|
||||||
int len = 0, inbytes = 0;
|
int inbytes = 0;
|
||||||
|
|
||||||
|
if (ret != SEC_E_INCOMPLETE_MESSAGE) {
|
||||||
|
len = 0;
|
||||||
|
p = sbin[0].pvBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
if (sbdout.pBuffers[0].cbBuffer) {
|
if (sbdout.pBuffers[0].cbBuffer) {
|
||||||
unsigned char *writebuff = sbdout.pBuffers[0].pvBuffer;
|
unsigned char *writebuff = sbdout.pBuffers[0].pvBuffer;
|
||||||
|
|||||||
@@ -169,6 +169,10 @@ typedef struct _xmpp_stanza_t xmpp_stanza_t;
|
|||||||
* 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,6 +221,7 @@ typedef void (*xmpp_conn_handler)(xmpp_conn_t * const conn,
|
|||||||
xmpp_stream_error_t * const stream_error,
|
xmpp_stream_error_t * const stream_error,
|
||||||
void * const userdata);
|
void * const userdata);
|
||||||
|
|
||||||
|
void xmpp_send_error(xmpp_conn_t * const conn, xmpp_error_type_t const type, char * const text);
|
||||||
xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t * const ctx);
|
xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t * const ctx);
|
||||||
xmpp_conn_t *xmpp_conn_clone(xmpp_conn_t * const conn);
|
xmpp_conn_t *xmpp_conn_clone(xmpp_conn_t * const conn);
|
||||||
int xmpp_conn_release(xmpp_conn_t * const conn);
|
int xmpp_conn_release(xmpp_conn_t * const conn);
|
||||||
@@ -381,6 +386,8 @@ int xmpp_message_set_body(xmpp_stanza_t *msg, const char * const text);
|
|||||||
xmpp_stanza_t *xmpp_iq_new(xmpp_ctx_t *ctx, const char * const type,
|
xmpp_stanza_t *xmpp_iq_new(xmpp_ctx_t *ctx, const char * const type,
|
||||||
const char * const id);
|
const char * const id);
|
||||||
xmpp_stanza_t *xmpp_presence_new(xmpp_ctx_t *ctx);
|
xmpp_stanza_t *xmpp_presence_new(xmpp_ctx_t *ctx);
|
||||||
|
xmpp_stanza_t *xmpp_error_new(xmpp_ctx_t *ctx, xmpp_error_type_t const type,
|
||||||
|
const char * const text);
|
||||||
|
|
||||||
/* jid */
|
/* jid */
|
||||||
|
|
||||||
|
|||||||
@@ -16,18 +16,19 @@
|
|||||||
#include "strophe.h"
|
#include "strophe.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "hash.h"
|
#include "hash.h"
|
||||||
|
#include "test.h"
|
||||||
|
|
||||||
#define TABLESIZE 100
|
#define TABLESIZE 100
|
||||||
#define TESTSIZE 500
|
#define TESTSIZE 500
|
||||||
|
|
||||||
/* static test data */
|
/* static test data */
|
||||||
const int nkeys = 5;
|
|
||||||
const char *keys[] = {
|
const char *keys[] = {
|
||||||
"foo", "bar", "baz", "quux", "xyzzy"
|
"foo", "bar", "baz", "quux", "xyzzy"
|
||||||
};
|
};
|
||||||
const char *values[] = {
|
const char *values[] = {
|
||||||
"wuzzle", "mug", "canonical", "rosebud", "lottery"
|
"wuzzle", "mug", "canonical", "rosebud", "lottery"
|
||||||
};
|
};
|
||||||
|
const int nkeys = ARRAY_SIZE(keys);
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
@@ -58,7 +59,7 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* allocate a hash table */
|
/* allocate a hash table */
|
||||||
table = hash_new(ctx, TABLESIZE, NULL);
|
table = hash_new(ctx, TABLESIZE, xmpp_free);
|
||||||
if (table == NULL) {
|
if (table == NULL) {
|
||||||
/* table allocation failed! */
|
/* table allocation failed! */
|
||||||
return 1;
|
return 1;
|
||||||
@@ -66,7 +67,7 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
/* test insertion */
|
/* test insertion */
|
||||||
for (i = 0; i < nkeys; i++) {
|
for (i = 0; i < nkeys; i++) {
|
||||||
err = hash_add(table, keys[i], (void*)values[i]);
|
err = hash_add(table, keys[i], xmpp_strdup(ctx, values[i]));
|
||||||
if (err) return err;
|
if (err) return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,7 +79,7 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
/* 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], (void*)values[i]);
|
err = hash_add(table, keys[0], xmpp_strdup(ctx, values[i]));
|
||||||
if (err) return err;
|
if (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]);
|
||||||
@@ -86,7 +87,7 @@ int main(int argc, char **argv)
|
|||||||
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], (void*)values[0]);
|
hash_add(table, keys[0], xmpp_strdup(ctx, values[0]));
|
||||||
|
|
||||||
/* test cloning */
|
/* test cloning */
|
||||||
clone = hash_clone(table);
|
clone = hash_clone(table);
|
||||||
|
|||||||
@@ -20,6 +20,16 @@
|
|||||||
|
|
||||||
#include "test.h" /* ARRAY_SIZE */
|
#include "test.h" /* ARRAY_SIZE */
|
||||||
|
|
||||||
|
/* strtok_s() has appeared in visual studio 2005.
|
||||||
|
Use own implementation for older versions. */
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
# if (_MSC_VER >= 1400)
|
||||||
|
# define strtok_r strtok_s
|
||||||
|
# else
|
||||||
|
# define strtok_r xmpp_strtok_r
|
||||||
|
# endif
|
||||||
|
#endif /* _MSC_VER */
|
||||||
|
|
||||||
static int test_strtok_r(void)
|
static int test_strtok_r(void)
|
||||||
{
|
{
|
||||||
const char *test = "-abc-=-def--";
|
const char *test = "-abc-=-def--";
|
||||||
|
|||||||
Reference in New Issue
Block a user