diff options
author | Christian Grothoff <christian@grothoff.org> | 2010-02-10 16:54:51 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2010-02-10 16:54:51 +0000 |
commit | 1b49f3e84f047a26e2742c68893c3be6b5c1ec69 (patch) | |
tree | de2afa79ee3e3b95018df16cf5f180a9227626c5 /src/util/server.c | |
parent | 1366ecaaa9c01dc3d9596fd48d53c50a29f17e02 (diff) | |
download | gnunet-1b49f3e84f047a26e2742c68893c3be6b5c1ec69.tar.gz gnunet-1b49f3e84f047a26e2742c68893c3be6b5c1ec69.zip |
cleaning up server code, subtle fixes
Diffstat (limited to 'src/util/server.c')
-rw-r--r-- | src/util/server.c | 192 |
1 files changed, 104 insertions, 88 deletions
diff --git a/src/util/server.c b/src/util/server.c index 32008bce8..bf4eb4518 100644 --- a/src/util/server.c +++ b/src/util/server.c | |||
@@ -214,6 +214,11 @@ struct GNUNET_SERVER_Client | |||
214 | char *side_buf; | 214 | char *side_buf; |
215 | 215 | ||
216 | /** | 216 | /** |
217 | * ID of task used to restart processing. | ||
218 | */ | ||
219 | GNUNET_SCHEDULER_TaskIdentifier restart_task; | ||
220 | |||
221 | /** | ||
217 | * Number of bytes in the side buffer. | 222 | * Number of bytes in the side buffer. |
218 | */ | 223 | */ |
219 | size_t side_buf_size; | 224 | size_t side_buf_size; |
@@ -260,6 +265,10 @@ struct GNUNET_SERVER_Client | |||
260 | */ | 265 | */ |
261 | int shutdown_now; | 266 | int shutdown_now; |
262 | 267 | ||
268 | /** | ||
269 | * Are we currently trying to receive? | ||
270 | */ | ||
271 | int receive_pending; | ||
263 | }; | 272 | }; |
264 | 273 | ||
265 | 274 | ||
@@ -339,6 +348,8 @@ process_listen_socket (void *cls, | |||
339 | /** | 348 | /** |
340 | * Create and initialize a listen socket for the server. | 349 | * Create and initialize a listen socket for the server. |
341 | * | 350 | * |
351 | * @param serverAddr address to listen on | ||
352 | * @param socklen length of address | ||
342 | * @return NULL on error, otherwise the listen socket | 353 | * @return NULL on error, otherwise the listen socket |
343 | */ | 354 | */ |
344 | static struct GNUNET_NETWORK_Handle * | 355 | static struct GNUNET_NETWORK_Handle * |
@@ -500,11 +511,12 @@ GNUNET_SERVER_create (struct GNUNET_SCHEDULER_Handle *sched, | |||
500 | 511 | ||
501 | /** | 512 | /** |
502 | * Free resources held by this server. | 513 | * Free resources held by this server. |
514 | * | ||
515 | * @param s server to destroy | ||
503 | */ | 516 | */ |
504 | void | 517 | void |
505 | GNUNET_SERVER_destroy (struct GNUNET_SERVER_Handle *s) | 518 | GNUNET_SERVER_destroy (struct GNUNET_SERVER_Handle *s) |
506 | { | 519 | { |
507 | struct GNUNET_SERVER_Client *pos; | ||
508 | struct HandlerList *hpos; | 520 | struct HandlerList *hpos; |
509 | struct NotifyList *npos; | 521 | struct NotifyList *npos; |
510 | unsigned int i; | 522 | unsigned int i; |
@@ -527,11 +539,7 @@ GNUNET_SERVER_destroy (struct GNUNET_SERVER_Handle *s) | |||
527 | s->listen_sockets = NULL; | 539 | s->listen_sockets = NULL; |
528 | } | 540 | } |
529 | while (s->clients != NULL) | 541 | while (s->clients != NULL) |
530 | { | 542 | GNUNET_SERVER_client_disconnect (s->clients); |
531 | pos = s->clients; | ||
532 | s->clients = pos->next; | ||
533 | pos->server = NULL; | ||
534 | } | ||
535 | while (NULL != (hpos = s->handlers)) | 543 | while (NULL != (hpos = s->handlers)) |
536 | { | 544 | { |
537 | s->handlers = hpos->next; | 545 | s->handlers = hpos->next; |
@@ -645,52 +653,6 @@ GNUNET_SERVER_inject (struct GNUNET_SERVER_Handle *server, | |||
645 | 653 | ||
646 | 654 | ||
647 | /** | 655 | /** |
648 | * We're finished with this client and especially its input | ||
649 | * processing. If the RC is zero, free all resources otherwise wait | ||
650 | * until RC hits zero to do so. | ||
651 | */ | ||
652 | static void | ||
653 | shutdown_incoming_processing (struct GNUNET_SERVER_Client *client) | ||
654 | { | ||
655 | struct GNUNET_SERVER_Client *prev; | ||
656 | struct GNUNET_SERVER_Client *pos; | ||
657 | struct GNUNET_SERVER_Handle *server; | ||
658 | struct NotifyList *n; | ||
659 | unsigned int rc; | ||
660 | |||
661 | rc = client->reference_count; | ||
662 | if (client->server != NULL) | ||
663 | { | ||
664 | server = client->server; | ||
665 | client->server = NULL; | ||
666 | prev = NULL; | ||
667 | pos = server->clients; | ||
668 | while ((pos != NULL) && (pos != client)) | ||
669 | { | ||
670 | prev = pos; | ||
671 | pos = pos->next; | ||
672 | } | ||
673 | GNUNET_assert (pos != NULL); | ||
674 | if (prev == NULL) | ||
675 | server->clients = pos->next; | ||
676 | else | ||
677 | prev->next = pos->next; | ||
678 | n = server->disconnect_notify_list; | ||
679 | while (n != NULL) | ||
680 | { | ||
681 | n->callback (n->callback_cls, client); | ||
682 | n = n->next; | ||
683 | } | ||
684 | } | ||
685 | /* wait for RC to hit zero, then free */ | ||
686 | if (rc > 0) | ||
687 | return; | ||
688 | client->destroy (client->client_closure); | ||
689 | GNUNET_free (client); | ||
690 | } | ||
691 | |||
692 | |||
693 | /** | ||
694 | * Go over the contents of the client buffer; as long as full messages | 656 | * Go over the contents of the client buffer; as long as full messages |
695 | * are available, pass them on for processing. Update the buffer | 657 | * are available, pass them on for processing. Update the buffer |
696 | * accordingly. Handles fatal errors by shutting down the connection. | 658 | * accordingly. Handles fatal errors by shutting down the connection. |
@@ -713,8 +675,9 @@ process_client_buffer (struct GNUNET_SERVER_Client *client) | |||
713 | client->suspended ? "suspended" : "up", | 675 | client->suspended ? "suspended" : "up", |
714 | client->shutdown_now ? "in shutdown" : "running"); | 676 | client->shutdown_now ? "in shutdown" : "running"); |
715 | #endif | 677 | #endif |
716 | while ((client->receive_pos >= sizeof (struct GNUNET_MessageHeader)) && | 678 | while ( (client->receive_pos >= sizeof (struct GNUNET_MessageHeader)) && |
717 | (0 == client->suspended) && (GNUNET_YES != client->shutdown_now)) | 679 | (0 == client->suspended) && |
680 | (GNUNET_YES != client->shutdown_now) ) | ||
718 | { | 681 | { |
719 | hdr = (const struct GNUNET_MessageHeader *) &client->incoming_buffer; | 682 | hdr = (const struct GNUNET_MessageHeader *) &client->incoming_buffer; |
720 | msize = ntohs (hdr->size); | 683 | msize = ntohs (hdr->size); |
@@ -731,11 +694,11 @@ process_client_buffer (struct GNUNET_SERVER_Client *client) | |||
731 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 694 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
732 | "Passing %u bytes to callback for processing\n", msize); | 695 | "Passing %u bytes to callback for processing\n", msize); |
733 | #endif | 696 | #endif |
734 | if ((msize < sizeof (struct GNUNET_MessageHeader)) || | 697 | if ( (msize < sizeof (struct GNUNET_MessageHeader)) || |
735 | (GNUNET_OK != GNUNET_SERVER_inject (server, client, hdr))) | 698 | (GNUNET_OK != GNUNET_SERVER_inject (server, client, hdr)) ) |
736 | { | 699 | { |
737 | client->in_process_client_buffer = GNUNET_NO; | 700 | client->in_process_client_buffer = GNUNET_NO; |
738 | shutdown_incoming_processing (client); | 701 | GNUNET_SERVER_client_disconnect (client); |
739 | return; | 702 | return; |
740 | } | 703 | } |
741 | /* FIXME: this is highly inefficient; we should | 704 | /* FIXME: this is highly inefficient; we should |
@@ -747,7 +710,7 @@ process_client_buffer (struct GNUNET_SERVER_Client *client) | |||
747 | } | 710 | } |
748 | client->in_process_client_buffer = GNUNET_NO; | 711 | client->in_process_client_buffer = GNUNET_NO; |
749 | if (GNUNET_YES == client->shutdown_now) | 712 | if (GNUNET_YES == client->shutdown_now) |
750 | shutdown_incoming_processing (client); | 713 | GNUNET_SERVER_client_disconnect (client); |
751 | } | 714 | } |
752 | 715 | ||
753 | 716 | ||
@@ -772,6 +735,7 @@ process_incoming (void *cls, | |||
772 | const char *cbuf = buf; | 735 | const char *cbuf = buf; |
773 | size_t maxcpy; | 736 | size_t maxcpy; |
774 | 737 | ||
738 | client->receive_pending = GNUNET_NO; | ||
775 | if ((buf == NULL) || | 739 | if ((buf == NULL) || |
776 | (available == 0) || | 740 | (available == 0) || |
777 | (errCode != 0) || | 741 | (errCode != 0) || |
@@ -780,7 +744,7 @@ process_incoming (void *cls, | |||
780 | (GNUNET_YES != client->check (client->client_closure))) | 744 | (GNUNET_YES != client->check (client->client_closure))) |
781 | { | 745 | { |
782 | /* other side closed connection, error connecting, etc. */ | 746 | /* other side closed connection, error connecting, etc. */ |
783 | shutdown_incoming_processing (client); | 747 | GNUNET_SERVER_client_disconnect (client); |
784 | return; | 748 | return; |
785 | } | 749 | } |
786 | #if DEBUG_SERVER | 750 | #if DEBUG_SERVER |
@@ -833,18 +797,23 @@ process_incoming (void *cls, | |||
833 | (GNUNET_YES != client->shutdown_now) && (client->server != NULL)) | 797 | (GNUNET_YES != client->shutdown_now) && (client->server != NULL)) |
834 | { | 798 | { |
835 | /* Finally, keep receiving! */ | 799 | /* Finally, keep receiving! */ |
800 | client->receive_pending = GNUNET_YES; | ||
836 | client->receive (client->client_closure, | 801 | client->receive (client->client_closure, |
837 | GNUNET_SERVER_MAX_MESSAGE_SIZE, | 802 | GNUNET_SERVER_MAX_MESSAGE_SIZE, |
838 | server->idle_timeout, &process_incoming, client); | 803 | server->idle_timeout, &process_incoming, client); |
839 | } | 804 | } |
840 | if (GNUNET_YES == client->shutdown_now) | 805 | if (GNUNET_YES == client->shutdown_now) |
841 | shutdown_incoming_processing (client); | 806 | GNUNET_SERVER_client_disconnect (client); |
842 | GNUNET_SERVER_client_drop (client); | 807 | GNUNET_SERVER_client_drop (client); |
843 | } | 808 | } |
844 | 809 | ||
845 | 810 | ||
846 | /** | 811 | /** |
847 | * FIXME: document. | 812 | * Task run to start again receiving from the network |
813 | * and process requests. | ||
814 | * | ||
815 | * @param cls our 'struct GNUNET_SERVER_Client*' to process more requests from | ||
816 | * @param tc scheduler context (unused) | ||
848 | */ | 817 | */ |
849 | static void | 818 | static void |
850 | restart_processing (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | 819 | restart_processing (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) |
@@ -852,19 +821,22 @@ restart_processing (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | |||
852 | struct GNUNET_SERVER_Client *client = cls; | 821 | struct GNUNET_SERVER_Client *client = cls; |
853 | struct GNUNET_SERVER_Handle *server = client->server; | 822 | struct GNUNET_SERVER_Handle *server = client->server; |
854 | 823 | ||
824 | client->restart_task = GNUNET_SCHEDULER_NO_TASK; | ||
855 | if ( (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) && | 825 | if ( (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) && |
856 | ( (server == NULL) || | 826 | (GNUNET_NO == server->clients_ignore_shutdown) ) |
857 | (GNUNET_NO == server->clients_ignore_shutdown) ) ) | ||
858 | { | 827 | { |
859 | shutdown_incoming_processing (client); | 828 | GNUNET_SERVER_client_disconnect (client); |
860 | return; | 829 | return; |
861 | } | 830 | } |
862 | GNUNET_SERVER_client_keep (client); | 831 | GNUNET_SERVER_client_keep (client); |
863 | process_client_buffer (client); | 832 | process_client_buffer (client); |
864 | if (0 == client->suspended) | 833 | if (0 == client->suspended) |
865 | client->receive (client->client_closure, | 834 | { |
866 | GNUNET_SERVER_MAX_MESSAGE_SIZE, | 835 | client->receive_pending = GNUNET_YES; |
867 | client->server->idle_timeout, &process_incoming, client); | 836 | client->receive (client->client_closure, |
837 | GNUNET_SERVER_MAX_MESSAGE_SIZE, | ||
838 | client->server->idle_timeout, &process_incoming, client); | ||
839 | } | ||
868 | GNUNET_SERVER_client_drop (client); | 840 | GNUNET_SERVER_client_drop (client); |
869 | } | 841 | } |
870 | 842 | ||
@@ -881,6 +853,7 @@ add_client (struct GNUNET_SERVER_Handle *server, | |||
881 | client->last_activity = GNUNET_TIME_absolute_get (); | 853 | client->last_activity = GNUNET_TIME_absolute_get (); |
882 | client->next = server->clients; | 854 | client->next = server->clients; |
883 | server->clients = client; | 855 | server->clients = client; |
856 | client->receive_pending = GNUNET_YES; | ||
884 | client->receive (client->client_closure, | 857 | client->receive (client->client_closure, |
885 | GNUNET_SERVER_MAX_MESSAGE_SIZE, | 858 | GNUNET_SERVER_MAX_MESSAGE_SIZE, |
886 | server->idle_timeout, &process_incoming, client); | 859 | server->idle_timeout, &process_incoming, client); |
@@ -1079,8 +1052,9 @@ GNUNET_SERVER_client_drop (struct GNUNET_SERVER_Client *client) | |||
1079 | { | 1052 | { |
1080 | GNUNET_assert (client->reference_count > 0); | 1053 | GNUNET_assert (client->reference_count > 0); |
1081 | client->reference_count--; | 1054 | client->reference_count--; |
1082 | if ((client->server == NULL) && (client->reference_count == 0)) | 1055 | if ( (client->shutdown_now == GNUNET_YES) && |
1083 | shutdown_incoming_processing (client); | 1056 | (client->reference_count == 0) ) |
1057 | GNUNET_SERVER_client_disconnect (client); | ||
1084 | } | 1058 | } |
1085 | 1059 | ||
1086 | 1060 | ||
@@ -1177,10 +1151,59 @@ GNUNET_SERVER_disconnect_notify_cancel (struct GNUNET_SERVER_Handle *server, | |||
1177 | void | 1151 | void |
1178 | GNUNET_SERVER_client_disconnect (struct GNUNET_SERVER_Client *client) | 1152 | GNUNET_SERVER_client_disconnect (struct GNUNET_SERVER_Client *client) |
1179 | { | 1153 | { |
1180 | if (client->server == NULL) | 1154 | struct GNUNET_SERVER_Client *prev; |
1181 | return; /* already disconnected */ | 1155 | struct GNUNET_SERVER_Client *pos; |
1182 | client->receive_cancel (client->client_closure); | 1156 | struct GNUNET_SERVER_Handle *server; |
1183 | shutdown_incoming_processing (client); | 1157 | struct NotifyList *n; |
1158 | unsigned int rc; | ||
1159 | |||
1160 | if (client->restart_task != GNUNET_SCHEDULER_NO_TASK) | ||
1161 | { | ||
1162 | GNUNET_SCHEDULER_cancel (client->server->sched, | ||
1163 | client->restart_task); | ||
1164 | client->restart_task = GNUNET_SCHEDULER_NO_TASK; | ||
1165 | } | ||
1166 | if (GNUNET_YES == client->receive_pending) | ||
1167 | { | ||
1168 | client->receive_cancel (client->client_closure); | ||
1169 | client->receive_pending = GNUNET_NO; | ||
1170 | } | ||
1171 | rc = client->reference_count; | ||
1172 | if (client->server != NULL) | ||
1173 | { | ||
1174 | server = client->server; | ||
1175 | client->server = NULL; | ||
1176 | client->shutdown_now = GNUNET_YES; | ||
1177 | prev = NULL; | ||
1178 | pos = server->clients; | ||
1179 | while ((pos != NULL) && (pos != client)) | ||
1180 | { | ||
1181 | prev = pos; | ||
1182 | pos = pos->next; | ||
1183 | } | ||
1184 | GNUNET_assert (pos != NULL); | ||
1185 | if (prev == NULL) | ||
1186 | server->clients = pos->next; | ||
1187 | else | ||
1188 | prev->next = pos->next; | ||
1189 | n = server->disconnect_notify_list; | ||
1190 | while (n != NULL) | ||
1191 | { | ||
1192 | n->callback (n->callback_cls, client); | ||
1193 | n = n->next; | ||
1194 | } | ||
1195 | if (client->restart_task != GNUNET_SCHEDULER_NO_TASK) | ||
1196 | GNUNET_SCHEDULER_cancel (client->server->sched, | ||
1197 | client->restart_task); | ||
1198 | } | ||
1199 | if (rc > 0) | ||
1200 | return; | ||
1201 | if (client->in_process_client_buffer) | ||
1202 | return; | ||
1203 | client->destroy (client->client_closure); | ||
1204 | GNUNET_free (client); | ||
1205 | |||
1206 | |||
1184 | } | 1207 | } |
1185 | 1208 | ||
1186 | 1209 | ||
@@ -1234,7 +1257,10 @@ GNUNET_SERVER_receive_done (struct GNUNET_SERVER_Client *client, int success) | |||
1234 | GNUNET_assert (client->suspended > 0); | 1257 | GNUNET_assert (client->suspended > 0); |
1235 | client->suspended--; | 1258 | client->suspended--; |
1236 | if (success != GNUNET_OK) | 1259 | if (success != GNUNET_OK) |
1237 | client->shutdown_now = GNUNET_YES; | 1260 | { |
1261 | GNUNET_SERVER_client_disconnect (client); | ||
1262 | return; | ||
1263 | } | ||
1238 | if (client->suspended > 0) | 1264 | if (client->suspended > 0) |
1239 | return; | 1265 | return; |
1240 | if (client->in_process_client_buffer == GNUNET_YES) | 1266 | if (client->in_process_client_buffer == GNUNET_YES) |
@@ -1245,24 +1271,14 @@ GNUNET_SERVER_receive_done (struct GNUNET_SERVER_Client *client, int success) | |||
1245 | sb = client->side_buf; | 1271 | sb = client->side_buf; |
1246 | client->side_buf = NULL; | 1272 | client->side_buf = NULL; |
1247 | /* this will also resume the receive job */ | 1273 | /* this will also resume the receive job */ |
1248 | if (GNUNET_YES != client->shutdown_now) | 1274 | process_incoming (client, sb, client->side_buf_size, NULL, 0, 0); |
1249 | process_incoming (client, sb, client->side_buf_size, NULL, 0, 0); | ||
1250 | else | ||
1251 | shutdown_incoming_processing (client); | ||
1252 | /* finally, free the side-buf */ | 1275 | /* finally, free the side-buf */ |
1253 | GNUNET_free (sb); | 1276 | GNUNET_free (sb); |
1254 | return; | 1277 | return; |
1255 | } | 1278 | } |
1256 | /* resume receive job */ | 1279 | client->restart_task = GNUNET_SCHEDULER_add_now (client->server->sched, |
1257 | if (GNUNET_YES != client->shutdown_now) | 1280 | &restart_processing, |
1258 | { | 1281 | client); |
1259 | GNUNET_SCHEDULER_add_continuation (client->server->sched, | ||
1260 | &restart_processing, | ||
1261 | client, | ||
1262 | GNUNET_SCHEDULER_REASON_PREREQ_DONE); | ||
1263 | return; | ||
1264 | } | ||
1265 | shutdown_incoming_processing (client); | ||
1266 | } | 1282 | } |
1267 | 1283 | ||
1268 | 1284 | ||