Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f13ea6e556 | ||
|
|
29f68c0dd7 | ||
|
|
3c0966d74e | ||
|
|
c90128779f | ||
|
|
acb8e0f629 | ||
|
|
f3460460e9 | ||
|
|
37555868f6 | ||
|
|
b0855f75f5 | ||
|
|
977ef75b14 | ||
|
|
d7d7435f21 | ||
|
|
d22558e0e3 | ||
|
|
96ece6fbdb | ||
|
|
a60d2ea19d | ||
|
|
70a908e18b | ||
|
|
004a5bf7fc | ||
|
|
e9bd06354a | ||
|
|
54b92c0255 | ||
|
|
6881a2e770 | ||
|
|
e29f422511 | ||
|
|
1a8be1d617 | ||
|
|
8ea15cf656 |
17
.github/workflows/main.yml
vendored
17
.github/workflows/main.yml
vendored
@@ -2,7 +2,9 @@ name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [master]
|
||||
branches:
|
||||
- master
|
||||
- next
|
||||
pull_request:
|
||||
branches: [master]
|
||||
|
||||
@@ -95,13 +97,18 @@ jobs:
|
||||
name: Check if release would work
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: install dependencies
|
||||
- name: install dependencies & bootstrap
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install -y libtool pkg-config libexpat1-dev
|
||||
- name: Setup the library
|
||||
run: |
|
||||
sudo apt install -y libtool pkg-config libexpat1-dev dash
|
||||
./bootstrap.sh
|
||||
- name: Check if configure works with non-bash shells
|
||||
# https://github.com/actions/runner/issues/241 requires us to use this following line...
|
||||
shell: 'script --return --quiet --command "bash {0}"'
|
||||
run: |
|
||||
[ "`CONFIG_SHELL=/bin/dash ./configure 2>&1 1>/dev/null | tee /dev/tty | wc -l`" = "0" ]
|
||||
- name: Re-run configure with the default shell
|
||||
run: |
|
||||
./configure
|
||||
- name: Try release & tests
|
||||
run: |
|
||||
|
||||
7
AUTHORS
7
AUTHORS
@@ -1 +1,8 @@
|
||||
Current maintainer:
|
||||
Steffen Jaeckel <gh@jaeckel.eu>
|
||||
|
||||
Previous maintainers:
|
||||
Dmitry Podgorny <pasis.ua@gmail.com>
|
||||
Jack Moffit <jack@metajack.im>
|
||||
|
||||
Other contributors can be extracted from the Git log.
|
||||
|
||||
17
ChangeLog
17
ChangeLog
@@ -1,3 +1,20 @@
|
||||
0.12.3
|
||||
- Improve TCP-connection establishment (#221)
|
||||
- Handle case where the server doesn't provide the `bind` feature (#224)
|
||||
- Fix configure script for non-bash shells (#218)
|
||||
- Parse JID's according to RFC7622 (#219)
|
||||
- Fix potential memory leak in internal DNS resolver (#219)
|
||||
- Fix potential memory leaks in `xmpp_conn_set_cafile()` and `xmpp_conn_set_capath()` (#219)
|
||||
- Internal improvements (#219)
|
||||
|
||||
0.12.2
|
||||
- Fix reconnect issues when Stream Management is enabled (#211)
|
||||
- Fix resolver ... this time for real hopefully (fixup of #200) (#214)
|
||||
- Fix clearing of password cache on resumed connection (#214)
|
||||
- Improve detection&implementation of `va_copy` (#213)
|
||||
- Fix Valgrind CI builds against LibreSSL (#212)
|
||||
- Fix perf example on platforms where an `rdtsc()` equivalent isn't implemented (#212)
|
||||
|
||||
0.12.1
|
||||
- Fix compilation in buildroot (#207)
|
||||
- Fixes regarding OpenSSL (#208)
|
||||
|
||||
41
configure.ac
41
configure.ac
@@ -1,6 +1,6 @@
|
||||
m4_define([v_maj], [0])
|
||||
m4_define([v_min], [12])
|
||||
m4_define([v_patch], [1])
|
||||
m4_define([v_patch], [3])
|
||||
m4_define([project_version], [v_maj.v_min.v_patch])
|
||||
|
||||
m4_define([lt_cur], m4_eval(v_maj + v_min))
|
||||
@@ -86,11 +86,44 @@ AX_VALGRIND_DFLT([helgrind], [off])
|
||||
AX_VALGRIND_DFLT([sgcheck], [off])
|
||||
AX_VALGRIND_CHECK
|
||||
|
||||
AC_SEARCH_LIBS([clock_gettime], [rt], AC_DEFINE(HAVE_CLOCK_GETTIME,1))
|
||||
AC_SEARCH_LIBS([socket], [network socket])
|
||||
AC_CHECK_FUNCS([snprintf vsnprintf], [], [have_snprintf=no])
|
||||
AC_CHECK_DECLS([va_copy], [], [], [#include <stdarg.h>])
|
||||
|
||||
if test "x$enable_tls" != xno -a "x$with_gnutls" == xyes; then
|
||||
dnl Checking for va_copy availability
|
||||
AC_MSG_CHECKING([for va_copy])
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <stdarg.h>
|
||||
va_list ap1,ap2;]], [[va_copy(ap1,ap2);]])],
|
||||
have_va_copy=yes,
|
||||
have_va_copy=no)
|
||||
AC_MSG_RESULT($have_va_copy)
|
||||
if test x"$have_va_copy" = x"yes"; then
|
||||
AC_DEFINE(HAVE_VA_COPY,1,[Whether va_copy() is available])
|
||||
else
|
||||
AC_MSG_CHECKING([for __va_copy])
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <stdarg.h>
|
||||
va_list ap1,ap2;]], [[__va_copy(ap1,ap2);]])],
|
||||
have___va_copy=yes,
|
||||
have___va_copy=no)
|
||||
AC_MSG_RESULT($have___va_copy)
|
||||
if test x"$have___va_copy" = x"yes"; then
|
||||
AC_DEFINE(HAVE___VA_COPY,1,[Whether __va_copy() is available])
|
||||
fi
|
||||
fi
|
||||
|
||||
if test x"$have_va_copy$have___va_copy" = x"nono"; then
|
||||
dnl Checking whether va_list is an array type
|
||||
AC_MSG_CHECKING([whether va_list is an array type])
|
||||
AC_TRY_COMPILE2([
|
||||
#include <stdarg.h>
|
||||
void a(va_list * ap) {}],[
|
||||
va_list ap1, ap2; a(&ap1); ap2 = (va_list) ap1],[
|
||||
AC_MSG_RESULT(no)],[
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE([VA_LIST_IS_ARRAY], [1],[Define if va_list is an array type])])
|
||||
fi
|
||||
|
||||
if test "x$enable_tls" != xno -a "x$with_gnutls" = xyes; then
|
||||
PKG_CHECK_MODULES([gnutls], [gnutls],
|
||||
[PC_REQUIRES="gnutls ${PC_REQUIRES}"],
|
||||
[AC_CHECK_HEADER([gnutls/gnutls.h],
|
||||
@@ -100,7 +133,7 @@ if test "x$enable_tls" != xno -a "x$with_gnutls" == xyes; then
|
||||
],
|
||||
[AC_MSG_ERROR([gnutls not found; gnutls required])]
|
||||
)])
|
||||
elif test "x$enable_tls" != xno -a "x$with_schannel" == xyes; then
|
||||
elif test "x$enable_tls" != xno -a "x$with_schannel" = xyes; then
|
||||
if test "x$PLATFORM" != xwin32; then
|
||||
AC_MSG_ERROR([schannel is only supported on Windows])
|
||||
fi
|
||||
|
||||
@@ -20,16 +20,20 @@
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <inttypes.h>
|
||||
#include <time.h>
|
||||
|
||||
static void init_timer(void);
|
||||
static void t_start(void);
|
||||
static uint64_t t_read(void);
|
||||
static const char *perf_time_unit;
|
||||
|
||||
#define NUM_SAMPLES 1000u
|
||||
|
||||
static void perf_rand(xmpp_ctx_t *ctx)
|
||||
{
|
||||
xmpp_rand_t *rng = xmpp_rand_new(ctx);
|
||||
|
||||
uint64_t t1, t2;
|
||||
uint64_t t1, t2, t3 = 0;
|
||||
unsigned int n;
|
||||
const size_t alloc_sz = 0x1000u;
|
||||
size_t sz;
|
||||
@@ -37,12 +41,12 @@ static void perf_rand(xmpp_ctx_t *ctx)
|
||||
|
||||
/* pre-heat */
|
||||
for (n = 1; n < 4; ++n) {
|
||||
xmpp_rand_bytes(rng, buf, n * 10);
|
||||
xmpp_rand_bytes(rng, buf, alloc_sz / n);
|
||||
}
|
||||
|
||||
for (sz = 2; sz <= alloc_sz; sz <<= 1) {
|
||||
t2 = 0;
|
||||
for (n = 0; n < 1000u; ++n) {
|
||||
for (n = 0; n < NUM_SAMPLES; ++n) {
|
||||
|
||||
t_start();
|
||||
t1 = t_read();
|
||||
@@ -52,10 +56,15 @@ static void perf_rand(xmpp_ctx_t *ctx)
|
||||
t1 = t_read() - t1;
|
||||
t2 += t1;
|
||||
}
|
||||
t2 /= 1000;
|
||||
fprintf(stderr,
|
||||
"Reading %6zu bytes from PRNG took %8" PRIu64 " cycles\n", sz,
|
||||
t2);
|
||||
t2 /= NUM_SAMPLES;
|
||||
fprintf(stderr, "Reading %6zu bytes from PRNG took %8" PRIu64 " %s\n",
|
||||
sz, t2, perf_time_unit);
|
||||
if (t3) {
|
||||
double d3 = (double)t3, d2 = (double)t2;
|
||||
fprintf(stderr, " +%.2f%%\n",
|
||||
(d2 - d3) / ((d2 + d3) * 0.5) * 100.);
|
||||
}
|
||||
t3 = t2;
|
||||
}
|
||||
free(buf);
|
||||
xmpp_rand_free(ctx, rng);
|
||||
@@ -90,7 +99,7 @@ static uint64_t rdtsc(void)
|
||||
unsigned hi, lo;
|
||||
__asm__ __volatile__("rdtsc" : "=a"(lo), "=d"(hi));
|
||||
return ((uint64_t)lo) | (((uint64_t)hi) << 32);
|
||||
#elif defined(LTC_PPC32) || defined(TFM_PPC32)
|
||||
#elif defined(__POWERPC__)
|
||||
unsigned long a, b;
|
||||
__asm__ __volatile__("mftbu %1 \nmftb %0\n" : "=r"(a), "=r"(b));
|
||||
return (((uint64_t)b) << 32ULL) | ((uint64_t)a);
|
||||
@@ -116,25 +125,41 @@ static uint64_t rdtsc(void)
|
||||
uint64_t CNTVCT_EL0;
|
||||
__asm__ __volatile__("mrs %0, cntvct_el0" : "=r"(CNTVCT_EL0));
|
||||
return CNTVCT_EL0;
|
||||
#elif defined HAVE_CLOCK_GETTIME
|
||||
#define USE_CLOCK_GETTIME
|
||||
struct timespec result;
|
||||
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &result);
|
||||
return result.tv_sec * 1000000000 + result.tv_nsec;
|
||||
#else
|
||||
return clock();
|
||||
#endif
|
||||
#endif /* __GNUC__ */
|
||||
|
||||
/* Microsoft and Intel Windows compilers */
|
||||
#elif defined _M_IX86 && !defined(LTC_NO_ASM)
|
||||
#elif defined _M_IX86
|
||||
__asm rdtsc
|
||||
#elif defined _M_AMD64 && !defined(LTC_NO_ASM)
|
||||
#elif defined _M_AMD64
|
||||
return __rdtsc();
|
||||
#elif defined _M_IA64 && !defined(LTC_NO_ASM)
|
||||
#elif defined _M_IA64
|
||||
#if defined __INTEL_COMPILER
|
||||
#include <ia64intrin.h>
|
||||
#endif
|
||||
return __getReg(3116);
|
||||
#elif defined HAVE_CLOCK_GETTIME
|
||||
#define USE_CLOCK_GETTIME
|
||||
struct timespec result;
|
||||
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &result);
|
||||
return result.tv_sec * 1000000000 + result.tv_nsec;
|
||||
#else
|
||||
return clock();
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined USE_CLOCK_GETTIME
|
||||
static const char *perf_time_unit = "ns";
|
||||
#else
|
||||
static const char *perf_time_unit = "cycles";
|
||||
#endif
|
||||
|
||||
static void t_start(void)
|
||||
{
|
||||
timer = rdtsc();
|
||||
|
||||
28
m4/ac_try_compile2.m4
Normal file
28
m4/ac_try_compile2.m4
Normal file
@@ -0,0 +1,28 @@
|
||||
dnl Like AC_TRY_EVAL but also errors out if the compiler generates
|
||||
dnl _any_ output. Some compilers might issue warnings which we want
|
||||
dnl to catch.
|
||||
AC_DEFUN([AC_TRY_EVAL2],
|
||||
[{ (eval echo configure:__oline__: \"[$]$1\") 1>&AS_MESSAGE_LOG_FD; dnl
|
||||
(eval [$]$1) 2>&AS_MESSAGE_LOG_FD; _out=`eval [$]$1 2>&1` && test "x$_out" = x; }])
|
||||
|
||||
dnl Like AC_TRY_COMPILE but calls AC_TRY_EVAL2 instead of AC_TRY_EVAL
|
||||
AC_DEFUN([AC_TRY_COMPILE2],
|
||||
[cat > conftest.$ac_ext <<EOF
|
||||
[#]line __oline__ "configure"
|
||||
#include "confdefs.h"
|
||||
[$1]
|
||||
int main(void) {
|
||||
[$2]
|
||||
; return 0; }
|
||||
EOF
|
||||
if AC_TRY_EVAL2(ac_compile); then
|
||||
ifelse([$3], , :, [rm -rf conftest*
|
||||
$3])
|
||||
else
|
||||
echo "configure: failed program was:" >&AS_MESSAGE_LOG_FD
|
||||
cat conftest.$ac_ext >&AS_MESSAGE_LOG_FD
|
||||
ifelse([$4], , , [ rm -rf conftest*
|
||||
$4
|
||||
])dnl
|
||||
fi
|
||||
rm -f conftest*])
|
||||
85
src/auth.c
85
src/auth.c
@@ -391,14 +391,12 @@ static int _handle_digestmd5_challenge(xmpp_conn_t *conn,
|
||||
xmpp_stanza_set_text(authdata, response);
|
||||
strophe_free(conn->ctx, response);
|
||||
|
||||
xmpp_stanza_add_child(auth, authdata);
|
||||
xmpp_stanza_release(authdata);
|
||||
xmpp_stanza_add_child_ex(auth, authdata, 0);
|
||||
|
||||
handler_add(conn, _handle_digestmd5_rspauth, XMPP_NS_SASL, NULL, NULL,
|
||||
NULL);
|
||||
|
||||
send_stanza(conn, auth, XMPP_QUEUE_STROPHE);
|
||||
xmpp_stanza_release(auth);
|
||||
|
||||
} else {
|
||||
return _handle_sasl_result(conn, stanza, "DIGEST-MD5");
|
||||
@@ -432,7 +430,6 @@ static int _handle_digestmd5_rspauth(xmpp_conn_t *conn,
|
||||
xmpp_stanza_set_name(auth, "response");
|
||||
xmpp_stanza_set_ns(auth, XMPP_NS_SASL);
|
||||
send_stanza(conn, auth, XMPP_QUEUE_STROPHE);
|
||||
xmpp_stanza_release(auth);
|
||||
} else {
|
||||
return _handle_sasl_result(conn, stanza, "DIGEST-MD5");
|
||||
}
|
||||
@@ -491,11 +488,9 @@ static int _handle_scram_challenge(xmpp_conn_t *conn,
|
||||
xmpp_stanza_set_text(authdata, response);
|
||||
strophe_free(conn->ctx, response);
|
||||
|
||||
xmpp_stanza_add_child(auth, authdata);
|
||||
xmpp_stanza_release(authdata);
|
||||
xmpp_stanza_add_child_ex(auth, authdata, 0);
|
||||
|
||||
send_stanza(conn, auth, XMPP_QUEUE_STROPHE);
|
||||
xmpp_stanza_release(auth);
|
||||
|
||||
rc = 1; /* Keep handler */
|
||||
} else {
|
||||
@@ -625,7 +620,6 @@ static void _auth(xmpp_conn_t *conn)
|
||||
NULL);
|
||||
|
||||
send_stanza(conn, auth, XMPP_QUEUE_STROPHE);
|
||||
xmpp_stanza_release(auth);
|
||||
|
||||
/* TLS was tried, unset flag */
|
||||
conn->tls_support = 0;
|
||||
@@ -653,7 +647,6 @@ static void _auth(xmpp_conn_t *conn)
|
||||
"ANONYMOUS");
|
||||
|
||||
send_stanza(conn, auth, XMPP_QUEUE_STROPHE);
|
||||
xmpp_stanza_release(auth);
|
||||
|
||||
/* SASL ANONYMOUS was tried, unset flag */
|
||||
conn->sasl_support &= ~SASL_MASK_ANONYMOUS;
|
||||
@@ -689,14 +682,12 @@ static void _auth(xmpp_conn_t *conn)
|
||||
}
|
||||
strophe_free(conn->ctx, str);
|
||||
|
||||
xmpp_stanza_add_child(auth, authdata);
|
||||
xmpp_stanza_release(authdata);
|
||||
xmpp_stanza_add_child_ex(auth, authdata, 0);
|
||||
|
||||
handler_add(conn, _handle_sasl_result, XMPP_NS_SASL, NULL, NULL,
|
||||
"EXTERNAL");
|
||||
|
||||
send_stanza(conn, auth, XMPP_QUEUE_STROPHE);
|
||||
xmpp_stanza_release(auth);
|
||||
|
||||
/* SASL EXTERNAL was tried, unset flag */
|
||||
conn->sasl_support &= ~SASL_MASK_EXTERNAL;
|
||||
@@ -754,14 +745,12 @@ static void _auth(xmpp_conn_t *conn)
|
||||
}
|
||||
xmpp_stanza_set_text(authdata, str);
|
||||
strophe_free(conn->ctx, str);
|
||||
xmpp_stanza_add_child(auth, authdata);
|
||||
xmpp_stanza_release(authdata);
|
||||
xmpp_stanza_add_child_ex(auth, authdata, 0);
|
||||
|
||||
handler_add(conn, _handle_scram_challenge, XMPP_NS_SASL, NULL, NULL,
|
||||
(void *)scram_ctx);
|
||||
|
||||
send_stanza(conn, auth, XMPP_QUEUE_STROPHE);
|
||||
xmpp_stanza_release(auth);
|
||||
|
||||
/* SASL SCRAM-SHA-1 was tried, unset flag */
|
||||
conn->sasl_support &= ~scram_ctx->alg->mask;
|
||||
@@ -776,7 +765,6 @@ static void _auth(xmpp_conn_t *conn)
|
||||
NULL);
|
||||
|
||||
send_stanza(conn, auth, XMPP_QUEUE_STROPHE);
|
||||
xmpp_stanza_release(auth);
|
||||
|
||||
/* SASL DIGEST-MD5 was tried, unset flag */
|
||||
conn->sasl_support &= ~SASL_MASK_DIGESTMD5;
|
||||
@@ -805,14 +793,12 @@ static void _auth(xmpp_conn_t *conn)
|
||||
strophe_free(conn->ctx, str);
|
||||
strophe_free(conn->ctx, authid);
|
||||
|
||||
xmpp_stanza_add_child(auth, authdata);
|
||||
xmpp_stanza_release(authdata);
|
||||
xmpp_stanza_add_child_ex(auth, authdata, 0);
|
||||
|
||||
handler_add(conn, _handle_sasl_result, XMPP_NS_SASL, NULL, NULL,
|
||||
"PLAIN");
|
||||
|
||||
send_stanza(conn, auth, XMPP_QUEUE_STROPHE);
|
||||
xmpp_stanza_release(auth);
|
||||
|
||||
/* SASL PLAIN was tried */
|
||||
conn->sasl_support &= ~SASL_MASK_PLAIN;
|
||||
@@ -923,19 +909,15 @@ static int _do_bind(xmpp_conn_t *conn, xmpp_stanza_t *bind)
|
||||
return 0;
|
||||
}
|
||||
xmpp_stanza_set_text(text, resource);
|
||||
xmpp_stanza_add_child(res, text);
|
||||
xmpp_stanza_release(text);
|
||||
xmpp_stanza_add_child(bind, res);
|
||||
xmpp_stanza_release(res);
|
||||
xmpp_stanza_add_child_ex(res, text, 0);
|
||||
xmpp_stanza_add_child_ex(bind, res, 0);
|
||||
strophe_free(conn->ctx, resource);
|
||||
}
|
||||
|
||||
xmpp_stanza_add_child(iq, bind);
|
||||
xmpp_stanza_release(bind);
|
||||
xmpp_stanza_add_child_ex(iq, bind, 0);
|
||||
|
||||
/* send bind request */
|
||||
send_stanza(conn, iq, XMPP_QUEUE_STROPHE);
|
||||
xmpp_stanza_release(iq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -957,6 +939,13 @@ _handle_features_sasl(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
|
||||
if (bind) {
|
||||
ns = xmpp_stanza_get_ns(bind);
|
||||
conn->bind_required = ns != NULL && strcmp(ns, XMPP_NS_BIND) == 0;
|
||||
bind = xmpp_stanza_copy(bind);
|
||||
if (!bind) {
|
||||
disconnect_mem_error(conn);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
conn->bind_required = 0;
|
||||
}
|
||||
|
||||
/* check whether session establishment is required */
|
||||
@@ -974,12 +963,6 @@ _handle_features_sasl(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
|
||||
conn->sm_state->sm_support = 1;
|
||||
}
|
||||
|
||||
bind = xmpp_stanza_copy(bind);
|
||||
if (!bind) {
|
||||
disconnect_mem_error(conn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* we are expecting either <bind/> and <session/> since this is a
|
||||
XMPP style connection or we <resume/> the previous session */
|
||||
|
||||
@@ -999,7 +982,6 @@ _handle_features_sasl(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
|
||||
strophe_snprintf(h, sizeof(h), "%u", conn->sm_state->sm_handled_nr);
|
||||
xmpp_stanza_set_attribute(resume, "h", h);
|
||||
send_stanza(conn, resume, XMPP_QUEUE_SM_STROPHE);
|
||||
xmpp_stanza_release(resume);
|
||||
handler_add(conn, _handle_sm, XMPP_NS_SM, NULL, NULL, NULL);
|
||||
}
|
||||
/* if bind is required, go ahead and start it */
|
||||
@@ -1008,7 +990,9 @@ _handle_features_sasl(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
|
||||
_do_bind(conn, bind);
|
||||
} else {
|
||||
/* can't bind, disconnect */
|
||||
xmpp_stanza_release(bind);
|
||||
if (bind) {
|
||||
xmpp_stanza_release(bind);
|
||||
}
|
||||
strophe_error(conn->ctx, "xmpp",
|
||||
"Stream features does not allow "
|
||||
"resource bind.");
|
||||
@@ -1080,12 +1064,10 @@ _handle_bind(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
|
||||
xmpp_stanza_set_name(session, "session");
|
||||
xmpp_stanza_set_ns(session, XMPP_NS_SESSION);
|
||||
|
||||
xmpp_stanza_add_child(iq, session);
|
||||
xmpp_stanza_release(session);
|
||||
xmpp_stanza_add_child_ex(iq, session, 0);
|
||||
|
||||
/* send session establishment request */
|
||||
send_stanza(conn, iq, XMPP_QUEUE_STROPHE);
|
||||
xmpp_stanza_release(iq);
|
||||
}
|
||||
|
||||
if (conn->sm_state->sm_support && !conn->sm_disable) {
|
||||
@@ -1100,7 +1082,6 @@ _handle_bind(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
|
||||
xmpp_stanza_set_attribute(enable, "resume", "true");
|
||||
handler_add(conn, _handle_sm, XMPP_NS_SM, NULL, NULL, NULL);
|
||||
send_stanza(conn, enable, XMPP_QUEUE_SM_STROPHE);
|
||||
xmpp_stanza_release(enable);
|
||||
}
|
||||
|
||||
if (!conn->session_required) {
|
||||
@@ -1239,10 +1220,8 @@ static int _handle_sm(xmpp_conn_t *const conn,
|
||||
}
|
||||
strophe_free(conn->ctx, queue_element_free(conn->ctx, e));
|
||||
}
|
||||
conn->authenticated = 1;
|
||||
|
||||
/* call connection handler */
|
||||
conn->conn_handler(conn, XMPP_CONN_CONNECT, 0, NULL, conn->userdata);
|
||||
strophe_debug(conn->ctx, "xmpp", "Session resumed successfully.");
|
||||
_auth_success(conn);
|
||||
} else if (strcmp(name, "failed") == 0) {
|
||||
name = NULL;
|
||||
|
||||
@@ -1361,15 +1340,13 @@ static void _auth_legacy(xmpp_conn_t *conn)
|
||||
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);
|
||||
xmpp_stanza_add_child_ex(iq, query, 0);
|
||||
|
||||
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);
|
||||
xmpp_stanza_add_child_ex(query, child, 0);
|
||||
|
||||
authdata = xmpp_stanza_new(conn->ctx);
|
||||
if (!authdata)
|
||||
@@ -1381,29 +1358,25 @@ static void _auth_legacy(xmpp_conn_t *conn)
|
||||
}
|
||||
xmpp_stanza_set_text(authdata, str);
|
||||
strophe_free(conn->ctx, str);
|
||||
xmpp_stanza_add_child(child, authdata);
|
||||
xmpp_stanza_release(authdata);
|
||||
xmpp_stanza_add_child_ex(child, authdata, 0);
|
||||
|
||||
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);
|
||||
xmpp_stanza_add_child_ex(query, child, 0);
|
||||
|
||||
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);
|
||||
xmpp_stanza_add_child_ex(child, authdata, 0);
|
||||
|
||||
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);
|
||||
xmpp_stanza_add_child_ex(query, child, 0);
|
||||
|
||||
authdata = xmpp_stanza_new(conn->ctx);
|
||||
if (!authdata)
|
||||
@@ -1420,14 +1393,12 @@ static void _auth_legacy(xmpp_conn_t *conn)
|
||||
xmpp_disconnect(conn);
|
||||
return;
|
||||
}
|
||||
xmpp_stanza_add_child(child, authdata);
|
||||
xmpp_stanza_release(authdata);
|
||||
xmpp_stanza_add_child_ex(child, authdata, 0);
|
||||
|
||||
handler_add_id(conn, _handle_legacy, "_xmpp_auth1", NULL);
|
||||
handler_add_timed(conn, _handle_missing_legacy, LEGACY_TIMEOUT, NULL);
|
||||
|
||||
send_stanza(conn, iq, XMPP_QUEUE_STROPHE);
|
||||
xmpp_stanza_release(iq);
|
||||
return;
|
||||
|
||||
err_free:
|
||||
|
||||
@@ -198,6 +198,7 @@ struct _xmpp_conn_t {
|
||||
int error;
|
||||
xmpp_stream_error_t *stream_error;
|
||||
|
||||
xmpp_sock_t *xsock;
|
||||
sock_t sock;
|
||||
int ka_timeout; /* TCP keepalive timeout */
|
||||
int ka_interval; /* TCP keepalive interval */
|
||||
|
||||
147
src/conn.c
147
src/conn.c
@@ -29,7 +29,6 @@
|
||||
#include "common.h"
|
||||
#include "util.h"
|
||||
#include "parser.h"
|
||||
#include "resolver.h"
|
||||
|
||||
#ifndef DEFAULT_SEND_QUEUE_MAX
|
||||
/** @def DEFAULT_SEND_QUEUE_MAX
|
||||
@@ -79,6 +78,7 @@
|
||||
#endif
|
||||
|
||||
static int _disconnect_cleanup(xmpp_conn_t *conn, void *userdata);
|
||||
static void _reset_sm_state_for_reconnect(xmpp_conn_t *conn);
|
||||
static char *_conn_build_stream_tag(xmpp_conn_t *conn,
|
||||
char **attributes,
|
||||
size_t attributes_len);
|
||||
@@ -102,8 +102,6 @@ static unsigned short _conn_default_port(xmpp_conn_t *conn,
|
||||
static void _conn_reset(xmpp_conn_t *conn);
|
||||
static int _conn_connect(xmpp_conn_t *conn,
|
||||
const char *domain,
|
||||
const char *host,
|
||||
unsigned short port,
|
||||
xmpp_conn_type_t type,
|
||||
xmpp_conn_handler callback,
|
||||
void *userdata);
|
||||
@@ -122,8 +120,6 @@ void xmpp_send_error(xmpp_conn_t *conn, xmpp_error_type_t type, char *text)
|
||||
xmpp_stanza_t *error = xmpp_error_new(conn->ctx, type, text);
|
||||
|
||||
send_stanza(conn, error, XMPP_QUEUE_STROPHE);
|
||||
|
||||
xmpp_stanza_release(error);
|
||||
}
|
||||
|
||||
/** Create a new Strophe connection object.
|
||||
@@ -149,7 +145,8 @@ xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t *ctx)
|
||||
conn->type = XMPP_UNKNOWN;
|
||||
conn->state = XMPP_STATE_DISCONNECTED;
|
||||
|
||||
conn->sock = -1;
|
||||
conn->xsock = NULL;
|
||||
conn->sock = INVALID_SOCKET;
|
||||
conn->ka_timeout = KEEPALIVE_TIMEOUT;
|
||||
conn->ka_interval = KEEPALIVE_INTERVAL;
|
||||
conn->ka_count = KEEPALIVE_COUNT;
|
||||
@@ -403,6 +400,7 @@ int xmpp_conn_release(xmpp_conn_t *conn)
|
||||
if (conn->sm_state)
|
||||
xmpp_free_sm_state(conn->sm_state);
|
||||
tls_clear_password_cache(conn);
|
||||
sock_free(conn->xsock);
|
||||
strophe_free(ctx, conn);
|
||||
released = 1;
|
||||
}
|
||||
@@ -482,6 +480,8 @@ void xmpp_conn_set_certfail_handler(xmpp_conn_t *const conn,
|
||||
*/
|
||||
void xmpp_conn_set_cafile(xmpp_conn_t *const conn, const char *path)
|
||||
{
|
||||
if (conn->tls_cafile)
|
||||
strophe_free(conn->ctx, conn->tls_cafile);
|
||||
conn->tls_cafile = strophe_strdup(conn->ctx, path);
|
||||
}
|
||||
|
||||
@@ -494,6 +494,8 @@ void xmpp_conn_set_cafile(xmpp_conn_t *const conn, const char *path)
|
||||
*/
|
||||
void xmpp_conn_set_capath(xmpp_conn_t *const conn, const char *path)
|
||||
{
|
||||
if (conn->tls_capath)
|
||||
strophe_free(conn->ctx, conn->tls_capath);
|
||||
conn->tls_capath = strophe_strdup(conn->ctx, path);
|
||||
}
|
||||
|
||||
@@ -702,12 +704,7 @@ int xmpp_connect_client(xmpp_conn_t *conn,
|
||||
xmpp_conn_handler callback,
|
||||
void *userdata)
|
||||
{
|
||||
resolver_srv_rr_t *srv_rr_list = NULL;
|
||||
resolver_srv_rr_t *rr;
|
||||
char *domain;
|
||||
const char *host = NULL;
|
||||
unsigned short port = 0;
|
||||
int found = XMPP_DOMAIN_NOT_FOUND;
|
||||
int rc;
|
||||
|
||||
if (!conn->jid && (conn->tls_client_cert || conn->tls_client_key)) {
|
||||
@@ -736,48 +733,35 @@ int xmpp_connect_client(xmpp_conn_t *conn,
|
||||
if (!conn->sm_state) {
|
||||
conn->sm_state = strophe_alloc(conn->ctx, sizeof(*conn->sm_state));
|
||||
if (!conn->sm_state)
|
||||
return XMPP_EMEM;
|
||||
goto err_mem;
|
||||
memset(conn->sm_state, 0, sizeof(*conn->sm_state));
|
||||
conn->sm_state->ctx = conn->ctx;
|
||||
}
|
||||
|
||||
if (altdomain != NULL) {
|
||||
strophe_debug(conn->ctx, "xmpp", "Connecting via altdomain.");
|
||||
host = altdomain;
|
||||
port = altport ? altport : _conn_default_port(conn, XMPP_CLIENT);
|
||||
found = XMPP_DOMAIN_ALTDOMAIN;
|
||||
if (altdomain != NULL)
|
||||
strophe_debug(conn->ctx, "conn", "Connecting via altdomain.");
|
||||
|
||||
if (conn->tls_legacy_ssl && !altdomain) {
|
||||
/* SSL tunneled connection on 5223 port is legacy and doesn't
|
||||
* have an SRV record. */
|
||||
} else if (!conn->tls_legacy_ssl) {
|
||||
found = resolver_srv_lookup(conn->ctx, "xmpp-client", "tcp", domain,
|
||||
&srv_rr_list);
|
||||
altdomain = domain;
|
||||
}
|
||||
altport = altport ? altport : _conn_default_port(conn, XMPP_CLIENT);
|
||||
|
||||
if (XMPP_DOMAIN_NOT_FOUND == found) {
|
||||
strophe_debug(conn->ctx, "xmpp",
|
||||
"SRV lookup failed, "
|
||||
"connecting via domain.");
|
||||
host = domain;
|
||||
port = altport ? altport : _conn_default_port(conn, XMPP_CLIENT);
|
||||
found = XMPP_DOMAIN_ALTDOMAIN;
|
||||
}
|
||||
|
||||
rr = srv_rr_list;
|
||||
do {
|
||||
if (XMPP_DOMAIN_FOUND == found && rr != NULL) {
|
||||
host = rr->target;
|
||||
port = rr->port;
|
||||
rr = rr->next;
|
||||
}
|
||||
rc = _conn_connect(conn, domain, host, port, XMPP_CLIENT, callback,
|
||||
userdata);
|
||||
} while (rc != 0 && rr != NULL);
|
||||
if (conn->xsock)
|
||||
sock_free(conn->xsock);
|
||||
conn->xsock = sock_new(conn, domain, altdomain, altport);
|
||||
if (!conn->xsock)
|
||||
goto err_mem;
|
||||
|
||||
rc = _conn_connect(conn, domain, XMPP_CLIENT, callback, userdata);
|
||||
strophe_free(conn->ctx, domain);
|
||||
resolver_srv_free(conn->ctx, srv_rr_list);
|
||||
|
||||
return rc;
|
||||
|
||||
err_mem:
|
||||
strophe_free(conn->ctx, domain);
|
||||
return XMPP_EMEM;
|
||||
}
|
||||
|
||||
/** Initiate a component connection to server.
|
||||
@@ -823,10 +807,15 @@ int xmpp_connect_component(xmpp_conn_t *conn,
|
||||
}
|
||||
|
||||
port = port ? port : _conn_default_port(conn, XMPP_COMPONENT);
|
||||
if (conn->xsock)
|
||||
sock_free(conn->xsock);
|
||||
conn->xsock = sock_new(conn, NULL, server, port);
|
||||
if (!conn->xsock)
|
||||
return XMPP_EMEM;
|
||||
|
||||
/* JID serves as an identifier here and will be used as "to" attribute
|
||||
of the stream */
|
||||
return _conn_connect(conn, conn->jid, server, port, XMPP_COMPONENT,
|
||||
callback, userdata);
|
||||
return _conn_connect(conn, conn->jid, XMPP_COMPONENT, callback, userdata);
|
||||
}
|
||||
|
||||
/** Initiate a raw connection to the XMPP server.
|
||||
@@ -974,7 +963,9 @@ void conn_disconnect(xmpp_conn_t *conn)
|
||||
tls_free(conn->tls);
|
||||
conn->tls = NULL;
|
||||
}
|
||||
sock_close(conn->sock);
|
||||
if (conn->sock != INVALID_SOCKET)
|
||||
sock_close(conn->sock);
|
||||
_reset_sm_state_for_reconnect(conn);
|
||||
|
||||
/* fire off connection handler */
|
||||
conn->conn_handler(conn, XMPP_CONN_DISCONNECT, conn->error,
|
||||
@@ -1071,7 +1062,7 @@ void xmpp_send_raw(xmpp_conn_t *conn, const char *data, size_t len)
|
||||
*/
|
||||
void xmpp_send(xmpp_conn_t *conn, xmpp_stanza_t *stanza)
|
||||
{
|
||||
send_stanza(conn, stanza, XMPP_QUEUE_USER);
|
||||
send_stanza(conn, xmpp_stanza_clone(stanza), XMPP_QUEUE_USER);
|
||||
}
|
||||
|
||||
/** Send the opening <stream:stream> tag to the server.
|
||||
@@ -1298,32 +1289,38 @@ xmpp_sm_state_t *xmpp_conn_get_sm_state(xmpp_conn_t *conn)
|
||||
|
||||
ret = conn->sm_state;
|
||||
conn->sm_state = NULL;
|
||||
if (ret->previd) {
|
||||
strophe_free(conn->ctx, ret->previd);
|
||||
ret->previd = NULL;
|
||||
}
|
||||
|
||||
if (ret->can_resume) {
|
||||
ret->previd = ret->id;
|
||||
ret->id = NULL;
|
||||
|
||||
ret->bound_jid = conn->bound_jid;
|
||||
conn->bound_jid = NULL;
|
||||
} else if (ret->id) {
|
||||
strophe_free(conn->ctx, ret->id);
|
||||
ret->id = NULL;
|
||||
}
|
||||
|
||||
ret->sm_enabled = ret->sm_support = ret->resume = 0;
|
||||
|
||||
if (ret->bind) {
|
||||
xmpp_stanza_release(ret->bind);
|
||||
ret->bind = NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void _reset_sm_state_for_reconnect(xmpp_conn_t *conn)
|
||||
{
|
||||
xmpp_sm_state_t *s = conn->sm_state;
|
||||
|
||||
if (s->previd) {
|
||||
strophe_free(conn->ctx, s->previd);
|
||||
s->previd = NULL;
|
||||
}
|
||||
|
||||
if (s->can_resume) {
|
||||
s->previd = s->id;
|
||||
s->id = NULL;
|
||||
|
||||
s->bound_jid = conn->bound_jid;
|
||||
conn->bound_jid = NULL;
|
||||
} else if (s->id) {
|
||||
strophe_free(conn->ctx, s->id);
|
||||
s->id = NULL;
|
||||
}
|
||||
|
||||
s->sm_enabled = s->sm_support = s->resume = 0;
|
||||
|
||||
if (s->bind) {
|
||||
xmpp_stanza_release(s->bind);
|
||||
s->bind = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param conn a Strophe connection object
|
||||
* @param sm_state A Stream Management state returned from a call to
|
||||
@@ -1730,7 +1727,6 @@ static void _conn_sm_handle_stanza(xmpp_conn_t *const conn,
|
||||
strophe_snprintf(h, sizeof(h), "%u", conn->sm_state->sm_handled_nr);
|
||||
xmpp_stanza_set_attribute(a, "h", h);
|
||||
send_stanza(conn, a, XMPP_QUEUE_SM_STROPHE);
|
||||
xmpp_stanza_release(a);
|
||||
} else if (strcmp(name, "a") == 0) {
|
||||
attr_h = xmpp_stanza_get_attribute(stanza, "h");
|
||||
if (!attr_h) {
|
||||
@@ -1836,8 +1832,6 @@ static void _conn_reset(xmpp_conn_t *conn)
|
||||
|
||||
static int _conn_connect(xmpp_conn_t *conn,
|
||||
const char *domain,
|
||||
const char *host,
|
||||
unsigned short port,
|
||||
xmpp_conn_type_t type,
|
||||
xmpp_conn_handler callback,
|
||||
void *userdata)
|
||||
@@ -1848,8 +1842,6 @@ static int _conn_connect(xmpp_conn_t *conn,
|
||||
return XMPP_EINVOP;
|
||||
if (type != XMPP_CLIENT && type != XMPP_COMPONENT)
|
||||
return XMPP_EINVOP;
|
||||
if (host == NULL || port == 0)
|
||||
return XMPP_EINT;
|
||||
|
||||
_conn_reset(conn);
|
||||
|
||||
@@ -1858,10 +1850,8 @@ static int _conn_connect(xmpp_conn_t *conn,
|
||||
if (!conn->domain)
|
||||
return XMPP_EMEM;
|
||||
|
||||
conn->sock = sock_connect(conn, host, port);
|
||||
strophe_debug(conn->ctx, "xmpp", "sock_connect() to %s:%u returned %d",
|
||||
host, port, conn->sock);
|
||||
if (conn->sock == -1)
|
||||
conn->sock = sock_connect(conn->xsock);
|
||||
if (conn->sock == INVALID_SOCKET)
|
||||
return XMPP_EINT;
|
||||
|
||||
/* setup handler */
|
||||
@@ -1880,7 +1870,6 @@ static int _conn_connect(xmpp_conn_t *conn,
|
||||
|
||||
conn->state = XMPP_STATE_CONNECTING;
|
||||
conn->timeout_stamp = time_stamp();
|
||||
strophe_debug(conn->ctx, "xmpp", "Attempting to connect to %s", host);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1964,14 +1953,16 @@ void send_stanza(xmpp_conn_t *conn,
|
||||
size_t len;
|
||||
|
||||
if (conn->state != XMPP_STATE_CONNECTED)
|
||||
return;
|
||||
goto out;
|
||||
|
||||
if (xmpp_stanza_to_text(stanza, &buf, &len) != 0) {
|
||||
strophe_error(conn->ctx, "conn", "Failed to stanza_to_text");
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
|
||||
_send_raw(conn, buf, len, owner, NULL);
|
||||
out:
|
||||
xmpp_stanza_release(stanza);
|
||||
}
|
||||
|
||||
void add_queue_back(xmpp_queue_t *queue, xmpp_send_queue_t *item)
|
||||
|
||||
20
src/ctx.c
20
src/ctx.c
@@ -50,10 +50,22 @@
|
||||
#include "resolver.h"
|
||||
#include "util.h"
|
||||
|
||||
/* Workaround for systems without va_copy support. */
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1800 || \
|
||||
!defined(_MSC_VER) && !defined(HAVE_DECL_VA_COPY)
|
||||
#define va_copy(d, s) (memcpy(&d, &s, sizeof(va_list)))
|
||||
#ifndef va_copy
|
||||
#ifdef HAVE_VA_COPY
|
||||
#define va_copy(dest, src) va_copy(dest, src)
|
||||
#else
|
||||
#ifdef HAVE___VA_COPY
|
||||
#define va_copy(dest, src) __va_copy(dest, src)
|
||||
#else
|
||||
#ifndef VA_LIST_IS_ARRAY
|
||||
#define va_copy(dest, src) (dest) = (src)
|
||||
#else
|
||||
#include <string.h>
|
||||
#define va_copy(dest, src) \
|
||||
memcpy((char *)(dest), (char *)(src), sizeof(va_list))
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/** Initialize the Strophe library.
|
||||
|
||||
27
src/event.c
27
src/event.c
@@ -60,6 +60,18 @@
|
||||
/** Max buffer size for receiving messages. */
|
||||
#define STROPE_MESSAGE_BUFFER_SIZE 4096
|
||||
|
||||
static int _connect_next(xmpp_conn_t *conn)
|
||||
{
|
||||
sock_close(conn->sock);
|
||||
conn->sock = sock_connect(conn->xsock);
|
||||
if (conn->sock == INVALID_SOCKET)
|
||||
return -1;
|
||||
|
||||
conn->timeout_stamp = time_stamp();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Run the event loop once.
|
||||
* This function will run send any data that has been queued by
|
||||
* xmpp_send and related functions and run through the Strophe even
|
||||
@@ -209,9 +221,14 @@ next_item:
|
||||
conn->connect_timeout)
|
||||
FD_SET(conn->sock, &wfds);
|
||||
else {
|
||||
conn->error = ETIMEDOUT;
|
||||
strophe_info(ctx, "xmpp", "Connection attempt timed out.");
|
||||
conn_disconnect(conn);
|
||||
ret = _connect_next(conn);
|
||||
if (ret != 0) {
|
||||
conn->error = ETIMEDOUT;
|
||||
conn_disconnect(conn);
|
||||
} else {
|
||||
FD_SET(conn->sock, &wfds);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case XMPP_STATE_CONNECTED:
|
||||
@@ -272,7 +289,11 @@ next_item:
|
||||
/* connection failed */
|
||||
strophe_debug(ctx, "xmpp", "connection failed, error %d",
|
||||
ret);
|
||||
conn_disconnect(conn);
|
||||
ret = _connect_next(conn);
|
||||
if (ret != 0) {
|
||||
conn->error = ret;
|
||||
conn_disconnect(conn);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
79
src/jid.c
79
src/jid.c
@@ -37,8 +37,10 @@ char *xmpp_jid_new(xmpp_ctx_t *ctx,
|
||||
size_t len, nlen, dlen, rlen;
|
||||
|
||||
/* jid must at least have a domain */
|
||||
if (domain == NULL)
|
||||
if (domain == NULL) {
|
||||
strophe_error(ctx, "jid", "domainpart missing.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* accumulate lengths */
|
||||
dlen = strlen(domain);
|
||||
@@ -46,6 +48,26 @@ char *xmpp_jid_new(xmpp_ctx_t *ctx,
|
||||
rlen = (resource) ? strlen(resource) + 1 : 0;
|
||||
len = nlen + dlen + rlen;
|
||||
|
||||
if (dlen > 1023) {
|
||||
strophe_error(ctx, "jid", "domainpart too long.");
|
||||
return NULL;
|
||||
}
|
||||
if (nlen > 1024) {
|
||||
strophe_error(ctx, "jid", "localpart too long.");
|
||||
return NULL;
|
||||
}
|
||||
if (rlen > 1024) {
|
||||
strophe_error(ctx, "jid", "resourcepart too long.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (node) {
|
||||
if (strcspn(node, "\"&'/:<>@") != nlen - 1) {
|
||||
strophe_error(ctx, "jid", "localpart contained invalid character.");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* concat components */
|
||||
result = strophe_alloc(ctx, len + 1);
|
||||
if (result != NULL) {
|
||||
@@ -96,17 +118,29 @@ char *xmpp_jid_bare(xmpp_ctx_t *ctx, const char *jid)
|
||||
*/
|
||||
char *xmpp_jid_node(xmpp_ctx_t *ctx, const char *jid)
|
||||
{
|
||||
char *dup_jid = strophe_strdup(ctx, jid);
|
||||
char *result = NULL;
|
||||
const char *c;
|
||||
|
||||
c = strchr(jid, '@');
|
||||
/* Apply the same parsing rules from rfc7622 Section 3.2
|
||||
* 1. Strip resource
|
||||
* 2. take part before the '@'
|
||||
*/
|
||||
|
||||
char *resource = strchr(dup_jid, '/');
|
||||
if (resource != NULL) {
|
||||
*resource = '\0';
|
||||
}
|
||||
|
||||
c = strchr(dup_jid, '@');
|
||||
if (c != NULL) {
|
||||
result = strophe_alloc(ctx, (c - jid) + 1);
|
||||
result = strophe_alloc(ctx, (c - dup_jid) + 1);
|
||||
if (result != NULL) {
|
||||
memcpy(result, jid, (c - jid));
|
||||
result[c - jid] = '\0';
|
||||
memcpy(result, dup_jid, (c - dup_jid));
|
||||
result[c - dup_jid] = '\0';
|
||||
}
|
||||
}
|
||||
strophe_free(ctx, dup_jid);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -120,24 +154,29 @@ char *xmpp_jid_node(xmpp_ctx_t *ctx, const char *jid)
|
||||
*/
|
||||
char *xmpp_jid_domain(xmpp_ctx_t *ctx, const char *jid)
|
||||
{
|
||||
char *result = NULL;
|
||||
const char *c;
|
||||
size_t dlen;
|
||||
char *dup_jid = strophe_strdup(ctx, jid);
|
||||
|
||||
c = strchr(jid, '@');
|
||||
if (c == NULL) {
|
||||
/* no node, assume domain */
|
||||
c = jid;
|
||||
/* rfc7622 Section 3.2
|
||||
* 1. Remove any portion from the first '/' character to the end of the
|
||||
* string (if there is a '/' character present).
|
||||
*/
|
||||
|
||||
char *resource = strchr(dup_jid, '/');
|
||||
if (resource != NULL) {
|
||||
*resource = '\0';
|
||||
}
|
||||
|
||||
/* 2. Remove any portion from the beginning of the string to the first
|
||||
* '@' character (if there is an '@' character present).
|
||||
*/
|
||||
char *at_sign = strchr(dup_jid, '@');
|
||||
char *result = NULL;
|
||||
if (at_sign != NULL) {
|
||||
result = strophe_strdup(ctx, (at_sign + 1));
|
||||
} else {
|
||||
/* advance past the separator */
|
||||
c++;
|
||||
}
|
||||
dlen = strcspn(c, "/"); /* do not include resource */
|
||||
result = strophe_alloc(ctx, dlen + 1);
|
||||
if (result != NULL) {
|
||||
memcpy(result, c, dlen);
|
||||
result[dlen] = '\0';
|
||||
result = strophe_strdup(ctx, dup_jid);
|
||||
}
|
||||
strophe_free(ctx, dup_jid);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -152,8 +152,7 @@ static void complete_inner_text(parser_t *parser)
|
||||
/* FIXME: disconnect on allocation error */
|
||||
if (stanza) {
|
||||
xmpp_stanza_set_text(stanza, parser->inner_text);
|
||||
xmpp_stanza_add_child(parser->stanza, stanza);
|
||||
xmpp_stanza_release(stanza);
|
||||
xmpp_stanza_add_child_ex(parser->stanza, stanza, 0);
|
||||
}
|
||||
strophe_free(parser->ctx, parser->inner_text);
|
||||
parser->inner_text = NULL;
|
||||
@@ -195,8 +194,7 @@ _start_element(void *userdata, const XML_Char *nsname, const XML_Char **attrs)
|
||||
|
||||
if (parser->stanza != NULL) {
|
||||
complete_inner_text(parser);
|
||||
xmpp_stanza_add_child(parser->stanza, child);
|
||||
xmpp_stanza_release(child);
|
||||
xmpp_stanza_add_child_ex(parser->stanza, child, 0);
|
||||
}
|
||||
parser->stanza = child;
|
||||
}
|
||||
|
||||
@@ -164,10 +164,7 @@ static void _start_element(void *userdata,
|
||||
xmpp_stanza_set_ns(child, (char *)uri);
|
||||
|
||||
/* add child to parent */
|
||||
xmpp_stanza_add_child(parser->stanza, child);
|
||||
|
||||
/* the child is owned by the toplevel stanza now */
|
||||
xmpp_stanza_release(child);
|
||||
xmpp_stanza_add_child_ex(parser->stanza, child, 0);
|
||||
|
||||
/* make child the current stanza */
|
||||
parser->stanza = child;
|
||||
@@ -223,8 +220,7 @@ static void _characters(void *userdata, const xmlChar *chr, int len)
|
||||
}
|
||||
xmpp_stanza_set_text_with_size(stanza, (char *)chr, len);
|
||||
|
||||
xmpp_stanza_add_child(parser->stanza, stanza);
|
||||
xmpp_stanza_release(stanza);
|
||||
xmpp_stanza_add_child_ex(parser->stanza, stanza, 0);
|
||||
}
|
||||
|
||||
/* create a new parser */
|
||||
|
||||
@@ -91,6 +91,25 @@ void resolver_shutdown(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
resolver_srv_rr_t *resolver_srv_rr_new(xmpp_ctx_t *ctx,
|
||||
const char *host,
|
||||
unsigned short port,
|
||||
unsigned short prio,
|
||||
unsigned short weight)
|
||||
{
|
||||
resolver_srv_rr_t *rr = strophe_alloc(ctx, sizeof(*rr));
|
||||
if (rr) {
|
||||
memset(rr, 0, sizeof(*rr));
|
||||
rr->port = port;
|
||||
rr->priority = prio;
|
||||
rr->weight = weight;
|
||||
if (host) {
|
||||
snprintf(rr->target, sizeof(rr->target), "%s", host);
|
||||
}
|
||||
}
|
||||
return rr;
|
||||
}
|
||||
|
||||
static void resolver_srv_list_sort(resolver_srv_rr_t **srv_rr_list)
|
||||
{
|
||||
resolver_srv_rr_t *rr_head;
|
||||
@@ -158,6 +177,10 @@ int resolver_srv_lookup_buf(xmpp_ctx_t *ctx,
|
||||
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);
|
||||
if (set != XMPP_DOMAIN_FOUND && *srv_rr_list != NULL) {
|
||||
resolver_srv_free(ctx, *srv_rr_list);
|
||||
*srv_rr_list = NULL;
|
||||
}
|
||||
#endif
|
||||
resolver_srv_list_sort(srv_rr_list);
|
||||
|
||||
@@ -322,7 +345,7 @@ static unsigned message_name_get(const unsigned char *buf,
|
||||
return 0;
|
||||
pointer = (label_len & 0x3f) << 8 | buf[i++];
|
||||
/* Prevent infinite looping */
|
||||
if (pointer == buf_offset)
|
||||
if (pointer >= buf_offset)
|
||||
return 0;
|
||||
if (name != NULL && name_len >= name_max && name_max > 0) {
|
||||
/* We have filled the name buffer. Don't pass it recursively. */
|
||||
@@ -434,17 +457,19 @@ static int resolver_raw_srv_lookup_buf(xmpp_ctx_t *ctx,
|
||||
rdlength = xmpp_ntohs_ptr(&buf[j + 8]);
|
||||
j += 10;
|
||||
if (type == MESSAGE_T_SRV && class == MESSAGE_C_IN) {
|
||||
rr = strophe_alloc(ctx, sizeof(*rr));
|
||||
rr->next = *srv_rr_list;
|
||||
rr->priority = xmpp_ntohs_ptr(&buf[j]);
|
||||
rr->weight = xmpp_ntohs_ptr(&buf[j + 2]);
|
||||
rr->port = xmpp_ntohs_ptr(&buf[j + 4]);
|
||||
name_len = message_name_get(buf, len, j + 6, rr->target,
|
||||
sizeof(rr->target));
|
||||
if (name_len > 0)
|
||||
*srv_rr_list = rr;
|
||||
else
|
||||
strophe_free(ctx, rr); /* skip broken record */
|
||||
rr = resolver_srv_rr_new(ctx, NULL, 0, 0, 0);
|
||||
if (rr) {
|
||||
rr->next = *srv_rr_list;
|
||||
rr->priority = xmpp_ntohs_ptr(&buf[j]);
|
||||
rr->weight = xmpp_ntohs_ptr(&buf[j + 2]);
|
||||
rr->port = xmpp_ntohs_ptr(&buf[j + 4]);
|
||||
name_len = message_name_get(buf, len, j + 6, rr->target,
|
||||
sizeof(rr->target));
|
||||
if (name_len > 0)
|
||||
*srv_rr_list = rr;
|
||||
else
|
||||
strophe_free(ctx, rr); /* skip broken record */
|
||||
}
|
||||
}
|
||||
j += rdlength;
|
||||
}
|
||||
|
||||
@@ -36,6 +36,12 @@ typedef struct resolver_srv_rr_struc {
|
||||
void resolver_initialize(void);
|
||||
void resolver_shutdown(void);
|
||||
|
||||
resolver_srv_rr_t *resolver_srv_rr_new(xmpp_ctx_t *ctx,
|
||||
const char *host,
|
||||
unsigned short port,
|
||||
unsigned short prio,
|
||||
unsigned short weight);
|
||||
|
||||
/** Perform lookup for RFC1035 message format.
|
||||
* This function allocates all elements.
|
||||
*
|
||||
|
||||
207
src/sock.c
207
src/sock.c
@@ -24,6 +24,7 @@
|
||||
#include <iphlpapi.h>
|
||||
#include <mstcpip.h> /* tcp_keepalive */
|
||||
#else
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
@@ -34,6 +35,18 @@
|
||||
#endif
|
||||
|
||||
#include "common.h"
|
||||
#include "resolver.h"
|
||||
|
||||
struct _xmpp_sock_t {
|
||||
xmpp_ctx_t *ctx;
|
||||
xmpp_conn_t *conn;
|
||||
struct addrinfo *ainfo_list;
|
||||
struct addrinfo *ainfo_cur;
|
||||
resolver_srv_rr_t *srv_rr_list;
|
||||
resolver_srv_rr_t *srv_rr_cur;
|
||||
const char *host;
|
||||
unsigned short port;
|
||||
};
|
||||
|
||||
void sock_initialize(void)
|
||||
{
|
||||
@@ -68,50 +81,164 @@ static int _in_progress(int error)
|
||||
#endif
|
||||
}
|
||||
|
||||
sock_t sock_connect(xmpp_conn_t *conn, const char *host, unsigned short port)
|
||||
static void sock_getaddrinfo(xmpp_sock_t *xsock)
|
||||
{
|
||||
sock_t sock;
|
||||
char service[6];
|
||||
struct addrinfo *res, *ainfo, hints;
|
||||
int err;
|
||||
struct addrinfo hints;
|
||||
int rc;
|
||||
|
||||
strophe_snprintf(service, 6, "%u", port);
|
||||
|
||||
memset(&hints, 0, sizeof(struct addrinfo));
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
#ifdef AI_ADDRCONFIG
|
||||
hints.ai_flags = AI_ADDRCONFIG;
|
||||
#endif /* AI_ADDRCONFIG */
|
||||
hints.ai_protocol = IPPROTO_TCP;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
|
||||
err = getaddrinfo(host, service, &hints, &res);
|
||||
if (err != 0)
|
||||
return -1;
|
||||
|
||||
for (ainfo = res; ainfo != NULL; ainfo = ainfo->ai_next) {
|
||||
sock = socket(ainfo->ai_family, ainfo->ai_socktype, ainfo->ai_protocol);
|
||||
if (sock < 0)
|
||||
continue;
|
||||
|
||||
if (conn->sockopt_cb != NULL)
|
||||
err = (conn->sockopt_cb)(conn, &sock);
|
||||
|
||||
if (err != 0) {
|
||||
sock_close(sock);
|
||||
continue;
|
||||
}
|
||||
|
||||
err = sock_set_nonblocking(sock);
|
||||
if (err == 0) {
|
||||
err = connect(sock, ainfo->ai_addr, ainfo->ai_addrlen);
|
||||
if (err == 0 || _in_progress(sock_error()))
|
||||
break;
|
||||
}
|
||||
sock_close(sock);
|
||||
if (xsock->ainfo_list) {
|
||||
freeaddrinfo(xsock->ainfo_list);
|
||||
xsock->ainfo_list = NULL;
|
||||
}
|
||||
freeaddrinfo(res);
|
||||
sock = ainfo == NULL ? -1 : sock;
|
||||
|
||||
if (xsock->srv_rr_cur) {
|
||||
/* Cache host and port for debug logs. */
|
||||
xsock->host = xsock->srv_rr_cur->target;
|
||||
xsock->port = xsock->srv_rr_cur->port;
|
||||
|
||||
strophe_snprintf(service, 6, "%u", xsock->srv_rr_cur->port);
|
||||
memset(&hints, 0, sizeof(struct addrinfo));
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
#ifdef AI_ADDRCONFIG
|
||||
hints.ai_flags = AI_ADDRCONFIG;
|
||||
#endif /* AI_ADDRCONFIG */
|
||||
hints.ai_protocol = IPPROTO_TCP;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
|
||||
rc = getaddrinfo(xsock->srv_rr_cur->target, service, &hints,
|
||||
&xsock->ainfo_list);
|
||||
if (rc != 0) {
|
||||
strophe_debug(xsock->ctx, "sock", "getaddrinfo() failed with %d",
|
||||
rc);
|
||||
xsock->ainfo_list = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
xsock->ainfo_cur = xsock->ainfo_list;
|
||||
}
|
||||
|
||||
xmpp_sock_t *sock_new(xmpp_conn_t *conn,
|
||||
const char *domain,
|
||||
const char *host,
|
||||
unsigned short port)
|
||||
{
|
||||
xmpp_ctx_t *ctx = conn->ctx;
|
||||
xmpp_sock_t *xsock;
|
||||
int found = XMPP_DOMAIN_NOT_FOUND;
|
||||
|
||||
xsock = strophe_alloc(ctx, sizeof(*xsock));
|
||||
if (!xsock) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
xsock->ctx = ctx;
|
||||
xsock->conn = conn;
|
||||
xsock->host = NULL;
|
||||
xsock->port = 0;
|
||||
|
||||
if (!host) {
|
||||
found = resolver_srv_lookup(ctx, "xmpp-client", "tcp", domain,
|
||||
&xsock->srv_rr_list);
|
||||
if (XMPP_DOMAIN_NOT_FOUND == found)
|
||||
strophe_debug(ctx, "sock",
|
||||
"SRV lookup failed, connecting via domain.");
|
||||
}
|
||||
if (XMPP_DOMAIN_NOT_FOUND == found) {
|
||||
/* Resolution failed or the host is provided explicitly. */
|
||||
xsock->srv_rr_list =
|
||||
resolver_srv_rr_new(ctx, host ? host : domain, port, 0, 0);
|
||||
}
|
||||
xsock->srv_rr_cur = xsock->srv_rr_list;
|
||||
|
||||
xsock->ainfo_list = NULL;
|
||||
sock_getaddrinfo(xsock);
|
||||
if (xsock->srv_rr_cur)
|
||||
xsock->srv_rr_cur = xsock->srv_rr_cur->next;
|
||||
|
||||
return xsock;
|
||||
}
|
||||
|
||||
void sock_free(xmpp_sock_t *xsock)
|
||||
{
|
||||
if (!xsock)
|
||||
return;
|
||||
|
||||
if (xsock->ainfo_list)
|
||||
freeaddrinfo(xsock->ainfo_list);
|
||||
if (xsock->srv_rr_list)
|
||||
resolver_srv_free(xsock->ctx, xsock->srv_rr_list);
|
||||
strophe_free(xsock->ctx, xsock);
|
||||
}
|
||||
|
||||
static const char *_sockaddr2str(struct sockaddr *sa, char *buf, size_t buflen)
|
||||
{
|
||||
buf[0] = '\0';
|
||||
|
||||
switch (sa->sa_family) {
|
||||
case AF_INET:
|
||||
inet_ntop(AF_INET, &((struct sockaddr_in *)sa)->sin_addr, buf, buflen);
|
||||
break;
|
||||
case AF_INET6:
|
||||
inet_ntop(AF_INET6, &((struct sockaddr_in6 *)sa)->sin6_addr, buf,
|
||||
buflen);
|
||||
break;
|
||||
default:
|
||||
strophe_snprintf(buf, buflen, "<Unknown>");
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
sock_t sock_connect(xmpp_sock_t *xsock)
|
||||
{
|
||||
struct addrinfo *ainfo;
|
||||
sock_t sock;
|
||||
int rc = 0;
|
||||
char buf[64];
|
||||
|
||||
do {
|
||||
if (!xsock->ainfo_cur) {
|
||||
sock_getaddrinfo(xsock);
|
||||
if (xsock->srv_rr_cur)
|
||||
xsock->srv_rr_cur = xsock->srv_rr_cur->next;
|
||||
}
|
||||
if (!xsock->ainfo_cur) {
|
||||
/* We tried all available addresses. */
|
||||
return INVALID_SOCKET;
|
||||
}
|
||||
|
||||
ainfo = xsock->ainfo_cur;
|
||||
strophe_debug(xsock->ctx, "sock", "Connecting to %s:%u via %s",
|
||||
xsock->host, xsock->port,
|
||||
_sockaddr2str(ainfo->ai_addr, buf, sizeof(buf)));
|
||||
|
||||
sock = socket(ainfo->ai_family, ainfo->ai_socktype, ainfo->ai_protocol);
|
||||
if (sock != INVALID_SOCKET) {
|
||||
if (xsock->conn->sockopt_cb) {
|
||||
/* Don't allow user to overwrite sockfd value. */
|
||||
sock_t sock_copy = sock;
|
||||
rc = xsock->conn->sockopt_cb(xsock->conn, &sock_copy);
|
||||
if (rc != 0) {
|
||||
strophe_debug(xsock->ctx, "sock",
|
||||
"User's setsockopt callback"
|
||||
"failed with %d (errno=%d)",
|
||||
rc, errno);
|
||||
}
|
||||
}
|
||||
if (rc == 0)
|
||||
rc = sock_set_nonblocking(sock);
|
||||
if (rc == 0)
|
||||
rc = connect(sock, ainfo->ai_addr, ainfo->ai_addrlen);
|
||||
/* Assume only connect() can cause "in progress" error. */
|
||||
if (rc != 0 && !_in_progress(sock_error())) {
|
||||
sock_close(sock);
|
||||
sock = INVALID_SOCKET;
|
||||
}
|
||||
}
|
||||
strophe_debug(xsock->ctx, "sock", "sock_connect() result %d", sock);
|
||||
|
||||
xsock->ainfo_cur = xsock->ainfo_cur->ai_next;
|
||||
} while (sock == INVALID_SOCKET);
|
||||
|
||||
return sock;
|
||||
}
|
||||
|
||||
10
src/sock.h
10
src/sock.h
@@ -20,6 +20,7 @@
|
||||
|
||||
#ifndef _WIN32
|
||||
typedef int sock_t;
|
||||
#define INVALID_SOCKET (-1)
|
||||
#else
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
@@ -28,12 +29,19 @@ typedef int sock_t;
|
||||
typedef SOCKET sock_t;
|
||||
#endif
|
||||
|
||||
typedef struct _xmpp_sock_t xmpp_sock_t;
|
||||
|
||||
void sock_initialize(void);
|
||||
void sock_shutdown(void);
|
||||
|
||||
int sock_error(void);
|
||||
|
||||
sock_t sock_connect(xmpp_conn_t *conn, const char *host, unsigned short port);
|
||||
xmpp_sock_t *sock_new(xmpp_conn_t *conn,
|
||||
const char *domain,
|
||||
const char *host,
|
||||
unsigned short port);
|
||||
void sock_free(xmpp_sock_t *xsock);
|
||||
sock_t sock_connect(xmpp_sock_t *xsock);
|
||||
int sock_close(sock_t sock);
|
||||
|
||||
int sock_set_blocking(sock_t sock);
|
||||
|
||||
10
src/stanza.c
10
src/stanza.c
@@ -182,6 +182,7 @@ int xmpp_stanza_release(xmpp_stanza_t *stanza)
|
||||
while (child) {
|
||||
tchild = child;
|
||||
child = child->next;
|
||||
tchild->next = NULL;
|
||||
xmpp_stanza_release(tchild);
|
||||
}
|
||||
|
||||
@@ -1604,8 +1605,7 @@ xmpp_error_new(xmpp_ctx_t *ctx, xmpp_error_type_t type, const char *text)
|
||||
}
|
||||
|
||||
xmpp_stanza_set_ns(error_type, XMPP_NS_STREAMS_IETF);
|
||||
xmpp_stanza_add_child(error, error_type);
|
||||
xmpp_stanza_release(error_type);
|
||||
xmpp_stanza_add_child_ex(error, error_type, 0);
|
||||
|
||||
if (text) {
|
||||
xmpp_stanza_t *error_text = xmpp_stanza_new(ctx);
|
||||
@@ -1615,11 +1615,9 @@ xmpp_error_new(xmpp_ctx_t *ctx, xmpp_error_type_t type, const char *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_ex(error_text, content, 0);
|
||||
|
||||
xmpp_stanza_add_child(error, error_text);
|
||||
xmpp_stanza_release(error_text);
|
||||
xmpp_stanza_add_child_ex(error, error_text, 0);
|
||||
}
|
||||
|
||||
return error;
|
||||
|
||||
24
tests/test.h
24
tests/test.h
@@ -34,17 +34,19 @@
|
||||
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
|
||||
#endif
|
||||
|
||||
#define COMPARE(v1, v2) \
|
||||
do { \
|
||||
const char *__v1 = v1; \
|
||||
const char *__v2 = v2; \
|
||||
if (!__v1 || !__v2 || strcmp(__v1, __v2) != 0) { \
|
||||
printf("Error: %s\n" \
|
||||
"Expected: %s\n" \
|
||||
"Got: %s\n", \
|
||||
#v1 " != " #v2, __v1, __v2); \
|
||||
exit(1); \
|
||||
} \
|
||||
#define COMPARE(v1, v2) \
|
||||
do { \
|
||||
const char *__v1 = v1; \
|
||||
const char *__v2 = v2; \
|
||||
if ((__v1 == NULL) && (__v2 == NULL)) { \
|
||||
/* noop */ \
|
||||
} else if (!__v1 || !__v2 || strcmp(__v1, __v2) != 0) { \
|
||||
printf("Error: %s\n" \
|
||||
"Expected: %s\n" \
|
||||
"Got: %s\n", \
|
||||
#v1 " != " #v2, __v1, __v2); \
|
||||
exit(1); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define COMPARE_BUF(v1, len1, v2, len2) \
|
||||
|
||||
169
tests/test_jid.c
169
tests/test_jid.c
@@ -15,114 +15,80 @@
|
||||
#include "strophe.h"
|
||||
#include "common.h"
|
||||
|
||||
static const char jid1[] = "foo@bar.com";
|
||||
static const char jid2[] = "anyone@example.com/hullo";
|
||||
static const char jid3[] = "manic.porter@xyz.net/frob";
|
||||
static const char jid4[] = "domain.tld";
|
||||
#include "test.h"
|
||||
|
||||
static const char *_s(const char *s)
|
||||
{
|
||||
return s == NULL ? "<NULL>" : s;
|
||||
}
|
||||
|
||||
int test_jid(xmpp_ctx_t *ctx)
|
||||
static int test_jid(xmpp_ctx_t *ctx)
|
||||
{
|
||||
char *bare;
|
||||
char *node;
|
||||
char *domain;
|
||||
char *resource;
|
||||
size_t n;
|
||||
struct {
|
||||
const char *jid;
|
||||
const char *bare;
|
||||
const char *node;
|
||||
const char *domain;
|
||||
const char *resource;
|
||||
} testcases[] = {
|
||||
{"foo@bar.com", "foo@bar.com", "foo", "bar.com", NULL},
|
||||
{
|
||||
"anyone@example.com/hullo",
|
||||
"anyone@example.com",
|
||||
"anyone",
|
||||
"example.com",
|
||||
"hullo",
|
||||
},
|
||||
{
|
||||
"a.example.com/b@example.net",
|
||||
"a.example.com",
|
||||
NULL,
|
||||
"a.example.com",
|
||||
"b@example.net",
|
||||
},
|
||||
{
|
||||
"manic.porter@xyz.net/frob",
|
||||
"manic.porter@xyz.net",
|
||||
"manic.porter",
|
||||
"xyz.net",
|
||||
"frob",
|
||||
},
|
||||
{
|
||||
"domain.tld",
|
||||
"domain.tld",
|
||||
NULL,
|
||||
"domain.tld",
|
||||
NULL,
|
||||
},
|
||||
};
|
||||
|
||||
bare = xmpp_jid_bare(ctx, jid1);
|
||||
node = xmpp_jid_node(ctx, jid1);
|
||||
domain = xmpp_jid_domain(ctx, jid1);
|
||||
resource = xmpp_jid_resource(ctx, jid1);
|
||||
printf("jid '%s' parsed to %s, %s, %s\n", jid1, _s(node), _s(domain),
|
||||
_s(resource));
|
||||
if (bare == NULL || strcmp(bare, "foo@bar.com"))
|
||||
return 1;
|
||||
if (node == NULL || strcmp(node, "foo"))
|
||||
return 1;
|
||||
if (domain == NULL || strcmp(domain, "bar.com"))
|
||||
return 1;
|
||||
if (resource != NULL)
|
||||
return 1;
|
||||
if (bare)
|
||||
strophe_free(ctx, bare);
|
||||
if (node)
|
||||
strophe_free(ctx, node);
|
||||
if (domain)
|
||||
strophe_free(ctx, domain);
|
||||
if (resource)
|
||||
strophe_free(ctx, resource);
|
||||
for (n = 0; n < sizeof(testcases) / sizeof(testcases[0]); ++n) {
|
||||
bare = xmpp_jid_bare(ctx, testcases[n].jid);
|
||||
node = xmpp_jid_node(ctx, testcases[n].jid);
|
||||
domain = xmpp_jid_domain(ctx, testcases[n].jid);
|
||||
resource = xmpp_jid_resource(ctx, testcases[n].jid);
|
||||
printf("jid '%s' parsed to %s, %s, %s\n", testcases[n].jid, _s(node),
|
||||
_s(domain), _s(resource));
|
||||
COMPARE(testcases[n].bare, bare);
|
||||
COMPARE(testcases[n].node, node);
|
||||
COMPARE(testcases[n].domain, domain);
|
||||
COMPARE(testcases[n].resource, resource);
|
||||
if (bare)
|
||||
strophe_free(ctx, bare);
|
||||
if (node)
|
||||
strophe_free(ctx, node);
|
||||
if (domain)
|
||||
strophe_free(ctx, domain);
|
||||
if (resource)
|
||||
strophe_free(ctx, resource);
|
||||
}
|
||||
|
||||
bare = xmpp_jid_bare(ctx, jid2);
|
||||
node = xmpp_jid_node(ctx, jid2);
|
||||
domain = xmpp_jid_domain(ctx, jid2);
|
||||
resource = xmpp_jid_resource(ctx, jid2);
|
||||
printf("jid '%s' parsed to %s, %s, %s\n", jid2, _s(node), _s(domain),
|
||||
_s(resource));
|
||||
if (bare == NULL || strcmp(bare, "anyone@example.com"))
|
||||
return 1;
|
||||
if (node == NULL || strcmp(node, "anyone"))
|
||||
return 1;
|
||||
if (domain == NULL || strcmp(domain, "example.com"))
|
||||
return 1;
|
||||
if (resource == NULL || strcmp(resource, "hullo"))
|
||||
return 1;
|
||||
if (bare)
|
||||
strophe_free(ctx, bare);
|
||||
if (node)
|
||||
strophe_free(ctx, node);
|
||||
if (domain)
|
||||
strophe_free(ctx, domain);
|
||||
if (resource)
|
||||
strophe_free(ctx, resource);
|
||||
|
||||
bare = xmpp_jid_bare(ctx, jid3);
|
||||
node = xmpp_jid_node(ctx, jid3);
|
||||
domain = xmpp_jid_domain(ctx, jid3);
|
||||
resource = xmpp_jid_resource(ctx, jid3);
|
||||
printf("jid '%s' parsed to %s, %s, %s\n", jid3, _s(node), _s(domain),
|
||||
_s(resource));
|
||||
if (bare == NULL || strcmp(bare, "manic.porter@xyz.net"))
|
||||
return 1;
|
||||
if (node == NULL || strcmp(node, "manic.porter"))
|
||||
return 1;
|
||||
if (domain == NULL || strcmp(domain, "xyz.net"))
|
||||
return 1;
|
||||
if (resource == NULL || strcmp(resource, "frob"))
|
||||
return 1;
|
||||
if (bare)
|
||||
strophe_free(ctx, bare);
|
||||
if (node)
|
||||
strophe_free(ctx, node);
|
||||
if (domain)
|
||||
strophe_free(ctx, domain);
|
||||
if (resource)
|
||||
strophe_free(ctx, resource);
|
||||
|
||||
bare = xmpp_jid_bare(ctx, jid4);
|
||||
node = xmpp_jid_node(ctx, jid4);
|
||||
domain = xmpp_jid_domain(ctx, jid4);
|
||||
resource = xmpp_jid_resource(ctx, jid4);
|
||||
printf("jid '%s' parsed to %s, %s, %s\n", jid4, _s(node), _s(domain),
|
||||
_s(resource));
|
||||
if (bare == NULL || strcmp(bare, "domain.tld"))
|
||||
return 1;
|
||||
if (node != NULL)
|
||||
return 1;
|
||||
if (domain == NULL || strcmp(domain, "domain.tld"))
|
||||
return 1;
|
||||
if (resource != NULL)
|
||||
return 1;
|
||||
if (bare)
|
||||
strophe_free(ctx, bare);
|
||||
if (node)
|
||||
strophe_free(ctx, node);
|
||||
if (domain)
|
||||
strophe_free(ctx, domain);
|
||||
if (resource)
|
||||
strophe_free(ctx, resource);
|
||||
printf("test_jid() finished successfully\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -143,6 +109,19 @@ int test_jid_new(xmpp_ctx_t *ctx)
|
||||
return 1;
|
||||
strophe_free(ctx, jid);
|
||||
|
||||
const char *invalid_chars = "\"&'/:<>@";
|
||||
char localpart[] = "localpart";
|
||||
do {
|
||||
localpart[1] = *invalid_chars;
|
||||
jid = xmpp_jid_new(ctx, localpart, "bar.com", NULL);
|
||||
if (jid != NULL) {
|
||||
printf("Shouldn't have created JID with localpart=\"%s\"\n",
|
||||
localpart);
|
||||
return 1;
|
||||
}
|
||||
invalid_chars++;
|
||||
} while (*invalid_chars != '\0');
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -174,10 +174,10 @@ int main()
|
||||
xmpp_ctx_t *ctx;
|
||||
xmpp_rand_t *rand;
|
||||
resolver_srv_rr_t *srv_rr_list;
|
||||
char *domain;
|
||||
char *domain, *rnd_b64;
|
||||
unsigned char *buf;
|
||||
unsigned short port;
|
||||
size_t i;
|
||||
size_t i, slen;
|
||||
int ret;
|
||||
|
||||
ctx = xmpp_ctx_new(NULL, NULL);
|
||||
@@ -223,10 +223,18 @@ int main()
|
||||
ret = resolver_srv_lookup_buf(ctx, buf, sizeof(data2), &srv_rr_list);
|
||||
if (ret == XMPP_DOMAIN_FOUND && srv_rr_list != NULL)
|
||||
resolver_srv_free(ctx, srv_rr_list);
|
||||
strophe_free(ctx, buf);
|
||||
xmpp_rand_free(ctx, rand);
|
||||
printf("ok\n");
|
||||
|
||||
printf("Broken message was:\n");
|
||||
rnd_b64 = xmpp_base64_encode(ctx, buf, sizeof(data2));
|
||||
slen = strlen(rnd_b64);
|
||||
for (i = 0; i < slen; i += 64) {
|
||||
printf("%.64s\n", &rnd_b64[i]);
|
||||
}
|
||||
|
||||
strophe_free(ctx, buf);
|
||||
strophe_free(ctx, rnd_b64);
|
||||
xmpp_ctx_free(ctx);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -7,7 +7,7 @@ set -e
|
||||
if [ "x$LIBRESSL" = "xtrue" ]; then
|
||||
REPO_URL="https://github.com/libressl-portable/portable.git"
|
||||
AUTOGEN_CMD="./autogen.sh"
|
||||
CONFIG_CMD="./configure --prefix=$HOME/xssl"
|
||||
CONFIG_CMD="./configure --prefix=$HOME/xssl --disable-asm"
|
||||
MAKE_TARGET="install"
|
||||
else
|
||||
REPO_URL="https://github.com/openssl/openssl.git"
|
||||
|
||||
Reference in New Issue
Block a user