static PurpleHTTPConnection * find_available_http_connection(PurpleBOSHConnection *conn) { int i; if (purple_debug_is_verbose()) debug_dump_http_connections(conn); /* Easy solution: Does everyone involved support pipelining? Hooray! Just use * one TCP connection! */ if (conn->pipelining) return conn->connections[0]->state == HTTP_CONN_CONNECTED ? conn->connections[0] : NULL; /* First loop, look for a connection that's ready */ for (i = 0; i < NUM_HTTP_CONNECTIONS; ++i) { if (conn->connections[i] && conn->connections[i]->state == HTTP_CONN_CONNECTED && conn->connections[i]->requests == 0) return conn->connections[i]; } /* Second loop, is something currently connecting? If so, just queue up. */ for (i = 0; i < NUM_HTTP_CONNECTIONS; ++i) { if (conn->connections[i] && conn->connections[i]->state == HTTP_CONN_CONNECTING) return NULL; } /* Third loop, is something offline that we can connect? */ for (i = 0; i < NUM_HTTP_CONNECTIONS; ++i) { if (conn->connections[i] && conn->connections[i]->state == HTTP_CONN_OFFLINE) { purple_debug_info("jabber", "bosh: Reconnecting httpconn " "(%i, %p)\n", i, conn->connections[i]); http_connection_connect(conn->connections[i]); return NULL; } } /* Fourth loop, look for one that's NULL and create a new connection */ for (i = 0; i < NUM_HTTP_CONNECTIONS; ++i) { if (!conn->connections[i]) { conn->connections[i] = jabber_bosh_http_connection_init(conn); purple_debug_info("jabber", "bosh: Creating and connecting new httpconn " "(%i, %p)\n", i, conn->connections[i]); http_connection_connect(conn->connections[i]); return NULL; } } purple_debug_warning("jabber", "Could not find a HTTP connection!\n"); /* None available. */ return NULL; }
PurpleBOSHConnection* jabber_bosh_connection_init(JabberStream *js, const char *url) { PurpleBOSHConnection *conn; char *host, *path, *user, *passwd; int port; if (!purple_url_parse(url, &host, &port, &path, &user, &passwd)) { purple_debug_info("jabber", "Unable to parse given URL.\n"); return NULL; } conn = g_new0(PurpleBOSHConnection, 1); conn->host = host; conn->port = port; conn->path = g_strdup_printf("/%s", path); g_free(path); conn->pipelining = TRUE; if (purple_ip_address_is_valid(host)) js->serverFQDN = g_strdup(js->user->domain); else js->serverFQDN = g_strdup(host); if ((user && user[0] != '\0') || (passwd && passwd[0] != '\0')) { purple_debug_info("jabber", "Ignoring unexpected username and password " "in BOSH URL.\n"); } g_free(user); g_free(passwd); conn->js = js; /* * Random 64-bit integer masked off by 2^52 - 1. * * This should produce a random integer in the range [0, 2^52). It's * unlikely we'll send enough packets in one session to overflow the rid. */ conn->rid = ((guint64)g_random_int() << 32) | g_random_int(); conn->rid &= 0xFFFFFFFFFFFFFLL; conn->pending = purple_circ_buffer_new(0 /* default grow size */); conn->state = BOSH_CONN_OFFLINE; if (purple_strcasestr(url, "https://") != NULL) conn->ssl = TRUE; else conn->ssl = FALSE; conn->connections[0] = jabber_bosh_http_connection_init(conn); return conn; }
static PurpleHTTPConnection * find_available_http_connection(PurpleBOSHConnection *conn) { int i; if (purple_debug_is_verbose()) { for (i = 0; i < NUM_HTTP_CONNECTIONS; ++i) { PurpleHTTPConnection *httpconn = conn->connections[i]; if (httpconn == NULL) purple_debug_misc("jabber", "BOSH %p->connections[%d] = (nil)\n", conn, i); else purple_debug_misc("jabber", "BOSH %p->connections[%d] = %p, state = %d" ", requests = %d\n", conn, i, httpconn, httpconn->state, httpconn->requests); } } /* Easy solution: Does everyone involved support pipelining? Hooray! Just use * one TCP connection! */ if (conn->pipelining) return conn->connections[0]->state == HTTP_CONN_CONNECTED ? conn->connections[0] : NULL; /* First loop, look for a connection that's ready */ for (i = 0; i < NUM_HTTP_CONNECTIONS; ++i) { if (conn->connections[i] && conn->connections[i]->state == HTTP_CONN_CONNECTED && conn->connections[i]->requests == 0) return conn->connections[i]; } /* Second loop, is something currently connecting? If so, just queue up. */ for (i = 0; i < NUM_HTTP_CONNECTIONS; ++i) { if (conn->connections[i] && conn->connections[i]->state == HTTP_CONN_CONNECTING) return NULL; } /* Third loop, look for one that's NULL and create a new connection */ for (i = 0; i < NUM_HTTP_CONNECTIONS; ++i) { if (!conn->connections[i]) { purple_debug_info("jabber", "bosh: Creating and connecting new httpconn\n"); conn->connections[i] = jabber_bosh_http_connection_init(conn); http_connection_connect(conn->connections[i]); return NULL; } } purple_debug_warning("jabber", "Could not find a HTTP connection!\n"); /* None available. */ return NULL; }
static void http_connection_disconnected(PurpleHTTPConnection *conn) { /* * Well, then. Fine! I never liked you anyway, server! I was cheating on you * with AIM! */ conn->state = HTTP_CONN_OFFLINE; if (conn->psc) { purple_ssl_close(conn->psc); conn->psc = NULL; } else if (conn->fd >= 0) { close(conn->fd); conn->fd = -1; } if (conn->readh) { purple_input_remove(conn->readh); conn->readh = 0; } if (conn->writeh) { purple_input_remove(conn->writeh); conn->writeh = 0; } if (conn->requests > 0 && conn->read_buf->len == 0) { purple_debug_error("jabber", "bosh: Adjusting BOSHconn requests (%d) to %d\n", conn->bosh->requests, conn->bosh->requests - conn->requests); conn->bosh->requests -= conn->requests; conn->requests = 0; } if (conn->bosh->pipelining) { /* Hmmmm, fall back to multiple connections */ conn->bosh->pipelining = FALSE; if (conn->bosh->connections[1] == NULL) { conn->bosh->connections[1] = jabber_bosh_http_connection_init(conn->bosh); http_connection_connect(conn->bosh->connections[1]); } } if (++conn->bosh->failed_connections == MAX_FAILED_CONNECTIONS) { purple_connection_error_reason(conn->bosh->js->gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("Unable to establish a connection with the server")); } else { /* No! Please! Take me back. It was me, not you! I was weak! */ http_connection_connect(conn); } }
static void jabber_bosh_disable_pipelining(PurpleBOSHConnection *bosh) { /* Do nothing if it's already disabled */ if (!bosh->pipelining) return; purple_debug_info("jabber", "BOSH: Disabling pipelining on conn %p\n", bosh); bosh->pipelining = FALSE; if (bosh->connections[1] == NULL) { bosh->connections[1] = jabber_bosh_http_connection_init(bosh); http_connection_connect(bosh->connections[1]); } else { /* Shouldn't happen; this should be the only place pipelining * is turned off. */ g_warn_if_reached(); } }