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..707053f8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -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])
diff --git a/examples/bot.c b/examples/bot.c
index bf10a028..7980053a 100644
--- a/examples/bot.c
+++ b/examples/bot.c
@@ -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))
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..2c9fc904 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,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;
@@ -250,12 +270,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..dc17bda1
--- /dev/null
+++ b/src/compression.c
@@ -0,0 +1,271 @@
+/* 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 _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;
+}
+
+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;
+ }
+}
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..5272d87c 100644
--- a/src/conn.c
+++ b/src/conn.c
@@ -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;
@@ -1757,14 +1778,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) {
diff --git a/src/event.c b/src/event.c
index 06f5cc11..e3a0c212 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(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;
@@ -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(NULL, 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(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.");
diff --git a/src/sock.c b/src/sock.c
index c18fa142..e5431343 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,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);
}
diff --git a/src/sock.h b/src/sock.h
index 9907f107..096ad9e7 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,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,
diff --git a/src/tls.c b/src/tls.c
index 9e7e18f3..c548d823 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,
+ tls_clear_pending_write,
+ tls_pending,
+ tls_error,
+ tls_is_recoverable,
+ /* init conn */
+ NULL,
+};
+
struct _dnsname_t {
char **data;
size_t cur, max;
diff --git a/src/tls.h b/src/tls.h
index 338b2421..79f1e544 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_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);
diff --git a/src/tls_dummy.c b/src/tls_dummy.c
index edd8e469..bb5e36d3 100644
--- a/src/tls_dummy.c
+++ b/src/tls_dummy.c
@@ -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;
}
diff --git a/src/tls_gnutls.c b/src/tls_gnutls.c
index 0e24bc53..a6c14cb2 100644
--- a/src/tls_gnutls.c
+++ b/src/tls_gnutls.c
@@ -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;
}
diff --git a/src/tls_openssl.c b/src/tls_openssl.c
index f82eefb0..3d84ee66 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
@@ -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);
diff --git a/src/tls_schannel.c b/src/tls_schannel.c
index f40c9e95..6463bbe5 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,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;
}
}
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 {