-handler for INIT messages in testbed server
[oweals/gnunet.git] / src / testbed / gnunet-service-testbed.c
1 /*
2   This file is part of GNUnet.
3   (C) 2012 Christian Grothoff (and other contributing authors)
4
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.
9
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.
14
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.
19 */
20
21 /**
22  * @file testbed/gnunet-service-testbed.c
23  * @brief implementation of the TESTBED service
24  * @author Sree Harsha Totakura
25  */
26
27 #include "platform.h"
28 #include "gnunet_service_lib.h"
29 #include "gnunet_server_lib.h"
30
31 #include "testbed.h"
32
33
34 #define LOG(kind,...)                           \
35   GNUNET_log (kind, __VA_ARGS__)
36
37
38 struct Context
39 {
40   /**
41    * The client handle associated with this context
42    */
43   struct GNUNET_SERVER_Client *client;
44   
45   /**
46    * Event mask of event to be responded in this context
47    */
48   uint64_t event_mask;
49
50   /**
51    * Our host id according to this context
52    */
53   uint32_t host_id;
54 };
55
56
57 /**
58  * The master context; generated with the first INIT message
59  */
60 static struct Context *master_context;
61
62 /**
63  * The shutdown task handle
64  */
65 static GNUNET_SCHEDULER_TaskIdentifier shutdown_task_id;
66
67
68 /**
69  * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_INIT messages
70  *
71  * @param cls NULL
72  * @param client identification of the client
73  * @param message the actual message
74  */
75 static void 
76 handle_init (void *cls,
77              struct GNUNET_SERVER_Client *client,
78              const struct GNUNET_MessageHeader *message)
79 {
80   const struct GNUNET_TESTBED_Message *msg;
81
82   if (NULL != master_context)
83   {
84     GNUNET_break (0);
85     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
86     return;
87   }
88   msg = (const struct GNUNET_TESTBED_Message *) message;  
89   master_context = GNUNET_malloc (sizeof (struct Context));
90   master_context->client = client;
91   master_context->host_id = ntohl (msg->host_id);
92   master_context->event_mask = GNUNET_ntohll (msg->event_mask);
93   GNUNET_SERVER_client_keep (client);
94   LOG (GNUNET_ERROR_TYPE_DEBUG,
95        "Created master context with host ID: %u\n", master_context->host_id);
96   GNUNET_SERVER_receive_done (client, GNUNET_OK);
97 }
98
99
100 /**
101  * Task to clean up and shutdown nicely
102  *
103  * @param cls NULL
104  * @param tc the TaskContext from scheduler
105  */
106 static void
107 shutdown_task (void *cls,
108                const struct GNUNET_SCHEDULER_TaskContext *tc)
109 {
110   LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down testbed service\n");
111   GNUNET_free_non_null (master_context);
112 }
113
114
115 /**
116  * Callback for client disconnect
117  *
118  * @param cls NULL
119  * @param client the client which has disconnected
120  */
121 static void
122 client_disconnect_cb (void *cls, struct GNUNET_SERVER_Client *client)
123 {
124   if (NULL == master_context)
125     return;
126   if (client == master_context->client)
127   {
128     LOG (GNUNET_ERROR_TYPE_DEBUG, "Master client disconnected\n");
129     GNUNET_SERVER_client_drop (client);
130     GNUNET_SCHEDULER_cancel (shutdown_task_id);    
131     shutdown_task_id = 
132       GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
133   }
134 }
135
136
137 /**
138  * Testbed setup
139  *
140  * @param cls closure
141  * @param server the initialized server
142  * @param cfg configuration to use
143  */
144 static void 
145 testbed_run (void *cls,
146              struct GNUNET_SERVER_Handle *server,
147              const struct GNUNET_CONFIGURATION_Handle *cfg)
148 {
149   static const struct GNUNET_SERVER_MessageHandler message_handlers[] =
150     {
151       {&handle_init, NULL, GNUNET_MESSAGE_TYPE_TESTBED_INIT,
152        sizeof (struct GNUNET_TESTBED_Message)},
153       {NULL}
154     };
155
156   GNUNET_SERVER_add_handlers (server,
157                               message_handlers);
158   GNUNET_SERVER_disconnect_notify (server,
159                                    &client_disconnect_cb,
160                                    NULL);
161   shutdown_task_id = 
162     GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
163                                   &shutdown_task,
164                                   NULL);
165 }
166
167
168 /**
169  * The starting point of execution
170  */
171 int main (int argc, char *const *argv)
172 {
173   return
174     (GNUNET_OK ==
175      GNUNET_SERVICE_run (argc,
176                          argv,
177                          "testbed",
178                          GNUNET_SERVICE_OPTION_NONE,
179                          &testbed_run,
180                          NULL)) ? 0 : 1;
181 }