Mercurial > pidgin
comparison libpurple/protocols/jabber/bosh.c @ 25184:1ce32c6752fc
Make the Request ID a long long (fit in 2^53-1)
Standardize the BOSHConnection receive callbacks and drop two prototypes
Some annoying whitespace changes snuck in there, too. Sorry.
author | Paul Aurich <paul@darkrain42.org> |
---|---|
date | Fri, 05 Dec 2008 06:51:39 +0000 |
parents | 62d9bce9ff74 |
children | 592c2cf00fea |
comparison
equal
deleted
inserted
replaced
25183:62d9bce9ff74 | 25184:1ce32c6752fc |
---|---|
43 struct _PurpleBOSHConnection { | 43 struct _PurpleBOSHConnection { |
44 /* decoded URL */ | 44 /* decoded URL */ |
45 char *host; | 45 char *host; |
46 int port; | 46 int port; |
47 char *path; | 47 char *path; |
48 | 48 |
49 int rid; | 49 /* Must be big enough to hold 2^53 - 1 */ |
50 guint64 rid; | |
50 char *sid; | 51 char *sid; |
51 int wait; | 52 int wait; |
52 | 53 |
53 JabberStream *js; | 54 JabberStream *js; |
54 gboolean pipelining; | 55 gboolean pipelining; |
55 PurpleHTTPConnection *conn_a; | 56 PurpleHTTPConnection *conn_a; |
56 PurpleHTTPConnection *conn_b; | 57 PurpleHTTPConnection *conn_b; |
57 | 58 |
58 gboolean ready; | 59 gboolean ready; |
59 PurpleBOSHConnectionConnectFunction connect_cb; | 60 PurpleBOSHConnectionConnectFunction connect_cb; |
60 PurpleBOSHConnectionReceiveFunction receive_cb; | 61 PurpleBOSHConnectionReceiveFunction receive_cb; |
61 }; | 62 }; |
62 | 63 |
95 }; | 96 }; |
96 | 97 |
97 static void jabber_bosh_connection_stream_restart(PurpleBOSHConnection *conn); | 98 static void jabber_bosh_connection_stream_restart(PurpleBOSHConnection *conn); |
98 static gboolean jabber_bosh_connection_error_check(PurpleBOSHConnection *conn, xmlnode *node); | 99 static gboolean jabber_bosh_connection_error_check(PurpleBOSHConnection *conn, xmlnode *node); |
99 static void jabber_bosh_connection_received(PurpleBOSHConnection *conn, xmlnode *node); | 100 static void jabber_bosh_connection_received(PurpleBOSHConnection *conn, xmlnode *node); |
100 static void jabber_bosh_connection_auth_response(PurpleBOSHConnection *conn, xmlnode *node); | |
101 static void jabber_bosh_connection_boot_response(PurpleBOSHConnection *conn, xmlnode *node); | |
102 static void jabber_bosh_connection_http_received_cb(PurpleHTTPRequest *req, PurpleHTTPResponse *res, void *userdata); | 101 static void jabber_bosh_connection_http_received_cb(PurpleHTTPRequest *req, PurpleHTTPResponse *res, void *userdata); |
103 static void jabber_bosh_connection_send_native(PurpleBOSHConnection *conn, xmlnode *node); | 102 static void jabber_bosh_connection_send_native(PurpleBOSHConnection *conn, xmlnode *node); |
104 | 103 |
105 static void jabber_bosh_http_connection_connect(PurpleHTTPConnection *conn); | 104 static void jabber_bosh_http_connection_connect(PurpleHTTPConnection *conn); |
106 static void jabber_bosh_http_connection_send_request(PurpleHTTPConnection *conn, PurpleHTTPRequest *req); | 105 static void jabber_bosh_http_connection_send_request(PurpleHTTPConnection *conn, PurpleHTTPRequest *req); |
251 } | 250 } |
252 | 251 |
253 void jabber_bosh_connection_close(PurpleBOSHConnection *conn) | 252 void jabber_bosh_connection_close(PurpleBOSHConnection *conn) |
254 { | 253 { |
255 xmlnode *packet = xmlnode_new("body"); | 254 xmlnode *packet = xmlnode_new("body"); |
256 char *tmp; | 255 /* XEP-0124: The rid must not exceed 16 characters */ |
257 | 256 char rid[17]; |
257 g_snprintf(rid, sizeof(rid), "%" G_GUINT64_FORMAT, ++conn->rid); | |
258 xmlnode_set_attrib(packet, "type", "terminate"); | 258 xmlnode_set_attrib(packet, "type", "terminate"); |
259 xmlnode_set_attrib(packet, "xmlns", "http://jabber.org/protocol/httpbind"); | 259 xmlnode_set_attrib(packet, "xmlns", "http://jabber.org/protocol/httpbind"); |
260 xmlnode_set_attrib(packet, "sid", conn->sid); | 260 xmlnode_set_attrib(packet, "sid", conn->sid); |
261 tmp = g_strdup_printf("%d", ++conn->rid); | 261 xmlnode_set_attrib(packet, "rid", rid); |
262 xmlnode_set_attrib(packet, "rid", tmp); | |
263 g_free(tmp); | |
264 | 262 |
265 jabber_bosh_connection_send_native(conn, packet); | 263 jabber_bosh_connection_send_native(conn, packet); |
266 xmlnode_free(packet); | 264 xmlnode_free(packet); |
267 } | 265 } |
268 | 266 |
269 static void jabber_bosh_connection_stream_restart(PurpleBOSHConnection *conn) { | 267 static void jabber_bosh_connection_stream_restart(PurpleBOSHConnection *conn) { |
270 xmlnode *restart = xmlnode_new("body"); | 268 xmlnode *restart = xmlnode_new("body"); |
271 char *tmp = NULL; | 269 /* XEP-0124: The rid must not exceed 16 characters */ |
272 conn->rid++; | 270 char rid[17]; |
273 xmlnode_set_attrib(restart, "rid", tmp = g_strdup_printf("%d", conn->rid)); | 271 g_snprintf(rid, sizeof(rid), "%" G_GUINT64_FORMAT, ++conn->rid); |
274 g_free(tmp); | 272 xmlnode_set_attrib(restart, "rid", rid); |
275 xmlnode_set_attrib(restart, "sid", conn->sid); | 273 xmlnode_set_attrib(restart, "sid", conn->sid); |
276 xmlnode_set_attrib(restart, "to", conn->js->user->domain); | 274 xmlnode_set_attrib(restart, "to", conn->js->user->domain); |
277 xmlnode_set_attrib(restart, "xml:lang", "en"); | 275 xmlnode_set_attrib(restart, "xml:lang", "en"); |
278 xmlnode_set_attrib(restart, "xmpp:restart", "true"); | 276 xmlnode_set_attrib(restart, "xmpp:restart", "true"); |
279 xmlnode_set_attrib(restart, "xmlns", "http://jabber.org/protocol/httpbind"); | 277 xmlnode_set_attrib(restart, "xmlns", "http://jabber.org/protocol/httpbind"); |
283 xmlnode_free(restart); | 281 xmlnode_free(restart); |
284 } | 282 } |
285 | 283 |
286 static gboolean jabber_bosh_connection_error_check(PurpleBOSHConnection *conn, xmlnode *node) { | 284 static gboolean jabber_bosh_connection_error_check(PurpleBOSHConnection *conn, xmlnode *node) { |
287 const char *type; | 285 const char *type; |
288 | 286 |
289 if (!node) return FALSE; | |
290 type = xmlnode_get_attrib(node, "type"); | 287 type = xmlnode_get_attrib(node, "type"); |
291 | 288 |
292 if (type != NULL && !strcmp(type, "terminate")) { | 289 if (type != NULL && !strcmp(type, "terminate")) { |
293 conn->ready = FALSE; | 290 conn->ready = FALSE; |
294 purple_connection_error_reason (conn->js->gc, | 291 purple_connection_error_reason (conn->js->gc, |
300 } | 297 } |
301 | 298 |
302 static void jabber_bosh_connection_received(PurpleBOSHConnection *conn, xmlnode *node) { | 299 static void jabber_bosh_connection_received(PurpleBOSHConnection *conn, xmlnode *node) { |
303 xmlnode *child; | 300 xmlnode *child; |
304 JabberStream *js = conn->js; | 301 JabberStream *js = conn->js; |
305 | 302 |
306 if (node == NULL) return; | 303 g_return_if_fail(node == NULL); |
307 | 304 if (jabber_bosh_connection_error_check(conn, node)) |
308 if (jabber_bosh_connection_error_check(conn, node) == TRUE) return; | 305 return; |
309 | 306 |
310 child = node->child; | 307 child = node->child; |
311 while (child != 0) { | 308 while (child != NULL) { |
312 if (child->type == XMLNODE_TYPE_TAG) { | 309 if (child->type == XMLNODE_TYPE_TAG) { |
313 xmlnode *session = NULL; | 310 xmlnode *session = NULL; |
314 if (!strcmp(child->name, "iq")) session = xmlnode_get_child(child, "session"); | 311 if (!strcmp(child->name, "iq")) session = xmlnode_get_child(child, "session"); |
315 if (session) { | 312 if (session) { |
316 conn->ready = TRUE; | 313 conn->ready = TRUE; |
319 } | 316 } |
320 child = child->next; | 317 child = child->next; |
321 } | 318 } |
322 } | 319 } |
323 | 320 |
324 static void jabber_bosh_connection_auth_response(PurpleBOSHConnection *conn, xmlnode *node) { | 321 static void auth_response_cb(PurpleBOSHConnection *conn, xmlnode *node) { |
325 xmlnode *child = node->child; | 322 xmlnode *child; |
326 | 323 |
327 if (jabber_bosh_connection_error_check(conn, node) == TRUE) return; | 324 g_return_if_fail(node == NULL); |
328 | 325 if (jabber_bosh_connection_error_check(conn, node)) |
326 return; | |
327 | |
328 child = node->child; | |
329 while(child != NULL && child->type != XMLNODE_TYPE_TAG) { | 329 while(child != NULL && child->type != XMLNODE_TYPE_TAG) { |
330 child = child->next; | 330 child = child->next; |
331 } | 331 } |
332 | 332 |
333 /* We're only expecting one XML node here, so only process the first one */ | |
333 if (child != NULL && child->type == XMLNODE_TYPE_TAG) { | 334 if (child != NULL && child->type == XMLNODE_TYPE_TAG) { |
334 JabberStream *js = conn->js; | 335 JabberStream *js = conn->js; |
335 if (!strcmp(child->name, "success")) { | 336 if (!strcmp(child->name, "success")) { |
336 jabber_bosh_connection_stream_restart(conn); | 337 jabber_bosh_connection_stream_restart(conn); |
337 jabber_process_packet(js, &child); | 338 jabber_process_packet(js, &child); |
338 conn->receive_cb = jabber_bosh_connection_received; | 339 conn->receive_cb = jabber_bosh_connection_received; |
339 } else { | 340 } else { |
340 js->state = JABBER_STREAM_AUTHENTICATING; | 341 js->state = JABBER_STREAM_AUTHENTICATING; |
341 jabber_process_packet(js, &child); | 342 jabber_process_packet(js, &child); |
342 } | 343 } |
343 } else printf("\n!! no child!!\n"); | |
344 } | |
345 | |
346 static void jabber_bosh_connection_boot_response(PurpleBOSHConnection *conn, xmlnode *node) { | |
347 char *version; | |
348 | |
349 if (jabber_bosh_connection_error_check(conn, node) == TRUE) return; | |
350 | |
351 if (xmlnode_get_attrib(node, "sid")) { | |
352 conn->sid = g_strdup(xmlnode_get_attrib(node, "sid")); | |
353 } else { | 344 } else { |
354 purple_debug_info("jabber", "Connection manager doesn't behave BOSH-like!\n"); | 345 purple_debug_warning("jabber", "Received unexepcted empty BOSH packet.\n"); |
355 } | 346 } |
356 | 347 } |
357 if ((version = g_strdup(xmlnode_get_attrib(node, "ver")))) { | 348 |
358 char *dot = strstr(version, "."); | 349 static void boot_response_cb(PurpleBOSHConnection *conn, xmlnode *node) { |
350 const char *sid, *version; | |
351 | |
352 g_return_if_fail(node != NULL); | |
353 if (jabber_bosh_connection_error_check(conn, node)) | |
354 return; | |
355 | |
356 sid = xmlnode_get_attrib(node, "sid"); | |
357 version = xmlnode_get_attrib(node, "ver"); | |
358 | |
359 if (sid) { | |
360 conn->sid = g_strdup(sid); | |
361 } else { | |
362 purple_connection_error_reason(conn->js->gc, | |
363 PURPLE_CONNECTION_ERROR_NETWORK_ERROR, | |
364 _("No session ID given")); | |
365 return; | |
366 } | |
367 | |
368 if (version) { | |
369 const char *dot = strstr(version, "."); | |
359 int major = atoi(version); | 370 int major = atoi(version); |
360 int minor = atoi(dot + 1); | 371 int minor = atoi(dot + 1); |
361 | 372 |
362 purple_debug_info("jabber", "BOSH connection manager version %s\n", version); | 373 purple_debug_info("jabber", "BOSH connection manager version %s\n", version); |
363 | 374 |
375 /* TODO: Are major increments incompatible? */ | |
364 if (major > 1 || (major == 1 && minor >= 6)) { | 376 if (major > 1 || (major == 1 && minor >= 6)) { |
365 xmlnode *packet = xmlnode_get_child(node, "features"); | 377 xmlnode *packet = xmlnode_get_child(node, "features"); |
366 conn->js->use_bosh = TRUE; | 378 conn->js->use_bosh = TRUE; |
367 conn->receive_cb = jabber_bosh_connection_auth_response; | 379 conn->receive_cb = auth_response_cb; |
368 jabber_stream_features_parse(conn->js, packet); | 380 jabber_stream_features_parse(conn->js, packet); |
369 } else { | 381 } else { |
370 purple_connection_error_reason(conn->js->gc, | 382 purple_connection_error_reason(conn->js->gc, |
371 PURPLE_CONNECTION_ERROR_NETWORK_ERROR, | 383 PURPLE_CONNECTION_ERROR_NETWORK_ERROR, |
372 _("Unsupported version of BOSH protocol")); | 384 _("Unsupported version of BOSH protocol")); |
373 } | 385 } |
374 | |
375 g_free(version); | |
376 } else { | 386 } else { |
377 purple_debug_info("jabber", "Missing version in BOSH initiation\n"); | 387 purple_debug_info("jabber", "Missing version in BOSH initiation\n"); |
378 } | 388 } |
379 } | 389 } |
380 | 390 |
381 static void jabber_bosh_connection_boot(PurpleBOSHConnection *conn) { | 391 static void jabber_bosh_connection_boot(PurpleBOSHConnection *conn) { |
382 char *tmp; | |
383 xmlnode *init = xmlnode_new("body"); | 392 xmlnode *init = xmlnode_new("body"); |
393 /* XEP-0124: The rid must not exceed 16 characters */ | |
394 char rid[17]; | |
395 g_snprintf(rid, sizeof(rid), "%" G_GUINT64_FORMAT, ++conn->rid); | |
384 xmlnode_set_attrib(init, "content", "text/xml; charset=utf-8"); | 396 xmlnode_set_attrib(init, "content", "text/xml; charset=utf-8"); |
385 xmlnode_set_attrib(init, "secure", "true"); | 397 xmlnode_set_attrib(init, "secure", "true"); |
386 //xmlnode_set_attrib(init, "route", tmp = g_strdup_printf("xmpp:%s:5222", conn->js->user->domain)); | 398 /* |
387 //g_free(tmp); | 399 xmlnode_set_attrib(init, "route", tmp = g_strdup_printf("xmpp:%s:5222", conn->js->user->domain)); |
400 g_free(tmp); | |
401 */ | |
388 xmlnode_set_attrib(init, "to", conn->js->user->domain); | 402 xmlnode_set_attrib(init, "to", conn->js->user->domain); |
389 xmlnode_set_attrib(init, "xml:lang", "en"); | 403 xmlnode_set_attrib(init, "xml:lang", "en"); |
390 xmlnode_set_attrib(init, "xmpp:version", "1.0"); | 404 xmlnode_set_attrib(init, "xmpp:version", "1.0"); |
391 xmlnode_set_attrib(init, "ver", "1.6"); | 405 xmlnode_set_attrib(init, "ver", "1.6"); |
392 xmlnode_set_attrib(init, "xmlns:xmpp", "urn:xmpp:xbosh"); | 406 xmlnode_set_attrib(init, "xmlns:xmpp", "urn:xmpp:xbosh"); |
393 xmlnode_set_attrib(init, "rid", tmp = g_strdup_printf("%d", conn->rid)); | 407 xmlnode_set_attrib(init, "rid", rid); |
394 g_free(tmp); | |
395 xmlnode_set_attrib(init, "wait", "60"); /* this should be adjusted automatically according to real time network behavior */ | 408 xmlnode_set_attrib(init, "wait", "60"); /* this should be adjusted automatically according to real time network behavior */ |
396 xmlnode_set_attrib(init, "xmlns", "http://jabber.org/protocol/httpbind"); | 409 xmlnode_set_attrib(init, "xmlns", "http://jabber.org/protocol/httpbind"); |
397 xmlnode_set_attrib(init, "hold", "1"); | 410 xmlnode_set_attrib(init, "hold", "1"); |
398 | 411 |
399 conn->receive_cb = jabber_bosh_connection_boot_response; | 412 conn->receive_cb = boot_response_cb; |
400 jabber_bosh_connection_send_native(conn, init); | 413 jabber_bosh_connection_send_native(conn, init); |
401 xmlnode_free(init); | 414 xmlnode_free(init); |
402 } | 415 } |
403 | 416 |
404 static void jabber_bosh_connection_http_received_cb(PurpleHTTPRequest *req, PurpleHTTPResponse *res, void *userdata) { | 417 static void jabber_bosh_connection_http_received_cb(PurpleHTTPRequest *req, PurpleHTTPResponse *res, void *userdata) { |
417 } else purple_debug_info("jabber", "missing receive_cb of PurpleBOSHConnection.\n"); | 430 } else purple_debug_info("jabber", "missing receive_cb of PurpleBOSHConnection.\n"); |
418 } | 431 } |
419 | 432 |
420 void jabber_bosh_connection_send(PurpleBOSHConnection *conn, xmlnode *node) { | 433 void jabber_bosh_connection_send(PurpleBOSHConnection *conn, xmlnode *node) { |
421 xmlnode *packet = xmlnode_new("body"); | 434 xmlnode *packet = xmlnode_new("body"); |
422 char *tmp; | 435 /* XEP-0124: The rid must not exceed 16 characters */ |
423 conn->rid++; | 436 char rid[17]; |
437 g_snprintf(rid, sizeof(rid), "%" G_GUINT64_FORMAT, ++conn->rid); | |
424 xmlnode_set_attrib(packet, "xmlns", "http://jabber.org/protocol/httpbind"); | 438 xmlnode_set_attrib(packet, "xmlns", "http://jabber.org/protocol/httpbind"); |
425 xmlnode_set_attrib(packet, "sid", conn->sid); | 439 xmlnode_set_attrib(packet, "sid", conn->sid); |
426 tmp = g_strdup_printf("%d", conn->rid); | 440 xmlnode_set_attrib(packet, "rid", rid); |
427 xmlnode_set_attrib(packet, "rid", tmp); | |
428 g_free(tmp); | |
429 | 441 |
430 if (node) { | 442 if (node) { |
431 xmlnode_insert_child(packet, node); | 443 xmlnode_insert_child(packet, node); |
432 if (conn->ready == TRUE) xmlnode_set_attrib(node, "xmlns", "jabber:client"); | 444 if (conn->ready == TRUE) xmlnode_set_attrib(node, "xmlns", "jabber:client"); |
433 } | 445 } |