libpurple/protocols/jabber/bosh.c

branch
cpw.darkrain42.xmpp.bosh
changeset 25488
acdb4dbab299
parent 25487
00e94f044205
child 25489
9c591341d172
equal deleted inserted replaced
25487:00e94f044205 25488:acdb4dbab299
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
64 struct _PurpleHTTPConnection { 62 struct _PurpleHTTPConnection {
65 int fd; 63 int fd;
66 char *host; 64 char *host;
67 int port; 65 int port;
68 int ie_handle; 66 int ie_handle;
69 GQueue *requests; /* Queue of PurpleHTTPRequestCallbacks */ 67 int requests; /* number of outstanding HTTP requests */
70 68
71 PurpleHTTPResponse *current_response;
72 GString *buf; 69 GString *buf;
73 gboolean headers_done; 70 gboolean headers_done;
74 gsize handled_len; 71 gsize handled_len;
75 gsize body_len; 72 gsize body_len;
76 73
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
159 g_free(conn->host); 141 g_free(conn->host);
160 142
161 if (conn->buf) 143 if (conn->buf)
162 g_string_free(conn->buf, TRUE); 144 g_string_free(conn->buf, TRUE);
163 145
164 if (conn->requests)
165 g_queue_free(conn->requests);
166
167 if (conn->current_response)
168 jabber_bosh_http_response_destroy(conn->current_response);
169
170 if (conn->ie_handle) 146 if (conn->ie_handle)
171 purple_input_remove(conn->ie_handle); 147 purple_input_remove(conn->ie_handle);
172 if (conn->fd > 0) 148 if (conn->fd >= 0)
173 close(conn->fd); 149 close(conn->fd);
174 150
175 g_free(conn); 151 g_free(conn);
176 } 152 }
177 153
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

mercurial