2 This file is part of GNUnet.
3 (C) 2012 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 2, or (at your
8 option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
22 * @file testbed/gnunet-service-testbed.c
23 * @brief implementation of the TESTBED service
24 * @author Sree Harsha Totakura
28 #include "gnunet_service_lib.h"
29 #include "gnunet_server_lib.h"
33 #include "gnunet_testbed_service.h"
34 #include "testbed_api_hosts.h"
39 #define LOG(kind,...) \
40 GNUNET_log (kind, __VA_ARGS__)
45 #define LOG_DEBUG(...) \
46 LOG (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
51 * The client handle associated with this context
53 struct GNUNET_SERVER_Client *client;
56 * Event mask of event to be responded in this context
61 * Our host id according to this context
68 * The message queue for sending messages to clients
73 * The message to be sent
75 struct GNUNET_MessageHeader *msg;
78 * The client to send the message to
80 struct GNUNET_SERVER_Client *client;
83 * next pointer for DLL
85 struct MessageQueue *next;
88 * prev pointer for DLL
90 struct MessageQueue *prev;
95 * The structure for identifying a shared service
100 * The name of the shared service
105 * Number of shared peers per instance of the shared service
110 * Number of peers currently sharing the service
112 uint32_t num_sharing;
122 * The forwarding (next hop) host id
127 * The controller handle if we have started the controller at the next hop
130 struct GNUNET_TESTBED_Controller *fcontroller;
135 * States of LCFContext
140 * The Context has been initialized; Nothing has been done on it
145 * Delegated host has been registered at the forwarding controller
147 DELEGATED_HOST_REGISTERED,
150 * The slave host has been registred at the forwarding controller
152 SLAVE_HOST_REGISTERED,
155 * The context has been finished (may have error)
163 * Link controllers request forwarding context
170 struct GNUNET_CONFIGURATION_Handle *cfg;
173 * The handle of the controller this request has to be forwarded to
175 struct GNUNET_TESTBED_Controller *fcontroller;
178 * The host registration handle while registered hosts in this context
180 struct GNUNET_TESTBED_HostRegistrationHandle *rhandle;
183 * Should the delegated host be started by the slave host?
188 * The state of this context
190 enum LCFContextState state;
195 uint32_t delegated_host_id;
200 uint32_t slave_host_id;
206 * Structure of a queue entry in LCFContext request queue
208 struct LCFContextQueue
213 struct LCFContext *lcf;
218 struct LCFContextQueue *next;
223 struct LCFContextQueue *prev;
230 static struct GNUNET_DISK_FileHandle *fh;
233 * The master context; generated with the first INIT message
235 static struct Context *master_context;
238 * The shutdown task handle
240 static GNUNET_SCHEDULER_TaskIdentifier shutdown_task_id;
245 static struct GNUNET_TESTBED_Host **host_list;
248 * The size of the host list
250 static uint32_t host_list_size;
255 static struct Route **route_list;
258 * The size of the route list
260 static uint32_t route_list_size;
263 * The message queue head
265 static struct MessageQueue *mq_head;
268 * The message queue tail
270 static struct MessageQueue *mq_tail;
273 * The head for the LCF queue
275 static struct LCFContextQueue *lcfq_head;
278 * The tail for the LCF queue
280 static struct LCFContextQueue *lcfq_tail;
283 * Current Transmit Handle; NULL if no notify transmit exists currently
285 struct GNUNET_SERVER_TransmitHandle *transmit_handle;
288 * The hashmap of shared services
290 struct GNUNET_CONTAINER_MultiHashMap *ss_map;
294 * Function called to notify a client about the connection begin ready to queue
295 * more data. "buf" will be NULL and "size" zero if the connection was closed
296 * for writing in the meantime.
299 * @param size number of bytes available in buf
300 * @param buf where the callee should write the message
301 * @return number of bytes written to buf
304 transmit_ready_notify (void *cls, size_t size, void *buf)
306 struct MessageQueue *mq_entry;
308 transmit_handle = NULL;
310 GNUNET_assert (NULL != mq_entry);
313 GNUNET_assert (ntohs (mq_entry->msg->size) <= size);
314 size = ntohs (mq_entry->msg->size);
315 memcpy (buf, mq_entry->msg, size);
316 GNUNET_free (mq_entry->msg);
317 GNUNET_CONTAINER_DLL_remove (mq_head, mq_tail, mq_entry);
318 GNUNET_free (mq_entry);
320 if (NULL != mq_entry)
322 GNUNET_SERVER_notify_transmit_ready (mq_entry->client,
323 ntohs (mq_entry->msg->size),
324 GNUNET_TIME_UNIT_FOREVER_REL,
325 &transmit_ready_notify, NULL);
331 * Queues a message in send queue for sending to the service
333 * @param client the client to whom the queued message has to be sent
334 * @param msg the message to queue
337 queue_message (struct GNUNET_SERVER_Client *client,
338 struct GNUNET_MessageHeader *msg)
340 struct MessageQueue *mq_entry;
344 type = ntohs (msg->type);
345 size = ntohs (msg->size);
346 GNUNET_assert ((GNUNET_MESSAGE_TYPE_TESTBED_INIT <= type) &&
347 (GNUNET_MESSAGE_TYPE_TESTBED_MAX > type));
348 mq_entry = GNUNET_malloc (sizeof (struct MessageQueue));
350 mq_entry->client = client;
351 LOG_DEBUG ( "Queueing message of type %u, size %u for sending\n", type,
353 GNUNET_CONTAINER_DLL_insert_tail (mq_head, mq_tail, mq_entry);
354 if (NULL == transmit_handle)
356 GNUNET_SERVER_notify_transmit_ready (client, size,
357 GNUNET_TIME_UNIT_FOREVER_REL,
358 &transmit_ready_notify, NULL);
363 * Function to add a host to the current list of known hosts
365 * @param host the host to add
366 * @return GNUNET_OK on success; GNUNET_SYSERR on failure due to host-id
370 host_list_add (struct GNUNET_TESTBED_Host *host)
374 host_id = GNUNET_TESTBED_host_get_id_ (host);
375 if (host_list_size <= host_id)
377 host_list = GNUNET_realloc (host_list,
378 sizeof (struct GNUNET_TESTBED_Host *)
380 host_list_size += (host_id + 10);
382 if (NULL != host_list[host_id])
384 LOG_DEBUG ("A host with id: %u already exists\n", host_id);
385 return GNUNET_SYSERR;
387 host_list[host_id] = host;
393 * Routes message to a host given its host_id
395 * @param host_id the id of the destination host
396 * @param msg the message to be routed
399 route_message (uint32_t host_id, const struct GNUNET_MessageHeader *msg)
406 * The Link Controller forwarding task
408 * @param cls the LCFContext
409 * @param tc the Task context from scheduler
412 lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
416 * Completion callback for host registrations while forwarding Link Controller messages
418 * @param cls the LCFContext
419 * @param emsg the error message; NULL if host registration is successful
422 lcf_proc_cc (void *cls, const char *emsg)
424 struct LCFContext *lcf = cls;
431 goto registration_error;
432 lcf->state = DELEGATED_HOST_REGISTERED;
433 (void) GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
435 case DELEGATED_HOST_REGISTERED:
437 goto registration_error;
438 lcf->state = SLAVE_HOST_REGISTERED;
439 (void) GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
442 GNUNET_assert (0); /* Shouldn't reach here */
447 LOG (GNUNET_ERROR_TYPE_WARNING,
448 "Host registration failed with message: %s\n", emsg);
449 lcf->state = FINISHED;
450 (void) GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
455 * The Link Controller forwarding task
457 * @param cls the LCFContext
458 * @param tc the Task context from scheduler
461 lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
463 struct LCFContext *lcf = cls;
464 struct LCFContextQueue *lcfq;
470 GNUNET_TESTBED_is_host_registered_ (host_list[lcf->delegated_host_id],
474 GNUNET_TESTBED_register_host (lcf->fcontroller,
475 host_list[lcf->delegated_host_id],
480 lcf->state = DELEGATED_HOST_REGISTERED;
481 (void) GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
484 case DELEGATED_HOST_REGISTERED:
486 GNUNET_TESTBED_is_host_registered_ (host_list[lcf->slave_host_id],
490 GNUNET_TESTBED_register_host (lcf->fcontroller,
491 host_list[lcf->slave_host_id],
496 lcf->state = SLAVE_HOST_REGISTERED;
497 (void) GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
500 case SLAVE_HOST_REGISTERED:
501 GNUNET_TESTBED_controller_link (lcf->fcontroller,
502 host_list[lcf->delegated_host_id],
503 host_list[lcf->slave_host_id],
504 lcf->cfg, lcf->is_subordinate);
505 lcf->state = FINISHED;
509 GNUNET_CONFIGURATION_destroy (lcfq->lcf->cfg);
510 GNUNET_free (lcfq->lcf);
511 GNUNET_CONTAINER_DLL_remove (lcfq_head, lcfq_tail, lcfq);
513 if (NULL != lcfq_head)
514 (void) GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcfq_head->lcf);
520 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_INIT messages
523 * @param client identification of the client
524 * @param message the actual message
527 handle_init (void *cls,
528 struct GNUNET_SERVER_Client *client,
529 const struct GNUNET_MessageHeader *message)
531 const struct GNUNET_TESTBED_InitMessage *msg;
532 struct GNUNET_TESTBED_Host *host;
534 if (NULL != master_context)
537 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
540 msg = (const struct GNUNET_TESTBED_InitMessage *) message;
541 master_context = GNUNET_malloc (sizeof (struct Context));
542 master_context->client = client;
543 master_context->host_id = ntohl (msg->host_id);
544 host = GNUNET_TESTBED_host_create_with_id (master_context->host_id,
546 host_list_add (host);
547 master_context->event_mask = GNUNET_ntohll (msg->event_mask);
548 GNUNET_SERVER_client_keep (client);
549 LOG_DEBUG ("Created master context with host ID: %u\n",
550 master_context->host_id);
551 GNUNET_SERVER_receive_done (client, GNUNET_OK);
556 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST messages
559 * @param client identification of the client
560 * @param message the actual message
563 handle_add_host (void *cls,
564 struct GNUNET_SERVER_Client *client,
565 const struct GNUNET_MessageHeader *message)
567 struct GNUNET_TESTBED_Host *host;
568 const struct GNUNET_TESTBED_AddHostMessage *msg;
569 struct GNUNET_TESTBED_HostConfirmedMessage *reply;
574 uint16_t username_length;
575 uint16_t hostname_length;
578 msg = (const struct GNUNET_TESTBED_AddHostMessage *) message;
579 username_length = ntohs (msg->user_name_length);
580 username_length = (0 == username_length) ? 0 : username_length + 1;
581 username = (char *) &(msg[1]);
582 hostname = username + username_length;
583 if (ntohs (message->size) <=
584 (sizeof (struct GNUNET_TESTBED_AddHostMessage) + username_length))
587 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
590 hostname_length = ntohs (message->size)
591 - (sizeof (struct GNUNET_TESTBED_AddHostMessage) + username_length);
592 if (strlen (hostname) != hostname_length)
595 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
598 host_id = ntohl (msg->host_id);
599 LOG_DEBUG ("Received ADDHOST message\n");
600 LOG_DEBUG ("-------host id: %u\n", host_id);
601 if (NULL != hostname) LOG_DEBUG ("-------hostname: %s\n", hostname);
602 if (NULL != username) LOG_DEBUG ("-------username: %s\n", username);
603 LOG_DEBUG ("-------ssh port: %u\n", ntohs (msg->ssh_port));
604 host = GNUNET_TESTBED_host_create_with_id (host_id, hostname, username,
605 ntohs (msg->ssh_port));
606 GNUNET_SERVER_receive_done (client, GNUNET_OK);
607 reply_size = sizeof (struct GNUNET_TESTBED_HostConfirmedMessage);
608 if (GNUNET_OK != host_list_add (host))
610 /* We are unable to add a host */
611 emsg = "A host exists with given host-id";
612 LOG_DEBUG ("%s: %u", emsg, host_id);
613 GNUNET_TESTBED_host_destroy (host);
614 reply_size += strlen (emsg) + 1;
615 reply = GNUNET_malloc (reply_size);
616 memcpy (&reply[1], emsg, strlen (emsg) + 1);
619 reply = GNUNET_malloc (reply_size);
620 reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_ADDHOSTCONFIRM);
621 reply->header.size = htons (reply_size);
622 reply->host_id = htonl (host_id);
623 queue_message (client, (struct GNUNET_MessageHeader *) reply);
628 * Iterator over hash map entries.
631 * @param key current key code
632 * @param value value in the hash map
633 * @return GNUNET_YES if we should continue to
637 int ss_exists_iterator (void *cls,
638 const struct GNUNET_HashCode * key,
641 struct SharedService *queried_ss = cls;
642 struct SharedService *ss = value;
644 if (0 == strcmp (ss->name, queried_ss->name))
651 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST messages
654 * @param client identification of the client
655 * @param message the actual message
658 handle_configure_shared_service (void *cls,
659 struct GNUNET_SERVER_Client *client,
660 const struct GNUNET_MessageHeader *message)
662 const struct GNUNET_TESTBED_ConfigureSharedServiceMessage *msg;
663 struct SharedService *ss;
665 struct GNUNET_HashCode hash;
667 uint16_t service_name_size;
669 msg = (const struct GNUNET_TESTBED_ConfigureSharedServiceMessage *) message;
670 msg_size = ntohs (message->size);
671 if (msg_size <= sizeof (struct GNUNET_TESTBED_ConfigureSharedServiceMessage))
674 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
677 service_name_size = msg_size -
678 sizeof (struct GNUNET_TESTBED_ConfigureSharedServiceMessage);
679 service_name = (char *) &msg[1];
680 if ('\0' != service_name[service_name_size - 1])
683 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
686 LOG_DEBUG ("Received service sharing request for %s, with %d peers\n",
687 service_name, ntohl (msg->num_peers));
688 if (ntohl (msg->host_id) != master_context->host_id)
690 route_message (ntohl (msg->host_id), message);
691 GNUNET_SERVER_receive_done (client, GNUNET_OK);
694 GNUNET_SERVER_receive_done (client, GNUNET_OK);
695 ss = GNUNET_malloc (sizeof (struct SharedService));
696 ss->name = strdup (service_name);
697 ss->num_shared = ntohl (msg->num_peers);
698 GNUNET_CRYPTO_hash (ss->name, service_name_size, &hash);
700 GNUNET_CONTAINER_multihashmap_get_multiple (ss_map, &hash,
701 &ss_exists_iterator, ss))
703 LOG (GNUNET_ERROR_TYPE_WARNING,
704 "Service %s already configured as a shared service. "
705 "Ignoring service sharing request \n", ss->name);
706 GNUNET_free (ss->name);
710 GNUNET_CONTAINER_multihashmap_put (ss_map, &hash, ss,
711 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
716 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_LCONTROLLERS message
719 * @param client identification of the client
720 * @param message the actual message
723 handle_link_controllers (void *cls,
724 struct GNUNET_SERVER_Client *client,
725 const struct GNUNET_MessageHeader *message)
727 const struct GNUNET_TESTBED_ControllerLinkMessage *msg;
728 struct GNUNET_CONFIGURATION_Handle *cfg;
729 struct LCFContextQueue *lcfq;
734 uint32_t delegated_host_id;
735 uint32_t slave_host_id;
738 msize = ntohs (message->size);
739 if (sizeof (struct GNUNET_TESTBED_ControllerLinkMessage) >= msize)
742 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
745 msg = (const struct GNUNET_TESTBED_ControllerLinkMessage *) message;
746 delegated_host_id = ntohl (msg->delegated_host_id);
747 if (delegated_host_id == master_context->host_id)
750 LOG (GNUNET_ERROR_TYPE_WARNING, "Trying to link ourselves\n");
751 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
754 if ((delegated_host_id >= host_list_size) ||
755 (NULL == host_list[delegated_host_id]))
757 LOG (GNUNET_ERROR_TYPE_WARNING, "Delegated host not registered with us\n");
758 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
761 slave_host_id = ntohl (msg->slave_host_id);
762 if ((slave_host_id >= host_list_size) || (NULL == host_list[slave_host_id]))
764 LOG (GNUNET_ERROR_TYPE_WARNING, "Slave host not registered with us\n");
765 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
769 config_size = ntohs (msg->config_size);
770 config = GNUNET_malloc (config_size);
771 dest_size = (uLongf) config_size;
772 msize -= sizeof (struct GNUNET_TESTBED_ControllerLinkMessage);
773 if (Z_OK != uncompress ((Bytef *) config, &dest_size,
774 (const Bytef *) &msg[1], (uLong) msize))
776 GNUNET_break (0); /* Compression error */
777 GNUNET_free (config);
778 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
781 GNUNET_assert (config_size == dest_size);
782 cfg = GNUNET_CONFIGURATION_create ();
783 if (GNUNET_OK != GNUNET_CONFIGURATION_deserialize (cfg, config, config_size,
786 GNUNET_break (0); /* Configuration parsing error */
787 GNUNET_break (config);
788 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
791 GNUNET_free (config);
793 /* If delegated host and slave host are not same we have to forward
794 towards delegated host */
795 if (slave_host_id != delegated_host_id)
797 if ((slave_host_id >= route_list_size) ||
798 (NULL == (route = route_list[slave_host_id])) ||
799 (NULL == route->fcontroller))
801 LOG (GNUNET_ERROR_TYPE_WARNING, "Not route towards slave host");
802 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
805 if (slave_host_id == route->next_hop) /* Slave directly connected */
807 /* Then make slave host and delegated host same so that slave
808 will startup directly link to the delegated host */
809 slave_host_id = delegated_host_id;
811 lcfq = GNUNET_malloc (sizeof (struct LCFContextQueue));
812 lcfq->lcf = GNUNET_malloc (sizeof (struct LCFContext));
813 lcfq->lcf->delegated_host_id = delegated_host_id;
814 lcfq->lcf->slave_host_id = slave_host_id;
815 lcfq->lcf->is_subordinate =
816 (1 == msg->is_subordinate) ? GNUNET_YES : GNUNET_NO;
817 lcfq->lcf->state = INIT;
818 lcfq->lcf->fcontroller = route->fcontroller;
819 lcfq->lcf->cfg = cfg;
820 if (NULL == lcfq_head)
822 GNUNET_CONTAINER_DLL_insert_tail (lcfq_head, lcfq_tail, lcfq);
823 (void) GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcfq);
826 GNUNET_CONTAINER_DLL_insert_tail (lcfq_head, lcfq_tail, lcfq);
827 GNUNET_SERVER_receive_done (client, GNUNET_OK);
830 GNUNET_SERVER_receive_done (client, GNUNET_OK);
831 /* If we are not the slave controller then we have to route the request
832 towards the slave controller */
833 if (1 == msg->is_subordinate)
835 GNUNET_break (0); /* FIXME: Implement the slave controller
838 GNUNET_CONFIGURATION_destroy (cfg);
843 * Iterator over hash map entries.
846 * @param key current key code
847 * @param value value in the hash map
848 * @return GNUNET_YES if we should continue to
853 ss_map_free_iterator (void *cls,
854 const struct GNUNET_HashCode * key, void *value)
856 struct SharedService *ss = value;
858 GNUNET_assert (GNUNET_YES ==
859 GNUNET_CONTAINER_multihashmap_remove (ss_map, key, value));
860 GNUNET_free (ss->name);
867 * Task to clean up and shutdown nicely
870 * @param tc the TaskContext from scheduler
873 shutdown_task (void *cls,
874 const struct GNUNET_SCHEDULER_TaskContext *tc)
879 shutdown_task_id = GNUNET_SCHEDULER_NO_TASK;
880 GNUNET_SCHEDULER_shutdown ();
881 LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down testbed service\n");
882 (void) GNUNET_CONTAINER_multihashmap_iterate (ss_map, &ss_map_free_iterator,
884 GNUNET_CONTAINER_multihashmap_destroy (ss_map);
887 GNUNET_DISK_file_close (fh);
890 /* Clear host list */
891 for (host_id = 0; host_id < host_list_size; host_id++)
892 if (NULL != host_list[host_id])
893 GNUNET_TESTBED_host_destroy (host_list[host_id]);
894 GNUNET_free_non_null (host_list);
895 /* Clear route list */
896 for (route_id = 0; route_id < route_list_size; route_id++)
897 if (NULL != route_list[route_id])
899 if (NULL != route_list[route_id]->fcontroller)
900 GNUNET_TESTBED_controller_stop (route_list[route_id]->fcontroller);
901 GNUNET_free (route_list[route_id]);
903 GNUNET_free_non_null (route_list);
904 GNUNET_free_non_null (master_context);
909 * Callback for client disconnect
912 * @param client the client which has disconnected
915 client_disconnect_cb (void *cls, struct GNUNET_SERVER_Client *client)
917 if (NULL == master_context)
919 if (client == master_context->client)
921 LOG (GNUNET_ERROR_TYPE_DEBUG, "Master client disconnected\n");
922 GNUNET_SERVER_client_drop (client);
923 /* should not be needed as we're terminated by failure to read
924 from stdin, but if stdin fails for some reason, this shouldn't
925 hurt for now --- might need to revise this later if we ever
926 decide that master connections might be temporarily down
928 GNUNET_SCHEDULER_shutdown ();
937 * @param server the initialized server
938 * @param cfg configuration to use
941 testbed_run (void *cls,
942 struct GNUNET_SERVER_Handle *server,
943 const struct GNUNET_CONFIGURATION_Handle *cfg)
945 static const struct GNUNET_SERVER_MessageHandler message_handlers[] =
947 {&handle_init, NULL, GNUNET_MESSAGE_TYPE_TESTBED_INIT,
948 sizeof (struct GNUNET_TESTBED_InitMessage)},
949 {&handle_add_host, NULL, GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST, 0},
950 {&handle_configure_shared_service, NULL,
951 GNUNET_MESSAGE_TYPE_TESTBED_SERVICESHARE, 0},
952 {&handle_link_controllers, NULL,
953 GNUNET_MESSAGE_TYPE_TESTBED_LCONTROLLERS, 0},
957 GNUNET_SERVER_add_handlers (server,
959 GNUNET_SERVER_disconnect_notify (server,
960 &client_disconnect_cb,
962 ss_map = GNUNET_CONTAINER_multihashmap_create (5);
963 fh = GNUNET_DISK_get_handle_from_native (stdin);
966 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
971 GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
979 * The starting point of execution
981 int main (int argc, char *const *argv)
985 GNUNET_SERVICE_run (argc,
988 GNUNET_SERVICE_OPTION_NONE,