| 27 #include "xmlnode.h" |
27 #include "xmlnode.h" |
| 28 |
28 |
| 29 #include "bosh.h" |
29 #include "bosh.h" |
| 30 |
30 |
| 31 typedef struct _PurpleHTTPRequest PurpleHTTPRequest; |
31 typedef struct _PurpleHTTPRequest PurpleHTTPRequest; |
| 32 typedef struct _PurpleHTTPResponse PurpleHTTPResponse; |
|
| 33 typedef struct _PurpleHTTPConnection PurpleHTTPConnection; |
32 typedef struct _PurpleHTTPConnection PurpleHTTPConnection; |
| 34 |
33 |
| 35 typedef void (*PurpleHTTPConnectionConnectFunction)(PurpleHTTPConnection *conn); |
34 typedef void (*PurpleHTTPConnectionConnectFunction)(PurpleHTTPConnection *conn); |
| 36 typedef void (*PurpleHTTPConnectionDisconnectFunction)(PurpleHTTPConnection *conn); |
35 typedef void (*PurpleHTTPConnectionDisconnectFunction)(PurpleHTTPConnection *conn); |
| 37 typedef void (*PurpleHTTPRequestCallback)(PurpleHTTPResponse *res, void *userdata); |
|
| 38 typedef void (*PurpleBOSHConnectionConnectFunction)(PurpleBOSHConnection *conn); |
36 typedef void (*PurpleBOSHConnectionConnectFunction)(PurpleBOSHConnection *conn); |
| 39 typedef void (*PurpleBOSHConnectionReceiveFunction)(PurpleBOSHConnection *conn, xmlnode *node); |
37 typedef void (*PurpleBOSHConnectionReceiveFunction)(PurpleBOSHConnection *conn, xmlnode *node); |
| 40 |
38 |
| 41 static char *bosh_useragent = NULL; |
39 static char *bosh_useragent = NULL; |
| 42 |
40 |
| 79 PurpleHTTPConnectionConnectFunction disconnect_cb; |
76 PurpleHTTPConnectionConnectFunction disconnect_cb; |
| 80 void *userdata; |
77 void *userdata; |
| 81 }; |
78 }; |
| 82 |
79 |
| 83 struct _PurpleHTTPRequest { |
80 struct _PurpleHTTPRequest { |
| 84 PurpleHTTPRequestCallback cb; |
|
| 85 const char *path; |
81 const char *path; |
| 86 char *data; |
82 char *data; |
| 87 int data_len; |
83 int data_len; |
| 88 void *userdata; |
84 void *userdata; |
| 89 }; |
85 }; |
| 90 |
86 |
| 91 struct _PurpleHTTPResponse { |
|
| 92 char *data; |
|
| 93 int data_len; |
|
| 94 }; |
|
| 95 |
|
| 96 static void jabber_bosh_connection_stream_restart(PurpleBOSHConnection *conn); |
87 static void jabber_bosh_connection_stream_restart(PurpleBOSHConnection *conn); |
| 97 static gboolean jabber_bosh_connection_error_check(PurpleBOSHConnection *conn, xmlnode *node); |
88 static gboolean jabber_bosh_connection_error_check(PurpleBOSHConnection *conn, xmlnode *node); |
| 98 static void jabber_bosh_connection_received(PurpleBOSHConnection *conn, xmlnode *node); |
89 static void jabber_bosh_connection_received(PurpleBOSHConnection *conn, xmlnode *node); |
| 99 static void jabber_bosh_connection_http_received_cb(PurpleHTTPResponse *res, void *userdata); |
|
| 100 static void jabber_bosh_connection_send_native(PurpleBOSHConnection *conn, xmlnode *node); |
90 static void jabber_bosh_connection_send_native(PurpleBOSHConnection *conn, xmlnode *node); |
| 101 |
91 |
| 102 static void jabber_bosh_http_connection_connect(PurpleHTTPConnection *conn); |
92 static void jabber_bosh_http_connection_connect(PurpleHTTPConnection *conn); |
| 103 static void jabber_bosh_http_connection_send_request(PurpleHTTPConnection *conn, PurpleHTTPRequest *req); |
93 static void jabber_bosh_http_connection_send_request(PurpleHTTPConnection *conn, PurpleHTTPRequest *req); |
| 104 |
94 |
| 132 { |
122 { |
| 133 g_free(req->data); |
123 g_free(req->data); |
| 134 g_free(req); |
124 g_free(req); |
| 135 } |
125 } |
| 136 |
126 |
| 137 static void |
|
| 138 jabber_bosh_http_response_destroy(PurpleHTTPResponse *res) |
|
| 139 { |
|
| 140 g_free(res->data); |
|
| 141 g_free(res); |
|
| 142 } |
|
| 143 |
|
| 144 static PurpleHTTPConnection* |
127 static PurpleHTTPConnection* |
| 145 jabber_bosh_http_connection_init(const char *host, int port) |
128 jabber_bosh_http_connection_init(const char *host, int port) |
| 146 { |
129 { |
| 147 PurpleHTTPConnection *conn = g_new0(PurpleHTTPConnection, 1); |
130 PurpleHTTPConnection *conn = g_new0(PurpleHTTPConnection, 1); |
| 148 conn->host = g_strdup(host); |
131 conn->host = g_strdup(host); |
| 149 conn->port = port; |
132 conn->port = port; |
| 150 conn->fd = -1; |
133 conn->fd = -1; |
| 151 conn->requests = g_queue_new(); |
|
| 152 |
134 |
| 153 return conn; |
135 return conn; |
| 154 } |
136 } |
| 155 |
137 |
| 156 static void |
138 static void |
| 394 conn->receive_cb = boot_response_cb; |
370 conn->receive_cb = boot_response_cb; |
| 395 jabber_bosh_connection_send_native(conn, init); |
371 jabber_bosh_connection_send_native(conn, init); |
| 396 xmlnode_free(init); |
372 xmlnode_free(init); |
| 397 } |
373 } |
| 398 |
374 |
| 399 static void jabber_bosh_connection_http_received_cb(PurpleHTTPResponse *res, void *userdata) { |
375 static void |
| |
376 http_received_cb(const char *data, int len, void *userdata) |
| |
377 { |
| 400 PurpleBOSHConnection *conn = userdata; |
378 PurpleBOSHConnection *conn = userdata; |
| 401 if (conn->receive_cb) { |
379 if (conn->receive_cb) { |
| 402 xmlnode *node = xmlnode_from_str(res->data, res->data_len); |
380 xmlnode *node = xmlnode_from_str(data, len); |
| 403 if (node) { |
381 if (node) { |
| 404 char *txt = xmlnode_to_formatted_str(node, NULL); |
382 char *txt = xmlnode_to_formatted_str(node, NULL); |
| 405 printf("\njabber_bosh_connection_http_received_cb\n%s\n", txt); |
383 printf("\nhttp_received_cb\n%s\n", txt); |
| 406 g_free(txt); |
384 g_free(txt); |
| 407 conn->receive_cb(conn, node); |
385 conn->receive_cb(conn, node); |
| 408 xmlnode_free(node); |
386 xmlnode_free(node); |
| 409 } else { |
387 } else { |
| 410 purple_debug_warning("jabber", "BOSH: Received invalid XML\n"); |
388 purple_debug_warning("jabber", "BOSH: Received invalid XML\n"); |
| 454 static void jabber_bosh_connection_send_native(PurpleBOSHConnection *conn, xmlnode *node) { |
432 static void jabber_bosh_connection_send_native(PurpleBOSHConnection *conn, xmlnode *node) { |
| 455 PurpleHTTPRequest *request; |
433 PurpleHTTPRequest *request; |
| 456 |
434 |
| 457 request = g_new0(PurpleHTTPRequest, 1); |
435 request = g_new0(PurpleHTTPRequest, 1); |
| 458 request->path = conn->path; |
436 request->path = conn->path; |
| 459 request->cb = jabber_bosh_connection_http_received_cb; |
|
| 460 request->userdata = conn; |
437 request->userdata = conn; |
| 461 |
438 |
| 462 request->data = xmlnode_to_str(node, &(request->data_len)); |
439 request->data = xmlnode_to_str(node, &(request->data_len)); |
| 463 |
440 |
| 464 jabber_bosh_http_connection_send_request(conn->conn_a, request); |
441 jabber_bosh_http_connection_send_request(conn->conn_a, request); |
| 491 |
468 |
| 492 static void |
469 static void |
| 493 jabber_bosh_http_connection_process(PurpleHTTPConnection *conn) |
470 jabber_bosh_http_connection_process(PurpleHTTPConnection *conn) |
| 494 { |
471 { |
| 495 PurpleBOSHConnection *bosh_conn = conn->userdata; |
472 PurpleBOSHConnection *bosh_conn = conn->userdata; |
| 496 PurpleHTTPRequestCallback cb; |
|
| 497 const char *cursor; |
473 const char *cursor; |
| 498 |
|
| 499 if (!conn->current_response) |
|
| 500 conn->current_response = g_new0(PurpleHTTPResponse, 1); |
|
| 501 |
474 |
| 502 cursor = conn->buf->str + conn->handled_len; |
475 cursor = conn->buf->str + conn->handled_len; |
| 503 |
476 |
| 504 if (!conn->headers_done) { |
477 if (!conn->headers_done) { |
| 505 const char *content_length = purple_strcasestr(cursor, "\r\nContent-Length"); |
478 const char *content_length = purple_strcasestr(cursor, "\r\nContent-Length"); |
| 531 |
504 |
| 532 /* Have we read all that the Content-Length promised us? */ |
505 /* Have we read all that the Content-Length promised us? */ |
| 533 if (conn->buf->len - conn->handled_len < conn->body_len) |
506 if (conn->buf->len - conn->handled_len < conn->body_len) |
| 534 return; |
507 return; |
| 535 |
508 |
| 536 cb = g_queue_pop_head(conn->requests); |
509 --conn->requests; |
| 537 |
510 |
| 538 #warning For a pure HTTP 1.1 stack, this would need to be handled elsewhere. |
511 #warning For a pure HTTP 1.1 stack, this would need to be handled elsewhere. |
| 539 if (bosh_conn->ready && g_queue_is_empty(conn->requests)) { |
512 if (bosh_conn->ready && conn->requests == 0) { |
| 540 jabber_bosh_connection_send(bosh_conn, NULL); |
513 jabber_bosh_connection_send(bosh_conn, NULL); |
| 541 purple_debug_misc("jabber", "BOSH: Sending an empty request\n"); |
514 purple_debug_misc("jabber", "BOSH: Sending an empty request\n"); |
| 542 } |
515 } |
| 543 |
516 |
| 544 if (cb) { |
517 http_received_cb(conn->buf->str + conn->handled_len, conn->body_len, |
| 545 conn->current_response->data_len = conn->body_len; |
518 conn->userdata); |
| 546 conn->current_response->data = g_memdup(conn->buf->str + conn->handled_len, conn->body_len + 1); |
|
| 547 |
|
| 548 cb(conn->current_response, conn->userdata); |
|
| 549 } else { |
|
| 550 purple_debug_warning("jabber", "Received HTTP response before POST\n"); |
|
| 551 } |
|
| 552 |
519 |
| 553 g_string_free(conn->buf, TRUE); |
520 g_string_free(conn->buf, TRUE); |
| 554 conn->buf = NULL; |
521 conn->buf = NULL; |
| 555 jabber_bosh_http_response_destroy(conn->current_response); |
522 conn->headers_done = FALSE; |
| 556 conn->current_response = NULL; |
523 conn->handled_len = conn->body_len = 0; |
| 557 conn->headers_done = conn->handled_len = conn->body_len = 0; |
|
| 558 } |
524 } |
| 559 |
525 |
| 560 static void |
526 static void |
| 561 jabber_bosh_http_connection_read(gpointer data, gint fd, |
527 jabber_bosh_http_connection_read(gpointer data, gint fd, |
| 562 PurpleInputCondition condition) |
528 PurpleInputCondition condition) |
| 660 purple_debug_misc("jabber", "BOSH out: %s\n", packet->str); |
626 purple_debug_misc("jabber", "BOSH out: %s\n", packet->str); |
| 661 /* TODO: Better error handling, circbuffer or possible integration with |
627 /* TODO: Better error handling, circbuffer or possible integration with |
| 662 * low-level code in jabber.c */ |
628 * low-level code in jabber.c */ |
| 663 ret = write(conn->fd, packet->str, packet->len); |
629 ret = write(conn->fd, packet->str, packet->len); |
| 664 |
630 |
| |
631 ++conn->requests; |
| 665 g_string_free(packet, TRUE); |
632 g_string_free(packet, TRUE); |
| 666 g_queue_push_tail(conn->requests, req->cb); |
|
| 667 jabber_bosh_http_request_destroy(req); |
633 jabber_bosh_http_request_destroy(req); |
| 668 |
634 |
| 669 if (ret < 0 && errno == EAGAIN) |
635 if (ret < 0 && errno == EAGAIN) |
| 670 purple_debug_warning("jabber", "BOSH write would have blocked\n"); |
636 purple_debug_warning("jabber", "BOSH write would have blocked\n"); |
| 671 |
637 |