conn: xmpp_conn_open_stream() sends user-supplied tag

Default opening tag doesn't allow to implement XEP-0174. In this case
client needs to send specific attributes. As solution user passes
attributes that are sent inside opening tag. Previous variant of this
function is renamed to xmpp_conn_open_stream_default().

The way to pass attributes is not the best one, but it's used to conform
existent interface of xmpp_stanza_get_attributes().

Remove "raw" suffix from functions that work with a raw connection.
This commit is contained in:
Dmitry Podgorny
2016-09-06 22:06:29 +03:00
parent dd7aeff5d2
commit 229215b49c
4 changed files with 163 additions and 40 deletions

View File

@@ -6,14 +6,15 @@
according to RFC2052.
- xmpp_connect_raw() provides access to a xmpp_conn object just after
establishing TCP connection. This allows to implement in-band
registration or authentication mechanisms.
registration, authentication mechanisms or serverless messaging.
- xmpp_conn_t object is reusable now and can be reconnected with saving
all handlers, flags, jid and password.
- New API:
- xmpp_uuid_gen()
- xmpp_connect_raw()
- xmpp_conn_raw_open_stream()
- xmpp_conn_raw_tls_start()
- xmpp_conn_open_stream_default()
- xmpp_conn_open_stream()
- xmpp_conn_tls_start()
- xmpp_conn_get_flags()
- xmpp_conn_set_flags()
- xmpp_conn_set_keepalive()

View File

@@ -1140,6 +1140,8 @@ static int _handle_missing_legacy(xmpp_conn_t * const conn,
void auth_handle_component_open(xmpp_conn_t * const conn)
{
int rc;
/* reset all timed handlers */
handler_reset_timed(conn, 0);
@@ -1148,7 +1150,11 @@ void auth_handle_component_open(xmpp_conn_t * const conn)
"handshake", NULL, NULL);
handler_add_timed(conn, _handle_missing_handshake, HANDSHAKE_TIMEOUT, NULL);
_handle_component_auth(conn);
rc = _handle_component_auth(conn);
if (rc != 0) {
xmpp_error(conn->ctx, "auth", "Component authentication failed.");
xmpp_disconnect(conn);
}
}
/* Will compute SHA1 and authenticate the component to the server */
@@ -1159,6 +1165,11 @@ int _handle_component_auth(xmpp_conn_t * const conn)
char *digest;
size_t i;
if (conn->stream_id == NULL) {
xmpp_error(conn->ctx, "auth", "Received no stream id from the server.");
return XMPP_EINT;
}
/* Feed the session id and passphrase to the algorithm.
* We need to compute SHA1(session_id + passphrase)
*/
@@ -1186,7 +1197,6 @@ int _handle_component_auth(xmpp_conn_t * const conn)
} else {
xmpp_debug(conn->ctx, "auth", "Couldn't allocate memory for component "\
"handshake digest.");
xmpp_disconnect(conn);
return XMPP_EMEM;
}

View File

@@ -50,7 +50,12 @@
static int _disconnect_cleanup(xmpp_conn_t * const conn,
void * const userdata);
static char *_conn_build_stream_tag(xmpp_conn_t * const conn,
char **attributes, size_t attributes_len);
static void _conn_attributes_new(xmpp_conn_t *conn, char **attrs,
char ***attributes, size_t *attributes_len);
static void _conn_attributes_destroy(xmpp_conn_t *conn, char **attributes,
size_t attributes_len);
static void _handle_stream_start(char *name, char **attrs,
void * const userdata);
static void _handle_stream_end(char *name,
@@ -531,9 +536,8 @@ int xmpp_connect_component(xmpp_conn_t * const conn, const char * const server,
* the only required configuration is a domain (or full jid) passed via
* xmpp_conn_set_jid().
*
* Next step should be xmpp_conn_raw_open_stream(). In case of legacy SSL,
* user might want to call xmpp_conn_raw_tls_start() before opening the
* stream.
* Next step should be xmpp_conn_open_stream(). In case of legacy SSL,
* user might want to call xmpp_conn_tls_start() before opening the stream.
*
* @see xmpp_connect_client()
*
@@ -574,15 +578,18 @@ void conn_established(xmpp_conn_t * const conn)
}
}
/** Send an opening stream tag.
/** Send the default opening stream tag.
* The default tag is the one sent by xmpp_connect_client().
* User's connection handler is called with event XMPP_CONN_CONNECT when
* server replies with its opening tag.
*
* @return XMPP_EOK (0) on success a number less than 0 on failure
*
* @note The connection must be connected with xmpp_connect_raw().
*
* @ingroup Connections
*/
int xmpp_conn_raw_open_stream(xmpp_conn_t * const conn)
int xmpp_conn_open_stream_default(xmpp_conn_t * const conn)
{
if (!conn->is_raw)
return XMPP_EINVOP;
@@ -593,11 +600,48 @@ int xmpp_conn_raw_open_stream(xmpp_conn_t * const conn)
return XMPP_EOK;
}
/** Send an opening stream tag.
* User's connection handler is called with event XMPP_CONN_CONNECT when
* server replies with its opening tag.
*
* @param conn a Strophe connection object
* @param attributes Array of strings in format: even index points to
* an attribute name and odd index points to its value
* @param attributes_len Number of elements in the attributes array, it
* should be number of attributes multiplied by 2
*
* @return XMPP_EOK (0) on success a number less than 0 on failure
*
* @note The connection must be connected with xmpp_connect_raw().
*
* @ingroup Connections
*/
int xmpp_conn_open_stream(xmpp_conn_t * const conn, char **attributes,
size_t attributes_len)
{
char *tag;
if (!conn->is_raw)
return XMPP_EINVOP;
tag = _conn_build_stream_tag(conn, attributes, attributes_len);
if (!tag)
return XMPP_EMEM;
conn_prepare_reset(conn, auth_handle_open_raw);
xmpp_send_raw_string(conn, "<?xml version=\"1.0\"?>%s", tag);
xmpp_free(conn->ctx, tag);
return XMPP_EOK;
}
/** Start synchronous TLS handshake with the server.
*
* @return XMPP_EOK (0) on success a number less than 0 on failure
*
* @ingroup Connections
*/
int xmpp_conn_raw_tls_start(xmpp_conn_t * const conn)
int xmpp_conn_tls_start(xmpp_conn_t * const conn)
{
return conn_tls_start(conn);
}
@@ -951,34 +995,99 @@ int xmpp_conn_is_secured(xmpp_conn_t * const conn)
return conn->secured && !conn->tls_failed && conn->tls != NULL ? 1 : 0;
}
static void _log_open_tag(xmpp_conn_t *conn, char **attrs)
static char *_conn_build_stream_tag(xmpp_conn_t * const conn,
char **attributes, size_t attributes_len)
{
char buf[4096];
size_t pos;
int len;
int i;
char *attr;
char *tag;
size_t len;
size_t i;
if (!attrs) return;
static const char *tag_head = "<stream:stream";
static const char *tag_tail = ">";
pos = 0;
len = xmpp_snprintf(buf, 4096, "<stream:stream");
if (len < 0) return;
/* ignore the last element unless number is even */
attributes_len &= ~(size_t)1;
pos += len;
for (i = 0; attrs[i]; i += 2) {
attr = parser_attr_name(conn->ctx, attrs[i]);
len = xmpp_snprintf(&buf[pos], 4096 - pos, " %s='%s'",
attr, attrs[i+1]);
xmpp_free(conn->ctx, attr);
if (len < 0) return;
pos += len;
len = strlen(tag_head) + strlen(tag_tail);
for (i = 0; i < attributes_len; ++i)
len += strlen(attributes[i]) + 2;
tag = xmpp_alloc(conn->ctx, len + 1);
if (!tag) return NULL;
strcpy(tag, tag_head);
for (i = 0; i < attributes_len; ++i) {
if ((i & 1) == 0) {
strcat(tag, " ");
strcat(tag, attributes[i]);
strcat(tag, "=\"");
} else {
strcat(tag, attributes[i]);
strcat(tag, "\"");
}
}
strcat(tag, tag_tail);
if (strlen(tag) != len) {
xmpp_error(conn->ctx, "xmpp", "Internal error in "
"_conn_build_stream_tag().");
xmpp_free(conn->ctx, tag);
tag = NULL;
}
len = xmpp_snprintf(&buf[pos], 4096 - pos, ">");
if (len < 0) return;
return tag;
}
xmpp_debug(conn->ctx, "xmpp", "RECV: %s", buf);
static void _conn_attributes_new(xmpp_conn_t *conn, char **attrs,
char ***attributes, size_t *attributes_len)
{
char **array = NULL;
size_t nr = 0;
size_t i;
if (attrs) {
for (; attrs[nr]; ++nr);
array = xmpp_alloc(conn->ctx, sizeof(*array) * nr);
for (i = 0; array && i < nr; ++i) {
array[i] = (i & 1) == 0 ? parser_attr_name(conn->ctx, attrs[i])
: xmpp_strdup(conn->ctx, attrs[i]);
if (array[i] == NULL) break;
}
if (!array || i < nr) {
xmpp_error(conn->ctx, "xmpp", "Memory allocation error.");
_conn_attributes_destroy(conn, array, i);
array = NULL;
nr = 0;
}
}
*attributes = array;
*attributes_len = nr;
}
static void _conn_attributes_destroy(xmpp_conn_t *conn, char **attributes,
size_t attributes_len)
{
size_t i;
if (attributes) {
for (i = 0; i < attributes_len; ++i)
xmpp_free(conn->ctx, attributes[i]);
xmpp_free(conn->ctx, attributes);
}
}
static void _log_open_tag(xmpp_conn_t *conn, char **attrs)
{
char **attributes;
char *tag;
size_t nr;
_conn_attributes_new(conn, attrs, &attributes, &nr);
tag = _conn_build_stream_tag(conn, attributes, nr);
if (tag) {
xmpp_debug(conn->ctx, "xmpp", "RECV: %s", tag);
xmpp_free(conn->ctx, tag);
}
_conn_attributes_destroy(conn, attributes, nr);
}
static char *_get_stream_attribute(char **attrs, char *name)
@@ -999,6 +1108,7 @@ static void _handle_stream_start(char *name, char **attrs,
{
xmpp_conn_t *conn = (xmpp_conn_t *)userdata;
char *id;
int failed = 0;
if (conn->stream_id) xmpp_free(conn->ctx, conn->stream_id);
conn->stream_id = NULL;
@@ -1009,17 +1119,17 @@ static void _handle_stream_start(char *name, char **attrs,
if (id)
conn->stream_id = xmpp_strdup(conn->ctx, id);
/* check and log errors */
if (!id)
xmpp_error(conn->ctx, "conn", "No id attribute.");
else if (!conn->stream_id)
if (id && !conn->stream_id) {
xmpp_error(conn->ctx, "conn", "Memory allocation failed.");
failed = 1;
}
} else {
xmpp_error(conn->ctx, "conn", "Server did not open valid stream."
" name = %s.", name);
failed = 1;
}
if (conn->stream_id) {
if (!failed) {
/* call stream open handler */
conn->open_handler(conn);
} else {

View File

@@ -244,8 +244,10 @@ int xmpp_connect_raw(xmpp_conn_t * const conn,
unsigned short altport,
xmpp_conn_handler callback,
void * const userdata);
int xmpp_conn_raw_open_stream(xmpp_conn_t * const conn);
int xmpp_conn_raw_tls_start(xmpp_conn_t * const conn);
int xmpp_conn_open_stream_default(xmpp_conn_t * const conn);
int xmpp_conn_open_stream(xmpp_conn_t * const conn, char **attributes,
size_t attributes_len);
int xmpp_conn_tls_start(xmpp_conn_t * const conn);
void xmpp_disconnect(xmpp_conn_t * const conn);