1 Commits

Author SHA1 Message Date
Dmitry Podgorny
b1698f7b5d WIP Initial server support 2017-07-15 21:38:38 +03:00
22 changed files with 587 additions and 361 deletions

1
.gitignore vendored
View File

@@ -35,6 +35,7 @@ examples/basic
examples/bot examples/bot
examples/component examples/component
examples/roster examples/roster
examples/server
examples/uuid examples/uuid
examples/vcard examples/vcard
test_stamp test_stamp

View File

@@ -8,9 +8,6 @@
userdata userdata
- System handlers are deleted on xmpp_conn_t reconnection. Old system - System handlers are deleted on xmpp_conn_t reconnection. Old system
handlers could cause problems handlers could cause problems
- Default timeout for xmpp_run() is increased from 1 millisecond to 1
second in order to reduce CPU consumption
- Reduced memory usage in expat module
- New functions: - New functions:
- xmpp_ctx_set_timeout() - xmpp_ctx_set_timeout()
- xmpp_sha1_digest() - xmpp_sha1_digest()

View File

@@ -11,7 +11,7 @@ SSL_LIBS = @openssl_LIBS@
RESOLV_LIBS = @RESOLV_LIBS@ RESOLV_LIBS = @RESOLV_LIBS@
STROPHE_FLAGS = -I$(top_srcdir) -Wall -Wextra -Wno-unused-parameter STROPHE_FLAGS = -I$(top_srcdir) -Wall -Wextra -Werror -Wno-unused-parameter
STROPHE_LIBS = libstrophe.la STROPHE_LIBS = libstrophe.la
## Main build targets ## Main build targets
@@ -36,6 +36,7 @@ libstrophe_la_SOURCES = \
src/resolver.c \ src/resolver.c \
src/sasl.c \ src/sasl.c \
src/scram.c \ src/scram.c \
src/server.c \
src/sha1.c \ src/sha1.c \
src/snprintf.c \ src/snprintf.c \
src/sock.c \ src/sock.c \
@@ -99,6 +100,7 @@ noinst_PROGRAMS = \
examples/bot \ examples/bot \
examples/component \ examples/component \
examples/roster \ examples/roster \
examples/server \
examples/uuid \ examples/uuid \
examples/vcard examples/vcard
@@ -117,6 +119,9 @@ examples_component_LDADD = $(STROPHE_LIBS)
examples_roster_SOURCES = examples/roster.c examples_roster_SOURCES = examples/roster.c
examples_roster_CFLAGS = $(STROPHE_FLAGS) examples_roster_CFLAGS = $(STROPHE_FLAGS)
examples_roster_LDADD = $(STROPHE_LIBS) examples_roster_LDADD = $(STROPHE_LIBS)
examples_server_SOURCES = examples/server.c
examples_server_CFLAGS = $(STROPHE_FLAGS)
examples_server_LDADD = $(STROPHE_LIBS)
examples_uuid_SOURCES = examples/uuid.c examples_uuid_SOURCES = examples/uuid.c
examples_uuid_CFLAGS = $(STROPHE_FLAGS) examples_uuid_CFLAGS = $(STROPHE_FLAGS)
examples_uuid_LDADD = $(STROPHE_LIBS) examples_uuid_LDADD = $(STROPHE_LIBS)

View File

@@ -1,4 +1,4 @@
AC_INIT([libstrophe], [0.9.2], [jack@metajack.im]) AC_INIT([libstrophe], [0.9.1], [jack@metajack.im])
AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_MACRO_DIR([m4])
AM_INIT_AUTOMAKE([foreign]) AM_INIT_AUTOMAKE([foreign])
LT_INIT([dlopen]) LT_INIT([dlopen])

83
examples/server.c Normal file
View File

@@ -0,0 +1,83 @@
#include <stdio.h>
#include <string.h>
#include <strophe.h>
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
#endif
int message_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza,
void * const userdata)
{
xmpp_ctx_t *ctx = (xmpp_ctx_t *)userdata;
xmpp_stanza_t *success;
if (strcmp(xmpp_stanza_get_name(stanza), "auth") == 0) {
success = xmpp_stanza_new(ctx);
xmpp_stanza_set_name(success, "success");
xmpp_stanza_set_ns(success, XMPP_NS_SASL);
xmpp_send(conn, success);
xmpp_stanza_release(success);
} else
xmpp_disconnect(conn);
return 1;
}
void server_handler(xmpp_server_t * const srv, xmpp_conn_t * const conn,
const xmpp_server_event_t event, const int error,
void * const userdata)
{
xmpp_ctx_t *ctx = (xmpp_ctx_t *)userdata;
static char *attrs[] = {
"xmlns", XMPP_NS_CLIENT, "xmlns:stream", XMPP_NS_STREAMS,
"id", "0123456789", "from", "127.0.0.1", "version", "1.0",
"xml:lang", "en",
};
switch (event) {
case XMPP_SERVER_ACCEPT:
printf("Event XMPP_SERVER_ACCEPT\n");
break;
case XMPP_SERVER_OPEN_STREAM:
printf("Event XMPP_SERVER_OPEN_STREAM\n");
xmpp_handler_add(conn, message_handler, NULL, NULL, NULL, ctx);
xmpp_conn_open_stream(conn, attrs, ARRAY_SIZE(attrs));
xmpp_send_raw_string(conn,
"<stream:features>"
"<mechanisms xmlns=\"%s\"><mechanism>PLAIN</mechanism>"
"</mechanisms></stream:features>", XMPP_NS_SASL);
break;
case XMPP_SERVER_DISCONNECT:
printf("Event XMPP_SERVER_DISCONNECT\n");
xmpp_stop(ctx);
break;
default:
printf("Unknown event\n");
break;
}
}
int main()
{
xmpp_ctx_t *ctx;
xmpp_log_t *log;
xmpp_server_t *srv;
xmpp_initialize();
log = xmpp_get_default_logger(XMPP_LEVEL_DEBUG);
ctx = xmpp_ctx_new(NULL, log);
srv = xmpp_server_new(ctx);
xmpp_server_listen(srv, 0, server_handler, ctx);
xmpp_run(ctx);
xmpp_server_stop(srv);
xmpp_server_free(srv);
xmpp_ctx_free(ctx);
xmpp_shutdown();
return 0;
}

View File

@@ -44,6 +44,7 @@ LOCAL_SRC_FILES := \
../src/resolver.c \ ../src/resolver.c \
../src/sasl.c \ ../src/sasl.c \
../src/scram.c \ ../src/scram.c \
../src/server.c \
../src/sha1.c \ ../src/sha1.c \
../src/snprintf.c \ ../src/snprintf.c \
../src/sock.c \ ../src/sock.c \

View File

@@ -43,6 +43,11 @@ typedef struct _xmpp_connlist_t {
struct _xmpp_connlist_t *next; struct _xmpp_connlist_t *next;
} xmpp_connlist_t; } xmpp_connlist_t;
typedef struct _xmpp_serverlist_t {
xmpp_server_t *server;
struct _xmpp_serverlist_t *next;
} xmpp_serverlist_t;
struct _xmpp_ctx_t { struct _xmpp_ctx_t {
const xmpp_mem_t *mem; const xmpp_mem_t *mem;
const xmpp_log_t *log; const xmpp_log_t *log;
@@ -50,6 +55,7 @@ struct _xmpp_ctx_t {
xmpp_rand_t *rand; xmpp_rand_t *rand;
xmpp_loop_status_t loop_status; xmpp_loop_status_t loop_status;
xmpp_connlist_t *connlist; xmpp_connlist_t *connlist;
xmpp_serverlist_t *serverlist;
unsigned long timeout; unsigned long timeout;
}; };
@@ -225,6 +231,24 @@ int conn_tls_start(xmpp_conn_t * const conn);
void conn_prepare_reset(xmpp_conn_t * const conn, xmpp_open_handler handler); void conn_prepare_reset(xmpp_conn_t * const conn, xmpp_open_handler handler);
void conn_parser_reset(xmpp_conn_t * const conn); void conn_parser_reset(xmpp_conn_t * const conn);
typedef enum {
XMPP_STATE_STOPPED,
XMPP_STATE_LISTENING
} xmpp_server_state_t;
struct _xmpp_server_t {
xmpp_ctx_t *ctx;
xmpp_server_state_t state;
sock_t sock;
unsigned short port;
xmpp_server_handler callback;
void *userdata;
/* incomming connections list */
};
void server_accept(xmpp_server_t * const srv);
void server_handle_open(xmpp_conn_t * const conn);
typedef enum { typedef enum {
XMPP_STANZA_UNKNOWN, XMPP_STANZA_UNKNOWN,

View File

@@ -73,15 +73,6 @@ static int _conn_connect(xmpp_conn_t * const conn,
xmpp_conn_handler callback, xmpp_conn_handler callback,
void * const userdata); void * const userdata);
void xmpp_send_error(xmpp_conn_t * const conn, xmpp_error_type_t const type, char * const text)
{
xmpp_stanza_t *error = xmpp_error_new(conn->ctx, type, text);
xmpp_send(conn, error);
xmpp_stanza_release(error);
}
/** Create a new Strophe connection object. /** Create a new Strophe connection object.
* *
* @param ctx a Strophe context object * @param ctx a Strophe context object
@@ -634,14 +625,15 @@ int xmpp_conn_open_stream(xmpp_conn_t * const conn, char **attributes,
{ {
char *tag; char *tag;
if (!conn->is_raw) if (!conn->is_raw && conn->type != XMPP_INCOMING)
return XMPP_EINVOP; return XMPP_EINVOP;
tag = _conn_build_stream_tag(conn, attributes, attributes_len); tag = _conn_build_stream_tag(conn, attributes, attributes_len);
if (!tag) if (!tag)
return XMPP_EMEM; return XMPP_EMEM;
conn_prepare_reset(conn, auth_handle_open_raw); if (conn->type != XMPP_INCOMING)
conn_prepare_reset(conn, auth_handle_open_raw);
xmpp_send_raw_string(conn, "<?xml version=\"1.0\"?>%s", tag); xmpp_send_raw_string(conn, "<?xml version=\"1.0\"?>%s", tag);
xmpp_free(conn->ctx, tag); xmpp_free(conn->ctx, tag);

View File

@@ -61,7 +61,7 @@ static char *digest_to_string_alloc(xmpp_ctx_t *ctx, const uint8_t *digest)
return s; return s;
} }
/** Compute SHA1 message digest. /** Compute SHA1 message digest
* Returns an allocated string which represents SHA1 message digest in * Returns an allocated string which represents SHA1 message digest in
* hexadecimal notation. The string must be freed with xmpp_free(). * hexadecimal notation. The string must be freed with xmpp_free().
* *
@@ -81,7 +81,7 @@ char *xmpp_sha1(xmpp_ctx_t *ctx, const unsigned char *data, size_t len)
return digest_to_string_alloc(ctx, digest); return digest_to_string_alloc(ctx, digest);
} }
/** Compute SHA1 message digest. /** Compute SHA1 message digest
* Stores digest in user's buffer which must be at least XMPP_SHA1_DIGEST_SIZE * Stores digest in user's buffer which must be at least XMPP_SHA1_DIGEST_SIZE
* bytes long. * bytes long.
* *
@@ -97,7 +97,7 @@ void xmpp_sha1_digest(const unsigned char *data, size_t len,
crypto_SHA1((const uint8_t *)data, len, digest); crypto_SHA1((const uint8_t *)data, len, digest);
} }
/** Create new SHA1 object. /** Create new SHA1 object
* SHA1 object is used to compute SHA1 digest of a buffer that is split * SHA1 object is used to compute SHA1 digest of a buffer that is split
* in multiple chunks or provided in stream mode. A single buffer can be * in multiple chunks or provided in stream mode. A single buffer can be
* processed by short functions xmpp_sha1() and xmpp_sha1_digest(). * processed by short functions xmpp_sha1() and xmpp_sha1_digest().
@@ -111,7 +111,7 @@ void xmpp_sha1_digest(const unsigned char *data, size_t len,
* xmpp_sha1_free(sha1); * xmpp_sha1_free(sha1);
* @endcode * @endcode
* *
* @param ctx a Strophe context object * @param ctx a Strophe context onject
* *
* @return new SHA1 object * @return new SHA1 object
* *
@@ -130,7 +130,7 @@ xmpp_sha1_t *xmpp_sha1_new(xmpp_ctx_t *ctx)
return sha1; return sha1;
} }
/** Destroy SHA1 object. /** Destroy SHA1 object
* *
* @param sha1 a SHA1 object * @param sha1 a SHA1 object
* *
@@ -141,7 +141,7 @@ void xmpp_sha1_free(xmpp_sha1_t *sha1)
xmpp_free(sha1->xmpp_ctx, sha1); xmpp_free(sha1->xmpp_ctx, sha1);
} }
/** Update SHA1 context with the next portion of data. /** Update SHA1 context with the next portion of data
* Can be called repeatedly. * Can be called repeatedly.
* *
* @param sha1 a SHA1 object * @param sha1 a SHA1 object
@@ -155,7 +155,7 @@ void xmpp_sha1_update(xmpp_sha1_t *sha1, const unsigned char *data, size_t len)
crypto_SHA1_Update(&sha1->ctx, data, len); crypto_SHA1_Update(&sha1->ctx, data, len);
} }
/** Finish SHA1 computation. /** Finish SHA1 computation
* Don't call xmpp_sha1_update() after this function. Retrieve resulting * Don't call xmpp_sha1_update() after this function. Retrieve resulting
* message digest with xmpp_sha1_to_string() or xmpp_sha1_to_digest(). * message digest with xmpp_sha1_to_string() or xmpp_sha1_to_digest().
* *
@@ -168,7 +168,7 @@ void xmpp_sha1_final(xmpp_sha1_t *sha1)
crypto_SHA1_Final(&sha1->ctx, sha1->digest); crypto_SHA1_Final(&sha1->ctx, sha1->digest);
} }
/** Return message digest rendered as a string. /** Return message digest rendered as a string
* Stores the string to a user's buffer and returns the buffer. Call this * Stores the string to a user's buffer and returns the buffer. Call this
* function after xmpp_sha1_final(). * function after xmpp_sha1_final().
* *
@@ -185,7 +185,7 @@ char *xmpp_sha1_to_string(xmpp_sha1_t *sha1, char *s, size_t slen)
return digest_to_string(sha1->digest, s, slen); return digest_to_string(sha1->digest, s, slen);
} }
/** Return message digest rendered as a string. /** Return message digest rendered as a string
* Returns an allocated string. Free the string using the Strophe context * Returns an allocated string. Free the string using the Strophe context
* which is passed to xmpp_sha1_new(). Call this function after * which is passed to xmpp_sha1_new(). Call this function after
* xmpp_sha1_final(). * xmpp_sha1_final().
@@ -201,7 +201,7 @@ char *xmpp_sha1_to_string_alloc(xmpp_sha1_t *sha1)
return digest_to_string_alloc(sha1->xmpp_ctx, sha1->digest); return digest_to_string_alloc(sha1->xmpp_ctx, sha1->digest);
} }
/** Stores message digest to a user's buffer. /** Stores message digest to a user's buffer
* *
* @param sha1 a SHA1 object * @param sha1 a SHA1 object
* @param digest output buffer of XMPP_SHA1_DIGEST_SIZE bytes * @param digest output buffer of XMPP_SHA1_DIGEST_SIZE bytes
@@ -419,7 +419,7 @@ _base64_error:
*outlen = 0; *outlen = 0;
} }
/** Base64 encoding routine. /** Base64 encoding routine
* Returns an allocated string which must be freed with xmpp_free(). * Returns an allocated string which must be freed with xmpp_free().
* *
* @param ctx a Strophe context * @param ctx a Strophe context
@@ -435,7 +435,7 @@ char *xmpp_base64_encode(xmpp_ctx_t *ctx, const unsigned char *data, size_t len)
return base64_encode(ctx, data, len); return base64_encode(ctx, data, len);
} }
/** Base64 decoding routine. /** Base64 decoding routine
* Returns an allocated string which must be freed with xmpp_free(). User * Returns an allocated string which must be freed with xmpp_free(). User
* calls this function when the result must be a string. When decoded buffer * calls this function when the result must be a string. When decoded buffer
* contains '\0' NULL is returned. * contains '\0' NULL is returned.
@@ -471,7 +471,7 @@ char *xmpp_base64_decode_str(xmpp_ctx_t *ctx, const char *base64, size_t len)
return (char *)buf; return (char *)buf;
} }
/** Base64 decoding routine. /** Base64 decoding routine
* Returns an allocated buffer which must be freed with xmpp_free(). * Returns an allocated buffer which must be freed with xmpp_free().
* *
* @param ctx a Strophe context * @param ctx a Strophe context

View File

@@ -415,6 +415,7 @@ xmpp_ctx_t *xmpp_ctx_new(const xmpp_mem_t * const mem,
ctx->log = log; ctx->log = log;
ctx->connlist = NULL; ctx->connlist = NULL;
ctx->serverlist = NULL;
ctx->loop_status = XMPP_LOOP_NOTSTARTED; ctx->loop_status = XMPP_LOOP_NOTSTARTED;
ctx->rand = xmpp_rand_new(ctx); ctx->rand = xmpp_rand_new(ctx);
ctx->timeout = EVENT_LOOP_DEFAULT_TIMEOUT; ctx->timeout = EVENT_LOOP_DEFAULT_TIMEOUT;

View File

@@ -67,7 +67,9 @@
void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout) void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
{ {
xmpp_connlist_t *connitem; xmpp_connlist_t *connitem;
xmpp_serverlist_t *serveritem;
xmpp_conn_t *conn; xmpp_conn_t *conn;
xmpp_server_t *srv;
fd_set rfds, wfds; fd_set rfds, wfds;
sock_t max = 0; sock_t max = 0;
int ret; int ret;
@@ -206,6 +208,23 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
connitem = connitem->next; connitem = connitem->next;
} }
serveritem = ctx->serverlist;
while (serveritem) {
srv = serveritem->server;
switch (srv->state) {
case XMPP_STATE_LISTENING:
FD_SET(srv->sock, &rfds);
if (srv->sock > max) max = srv->sock;
break;
case XMPP_STATE_STOPPED:
/* do nothing */
default:
break;
}
serveritem = serveritem->next;
}
/* check for events */ /* check for events */
if (max > 0) if (max > 0)
ret = select(max + 1, &rfds, &wfds, NULL, &tv); ret = select(max + 1, &rfds, &wfds, NULL, &tv);
@@ -262,8 +281,10 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
if (ret > 0) { if (ret > 0) {
ret = parser_feed(conn->parser, buf, ret); ret = parser_feed(conn->parser, buf, ret);
if (!ret) { if (!ret) {
xmpp_debug(ctx, "xmpp", "parse error [%s]", buf); /* parse error, we need to shut down */
xmpp_send_error(conn, XMPP_SE_INVALID_XML, "parse error"); /* FIXME */
xmpp_debug(ctx, "xmpp", "parse error, disconnecting");
conn_disconnect(conn);
} }
} else { } else {
if (conn->tls) { if (conn->tls) {
@@ -291,6 +312,24 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
connitem = connitem->next; connitem = connitem->next;
} }
serveritem = ctx->serverlist;
while (serveritem) {
srv = serveritem->server;
switch (srv->state) {
case XMPP_STATE_LISTENING:
if (FD_ISSET(srv->sock, &rfds)) {
server_accept(srv);
}
break;
case XMPP_STATE_STOPPED:
/* do nothing */
default:
break;
}
serveritem = serveritem->next;
}
/* fire any ready handlers */ /* fire any ready handlers */
handler_fire_timed(ctx); handler_fire_timed(ctx);
} }

View File

@@ -241,7 +241,7 @@ void hash_iter_release(hash_iterator_t *iter)
iter->ref--; iter->ref--;
if (iter->ref == 0) { // ref is unsigned!!! if (iter->ref <= 0) {
hash_release(iter->table); hash_release(iter->table);
xmpp_free(ctx, iter); xmpp_free(ctx, iter);
} }

View File

@@ -249,8 +249,6 @@ void parser_free(parser_t *parser)
{ {
if (parser->xmlctx) if (parser->xmlctx)
xmlFreeParserCtxt(parser->xmlctx); xmlFreeParserCtxt(parser->xmlctx);
if (parser->stanza)
xmpp_stanza_release(parser->stanza);
xmpp_free(parser->ctx, parser); xmpp_free(parser->ctx, parser);
} }
@@ -259,16 +257,18 @@ int parser_reset(parser_t *parser)
{ {
if (parser->xmlctx) if (parser->xmlctx)
xmlFreeParserCtxt(parser->xmlctx); xmlFreeParserCtxt(parser->xmlctx);
if (parser->stanza) if (parser->stanza)
xmpp_stanza_release(parser->stanza); xmpp_stanza_release(parser->stanza);
parser->stanza = NULL;
parser->depth = 0;
parser->xmlctx = xmlCreatePushParserCtxt(&parser->handlers, parser->xmlctx = xmlCreatePushParserCtxt(&parser->handlers,
parser, NULL, 0, NULL); parser, NULL, 0, NULL);
if (!parser->xmlctx) return 0;
return parser->xmlctx ? 1 : 0; parser->depth = 0;
parser->stanza = NULL;
return 1;
} }
/* feed a chunk of data to the parser */ /* feed a chunk of data to the parser */

View File

@@ -517,7 +517,7 @@ static int resolver_win32_srv_query(const char *fulldomain,
unsigned char *buf, size_t len) unsigned char *buf, size_t len)
{ {
int set = 0; int set = 0;
int insize = 0; int insize;
/* if dnsapi didn't work/isn't there, try querying the dns server manually */ /* if dnsapi didn't work/isn't there, try querying the dns server manually */
if (!set) if (!set)
@@ -550,7 +550,7 @@ static int resolver_win32_srv_query(const char *fulldomain,
char buffer[65535]; char buffer[65535];
len = 65535; len = 65535;
fi = (FIXED_INFO *)buffer; fi = buffer;
if ((error = pGetNetworkParams(fi, &len)) == ERROR_SUCCESS) if ((error = pGetNetworkParams(fi, &len)) == ERROR_SUCCESS)
{ {

View File

@@ -264,8 +264,7 @@ char *sasl_digest_md5(xmpp_ctx_t *ctx, const char *challenge,
xmpp_rand_nonce(ctx->rand, cnonce, sizeof(cnonce)); xmpp_rand_nonce(ctx->rand, cnonce, sizeof(cnonce));
hash_add(table, "cnonce", xmpp_strdup(ctx, cnonce)); hash_add(table, "cnonce", xmpp_strdup(ctx, cnonce));
hash_add(table, "nc", xmpp_strdup(ctx, "00000001")); hash_add(table, "nc", xmpp_strdup(ctx, "00000001"));
if (hash_get(table, "qop") == NULL) hash_add(table, "qop", xmpp_strdup(ctx, "auth"));
hash_add(table, "qop", xmpp_strdup(ctx, "auth"));
value = xmpp_alloc(ctx, 5 + strlen(domain) + 1); value = xmpp_alloc(ctx, 5 + strlen(domain) + 1);
memcpy(value, "xmpp/", 5); memcpy(value, "xmpp/", 5);
memcpy(value+5, domain, strlen(domain)); memcpy(value+5, domain, strlen(domain));

162
src/server.c Normal file
View File

@@ -0,0 +1,162 @@
/* server.c
* strophe XMPP client library -- server object functions
*
* Copyright (C) 2016 Dmitry Podgorny <pasis.ua@gmail.com>
*
* This software is provided AS-IS with no warranty, either express
* or implied.
*
* This program is dual licensed under the MIT and GPLv3 licenses.
*/
/** @file
* Server management.
*/
/** @defgroup Server Server management
*/
#include <string.h>
#include "common.h"
#include "strophe.h"
static xmpp_server_t *conn2srv(xmpp_conn_t *conn);
static void _server_conn_handler(xmpp_conn_t * const conn,
const xmpp_conn_event_t status,
const int error,
xmpp_stream_error_t * const stream_error,
void * const userdata);
xmpp_server_t *xmpp_server_new(xmpp_ctx_t * const ctx)
{
xmpp_server_t *srv;
xmpp_serverlist_t *item;
srv = xmpp_alloc(ctx, sizeof(*srv));
item = xmpp_alloc(ctx, sizeof(*item));
if (srv == NULL || item == NULL) {
xmpp_error(ctx, "xmpp", "Failed to allocate memory.");
xmpp_free(ctx, srv);
xmpp_free(ctx, item);
srv = NULL;
item = NULL;
}
if (srv != NULL) {
memset(srv, 0, sizeof(*srv));
srv->state = XMPP_STATE_STOPPED;
srv->ctx = ctx;
srv->sock = -1;
item->server = srv;
item->next = ctx->serverlist;
ctx->serverlist = item;
}
return srv;
}
void xmpp_server_free(xmpp_server_t * const srv)
{
xmpp_ctx_t *ctx = srv->ctx;
xmpp_serverlist_t *item, *prev = NULL;
item = ctx->serverlist;
while (item != NULL) {
if (item->server == srv) {
if (prev == NULL) ctx->serverlist = item->next;
if (prev != NULL) prev->next = item->next;
xmpp_free(ctx, item);
}
prev = item;
item = item->next;
}
xmpp_free(ctx, srv);
}
int xmpp_server_listen(xmpp_server_t * const srv, unsigned short port,
xmpp_server_handler callback, void * const userdata)
{
int rc = 0;
if (port == 0) port = XMPP_PORT_CLIENT;
srv->callback = callback;
srv->userdata = userdata;
srv->port = port;
srv->sock = sock_listen(port);
if (srv->sock >= 0) {
srv->state = XMPP_STATE_LISTENING;
xmpp_debug(srv->ctx, "xmpp", "Listening on port %u.", port);
} else
rc = XMPP_EINT;
return rc;
}
void xmpp_server_stop(xmpp_server_t * const srv)
{
srv->state = XMPP_STATE_STOPPED;
sock_stop_listen(srv->sock);
xmpp_debug(srv->ctx, "xmpp", "Server stopped on %u.", srv->port);
}
void server_accept(xmpp_server_t * const srv)
{
xmpp_conn_t *conn;
sock_t fd;
fd = sock_accept(srv->sock);
if (fd >= 0) {
xmpp_debug(srv->ctx, "xmpp", "New incoming connection on port %u.",
srv->port);
conn = xmpp_conn_new(srv->ctx);
conn->type = XMPP_INCOMING;
conn->state = XMPP_STATE_CONNECTED;
conn->sock = fd;
conn->conn_handler = _server_conn_handler;
conn->userdata = (void *)srv;
conn->authenticated = 1; /* don't ignore handlers */
conn_prepare_reset(conn, server_handle_open);
srv->callback(srv, conn, XMPP_SERVER_ACCEPT, 0, srv->userdata);
}
}
void server_handle_open(xmpp_conn_t * const conn)
{
xmpp_server_t *srv = conn2srv(conn);
/* XXX need to reset parser and re-open stream after authentication */
srv->callback(srv, conn, XMPP_SERVER_OPEN_STREAM, 0, srv->userdata);
}
static xmpp_server_t *conn2srv(xmpp_conn_t *conn)
{
xmpp_server_t *srv;
/* XXX dirty hack */
if (conn->ctx->serverlist != NULL)
srv = conn->ctx->serverlist->server;
else
srv = NULL;
return srv;
}
static void _server_conn_handler(xmpp_conn_t * const conn,
const xmpp_conn_event_t status,
const int error,
xmpp_stream_error_t * const stream_error,
void * const userdata)
{
xmpp_server_t *srv = (xmpp_server_t *)userdata;
if (status == XMPP_CONN_DISCONNECT) {
/* remove conn from the list */
/* XXX when client sends </stream> first, server should close stream too */
srv->callback(srv, conn, XMPP_SERVER_DISCONNECT, error, srv->userdata);
}
}

View File

@@ -109,6 +109,43 @@ sock_t sock_connect(const char * const host, const unsigned short port)
return sock; return sock;
} }
sock_t sock_listen(const unsigned short port)
{
struct sockaddr_in addr;
sock_t sock;
int rc;
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) return -1;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = INADDR_ANY;
rc = bind(sock, (struct sockaddr *)&addr, sizeof(addr));
if (rc == 0) {
rc = listen(sock, 100);
sock_set_nonblocking(sock);
}
if (rc != 0) close(sock);
return rc == 0 ? sock : -1;
}
int sock_stop_listen(const sock_t sock)
{
return sock_close(sock);
}
sock_t sock_accept(const sock_t sock)
{
sock_t fd;
fd = accept(sock, NULL, NULL);
return fd;
}
int sock_set_keepalive(const sock_t sock, int timeout, int interval) int sock_set_keepalive(const sock_t sock, int timeout, int interval)
{ {
int ret; int ret;

View File

@@ -32,6 +32,9 @@ int sock_error(void);
sock_t sock_connect(const char * const host, const unsigned short port); sock_t sock_connect(const char * const host, const unsigned short port);
int sock_close(const sock_t sock); int sock_close(const sock_t sock);
sock_t sock_listen(const unsigned short port);
int sock_stop_listen(const sock_t sock);
sock_t sock_accept(const sock_t sock);
int sock_set_blocking(const sock_t sock); int sock_set_blocking(const sock_t sock);
int sock_set_nonblocking(const sock_t sock); int sock_set_nonblocking(const sock_t sock);

View File

@@ -1,7 +1,7 @@
/* stanza.c /* stanza.c
** strophe XMPP client library -- XMPP stanza object and utilities ** strophe XMPP client library -- XMPP stanza object and utilities
** **
** Copyright (C) 2005-2009 Collecta, Inc. ** Copyright (C) 2005-2009 Collecta, Inc.
** **
** This software is provided AS-IS with no warranty, either express ** This software is provided AS-IS with no warranty, either express
** or implied. ** or implied.
@@ -40,15 +40,15 @@ xmpp_stanza_t *xmpp_stanza_new(xmpp_ctx_t *ctx)
stanza = xmpp_alloc(ctx, sizeof(xmpp_stanza_t)); stanza = xmpp_alloc(ctx, sizeof(xmpp_stanza_t));
if (stanza != NULL) { if (stanza != NULL) {
stanza->ref = 1; stanza->ref = 1;
stanza->ctx = ctx; stanza->ctx = ctx;
stanza->type = XMPP_STANZA_UNKNOWN; stanza->type = XMPP_STANZA_UNKNOWN;
stanza->prev = NULL; stanza->prev = NULL;
stanza->next = NULL; stanza->next = NULL;
stanza->children = NULL; stanza->children = NULL;
stanza->parent = NULL; stanza->parent = NULL;
stanza->data = NULL; stanza->data = NULL;
stanza->attributes = NULL; stanza->attributes = NULL;
} }
return stanza; return stanza;
@@ -121,27 +121,27 @@ xmpp_stanza_t *xmpp_stanza_copy(const xmpp_stanza_t * const stanza)
copy->type = stanza->type; copy->type = stanza->type;
if (stanza->data) { if (stanza->data) {
copy->data = xmpp_strdup(stanza->ctx, stanza->data); copy->data = xmpp_strdup(stanza->ctx, stanza->data);
if (!copy->data) goto copy_error; if (!copy->data) goto copy_error;
} }
if (stanza->attributes) { if (stanza->attributes) {
if (_stanza_copy_attributes(copy, stanza) == -1) if (_stanza_copy_attributes(copy, stanza) == -1)
goto copy_error; goto copy_error;
} }
tail = copy->children; tail = copy->children;
for (child = stanza->children; child; child = child->next) { for (child = stanza->children; child; child = child->next) {
copychild = xmpp_stanza_copy(child); copychild = xmpp_stanza_copy(child);
if (!copychild) goto copy_error; if (!copychild) goto copy_error;
copychild->parent = copy; copychild->parent = copy;
if (tail) { if (tail) {
copychild->prev = tail; copychild->prev = tail;
tail->next = copychild; tail->next = copychild;
} else } else
copy->children = copychild; copy->children = copychild;
tail = copychild; tail = copychild;
} }
return copy; return copy;
@@ -153,7 +153,7 @@ copy_error:
} }
/** Release a stanza object and all of its children. /** Release a stanza object and all of its children.
* This function releases a stanza object and potentially all of its * This function releases a stanza object and potentially all of its
* children, which may cause the object(s) to be freed. * children, which may cause the object(s) to be freed.
* *
* @param stanza a Strophe stanza object * @param stanza a Strophe stanza object
@@ -169,20 +169,20 @@ int xmpp_stanza_release(xmpp_stanza_t * const stanza)
/* release stanza */ /* release stanza */
if (stanza->ref > 1) if (stanza->ref > 1)
stanza->ref--; stanza->ref--;
else { else {
/* release all children */ /* release all children */
child = stanza->children; child = stanza->children;
while (child) { while (child) {
tchild = child; tchild = child;
child = child->next; child = child->next;
xmpp_stanza_release(tchild); xmpp_stanza_release(tchild);
} }
if (stanza->attributes) hash_release(stanza->attributes); if (stanza->attributes) hash_release(stanza->attributes);
if (stanza->data) xmpp_free(stanza->ctx, stanza->data); if (stanza->data) xmpp_free(stanza->ctx, stanza->data);
xmpp_free(stanza->ctx, stanza); xmpp_free(stanza->ctx, stanza);
released = 1; released = 1;
} }
return released; return released;
@@ -274,17 +274,17 @@ static char *_escape_xml(xmpp_ctx_t * const ctx, char *text)
/* small helper function */ /* small helper function */
static void _render_update(int *written, const int length, static void _render_update(int *written, const int length,
const int lastwrite, const int lastwrite,
size_t *left, char **ptr) size_t *left, char **ptr)
{ {
*written += lastwrite; *written += lastwrite;
if (*written >= length) { if (*written >= length) {
*left = 0; *left = 0;
*ptr = NULL; *ptr = NULL;
} else { } else {
*left -= lastwrite; *left -= lastwrite;
*ptr = &(*ptr)[lastwrite]; *ptr = &(*ptr)[lastwrite];
} }
} }
@@ -294,7 +294,7 @@ static void _render_update(int *written, const int length,
* and return values > buflen indicate buffer was not large enough * and return values > buflen indicate buffer was not large enough
*/ */
static int _render_stanza_recursive(xmpp_stanza_t *stanza, static int _render_stanza_recursive(xmpp_stanza_t *stanza,
char * const buf, size_t const buflen) char * const buf, size_t const buflen)
{ {
char *ptr = buf; char *ptr = buf;
size_t left = buflen; size_t left = buflen;
@@ -309,80 +309,80 @@ static int _render_stanza_recursive(xmpp_stanza_t *stanza,
if (stanza->type == XMPP_STANZA_UNKNOWN) return XMPP_EINVOP; if (stanza->type == XMPP_STANZA_UNKNOWN) return XMPP_EINVOP;
if (stanza->type == XMPP_STANZA_TEXT) { if (stanza->type == XMPP_STANZA_TEXT) {
if (!stanza->data) return XMPP_EINVOP; if (!stanza->data) return XMPP_EINVOP;
tmp = _escape_xml(stanza->ctx, stanza->data); tmp = _escape_xml(stanza->ctx, stanza->data);
if (tmp == NULL) return XMPP_EMEM; if (tmp == NULL) return XMPP_EMEM;
ret = xmpp_snprintf(ptr, left, "%s", tmp); ret = xmpp_snprintf(ptr, left, "%s", tmp);
xmpp_free(stanza->ctx, tmp); xmpp_free(stanza->ctx, tmp);
if (ret < 0) return XMPP_EMEM; if (ret < 0) return XMPP_EMEM;
_render_update(&written, buflen, ret, &left, &ptr); _render_update(&written, buflen, ret, &left, &ptr);
} else { /* stanza->type == XMPP_STANZA_TAG */ } else { /* stanza->type == XMPP_STANZA_TAG */
if (!stanza->data) return XMPP_EINVOP; if (!stanza->data) return XMPP_EINVOP;
/* write beginning of tag and attributes */ /* write beginning of tag and attributes */
ret = xmpp_snprintf(ptr, left, "<%s", stanza->data); ret = xmpp_snprintf(ptr, left, "<%s", stanza->data);
if (ret < 0) return XMPP_EMEM; if (ret < 0) return XMPP_EMEM;
_render_update(&written, buflen, ret, &left, &ptr); _render_update(&written, buflen, ret, &left, &ptr);
if (stanza->attributes && hash_num_keys(stanza->attributes) > 0) { if (stanza->attributes && hash_num_keys(stanza->attributes) > 0) {
iter = hash_iter_new(stanza->attributes); iter = hash_iter_new(stanza->attributes);
while ((key = hash_iter_next(iter))) { while ((key = hash_iter_next(iter))) {
if (!strcmp(key, "xmlns")) { if (!strcmp(key, "xmlns")) {
/* don't output namespace if parent stanza is the same */ /* don't output namespace if parent stanza is the same */
if (stanza->parent && if (stanza->parent &&
stanza->parent->attributes && stanza->parent->attributes &&
hash_get(stanza->parent->attributes, key) && hash_get(stanza->parent->attributes, key) &&
!strcmp((char*)hash_get(stanza->attributes, key), !strcmp((char*)hash_get(stanza->attributes, key),
(char*)hash_get(stanza->parent->attributes, key))) (char*)hash_get(stanza->parent->attributes, key)))
continue; continue;
/* or if this is the stream namespace */ /* or if this is the stream namespace */
if (!stanza->parent && if (!stanza->parent &&
!strcmp((char*)hash_get(stanza->attributes, key), !strcmp((char*)hash_get(stanza->attributes, key),
XMPP_NS_CLIENT)) XMPP_NS_CLIENT))
continue; continue;
} }
tmp = _escape_xml(stanza->ctx, tmp = _escape_xml(stanza->ctx,
(char *)hash_get(stanza->attributes, key)); (char *)hash_get(stanza->attributes, key));
if (tmp == NULL) return XMPP_EMEM; if (tmp == NULL) return XMPP_EMEM;
ret = xmpp_snprintf(ptr, left, " %s=\"%s\"", key, tmp); ret = xmpp_snprintf(ptr, left, " %s=\"%s\"", key, tmp);
xmpp_free(stanza->ctx, tmp); xmpp_free(stanza->ctx, tmp);
if (ret < 0) return XMPP_EMEM; if (ret < 0) return XMPP_EMEM;
_render_update(&written, buflen, ret, &left, &ptr); _render_update(&written, buflen, ret, &left, &ptr);
} }
hash_iter_release(iter); hash_iter_release(iter);
} }
if (!stanza->children) { if (!stanza->children) {
/* write end if singleton tag */ /* write end if singleton tag */
ret = xmpp_snprintf(ptr, left, "/>"); ret = xmpp_snprintf(ptr, left, "/>");
if (ret < 0) return XMPP_EMEM; if (ret < 0) return XMPP_EMEM;
_render_update(&written, buflen, ret, &left, &ptr); _render_update(&written, buflen, ret, &left, &ptr);
} else { } else {
/* this stanza has child stanzas */ /* this stanza has child stanzas */
/* write end of start tag */ /* write end of start tag */
ret = xmpp_snprintf(ptr, left, ">"); ret = xmpp_snprintf(ptr, left, ">");
if (ret < 0) return XMPP_EMEM; if (ret < 0) return XMPP_EMEM;
_render_update(&written, buflen, ret, &left, &ptr); _render_update(&written, buflen, ret, &left, &ptr);
/* iterate and recurse over child stanzas */
child = stanza->children;
while (child) {
ret = _render_stanza_recursive(child, ptr, left);
if (ret < 0) return ret;
/* iterate and recurse over child stanzas */ _render_update(&written, buflen, ret, &left, &ptr);
child = stanza->children;
while (child) {
ret = _render_stanza_recursive(child, ptr, left);
if (ret < 0) return ret;
_render_update(&written, buflen, ret, &left, &ptr); child = child->next;
}
child = child->next; /* write end tag */
} ret = xmpp_snprintf(ptr, left, "</%s>", stanza->data);
if (ret < 0) return XMPP_EMEM;
/* write end tag */
ret = xmpp_snprintf(ptr, left, "</%s>", stanza->data); _render_update(&written, buflen, ret, &left, &ptr);
if (ret < 0) return XMPP_EMEM; }
_render_update(&written, buflen, ret, &left, &ptr);
}
} }
return written; return written;
@@ -415,27 +415,27 @@ int xmpp_stanza_to_text(xmpp_stanza_t *stanza,
length = 1024; length = 1024;
buffer = xmpp_alloc(stanza->ctx, length); buffer = xmpp_alloc(stanza->ctx, length);
if (!buffer) { if (!buffer) {
*buf = NULL; *buf = NULL;
*buflen = 0; *buflen = 0;
return XMPP_EMEM; return XMPP_EMEM;
} }
ret = _render_stanza_recursive(stanza, buffer, length); ret = _render_stanza_recursive(stanza, buffer, length);
if (ret < 0) return ret; if (ret < 0) return ret;
if ((size_t)ret > length - 1) { if ((size_t)ret > length - 1) {
tmp = xmpp_realloc(stanza->ctx, buffer, ret + 1); tmp = xmpp_realloc(stanza->ctx, buffer, ret + 1);
if (!tmp) { if (!tmp) {
xmpp_free(stanza->ctx, buffer); xmpp_free(stanza->ctx, buffer);
*buf = NULL; *buf = NULL;
*buflen = 0; *buflen = 0;
return XMPP_EMEM; return XMPP_EMEM;
} }
length = ret + 1; length = ret + 1;
buffer = tmp; buffer = tmp;
ret = _render_stanza_recursive(stanza, buffer, length); ret = _render_stanza_recursive(stanza, buffer, length);
if ((size_t)ret > length - 1) return XMPP_EMEM; if ((size_t)ret > length - 1) return XMPP_EMEM;
} }
buffer[length - 1] = 0; buffer[length - 1] = 0;
@@ -457,7 +457,7 @@ int xmpp_stanza_to_text(xmpp_stanza_t *stanza,
* @ingroup Stanza * @ingroup Stanza
*/ */
int xmpp_stanza_set_name(xmpp_stanza_t *stanza, int xmpp_stanza_set_name(xmpp_stanza_t *stanza,
const char * const name) const char * const name)
{ {
if (stanza->type == XMPP_STANZA_TEXT) return XMPP_EINVOP; if (stanza->type == XMPP_STANZA_TEXT) return XMPP_EINVOP;
@@ -496,7 +496,7 @@ const char *xmpp_stanza_get_name(xmpp_stanza_t * const stanza)
int xmpp_stanza_get_attribute_count(xmpp_stanza_t * const stanza) int xmpp_stanza_get_attribute_count(xmpp_stanza_t * const stanza)
{ {
if (stanza->attributes == NULL) { if (stanza->attributes == NULL) {
return 0; return 0;
} }
return hash_num_keys(stanza->attributes); return hash_num_keys(stanza->attributes);
@@ -517,30 +517,30 @@ int xmpp_stanza_get_attribute_count(xmpp_stanza_t * const stanza)
* @ingroup Stanza * @ingroup Stanza
*/ */
int xmpp_stanza_get_attributes(xmpp_stanza_t * const stanza, int xmpp_stanza_get_attributes(xmpp_stanza_t * const stanza,
const char **attr, int attrlen) const char **attr, int attrlen)
{ {
hash_iterator_t *iter; hash_iterator_t *iter;
const char *key; const char *key;
int num = 0; int num = 0;
if (stanza->attributes == NULL) { if (stanza->attributes == NULL) {
return 0; return 0;
} }
iter = hash_iter_new(stanza->attributes); iter = hash_iter_new(stanza->attributes);
while ((key = hash_iter_next(iter)) != NULL && attrlen) { while ((key = hash_iter_next(iter)) != NULL && attrlen) {
attr[num++] = key; attr[num++] = key;
attrlen--; attrlen--;
if (attrlen == 0) { if (attrlen == 0) {
hash_iter_release(iter); hash_iter_release(iter);
return num; return num;
} }
attr[num++] = hash_get(stanza->attributes, key); attr[num++] = hash_get(stanza->attributes, key);
attrlen--; attrlen--;
if (attrlen == 0) { if (attrlen == 0) {
hash_iter_release(iter); hash_iter_release(iter);
return num; return num;
} }
} }
hash_iter_release(iter); hash_iter_release(iter);
@@ -558,8 +558,8 @@ int xmpp_stanza_get_attributes(xmpp_stanza_t * const stanza,
* @ingroup Stanza * @ingroup Stanza
*/ */
int xmpp_stanza_set_attribute(xmpp_stanza_t * const stanza, int xmpp_stanza_set_attribute(xmpp_stanza_t * const stanza,
const char * const key, const char * const key,
const char * const value) const char * const value)
{ {
char *val; char *val;
int rc; int rc;
@@ -567,8 +567,8 @@ int xmpp_stanza_set_attribute(xmpp_stanza_t * const stanza,
if (stanza->type != XMPP_STANZA_TAG) return XMPP_EINVOP; if (stanza->type != XMPP_STANZA_TAG) return XMPP_EINVOP;
if (!stanza->attributes) { if (!stanza->attributes) {
stanza->attributes = hash_new(stanza->ctx, 8, xmpp_free); stanza->attributes = hash_new(stanza->ctx, 8, xmpp_free);
if (!stanza->attributes) return XMPP_EMEM; if (!stanza->attributes) return XMPP_EMEM;
} }
val = xmpp_strdup(stanza->ctx, value); val = xmpp_strdup(stanza->ctx, value);
@@ -598,7 +598,7 @@ int xmpp_stanza_set_attribute(xmpp_stanza_t * const stanza,
* @ingroup Stanza * @ingroup Stanza
*/ */
int xmpp_stanza_set_ns(xmpp_stanza_t * const stanza, int xmpp_stanza_set_ns(xmpp_stanza_t * const stanza,
const char * const ns) const char * const ns)
{ {
return xmpp_stanza_set_attribute(stanza, "xmlns", ns); return xmpp_stanza_set_attribute(stanza, "xmlns", ns);
} }
@@ -624,12 +624,12 @@ int xmpp_stanza_add_child(xmpp_stanza_t *stanza, xmpp_stanza_t *child)
child->parent = stanza; child->parent = stanza;
if (!stanza->children) if (!stanza->children)
stanza->children = child; stanza->children = child;
else { else {
s = stanza->children; s = stanza->children;
while (s->next) s = s->next; while (s->next) s = s->next;
s->next = child; s->next = child;
child->prev = s; child->prev = s;
} }
return XMPP_EOK; return XMPP_EOK;
@@ -649,7 +649,7 @@ int xmpp_stanza_add_child(xmpp_stanza_t *stanza, xmpp_stanza_t *child)
* @ingroup Stanza * @ingroup Stanza
*/ */
int xmpp_stanza_set_text(xmpp_stanza_t *stanza, int xmpp_stanza_set_text(xmpp_stanza_t *stanza,
const char * const text) const char * const text)
{ {
if (stanza->type == XMPP_STANZA_TAG) return XMPP_EINVOP; if (stanza->type == XMPP_STANZA_TAG) return XMPP_EINVOP;
@@ -676,8 +676,8 @@ int xmpp_stanza_set_text(xmpp_stanza_t *stanza,
* @ingroup Stanza * @ingroup Stanza
*/ */
int xmpp_stanza_set_text_with_size(xmpp_stanza_t *stanza, int xmpp_stanza_set_text_with_size(xmpp_stanza_t *stanza,
const char * const text, const char * const text,
const size_t size) const size_t size)
{ {
if (stanza->type == XMPP_STANZA_TAG) return XMPP_EINVOP; if (stanza->type == XMPP_STANZA_TAG) return XMPP_EINVOP;
@@ -780,14 +780,14 @@ const char *xmpp_stanza_get_from(xmpp_stanza_t * const stanza)
* @ingroup Stanza * @ingroup Stanza
*/ */
xmpp_stanza_t *xmpp_stanza_get_child_by_name(xmpp_stanza_t * const stanza, xmpp_stanza_t *xmpp_stanza_get_child_by_name(xmpp_stanza_t * const stanza,
const char * const name) const char * const name)
{ {
xmpp_stanza_t *child; xmpp_stanza_t *child;
for (child = stanza->children; child; child = child->next) { for (child = stanza->children; child; child = child->next) {
if (child->type == XMPP_STANZA_TAG && if (child->type == XMPP_STANZA_TAG &&
(strcmp(name, xmpp_stanza_get_name(child)) == 0)) (strcmp(name, xmpp_stanza_get_name(child)) == 0))
break; break;
} }
return child; return child;
@@ -806,14 +806,14 @@ xmpp_stanza_t *xmpp_stanza_get_child_by_name(xmpp_stanza_t * const stanza,
* @ingroup Stanza * @ingroup Stanza
*/ */
xmpp_stanza_t *xmpp_stanza_get_child_by_ns(xmpp_stanza_t * const stanza, xmpp_stanza_t *xmpp_stanza_get_child_by_ns(xmpp_stanza_t * const stanza,
const char * const ns) const char * const ns)
{ {
xmpp_stanza_t *child; xmpp_stanza_t *child;
for (child = stanza->children; child; child = child->next) { for (child = stanza->children; child; child = child->next) {
if (xmpp_stanza_get_ns(child) && if (xmpp_stanza_get_ns(child) &&
strcmp(ns, xmpp_stanza_get_ns(child)) == 0) strcmp(ns, xmpp_stanza_get_ns(child)) == 0)
break; break;
} }
return child; return child;
@@ -866,16 +866,16 @@ char *xmpp_stanza_get_text(xmpp_stanza_t * const stanza)
char *text; char *text;
if (stanza->type == XMPP_STANZA_TEXT) { if (stanza->type == XMPP_STANZA_TEXT) {
if (stanza->data) if (stanza->data)
return xmpp_strdup(stanza->ctx, stanza->data); return xmpp_strdup(stanza->ctx, stanza->data);
else else
return NULL; return NULL;
} }
len = 0; len = 0;
for (child = stanza->children; child; child = child->next) for (child = stanza->children; child; child = child->next)
if (child->type == XMPP_STANZA_TEXT) if (child->type == XMPP_STANZA_TEXT)
len += strlen(child->data); len += strlen(child->data);
if (len == 0) return NULL; if (len == 0) return NULL;
@@ -884,11 +884,11 @@ char *xmpp_stanza_get_text(xmpp_stanza_t * const stanza)
len = 0; len = 0;
for (child = stanza->children; child; child = child->next) for (child = stanza->children; child; child = child->next)
if (child->type == XMPP_STANZA_TEXT) { if (child->type == XMPP_STANZA_TEXT) {
clen = strlen(child->data); clen = strlen(child->data);
memcpy(&text[len], child->data, clen); memcpy(&text[len], child->data, clen);
len += clen; len += clen;
} }
text[len] = 0; text[len] = 0;
@@ -911,7 +911,7 @@ char *xmpp_stanza_get_text(xmpp_stanza_t * const stanza)
const char *xmpp_stanza_get_text_ptr(xmpp_stanza_t * const stanza) const char *xmpp_stanza_get_text_ptr(xmpp_stanza_t * const stanza)
{ {
if (stanza->type == XMPP_STANZA_TEXT) if (stanza->type == XMPP_STANZA_TEXT)
return stanza->data; return stanza->data;
return NULL; return NULL;
} }
@@ -928,7 +928,7 @@ const char *xmpp_stanza_get_text_ptr(xmpp_stanza_t * const stanza)
* @ingroup Stanza * @ingroup Stanza
*/ */
int xmpp_stanza_set_id(xmpp_stanza_t * const stanza, int xmpp_stanza_set_id(xmpp_stanza_t * const stanza,
const char * const id) const char * const id)
{ {
return xmpp_stanza_set_attribute(stanza, "id", id); return xmpp_stanza_set_attribute(stanza, "id", id);
} }
@@ -945,7 +945,7 @@ int xmpp_stanza_set_id(xmpp_stanza_t * const stanza,
* @ingroup Stanza * @ingroup Stanza
*/ */
int xmpp_stanza_set_type(xmpp_stanza_t * const stanza, int xmpp_stanza_set_type(xmpp_stanza_t * const stanza,
const char * const type) const char * const type)
{ {
return xmpp_stanza_set_attribute(stanza, "type", type); return xmpp_stanza_set_attribute(stanza, "type", type);
} }
@@ -1001,10 +1001,10 @@ const char *xmpp_stanza_get_attribute(xmpp_stanza_t * const stanza,
const char * const name) const char * const name)
{ {
if (stanza->type != XMPP_STANZA_TAG) if (stanza->type != XMPP_STANZA_TAG)
return NULL; return NULL;
if (!stanza->attributes) if (!stanza->attributes)
return NULL; return NULL;
return hash_get(stanza->attributes, name); return hash_get(stanza->attributes, name);
} }
@@ -1218,122 +1218,3 @@ xmpp_stanza_t *xmpp_presence_new(xmpp_ctx_t *ctx)
{ {
return _stanza_new_with_attrs(ctx, "presence", NULL, NULL, NULL); return _stanza_new_with_attrs(ctx, "presence", NULL, NULL, NULL);
} }
/** Create an <stream:error/> stanza object with given type and error text.
* The error text is optional and may be NULL.
*
* @param ctx a Strophe context object
* @param type enum of xmpp_error_type_t
* @param text content of a 'text'
*
* @return a new Strophe stanza object
*
* @todo Handle errors in this function
*
* @ingroup Stanza
*/
xmpp_stanza_t *xmpp_error_new(xmpp_ctx_t *ctx, xmpp_error_type_t const type,
const char * const text)
{
xmpp_stanza_t *error = _stanza_new_with_attrs(ctx, "stream:error", NULL, NULL, NULL);
xmpp_stanza_t *error_type = xmpp_stanza_new(ctx);
switch(type) {
case XMPP_SE_BAD_FORMAT:
xmpp_stanza_set_name(error_type, "bad-format");
break;
case XMPP_SE_BAD_NS_PREFIX:
xmpp_stanza_set_name(error_type, "bad-namespace-prefix");
break;
case XMPP_SE_CONFLICT:
xmpp_stanza_set_name(error_type, "conflict");
break;
case XMPP_SE_CONN_TIMEOUT:
xmpp_stanza_set_name(error_type, "connection-timeout");
break;
case XMPP_SE_HOST_GONE:
xmpp_stanza_set_name(error_type, "host-gone");
break;
case XMPP_SE_HOST_UNKNOWN:
xmpp_stanza_set_name(error_type, "host-unknown");
break;
case XMPP_SE_IMPROPER_ADDR:
xmpp_stanza_set_name(error_type, "improper-addressing");
break;
case XMPP_SE_INTERNAL_SERVER_ERROR:
xmpp_stanza_set_name(error_type, "internal-server-error");
break;
case XMPP_SE_INVALID_FROM:
xmpp_stanza_set_name(error_type, "invalid-from");
break;
case XMPP_SE_INVALID_ID:
xmpp_stanza_set_name(error_type, "invalid-id");
break;
case XMPP_SE_INVALID_NS:
xmpp_stanza_set_name(error_type, "invalid-namespace");
break;
case XMPP_SE_INVALID_XML:
xmpp_stanza_set_name(error_type, "invalid-xml");
break;
case XMPP_SE_NOT_AUTHORIZED:
xmpp_stanza_set_name(error_type, "not-authorized");
break;
case XMPP_SE_POLICY_VIOLATION:
xmpp_stanza_set_name(error_type, "policy-violation");
break;
case XMPP_SE_REMOTE_CONN_FAILED:
xmpp_stanza_set_name(error_type, "remote-connection-failed");
break;
case XMPP_SE_RESOURCE_CONSTRAINT:
xmpp_stanza_set_name(error_type, "resource-constraint");
break;
case XMPP_SE_RESTRICTED_XML:
xmpp_stanza_set_name(error_type, "restricted-xml");
break;
case XMPP_SE_SEE_OTHER_HOST:
xmpp_stanza_set_name(error_type, "see-other-host");
break;
case XMPP_SE_SYSTEM_SHUTDOWN:
xmpp_stanza_set_name(error_type, "system-shutdown");
break;
case XMPP_SE_UNDEFINED_CONDITION:
xmpp_stanza_set_name(error_type, "undefined-condition");
break;
case XMPP_SE_UNSUPPORTED_ENCODING:
xmpp_stanza_set_name(error_type, "unsupported-encoding");
break;
case XMPP_SE_UNSUPPORTED_STANZA_TYPE:
xmpp_stanza_set_name(error_type, "unsupported-stanza-type");
break;
case XMPP_SE_UNSUPPORTED_VERSION:
xmpp_stanza_set_name(error_type, "unsupported-version");
break;
case XMPP_SE_XML_NOT_WELL_FORMED:
xmpp_stanza_set_name(error_type, "xml-not-well-formed");
break;
default:
xmpp_stanza_set_name(error_type, "internal-server-error");
break;
}
xmpp_stanza_set_ns(error_type, XMPP_NS_STREAMS_IETF);
xmpp_stanza_add_child(error, error_type);
xmpp_stanza_release(error_type);
if (text) {
xmpp_stanza_t *error_text = xmpp_stanza_new(ctx);
xmpp_stanza_t *content = xmpp_stanza_new(ctx);
xmpp_stanza_set_name(error_text, "text");
xmpp_stanza_set_ns(error_text, XMPP_NS_STREAMS_IETF);
xmpp_stanza_set_text(content, text);
xmpp_stanza_add_child(error_text, content);
xmpp_stanza_release(content);
xmpp_stanza_add_child(error, error_text);
xmpp_stanza_release(error_text);
}
return error;
}

View File

@@ -209,14 +209,6 @@ int tls_stop(tls_t *tls)
} }
_tls_sock_wait(tls, error); _tls_sock_wait(tls, error);
} }
if (error == SSL_ERROR_SYSCALL && errno == 0) {
/*
* Handle special case when peer closes connection instead of
* proper shutdown.
*/
error = 0;
ret = 1;
}
_tls_set_error(tls, error); _tls_set_error(tls, error);
return ret <= 0 ? 0 : 1; return ret <= 0 ? 0 : 1;
@@ -268,8 +260,6 @@ static void _tls_sock_wait(tls_t *tls, int error)
int nfds; int nfds;
int ret; int ret;
if (error == SSL_ERROR_NONE) return;
FD_ZERO(&rfds); FD_ZERO(&rfds);
FD_ZERO(&wfds); FD_ZERO(&wfds);
if (error == SSL_ERROR_WANT_READ) if (error == SSL_ERROR_WANT_READ)
@@ -288,7 +278,6 @@ static void _tls_sock_wait(tls_t *tls, int error)
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(error)) {
xmpp_debug(tls->ctx, "tls", "error=%d errno=%d", error, errno);
_tls_log_error(tls->ctx); _tls_log_error(tls->ctx);
} }
tls->lasterror = error; tls->lasterror = error;

View File

@@ -139,7 +139,8 @@ typedef enum {
typedef enum { typedef enum {
XMPP_UNKNOWN, XMPP_UNKNOWN,
XMPP_CLIENT, XMPP_CLIENT,
XMPP_COMPONENT XMPP_COMPONENT,
XMPP_INCOMING
} xmpp_conn_type_t; } xmpp_conn_type_t;
typedef void (*xmpp_log_handler)(void * const userdata, typedef void (*xmpp_log_handler)(void * const userdata,
@@ -211,13 +212,12 @@ typedef struct {
xmpp_stanza_t *stanza; xmpp_stanza_t *stanza;
} xmpp_stream_error_t; } xmpp_stream_error_t;
typedef void (*xmpp_conn_handler)(xmpp_conn_t * const conn, typedef void (*xmpp_conn_handler)(xmpp_conn_t * const conn,
const xmpp_conn_event_t event, const xmpp_conn_event_t event,
const int error, const int error,
xmpp_stream_error_t * const stream_error, xmpp_stream_error_t * const stream_error,
void * const userdata); void * const userdata);
void xmpp_send_error(xmpp_conn_t * const conn, xmpp_error_type_t const type, char * const text);
xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t * const ctx); xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t * const ctx);
xmpp_conn_t *xmpp_conn_clone(xmpp_conn_t * const conn); xmpp_conn_t *xmpp_conn_clone(xmpp_conn_t * const conn);
int xmpp_conn_release(xmpp_conn_t * const conn); int xmpp_conn_release(xmpp_conn_t * const conn);
@@ -264,6 +264,30 @@ void xmpp_send_raw_string(xmpp_conn_t * const conn,
void xmpp_send_raw(xmpp_conn_t * const conn, void xmpp_send_raw(xmpp_conn_t * const conn,
const char * const data, const size_t len); const char * const data, const size_t len);
/* server */
/* opaque server object */
typedef struct _xmpp_server_t xmpp_server_t;
/* server callback */
typedef enum {
XMPP_SERVER_ACCEPT,
XMPP_SERVER_OPEN_STREAM,
XMPP_SERVER_DISCONNECT,
XMPP_SERVER_FAIL
} xmpp_server_event_t;
typedef void (*xmpp_server_handler)(xmpp_server_t * const srv,
xmpp_conn_t * const conn,
const xmpp_server_event_t event,
const int error,
void * const userdata);
xmpp_server_t *xmpp_server_new(xmpp_ctx_t * const ctx);
void xmpp_server_free(xmpp_server_t * const srv);
int xmpp_server_listen(xmpp_server_t * const srv, unsigned short port,
xmpp_server_handler callback, void * const userdata);
void xmpp_server_stop(xmpp_server_t * const srv);
/* handlers */ /* handlers */
@@ -382,8 +406,6 @@ int xmpp_message_set_body(xmpp_stanza_t *msg, const char * const text);
xmpp_stanza_t *xmpp_iq_new(xmpp_ctx_t *ctx, const char * const type, xmpp_stanza_t *xmpp_iq_new(xmpp_ctx_t *ctx, const char * const type,
const char * const id); const char * const id);
xmpp_stanza_t *xmpp_presence_new(xmpp_ctx_t *ctx); xmpp_stanza_t *xmpp_presence_new(xmpp_ctx_t *ctx);
xmpp_stanza_t *xmpp_error_new(xmpp_ctx_t *ctx, xmpp_error_type_t const type,
const char * const text);
/* jid */ /* jid */

View File

@@ -20,16 +20,6 @@
#include "test.h" /* ARRAY_SIZE */ #include "test.h" /* ARRAY_SIZE */
/* strtok_s() has appeared in visual studio 2005.
Use own implementation for older versions. */
#ifdef _MSC_VER
# if (_MSC_VER >= 1400)
# define strtok_r strtok_s
# else
# define strtok_r xmpp_strtok_r
# endif
#endif /* _MSC_VER */
static int test_strtok_r(void) static int test_strtok_r(void)
{ {
const char *test = "-abc-=-def--"; const char *test = "-abc-=-def--";