Re-factor into separate compression module

Introduce a `conn_interface` to simplify the decision logic which API
we must call.

This also fixes some bugs of the previous commit.

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
This commit is contained in:
Steffen Jaeckel
2024-01-26 20:43:59 +01:00
parent c7d410f38b
commit 3f03de031c
19 changed files with 555 additions and 359 deletions

View File

@@ -85,6 +85,12 @@ if NEED_SNPRINTF
libstrophe_la_SOURCES += src/snprintf.c
endif
if DISABLE_COMPRESSION
libstrophe_la_SOURCES += src/compression_dummy.c
else
libstrophe_la_SOURCES += src/compression.c
endif
if DISABLE_TLS
libstrophe_la_SOURCES += src/tls_dummy.c
else

View File

@@ -252,7 +252,7 @@ fi
if test "x$enable_zlib" != xno; then
PKG_CHECK_MODULES([zlib], [zlib >= 1.2.0],
[
PC_REQUIRES="libzlib ${PC_REQUIRES}"
PC_REQUIRES="zlib ${PC_REQUIRES}"
ZLIB_CFLAGS=$zlib_CFLAGS
ZLIB_LIBS=$zlib_LIBS
AC_DEFINE([HAVE_ZLIB])
@@ -269,6 +269,7 @@ m4_ifdef([PKG_INSTALLDIR], [PKG_INSTALLDIR],
AC_SUBST([pkgconfigdir], [${with_pkgconfigdir}])])
AM_CONDITIONAL([PARSER_EXPAT], [test x$with_parser != xlibxml2])
AM_CONDITIONAL([DISABLE_COMPRESSION], [test x$enable_zlib = xno])
AM_CONDITIONAL([DISABLE_TLS], [test x$enable_tls = xno])
AM_CONDITIONAL([DISABLE_STATIC], [test x$enable_static = xno])
AM_CONDITIONAL([NEED_SNPRINTF], [test x$have_snprintf = xno])

View File

@@ -77,13 +77,19 @@ int version_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
return 1;
}
static int _quit_handler(xmpp_conn_t *conn, void *userdata)
{
(void)userdata;
xmpp_disconnect(conn);
return 0;
}
int message_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
{
xmpp_ctx_t *ctx = (xmpp_ctx_t *)userdata;
xmpp_stanza_t *body, *reply;
const char *type;
char *intext, *replytext;
int quit = 0;
body = xmpp_stanza_get_child_by_name(stanza, "body");
if (body == NULL)
@@ -103,11 +109,11 @@ int message_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
if (strcmp(intext, "quit") == 0) {
replytext = strdup("bye!");
quit = 1;
xmpp_timed_handler_add(conn, _quit_handler, 500, NULL);
} else if (strcmp(intext, "reconnect") == 0) {
replytext = strdup("alright, let's see what happens!");
reconnect = 1;
quit = 1;
xmpp_timed_handler_add(conn, _quit_handler, 500, NULL);
} else {
replytext = (char *)malloc(strlen(" to you too!") + strlen(intext) + 1);
strcpy(replytext, intext);
@@ -120,9 +126,6 @@ int message_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
xmpp_stanza_release(reply);
free(replytext);
if (quit)
xmpp_disconnect(conn);
return 1;
}
@@ -216,8 +219,8 @@ static void usage(int exit_code)
"Note: --disable-tls conflicts with --mandatory-tls or "
"--legacy-ssl\n"
" --zlib Enable compression via zlib.\n"
" --dont-flush When using zlib, don't flush after "
"compression.\n");
" --dont-reset When using zlib, don't do a full-flush "
"after compression.\n");
exit(exit_code);
}
@@ -249,8 +252,8 @@ int main(int argc, char **argv)
flags |= XMPP_CONN_FLAG_LEGACY_AUTH;
else if (strcmp(argv[i], "--zlib") == 0)
flags |= XMPP_CONN_FLAG_ENABLE_COMPRESSION;
else if (strcmp(argv[i], "--dont-flush") == 0)
flags |= XMPP_CONN_FLAG_COMPRESSION_DONT_FLUSH;
else if (strcmp(argv[i], "--dont-reset") == 0)
flags |= XMPP_CONN_FLAG_COMPRESSION_DONT_RESET;
else if ((strcmp(argv[i], "--jid") == 0) && (++i < argc))
jid = argv[i];
else if ((strcmp(argv[i], "--pass") == 0) && (++i < argc))

View File

@@ -240,8 +240,8 @@ static void usage(int exit_code)
" --legacy-ssl Use old style SSL.\n"
" --legacy-auth Allow legacy authentication.\n"
" --zlib Enable compression via zlib.\n"
" --dont-flush When using zlib, don't flush after "
"compression.\n"
" --dont-reset When using zlib, don't do a full-flush "
"after compression.\n"
" --verbose Increase the verbosity level.\n"
" --tcp-keepalive Configure TCP keepalive.\n\n"
"Note: --disable-tls conflicts with --mandatory-tls or "
@@ -278,8 +278,8 @@ int main(int argc, char **argv)
flags |= XMPP_CONN_FLAG_LEGACY_AUTH;
else if (strcmp(argv[i], "--zlib") == 0)
flags |= XMPP_CONN_FLAG_ENABLE_COMPRESSION;
else if (strcmp(argv[i], "--dont-flush") == 0)
flags |= XMPP_CONN_FLAG_COMPRESSION_DONT_FLUSH;
else if (strcmp(argv[i], "--dont-reset") == 0)
flags |= XMPP_CONN_FLAG_COMPRESSION_DONT_RESET;
else if (strcmp(argv[i], "--verbose") == 0)
verbosity++;
else if (strcmp(argv[i], "--tcp-keepalive") == 0)

View File

@@ -255,19 +255,10 @@ static void _handle_sasl_children(xmpp_conn_t *conn, const char *text)
}
}
static void _handle_compression_children(xmpp_conn_t *conn, const char *text)
{
if (strcasecmp(text, "zlib") == 0) {
conn->compression_supported = 1;
}
}
static int
_handle_features(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
{
xmpp_stanza_t *child, *children;
const char *ns;
char *text;
xmpp_stanza_t *child;
UNUSED(userdata);
@@ -297,13 +288,6 @@ _handle_features(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
if (conn->sasl_support & ~(SASL_MASK_PLAIN | SASL_MASK_ANONYMOUS))
conn->sasl_support &= ~SASL_MASK_PLAIN;
/* check for compression */
child = xmpp_stanza_get_child_by_name_and_ns(stanza, "compression",
XMPP_NS_COMPRESSION);
if (conn->compression_allowed && child) {
_foreach_child(conn, child, "method", _handle_compression_children);
}
_auth(conn);
return 0;
@@ -371,7 +355,7 @@ _handle_sasl_result(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
(char *)userdata);
/* reset parser */
conn_prepare_reset(conn, conn->compression_allowed
conn_prepare_reset(conn, conn->compression.allowed
? _handle_open_compress
: _handle_open_sasl);
@@ -1058,6 +1042,8 @@ static int _handle_compress_result(xmpp_conn_t *const conn,
{
const char *name = xmpp_stanza_get_name(stanza);
UNUSED(userdata);
if (!name)
return 0;
if (strcmp(name, "compressed") == 0) {
@@ -1068,7 +1054,7 @@ static int _handle_compress_result(xmpp_conn_t *const conn,
conn_prepare_reset(conn, _handle_open_sasl);
/* make compression effective */
conn->compress = 1;
compression_init(conn);
/* send stream tag */
conn_open_stream(conn);
@@ -1082,15 +1068,26 @@ static int _handle_features_compress(xmpp_conn_t *conn,
{
const char *compress = "<compress xmlns='" XMPP_NS_COMPRESSION
"'><method>zlib</method></compress>";
UNUSED(userdata);
xmpp_stanza_t *child;
/* remove missing features handler */
xmpp_timed_handler_delete(conn, _handle_missing_features);
send_raw(conn, compress, strlen(compress), XMPP_QUEUE_STROPHE, NULL);
handler_add(conn, _handle_compress_result, XMPP_NS_COMPRESSION, NULL, NULL,
NULL);
/* check for compression */
child = xmpp_stanza_get_child_by_name_and_ns(stanza, "compression",
XMPP_NS_FEATURE_COMPRESSION);
if (conn->compression.allowed && child) {
_foreach_child(conn, child, "method",
compression_handle_feature_children);
}
if (conn->compression.supported) {
send_raw(conn, compress, strlen(compress), XMPP_QUEUE_STROPHE, NULL);
handler_add(conn, _handle_compress_result, XMPP_NS_COMPRESSION, NULL,
NULL, NULL);
} else {
return _handle_features_sasl(conn, stanza, userdata);
}
return 0;
}

View File

@@ -19,7 +19,6 @@
#include <stdio.h>
#include <stdarg.h>
#include <zlib.h>
#include "strophe.h"
#include "ostypes.h"
@@ -208,7 +207,28 @@ struct _xmpp_sm_t {
xmpp_stanza_t *bind;
};
struct conn_interface {
int (*read)(struct conn_interface *intf, void *buff, size_t len);
int (*write)(struct conn_interface *intf, const void *buff, size_t len);
int (*flush)(struct conn_interface *intf);
int (*pending)(struct conn_interface *intf);
int (*get_error)(struct conn_interface *intf);
int (*error_is_recoverable)(struct conn_interface *intf, int err);
xmpp_conn_t *conn;
};
int conn_interface_write(struct conn_interface *intf,
const void *buff,
size_t len);
int conn_int_nop(struct conn_interface *intf);
int compression_init(xmpp_conn_t *conn);
void compression_free(xmpp_conn_t *conn);
void compression_handle_feature_children(xmpp_conn_t *conn, const char *text);
struct _xmpp_conn_t {
struct conn_interface intf;
unsigned int ref;
xmpp_ctx_t *ctx;
xmpp_conn_type_t type;
@@ -256,12 +276,10 @@ struct _xmpp_conn_t {
int sm_disable;
xmpp_sm_state_t *sm_state;
int compression_allowed, compression_supported;
int compress, compression_dont_flush;
struct zlib_compression {
void *buffer, *buffer_end;
z_stream stream;
} compression, decompression;
struct {
struct xmpp_compression *state;
int allowed, supported, dont_reset;
} compression;
char *lang;
char *domain;

270
src/compression.c Normal file
View File

@@ -0,0 +1,270 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* compression.c
** strophe XMPP client library -- XEP-0138 Stream Compression
**
** Copyright (C) 2024 Steffen Jaeckel <jaeckel-floss@eyet-services.de>
**
** This software is provided AS-IS with no warranty, either express
** or implied.
**
** This program is dual licensed under the MIT or GPLv3 licenses.
*/
/** @file
* XEP-0138 Stream Compression.
*/
#include <zlib.h>
#include <string.h>
#include <errno.h>
#include "common.h"
#ifndef STROPHE_COMPRESSION_BUFFER_SIZE
/** Max buffer size for compressed data (send & receive). */
#define STROPHE_COMPRESSION_BUFFER_SIZE 4096
#endif
struct zlib_compression {
void *buffer, *buffer_end;
z_stream stream;
};
struct xmpp_compression {
xmpp_conn_t *conn;
struct zlib_compression compression, decompression;
struct conn_interface next;
};
static int _conn_decompress(struct xmpp_compression *comp,
size_t c_len,
void *buff,
size_t len)
{
if (comp->decompression.stream.next_in == NULL) {
comp->decompression.stream.next_in = comp->decompression.buffer;
comp->decompression.buffer_end =
comp->decompression.stream.next_in + c_len;
comp->decompression.stream.avail_in = c_len;
} else if (c_len) {
strophe_error(comp->conn->ctx, "zlib",
"_conn_decompress() called with c_len=%zu", c_len);
}
comp->decompression.stream.next_out = buff;
comp->decompression.stream.avail_out = len;
int ret = inflate(&comp->decompression.stream, Z_SYNC_FLUSH);
switch (ret) {
case Z_STREAM_END:
case Z_OK:
if (comp->decompression.buffer_end ==
comp->decompression.stream.next_in)
comp->decompression.stream.next_in = NULL;
return comp->decompression.stream.next_out - (Bytef *)buff;
case Z_BUF_ERROR:
break;
default:
strophe_error(comp->conn->ctx, "zlib", "inflate error %d", ret);
comp->conn->error = EBADFD;
conn_disconnect(comp->conn);
break;
}
return 0;
}
static int compression_read(struct conn_interface *intf, void *buff, size_t len)
{
xmpp_conn_t *conn = intf->conn;
struct xmpp_compression *comp = conn->compression.state;
void *dbuff = buff;
size_t dlen = len;
if (comp->decompression.stream.next_in != NULL) {
return _conn_decompress(comp, 0, buff, len);
}
dbuff = comp->decompression.buffer;
dlen = STROPHE_COMPRESSION_BUFFER_SIZE;
int ret = comp->next.read(intf, dbuff, dlen);
if (ret > 0) {
return _conn_decompress(comp, ret, buff, len);
}
return ret;
}
static int _try_compressed_write_to_network(xmpp_conn_t *conn, int force)
{
struct xmpp_compression *comp = conn->compression.state;
int ret = 0;
ptrdiff_t len =
comp->compression.stream.next_out - (Bytef *)comp->compression.buffer;
int buffer_full =
comp->compression.stream.next_out == comp->compression.buffer_end;
if ((buffer_full || force) && len > 0) {
ret = conn_interface_write(&comp->next, comp->compression.buffer, len);
if (ret < 0)
return ret;
comp->compression.stream.next_out = comp->compression.buffer;
comp->compression.stream.avail_out = STROPHE_COMPRESSION_BUFFER_SIZE;
}
return ret;
}
static int
_compression_write(xmpp_conn_t *conn, const void *buff, size_t len, int flush)
{
int ret;
const void *buff_end = buff + len;
struct xmpp_compression *comp = conn->compression.state;
comp->compression.stream.next_in = (Bytef *)buff;
comp->compression.stream.avail_in = len;
do {
ret = _try_compressed_write_to_network(conn, 0);
if (ret < 0) {
return ret;
}
ret = deflate(&comp->compression.stream, flush);
if (ret == Z_STREAM_END) {
break;
}
if (flush && ret == Z_BUF_ERROR) {
break;
}
if (ret != Z_OK) {
strophe_error(conn->ctx, "zlib", "deflate error %d", ret);
conn->error = EBADFD;
conn_disconnect(conn);
return ret;
}
ret = comp->compression.stream.next_in - (Bytef *)buff;
} while (comp->compression.stream.next_in < (Bytef *)buff_end);
if (flush) {
ret = _try_compressed_write_to_network(conn, 1);
if (ret < 0) {
return ret;
}
}
return ret;
}
static int
compression_write(struct conn_interface *intf, const void *buff, size_t len)
{
return _compression_write(intf->conn, buff, len, Z_NO_FLUSH);
}
static int compression_flush(struct conn_interface *intf)
{
xmpp_conn_t *conn = intf->conn;
struct xmpp_compression *comp = conn->compression.state;
return _compression_write(conn, comp->compression.buffer, 0,
conn->compression.dont_reset ? Z_SYNC_FLUSH
: Z_FULL_FLUSH);
}
static int compression_pending(struct conn_interface *intf)
{
xmpp_conn_t *conn = intf->conn;
struct xmpp_compression *comp = conn->compression.state;
return comp->decompression.stream.next_in != NULL ||
comp->next.pending(intf);
}
static int compression_get_error(struct conn_interface *intf)
{
struct conn_interface *next = &intf->conn->compression.state->next;
return next->get_error(next);
}
static int compression_is_recoverable(struct conn_interface *intf, int err)
{
struct conn_interface *next = &intf->conn->compression.state->next;
return next->error_is_recoverable(next, err);
}
static const struct conn_interface compression_intf = {
compression_read,
compression_write,
compression_flush,
compression_pending,
compression_get_error,
compression_is_recoverable,
NULL,
};
static void *_zlib_alloc(void *opaque, unsigned int items, unsigned int size)
{
size_t sz = items * size;
/* Poor man's multiplication overflow check */
if (sz < items || sz < size)
return NULL;
return strophe_alloc(opaque, sz);
}
static void _init_zlib_compression(xmpp_ctx_t *ctx, struct zlib_compression *s)
{
s->buffer = strophe_alloc(ctx, STROPHE_COMPRESSION_BUFFER_SIZE);
s->buffer_end = s->buffer + STROPHE_COMPRESSION_BUFFER_SIZE;
s->stream.opaque = ctx;
s->stream.zalloc = _zlib_alloc;
s->stream.zfree = (free_func)strophe_free;
}
int compression_init(xmpp_conn_t *conn)
{
if (!conn->compression.allowed || !conn->compression.supported)
return -1;
conn->compression.state =
strophe_alloc(conn->ctx, sizeof(*conn->compression.state));
struct xmpp_compression *comp = conn->compression.state;
memset(comp, 0, sizeof(*comp));
comp->conn = conn;
comp->next = conn->intf;
conn->intf = compression_intf;
conn->intf.conn = conn;
_init_zlib_compression(conn->ctx, &comp->compression);
comp->compression.stream.next_out = comp->compression.buffer;
comp->compression.stream.avail_out = STROPHE_COMPRESSION_BUFFER_SIZE;
int err = deflateInit(&comp->compression.stream, Z_DEFAULT_COMPRESSION);
if (err != Z_OK) {
strophe_free_and_null(conn->ctx, comp->compression.buffer);
conn->error = EBADFD;
conn_disconnect(conn);
return err;
}
_init_zlib_compression(conn->ctx, &comp->decompression);
err = inflateInit(&comp->decompression.stream);
if (err != Z_OK) {
strophe_free_and_null(conn->ctx, comp->decompression.buffer);
conn->error = EBADFD;
conn_disconnect(conn);
return err;
}
return 0;
}
void compression_free(xmpp_conn_t *conn)
{
struct xmpp_compression *comp = conn->compression.state;
if (!comp)
return;
if (comp->compression.buffer) {
deflateEnd(&comp->compression.stream);
strophe_free_and_null(conn->ctx, comp->compression.buffer);
}
if (comp->decompression.buffer) {
inflateEnd(&comp->decompression.stream);
strophe_free_and_null(conn->ctx, comp->decompression.buffer);
}
}
void compression_handle_feature_children(xmpp_conn_t *conn, const char *text)
{
if (strcasecmp(text, "zlib") == 0) {
conn->compression.supported = 1;
}
}

36
src/compression_dummy.c Normal file
View File

@@ -0,0 +1,36 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* compression_dummy.c
** strophe XMPP client library -- Dummy Compression
**
** Copyright (C) 2024 Steffen Jaeckel <jaeckel-floss@eyet-services.de>
**
** This software is provided AS-IS with no warranty, either express
** or implied.
**
** This program is dual licensed under the MIT or GPLv3 licenses.
*/
/** @file
* Dummy Compression.
*/
#include <strings.h>
#include <errno.h>
#include "common.h"
int compression_init(xmpp_conn_t *conn)
{
conn->compression.supported = 0;
return -1;
}
void compression_free(xmpp_conn_t *conn)
{
UNUSED(conn);
}
void compression_handle_feature_children(xmpp_conn_t *conn, const char *text)
{
UNUSED(text);
conn->compression.supported = 0;
}

View File

@@ -1062,6 +1062,23 @@ void conn_open_stream(xmpp_conn_t *conn)
strophe_free(conn->ctx, from);
}
int conn_interface_write(struct conn_interface *intf,
const void *buff,
size_t len)
{
int ret = intf->write(intf, buff, len);
if (ret < 0 && !intf->error_is_recoverable(intf, intf->get_error(intf))) {
intf->conn->error = intf->get_error(intf);
}
return ret;
}
int conn_int_nop(struct conn_interface *intf)
{
UNUSED(intf);
return 0;
}
int conn_tls_start(xmpp_conn_t *conn)
{
int rc;
@@ -1075,11 +1092,13 @@ int conn_tls_start(xmpp_conn_t *conn)
}
if (conn->tls != NULL) {
conn->intf = tls_intf;
conn->intf.conn = conn;
if (tls_start(conn->tls)) {
conn->secured = 1;
} else {
rc = XMPP_EINT;
conn->error = tls_error(conn->tls);
conn->error = tls_error(&conn->intf);
tls_free(conn->tls);
conn->tls = NULL;
conn->tls_failed = 1;
@@ -1112,8 +1131,8 @@ long xmpp_conn_get_flags(const xmpp_conn_t *conn)
XMPP_CONN_FLAG_LEGACY_SSL * conn->tls_legacy_ssl |
XMPP_CONN_FLAG_TRUST_TLS * conn->tls_trust |
XMPP_CONN_FLAG_DISABLE_SM * conn->sm_disable |
XMPP_CONN_FLAG_ENABLE_COMPRESSION * conn->compression_allowed |
XMPP_CONN_FLAG_COMPRESSION_DONT_FLUSH * conn->compression_dont_flush |
XMPP_CONN_FLAG_ENABLE_COMPRESSION * conn->compression.allowed |
XMPP_CONN_FLAG_COMPRESSION_DONT_RESET * conn->compression.dont_reset |
XMPP_CONN_FLAG_LEGACY_AUTH * conn->auth_legacy_enabled;
return flags;
@@ -1134,6 +1153,8 @@ long xmpp_conn_get_flags(const xmpp_conn_t *conn)
* - XMPP_CONN_FLAG_TRUST_TLS
* - XMPP_CONN_FLAG_LEGACY_AUTH
* - XMPP_CONN_FLAG_DISABLE_SM
* - XMPP_CONN_FLAG_ENABLE_COMPRESSION
* - XMPP_CONN_FLAG_COMPRESSION_DONT_RESET
*
* @param conn a Strophe connection object
* @param flags ORed connection flags
@@ -1163,15 +1184,15 @@ int xmpp_conn_set_flags(xmpp_conn_t *conn, long flags)
conn->tls_trust = (flags & XMPP_CONN_FLAG_TRUST_TLS) ? 1 : 0;
conn->auth_legacy_enabled = (flags & XMPP_CONN_FLAG_LEGACY_AUTH) ? 1 : 0;
conn->sm_disable = (flags & XMPP_CONN_FLAG_DISABLE_SM) ? 1 : 0;
conn->compression_allowed =
conn->compression.allowed =
(flags & XMPP_CONN_FLAG_ENABLE_COMPRESSION) ? 1 : 0;
conn->compression_dont_flush =
(flags & XMPP_CONN_FLAG_COMPRESSION_DONT_FLUSH) ? 1 : 0;
conn->compression.dont_reset =
(flags & XMPP_CONN_FLAG_COMPRESSION_DONT_RESET) ? 1 : 0;
flags &= ~(XMPP_CONN_FLAG_DISABLE_TLS | XMPP_CONN_FLAG_MANDATORY_TLS |
XMPP_CONN_FLAG_LEGACY_SSL | XMPP_CONN_FLAG_TRUST_TLS |
XMPP_CONN_FLAG_LEGACY_AUTH | XMPP_CONN_FLAG_DISABLE_SM |
XMPP_CONN_FLAG_ENABLE_COMPRESSION |
XMPP_CONN_FLAG_COMPRESSION_DONT_FLUSH);
XMPP_CONN_FLAG_COMPRESSION_DONT_RESET);
if (flags) {
strophe_error(conn->ctx, "conn", "Flags 0x%04lx unknown", flags);
return XMPP_EINVOP;
@@ -1768,14 +1789,11 @@ static void _conn_reset(xmpp_conn_t *conn)
return;
}
if (conn->compression.buffer) {
deflateEnd(&conn->compression.stream);
strophe_free_and_null(ctx, conn->compression.buffer);
}
if (conn->decompression.buffer) {
inflateEnd(&conn->decompression.stream);
strophe_free_and_null(ctx, conn->decompression.buffer);
}
compression_free(conn);
conn->intf = sock_intf;
conn->intf.conn = conn;
/* free queued */
sq = conn->send_queue_head;
while (sq) {

View File

@@ -75,202 +75,6 @@ static int _connect_next(xmpp_conn_t *conn)
return 0;
}
static int
_conn_write_to_network(xmpp_conn_t *conn, const void *buff, size_t len)
{
int ret;
if (conn->tls) {
ret = tls_write(conn->tls, buff, len);
if (ret < 0 && !tls_is_recoverable(tls_error(conn->tls)))
conn->error = tls_error(conn->tls);
} else {
ret = sock_write(conn->sock, buff, len);
if (ret < 0 && !sock_is_recoverable(sock_error()))
conn->error = sock_error();
}
return ret;
}
static int _try_compressed_write_to_network(xmpp_conn_t *conn, int force)
{
int ret = 0;
size_t len =
conn->compression.stream.next_out - (Bytef *)conn->compression.buffer;
int buffer_full =
conn->compression.stream.next_out == conn->compression.buffer_end;
if ((buffer_full || force) && len) {
ret = _conn_write_to_network(conn, conn->compression.buffer, len);
if (ret < 0)
return ret;
// print_hex(xmpp_base64_encode(conn->ctx,
// conn->compression.buffer, len),
// conn->compression.buffer, len);
char *b = xmpp_base64_encode(conn->ctx, conn->compression.buffer, len);
printf("Sent: %s\n", b);
xmpp_free(conn->ctx, b);
conn->compression.stream.next_out = conn->compression.buffer;
conn->compression.stream.avail_out = STROPHE_MESSAGE_BUFFER_SIZE;
}
return ret;
}
static int _conn_compress(xmpp_conn_t *conn, void *buff, size_t len, int flush)
{
int ret;
void *buff_end = buff + len;
conn->compression.stream.next_in = buff;
conn->compression.stream.avail_in = len;
do {
ret = _try_compressed_write_to_network(conn, 0);
if (ret < 0) {
return ret;
}
ret = deflate(&conn->compression.stream, flush);
if (ret == Z_STREAM_END) {
break;
}
if (flush && ret == Z_BUF_ERROR) {
break;
}
if (ret != Z_OK) {
strophe_error(conn->ctx, "zlib", "deflate error %d", ret);
conn->error = EBADFD;
conn_disconnect(conn);
return ret;
}
ret = conn->compression.stream.next_in - (const Bytef *)buff;
} while (conn->compression.stream.next_in < (const Bytef *)buff_end);
if (flush) {
ret = _try_compressed_write_to_network(conn, 1);
if (ret < 0) {
return ret;
}
}
return ret;
}
static void *_zlib_alloc(void *opaque, unsigned int items, unsigned int size)
{
size_t sz = items * size;
if (sz < items || sz < size)
return NULL;
return strophe_alloc(opaque, sz);
}
static void _init_zlib_compression(xmpp_ctx_t *ctx, struct zlib_compression *s)
{
s->buffer = strophe_alloc(ctx, STROPHE_MESSAGE_BUFFER_SIZE);
s->buffer_end = s->buffer + STROPHE_MESSAGE_BUFFER_SIZE;
s->stream.opaque = ctx;
s->stream.zalloc = _zlib_alloc;
s->stream.zfree = (free_func)strophe_free;
}
static int _conn_write(xmpp_conn_t *conn, void *buff, size_t len)
{
if (conn->compress) {
if (conn->compression.buffer == NULL) {
_init_zlib_compression(conn->ctx, &conn->compression);
conn->compression.stream.next_out = conn->compression.buffer;
conn->compression.stream.avail_out = STROPHE_MESSAGE_BUFFER_SIZE;
int err =
deflateInit(&conn->compression.stream, Z_DEFAULT_COMPRESSION);
if (err != Z_OK) {
strophe_free_and_null(conn->ctx, conn->compression.buffer);
conn->error = EBADFD;
conn_disconnect(conn);
return err;
}
}
return _conn_compress(conn, buff, len, Z_NO_FLUSH);
} else {
return _conn_write_to_network(conn, buff, len);
}
}
static int _conn_read_from_network(xmpp_conn_t *conn, void *buff, size_t len)
{
if (conn->tls) {
return tls_read(conn->tls, buff, len);
} else {
return sock_read(conn->sock, buff, len);
}
}
static int
_conn_decompress(xmpp_conn_t *conn, size_t c_len, void *buff, size_t len)
{
if (conn->decompression.stream.next_in == NULL) {
conn->decompression.stream.next_in = conn->decompression.buffer;
conn->decompression.buffer_end =
conn->decompression.stream.next_in + c_len;
conn->decompression.stream.avail_in = c_len;
} else if (c_len) {
strophe_error(conn->ctx, "zlib",
"_conn_decompress() called with c_len=%zu", c_len);
}
conn->decompression.stream.next_out = buff;
conn->decompression.stream.avail_out = len;
int ret = inflate(&conn->decompression.stream, Z_SYNC_FLUSH);
switch (ret) {
case Z_STREAM_END:
case Z_OK:
if (conn->decompression.buffer_end ==
conn->decompression.stream.next_in)
conn->decompression.stream.next_in = NULL;
/* -fallthrough */
return conn->decompression.stream.next_out - (Bytef *)buff;
case Z_BUF_ERROR:
break;
default:
strophe_error(conn->ctx, "zlib", "inflate error %d", ret);
conn->error = EBADFD;
conn_disconnect(conn);
break;
}
return 0;
}
static int _conn_read(xmpp_conn_t *conn, void *buff, size_t len)
{
void *dbuff = buff;
size_t dlen = len;
if (conn->compress) {
if (conn->decompression.buffer == NULL) {
_init_zlib_compression(conn->ctx, &conn->decompression);
int err = inflateInit(&conn->decompression.stream);
if (err != Z_OK) {
strophe_free_and_null(conn->ctx, conn->decompression.buffer);
return err;
}
}
if (conn->decompression.stream.next_in != NULL) {
return _conn_decompress(conn, 0, buff, len);
}
dbuff = conn->decompression.buffer;
dlen = STROPHE_MESSAGE_BUFFER_SIZE;
}
int ret = _conn_read_from_network(conn, dbuff, dlen);
if (ret > 0 && conn->compress) {
char *b = xmpp_base64_encode(conn->ctx, dbuff, ret);
printf("Read: %s\n", b);
xmpp_free(conn->ctx, b);
return _conn_decompress(conn, ret, buff, len);
}
return ret;
}
static int _conn_pending(xmpp_conn_t *conn)
{
return (conn->compress && conn->decompression.stream.next_in != NULL) ||
(conn->tls && tls_pending(conn->tls));
}
/** 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
@@ -288,6 +92,7 @@ void xmpp_run_once(xmpp_ctx_t *ctx, unsigned long timeout)
{
xmpp_connlist_t *connitem;
xmpp_conn_t *conn;
struct conn_interface *intf;
fd_set rfds, wfds;
sock_t max = 0;
int ret;
@@ -310,13 +115,14 @@ void xmpp_run_once(xmpp_ctx_t *ctx, unsigned long timeout)
connitem = connitem->next;
continue;
}
intf = &conn->intf;
/* if we're running tls, there may be some remaining data waiting to
* be sent, so push that out */
if (conn->tls) {
ret = tls_clear_pending_write(conn->tls);
ret = tls_clear_pending_write(intf);
if (ret < 0 && !tls_is_recoverable(tls_error(conn->tls))) {
if (ret < 0 && !tls_is_recoverable(intf, tls_error(intf))) {
/* an error occurred */
strophe_debug(
ctx, "xmpp",
@@ -332,7 +138,7 @@ void xmpp_run_once(xmpp_ctx_t *ctx, unsigned long timeout)
while (sq) {
towrite = sq->len - sq->written;
ret = _conn_write(conn, &sq->data[sq->written], towrite);
ret = conn_interface_write(intf, &sq->data[sq->written], towrite);
if (ret > 0 && ret < towrite)
sq->written += ret; /* not all data could be sent now */
sq->wip = 1;
@@ -369,11 +175,7 @@ void xmpp_run_once(xmpp_ctx_t *ctx, unsigned long timeout)
if (!sq)
conn->send_queue_tail = NULL;
}
if (conn->compress) {
_conn_compress(conn, conn->compression.buffer, 0,
conn->compression_dont_flush ? Z_SYNC_FLUSH
: Z_FULL_FLUSH);
}
intf->flush(intf);
/* tear down connection on error */
if (conn->error) {
@@ -408,6 +210,7 @@ next_item:
connitem = ctx->connlist;
while (connitem) {
conn = connitem->conn;
intf = &conn->intf;
switch (conn->state) {
case XMPP_STATE_CONNECTING:
@@ -442,7 +245,7 @@ next_item:
/* Check if there is something in the SSL buffer. */
if (conn->tls)
tls_read_bytes += tls_pending(conn->tls);
tls_read_bytes += tls_pending(intf);
if (conn->state != XMPP_STATE_DISCONNECTED && conn->sock > max)
max = conn->sock;
@@ -461,9 +264,9 @@ next_item:
/* select errored */
if (ret < 0) {
if (!sock_is_recoverable(sock_error()))
if (!sock_is_recoverable(NULL, sock_error(NULL)))
strophe_error(ctx, "xmpp", "event watcher internal error %d",
sock_error());
sock_error(NULL));
return;
}
@@ -475,6 +278,7 @@ next_item:
connitem = ctx->connlist;
while (connitem) {
conn = connitem->conn;
intf = &conn->intf;
switch (conn->state) {
case XMPP_STATE_CONNECTING:
@@ -502,9 +306,9 @@ next_item:
break;
case XMPP_STATE_CONNECTED:
if (FD_ISSET(conn->sock, &rfds) || _conn_pending(conn)) {
if (FD_ISSET(conn->sock, &rfds) || intf->pending(intf)) {
ret = _conn_read(conn, buf, STROPHE_MESSAGE_BUFFER_SIZE);
ret = intf->read(intf, buf, STROPHE_MESSAGE_BUFFER_SIZE);
if (ret > 0) {
ret = parser_feed(conn->parser, buf, ret);
@@ -514,15 +318,13 @@ next_item:
"parse error");
}
} else {
if (conn->tls) {
if (!tls_is_recoverable(tls_error(conn->tls))) {
strophe_debug(ctx, "xmpp",
"Unrecoverable TLS error, %d.",
tls_error(conn->tls));
conn->error = tls_error(conn->tls);
conn_disconnect(conn);
}
} else {
int err = intf->get_error(intf);
if (!intf->error_is_recoverable(intf, err)) {
strophe_debug(ctx, "xmpp", "Unrecoverable error: %d.",
err);
conn->error = err;
conn_disconnect(conn);
} else if (!conn->tls) {
/* return of 0 means socket closed by server */
strophe_debug(ctx, "xmpp",
"Socket closed by remote host.");

View File

@@ -38,6 +38,18 @@
#include "common.h"
#include "resolver.h"
const struct conn_interface sock_intf = {
sock_read,
sock_write,
/* no flush */
conn_int_nop,
/* no pending */
conn_int_nop,
sock_error,
sock_is_recoverable,
NULL,
};
struct _xmpp_sock_t {
xmpp_ctx_t *ctx;
xmpp_conn_t *conn;
@@ -64,8 +76,9 @@ void sock_shutdown(void)
#endif
}
int sock_error(void)
int sock_error(struct conn_interface *intf)
{
UNUSED(intf);
#ifdef _WIN32
return WSAGetLastError();
#else
@@ -231,7 +244,7 @@ sock_t sock_connect(xmpp_sock_t *xsock)
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())) {
if (rc != 0 && !_in_progress(sock_error(NULL))) {
sock_close(sock);
sock = INVALID_SOCKET;
}
@@ -376,18 +389,19 @@ int sock_set_nonblocking(sock_t sock)
return _sock_set_blocking_mode(sock, 0);
}
int sock_read(sock_t sock, void *buff, size_t len)
int sock_read(struct conn_interface *intf, void *buff, size_t len)
{
return recv(sock, buff, len, 0);
return recv(intf->conn->sock, buff, len, 0);
}
int sock_write(sock_t sock, const void *buff, size_t len)
int sock_write(struct conn_interface *intf, const void *buff, size_t len)
{
return send(sock, buff, len, 0);
return send(intf->conn->sock, buff, len, 0);
}
int sock_is_recoverable(int error)
int sock_is_recoverable(struct conn_interface *intf, int error)
{
UNUSED(intf);
#ifdef _WIN32
return (error == WSAEINTR || error == WSAEWOULDBLOCK ||
error == WSAEINPROGRESS);
@@ -416,15 +430,15 @@ int sock_connect_error(sock_t sock)
/* it's possible that the error wasn't ENOTCONN, so if it wasn't,
* return that */
#ifdef _WIN32
if (sock_error() != WSAENOTCONN)
return sock_error();
if (sock_error(NULL) != WSAENOTCONN)
return sock_error(NULL);
#else
if (sock_error() != ENOTCONN)
return sock_error();
if (sock_error(NULL) != ENOTCONN)
return sock_error(NULL);
#endif
/* load the correct error into errno through error slippage */
recv(sock, &temp, 1, 0);
return sock_error();
return sock_error(NULL);
}

View File

@@ -30,12 +30,14 @@ typedef int sock_t;
typedef SOCKET sock_t;
#endif
extern const struct conn_interface sock_intf;
typedef struct _xmpp_sock_t xmpp_sock_t;
void sock_initialize(void);
void sock_shutdown(void);
int sock_error(void);
int sock_error(struct conn_interface *intf);
xmpp_sock_t *sock_new(xmpp_conn_t *conn,
const char *domain,
@@ -47,9 +49,9 @@ int sock_close(sock_t sock);
int sock_set_blocking(sock_t sock);
int sock_set_nonblocking(sock_t sock);
int sock_read(sock_t sock, void *buff, size_t len);
int sock_write(sock_t sock, const void *buff, size_t len);
int sock_is_recoverable(int error);
int sock_read(struct conn_interface *intf, void *buff, size_t len);
int sock_write(struct conn_interface *intf, const void *buff, size_t len);
int sock_is_recoverable(struct conn_interface *intf, int error);
/* checks for an error after connect, return 0 if connect successful */
int sock_connect_error(sock_t sock);
int sock_set_keepalive(sock_t sock,

View File

@@ -30,6 +30,17 @@
#include "common.h"
const struct conn_interface tls_intf = {
tls_read,
tls_write,
tls_clear_pending_write,
tls_pending,
tls_error,
tls_is_recoverable,
/* init conn */
NULL,
};
struct _dnsname_t {
char **data;
size_t cur, max;

View File

@@ -53,16 +53,16 @@ const void *tls_get_channel_binding_data(tls_t *tls, size_t *size);
int tls_start(tls_t *tls);
int tls_stop(tls_t *tls);
int tls_error(tls_t *tls);
int tls_pending(struct conn_interface *intf);
int tls_read(struct conn_interface *intf, void *buff, size_t len);
int tls_write(struct conn_interface *intf, const void *buff, size_t len);
int tls_clear_pending_write(struct conn_interface *intf);
int tls_pending(tls_t *tls);
int tls_read(tls_t *tls, void *buff, size_t len);
int tls_write(tls_t *tls, const void *buff, size_t len);
int tls_clear_pending_write(tls_t *tls);
int tls_is_recoverable(int error);
int tls_error(struct conn_interface *intf);
int tls_is_recoverable(struct conn_interface *intf, int error);
/* provided by tls.c */
extern const struct conn_interface tls_intf;
xmpp_tlscert_t *tlscert_new(xmpp_ctx_t *ctx);
int tlscert_add_dnsname(xmpp_tlscert_t *cert, const char *dnsname);

View File

@@ -104,43 +104,43 @@ int tls_stop(tls_t *tls)
return -1;
}
int tls_error(tls_t *tls)
int tls_error(struct conn_interface *intf)
{
UNUSED(tls);
/* todo: some kind of error polling/dump */
UNUSED(intf);
return 0;
}
int tls_pending(tls_t *tls)
int tls_pending(struct conn_interface *intf)
{
UNUSED(tls);
UNUSED(intf);
return 0;
}
int tls_read(tls_t *tls, void *buff, size_t len)
int tls_read(struct conn_interface *intf, void *buff, size_t len)
{
UNUSED(tls);
UNUSED(intf);
UNUSED(buff);
UNUSED(len);
return -1;
}
int tls_write(tls_t *tls, const void *buff, size_t len)
int tls_write(struct conn_interface *intf, const void *buff, size_t len)
{
UNUSED(tls);
UNUSED(intf);
UNUSED(buff);
UNUSED(len);
return -1;
}
int tls_clear_pending_write(tls_t *tls)
int tls_clear_pending_write(struct conn_interface *intf)
{
UNUSED(tls);
UNUSED(intf);
return -1;
}
int tls_is_recoverable(int error)
int tls_is_recoverable(struct conn_interface *intf, int error)
{
UNUSED(intf);
UNUSED(error);
return 0;
}

View File

@@ -633,24 +633,26 @@ int tls_stop(tls_t *tls)
return tls->lasterror == GNUTLS_E_SUCCESS;
}
int tls_error(tls_t *tls)
int tls_error(struct conn_interface *intf)
{
return tls->lasterror;
return intf->conn->tls->lasterror;
}
int tls_is_recoverable(int error)
int tls_is_recoverable(struct conn_interface *intf, int error)
{
UNUSED(intf);
return !gnutls_error_is_fatal(error);
}
int tls_pending(tls_t *tls)
int tls_pending(struct conn_interface *intf)
{
return gnutls_record_check_pending(tls->session);
return gnutls_record_check_pending(intf->conn->tls->session);
}
int tls_read(tls_t *tls, void *buff, size_t len)
int tls_read(struct conn_interface *intf, void *buff, size_t len)
{
int ret;
tls_t *tls = intf->conn->tls;
ret = gnutls_record_recv(tls->session, buff, len);
tls->lasterror = ret < 0 ? ret : 0;
@@ -658,9 +660,10 @@ int tls_read(tls_t *tls, void *buff, size_t len)
return ret;
}
int tls_write(tls_t *tls, const void *buff, size_t len)
int tls_write(struct conn_interface *intf, const void *buff, size_t len)
{
int ret;
tls_t *tls = intf->conn->tls;
ret = gnutls_record_send(tls->session, buff, len);
tls->lasterror = ret < 0 ? ret : 0;
@@ -668,8 +671,8 @@ int tls_write(tls_t *tls, const void *buff, size_t len)
return ret;
}
int tls_clear_pending_write(tls_t *tls)
int tls_clear_pending_write(struct conn_interface *intf)
{
UNUSED(tls);
UNUSED(intf);
return 0;
}

View File

@@ -283,9 +283,9 @@ void tls_shutdown(void)
#endif
}
int tls_error(tls_t *tls)
int tls_error(struct conn_interface *intf)
{
return tls->lasterror;
return intf->conn->tls->lasterror;
}
/** Search through the SubjectAlternativeNames and return the next
@@ -815,7 +815,7 @@ int tls_start(tls_t *tls)
ret = SSL_connect(tls->ssl);
error = ret <= 0 ? SSL_get_error(tls->ssl, ret) : 0;
if (ret == -1 && tls_is_recoverable(error)) {
if (ret == -1 && tls_is_recoverable(NULL, error)) {
/* wait for something to happen on the sock before looping back */
_tls_sock_wait(tls, error);
continue;
@@ -856,7 +856,7 @@ int tls_stop(tls_t *tls)
++retries;
ret = SSL_shutdown(tls->ssl);
error = ret < 0 ? SSL_get_error(tls->ssl, ret) : 0;
if (ret == 1 || !tls_is_recoverable(error) ||
if (ret == 1 || !tls_is_recoverable(NULL, error) ||
retries >= TLS_SHUTDOWN_MAX_RETRIES) {
break;
}
@@ -875,21 +875,23 @@ int tls_stop(tls_t *tls)
return ret <= 0 ? 0 : 1;
}
int tls_is_recoverable(int error)
int tls_is_recoverable(struct conn_interface *intf, int error)
{
UNUSED(intf);
return (error == SSL_ERROR_NONE || error == SSL_ERROR_WANT_READ ||
error == SSL_ERROR_WANT_WRITE || error == SSL_ERROR_WANT_CONNECT ||
error == SSL_ERROR_WANT_ACCEPT);
}
int tls_pending(tls_t *tls)
int tls_pending(struct conn_interface *intf)
{
return SSL_pending(tls->ssl);
return SSL_pending(intf->conn->tls->ssl);
}
int tls_read(tls_t *tls, void *buff, size_t len)
int tls_read(struct conn_interface *intf, void *buff, size_t len)
{
int ret;
tls_t *tls = intf->conn->tls;
ret = SSL_read(tls->ssl, buff, len);
_tls_set_error(tls, ret <= 0 ? SSL_get_error(tls->ssl, ret) : 0);
@@ -897,9 +899,10 @@ int tls_read(tls_t *tls, void *buff, size_t len)
return ret;
}
int tls_write(tls_t *tls, const void *buff, size_t len)
int tls_write(struct conn_interface *intf, const void *buff, size_t len)
{
int ret;
tls_t *tls = intf->conn->tls;
ret = SSL_write(tls->ssl, buff, len);
_tls_set_error(tls, ret <= 0 ? SSL_get_error(tls->ssl, ret) : 0);
@@ -907,9 +910,9 @@ int tls_write(tls_t *tls, const void *buff, size_t len)
return ret;
}
int tls_clear_pending_write(tls_t *tls)
int tls_clear_pending_write(struct conn_interface *intf)
{
UNUSED(tls);
UNUSED(intf);
return 0;
}
@@ -947,7 +950,7 @@ static const char *_tls_error_str(int error, const char **tbl, size_t tbl_size)
static void _tls_set_error(tls_t *tls, int error)
{
if (error != 0 && !tls_is_recoverable(error)) {
if (error != 0 && !tls_is_recoverable(NULL, error)) {
strophe_debug(tls->ctx, "tls", "error=%s(%d) errno=%d lasterror=%d",
TLS_ERROR_STR(error, tls_errors), error, errno,
tls->lasterror);

View File

@@ -262,9 +262,11 @@ int tls_start(tls_t *tls)
SECURITY_STATUS ret;
int sent;
char *name;
struct conn_interface *intf;
/* use the domain there as our name */
name = tls->conn->domain;
intf = tls->conn->intf;
ctxtreq = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT |
ISC_REQ_CONFIDENTIALITY | ISC_RET_EXTENDED_ERROR |
@@ -313,9 +315,9 @@ int tls_start(tls_t *tls)
unsigned char *writebuff = sbdout.pBuffers[0].pvBuffer;
unsigned int writelen = sbdout.pBuffers[0].cbBuffer;
sent = sock_write(tls->sock, writebuff, writelen);
sent = sock_write(intf, writebuff, writelen);
if (sent == -1) {
tls->lasterror = sock_error();
tls->lasterror = sock_error(intf);
} else {
writebuff += sent;
writelen -= sent;
@@ -353,13 +355,13 @@ int tls_start(tls_t *tls)
select(tls->sock, &fds, NULL, NULL, &tv);
inbytes = sock_read(tls->sock, p, tls->spi->cbMaxToken - len);
inbytes = sock_read(intf, p, tls->spi->cbMaxToken - len);
if (inbytes > 0) {
len += inbytes;
p += inbytes;
} else {
tls->lasterror = sock_error();
tls->lasterror = sock_error(intf);
}
}
@@ -374,9 +376,9 @@ int tls_start(tls_t *tls)
if (sbdout.pBuffers[0].cbBuffer) {
unsigned char *writebuff = sbdout.pBuffers[0].pvBuffer;
unsigned int writelen = sbdout.pBuffers[0].cbBuffer;
sent = sock_write(tls->sock, writebuff, writelen);
sent = sock_write(intf, writebuff, writelen);
if (sent == -1) {
tls->lasterror = sock_error();
tls->lasterror = sock_error(intf);
} else {
writebuff += sent;
writelen -= sent;
@@ -423,20 +425,22 @@ int tls_stop(tls_t *tls)
return -1;
}
int tls_error(tls_t *tls)
int tls_error(struct conn_interface *intf)
{
return tls->lasterror;
return intf->conn->tls->lasterror;
}
int tls_is_recoverable(int error)
int tls_is_recoverable(struct conn_interface *intf, int error)
{
UNUSED(intf);
return (error == SEC_E_OK || error == SEC_E_INCOMPLETE_MESSAGE ||
error == WSAEWOULDBLOCK || error == WSAEMSGSIZE ||
error == WSAEINPROGRESS);
}
int tls_pending(tls_t *tls)
int tls_pending(struct conn_interface *intf)
{
tls_t *tls = intf->conn->tls;
// There are 3 cases:
// - there is data in ready buffer, so it is by default pending
// - there is data in recv buffer. If it is not decrypted yet, means it
@@ -452,9 +456,10 @@ int tls_pending(tls_t *tls)
return 0;
}
int tls_read(tls_t *tls, void *buff, size_t len)
int tls_read(struct conn_interface *intf, void *buff, size_t len)
{
int bytes;
tls_t *tls = intf->conn->tls;
/* first, if we've got some ready data, put that in the buffer */
if (tls->readybufferpos < tls->readybufferlen) {
@@ -477,7 +482,7 @@ int tls_read(tls_t *tls, void *buff, size_t len)
read = tls_read(tls, newbuff, len - bytes);
if (read == -1) {
if (tls_is_recoverable(tls->lasterror)) {
if (tls_is_recoverable(intf, tls->lasterror)) {
return bytes;
}
@@ -489,7 +494,7 @@ int tls_read(tls_t *tls, void *buff, size_t len)
}
/* next, top up our recv buffer */
bytes = sock_read(tls->sock, tls->recvbuffer + tls->recvbufferpos,
bytes = sock_read(intf, tls->recvbuffer + tls->recvbufferpos,
tls->recvbuffermaxlen - tls->recvbufferpos);
if (bytes == 0) {
@@ -498,8 +503,8 @@ int tls_read(tls_t *tls, void *buff, size_t len)
}
if (bytes == -1) {
if (!tls_is_recoverable(sock_error())) {
tls->lasterror = sock_error();
if (!tls_is_recoverable(intf, sock_error(intf))) {
tls->lasterror = sock_error(intf);
return -1;
}
}
@@ -574,16 +579,17 @@ int tls_read(tls_t *tls, void *buff, size_t len)
return -1;
}
int tls_clear_pending_write(tls_t *tls)
int tls_clear_pending_write(struct conn_interface *intf)
{
tls_t *tls = intf->conn->tls;
if (tls->sendbufferpos < tls->sendbufferlen) {
int bytes;
bytes = sock_write(tls->sock, tls->sendbuffer + tls->sendbufferpos,
bytes = sock_write(intf, tls->sendbuffer + tls->sendbufferpos,
tls->sendbufferlen - tls->sendbufferpos);
if (bytes == -1) {
tls->lasterror = sock_error();
tls->lasterror = sock_error(intf);
return -1;
} else if (bytes > 0) {
tls->sendbufferpos += bytes;
@@ -597,12 +603,13 @@ int tls_clear_pending_write(tls_t *tls)
return 1;
}
int tls_write(tls_t *tls, const void *buff, size_t len)
int tls_write(struct conn_interface *intf, const void *buff, size_t len)
{
SecBufferDesc sbdenc;
SecBuffer sbenc[4];
const unsigned char *p = buff;
int sent = 0, ret, remain = len;
tls_t *tls = intf->conn->tls;
ret = tls_clear_pending_write(tls);
if (ret <= 0) {
@@ -662,7 +669,7 @@ int tls_write(tls_t *tls, const void *buff, size_t len)
ret = tls_clear_pending_write(tls);
if (ret == -1 && !tls_is_recoverable(tls_error(tls))) {
if (ret == -1 && !tls_is_recoverable(intf, tls_error(tls))) {
return -1;
}
@@ -674,7 +681,8 @@ int tls_write(tls_t *tls, const void *buff, size_t len)
remain = 0;
}
if (ret == 0 || (ret == -1 && tls_is_recoverable(tls_error(tls)))) {
if (ret == 0 ||
(ret == -1 && tls_is_recoverable(intf, tls_error(tls)))) {
return sent;
}
}

View File

@@ -88,6 +88,10 @@ extern "C" {
* Namespace definition for Stream Compression.
*/
#define XMPP_NS_COMPRESSION "http://jabber.org/protocol/compress"
/** @def XMPP_NS_FEATURE_COMPRESSION
* Namespace definition for Stream Compression.
*/
#define XMPP_NS_FEATURE_COMPRESSION "http://jabber.org/features/compress"
/* error defines */
/** @def XMPP_EOK
@@ -199,11 +203,11 @@ typedef struct _xmpp_sm_t xmpp_sm_state_t;
* Enable Stream-Compression XEP-0138.
*/
#define XMPP_CONN_FLAG_ENABLE_COMPRESSION (1UL << 6)
/** @def XMPP_CONN_FLAG_COMPRESSION_DONT_FLUSH
* Don't flush the compressed stream after each stanza.
/** @def XMPP_CONN_FLAG_COMPRESSION_DONT_RESET
* Don't reset the compressed stream after each stanza.
* Only enable this flag if you know what you're doing.
*/
#define XMPP_CONN_FLAG_COMPRESSION_DONT_FLUSH (1UL << 7)
#define XMPP_CONN_FLAG_COMPRESSION_DONT_RESET (1UL << 7)
/* connect callback */
typedef enum {