Rewrote almost of pluto.c and pluto.h
Implemented changing client's uid and tag(subchannel).
Implemented publishing multicast
(This can publish to another server when the client requested with PUT).
@@ -104,17 +104,20 @@ | ||
104 | 104 | } |
105 | 105 | |
106 | 106 | apr_socket_t *listen; |
107 | - apr_pollset_t *pollset; | |
108 | 107 | mei_server_t *server = apr_pcalloc(mp, sizeof(mei_server_t)); |
109 | 108 | server->pool = mp; |
110 | 109 | server->config = config; |
110 | + server->clients = apr_hash_make(mp); | |
111 | 111 | server->executings = apr_hash_make(mp); |
112 | 112 | server->uids = apr_hash_make(mp); |
113 | 113 | server->tags = apr_hash_make(mp); |
114 | + | |
115 | + mei_server_create_listen_socket(server, &listen, mp); | |
116 | + server->socket = listen; | |
114 | 117 | mei_server_initialize_acl(server); |
115 | 118 | mei_server_initialize_channels(server); |
116 | 119 | |
117 | - apr_pollset_create(&pollset, | |
120 | + apr_pollset_create(&server->pollset, | |
118 | 121 | (apr_uint32_t) apr_atoi64(mei_config_get |
119 | 122 | (server->config, |
120 | 123 | "pluto.server.pollset.number", |
@@ -122,24 +125,21 @@ | ||
122 | 125 | apr_pollfd_t pfd = { mp, APR_POLL_SOCKET, APR_POLLIN, 0, {NULL} |
123 | 126 | , NULL |
124 | 127 | }; |
125 | - mei_server_create_listen_socket(server, &listen, mp); | |
126 | 128 | pfd.desc.s = listen; |
127 | - apr_pollset_add(pollset, &pfd); | |
129 | + apr_pollset_add(server->pollset, &pfd); | |
128 | 130 | apr_time_t timeout = apr_atoi64(mei_config_get(server->config, |
129 | 131 | "pluto.server.pollset.timeout", |
130 | 132 | "30")) * APR_USEC_PER_SEC; |
131 | 133 | |
132 | - apr_int32_t active; | |
133 | - const apr_pollfd_t *ret_pfd; | |
134 | - | |
135 | 134 | while (is_pluto_alive) { |
136 | - apr_status_t rv; | |
137 | - rv = apr_pollset_poll(pollset, timeout, &active, &ret_pfd); | |
138 | - if (rv == APR_SUCCESS) { | |
135 | + const apr_pollfd_t *ret_pfd; | |
136 | + apr_int32_t active; | |
137 | + if (apr_pollset_poll(server->pollset, timeout, &active, &ret_pfd) == | |
138 | + APR_SUCCESS) { | |
139 | 139 | int i; |
140 | 140 | for (i = 0; i < active; i++) { |
141 | 141 | if (ret_pfd[i].desc.s == listen) { |
142 | - mei_server_accept_client(server, pollset, listen); | |
142 | + mei_server_accept_client(server, listen); | |
143 | 143 | } |
144 | 144 | else { |
145 | 145 | mei_client_t *client = ret_pfd[i].client_data; |
@@ -149,7 +149,7 @@ | ||
149 | 149 | } |
150 | 150 | } |
151 | 151 | |
152 | - apr_pollset_destroy(pollset); | |
152 | + apr_pollset_destroy(server->pollset); | |
153 | 153 | apr_pool_destroy(mp); |
154 | 154 | mei_server_finalize(); |
155 | 155 |
@@ -221,11 +221,11 @@ | ||
221 | 221 | } |
222 | 222 | |
223 | 223 | static const apr_array_header_t *mei_config_get_all(mei_config_t * config, |
224 | - const char *key) | |
224 | + const char *key, | |
225 | + apr_pool_t * pool) | |
225 | 226 | { |
226 | - apr_array_header_t *values = | |
227 | - apr_array_make(apr_table_elts(config)->pool, 32, | |
228 | - sizeof(const char *)); | |
227 | + apr_array_header_t *values = apr_array_make(pool, 32, | |
228 | + sizeof(const char *)); | |
229 | 229 | apr_table_do(mei_config_add_value_to_array, values, config, key, NULL); |
230 | 230 | return values; |
231 | 231 | } |
@@ -255,7 +255,7 @@ | ||
255 | 255 | (apr_port_t) apr_atoi64(mei_config_get |
256 | 256 | (server->config, |
257 | 257 | "pluto.server.port", "8088")), |
258 | - 0, mp)); | |
258 | + (apr_int32_t) 0, mp)); | |
259 | 259 | |
260 | 260 | MEI_TRY_OR_THROW(apr_socket_create |
261 | 261 | (sock, sa->family, SOCK_STREAM, APR_PROTO_TCP, mp)); |
@@ -281,44 +281,52 @@ | ||
281 | 281 | } |
282 | 282 | |
283 | 283 | static void mei_server_accept_client(mei_server_t * server, |
284 | - apr_pollset_t * pollset, | |
285 | 284 | apr_socket_t * listen) |
286 | 285 | { |
287 | 286 | apr_socket_t *ns; |
288 | - apr_status_t rv; | |
289 | - apr_pool_t *client_pool; | |
287 | + apr_status_t rv = apr_socket_accept(&ns, listen, server->pool); | |
290 | 288 | |
291 | - MEI_TRY_OR_THROW(apr_pool_create(&client_pool, server->pool)); | |
292 | - rv = apr_socket_accept(&ns, listen, client_pool); | |
293 | - | |
294 | 289 | if (rv == APR_SUCCESS) { |
295 | - mei_client_t *client = apr_pcalloc(client_pool, sizeof(mei_client_t)); | |
296 | - apr_pollfd_t pfd = | |
297 | - { server->pool, APR_POLL_SOCKET, APR_POLLIN, 0, {NULL} | |
298 | - , client | |
299 | - }; | |
300 | - pfd.desc.s = ns; | |
290 | + mei_client_t *client; | |
291 | + apr_os_sock_t fd; | |
292 | + apr_os_sock_get(&fd, ns); | |
293 | + apr_socket_opt_set(ns, APR_SO_NONBLOCK, 1); | |
294 | + apr_socket_timeout_set(ns, (apr_interval_time_t) 0); | |
295 | + const char *sfd = apr_itoa(server->pool, fd); | |
301 | 296 | |
297 | + if ((client = | |
298 | + apr_hash_get(server->clients, sfd, | |
299 | + APR_HASH_KEY_STRING)) == NULL) { | |
300 | + apr_pool_t *client_pool; | |
301 | + MEI_TRY_OR_THROW(apr_pool_create(&client_pool, server->pool)); | |
302 | + | |
303 | + client = apr_pcalloc(client_pool, sizeof(mei_client_t)); | |
304 | + client->pool = client_pool; | |
305 | + client->connected_at = apr_time_now(); | |
306 | + client->event.committed_at = 0; | |
307 | + client->event.is_waiting = FALSE; | |
308 | + client->event.is_unbound = FALSE; | |
309 | + client->request.method = MEI_REQUEST_IS_UNKNOWN; | |
310 | + client->request.header = apr_table_make(client_pool, 32); | |
311 | + client->request.param = apr_table_make(client_pool, 32); | |
312 | + client->request.is_flash = 0; | |
313 | + client->response.close_connection = TRUE; | |
314 | + client->response.content_type = "text/html"; | |
315 | + client->response.status = 400; | |
316 | + apr_hash_set(server->clients, sfd, APR_HASH_KEY_STRING, client); | |
317 | + } | |
318 | + | |
302 | 319 | client->event_callback = mei_client_process_request; |
303 | 320 | client->parent = server; |
304 | - client->pool = client_pool; | |
305 | 321 | client->socket = ns; |
306 | - client->pollset = pollset; | |
307 | - client->connected_at = apr_time_now(); | |
308 | - client->event.committed_at = 0; | |
309 | - client->event.is_waiting = FALSE; | |
310 | - client->event.is_unbound = FALSE; | |
311 | - client->request.header = apr_hash_make(client_pool); | |
312 | - client->request.param = apr_hash_make(client_pool); | |
313 | - client->request.is_flash = 0; | |
314 | - client->response.close_connection = TRUE; | |
315 | - client->response.content_type = "text/html"; | |
316 | - client->response.status = 400; | |
322 | + client->fd = fd; | |
317 | 323 | |
318 | - apr_socket_opt_set(ns, APR_SO_NONBLOCK, 1); | |
319 | - apr_socket_timeout_set(ns, (apr_interval_time_t) 0); | |
320 | - | |
321 | - apr_pollset_add(pollset, &pfd); | |
324 | + apr_pollfd_t pfd = | |
325 | + { client->pool, APR_POLL_SOCKET, APR_POLLIN, 0, {NULL} | |
326 | + , client | |
327 | + }; | |
328 | + pfd.desc.s = client->socket; | |
329 | + apr_pollset_add(client->parent->pollset, &pfd); | |
322 | 330 | } |
323 | 331 | } |
324 | 332 |
@@ -325,10 +333,6 @@ | ||
325 | 333 | static const char *mei_server_status_code_to_string(int code) |
326 | 334 | { |
327 | 335 | switch (code) { |
328 | - case 413: | |
329 | - return "HTTP/1.1 413 Request Entity Too Large"; | |
330 | - case 411: | |
331 | - return "HTTP/1.1 411 Length Required"; | |
332 | 336 | case 404: |
333 | 337 | return "HTTP/1.1 404 Not Found"; |
334 | 338 | case 403: |
@@ -335,8 +339,6 @@ | ||
335 | 339 | return "HTTP/1.1 403 Forbidden"; |
336 | 340 | case 400: |
337 | 341 | return "HTTP/1.1 400 Bad Request"; |
338 | - case 201: | |
339 | - return "HTTP/1.1 201 Created"; | |
340 | 342 | default: |
341 | 343 | return "HTTP/1.1 200 OK"; |
342 | 344 | } |
@@ -345,7 +347,8 @@ | ||
345 | 347 | static void mei_server_initialize_acl(mei_server_t * server) |
346 | 348 | { |
347 | 349 | const apr_array_header_t *values = |
348 | - mei_config_get_all(server->config, "pluto.server.acl.put"); | |
350 | + mei_config_get_all(server->config, "pluto.server.acl.put", | |
351 | + server->pool); | |
349 | 352 | int i; |
350 | 353 | |
351 | 354 | server->acl = apr_pcalloc(server->pool, sizeof(mei_server_acl_t)); |
@@ -356,6 +359,7 @@ | ||
356 | 359 | char *mask, *ip = |
357 | 360 | apr_pstrdup(server->pool, ((const char **) values->elts)[i]); |
358 | 361 | ip = apr_strtok(ip, "/", &mask); |
362 | + | |
359 | 363 | if (apr_ipsubnet_create(&subnet, ip, mask, server->pool) == |
360 | 364 | APR_SUCCESS) { |
361 | 365 | mei_server_acl_entry_t *ent = |
@@ -394,11 +398,13 @@ | ||
394 | 398 | |
395 | 399 | static void mei_server_initialize_channels(mei_server_t * server) |
396 | 400 | { |
401 | + apr_hash_t *channels = apr_hash_make(server->pool); | |
397 | 402 | const apr_array_header_t *values = |
398 | - mei_config_get_all(server->config, "pluto.server.channel"); | |
403 | + mei_config_get_all(server->config, "pluto.server.channel", | |
404 | + apr_hash_pool_get(channels)); | |
399 | 405 | int i; |
400 | 406 | |
401 | - server->channels = apr_hash_make(server->pool); | |
407 | + server->channels = channels; | |
402 | 408 | for (i = 0; i < values->nelts; i++) { |
403 | 409 | const char *path = ((const char **) values->elts)[i]; |
404 | 410 | mei_channel_create(server, path); |
@@ -405,6 +411,97 @@ | ||
405 | 411 | } |
406 | 412 | } |
407 | 413 | |
414 | +static void mei_server_multicast(mei_server_t * server, mei_client_t * client, | |
415 | + const char *method, const char *body) | |
416 | +{ | |
417 | + MEI_START_ENTRY_POINT(); | |
418 | + | |
419 | + if (apr_table_get(client->request.header, "X-Pluto-Multicast") != NULL) { | |
420 | + D("X-Pluto-Multicast was received, and doesn't multicast\n"); | |
421 | + return; | |
422 | + } | |
423 | + | |
424 | + apr_pool_t *pool; | |
425 | + apr_sockaddr_t *self_sa; | |
426 | + apr_pool_create(&pool, server->pool); | |
427 | + apr_socket_addr_get(&self_sa, APR_LOCAL, server->socket); | |
428 | + | |
429 | + const apr_array_header_t *values = | |
430 | + mei_config_get_all(server->config, "pluto.server.multicast", pool); | |
431 | + int i; | |
432 | + | |
433 | + for (i = 0; i < values->nelts; i++) { | |
434 | + char *sp, *ip = apr_pstrdup(pool, ((const char **) values->elts)[i]); | |
435 | + ip = apr_strtok(ip, ":", &sp); | |
436 | + | |
437 | + if (sp != NULL) { | |
438 | + apr_sockaddr_t *sa; | |
439 | + apr_socket_t *s; | |
440 | + apr_port_t port = (apr_port_t) apr_atoi64(sp); | |
441 | + apr_status_t rv; | |
442 | + | |
443 | + if ((rv = | |
444 | + apr_sockaddr_info_get(&sa, ip, APR_INET, port, | |
445 | + (apr_int32_t) 0, | |
446 | + pool)) != APR_SUCCESS) { | |
447 | + MEI_RUNTIME_ERROR(rv); | |
448 | + continue; | |
449 | + } | |
450 | + if (apr_sockaddr_equal(self_sa, sa) && self_sa->port == sa->port) { | |
451 | + D("tried casting myself, skipping...\n"); | |
452 | + continue; | |
453 | + } | |
454 | + if ((rv = apr_socket_create | |
455 | + (&s, sa->family, SOCK_STREAM, APR_PROTO_TCP, | |
456 | + pool)) != APR_SUCCESS) { | |
457 | + MEI_RUNTIME_ERROR(rv); | |
458 | + continue; | |
459 | + } | |
460 | + apr_socket_opt_set(s, APR_SO_NONBLOCK, 1); | |
461 | + apr_socket_timeout_set(s, (apr_interval_time_t) 3); | |
462 | + | |
463 | + if ((rv = apr_socket_connect(s, sa)) != APR_SUCCESS) { | |
464 | + MEI_RUNTIME_ERROR(rv); | |
465 | + continue; | |
466 | + } | |
467 | + apr_socket_opt_set(s, APR_SO_NONBLOCK, 1); | |
468 | + apr_socket_timeout_set(s, (apr_interval_time_t) 3); | |
469 | + | |
470 | + if (body == NULL) { | |
471 | + body = ""; | |
472 | + } | |
473 | + const char *request = apr_psprintf(pool, | |
474 | + "%s %s HTTP/1.1" MEI_CRLF | |
475 | + "Content-Length: %" | |
476 | + APR_SIZE_T_FMT MEI_CRLF | |
477 | + "X-Pluto-Multicast: true" | |
478 | + MEI_CRLF MEI_CRLF "%s", | |
479 | + method, client->request.path, | |
480 | + strlen(body), body); | |
481 | + apr_size_t len = strlen(request); | |
482 | + | |
483 | + if ((rv = apr_socket_send(s, request, &len)) != APR_SUCCESS) { | |
484 | + MEI_RUNTIME_ERROR(rv); | |
485 | + continue; | |
486 | + } | |
487 | + | |
488 | + char response[1]; | |
489 | + len = 1; | |
490 | + rv = apr_socket_recv(s, response, &len); | |
491 | + if (!APR_STATUS_IS_EAGAIN(rv) && (APR_STATUS_IS_TIMEUP(rv) | |
492 | + || APR_STATUS_IS_EOF(rv) | |
493 | + || len == 0)) { | |
494 | + MEI_RUNTIME_ERROR(rv); | |
495 | + continue; | |
496 | + } | |
497 | + | |
498 | + apr_socket_close(s); | |
499 | + } | |
500 | + } | |
501 | + | |
502 | + apr_pool_destroy(pool); | |
503 | +} | |
504 | + | |
408 | 505 | static void mei_server_log(mei_server_t * server, const char *content) |
409 | 506 | { |
410 | 507 | if (mei_config_get(server->config, "pluto.server.log.enabled", NULL) != |
@@ -442,11 +539,12 @@ | ||
442 | 539 | { |
443 | 540 | char *body = apr_pstrdup(client->pool, ""); |
444 | 541 | apr_size_t body_length = 0; |
542 | + apr_socket_t *socket = client->socket; | |
445 | 543 | |
446 | 544 | while (1) { |
447 | 545 | char buf[BUFSIZE]; |
448 | 546 | apr_size_t len = sizeof(buf) - 1; |
449 | - apr_status_t rv = apr_socket_recv(client->socket, buf, &len); | |
547 | + apr_status_t rv = apr_socket_recv(socket, buf, &len); | |
450 | 548 | |
451 | 549 | if (APR_STATUS_IS_EAGAIN(rv)) { |
452 | 550 |
@@ -455,10 +553,11 @@ | ||
455 | 553 | break; |
456 | 554 | } |
457 | 555 | if (strncmp(body, "<policy-file-request/>", 22) == 0) { |
458 | - const char *domain = mei_config_get(client->parent->config, | |
556 | + mei_config_t *config = client->parent->config; | |
557 | + const char *domain = mei_config_get(config, | |
459 | 558 | "pluto.client.flash.access.domain", |
460 | 559 | "*"); |
461 | - const char *ports = mei_config_get(client->parent->config, | |
560 | + const char *ports = mei_config_get(config, | |
462 | 561 | "pluto.client.flash.access.ports", |
463 | 562 | "*"); |
464 | 563 | mei_client_send_content_for_flash(client, |
@@ -474,7 +573,6 @@ | ||
474 | 573 | ports), TRUE); |
475 | 574 | break; |
476 | 575 | } |
477 | - D("\n/*\n%s\n*/\n", body); | |
478 | 576 | |
479 | 577 | char *header = body; |
480 | 578 | if ((body = strstr(header, MEI_CRLF MEI_CRLF)) != NULL) { |
@@ -482,15 +580,39 @@ | ||
482 | 580 | /* strlen("\r\n\r\n") == 4 */ |
483 | 581 | body += 4; |
484 | 582 | } |
485 | - else { | |
486 | - body = apr_pstrdup(client->pool, ""); | |
583 | + | |
584 | + const char *path = client->request.path; | |
585 | + if (client->request.method == MEI_REQUEST_IS_UNKNOWN) { | |
586 | + char **tokens; | |
587 | + char *request_first_line = | |
588 | + apr_strtok(NULL, MEI_CRLF, &header); | |
589 | + apr_tokenize_to_argv(request_first_line, &tokens, | |
590 | + client->pool); | |
591 | + | |
592 | + const char *method = tokens[0]; | |
593 | + const char *protocol = tokens[2]; | |
594 | + client->request.path = path = tokens[1]; | |
595 | + D("/*\n * %s\n */\n", request_first_line); | |
596 | + if (sizeof(tokens) != 4 || method == NULL | |
597 | + || path == NULL || protocol == NULL | |
598 | + || strncmp(protocol, "HTTP/1.1", 8) != 0) { | |
599 | + client->response.close_connection = TRUE; | |
600 | + mei_client_send_content(client, 400, ""); | |
601 | + } | |
602 | + else if (strncmp(method, "GET", 3) == 0) { | |
603 | + client->request.method = MEI_REQUEST_IS_GET; | |
604 | + } | |
605 | + else if (strncmp(method, "POST", 4) == 0) { | |
606 | + client->request.method = MEI_REQUEST_IS_POST; | |
607 | + } | |
608 | + else if (strncmp(method, "PUT", 3) == 0) { | |
609 | + client->request.method = MEI_REQUEST_IS_PUT; | |
610 | + } | |
611 | + else if (strncmp(method, "DELETE", 6) == 0) { | |
612 | + client->request.method = MEI_REQUEST_IS_DELETE; | |
613 | + } | |
487 | 614 | } |
488 | 615 | |
489 | - char **tokens; | |
490 | - char *request_first_line = apr_strtok(NULL, MEI_CRLF, &header); | |
491 | - D("/*\n * %s\n */\n", request_first_line); | |
492 | - apr_tokenize_to_argv(request_first_line, &tokens, client->pool); | |
493 | - | |
494 | 616 | char *header_key; |
495 | 617 | while ((header_key = apr_strtok(NULL, MEI_CRLF, &header)) != NULL) { |
496 | 618 | char *header_value; |
@@ -502,86 +624,131 @@ | ||
502 | 624 | else { |
503 | 625 | header_value = apr_pstrdup(client->pool, ""); |
504 | 626 | } |
505 | - apr_hash_set(client->request.header, header_key, | |
506 | - APR_HASH_KEY_STRING, header_value); | |
627 | + apr_table_setn(client->request.header, header_key, | |
628 | + header_value); | |
507 | 629 | } |
508 | 630 | |
509 | - const char *method = tokens[0]; | |
510 | - const char *path = tokens[1]; | |
511 | - const char *protocol = tokens[2]; | |
512 | - if (sizeof(tokens) != 4 || method == NULL | |
513 | - || path == NULL || protocol == NULL | |
514 | - || strncmp(protocol, "HTTP/1.1", 8) != 0) { | |
515 | - client->response.close_connection = TRUE; | |
516 | - mei_client_send_content(client, 400, ""); | |
517 | - } | |
518 | - else if (strncmp(method, "GET", 3) == 0) { | |
631 | + if (client->request.method == MEI_REQUEST_IS_GET) { | |
519 | 632 | mei_request_parse_query_string(client, path); |
520 | 633 | mei_client_bind_to_server(client); |
521 | 634 | } |
522 | - else if (strncmp(method, "POST", 4) == 0) { | |
635 | + else if (client->request.method == MEI_REQUEST_IS_POST) { | |
523 | 636 | mei_request_parse_query_string(client, path); |
524 | 637 | const char *ct = |
525 | - apr_hash_get(client->request.header, "Content-Type", | |
526 | - APR_HASH_KEY_STRING); | |
638 | + apr_table_get(client->request.header, "Content-Type"); | |
527 | 639 | |
528 | 640 | if (ct != NULL |
529 | 641 | /* strlen("application/x-www-form-urlencoded") == 33 */ |
530 | 642 | && strncmp(ct, "application/x-www-form-urlencoded", |
531 | 643 | 33) == 0) { |
532 | - const char *cl = apr_hash_get | |
533 | - (client->request.header, "Content-Length", | |
534 | - APR_HASH_KEY_STRING); | |
535 | - if (cl == NULL) { | |
536 | - mei_client_send_content(client, 411, ""); | |
644 | + const char *cl = apr_table_get | |
645 | + (client->request.header, "Content-Length"); | |
646 | + if (cl == NULL || body_length <= apr_atoi64(cl)) { | |
537 | 647 | break; |
538 | 648 | } |
539 | - else if (body_length <= apr_atoi64(cl)) { | |
540 | - mei_client_send_content(client, 413, ""); | |
541 | - break; | |
542 | - } | |
543 | - else { | |
544 | - mei_request_set_parameters(client, body); | |
545 | - } | |
649 | + mei_request_set_parameters(client, body); | |
650 | + mei_client_bind_to_server(client); | |
546 | 651 | } |
547 | 652 | |
548 | - mei_client_bind_to_server(client); | |
549 | 653 | } |
550 | - else if (strncmp(method, "PUT", 3) == 0) { | |
654 | + else if (client->request.method == MEI_REQUEST_IS_PUT) { | |
551 | 655 | apr_sockaddr_t *sa; |
552 | 656 | apr_socket_addr_get(&sa, APR_REMOTE, client->socket); |
657 | + mei_server_t *server = client->parent; | |
553 | 658 | |
554 | - if (mei_server_check_acl(client->parent, sa)) { | |
659 | + if (mei_server_check_acl(server, sa)) { | |
555 | 660 | mei_request_parse_query_string(client, path); |
556 | 661 | mei_event_param_t *event = |
557 | 662 | apr_pcalloc(client->pool, sizeof(mei_event_param_t)); |
558 | 663 | mei_request_set_tags(client, &event->tag, "tag"); |
559 | 664 | event->id = mei_request_get_parameter(client, "id"); |
560 | - event->uid = mei_request_get_parameter(client, "uid"); | |
561 | 665 | event->status = MEI_EVENT_STATUS_UPDATE; |
666 | + const char *uid = event->uid = | |
667 | + mei_request_get_parameter(client, "uid"); | |
562 | 668 | |
669 | + const char *sig = | |
670 | + mei_request_get_parameter(client, "sig"); | |
563 | 671 | const char *channel_path = |
564 | 672 | apr_pstrdup(client->pool, client->request.path); |
565 | - mei_channel_create(client->parent, channel_path); | |
673 | + | |
674 | + client->signature = apr_pstrndup(client->pool, "", 1); | |
675 | + mei_channel_create(server, channel_path); | |
566 | 676 | mei_channel_t *channel = |
567 | - mei_channel_get(client->parent, channel_path); | |
677 | + mei_channel_get(server, channel_path); | |
678 | + | |
568 | 679 | if (event->id != NULL) { |
569 | - mei_channel_transmit(channel, event); | |
680 | + mei_channel_transmit(server, channel, client, event); | |
570 | 681 | } |
682 | + else if (sig != NULL) { | |
683 | + const char *new_sig = apr_pstrdup(server->pool, sig); | |
684 | + int tag_count = event->tag->nelts; | |
685 | + if (uid != NULL) { | |
686 | + apr_hash_set(server->uids, new_sig, | |
687 | + APR_HASH_KEY_STRING, | |
688 | + apr_pstrdup(apr_hash_pool_get | |
689 | + (server->uids), uid)); | |
690 | + } | |
691 | + if (tag_count > 0) { | |
692 | + int i = 0; | |
693 | + apr_array_header_t *new_tag = | |
694 | + apr_array_make(apr_hash_pool_get | |
695 | + (server->tags), 32, | |
696 | + sizeof(const char *)); | |
697 | + for (; i < tag_count; i++) { | |
698 | + *(const char **) apr_array_push(new_tag) | |
699 | + = apr_pstrdup(new_tag->pool, | |
700 | + ((const char **) event-> | |
701 | + tag->elts)[i]); | |
702 | + } | |
703 | + apr_hash_set(server->tags, new_sig, | |
704 | + APR_HASH_KEY_STRING, new_tag); | |
705 | + } | |
571 | 706 | |
572 | - mei_client_send_content(client, 201, ""); | |
707 | + const apr_array_header_t *ta = | |
708 | + apr_table_elts(channel); | |
709 | + const apr_table_entry_t *te = | |
710 | + (const apr_table_entry_t *) ta->elts; | |
711 | + int i = 0; | |
712 | + | |
713 | + for (; i < ta->nelts; i++) { | |
714 | + const char *s = te[i].val; | |
715 | + if (strcmp(s, sig) == 0) { | |
716 | + mei_client_t *c = | |
717 | + apr_hash_get(server->clients, te[i].key, | |
718 | + APR_HASH_KEY_STRING); | |
719 | + if (c != NULL) { | |
720 | + if (uid != NULL) { | |
721 | + c->request.uid = | |
722 | + apr_pstrdup(client->pool, uid); | |
723 | + } | |
724 | + if (tag_count > 0) { | |
725 | + c->request.tag = | |
726 | + apr_array_copy(client->pool, | |
727 | + event->tag); | |
728 | + } | |
729 | + } | |
730 | + } | |
731 | + } | |
732 | + | |
733 | + } | |
734 | + | |
735 | + mei_server_multicast(server, client, "PUT", body); | |
736 | + mei_client_send_content(client, 200, ""); | |
573 | 737 | } |
574 | 738 | else { |
575 | 739 | mei_client_send_content(client, 403, ""); |
576 | 740 | } |
577 | 741 | } |
578 | - else if (strncmp(method, "DELETE", 6) == 0) { | |
742 | + else if (client->request.method == MEI_REQUEST_IS_DELETE) { | |
579 | 743 | apr_sockaddr_t *sa; |
580 | 744 | apr_socket_addr_get(&sa, APR_REMOTE, client->socket); |
745 | + mei_server_t *server = client->parent; | |
581 | 746 | |
582 | - if (mei_server_check_acl(client->parent, sa)) { | |
747 | + if (mei_server_check_acl(server, sa)) { | |
583 | 748 | mei_request_parse_query_string(client, path); |
584 | - mei_channel_remove(client->parent, path); | |
749 | + mei_channel_remove(server, path, client); | |
750 | + | |
751 | + mei_server_multicast(server, client, "DELETE", body); | |
585 | 752 | mei_client_send_content(client, 200, ""); |
586 | 753 | } |
587 | 754 | else { |
@@ -594,8 +761,7 @@ | ||
594 | 761 | break; |
595 | 762 | } |
596 | 763 | else if (APR_STATUS_IS_EOF(rv) || len == 0) { |
597 | - mei_client_remove_poll(client); | |
598 | - mei_client_close_connection(client); | |
764 | + mei_client_unbind_from_server(client); | |
599 | 765 | break; |
600 | 766 | } |
601 | 767 | else { |
@@ -613,11 +779,12 @@ | ||
613 | 779 | { |
614 | 780 | MEI_START_ENTRY_POINT(); |
615 | 781 | |
782 | + client->response.status = code; | |
616 | 783 | client->response.close_connection = TRUE; |
617 | - client->response.status = code; | |
784 | + | |
618 | 785 | mei_client_set_response(client, content); |
619 | - mei_client_remove_poll(client); | |
620 | 786 | mei_client_process_response(client, strlen(client->response.buffer)); |
787 | + mei_client_close_connection(client); | |
621 | 788 | } |
622 | 789 | |
623 | 790 | static void mei_client_send_content_for_flash(mei_client_t * client, |
@@ -626,20 +793,15 @@ | ||
626 | 793 | { |
627 | 794 | MEI_START_ENTRY_POINT(); |
628 | 795 | |
629 | - client->response.buffer = content; | |
630 | - client->response.close_connection = close_connection; | |
631 | - mei_client_remove_poll(client); | |
632 | - mei_client_process_response(client, strlen(content) + 1); | |
633 | -} | |
634 | - | |
635 | -static void mei_client_remove_poll(mei_client_t * client) | |
636 | -{ | |
637 | 796 | apr_pollfd_t pfd = { client->pool, APR_POLL_SOCKET, APR_POLLIN, 0, {NULL} |
638 | 797 | , client |
639 | 798 | }; |
799 | + pfd.desc.s = client->socket; | |
800 | + apr_pollset_remove(client->parent->pollset, &pfd); | |
640 | 801 | |
641 | - pfd.desc.s = client->socket; | |
642 | - apr_pollset_remove(client->pollset, &pfd); | |
802 | + client->response.buffer = content; | |
803 | + client->response.close_connection = close_connection; | |
804 | + mei_client_process_response(client, strlen(content) + 1); | |
643 | 805 | } |
644 | 806 | |
645 | 807 | static void mei_client_bind_to_server(mei_client_t * client) |
@@ -646,30 +808,27 @@ | ||
646 | 808 | { |
647 | 809 | MEI_START_ENTRY_POINT(); |
648 | 810 | |
811 | + mei_server_t *server = client->parent; | |
649 | 812 | const char *type = mei_request_get_parameter(client, "type"); |
650 | - apr_uint64_t maxlen = apr_atoi64(mei_config_get(client->parent->config, | |
813 | + apr_uint64_t maxlen = apr_atoi64(mei_config_get(server->config, | |
651 | 814 | "pluto.client.signature.maxlen", |
652 | 815 | "255")); |
816 | + const char *signature = client->signature = | |
817 | + mei_request_get_parameter(client, "sig"); | |
818 | + const char *path = client->request.path; | |
819 | + int is_flash = FALSE; | |
653 | 820 | |
654 | - if (client->signature == NULL) { | |
655 | - client->signature = mei_request_get_parameter(client, "sig"); | |
821 | + if (signature == NULL || strlen(signature) > maxlen) { | |
822 | + return; | |
656 | 823 | } |
657 | 824 | if (type != NULL) { |
658 | - client->request.is_flash = strncmp(type, "flash", 5) == 0; | |
825 | + is_flash = client->request.is_flash = strncmp(type, "flash", 5) == 0; | |
659 | 826 | } |
660 | 827 | |
661 | - if (!mei_channel_exists(client->parent, client->request.path)) { | |
662 | - client->request.is_flash ? mei_client_send_content_for_flash(client, | |
663 | - "404\\0", | |
664 | - TRUE) | |
828 | + if (!mei_channel_exists(server, path)) { | |
829 | + is_flash ? mei_client_send_content_for_flash(client, "404\\0", TRUE) | |
665 | 830 | : mei_client_send_content(client, 404, ""); |
666 | 831 | } |
667 | - else if (client->signature == NULL || strlen(client->signature) > maxlen) { | |
668 | - client->request.is_flash ? mei_client_send_content_for_flash(client, | |
669 | - "400\\0", | |
670 | - TRUE) | |
671 | - : mei_client_send_content(client, 400, ""); | |
672 | - } | |
673 | 832 | else if (type == NULL) { |
674 | 833 | mei_request_send_iframe_connection(client); |
675 | 834 | } |
@@ -676,20 +835,18 @@ | ||
676 | 835 | else { |
677 | 836 | const char *phase = mei_request_get_parameter(client, "phase"); |
678 | 837 | client->event.executing = |
679 | - apr_hash_get(client->parent->executings, client->signature, | |
680 | - APR_HASH_KEY_STRING); | |
838 | + apr_hash_get(server->executings, signature, APR_HASH_KEY_STRING); | |
681 | 839 | |
682 | 840 | if (client->event.executing == NULL) { |
683 | 841 | apr_pool_t *pool; |
684 | - apr_pool_create(&pool, client->parent->pool); | |
842 | + apr_pool_create(&pool, server->pool); | |
685 | 843 | client->event.executing = apr_table_make(pool, 8); |
686 | - apr_hash_set(client->parent->executings, client->signature, | |
844 | + apr_hash_set(server->executings, signature, | |
687 | 845 | APR_HASH_KEY_STRING, client->event.executing); |
688 | 846 | } |
689 | 847 | |
690 | 848 | client->request.uid = |
691 | - apr_hash_get(client->parent->uids, client->signature, | |
692 | - APR_HASH_KEY_STRING); | |
849 | + apr_hash_get(server->uids, signature, APR_HASH_KEY_STRING); | |
693 | 850 | if (client->request.uid == NULL) { |
694 | 851 | client->request.uid = |
695 | 852 | apr_pstrdup(client->pool, |
@@ -696,8 +853,7 @@ | ||
696 | 853 | mei_request_get_parameter(client, "uid")); |
697 | 854 | } |
698 | 855 | client->request.tag = |
699 | - apr_hash_get(client->parent->tags, client->signature, | |
700 | - APR_HASH_KEY_STRING); | |
856 | + apr_hash_get(server->tags, signature, APR_HASH_KEY_STRING); | |
701 | 857 | if (client->request.tag == NULL) { |
702 | 858 | mei_request_set_tags(client, &client->request.tag, "tag"); |
703 | 859 | } |
@@ -712,26 +868,24 @@ | ||
712 | 868 | client->response.close_connection = FALSE; |
713 | 869 | |
714 | 870 | if (phase == NULL || strncmp(phase, "reconnect", 9) != 0) { |
715 | - if (client->request.is_flash) { | |
871 | + if (is_flash) { | |
716 | 872 | mei_request_send_flash_connection(client, event); |
717 | 873 | } |
718 | - mei_channel_notify(client->parent, client->request.path, event); | |
719 | - mei_server_log(client->parent, | |
874 | + mei_channel_notify(server, path, client, event); | |
875 | + mei_server_log(server, | |
720 | 876 | apr_psprintf(client->pool, "Connected: %s\n", |
721 | - client->signature)); | |
877 | + signature)); | |
722 | 878 | } |
723 | 879 | |
724 | - mei_channel_join(client->parent, client->request.path, client); | |
725 | - mei_client_remove_poll(client); | |
726 | - mei_server_log(client->parent, | |
880 | + mei_channel_join(server, path, client); | |
881 | + mei_server_log(server, | |
727 | 882 | apr_psprintf(client->pool, "Wait for %s:%s\n", |
728 | - client->request.path, client->signature)); | |
883 | + path, signature)); | |
729 | 884 | |
730 | 885 | if (mei_client_commit(client, event)) { |
731 | - mei_server_log(client->parent, | |
886 | + mei_server_log(server, | |
732 | 887 | apr_psprintf(client->pool, "Flushed %s:%s\n", |
733 | - client->request.path, | |
734 | - client->signature)); | |
888 | + path, signature)); | |
735 | 889 | } |
736 | 890 | } |
737 | 891 | } |
@@ -754,7 +908,7 @@ | ||
754 | 908 | apr_pcalloc(client->pool, sizeof(mei_event_param_t)); |
755 | 909 | event->status = MEI_EVENT_STATUS_LEAVE; |
756 | 910 | |
757 | - mei_channel_notify(server, path, event); | |
911 | + mei_channel_notify(server, path, client, event); | |
758 | 912 | } |
759 | 913 | } |
760 | 914 |
@@ -773,10 +927,27 @@ | ||
773 | 927 | } |
774 | 928 | |
775 | 929 | mei_server_log(server, |
776 | - apr_psprintf(client->pool, "Disconnected %s\n", | |
777 | - signature)); | |
930 | + apr_psprintf(client->pool, "Disconnected %s[%d]\n", | |
931 | + signature, client->fd)); | |
932 | + mei_client_close_connection(client); | |
933 | +} | |
934 | + | |
935 | +static void mei_client_close_connection(mei_client_t * client) | |
936 | +{ | |
937 | + MEI_START_ENTRY_POINT(); | |
938 | + | |
939 | + mei_server_t *server = client->parent; | |
940 | + apr_pollfd_t pfd = { client->pool, APR_POLL_SOCKET, APR_POLLIN, 0, {NULL} | |
941 | + , client | |
942 | + }; | |
943 | + pfd.desc.s = client->socket; | |
944 | + apr_pollset_remove(server->pollset, &pfd); | |
945 | + | |
946 | + apr_hash_set(server->clients, apr_itoa(client->parent->pool, client->fd), | |
947 | + APR_HASH_KEY_STRING, NULL); | |
948 | + apr_socket_close(client->socket); | |
778 | 949 | apr_pool_destroy(client->pool); |
779 | - client = NULL; | |
950 | + memset(client, 0, sizeof(mei_client_t)); | |
780 | 951 | } |
781 | 952 | |
782 | 953 | static int mei_client_can_respond(mei_client_t * client, |
@@ -790,11 +961,15 @@ | ||
790 | 961 | return FALSE; |
791 | 962 | } |
792 | 963 | |
964 | + mei_server_t *server = client->parent; | |
965 | + const char *signature = client->signature; | |
966 | + | |
793 | 967 | int is_matched = FALSE; |
794 | - apr_array_header_t *event_tag = event->tag; | |
795 | - apr_array_header_t *client_tag = client->request.tag; | |
968 | + const apr_array_header_t *event_tag = event->tag; | |
969 | + const apr_array_header_t *client_tag = client->request.tag; | |
796 | 970 | int event_tag_count = event_tag != NULL ? event_tag->nelts : 0; |
797 | 971 | int client_tag_count = client_tag != NULL ? client_tag->nelts : 0; |
972 | + | |
798 | 973 | if (event_tag_count > 0 && client_tag_count > 0) { |
799 | 974 | apr_size_t search_nelts, search_elt_size; |
800 | 975 | int i, iterate_nelts; |
@@ -815,9 +990,11 @@ | ||
815 | 990 | search_elt_size = client_tag->elt_size; |
816 | 991 | } |
817 | 992 | for (i = 0; i < iterate_nelts; i++) { |
993 | +/* | |
818 | 994 | D("iterate[%d](%d): %s / search(%d): %s\n", i, |
819 | 995 | iterate_nelts, ((const char **) iterate_elts)[i], search_nelts, |
820 | 996 | ((const char **) search_elts)[i]); |
997 | +*/ | |
821 | 998 | if (bsearch |
822 | 999 | (((const char **) iterate_elts)[i], search_elts, search_nelts, |
823 | 1000 | search_elt_size, mei_util_bsearch_compare_string) != NULL) { |
@@ -835,13 +1012,12 @@ | ||
835 | 1012 | } |
836 | 1013 | else { |
837 | 1014 | client->event.executing = |
838 | - apr_hash_get(client->parent->executings, client->signature, | |
839 | - APR_HASH_KEY_STRING); | |
1015 | + apr_hash_get(server->executings, signature, APR_HASH_KEY_STRING); | |
840 | 1016 | if (client->event.executing == NULL) { |
841 | 1017 | apr_pool_t *pool; |
842 | - apr_pool_create(&pool, client->parent->pool); | |
1018 | + apr_pool_create(&pool, server->pool); | |
843 | 1019 | client->event.executing = apr_table_make(pool, 8); |
844 | - apr_hash_set(client->parent->executings, client->signature, | |
1020 | + apr_hash_set(server->executings, signature, | |
845 | 1021 | APR_HASH_KEY_STRING, client->event.executing); |
846 | 1022 | } |
847 | 1023 |
@@ -877,12 +1053,13 @@ | ||
877 | 1053 | client->event.executing = NULL; |
878 | 1054 | client->event.committed_at = apr_time_now(); |
879 | 1055 | |
880 | - apr_size_t length = 0; | |
881 | 1056 | if (client->request.is_flash) { |
882 | - client->response.buffer = apr_pstrcat(client->pool, | |
883 | - client->response.publish_buffer, | |
884 | - "\\0", NULL); | |
885 | - length = strlen(client->response.publish_buffer) + 1; | |
1057 | + mei_client_send_content_for_flash(client, apr_pstrcat(client->pool, | |
1058 | + client-> | |
1059 | + response. | |
1060 | + publish_buffer, | |
1061 | + "\\0", NULL), | |
1062 | + FALSE); | |
886 | 1063 | } |
887 | 1064 | else { |
888 | 1065 | if (mei_client_check_connection(client) == FALSE) { |
@@ -891,15 +1068,10 @@ | ||
891 | 1068 | |
892 | 1069 | client->event.is_waiting = FALSE; |
893 | 1070 | client->response.status = 200; |
894 | - client->response.close_connection = TRUE; | |
895 | 1071 | client->response.content_type = "text/javascript"; |
896 | - mei_client_set_response(client, client->response.publish_buffer); | |
897 | - length = strlen(client->response.buffer); | |
1072 | + mei_client_send_content(client, 200, client->response.publish_buffer); | |
898 | 1073 | } |
899 | 1074 | |
900 | - client->response.publish_buffer = NULL; | |
901 | - mei_client_process_response(client, length); | |
902 | - | |
903 | 1075 | return TRUE; |
904 | 1076 | } |
905 | 1077 |
@@ -1029,13 +1201,12 @@ | ||
1029 | 1201 | apr_size_t length) |
1030 | 1202 | { |
1031 | 1203 | const char *data = client->response.buffer; |
1204 | + apr_socket_t *socket = client->socket; | |
1032 | 1205 | apr_size_t remain = length; |
1033 | 1206 | apr_size_t sent = remain; |
1034 | 1207 | |
1035 | - apr_socket_send(client->socket, data, &sent); | |
1036 | - if (client->response.close_connection == TRUE) { | |
1037 | - mei_client_close_connection(client); | |
1038 | - } | |
1208 | + apr_socket_send(socket, data, &sent); | |
1209 | + client->request.method = MEI_REQUEST_IS_UNKNOWN; | |
1039 | 1210 | |
1040 | 1211 | return TRUE; |
1041 | 1212 | } |
@@ -1046,11 +1217,12 @@ | ||
1046 | 1217 | |
1047 | 1218 | char buf[1]; |
1048 | 1219 | apr_size_t len = 1; |
1049 | - apr_status_t rv = apr_socket_recv(client->socket, buf, &len); | |
1220 | + apr_socket_t *socket = client->socket; | |
1221 | + apr_status_t rv = apr_socket_recv(socket, buf, &len); | |
1050 | 1222 | |
1051 | 1223 | if (!APR_STATUS_IS_EAGAIN(rv) && (APR_STATUS_IS_TIMEUP(rv) |
1052 | 1224 | || APR_STATUS_IS_EOF(rv) || len == 0)) { |
1053 | - mei_client_unbind_from_server(client); | |
1225 | + apr_socket_close(socket); | |
1054 | 1226 | return FALSE; |
1055 | 1227 | } |
1056 | 1228 |
@@ -1057,27 +1229,21 @@ | ||
1057 | 1229 | return TRUE; |
1058 | 1230 | } |
1059 | 1231 | |
1060 | -static int mei_client_close_connection(mei_client_t * client) | |
1061 | -{ | |
1062 | - if (client->socket != NULL) { | |
1063 | - apr_socket_close(client->socket); | |
1064 | - } | |
1065 | - return TRUE; | |
1066 | -} | |
1067 | - | |
1068 | 1232 | /* |
1069 | 1233 | * MEI channel class |
1070 | 1234 | */ |
1071 | 1235 | static void mei_channel_create(mei_server_t * server, const char *path) |
1072 | 1236 | { |
1073 | - if (apr_hash_get(server->channels, path, APR_HASH_KEY_STRING) == NULL) { | |
1074 | - const char *channel_path = apr_pstrdup(server->pool, path); | |
1075 | - mei_channel_t *channel = apr_table_make(server->pool, 32); | |
1076 | - apr_hash_set(server->channels, channel_path, APR_HASH_KEY_STRING, | |
1077 | - channel); | |
1237 | + apr_hash_t *channels = server->channels; | |
1238 | + apr_pool_t *pool; | |
1239 | + apr_pool_create(&pool, apr_hash_pool_get(channels)); | |
1240 | + | |
1241 | + if (apr_hash_get(channels, path, APR_HASH_KEY_STRING) == NULL) { | |
1242 | + mei_channel_t *channel = apr_table_make(pool, 32); | |
1243 | + const char *channel_path = apr_pstrdup(pool, path); | |
1244 | + apr_hash_set(channels, channel_path, APR_HASH_KEY_STRING, channel); | |
1078 | 1245 | mei_server_log(server, |
1079 | - apr_psprintf(server->pool, "Channel opened: %s\n", | |
1080 | - path)); | |
1246 | + apr_psprintf(pool, "Channel opened: %s\n", path)); | |
1081 | 1247 | } |
1082 | 1248 | } |
1083 | 1249 |
@@ -1101,16 +1267,11 @@ | ||
1101 | 1267 | apr_hash_get(server->channels, path, APR_HASH_KEY_STRING); |
1102 | 1268 | |
1103 | 1269 | if (channel != NULL && client->signature != NULL) { |
1104 | - const char *signature = | |
1105 | - apr_pstrdup(apr_table_elts(channel)->pool, client->signature); | |
1270 | + apr_pool_t *pool = apr_table_elts(channel)->pool; | |
1271 | + const char *signature = apr_pstrdup(pool, client->signature); | |
1272 | + const char *sfd = apr_itoa(pool, client->fd); | |
1273 | + apr_table_setn(channel, sfd, signature); | |
1106 | 1274 | |
1107 | - mei_client_t *used; | |
1108 | - if ((used = | |
1109 | - (mei_client_t *) apr_table_get(channel, signature)) != NULL) { | |
1110 | - apr_pool_destroy(used->pool); | |
1111 | - } | |
1112 | - apr_table_setn(channel, signature, (const char *) client); | |
1113 | - | |
1114 | 1275 | return TRUE; |
1115 | 1276 | } |
1116 | 1277 | else { |
@@ -1119,6 +1280,7 @@ | ||
1119 | 1280 | } |
1120 | 1281 | |
1121 | 1282 | static int mei_channel_notify(mei_server_t * server, const char *path, |
1283 | + mei_client_t * client, | |
1122 | 1284 | mei_event_param_t * event) |
1123 | 1285 | { |
1124 | 1286 | MEI_START_ENTRY_POINT(); |
@@ -1131,7 +1293,7 @@ | ||
1131 | 1293 | apr_psprintf(server->pool, |
1132 | 1294 | "pluto-charon-xhr-event-id-%" APR_TIME_T_FMT, |
1133 | 1295 | apr_time_now()); |
1134 | - mei_channel_transmit(channel, event); | |
1296 | + mei_channel_transmit(server, channel, client, event); | |
1135 | 1297 | return TRUE; |
1136 | 1298 | } |
1137 | 1299 | else { |
@@ -1139,7 +1301,9 @@ | ||
1139 | 1301 | } |
1140 | 1302 | } |
1141 | 1303 | |
1142 | -static void mei_channel_transmit(mei_channel_t * channel, | |
1304 | +static void mei_channel_transmit(mei_server_t * server, | |
1305 | + mei_channel_t * channel, | |
1306 | + mei_client_t * client, | |
1143 | 1307 | mei_event_param_t * event) |
1144 | 1308 | { |
1145 | 1309 | MEI_START_ENTRY_POINT(); |
@@ -1153,24 +1317,24 @@ | ||
1153 | 1317 | apr_hash_t *committed = apr_hash_make(tmp_pool); |
1154 | 1318 | |
1155 | 1319 | while (i < ta->nelts) { |
1156 | - const char *signature = te[i].key; | |
1157 | - mei_client_t *client = (mei_client_t *) te[i].val; | |
1320 | + const char *sfd = te[i].key; | |
1321 | + const char *signature = te[i].val; | |
1322 | + apr_os_sock_t fd = (apr_os_sock_t) apr_atoi64(sfd); | |
1323 | + mei_client_t *c = | |
1324 | + apr_hash_get(server->clients, sfd, APR_HASH_KEY_STRING); | |
1158 | 1325 | |
1159 | - if (client == NULL || client->parent == NULL) { | |
1160 | - apr_table_unset(channel, signature); | |
1161 | - i = 0; | |
1162 | - continue; | |
1163 | - } | |
1164 | 1326 | if (apr_hash_get(committed, signature, APR_HASH_KEY_STRING) != NULL) { |
1165 | 1327 | i++; |
1166 | 1328 | } |
1167 | - else if (mei_client_can_respond(client, event)) { | |
1168 | - mei_client_commit(client, event); | |
1329 | + else if (c != NULL && fd != client->fd | |
1330 | + && strcmp(signature, client->signature) != 0 | |
1331 | + && mei_client_can_respond(c, event)) { | |
1332 | + mei_client_commit(c, event); | |
1169 | 1333 | apr_hash_set(committed, signature, APR_HASH_KEY_STRING, ""); |
1170 | 1334 | i++; |
1171 | 1335 | } |
1172 | 1336 | else { |
1173 | - apr_table_unset(channel, signature); | |
1337 | + apr_table_unset(channel, sfd); | |
1174 | 1338 | i = 0; |
1175 | 1339 | } |
1176 | 1340 | } |
@@ -1187,7 +1351,8 @@ | ||
1187 | 1351 | channel = apr_hash_get(server->channels, path, APR_HASH_KEY_STRING); |
1188 | 1352 | |
1189 | 1353 | if (channel != NULL && client->signature != NULL) { |
1190 | - apr_table_unset(channel, client->signature); | |
1354 | + apr_pool_t *pool = apr_table_elts(channel)->pool; | |
1355 | + apr_table_unset(channel, apr_itoa(pool, client->fd)); | |
1191 | 1356 | return TRUE; |
1192 | 1357 | } |
1193 | 1358 | else { |
@@ -1195,7 +1360,8 @@ | ||
1195 | 1360 | } |
1196 | 1361 | } |
1197 | 1362 | |
1198 | -static void mei_channel_remove(mei_server_t * server, const char *path) | |
1363 | +static void mei_channel_remove(mei_server_t * server, const char *path, | |
1364 | + mei_client_t * client) | |
1199 | 1365 | { |
1200 | 1366 | MEI_START_ENTRY_POINT(); |
1201 | 1367 |
@@ -1207,9 +1373,13 @@ | ||
1207 | 1373 | int i = 0; |
1208 | 1374 | |
1209 | 1375 | while (i < ta->nelts) { |
1210 | - mei_client_t *client = (mei_client_t *) te[i].val; | |
1211 | - if (client != NULL && client->parent != NULL) { | |
1376 | + const char *sfd = te[i].key; | |
1377 | + apr_os_sock_t fd = (apr_os_sock_t) apr_atoi64(sfd); | |
1378 | + mei_client_t *c = | |
1379 | + apr_hash_get(server->clients, sfd, APR_HASH_KEY_STRING); | |
1380 | + if (c != NULL && fd != client->fd) { | |
1212 | 1381 | mei_client_unbind_from_server(client); |
1382 | + apr_table_unset(channel, te[i].val); | |
1213 | 1383 | i = 0; |
1214 | 1384 | } |
1215 | 1385 | else { |
@@ -1217,12 +1387,12 @@ | ||
1217 | 1387 | } |
1218 | 1388 | } |
1219 | 1389 | |
1220 | - apr_table_clear(channel); | |
1390 | + apr_hash_set(server->channels, path, APR_HASH_KEY_STRING, NULL); | |
1391 | + mei_server_log(server, | |
1392 | + apr_psprintf(apr_table_elts(channel)->pool, | |
1393 | + "Channel closed: %s\n", path)); | |
1394 | + apr_pool_destroy(apr_table_elts(channel)->pool); | |
1221 | 1395 | } |
1222 | - | |
1223 | - apr_hash_set(server->channels, path, APR_HASH_KEY_STRING, NULL); | |
1224 | - mei_server_log(server, | |
1225 | - apr_psprintf(server->pool, "Channel closed: %s\n", path)); | |
1226 | 1396 | } |
1227 | 1397 | |
1228 | 1398 | /* |
@@ -1248,9 +1418,8 @@ | ||
1248 | 1418 | const char *key) |
1249 | 1419 | { |
1250 | 1420 | return mei_request_decode_uri_string(client->pool, |
1251 | - apr_hash_get(client->request.param, | |
1252 | - key, | |
1253 | - APR_HASH_KEY_STRING)); | |
1421 | + apr_table_get(client->request.param, | |
1422 | + key)); | |
1254 | 1423 | } |
1255 | 1424 | |
1256 | 1425 | static void mei_request_set_parameters(mei_client_t * client, char *body) |
@@ -1266,8 +1435,7 @@ | ||
1266 | 1435 | if ((key = apr_strtok(kv_unit, "=", &kv_state)) != NULL) { |
1267 | 1436 | const char *value = kv_state; |
1268 | 1437 | if (value != NULL) { |
1269 | - apr_hash_set(client->request.param, key, | |
1270 | - APR_HASH_KEY_STRING, value); | |
1438 | + apr_table_setn(client->request.param, key, value); | |
1271 | 1439 | } |
1272 | 1440 | } |
1273 | 1441 | } while ((kv_unit = apr_strtok(NULL, "&", &qs_state)) != NULL); |
@@ -1282,7 +1450,7 @@ | ||
1282 | 1450 | key)); |
1283 | 1451 | |
1284 | 1452 | if (*tags == NULL) { |
1285 | - *tags = apr_array_make(client->pool, 8, sizeof(char *)); | |
1453 | + *tags = apr_array_make(client->pool, 8, sizeof(const char *)); | |
1286 | 1454 | } |
1287 | 1455 | if (tag == NULL || strncmp(tag, "", 1) == 0) { |
1288 | 1456 | return; |
@@ -1443,21 +1611,18 @@ | ||
1443 | 1611 | |
1444 | 1612 | static const char *mei_request_query_to_json(mei_client_t * client) |
1445 | 1613 | { |
1614 | + const apr_array_header_t *ta = apr_table_elts(client->request.param); | |
1615 | + const apr_table_entry_t *te = (const apr_table_entry_t *) ta->elts; | |
1446 | 1616 | const char *queries = apr_pstrdup(client->pool, ""); |
1617 | + int i, ta_count = ta->nelts; | |
1447 | 1618 | |
1448 | - apr_hash_index_t *hi; | |
1449 | - for (hi = apr_hash_first(NULL, client->request.param); hi; | |
1450 | - hi = apr_hash_next(hi)) { | |
1451 | - const void *key; | |
1452 | - void *value; | |
1453 | - apr_hash_this(hi, &key, NULL, &value); | |
1619 | + for (i = 0; i < ta_count; i++) { | |
1454 | 1620 | queries = |
1455 | 1621 | apr_pstrcat(client->pool, queries, "\"", |
1456 | 1622 | mei_request_escape_js(client->pool, |
1457 | - (const char *) key), "\":\"", | |
1623 | + te[i].key), "\":\"", | |
1458 | 1624 | mei_request_escape_js(client->pool, |
1459 | - (const char *) value), "\",", | |
1460 | - NULL); | |
1625 | + te[i].val), "\",", NULL); | |
1461 | 1626 | } |
1462 | 1627 | |
1463 | 1628 | return queries; |
@@ -32,6 +32,7 @@ | ||
32 | 32 | #include <apr_md5.h> |
33 | 33 | #include <apr_ring.h> |
34 | 34 | #include <apr_thread_proc.h> |
35 | +#include <apr_portable.h> | |
35 | 36 | |
36 | 37 | #ifdef __cplusplus |
37 | 38 | extern "C" |
@@ -81,7 +82,10 @@ | ||
81 | 82 | { |
82 | 83 | mei_config_t *config; |
83 | 84 | mei_server_acl_t *acl; |
85 | + apr_pollset_t *pollset; | |
86 | + apr_socket_t *socket; | |
84 | 87 | apr_pool_t *pool; |
88 | + apr_hash_t *clients; | |
85 | 89 | apr_hash_t *channels; |
86 | 90 | apr_hash_t *executings; |
87 | 91 | apr_hash_t *uids; |
@@ -93,12 +97,6 @@ | ||
93 | 97 | APR_RING_ENTRY(mei_server_acl_entry_t) link; |
94 | 98 | apr_ipsubnet_t *subnet; |
95 | 99 | }; |
96 | - | |
97 | - | |
98 | - | |
99 | - | |
100 | - | |
101 | - | |
102 | 100 | |
103 | 101 | |
104 | 102 |
@@ -108,12 +106,20 @@ | ||
108 | 106 | { |
109 | 107 | struct |
110 | 108 | { |
109 | + enum mei_request_method | |
110 | + { | |
111 | + MEI_REQUEST_IS_GET, | |
112 | + MEI_REQUEST_IS_POST, | |
113 | + MEI_REQUEST_IS_PUT, | |
114 | + MEI_REQUEST_IS_DELETE, | |
115 | + MEI_REQUEST_IS_UNKNOWN | |
116 | + } method; | |
111 | 117 | const char *path; |
112 | 118 | const char *uid; |
113 | 119 | apr_array_header_t *tag; |
114 | 120 | int is_flash; |
115 | - apr_hash_t *header; | |
116 | - apr_hash_t *param; | |
121 | + apr_table_t *header; | |
122 | + apr_table_t *param; | |
117 | 123 | } request; |
118 | 124 | struct |
119 | 125 | { |
@@ -122,7 +128,6 @@ | ||
122 | 128 | const char *content_type; |
123 | 129 | int status; |
124 | 130 | int close_connection; |
125 | - apr_hash_t *header; | |
126 | 131 | } response; |
127 | 132 | struct |
128 | 133 | { |
@@ -135,7 +140,7 @@ | ||
135 | 140 | const char *signature; |
136 | 141 | mei_server_t *parent; |
137 | 142 | apr_pool_t *pool; |
138 | - apr_pollset_t *pollset; | |
143 | + apr_os_sock_t fd; | |
139 | 144 | apr_socket_t *socket; |
140 | 145 | apr_time_t connected_at; |
141 | 146 | }; |
@@ -159,25 +164,13 @@ | ||
159 | 164 | mei_event_param_t *event; |
160 | 165 | }; |
161 | 166 | |
162 | -#define MEI_REQUEST_METHOD_IS_GET(client) \ | |
163 | - (client)->request.method == MEI_REQUEST_METHOD_GET | |
164 | -#define MEI_REQUEST_METHOD_IS_POST(client) \ | |
165 | - (client)->request.method == MEI_REQUEST_METHOD_POST | |
166 | -#define MEI_REQUEST_METHOD_IS_HEAD(client) \ | |
167 | - (client)->request.method == MEI_REQUEST_METHOD_HEAD | |
168 | -#define MEI_REQUEST_METHOD_IS_PUT(client) \ | |
169 | - (client)->request.method == MEI_REQUEST_METHOD_PUT | |
170 | -#define MEI_REQUEST_METHOD_IS_DELETE(client) \ | |
171 | - (client)->request.method == MEI_REQUEST_METHOD_DELETE | |
172 | -#define MEI_REQUEST_METHOD_IS_UNKNOWN(client) \ | |
173 | - (client)->request.method == MEI_REQUEST_METHOD_UNKNOWN | |
174 | - | |
175 | 167 | static void usage(const char *self); |
176 | 168 | static mei_config_t *mei_config_load(apr_pool_t * mp, const char *path); |
177 | 169 | static const char *mei_config_get(mei_config_t * config, const char *key, |
178 | 170 | const char *def); |
179 | 171 | static const apr_array_header_t *mei_config_get_all(mei_config_t * config, |
180 | - const char *key); | |
172 | + const char *key, | |
173 | + apr_pool_t * pool); | |
181 | 174 | static int mei_config_add_value_to_array(void *data, const char *key, |
182 | 175 | const char *value); |
183 | 176 | static void mei_server_create_listen_socket(mei_server_t * server, |
@@ -184,7 +177,6 @@ | ||
184 | 177 | apr_socket_t ** sock, |
185 | 178 | apr_pool_t * mp); |
186 | 179 | static void mei_server_accept_client(mei_server_t * server, |
187 | - apr_pollset_t * pollset, | |
188 | 180 | apr_socket_t * listen); |
189 | 181 | static const char *mei_server_status_code_to_string(int code); |
190 | 182 | static void mei_server_initialize_acl(mei_server_t * server); |
@@ -197,7 +189,6 @@ | ||
197 | 189 | apr_size_t length); |
198 | 190 | static void mei_client_set_response(mei_client_t * client, |
199 | 191 | const char *response_body); |
200 | - static void mei_client_remove_poll(mei_client_t * client); | |
201 | 192 | static void mei_client_send_content(mei_client_t * client, int code, |
202 | 193 | const char *content); |
203 | 194 | static void mei_client_send_content_for_flash(mei_client_t * client, |
@@ -205,6 +196,7 @@ | ||
205 | 196 | int close_connection); |
206 | 197 | static void mei_client_bind_to_server(mei_client_t * client); |
207 | 198 | static void mei_client_unbind_from_server(mei_client_t * client); |
199 | + static void mei_client_close_connection(mei_client_t * client); | |
208 | 200 | static int mei_client_can_respond(mei_client_t * client, |
209 | 201 | mei_event_param_t * event); |
210 | 202 | static int mei_client_commit(mei_client_t * client, |
@@ -216,7 +208,6 @@ | ||
216 | 208 | mei_event_param_t * |
217 | 209 | event); |
218 | 210 | static int mei_client_check_connection(mei_client_t * client); |
219 | - static int mei_client_close_connection(mei_client_t * client); | |
220 | 211 | |
221 | 212 | static void mei_channel_create(mei_server_t * server, const char *path); |
222 | 213 | static int mei_channel_exists(mei_server_t * server, const char *path); |
@@ -225,12 +216,16 @@ | ||
225 | 216 | static int mei_channel_join(mei_server_t * server, const char *path, |
226 | 217 | mei_client_t * client); |
227 | 218 | static int mei_channel_notify(mei_server_t * server, const char *path, |
219 | + mei_client_t * client, | |
228 | 220 | mei_event_param_t * event); |
229 | - static void mei_channel_transmit(mei_channel_t * channel, | |
221 | + static void mei_channel_transmit(mei_server_t * server, | |
222 | + mei_channel_t * channel, | |
223 | + mei_client_t * client, | |
230 | 224 | mei_event_param_t * event); |
231 | 225 | static int mei_channel_leave(mei_server_t * server, const char *path, |
232 | 226 | mei_client_t * client); |
233 | - static void mei_channel_remove(mei_server_t * server, const char *path); | |
227 | + static void mei_channel_remove(mei_server_t * server, const char *path, | |
228 | + mei_client_t * client); | |
234 | 229 | |
235 | 230 | static void mei_request_parse_query_string(mei_client_t * client, |
236 | 231 | const char *path); |
@@ -268,6 +263,44 @@ | ||
268 | 263 | apr_file_printf(apr_stderr, \ |
269 | 264 | "[%s] %s at line %d\n", cbuf, __func__, __LINE__) |
270 | 265 | |
266 | +#define MEI_INSPECT_ARRAY(array) do { \ | |
267 | + if (array == NULL) { break; } \ | |
268 | + int i = 0; \ | |
269 | + printf("ARRAY: count:[%d] %s at line %d\n", \ | |
270 | + array->nelts, __func__, __LINE__); \ | |
271 | + for (; i < array->nelts; i++) { \ | |
272 | + printf("%d: key=[%s]\n", i, ((const char **)(array->elts))[i]); \ | |
273 | + } \ | |
274 | +} while(FALSE) | |
275 | + | |
276 | +#define MEI_INSPECT_TABLE(table) do { \ | |
277 | + if (table == NULL) { break; } \ | |
278 | + const apr_array_header_t *ta = apr_table_elts(table); \ | |
279 | + const apr_table_entry_t *te = (const apr_table_entry_t *) ta->elts; \ | |
280 | + int i = 0; \ | |
281 | + printf("TABLE: count:[%d] %s at line %d\n", \ | |
282 | + ta->nelts, __func__, __LINE__); \ | |
283 | + for (; i < ta->nelts; i++) { \ | |
284 | + printf("key=[%s] / value=[%s]\n", te[i].key, te[i].val); \ | |
285 | + } \ | |
286 | +} while(FALSE) | |
287 | + | |
288 | +#define MEI_INSPECT_HASH(hash, pool) do {\ | |
289 | + if (hash == NULL || pool == NULL) { break; } \ | |
290 | + apr_ssize_t len = 0; \ | |
291 | + const void *key = NULL; \ | |
292 | + void *val = NULL; \ | |
293 | + apr_hash_index_t *hash_index = apr_hash_first(pool, hash); \ | |
294 | + printf(apr_stderr, "HASH: count:[%d] %s at line\n", \ | |
295 | + apr_hash_count(hash), __func__, __LINE__); \ | |
296 | + while (hash_index) { \ | |
297 | + apr_hash_this(hash_index, &key, &len, &val); \ | |
298 | + printf("key=[%s:%d] / value=[%p]\n", \ | |
299 | + (const char *)key, len, val); \ | |
300 | + hash_index = apr_hash_next(hash_index); \ | |
301 | + } \ | |
302 | +} while(FALSE) | |
303 | + | |
271 | 304 | #else |
272 | 305 | |
273 | 306 | #define MEI_JS_LINE_BREAK |
@@ -276,6 +309,12 @@ | ||
276 | 309 | |
277 | 310 | #define MEI_START_ENTRY_POINT() (void)0 |
278 | 311 | |
312 | +#define MEI_INSPECT_ARRAY(array) (void)0 | |
313 | + | |
314 | +#define MEI_INSPECT_TABLE(table) (void)0 | |
315 | + | |
316 | +#define MEI_INSPECT_HASH(hash, pool) (void)0 | |
317 | + | |
279 | 318 | #endif |
280 | 319 | |
281 | 320 | #ifdef __cplusplus |