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:
@@ -85,6 +85,12 @@ if NEED_SNPRINTF
|
|||||||
libstrophe_la_SOURCES += src/snprintf.c
|
libstrophe_la_SOURCES += src/snprintf.c
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if DISABLE_COMPRESSION
|
||||||
|
libstrophe_la_SOURCES += src/compression_dummy.c
|
||||||
|
else
|
||||||
|
libstrophe_la_SOURCES += src/compression.c
|
||||||
|
endif
|
||||||
|
|
||||||
if DISABLE_TLS
|
if DISABLE_TLS
|
||||||
libstrophe_la_SOURCES += src/tls_dummy.c
|
libstrophe_la_SOURCES += src/tls_dummy.c
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -252,7 +252,7 @@ fi
|
|||||||
if test "x$enable_zlib" != xno; then
|
if test "x$enable_zlib" != xno; then
|
||||||
PKG_CHECK_MODULES([zlib], [zlib >= 1.2.0],
|
PKG_CHECK_MODULES([zlib], [zlib >= 1.2.0],
|
||||||
[
|
[
|
||||||
PC_REQUIRES="libzlib ${PC_REQUIRES}"
|
PC_REQUIRES="zlib ${PC_REQUIRES}"
|
||||||
ZLIB_CFLAGS=$zlib_CFLAGS
|
ZLIB_CFLAGS=$zlib_CFLAGS
|
||||||
ZLIB_LIBS=$zlib_LIBS
|
ZLIB_LIBS=$zlib_LIBS
|
||||||
AC_DEFINE([HAVE_ZLIB])
|
AC_DEFINE([HAVE_ZLIB])
|
||||||
@@ -269,6 +269,7 @@ m4_ifdef([PKG_INSTALLDIR], [PKG_INSTALLDIR],
|
|||||||
AC_SUBST([pkgconfigdir], [${with_pkgconfigdir}])])
|
AC_SUBST([pkgconfigdir], [${with_pkgconfigdir}])])
|
||||||
|
|
||||||
AM_CONDITIONAL([PARSER_EXPAT], [test x$with_parser != xlibxml2])
|
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_TLS], [test x$enable_tls = xno])
|
||||||
AM_CONDITIONAL([DISABLE_STATIC], [test x$enable_static = xno])
|
AM_CONDITIONAL([DISABLE_STATIC], [test x$enable_static = xno])
|
||||||
AM_CONDITIONAL([NEED_SNPRINTF], [test x$have_snprintf = xno])
|
AM_CONDITIONAL([NEED_SNPRINTF], [test x$have_snprintf = xno])
|
||||||
|
|||||||
@@ -77,13 +77,19 @@ int version_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
|
|||||||
return 1;
|
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)
|
int message_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
|
||||||
{
|
{
|
||||||
xmpp_ctx_t *ctx = (xmpp_ctx_t *)userdata;
|
xmpp_ctx_t *ctx = (xmpp_ctx_t *)userdata;
|
||||||
xmpp_stanza_t *body, *reply;
|
xmpp_stanza_t *body, *reply;
|
||||||
const char *type;
|
const char *type;
|
||||||
char *intext, *replytext;
|
char *intext, *replytext;
|
||||||
int quit = 0;
|
|
||||||
|
|
||||||
body = xmpp_stanza_get_child_by_name(stanza, "body");
|
body = xmpp_stanza_get_child_by_name(stanza, "body");
|
||||||
if (body == NULL)
|
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) {
|
if (strcmp(intext, "quit") == 0) {
|
||||||
replytext = strdup("bye!");
|
replytext = strdup("bye!");
|
||||||
quit = 1;
|
xmpp_timed_handler_add(conn, _quit_handler, 500, NULL);
|
||||||
} else if (strcmp(intext, "reconnect") == 0) {
|
} else if (strcmp(intext, "reconnect") == 0) {
|
||||||
replytext = strdup("alright, let's see what happens!");
|
replytext = strdup("alright, let's see what happens!");
|
||||||
reconnect = 1;
|
reconnect = 1;
|
||||||
quit = 1;
|
xmpp_timed_handler_add(conn, _quit_handler, 500, NULL);
|
||||||
} else {
|
} else {
|
||||||
replytext = (char *)malloc(strlen(" to you too!") + strlen(intext) + 1);
|
replytext = (char *)malloc(strlen(" to you too!") + strlen(intext) + 1);
|
||||||
strcpy(replytext, intext);
|
strcpy(replytext, intext);
|
||||||
@@ -120,9 +126,6 @@ int message_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
|
|||||||
xmpp_stanza_release(reply);
|
xmpp_stanza_release(reply);
|
||||||
free(replytext);
|
free(replytext);
|
||||||
|
|
||||||
if (quit)
|
|
||||||
xmpp_disconnect(conn);
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,8 +219,8 @@ static void usage(int exit_code)
|
|||||||
"Note: --disable-tls conflicts with --mandatory-tls or "
|
"Note: --disable-tls conflicts with --mandatory-tls or "
|
||||||
"--legacy-ssl\n"
|
"--legacy-ssl\n"
|
||||||
" --zlib Enable compression via zlib.\n"
|
" --zlib Enable compression via zlib.\n"
|
||||||
" --dont-flush When using zlib, don't flush after "
|
" --dont-reset When using zlib, don't do a full-flush "
|
||||||
"compression.\n");
|
"after compression.\n");
|
||||||
|
|
||||||
exit(exit_code);
|
exit(exit_code);
|
||||||
}
|
}
|
||||||
@@ -249,8 +252,8 @@ int main(int argc, char **argv)
|
|||||||
flags |= XMPP_CONN_FLAG_LEGACY_AUTH;
|
flags |= XMPP_CONN_FLAG_LEGACY_AUTH;
|
||||||
else if (strcmp(argv[i], "--zlib") == 0)
|
else if (strcmp(argv[i], "--zlib") == 0)
|
||||||
flags |= XMPP_CONN_FLAG_ENABLE_COMPRESSION;
|
flags |= XMPP_CONN_FLAG_ENABLE_COMPRESSION;
|
||||||
else if (strcmp(argv[i], "--dont-flush") == 0)
|
else if (strcmp(argv[i], "--dont-reset") == 0)
|
||||||
flags |= XMPP_CONN_FLAG_COMPRESSION_DONT_FLUSH;
|
flags |= XMPP_CONN_FLAG_COMPRESSION_DONT_RESET;
|
||||||
else if ((strcmp(argv[i], "--jid") == 0) && (++i < argc))
|
else if ((strcmp(argv[i], "--jid") == 0) && (++i < argc))
|
||||||
jid = argv[i];
|
jid = argv[i];
|
||||||
else if ((strcmp(argv[i], "--pass") == 0) && (++i < argc))
|
else if ((strcmp(argv[i], "--pass") == 0) && (++i < argc))
|
||||||
|
|||||||
@@ -240,8 +240,8 @@ static void usage(int exit_code)
|
|||||||
" --legacy-ssl Use old style SSL.\n"
|
" --legacy-ssl Use old style SSL.\n"
|
||||||
" --legacy-auth Allow legacy authentication.\n"
|
" --legacy-auth Allow legacy authentication.\n"
|
||||||
" --zlib Enable compression via zlib.\n"
|
" --zlib Enable compression via zlib.\n"
|
||||||
" --dont-flush When using zlib, don't flush after "
|
" --dont-reset When using zlib, don't do a full-flush "
|
||||||
"compression.\n"
|
"after compression.\n"
|
||||||
" --verbose Increase the verbosity level.\n"
|
" --verbose Increase the verbosity level.\n"
|
||||||
" --tcp-keepalive Configure TCP keepalive.\n\n"
|
" --tcp-keepalive Configure TCP keepalive.\n\n"
|
||||||
"Note: --disable-tls conflicts with --mandatory-tls or "
|
"Note: --disable-tls conflicts with --mandatory-tls or "
|
||||||
@@ -278,8 +278,8 @@ int main(int argc, char **argv)
|
|||||||
flags |= XMPP_CONN_FLAG_LEGACY_AUTH;
|
flags |= XMPP_CONN_FLAG_LEGACY_AUTH;
|
||||||
else if (strcmp(argv[i], "--zlib") == 0)
|
else if (strcmp(argv[i], "--zlib") == 0)
|
||||||
flags |= XMPP_CONN_FLAG_ENABLE_COMPRESSION;
|
flags |= XMPP_CONN_FLAG_ENABLE_COMPRESSION;
|
||||||
else if (strcmp(argv[i], "--dont-flush") == 0)
|
else if (strcmp(argv[i], "--dont-reset") == 0)
|
||||||
flags |= XMPP_CONN_FLAG_COMPRESSION_DONT_FLUSH;
|
flags |= XMPP_CONN_FLAG_COMPRESSION_DONT_RESET;
|
||||||
else if (strcmp(argv[i], "--verbose") == 0)
|
else if (strcmp(argv[i], "--verbose") == 0)
|
||||||
verbosity++;
|
verbosity++;
|
||||||
else if (strcmp(argv[i], "--tcp-keepalive") == 0)
|
else if (strcmp(argv[i], "--tcp-keepalive") == 0)
|
||||||
|
|||||||
45
src/auth.c
45
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
|
static int
|
||||||
_handle_features(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
|
_handle_features(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
|
||||||
{
|
{
|
||||||
xmpp_stanza_t *child, *children;
|
xmpp_stanza_t *child;
|
||||||
const char *ns;
|
|
||||||
char *text;
|
|
||||||
|
|
||||||
UNUSED(userdata);
|
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))
|
if (conn->sasl_support & ~(SASL_MASK_PLAIN | SASL_MASK_ANONYMOUS))
|
||||||
conn->sasl_support &= ~SASL_MASK_PLAIN;
|
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);
|
_auth(conn);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -371,7 +355,7 @@ _handle_sasl_result(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
|
|||||||
(char *)userdata);
|
(char *)userdata);
|
||||||
|
|
||||||
/* reset parser */
|
/* reset parser */
|
||||||
conn_prepare_reset(conn, conn->compression_allowed
|
conn_prepare_reset(conn, conn->compression.allowed
|
||||||
? _handle_open_compress
|
? _handle_open_compress
|
||||||
: _handle_open_sasl);
|
: _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);
|
const char *name = xmpp_stanza_get_name(stanza);
|
||||||
|
|
||||||
|
UNUSED(userdata);
|
||||||
|
|
||||||
if (!name)
|
if (!name)
|
||||||
return 0;
|
return 0;
|
||||||
if (strcmp(name, "compressed") == 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);
|
conn_prepare_reset(conn, _handle_open_sasl);
|
||||||
|
|
||||||
/* make compression effective */
|
/* make compression effective */
|
||||||
conn->compress = 1;
|
compression_init(conn);
|
||||||
|
|
||||||
/* send stream tag */
|
/* send stream tag */
|
||||||
conn_open_stream(conn);
|
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
|
const char *compress = "<compress xmlns='" XMPP_NS_COMPRESSION
|
||||||
"'><method>zlib</method></compress>";
|
"'><method>zlib</method></compress>";
|
||||||
|
xmpp_stanza_t *child;
|
||||||
UNUSED(userdata);
|
|
||||||
|
|
||||||
/* remove missing features handler */
|
/* remove missing features handler */
|
||||||
xmpp_timed_handler_delete(conn, _handle_missing_features);
|
xmpp_timed_handler_delete(conn, _handle_missing_features);
|
||||||
|
|
||||||
send_raw(conn, compress, strlen(compress), XMPP_QUEUE_STROPHE, NULL);
|
/* check for compression */
|
||||||
handler_add(conn, _handle_compress_result, XMPP_NS_COMPRESSION, NULL, NULL,
|
child = xmpp_stanza_get_child_by_name_and_ns(stanza, "compression",
|
||||||
NULL);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
32
src/common.h
32
src/common.h
@@ -19,7 +19,6 @@
|
|||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <zlib.h>
|
|
||||||
|
|
||||||
#include "strophe.h"
|
#include "strophe.h"
|
||||||
#include "ostypes.h"
|
#include "ostypes.h"
|
||||||
@@ -208,7 +207,28 @@ struct _xmpp_sm_t {
|
|||||||
xmpp_stanza_t *bind;
|
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 _xmpp_conn_t {
|
||||||
|
struct conn_interface intf;
|
||||||
|
|
||||||
unsigned int ref;
|
unsigned int ref;
|
||||||
xmpp_ctx_t *ctx;
|
xmpp_ctx_t *ctx;
|
||||||
xmpp_conn_type_t type;
|
xmpp_conn_type_t type;
|
||||||
@@ -256,12 +276,10 @@ struct _xmpp_conn_t {
|
|||||||
int sm_disable;
|
int sm_disable;
|
||||||
xmpp_sm_state_t *sm_state;
|
xmpp_sm_state_t *sm_state;
|
||||||
|
|
||||||
int compression_allowed, compression_supported;
|
struct {
|
||||||
int compress, compression_dont_flush;
|
struct xmpp_compression *state;
|
||||||
struct zlib_compression {
|
int allowed, supported, dont_reset;
|
||||||
void *buffer, *buffer_end;
|
} compression;
|
||||||
z_stream stream;
|
|
||||||
} compression, decompression;
|
|
||||||
|
|
||||||
char *lang;
|
char *lang;
|
||||||
char *domain;
|
char *domain;
|
||||||
|
|||||||
270
src/compression.c
Normal file
270
src/compression.c
Normal 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
36
src/compression_dummy.c
Normal 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;
|
||||||
|
}
|
||||||
48
src/conn.c
48
src/conn.c
@@ -1062,6 +1062,23 @@ void conn_open_stream(xmpp_conn_t *conn)
|
|||||||
strophe_free(conn->ctx, from);
|
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 conn_tls_start(xmpp_conn_t *conn)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
@@ -1075,11 +1092,13 @@ int conn_tls_start(xmpp_conn_t *conn)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (conn->tls != NULL) {
|
if (conn->tls != NULL) {
|
||||||
|
conn->intf = tls_intf;
|
||||||
|
conn->intf.conn = conn;
|
||||||
if (tls_start(conn->tls)) {
|
if (tls_start(conn->tls)) {
|
||||||
conn->secured = 1;
|
conn->secured = 1;
|
||||||
} else {
|
} else {
|
||||||
rc = XMPP_EINT;
|
rc = XMPP_EINT;
|
||||||
conn->error = tls_error(conn->tls);
|
conn->error = tls_error(&conn->intf);
|
||||||
tls_free(conn->tls);
|
tls_free(conn->tls);
|
||||||
conn->tls = NULL;
|
conn->tls = NULL;
|
||||||
conn->tls_failed = 1;
|
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_LEGACY_SSL * conn->tls_legacy_ssl |
|
||||||
XMPP_CONN_FLAG_TRUST_TLS * conn->tls_trust |
|
XMPP_CONN_FLAG_TRUST_TLS * conn->tls_trust |
|
||||||
XMPP_CONN_FLAG_DISABLE_SM * conn->sm_disable |
|
XMPP_CONN_FLAG_DISABLE_SM * conn->sm_disable |
|
||||||
XMPP_CONN_FLAG_ENABLE_COMPRESSION * conn->compression_allowed |
|
XMPP_CONN_FLAG_ENABLE_COMPRESSION * conn->compression.allowed |
|
||||||
XMPP_CONN_FLAG_COMPRESSION_DONT_FLUSH * conn->compression_dont_flush |
|
XMPP_CONN_FLAG_COMPRESSION_DONT_RESET * conn->compression.dont_reset |
|
||||||
XMPP_CONN_FLAG_LEGACY_AUTH * conn->auth_legacy_enabled;
|
XMPP_CONN_FLAG_LEGACY_AUTH * conn->auth_legacy_enabled;
|
||||||
|
|
||||||
return flags;
|
return flags;
|
||||||
@@ -1134,6 +1153,8 @@ long xmpp_conn_get_flags(const xmpp_conn_t *conn)
|
|||||||
* - XMPP_CONN_FLAG_TRUST_TLS
|
* - XMPP_CONN_FLAG_TRUST_TLS
|
||||||
* - XMPP_CONN_FLAG_LEGACY_AUTH
|
* - XMPP_CONN_FLAG_LEGACY_AUTH
|
||||||
* - XMPP_CONN_FLAG_DISABLE_SM
|
* - XMPP_CONN_FLAG_DISABLE_SM
|
||||||
|
* - XMPP_CONN_FLAG_ENABLE_COMPRESSION
|
||||||
|
* - XMPP_CONN_FLAG_COMPRESSION_DONT_RESET
|
||||||
*
|
*
|
||||||
* @param conn a Strophe connection object
|
* @param conn a Strophe connection object
|
||||||
* @param flags ORed connection flags
|
* @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->tls_trust = (flags & XMPP_CONN_FLAG_TRUST_TLS) ? 1 : 0;
|
||||||
conn->auth_legacy_enabled = (flags & XMPP_CONN_FLAG_LEGACY_AUTH) ? 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->sm_disable = (flags & XMPP_CONN_FLAG_DISABLE_SM) ? 1 : 0;
|
||||||
conn->compression_allowed =
|
conn->compression.allowed =
|
||||||
(flags & XMPP_CONN_FLAG_ENABLE_COMPRESSION) ? 1 : 0;
|
(flags & XMPP_CONN_FLAG_ENABLE_COMPRESSION) ? 1 : 0;
|
||||||
conn->compression_dont_flush =
|
conn->compression.dont_reset =
|
||||||
(flags & XMPP_CONN_FLAG_COMPRESSION_DONT_FLUSH) ? 1 : 0;
|
(flags & XMPP_CONN_FLAG_COMPRESSION_DONT_RESET) ? 1 : 0;
|
||||||
flags &= ~(XMPP_CONN_FLAG_DISABLE_TLS | XMPP_CONN_FLAG_MANDATORY_TLS |
|
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_SSL | XMPP_CONN_FLAG_TRUST_TLS |
|
||||||
XMPP_CONN_FLAG_LEGACY_AUTH | XMPP_CONN_FLAG_DISABLE_SM |
|
XMPP_CONN_FLAG_LEGACY_AUTH | XMPP_CONN_FLAG_DISABLE_SM |
|
||||||
XMPP_CONN_FLAG_ENABLE_COMPRESSION |
|
XMPP_CONN_FLAG_ENABLE_COMPRESSION |
|
||||||
XMPP_CONN_FLAG_COMPRESSION_DONT_FLUSH);
|
XMPP_CONN_FLAG_COMPRESSION_DONT_RESET);
|
||||||
if (flags) {
|
if (flags) {
|
||||||
strophe_error(conn->ctx, "conn", "Flags 0x%04lx unknown", flags);
|
strophe_error(conn->ctx, "conn", "Flags 0x%04lx unknown", flags);
|
||||||
return XMPP_EINVOP;
|
return XMPP_EINVOP;
|
||||||
@@ -1768,14 +1789,11 @@ static void _conn_reset(xmpp_conn_t *conn)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (conn->compression.buffer) {
|
compression_free(conn);
|
||||||
deflateEnd(&conn->compression.stream);
|
|
||||||
strophe_free_and_null(ctx, conn->compression.buffer);
|
conn->intf = sock_intf;
|
||||||
}
|
conn->intf.conn = conn;
|
||||||
if (conn->decompression.buffer) {
|
|
||||||
inflateEnd(&conn->decompression.stream);
|
|
||||||
strophe_free_and_null(ctx, conn->decompression.buffer);
|
|
||||||
}
|
|
||||||
/* free queued */
|
/* free queued */
|
||||||
sq = conn->send_queue_head;
|
sq = conn->send_queue_head;
|
||||||
while (sq) {
|
while (sq) {
|
||||||
|
|||||||
238
src/event.c
238
src/event.c
@@ -75,202 +75,6 @@ static int _connect_next(xmpp_conn_t *conn)
|
|||||||
return 0;
|
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.
|
/** Run the event loop once.
|
||||||
* This function will run send any data that has been queued by
|
* This function will run send any data that has been queued by
|
||||||
* xmpp_send and related functions and run through the Strophe even
|
* 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_connlist_t *connitem;
|
||||||
xmpp_conn_t *conn;
|
xmpp_conn_t *conn;
|
||||||
|
struct conn_interface *intf;
|
||||||
fd_set rfds, wfds;
|
fd_set rfds, wfds;
|
||||||
sock_t max = 0;
|
sock_t max = 0;
|
||||||
int ret;
|
int ret;
|
||||||
@@ -310,13 +115,14 @@ void xmpp_run_once(xmpp_ctx_t *ctx, unsigned long timeout)
|
|||||||
connitem = connitem->next;
|
connitem = connitem->next;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
intf = &conn->intf;
|
||||||
|
|
||||||
/* if we're running tls, there may be some remaining data waiting to
|
/* if we're running tls, there may be some remaining data waiting to
|
||||||
* be sent, so push that out */
|
* be sent, so push that out */
|
||||||
if (conn->tls) {
|
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 */
|
/* an error occurred */
|
||||||
strophe_debug(
|
strophe_debug(
|
||||||
ctx, "xmpp",
|
ctx, "xmpp",
|
||||||
@@ -332,7 +138,7 @@ void xmpp_run_once(xmpp_ctx_t *ctx, unsigned long timeout)
|
|||||||
while (sq) {
|
while (sq) {
|
||||||
towrite = sq->len - sq->written;
|
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)
|
if (ret > 0 && ret < towrite)
|
||||||
sq->written += ret; /* not all data could be sent now */
|
sq->written += ret; /* not all data could be sent now */
|
||||||
sq->wip = 1;
|
sq->wip = 1;
|
||||||
@@ -369,11 +175,7 @@ void xmpp_run_once(xmpp_ctx_t *ctx, unsigned long timeout)
|
|||||||
if (!sq)
|
if (!sq)
|
||||||
conn->send_queue_tail = NULL;
|
conn->send_queue_tail = NULL;
|
||||||
}
|
}
|
||||||
if (conn->compress) {
|
intf->flush(intf);
|
||||||
_conn_compress(conn, conn->compression.buffer, 0,
|
|
||||||
conn->compression_dont_flush ? Z_SYNC_FLUSH
|
|
||||||
: Z_FULL_FLUSH);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* tear down connection on error */
|
/* tear down connection on error */
|
||||||
if (conn->error) {
|
if (conn->error) {
|
||||||
@@ -408,6 +210,7 @@ next_item:
|
|||||||
connitem = ctx->connlist;
|
connitem = ctx->connlist;
|
||||||
while (connitem) {
|
while (connitem) {
|
||||||
conn = connitem->conn;
|
conn = connitem->conn;
|
||||||
|
intf = &conn->intf;
|
||||||
|
|
||||||
switch (conn->state) {
|
switch (conn->state) {
|
||||||
case XMPP_STATE_CONNECTING:
|
case XMPP_STATE_CONNECTING:
|
||||||
@@ -442,7 +245,7 @@ next_item:
|
|||||||
|
|
||||||
/* Check if there is something in the SSL buffer. */
|
/* Check if there is something in the SSL buffer. */
|
||||||
if (conn->tls)
|
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)
|
if (conn->state != XMPP_STATE_DISCONNECTED && conn->sock > max)
|
||||||
max = conn->sock;
|
max = conn->sock;
|
||||||
@@ -461,9 +264,9 @@ next_item:
|
|||||||
|
|
||||||
/* select errored */
|
/* select errored */
|
||||||
if (ret < 0) {
|
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",
|
strophe_error(ctx, "xmpp", "event watcher internal error %d",
|
||||||
sock_error());
|
sock_error(NULL));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -475,6 +278,7 @@ next_item:
|
|||||||
connitem = ctx->connlist;
|
connitem = ctx->connlist;
|
||||||
while (connitem) {
|
while (connitem) {
|
||||||
conn = connitem->conn;
|
conn = connitem->conn;
|
||||||
|
intf = &conn->intf;
|
||||||
|
|
||||||
switch (conn->state) {
|
switch (conn->state) {
|
||||||
case XMPP_STATE_CONNECTING:
|
case XMPP_STATE_CONNECTING:
|
||||||
@@ -502,9 +306,9 @@ next_item:
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
case XMPP_STATE_CONNECTED:
|
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) {
|
if (ret > 0) {
|
||||||
ret = parser_feed(conn->parser, buf, ret);
|
ret = parser_feed(conn->parser, buf, ret);
|
||||||
@@ -514,15 +318,13 @@ next_item:
|
|||||||
"parse error");
|
"parse error");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (conn->tls) {
|
int err = intf->get_error(intf);
|
||||||
if (!tls_is_recoverable(tls_error(conn->tls))) {
|
if (!intf->error_is_recoverable(intf, err)) {
|
||||||
strophe_debug(ctx, "xmpp",
|
strophe_debug(ctx, "xmpp", "Unrecoverable error: %d.",
|
||||||
"Unrecoverable TLS error, %d.",
|
err);
|
||||||
tls_error(conn->tls));
|
conn->error = err;
|
||||||
conn->error = tls_error(conn->tls);
|
conn_disconnect(conn);
|
||||||
conn_disconnect(conn);
|
} else if (!conn->tls) {
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* return of 0 means socket closed by server */
|
/* return of 0 means socket closed by server */
|
||||||
strophe_debug(ctx, "xmpp",
|
strophe_debug(ctx, "xmpp",
|
||||||
"Socket closed by remote host.");
|
"Socket closed by remote host.");
|
||||||
|
|||||||
38
src/sock.c
38
src/sock.c
@@ -38,6 +38,18 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "resolver.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 {
|
struct _xmpp_sock_t {
|
||||||
xmpp_ctx_t *ctx;
|
xmpp_ctx_t *ctx;
|
||||||
xmpp_conn_t *conn;
|
xmpp_conn_t *conn;
|
||||||
@@ -64,8 +76,9 @@ void sock_shutdown(void)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int sock_error(void)
|
int sock_error(struct conn_interface *intf)
|
||||||
{
|
{
|
||||||
|
UNUSED(intf);
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
return WSAGetLastError();
|
return WSAGetLastError();
|
||||||
#else
|
#else
|
||||||
@@ -231,7 +244,7 @@ sock_t sock_connect(xmpp_sock_t *xsock)
|
|||||||
if (rc == 0)
|
if (rc == 0)
|
||||||
rc = connect(sock, ainfo->ai_addr, ainfo->ai_addrlen);
|
rc = connect(sock, ainfo->ai_addr, ainfo->ai_addrlen);
|
||||||
/* Assume only connect() can cause "in progress" error. */
|
/* 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_close(sock);
|
||||||
sock = INVALID_SOCKET;
|
sock = INVALID_SOCKET;
|
||||||
}
|
}
|
||||||
@@ -376,18 +389,19 @@ int sock_set_nonblocking(sock_t sock)
|
|||||||
return _sock_set_blocking_mode(sock, 0);
|
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
|
#ifdef _WIN32
|
||||||
return (error == WSAEINTR || error == WSAEWOULDBLOCK ||
|
return (error == WSAEINTR || error == WSAEWOULDBLOCK ||
|
||||||
error == WSAEINPROGRESS);
|
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,
|
/* it's possible that the error wasn't ENOTCONN, so if it wasn't,
|
||||||
* return that */
|
* return that */
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
if (sock_error() != WSAENOTCONN)
|
if (sock_error(NULL) != WSAENOTCONN)
|
||||||
return sock_error();
|
return sock_error(NULL);
|
||||||
#else
|
#else
|
||||||
if (sock_error() != ENOTCONN)
|
if (sock_error(NULL) != ENOTCONN)
|
||||||
return sock_error();
|
return sock_error(NULL);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* load the correct error into errno through error slippage */
|
/* load the correct error into errno through error slippage */
|
||||||
recv(sock, &temp, 1, 0);
|
recv(sock, &temp, 1, 0);
|
||||||
|
|
||||||
return sock_error();
|
return sock_error(NULL);
|
||||||
}
|
}
|
||||||
|
|||||||
10
src/sock.h
10
src/sock.h
@@ -30,12 +30,14 @@ typedef int sock_t;
|
|||||||
typedef SOCKET sock_t;
|
typedef SOCKET sock_t;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
extern const struct conn_interface sock_intf;
|
||||||
|
|
||||||
typedef struct _xmpp_sock_t xmpp_sock_t;
|
typedef struct _xmpp_sock_t xmpp_sock_t;
|
||||||
|
|
||||||
void sock_initialize(void);
|
void sock_initialize(void);
|
||||||
void sock_shutdown(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,
|
xmpp_sock_t *sock_new(xmpp_conn_t *conn,
|
||||||
const char *domain,
|
const char *domain,
|
||||||
@@ -47,9 +49,9 @@ int sock_close(sock_t sock);
|
|||||||
|
|
||||||
int sock_set_blocking(sock_t sock);
|
int sock_set_blocking(sock_t sock);
|
||||||
int sock_set_nonblocking(sock_t sock);
|
int sock_set_nonblocking(sock_t sock);
|
||||||
int sock_read(sock_t sock, void *buff, size_t len);
|
int sock_read(struct conn_interface *intf, void *buff, size_t len);
|
||||||
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);
|
||||||
int sock_is_recoverable(int error);
|
int sock_is_recoverable(struct conn_interface *intf, int error);
|
||||||
/* checks for an error after connect, return 0 if connect successful */
|
/* checks for an error after connect, return 0 if connect successful */
|
||||||
int sock_connect_error(sock_t sock);
|
int sock_connect_error(sock_t sock);
|
||||||
int sock_set_keepalive(sock_t sock,
|
int sock_set_keepalive(sock_t sock,
|
||||||
|
|||||||
11
src/tls.c
11
src/tls.c
@@ -30,6 +30,17 @@
|
|||||||
|
|
||||||
#include "common.h"
|
#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 {
|
struct _dnsname_t {
|
||||||
char **data;
|
char **data;
|
||||||
size_t cur, max;
|
size_t cur, max;
|
||||||
|
|||||||
14
src/tls.h
14
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_start(tls_t *tls);
|
||||||
int tls_stop(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_error(struct conn_interface *intf);
|
||||||
int tls_read(tls_t *tls, void *buff, size_t len);
|
int tls_is_recoverable(struct conn_interface *intf, int error);
|
||||||
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);
|
|
||||||
|
|
||||||
/* provided by tls.c */
|
/* provided by tls.c */
|
||||||
|
extern const struct conn_interface tls_intf;
|
||||||
|
|
||||||
xmpp_tlscert_t *tlscert_new(xmpp_ctx_t *ctx);
|
xmpp_tlscert_t *tlscert_new(xmpp_ctx_t *ctx);
|
||||||
int tlscert_add_dnsname(xmpp_tlscert_t *cert, const char *dnsname);
|
int tlscert_add_dnsname(xmpp_tlscert_t *cert, const char *dnsname);
|
||||||
|
|||||||
@@ -104,43 +104,43 @@ int tls_stop(tls_t *tls)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tls_error(tls_t *tls)
|
int tls_error(struct conn_interface *intf)
|
||||||
{
|
{
|
||||||
UNUSED(tls);
|
UNUSED(intf);
|
||||||
/* todo: some kind of error polling/dump */
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tls_pending(tls_t *tls)
|
int tls_pending(struct conn_interface *intf)
|
||||||
{
|
{
|
||||||
UNUSED(tls);
|
UNUSED(intf);
|
||||||
return 0;
|
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(buff);
|
||||||
UNUSED(len);
|
UNUSED(len);
|
||||||
return -1;
|
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(buff);
|
||||||
UNUSED(len);
|
UNUSED(len);
|
||||||
return -1;
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tls_is_recoverable(int error)
|
int tls_is_recoverable(struct conn_interface *intf, int error)
|
||||||
{
|
{
|
||||||
|
UNUSED(intf);
|
||||||
UNUSED(error);
|
UNUSED(error);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -633,24 +633,26 @@ int tls_stop(tls_t *tls)
|
|||||||
return tls->lasterror == GNUTLS_E_SUCCESS;
|
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);
|
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;
|
int ret;
|
||||||
|
tls_t *tls = intf->conn->tls;
|
||||||
|
|
||||||
ret = gnutls_record_recv(tls->session, buff, len);
|
ret = gnutls_record_recv(tls->session, buff, len);
|
||||||
tls->lasterror = ret < 0 ? ret : 0;
|
tls->lasterror = ret < 0 ? ret : 0;
|
||||||
@@ -658,9 +660,10 @@ int tls_read(tls_t *tls, void *buff, size_t len)
|
|||||||
return ret;
|
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;
|
int ret;
|
||||||
|
tls_t *tls = intf->conn->tls;
|
||||||
|
|
||||||
ret = gnutls_record_send(tls->session, buff, len);
|
ret = gnutls_record_send(tls->session, buff, len);
|
||||||
tls->lasterror = ret < 0 ? ret : 0;
|
tls->lasterror = ret < 0 ? ret : 0;
|
||||||
@@ -668,8 +671,8 @@ int tls_write(tls_t *tls, const void *buff, size_t len)
|
|||||||
return ret;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -283,9 +283,9 @@ void tls_shutdown(void)
|
|||||||
#endif
|
#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
|
/** Search through the SubjectAlternativeNames and return the next
|
||||||
@@ -815,7 +815,7 @@ int tls_start(tls_t *tls)
|
|||||||
ret = SSL_connect(tls->ssl);
|
ret = SSL_connect(tls->ssl);
|
||||||
error = ret <= 0 ? SSL_get_error(tls->ssl, ret) : 0;
|
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 */
|
/* wait for something to happen on the sock before looping back */
|
||||||
_tls_sock_wait(tls, error);
|
_tls_sock_wait(tls, error);
|
||||||
continue;
|
continue;
|
||||||
@@ -856,7 +856,7 @@ int tls_stop(tls_t *tls)
|
|||||||
++retries;
|
++retries;
|
||||||
ret = SSL_shutdown(tls->ssl);
|
ret = SSL_shutdown(tls->ssl);
|
||||||
error = ret < 0 ? SSL_get_error(tls->ssl, ret) : 0;
|
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) {
|
retries >= TLS_SHUTDOWN_MAX_RETRIES) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -875,21 +875,23 @@ int tls_stop(tls_t *tls)
|
|||||||
return ret <= 0 ? 0 : 1;
|
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 ||
|
return (error == SSL_ERROR_NONE || error == SSL_ERROR_WANT_READ ||
|
||||||
error == SSL_ERROR_WANT_WRITE || error == SSL_ERROR_WANT_CONNECT ||
|
error == SSL_ERROR_WANT_WRITE || error == SSL_ERROR_WANT_CONNECT ||
|
||||||
error == SSL_ERROR_WANT_ACCEPT);
|
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;
|
int ret;
|
||||||
|
tls_t *tls = intf->conn->tls;
|
||||||
|
|
||||||
ret = SSL_read(tls->ssl, buff, len);
|
ret = SSL_read(tls->ssl, buff, len);
|
||||||
_tls_set_error(tls, ret <= 0 ? SSL_get_error(tls->ssl, ret) : 0);
|
_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;
|
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;
|
int ret;
|
||||||
|
tls_t *tls = intf->conn->tls;
|
||||||
|
|
||||||
ret = SSL_write(tls->ssl, buff, len);
|
ret = SSL_write(tls->ssl, buff, len);
|
||||||
_tls_set_error(tls, ret <= 0 ? SSL_get_error(tls->ssl, ret) : 0);
|
_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;
|
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;
|
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)
|
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",
|
strophe_debug(tls->ctx, "tls", "error=%s(%d) errno=%d lasterror=%d",
|
||||||
TLS_ERROR_STR(error, tls_errors), error, errno,
|
TLS_ERROR_STR(error, tls_errors), error, errno,
|
||||||
tls->lasterror);
|
tls->lasterror);
|
||||||
|
|||||||
@@ -262,9 +262,11 @@ int tls_start(tls_t *tls)
|
|||||||
SECURITY_STATUS ret;
|
SECURITY_STATUS ret;
|
||||||
int sent;
|
int sent;
|
||||||
char *name;
|
char *name;
|
||||||
|
struct conn_interface *intf;
|
||||||
|
|
||||||
/* use the domain there as our name */
|
/* use the domain there as our name */
|
||||||
name = tls->conn->domain;
|
name = tls->conn->domain;
|
||||||
|
intf = tls->conn->intf;
|
||||||
|
|
||||||
ctxtreq = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT |
|
ctxtreq = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT |
|
||||||
ISC_REQ_CONFIDENTIALITY | ISC_RET_EXTENDED_ERROR |
|
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 char *writebuff = sbdout.pBuffers[0].pvBuffer;
|
||||||
unsigned int writelen = sbdout.pBuffers[0].cbBuffer;
|
unsigned int writelen = sbdout.pBuffers[0].cbBuffer;
|
||||||
|
|
||||||
sent = sock_write(tls->sock, writebuff, writelen);
|
sent = sock_write(intf, writebuff, writelen);
|
||||||
if (sent == -1) {
|
if (sent == -1) {
|
||||||
tls->lasterror = sock_error();
|
tls->lasterror = sock_error(intf);
|
||||||
} else {
|
} else {
|
||||||
writebuff += sent;
|
writebuff += sent;
|
||||||
writelen -= sent;
|
writelen -= sent;
|
||||||
@@ -353,13 +355,13 @@ int tls_start(tls_t *tls)
|
|||||||
|
|
||||||
select(tls->sock, &fds, NULL, NULL, &tv);
|
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) {
|
if (inbytes > 0) {
|
||||||
len += inbytes;
|
len += inbytes;
|
||||||
p += inbytes;
|
p += inbytes;
|
||||||
} else {
|
} 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) {
|
if (sbdout.pBuffers[0].cbBuffer) {
|
||||||
unsigned char *writebuff = sbdout.pBuffers[0].pvBuffer;
|
unsigned char *writebuff = sbdout.pBuffers[0].pvBuffer;
|
||||||
unsigned int writelen = sbdout.pBuffers[0].cbBuffer;
|
unsigned int writelen = sbdout.pBuffers[0].cbBuffer;
|
||||||
sent = sock_write(tls->sock, writebuff, writelen);
|
sent = sock_write(intf, writebuff, writelen);
|
||||||
if (sent == -1) {
|
if (sent == -1) {
|
||||||
tls->lasterror = sock_error();
|
tls->lasterror = sock_error(intf);
|
||||||
} else {
|
} else {
|
||||||
writebuff += sent;
|
writebuff += sent;
|
||||||
writelen -= sent;
|
writelen -= sent;
|
||||||
@@ -423,20 +425,22 @@ int tls_stop(tls_t *tls)
|
|||||||
return -1;
|
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 ||
|
return (error == SEC_E_OK || error == SEC_E_INCOMPLETE_MESSAGE ||
|
||||||
error == WSAEWOULDBLOCK || error == WSAEMSGSIZE ||
|
error == WSAEWOULDBLOCK || error == WSAEMSGSIZE ||
|
||||||
error == WSAEINPROGRESS);
|
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 are 3 cases:
|
||||||
// - there is data in ready buffer, so it is by default pending
|
// - 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
|
// - 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;
|
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;
|
int bytes;
|
||||||
|
tls_t *tls = intf->conn->tls;
|
||||||
|
|
||||||
/* first, if we've got some ready data, put that in the buffer */
|
/* first, if we've got some ready data, put that in the buffer */
|
||||||
if (tls->readybufferpos < tls->readybufferlen) {
|
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);
|
read = tls_read(tls, newbuff, len - bytes);
|
||||||
|
|
||||||
if (read == -1) {
|
if (read == -1) {
|
||||||
if (tls_is_recoverable(tls->lasterror)) {
|
if (tls_is_recoverable(intf, tls->lasterror)) {
|
||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -489,7 +494,7 @@ int tls_read(tls_t *tls, void *buff, size_t len)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* next, top up our recv buffer */
|
/* 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);
|
tls->recvbuffermaxlen - tls->recvbufferpos);
|
||||||
|
|
||||||
if (bytes == 0) {
|
if (bytes == 0) {
|
||||||
@@ -498,8 +503,8 @@ int tls_read(tls_t *tls, void *buff, size_t len)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (bytes == -1) {
|
if (bytes == -1) {
|
||||||
if (!tls_is_recoverable(sock_error())) {
|
if (!tls_is_recoverable(intf, sock_error(intf))) {
|
||||||
tls->lasterror = sock_error();
|
tls->lasterror = sock_error(intf);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -574,16 +579,17 @@ int tls_read(tls_t *tls, void *buff, size_t len)
|
|||||||
return -1;
|
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) {
|
if (tls->sendbufferpos < tls->sendbufferlen) {
|
||||||
int bytes;
|
int bytes;
|
||||||
|
|
||||||
bytes = sock_write(tls->sock, tls->sendbuffer + tls->sendbufferpos,
|
bytes = sock_write(intf, tls->sendbuffer + tls->sendbufferpos,
|
||||||
tls->sendbufferlen - tls->sendbufferpos);
|
tls->sendbufferlen - tls->sendbufferpos);
|
||||||
|
|
||||||
if (bytes == -1) {
|
if (bytes == -1) {
|
||||||
tls->lasterror = sock_error();
|
tls->lasterror = sock_error(intf);
|
||||||
return -1;
|
return -1;
|
||||||
} else if (bytes > 0) {
|
} else if (bytes > 0) {
|
||||||
tls->sendbufferpos += bytes;
|
tls->sendbufferpos += bytes;
|
||||||
@@ -597,12 +603,13 @@ int tls_clear_pending_write(tls_t *tls)
|
|||||||
return 1;
|
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;
|
SecBufferDesc sbdenc;
|
||||||
SecBuffer sbenc[4];
|
SecBuffer sbenc[4];
|
||||||
const unsigned char *p = buff;
|
const unsigned char *p = buff;
|
||||||
int sent = 0, ret, remain = len;
|
int sent = 0, ret, remain = len;
|
||||||
|
tls_t *tls = intf->conn->tls;
|
||||||
|
|
||||||
ret = tls_clear_pending_write(tls);
|
ret = tls_clear_pending_write(tls);
|
||||||
if (ret <= 0) {
|
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);
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -674,7 +681,8 @@ int tls_write(tls_t *tls, const void *buff, size_t len)
|
|||||||
remain = 0;
|
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;
|
return sent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
10
strophe.h
10
strophe.h
@@ -88,6 +88,10 @@ extern "C" {
|
|||||||
* Namespace definition for Stream Compression.
|
* Namespace definition for Stream Compression.
|
||||||
*/
|
*/
|
||||||
#define XMPP_NS_COMPRESSION "http://jabber.org/protocol/compress"
|
#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 */
|
/* error defines */
|
||||||
/** @def XMPP_EOK
|
/** @def XMPP_EOK
|
||||||
@@ -199,11 +203,11 @@ typedef struct _xmpp_sm_t xmpp_sm_state_t;
|
|||||||
* Enable Stream-Compression XEP-0138.
|
* Enable Stream-Compression XEP-0138.
|
||||||
*/
|
*/
|
||||||
#define XMPP_CONN_FLAG_ENABLE_COMPRESSION (1UL << 6)
|
#define XMPP_CONN_FLAG_ENABLE_COMPRESSION (1UL << 6)
|
||||||
/** @def XMPP_CONN_FLAG_COMPRESSION_DONT_FLUSH
|
/** @def XMPP_CONN_FLAG_COMPRESSION_DONT_RESET
|
||||||
* Don't flush the compressed stream after each stanza.
|
* Don't reset the compressed stream after each stanza.
|
||||||
* Only enable this flag if you know what you're doing.
|
* 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 */
|
/* connect callback */
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
|||||||
Reference in New Issue
Block a user