From 9f592a29db4e7b3eaff12b38613a879dd5c85306 Mon Sep 17 00:00:00 2001 From: Steffen Jaeckel Date: Fri, 26 Jan 2024 20:43:59 +0100 Subject: [PATCH] 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 --- Makefile.am | 6 + configure.ac | 1 + examples/bot.c | 17 ++- examples/complex.c | 8 +- src/auth.c | 45 ++++--- src/common.h | 33 +++-- src/compression.c | 266 ++++++++++++++++++++++++++++++++++++++++ src/compression_dummy.c | 36 ++++++ src/conn.c | 54 +++++--- src/event.c | 238 +++-------------------------------- src/sock.c | 35 ++++-- src/sock.h | 8 +- src/tls.c | 11 ++ src/tls.h | 12 +- src/tls_dummy.c | 21 ++-- src/tls_gnutls.c | 18 +-- src/tls_openssl.c | 18 +-- src/tls_schannel.c | 40 +++--- strophe.h | 10 +- 19 files changed, 537 insertions(+), 340 deletions(-) create mode 100644 src/compression.c create mode 100644 src/compression_dummy.c diff --git a/Makefile.am b/Makefile.am index dedd0f6b..9540b28f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -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 diff --git a/configure.ac b/configure.ac index 0973b49f..8af73e1c 100644 --- a/configure.ac +++ b/configure.ac @@ -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]) diff --git a/examples/bot.c b/examples/bot.c index bf10a028..74227f70 100644 --- a/examples/bot.c +++ b/examples/bot.c @@ -77,6 +77,13 @@ 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; @@ -103,7 +110,7 @@ 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; @@ -216,8 +223,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 +256,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)) diff --git a/examples/complex.c b/examples/complex.c index 393db32e..4f980f30 100644 --- a/examples/complex.c +++ b/examples/complex.c @@ -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) diff --git a/src/auth.c b/src/auth.c index fe42361d..b4b32f12 100644 --- a/src/auth.c +++ b/src/auth.c @@ -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); @@ -1057,6 +1041,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) { @@ -1067,7 +1053,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); @@ -1081,15 +1067,26 @@ static int _handle_features_compress(xmpp_conn_t *conn, { const char *compress = "zlib"; - - 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; } diff --git a/src/common.h b/src/common.h index bbb43d34..1a1a22ca 100644 --- a/src/common.h +++ b/src/common.h @@ -19,7 +19,6 @@ #include #include -#include #include "strophe.h" #include "ostypes.h" @@ -202,7 +201,29 @@ 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)(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 conn_recoverable_nop(int err); + +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; @@ -250,12 +271,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; diff --git a/src/compression.c b/src/compression.c new file mode 100644 index 00000000..9fac6c0a --- /dev/null +++ b/src/compression.c @@ -0,0 +1,266 @@ +/* SPDX-License-Identifier: MIT OR GPL-3.0-only */ +/* compression.c +** strophe XMPP client library -- XEP-0138 Stream Compression +** +** Copyright (C) 2024 Steffen Jaeckel +** +** 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 +#include +#include + +#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 +compression_read(struct conn_interface *intf, void *buff, size_t len); +static int +compression_write(struct conn_interface *intf, const void *buff, size_t len); +static int compression_flush(struct conn_interface *intf); +static int compression_pending(struct conn_interface *intf); + +const struct conn_interface compression_intf = { + compression_read, + compression_write, + compression_flush, + compression_pending, + /* no errors */ + conn_int_nop, + conn_recoverable_nop, + 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; + } +} + +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; + /* -fallthrough */ + 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; +} + +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; +} + +int compression_write(struct conn_interface *intf, const void *buff, size_t len) +{ + return _compression_write(intf->conn, buff, len, Z_NO_FLUSH); +} + +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); +} + +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); +} diff --git a/src/compression_dummy.c b/src/compression_dummy.c new file mode 100644 index 00000000..994ef6ba --- /dev/null +++ b/src/compression_dummy.c @@ -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 +** +** 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 +#include + +#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; +} diff --git a/src/conn.c b/src/conn.c index 7e005887..0fb18e6a 100644 --- a/src/conn.c +++ b/src/conn.c @@ -145,6 +145,9 @@ xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t *ctx) memset(conn, 0, sizeof(xmpp_conn_t)); conn->ctx = ctx; + conn->intf = sock_intf; + conn->intf.conn = conn; + conn->type = XMPP_UNKNOWN; conn->state = XMPP_STATE_DISCONNECTED; @@ -1062,6 +1065,29 @@ 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->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_recoverable_nop(int err) +{ + UNUSED(err); + return 1; +} + int conn_tls_start(xmpp_conn_t *conn) { int rc; @@ -1075,11 +1101,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 +1140,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 +1162,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 +1193,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; @@ -1757,14 +1787,8 @@ 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); + /* free queued */ sq = conn->send_queue_head; while (sq) { diff --git a/src/event.c b/src/event.c index 06f5cc11..a6e9cf9c 100644 --- a/src/event.c +++ b/src/event.c @@ -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(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; @@ -368,11 +174,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) { @@ -407,6 +209,7 @@ void xmpp_run_once(xmpp_ctx_t *ctx, unsigned long timeout) connitem = ctx->connlist; while (connitem) { conn = connitem->conn; + intf = &conn->intf; switch (conn->state) { case XMPP_STATE_CONNECTING: @@ -441,7 +244,7 @@ void xmpp_run_once(xmpp_ctx_t *ctx, unsigned long timeout) /* 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; @@ -460,9 +263,9 @@ void xmpp_run_once(xmpp_ctx_t *ctx, unsigned long timeout) /* select errored */ if (ret < 0) { - if (!sock_is_recoverable(sock_error())) + if (!sock_is_recoverable(sock_error(NULL))) strophe_error(ctx, "xmpp", "event watcher internal error %d", - sock_error()); + sock_error(NULL)); return; } @@ -474,6 +277,7 @@ void xmpp_run_once(xmpp_ctx_t *ctx, unsigned long timeout) connitem = ctx->connlist; while (connitem) { conn = connitem->conn; + intf = &conn->intf; switch (conn->state) { case XMPP_STATE_CONNECTING: @@ -501,9 +305,9 @@ void xmpp_run_once(xmpp_ctx_t *ctx, unsigned long timeout) 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); @@ -513,15 +317,13 @@ void xmpp_run_once(xmpp_ctx_t *ctx, unsigned long timeout) "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(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."); diff --git a/src/sock.c b/src/sock.c index c18fa142..3c76237e 100644 --- a/src/sock.c +++ b/src/sock.c @@ -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,14 +389,14 @@ 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) @@ -416,15 +429,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); } diff --git a/src/sock.h b/src/sock.h index 9907f107..ebfd48ec 100644 --- a/src/sock.h +++ b/src/sock.h @@ -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,8 +49,8 @@ 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_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(int error); /* checks for an error after connect, return 0 if connect successful */ int sock_connect_error(sock_t sock); diff --git a/src/tls.c b/src/tls.c index 9e7e18f3..c21698f7 100644 --- a/src/tls.c +++ b/src/tls.c @@ -30,6 +30,17 @@ #include "common.h" +const struct conn_interface tls_intf = { + tls_read, + tls_write, + /* no flush */ + conn_int_nop, + tls_pending, + tls_error, + tls_is_recoverable, + NULL, +}; + struct _dnsname_t { char **data; size_t cur, max; diff --git a/src/tls.h b/src/tls.h index 338b2421..5012fd74 100644 --- a/src/tls.h +++ b/src/tls.h @@ -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_error(struct conn_interface *intf); int tls_is_recoverable(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); diff --git a/src/tls_dummy.c b/src/tls_dummy.c index edd8e469..1282e25b 100644 --- a/src/tls_dummy.c +++ b/src/tls_dummy.c @@ -104,38 +104,37 @@ 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; } diff --git a/src/tls_gnutls.c b/src/tls_gnutls.c index 0e24bc53..6a782f49 100644 --- a/src/tls_gnutls.c +++ b/src/tls_gnutls.c @@ -633,9 +633,9 @@ 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) @@ -643,14 +643,15 @@ int tls_is_recoverable(int error) 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 +659,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 +670,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; } diff --git a/src/tls_openssl.c b/src/tls_openssl.c index f82eefb0..2287bb73 100644 --- a/src/tls_openssl.c +++ b/src/tls_openssl.c @@ -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 @@ -882,14 +882,15 @@ int tls_is_recoverable(int error) 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 +898,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 +909,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; } diff --git a/src/tls_schannel.c b/src/tls_schannel.c index f40c9e95..35202811 100644 --- a/src/tls_schannel.c +++ b/src/tls_schannel.c @@ -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,9 +425,9 @@ 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) @@ -435,8 +437,9 @@ int tls_is_recoverable(int error) 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 +455,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) { @@ -489,7 +493,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 +502,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(sock_error(intf))) { + tls->lasterror = sock_error(intf); return -1; } } @@ -574,16 +578,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 +602,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) { diff --git a/strophe.h b/strophe.h index c4a69461..e3b9b104 100644 --- a/strophe.h +++ b/strophe.h @@ -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 {