9 Commits

Author SHA1 Message Date
Dmitry Podgorny
87d40d23db WIP add xsock 2019-10-30 23:29:56 +02:00
Dmitry Podgorny
484e971323 travis-ci: check --enable-cares 2019-10-14 20:37:41 +03:00
Dmitry Podgorny
038404cb99 sock: reduce copy-paste
Move setting (non)block mode to a single static function.
2019-10-14 20:13:04 +03:00
Dmitry Podgorny
6f075bfc71 resolver: fix gcc 9.2.0 warning
message_name_get() adds "." to the tail and it leads to:
    strncpy(&dest, ".", 1);
gcc 9.2.0 generates a warning, because string is truncated without
copying trailing '\0'. Replace strncpy() with memcpy() to fix the
warning.
2019-10-14 17:36:11 +03:00
Dmitry Podgorny
7aed036896 sha1: fixed libstrophe build issues on Windows
Backported from NetXMS.
2019-10-14 09:54:54 +03:00
Dmitry Podgorny
0e8c88a5e4 resolver: backport patch from netxms
explicitely use non-UNICODE structures in libstrophe DNS resolver on Windows
2019-10-14 09:44:11 +03:00
Dmitry Podgorny
a13847d994 resolver: add c-ares support
This patch based on the patch from @gbour (see #7). With
--enable-cares old implementation will be replaced with c-ares API.
2019-10-14 06:51:08 +03:00
Dmitry Podgorny
18b67d6eaf tls/openssl: add LibreSSL support
OpenSSL and LibreSSL versions are incompatible. Moreover, LibreSSL
always define OPENSSL_VERSION_NUMBER as 0x20000000L. Instead of checking
for LibreSSL everywhere explicitly, redefine OPENSSL_VERSION_NUMBER.

See similar issues with nginx project: https://trac.nginx.org/nginx/ticket/1605
2019-10-11 01:59:34 +03:00
Viktor Ivanov
886f45584c Fix bug with xmpp chat not connecting
The facebook suddenly stopped connecting on my dev machine. I still cannot
explain what caused this change in behaviour, but I was finally able to
diagnose and fix the problem.

Chat was not connecting due to an error in tls_start. The windows function
InitializeSecurityContext was returning a SEC_E_INCOMPLETE_MESSAGE status
which was being treated as an error. However, the documentation states
that this is not an error. This status simply indicates that more data
needs to be read. This commit does precisely that -- when
SEC_E_INCOMPLETE_MESSAGE we read more data from the socket and call
InitializeSecurityContext again.
2019-10-11 00:54:37 +03:00
14 changed files with 447 additions and 147 deletions

View File

@@ -1,7 +1,7 @@
language: c
install:
- sudo apt-get update
- sudo apt-get -y install libtool pkg-config libexpat1-dev libxml2-dev libssl-dev
- sudo apt-get -y install libtool pkg-config libexpat1-dev libxml2-dev libssl-dev libc-ares-dev
before_script:
- ./bootstrap.sh
script:
@@ -9,7 +9,7 @@ script:
env:
- CONFIGURE_OPT="--without-libxml2"
- CONFIGURE_OPT="--with-libxml2"
- CONFIGURE_OPT="--disable-tls --without-libxml2"
- CONFIGURE_OPT="--disable-tls --with-libxml2"
- CONFIGURE_OPT="--disable-tls"
- CONFIGURE_OPT="--enable-cares"
matrix:
fast_finish: true

View File

@@ -8,6 +8,7 @@ PARSER_LIBS=@PARSER_LIBS@
SSL_CFLAGS = @openssl_CFLAGS@
SSL_LIBS = @openssl_LIBS@
RESOLV_CFLAGS = @RESOLV_CFLAGS@
RESOLV_LIBS = @RESOLV_LIBS@
STROPHE_FLAGS = -I$(top_srcdir) -Wall -Wextra -Wno-unused-parameter
@@ -16,7 +17,7 @@ STROPHE_LIBS = libstrophe.la
## Main build targets
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
# Export only public API
libstrophe_la_LDFLAGS += -export-symbols-regex '^xmpp_'

View File

@@ -21,6 +21,8 @@ AC_ARG_WITH([libxml2],
[AS_HELP_STRING([--with-libxml2], [use libxml2 for XML parsing, expat is the default])])
AC_ARG_ENABLE([tls],
[AS_HELP_STRING([--disable-tls], [disable TLS support])])
AC_ARG_ENABLE([cares],
[AS_HELP_STRING([--enable-cares], [use c-ares for DNS resolution])])
if test "x$enable_tls" != xno; then
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])
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],
[bsd], [RESOLV_LIBS=""],
[qnx], [RESOLV_LIBS="-lsocket"],
@@ -110,6 +124,8 @@ AC_LINK_IFELSE([AC_LANG_SOURCE([
LIBS="${LIBS_TMP}"
PC_LIBS="${RESOLV_LIBS} ${PC_LIBS}"
fi
m4_ifdef([PKG_INSTALLDIR], [PKG_INSTALLDIR],
[AC_ARG_WITH([pkgconfigdir],
[AS_HELP_STRING([--with-pkgconfigdir],
@@ -126,6 +142,7 @@ AC_SUBST([PC_LIBS], [${PC_LIBS}])
AC_SUBST(PARSER_CFLAGS)
AC_SUBST(PARSER_LIBS)
AC_SUBST(RESOLV_CFLAGS)
AC_SUBST(RESOLV_LIBS)
AC_CONFIG_FILES([Makefile libstrophe.pc])
AC_OUTPUT

View File

@@ -160,6 +160,7 @@ struct _xmpp_conn_t {
xmpp_stream_error_t *stream_error;
sock_t sock;
xmpp_sock_t *xsock;
int ka_timeout; /* TCP keepalive timeout */
int ka_interval; /* TCP keepalive interval */

View File

@@ -689,7 +689,8 @@ void conn_disconnect(xmpp_conn_t * const conn)
tls_free(conn->tls);
conn->tls = NULL;
}
sock_close(conn->sock);
if (conn->sock >= 0)
sock_close(conn->sock);
/* fire off connection handler */
conn->conn_handler(conn, XMPP_CONN_DISCONNECT, conn->error,
@@ -1263,7 +1264,8 @@ static int _conn_connect(xmpp_conn_t * const conn,
conn->domain = xmpp_strdup(conn->ctx, domain);
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",
host, port, conn->sock);
if (conn->sock == -1) return XMPP_EINT;

View File

@@ -47,6 +47,7 @@
#include "strophe.h"
#include "common.h"
#include "resolver.h"
#include "util.h"
/* Workaround for visual studio without va_copy support. */
@@ -63,6 +64,7 @@
void xmpp_initialize(void)
{
sock_initialize();
resolver_initialize();
tls_initialize();
}
@@ -73,6 +75,7 @@
void xmpp_shutdown(void)
{
tls_shutdown();
resolver_shutdown();
sock_shutdown();
}

View File

@@ -51,6 +51,18 @@
#include "common.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.
* This function will run send any data that has been queued by
* 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)
FD_SET(conn->sock, &wfds);
else {
ret = _connect_next(conn);
if (ret == 0) {
FD_SET(conn->sock, &wfds);
break;
}
conn->error = ETIMEDOUT;
xmpp_info(ctx, "xmpp", "Connection attempt timed out.");
conn_disconnect(conn);
@@ -238,6 +255,11 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
/* check for error */
ret = sock_connect_error(conn->sock);
if (ret != 0) {
ret = _connect_next(conn);
if (ret == 0)
break;
}
if (ret != 0) {
/* connection failed */
xmpp_debug(ctx, "xmpp", "connection failed, error %d", ret);

View File

@@ -1,4 +1,4 @@
/* resolver.h
/* resolver.c
* strophe XMPP client library -- DNS resolver
*
* Copyright (C) 2015 Dmitry Podgorny <pasis.ua@gmail.com>
@@ -13,11 +13,15 @@
* DNS resolver.
*/
#ifndef _WIN32
#if !defined(_WIN32) && !defined(HAVE_CARES)
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <resolv.h> /* res_query */
#endif /* _WIN32 */
#endif /* _WIN32 && HAVE_CARES */
#ifdef HAVE_CARES
#include <ares.h>
#endif /* HAVE_CARES */
#include <string.h> /* strncpy */
@@ -31,6 +35,189 @@
#define MESSAGE_T_SRV 33
#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 {
uint16_t id;
uint8_t octet2;
@@ -41,13 +228,6 @@ struct message_header {
uint16_t arcount;
};
#ifdef _WIN32
static int resolver_win32_srv_lookup(xmpp_ctx_t *ctx, const char *fulldomain,
resolver_srv_rr_t **srv_rr_list);
static int resolver_win32_srv_query(const char *fulldomain,
unsigned char *buf, size_t len);
#endif /* _WIN32 */
/* the same as ntohs(), but receives pointer to the value */
static uint16_t xmpp_ntohs_ptr(const void *ptr)
{
@@ -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 = xmpp_min(tail_len, copy_len);
if (copy_len > 0)
strncpy(&name[name_len], tail, copy_len);
memcpy(&name[name_len], tail, copy_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);
}
static void resolver_srv_list_sort(resolver_srv_rr_t **srv_rr_list)
{
resolver_srv_rr_t * rr_head;
resolver_srv_rr_t * rr_current;
resolver_srv_rr_t * rr_next;
resolver_srv_rr_t * rr_prev;
int swap;
rr_head = *srv_rr_list;
if ((rr_head == NULL) || (rr_head->next == NULL)) {
/* Empty or single record list */
return;
}
do {
rr_prev = NULL;
rr_current = rr_head;
rr_next = rr_head->next;
swap = 0;
while (rr_next != NULL) {
/*
* RFC2052: A client MUST attempt to contact the target host
* with the lowest-numbered priority it can reach.
* RFC2052: When selecting a target host among the
* those that have the same priority, the chance of trying
* this one first SHOULD be proportional to its weight.
*/
if ((rr_current->priority > rr_next->priority) ||
(rr_current->priority == rr_next->priority &&
rr_current->weight < rr_next->weight))
{
/* Swap node */
swap = 1;
if (rr_prev != NULL) {
rr_prev->next = rr_next;
} else {
/* Swap head node */
rr_head = rr_next;
}
rr_current->next = rr_next->next;
rr_next->next = rr_current;
rr_prev = rr_next;
rr_next = rr_current->next;
} else {
/* Next node */
rr_prev = rr_current;
rr_current = rr_next;
rr_next = rr_next->next;
}
}
} while (swap != 0);
*srv_rr_list = rr_head;
}
#define BUF_OVERFLOW_CHECK(ptr, len) do { \
if ((ptr) >= (len)) { \
if (*srv_rr_list != NULL) \
@@ -226,8 +349,10 @@ static void resolver_srv_list_sort(resolver_srv_rr_t **srv_rr_list)
} \
} while (0)
int resolver_srv_lookup_buf(xmpp_ctx_t *ctx, const unsigned char *buf,
size_t len, resolver_srv_rr_t **srv_rr_list)
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)
{
unsigned i;
unsigned j;
@@ -292,52 +417,110 @@ int resolver_srv_lookup_buf(xmpp_ctx_t *ctx, const unsigned char *buf,
}
j += rdlength;
}
resolver_srv_list_sort(srv_rr_list);
return *srv_rr_list != NULL ? XMPP_DOMAIN_FOUND : XMPP_DOMAIN_NOT_FOUND;
}
int resolver_srv_lookup(xmpp_ctx_t *ctx, const char *service, const char *proto,
const char *domain, resolver_srv_rr_t **srv_rr_list)
{
char fulldomain[2048];
unsigned char buf[65535];
int len;
int set = XMPP_DOMAIN_NOT_FOUND;
#endif /* !HAVE_CARES */
xmpp_snprintf(fulldomain, sizeof(fulldomain),
"_%s._%s.%s", service, proto, domain);
#ifdef HAVE_CARES
/*******************************************************************************
* 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;
#ifdef _WIN32
set = resolver_win32_srv_lookup(ctx, fulldomain, srv_rr_list);
if (set == XMPP_DOMAIN_FOUND)
return set;
len = resolver_win32_srv_query(fulldomain, buf, sizeof(buf));
#else /* _WIN32 */
len = res_query(fulldomain, MESSAGE_C_IN, MESSAGE_T_SRV, buf, sizeof(buf));
#endif /* _WIN32 */
rc = ares_parse_srv_reply(buf, len, &srv);
if (rc != ARES_SUCCESS)
return XMPP_DOMAIN_NOT_FOUND;
if (len > 0)
set = resolver_srv_lookup_buf(ctx, buf, (size_t)len, srv_rr_list);
return set;
}
void resolver_srv_free(xmpp_ctx_t *ctx, resolver_srv_rr_t *srv_rr_list)
{
resolver_srv_rr_t *rr;
while (srv_rr_list != NULL) {
rr = srv_rr_list->next;
xmpp_free(ctx, srv_rr_list);
srv_rr_list = rr;
item = srv;
while (item != NULL) {
rr = xmpp_alloc(ctx, sizeof(*rr));
if (rr == NULL)
break;
rr->next = *srv_rr_list;
rr->priority = item->priority;
rr->weight = item->weight;
rr->port = item->port;
strncpy(rr->target, item->host, sizeof(rr->target) - 1);
rr->target[sizeof(rr->target) - 1] = '\0';
*srv_rr_list = rr;
item = item->next;
}
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.
*
@@ -470,21 +653,21 @@ static int resolver_win32_srv_lookup(xmpp_ctx_t *ctx, const char *fulldomain,
resolver_srv_rr_t *rr;
HINSTANCE hdnsapi = NULL;
DNS_STATUS (WINAPI * pDnsQuery_A)(PCSTR, WORD, DWORD, PIP4_ARRAY, PDNS_RECORD*, PVOID*);
void (WINAPI * pDnsRecordListFree)(PDNS_RECORD, DNS_FREE_TYPE);
DNS_STATUS (WINAPI * pDnsQuery_A)(PCSTR, WORD, DWORD, PIP4_ARRAY, DNS_RECORDA**, PVOID*);
void (WINAPI * pDnsRecordListFree)(DNS_RECORDA*, DNS_FREE_TYPE);
if (hdnsapi = LoadLibrary("dnsapi.dll")) {
pDnsQuery_A = (void *)GetProcAddress(hdnsapi, "DnsQuery_A");
pDnsRecordListFree = (void *)GetProcAddress(hdnsapi, "DnsRecordListFree");
if (pDnsQuery_A && pDnsRecordListFree) {
PDNS_RECORD dnsrecords = NULL;
DNS_RECORDA *dnsrecords = NULL;
DNS_STATUS error;
error = pDnsQuery_A(fulldomain, DNS_TYPE_SRV, DNS_QUERY_STANDARD, NULL, &dnsrecords, NULL);
if (error == 0) {
PDNS_RECORD current = dnsrecords;
DNS_RECORDA *current = dnsrecords;
while (current) {
if (current->wType == DNS_TYPE_SRV) {

View File

@@ -33,6 +33,9 @@ typedef struct resolver_srv_rr_struc {
struct resolver_srv_rr_struc *next;
} resolver_srv_rr_t;
void resolver_initialize(void);
void resolver_shutdown(void);
/** Perform lookup for RFC1035 message format.
* This function allocates all elements.
*

View File

@@ -197,8 +197,9 @@ void crypto_SHA1_Update(SHA1_CTX* context, const uint8_t* data,
size_t i, j;
j = (context->count[0] >> 3) & 63;
if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++;
context->count[1] += (len >> 29);
if ((context->count[0] += (uint32_t)len << 3) < ((uint32_t)len << 3))
context->count[1]++;
context->count[1] += (uint32_t)(len >> 29);
if ((j + len) > 63) {
memcpy(&context->buffer[j], data, (i = 64-j));
SHA1_Transform(context->state, context->buffer);

View File

@@ -33,9 +33,17 @@
#include <fcntl.h>
#endif
#include "common.h"
#include "sock.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)
{
#ifdef _WIN32
@@ -69,13 +77,23 @@ static int _in_progress(int error)
#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];
struct addrinfo *res, *ainfo, hints;
struct addrinfo hints;
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);
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_socktype = SOCK_STREAM;
err = getaddrinfo(host, service, &hints, &res);
if (err != 0)
return -1;
err = getaddrinfo(host, service, &hints, &xsock->ainfo_list);
if (err != 0) {
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);
if (sock < 0)
continue;
@@ -103,9 +143,13 @@ sock_t sock_connect(const char * const host, const unsigned short port)
}
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;
}
@@ -158,38 +202,33 @@ int sock_close(const sock_t sock)
#endif
}
int sock_set_blocking(const sock_t sock)
static int _sock_set_blocking_mode(sock_t sock, int blocking)
{
#ifdef _WIN32
u_long block = 0;
return ioctlsocket(sock, FIONBIO, &block);
#else
int rc;
rc = fcntl(sock, F_GETFL, NULL);
if (rc >= 0) {
rc = fcntl(sock, F_SETFL, rc & (~O_NONBLOCK));
}
return rc;
#endif
}
int sock_set_nonblocking(const sock_t sock)
{
#ifdef _WIN32
u_long nonblock = 1;
u_long nonblock = blocking ? 0 : 1;
return ioctlsocket(sock, FIONBIO, &nonblock);
#else
int rc;
rc = fcntl(sock, F_GETFL, NULL);
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;
#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)
{
return recv(sock, buff, len, 0);

View File

@@ -25,12 +25,16 @@ 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(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_set_blocking(const sock_t sock);

View File

@@ -31,6 +31,22 @@
#include "tls.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 {
xmpp_ctx_t *ctx;
sock_t sock;

View File

@@ -255,10 +255,18 @@ int tls_start(tls_t *tls)
NULL, 0, &(tls->hctxt), &sbdout,
&ctxtattr, NULL);
unsigned char *p = sbin[0].pvBuffer;
int len = 0;
while (ret == SEC_I_CONTINUE_NEEDED
|| ret == SEC_I_INCOMPLETE_CREDENTIALS) {
unsigned char *p = sbin[0].pvBuffer;
int len = 0, inbytes = 0;
|| ret == SEC_I_INCOMPLETE_CREDENTIALS
|| ret == SEC_E_INCOMPLETE_MESSAGE) {
int inbytes = 0;
if (ret != SEC_E_INCOMPLETE_MESSAGE) {
len = 0;
p = sbin[0].pvBuffer;
}
if (sbdout.pBuffers[0].cbBuffer) {
unsigned char *writebuff = sbdout.pBuffers[0].pvBuffer;