comparison libpurple/protocols/jabber/bosh.c @ 25669:828640306e31

Don't track a cb-per-POST and remove the PurpleHTTPResponse structure. The only callback ever used is http_received_cb and the ordering of responses from the server is not guaranteed to match the order of our requests, so the metaphor of matching them doesn't make sense. Instead of that, just track the number of requests (to ensure there is always a request outstanding). Additionally, pass the data const-ified instead of copying it. It's just fed to an XML parser anyway.
author Paul Aurich <paul@darkrain42.org>
date Wed, 21 Jan 2009 00:19:33 +0000
parents 8c58f31f41eb
children c11c14dde641
comparison
equal deleted inserted replaced
25668:8c58f31f41eb 25669:828640306e31
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