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:
@@ -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()
|
||||
|
||||
14
src/auth.c
14
src/auth.c
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
176
src/conn.c
176
src/conn.c
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user