static int _handle_proceedtls_default(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) { char *name; name = xmpp_stanza_get_name(stanza); xmpp_debug(conn->ctx, "xmpp", "handle proceedtls called for %s", name); if (strcmp(name, "proceed") == 0) { xmpp_debug(conn->ctx, "xmpp", "proceeding with TLS"); conn->tls = tls_new(conn->ctx, conn->sock); if (!tls_start(conn->tls)) { xmpp_debug(conn->ctx, "xmpp", "Couldn't start TLS! error %d", tls_error(conn->tls)); tls_free(conn->tls); conn->tls = NULL; conn->tls_failed = 1; /* failed tls spoils the connection, so disconnect */ xmpp_disconnect(conn); } else { conn->secured = 1; conn_prepare_reset(conn, auth_handle_open); conn_open_stream(conn); } } return 0; }
int conn_tls_start(xmpp_conn_t * const conn) { int rc; if (conn->tls_disabled) { conn->tls = NULL; rc = -ENOSYS; } else { conn->tls = tls_new(conn->ctx, conn->sock); rc = conn->tls == NULL ? -ENOMEM : 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; 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); return rc; }
static int _handle_sasl_result(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) { char *name; name = xmpp_stanza_get_name(stanza); /* the server should send a <success> or <failure> stanza */ if (strcmp(name, "failure") == 0) { xmpp_debug(conn->ctx, "xmpp", "SASL %s auth failed", (char *)userdata); /* fall back to next auth method */ _auth(conn); } else if (strcmp(name, "success") == 0) { /* SASL PLAIN auth successful, we need to restart the stream */ xmpp_debug(conn->ctx, "xmpp", "SASL %s auth successful", (char *)userdata); /* reset parser */ conn_prepare_reset(conn, _handle_open_sasl); /* send stream tag */ conn_open_stream(conn); } else { /* got unexpected reply */ xmpp_error(conn->ctx, "xmpp", "Got unexpected reply to SASL %s"\ "authentication.", (char *)userdata); xmpp_disconnect(conn); } return 0; }
/** 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_open_stream_default(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; }
/** Initiate a component connection to server. * This function returns immediately after starting the connection * process to the XMPP server, and notifiations of connection state changes * will be sent to the internal callback function that will set up handler * for the component handshake as defined in XEP-0114. * The domain and port to connect to must be provided in this case as the JID * provided to the call serves as component identifier to the server and is * not subject to DNS resolution. * * @param conn a Strophe connection object * @param server a string with domain to use directly as the domain can't be * extracted from the component name/JID. If this is not set, the call * will fail. * @param port an integer port number to use to connect to server expecting * an external component. If this is 0, the port 5347 will be assumed. * @param callback a xmpp_conn_handler callback function that will receive * notifications of connection status * @param userdata an opaque data pointer that will be passed to the callback * * @return 0 on success and -1 on an error * * @ingroup Connections */ int xmpp_connect_component(xmpp_conn_t * const conn, const char * const server, unsigned short port, xmpp_conn_handler callback, void * const userdata) { int connectport; if (conn->state != XMPP_STATE_DISCONNECTED) return -1; if (conn->domain != NULL) xmpp_free(conn->ctx, conn->domain); conn->type = XMPP_COMPONENT; conn->secured = 0; conn->tls_failed = 0; /* JID serves as an identificator here and will be used as "to" attribute of the stream */ conn->domain = xmpp_strdup(conn->ctx, conn->jid); /* The server domain, jid and password MUST be specified. */ if (!(server && conn->jid && conn->pass)) return -1; connectport = port ? port : _conn_default_port(conn); xmpp_debug(conn->ctx, "xmpp", "Connecting via %s", server); conn->sock = sock_connect(server, connectport); xmpp_debug(conn->ctx, "xmpp", "sock_connect to %s:%d returned %d", server, connectport, conn->sock); if (conn->sock == -1) return -1; /* XEP-0114 does not support TLS */ conn->tls_disabled = 1; /* setup handler */ conn->conn_handler = callback; conn->userdata = userdata; conn_prepare_reset(conn, auth_handle_component_open); /* FIXME: it could happen that the connect returns immediately as * successful, though this is pretty unlikely. This would be a little * hard to fix, since we'd have to detect and fire off the callback * from within the event loop */ conn->state = XMPP_STATE_CONNECTING; conn->timeout_stamp = time_stamp(); xmpp_debug(conn->ctx, "xmpp", "attempting to connect to %s", server); return 0; }
static int _conn_connect(xmpp_conn_t * const conn, const char * const domain, const char * const host, unsigned short port, xmpp_conn_type_t type, xmpp_conn_handler callback, void * const userdata) { xmpp_open_handler open_handler; if (conn->state != XMPP_STATE_DISCONNECTED) return XMPP_EINVOP; if (type != XMPP_CLIENT && type != XMPP_COMPONENT) return XMPP_EINVOP; if (host == NULL || port == 0) return XMPP_EINT; _conn_reset(conn); conn->type = type; conn->domain = xmpp_strdup(conn->ctx, domain); if (!conn->domain) return XMPP_EMEM; conn->sock = sock_connect(host, port); xmpp_debug(conn->ctx, "xmpp", "sock_connect() to %s:%u returned %d", host, port, conn->sock); if (conn->sock == -1) return XMPP_EINT; if (conn->ka_timeout || conn->ka_interval) sock_set_keepalive(conn->sock, conn->ka_timeout, conn->ka_interval); /* setup handler */ conn->conn_handler = callback; conn->userdata = userdata; 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 * hard to fix, since we'd have to detect and fire off the callback * from within the event loop */ conn->state = XMPP_STATE_CONNECTING; conn->timeout_stamp = time_stamp(); xmpp_debug(conn->ctx, "xmpp", "Attempting to connect to %s", host); return 0; }
/** 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; }
static int _handle_proceedtls_default(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) { const char *name; name = xmpp_stanza_get_name(stanza); xmpp_debug(conn->ctx, "xmpp", "handle proceedtls called for %s", name); if (strcmp(name, "proceed") == 0) { 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 */ xmpp_disconnect(conn); } } return 0; }
/** Create a new Strophe connection object. * * @param ctx a Strophe context object * * @return a Strophe connection object or NULL on an error * * @ingroup Connections */ xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t * const ctx) { xmpp_conn_t *conn = NULL; xmpp_connlist_t *tail, *item; if (ctx == NULL) return NULL; conn = xmpp_alloc(ctx, sizeof(xmpp_conn_t)); if (conn != NULL) { conn->ctx = ctx; conn->type = XMPP_UNKNOWN; conn->state = XMPP_STATE_DISCONNECTED; conn->sock = -1; conn->tls = NULL; conn->timeout_stamp = 0; conn->error = 0; conn->stream_error = NULL; /* default send parameters */ conn->blocking_send = 0; conn->send_queue_max = DEFAULT_SEND_QUEUE_MAX; conn->send_queue_len = 0; conn->send_queue_head = NULL; conn->send_queue_tail = NULL; /* default timeouts */ conn->connect_timeout = CONNECT_TIMEOUT; conn->lang = xmpp_strdup(conn->ctx, "en"); if (!conn->lang) { xmpp_free(conn->ctx, conn); return NULL; } conn->domain = NULL; conn->jid = NULL; conn->pass = NULL; conn->stream_id = NULL; conn->bound_jid = NULL; conn->tls_support = 0; conn->tls_disabled = 0; conn->tls_failed = 0; conn->sasl_support = 0; conn->secured = 0; conn->bind_required = 0; conn->session_required = 0; conn->parser = parser_new(conn->ctx, _handle_stream_start, _handle_stream_end, _handle_stream_stanza, conn); conn->reset_parser = 0; conn_prepare_reset(conn, auth_handle_open); conn->authenticated = 0; conn->conn_handler = NULL; conn->userdata = NULL; conn->timed_handlers = NULL; /* we own (and will free) the hash values */ conn->id_handlers = hash_new(conn->ctx, 32, NULL); conn->handlers = NULL; /* give the caller a reference to connection */ conn->ref = 1; /* add connection to ctx->connlist */ tail = conn->ctx->connlist; while (tail && tail->next) tail = tail->next; item = xmpp_alloc(conn->ctx, sizeof(xmpp_connlist_t)); if (!item) { xmpp_error(conn->ctx, "xmpp", "failed to allocate memory"); xmpp_free(conn->ctx, conn->lang); parser_free(conn->parser); xmpp_free(conn->ctx, conn); conn = NULL; } else { item->conn = conn; item->next = NULL; if (tail) tail->next = item; else conn->ctx->connlist = item; } } return conn; }
/** Create a new Strophe connection object. * * @param ctx a Strophe context object * * @return a Strophe connection object or NULL on an error * * @ingroup Connections */ xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t * const ctx) { xmpp_conn_t *conn; list_t *item; if (!ctx) return NULL; conn = xmpp_alloc(ctx, sizeof(xmpp_conn_t)); if (!conn) return NULL; conn->ctx = ctx; conn->type = XMPP_UNKNOWN; conn->state = XMPP_STATE_DISCONNECTED; conn->sock = -1; conn->tls = NULL; conn->timeout_stamp = 0; conn->error = 0; conn->stream_error = NULL; /* default send parameters */ conn->blocking_send = 0; conn->send_queue_max = DEFAULT_SEND_QUEUE_MAX; conn->send_queue = list_init(ctx); if (!conn->send_queue) goto out_free_conn; /* default timeouts */ conn->connect_timeout = CONNECT_TIMEOUT; conn->lang = xmpp_strdup(ctx, "en"); if (!conn->lang) goto out_free_send_queue; conn->domain = NULL; conn->jid = NULL; conn->pass = NULL; conn->stream_id = NULL; conn->bound_jid = NULL; conn->tls_support = 0; conn->tls_disabled = 0; conn->tls_failed = 0; conn->sasl_support = 0; conn->secured = 0; conn->bind_required = 0; conn->session_required = 0; conn->parser = parser_new(ctx, _handle_stream_start, _handle_stream_end, _handle_stream_stanza, conn); if (!conn->parser) goto out_free_lang; conn->reset_parser = 0; conn_prepare_reset(conn, auth_handle_open); conn->authenticated = 0; conn->conn_handler = NULL; conn->userdata = NULL; /* we own (and will free) the hash values */ conn->id_handlers = hash_new(ctx, 32, NULL); conn->timed_handlers = list_init(ctx); if (!conn->timed_handlers) goto out_free_parser; conn->handlers = list_init(ctx); if (!conn->handlers) goto out_free_timed_handlers; /* give the caller a reference to connection */ conn->ref = 1; /* add connection to ctx->connlist */ item = list_init_item(ctx); if (!item) goto out_free_handlers; else { item->data = (void *)conn; list_push(ctx->connlist, item); } return conn; out_free_handlers: list_destroy(conn->handlers); out_free_timed_handlers: list_destroy(conn->timed_handlers); out_free_parser: parser_free(conn->parser); out_free_lang: xmpp_free(ctx, conn->lang); out_free_send_queue: list_destroy(conn->send_queue); out_free_conn: xmpp_free(ctx, conn); return NULL; }