aboutsummaryrefslogtreecommitdiff
path: root/src/util/server.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2010-02-10 16:54:51 +0000
committerChristian Grothoff <christian@grothoff.org>2010-02-10 16:54:51 +0000
commit1b49f3e84f047a26e2742c68893c3be6b5c1ec69 (patch)
treede2afa79ee3e3b95018df16cf5f180a9227626c5 /src/util/server.c
parent1366ecaaa9c01dc3d9596fd48d53c50a29f17e02 (diff)
downloadgnunet-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.c192
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 */
344static struct GNUNET_NETWORK_Handle * 355static 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 */
504void 517void
505GNUNET_SERVER_destroy (struct GNUNET_SERVER_Handle *s) 518GNUNET_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 */
652static void
653shutdown_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 */
849static void 818static void
850restart_processing (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) 819restart_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,
1177void 1151void
1178GNUNET_SERVER_client_disconnect (struct GNUNET_SERVER_Client *client) 1152GNUNET_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