handling add host
[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 #include "gnunet_testbed_service.h"
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  * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST messages
102  *
103  * @param cls NULL
104  * @param client identification of the client
105  * @param message the actual message
106  */
107 static void 
108 handle_addhost (void *cls,
109                 struct GNUNET_SERVER_Client *client,
110                 const struct GNUNET_MessageHeader *message)
111 {
112   struct GNUNET_TESTBED_Host *host;
113   const struct GNUNET_TESTBED_AddHostMessage *msg;
114   char *username;
115   char *hostname;
116   uint16_t username_length;
117   uint16_t hostname_length;
118   
119   msg = (const struct GNUNET_TESTBED_AddHostMessage *) message;
120   username_length = ntohs (msg->user_name_length);
121   username_length = (0 == username_length) ? 0 : username_length + 1;
122   username = (char *) &(msg[1]);
123   hostname = username + username_length;
124   if (ntohs (message->size) <=
125       (sizeof (struct GNUNET_TESTBED_AddHostMessage) + username_length))
126   {
127     GNUNET_break (0);
128     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
129     return;
130   }
131   hostname_length = ntohs (message->size)
132     - (sizeof (struct GNUNET_TESTBED_AddHostMessage) + username_length);
133   if (strlen (hostname) != hostname_length)
134   {
135     GNUNET_break (0);
136     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
137     return;
138   }
139   host = GNUNET_TESTBED_host_create (hostname, username, ntohs
140                                      (msg->ssh_port));
141   /* Store host in a hashmap? But the host_id will be different */
142 }
143
144 /**
145  * Task to clean up and shutdown nicely
146  *
147  * @param cls NULL
148  * @param tc the TaskContext from scheduler
149  */
150 static void
151 shutdown_task (void *cls,
152                const struct GNUNET_SCHEDULER_TaskContext *tc)
153 {
154   LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down testbed service\n");
155   GNUNET_free_non_null (master_context);
156 }
157
158
159 /**
160  * Callback for client disconnect
161  *
162  * @param cls NULL
163  * @param client the client which has disconnected
164  */
165 static void
166 client_disconnect_cb (void *cls, struct GNUNET_SERVER_Client *client)
167 {
168   if (NULL == master_context)
169     return;
170   if (client == master_context->client)
171   {
172     LOG (GNUNET_ERROR_TYPE_DEBUG, "Master client disconnected\n");
173     GNUNET_SERVER_client_drop (client);
174     GNUNET_SCHEDULER_cancel (shutdown_task_id);    
175     shutdown_task_id = 
176       GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
177   }
178 }
179
180
181 /**
182  * Testbed setup
183  *
184  * @param cls closure
185  * @param server the initialized server
186  * @param cfg configuration to use
187  */
188 static void 
189 testbed_run (void *cls,
190              struct GNUNET_SERVER_Handle *server,
191              const struct GNUNET_CONFIGURATION_Handle *cfg)
192 {
193   static const struct GNUNET_SERVER_MessageHandler message_handlers[] =
194     {
195       {&handle_init, NULL, GNUNET_MESSAGE_TYPE_TESTBED_INIT,
196        sizeof (struct GNUNET_TESTBED_Message)},
197       {&handle_addhost, NULL, GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST, 0},
198       {NULL}
199     };
200
201   GNUNET_SERVER_add_handlers (server,
202                               message_handlers);
203   GNUNET_SERVER_disconnect_notify (server,
204                                    &client_disconnect_cb,
205                                    NULL);
206   shutdown_task_id = 
207     GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
208                                   &shutdown_task,
209                                   NULL);
210 }
211
212
213 /**
214  * The starting point of execution
215  */
216 int main (int argc, char *const *argv)
217 {
218   return
219     (GNUNET_OK ==
220      GNUNET_SERVICE_run (argc,
221                          argv,
222                          "testbed",
223                          GNUNET_SERVICE_OPTION_NONE,
224                          &testbed_run,
225                          NULL)) ? 0 : 1;
226 }