From dc56737b71b44ba16ff0f0902edd1c5b2c1dc217 Mon Sep 17 00:00:00 2001 From: Dmitry Podgorny Date: Tue, 26 Apr 2016 18:29:47 +0000 Subject: [PATCH] conn: implemented xmpp_connect_raw() This function is similar to xmpp_connect_client(), but doesn't perform authentication. Instead, it calls user's connection handler immediately after establishing the connection. Hence, user can implement own authendication or registration procedures. Such a "raw" connection can be useful when user interaction is required (e.g. Data Forms in XEP-0077, OAuth2). --- ChangeLog | 6 +++ src/auth.c | 14 +++++++ src/common.h | 4 ++ src/conn.c | 106 ++++++++++++++++++++++++++++++++++++++++++++++----- src/event.c | 13 +------ strophe.h | 9 +++++ 6 files changed, 130 insertions(+), 22 deletions(-) diff --git a/ChangeLog b/ChangeLog index 54dee5b..36ad2f1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,8 +4,14 @@ - Initial Android support - Resolver returns all SRV records instead of one. Lookup is performed 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. - New API: - xmpp_uuid_gen() + - xmpp_connect_raw() + - xmpp_conn_raw_open_stream() + - xmpp_conn_raw_tls_start() - xmpp_conn_get_flags() - xmpp_conn_set_flags() - xmpp_conn_set_keepalive() diff --git a/src/auth.c b/src/auth.c index a9a7e1d..b38e5b3 100644 --- a/src/auth.c +++ b/src/auth.c @@ -288,6 +288,7 @@ static int _handle_proceedtls_default(xmpp_conn_t * const conn, xmpp_debug(conn->ctx, "xmpp", "proceeding with TLS"); if (conn_tls_start(conn) == 0) { + conn_prepare_reset(conn, auth_handle_open); conn_open_stream(conn); } else { /* failed tls spoils the connection, so disconnect */ @@ -1235,3 +1236,16 @@ int _handle_missing_handshake(xmpp_conn_t * const conn, void * const userdata) xmpp_disconnect(conn); return 0; } + +void auth_handle_open_raw(xmpp_conn_t * const conn) +{ + handler_reset_timed(conn, 0); + /* user handlers are not called before authentication is completed. */ + conn->authenticated = 1; + conn->conn_handler(conn, XMPP_CONN_CONNECT, 0, NULL, conn->userdata); +} + +void auth_handle_open_stub(xmpp_conn_t * const conn) +{ + xmpp_warn(conn->ctx, "auth", "Stub callback is called."); +} diff --git a/src/common.h b/src/common.h index 48c3577..24e1c71 100644 --- a/src/common.h +++ b/src/common.h @@ -150,6 +150,7 @@ struct _xmpp_conn_t { unsigned int ref; xmpp_ctx_t *ctx; xmpp_conn_type_t type; + int is_raw; xmpp_conn_state_t state; uint64_t timeout_stamp; @@ -215,6 +216,7 @@ struct _xmpp_conn_t { void conn_disconnect(xmpp_conn_t * const conn); void conn_disconnect_clean(xmpp_conn_t * const conn); +void conn_established(xmpp_conn_t * const conn); void conn_open_stream(xmpp_conn_t * const conn); int conn_tls_start(xmpp_conn_t * const conn); void conn_prepare_reset(xmpp_conn_t * const conn, xmpp_open_handler handler); @@ -269,5 +271,7 @@ void disconnect_mem_error(xmpp_conn_t * const conn); /* auth functions */ void auth_handle_open(xmpp_conn_t * const conn); void auth_handle_component_open(xmpp_conn_t * const conn); +void auth_handle_open_raw(xmpp_conn_t * const conn); +void auth_handle_open_stub(xmpp_conn_t * const conn); #endif /* __LIBSTROPHE_COMMON_H__ */ diff --git a/src/conn.c b/src/conn.c index e1546ef..1e91b5c 100644 --- a/src/conn.c +++ b/src/conn.c @@ -118,6 +118,7 @@ xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t * const ctx) conn->stream_id = NULL; conn->bound_jid = NULL; + conn->is_raw = 0; conn->tls_support = 0; conn->tls_disabled = 0; conn->tls_mandatory = 0; @@ -520,6 +521,87 @@ int xmpp_connect_component(xmpp_conn_t * const conn, const char * const server, callback, userdata); } +/** Initiate a raw connection to the XMPP server. + * Arguments and behaviour of the function are similar to + * xmpp_connect_client(), but it skips authentication process. Instead, + * the user's callback is called with event XMPP_CONN_RAW_CONNECT as soon + * as tcp connection is established. + * + * This function doesn't use password nor node part of a jid. Therefore, + * 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. + * + * @see xmpp_connect_client() + * + * @return XMPP_EOK (0) on success a number less than 0 on failure + * + * @ingroup Connections + */ +int xmpp_connect_raw(xmpp_conn_t * const conn, + const char * const altdomain, + unsigned short altport, + xmpp_conn_handler callback, + void * const userdata) +{ + conn->is_raw = 1; + return xmpp_connect_client(conn, altdomain, altport, callback, userdata); +} + +/* Called when tcp connection is established. */ +void conn_established(xmpp_conn_t * const conn) +{ + if (conn->tls_legacy_ssl && !conn->is_raw) { + xmpp_debug(conn->ctx, "xmpp", "using legacy SSL connection"); + if (conn_tls_start(conn) != 0) { + conn_disconnect(conn); + return; + } + } + + if (conn->is_raw) { + handler_reset_timed(conn, 0); + /* we skip authentication for a "raw" connection, but the event loop + ignores user's handlers when conn->authenticated is not set. */ + conn->authenticated = 1; + conn->conn_handler(conn, XMPP_CONN_RAW_CONNECT, 0, NULL, conn->userdata); + } else { + /* send stream init */ + conn_open_stream(conn); + } +} + +/** Send an opening stream tag. + * 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 + * + * @ingroup Connections + */ +int xmpp_conn_raw_open_stream(xmpp_conn_t * const conn) +{ + if (!conn->is_raw) + return XMPP_EINVOP; + + conn_prepare_reset(conn, auth_handle_open_raw); + conn_open_stream(conn); + + return XMPP_EOK; +} + +/** Start synchronous TLS handshake with the server. + * + * @return XMPP_EOK (0) on success a number less than 0 on failure + */ +int xmpp_conn_raw_tls_start(xmpp_conn_t * const conn) +{ + return conn_tls_start(conn); +} + /** Cleanly disconnect the connection. * This function is only called by the stream parser when * is received, and it not intended to be called by code outside of Strophe. @@ -756,27 +838,27 @@ int conn_tls_start(xmpp_conn_t * const conn) if (conn->tls_disabled) { conn->tls = NULL; - rc = -ENOSYS; + rc = XMPP_EINVOP; } else { conn->tls = tls_new(conn->ctx, conn->sock); - rc = conn->tls == NULL ? -ENOMEM : 0; + rc = conn->tls == NULL ? XMPP_EMEM : 0; } if (conn->tls != NULL) { if (tls_start(conn->tls)) { conn->secured = 1; - conn_prepare_reset(conn, auth_handle_open); } else { - rc = tls_error(conn->tls); - conn->error = rc; + rc = XMPP_EINT; + conn->error = tls_error(conn->tls); tls_free(conn->tls); conn->tls = NULL; conn->tls_failed = 1; } } - if (rc != 0) - xmpp_debug(conn->ctx, "conn", "Couldn't start TLS! error %d", rc); - + if (rc != 0) { + xmpp_debug(conn->ctx, "conn", "Couldn't start TLS! " + "error %d tls_error %d", rc, conn->error); + } return rc; } @@ -1030,6 +1112,8 @@ static int _conn_connect(xmpp_conn_t * const conn, xmpp_conn_handler callback, void * const userdata) { + xmpp_open_handler open_handler; + if (conn->state != XMPP_STATE_DISCONNECTED) return -1; if (type != XMPP_CLIENT && type != XMPP_COMPONENT) return -1; @@ -1050,8 +1134,10 @@ static int _conn_connect(xmpp_conn_t * const conn, conn->conn_handler = callback; conn->userdata = userdata; - conn_prepare_reset(conn, type == XMPP_CLIENT ? auth_handle_open : - auth_handle_component_open); + open_handler = conn->is_raw ? auth_handle_open_stub : + type == XMPP_CLIENT ? auth_handle_open : + auth_handle_component_open; + conn_prepare_reset(conn, open_handler); /* FIXME: it could happen that the connect returns immediately as * successful, though this is pretty unlikely. This would be a little diff --git a/src/event.c b/src/event.c index 2d73f55..4ef63ee 100644 --- a/src/event.c +++ b/src/event.c @@ -267,18 +267,7 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout) conn->state = XMPP_STATE_CONNECTED; xmpp_debug(ctx, "xmpp", "connection successful"); - - if (conn->tls_legacy_ssl) { - xmpp_debug(ctx, "xmpp", "using legacy SSL connection"); - ret = conn_tls_start(conn); - if (ret != 0) { - conn_disconnect(conn); - break; - } - } - - /* send stream init */ - conn_open_stream(conn); + conn_established(conn); } break; diff --git a/strophe.h b/strophe.h index 3db9ea7..1f26421 100644 --- a/strophe.h +++ b/strophe.h @@ -169,6 +169,7 @@ typedef struct _xmpp_stanza_t xmpp_stanza_t; /* connect callback */ typedef enum { XMPP_CONN_CONNECT, + XMPP_CONN_RAW_CONNECT, XMPP_CONN_DISCONNECT, XMPP_CONN_FAIL } xmpp_conn_event_t; @@ -238,6 +239,14 @@ int xmpp_connect_component(xmpp_conn_t * const conn, const char * const server, unsigned short port, xmpp_conn_handler callback, void * const userdata); +int xmpp_connect_raw(xmpp_conn_t * const conn, + const char * const altdomain, + 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); + void xmpp_disconnect(xmpp_conn_t * const conn); void xmpp_send(xmpp_conn_t * const conn,