Fix regression caused by SVN 34522
[oweals/gnunet.git] / src / testbed / gnunet-service-testbed-logger.c
1 /*
2   This file is part of GNUnet.
3   (C) 2008--2013 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 3, 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-logger.c
23  * @brief service for collecting messages and writing to a file
24  * @author Sree Harsha Totakura
25  */
26
27 #include "platform.h"
28 #include "gnunet_util_lib.h"
29
30 /**
31  * Generic logging shorthand
32  */
33 #define LOG(type, ...)                         \
34   GNUNET_log (type, __VA_ARGS__)
35
36 /**
37  * Debug logging shorthand
38  */
39 #define LOG_DEBUG(...)                          \
40   LOG (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
41
42 /**
43  * The message queue for sending messages to clients
44  */
45 struct MessageQueue
46 {
47   /**
48    * The message to be sent
49    */
50   struct GNUNET_MessageHeader *msg;
51
52   /**
53    * The client to send the message to
54    */
55   struct GNUNET_SERVER_Client *client;
56
57   /**
58    * next pointer for DLL
59    */
60   struct MessageQueue *next;
61
62   /**
63    * prev pointer for DLL
64    */
65   struct MessageQueue *prev;
66 };
67
68 /**
69  * The message queue head
70  */
71 static struct MessageQueue *mq_head;
72
73 /**
74  * The message queue tail
75  */
76 static struct MessageQueue *mq_tail;
77
78 /**
79  * Handle for buffered writing.
80  */
81 struct GNUNET_BIO_WriteHandle *bio;
82
83 /**
84  * The shutdown task handle
85  */
86 static GNUNET_SCHEDULER_TaskIdentifier shutdown_task_id;
87
88 /**
89  * The number of connections we have
90  */
91 static unsigned int nconn;
92
93 /**
94  * Are we shutting down?
95  */
96 static int in_shutdown;
97
98 /**
99  * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST messages
100  *
101  * @param cls NULL
102  * @param client identification of the client
103  * @param msg the actual message
104  */
105 static void
106 handle_log_msg (void *cls, struct GNUNET_SERVER_Client *client,
107                 const struct GNUNET_MessageHeader *msg)
108 {
109   uint16_t ms;
110
111   ms = ntohs (msg->size);
112   ms -= sizeof (struct GNUNET_MessageHeader);
113   GNUNET_BIO_write (bio, &msg[1], ms);
114   GNUNET_SERVER_receive_done (client, GNUNET_OK);
115 }
116
117
118 /**
119  * Task to clean up and shutdown nicely
120  *
121  * @param cls NULL
122  * @param tc the TaskContext from scheduler
123  */
124 static void
125 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
126 {
127   struct MessageQueue *mq_entry;
128
129   shutdown_task_id = GNUNET_SCHEDULER_NO_TASK;
130   in_shutdown = GNUNET_YES;
131   if (0 != nconn)
132   {
133     /* Delay shutdown if there are active connections */
134     shutdown_task_id = GNUNET_SCHEDULER_add_delayed
135         (GNUNET_TIME_UNIT_FOREVER_REL,
136          &shutdown_task, NULL);
137     return;
138   }
139   while (NULL != (mq_entry = mq_head))
140   {
141     GNUNET_free (mq_entry->msg);
142     GNUNET_SERVER_client_drop (mq_entry->client);
143     GNUNET_CONTAINER_DLL_remove (mq_head, mq_tail, mq_entry);
144     GNUNET_free (mq_entry);
145   }
146   GNUNET_break (GNUNET_OK == GNUNET_BIO_write_close (bio));
147 }
148
149
150 /**
151  * Functions with this signature are called whenever a client
152  * is disconnected on the network level.
153  *
154  * @param cls closure
155  * @param client identification of the client; NULL
156  *        for the last call when the server is destroyed
157  */
158 static void 
159 client_disconnected (void *cls, struct GNUNET_SERVER_Client *client)
160 {
161   if (NULL == client)
162   {
163     GNUNET_break (0 == nconn);
164     return;
165   }
166   nconn--;
167   if (GNUNET_YES != in_shutdown)
168     return;
169   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != shutdown_task_id);
170   GNUNET_SCHEDULER_cancel (shutdown_task_id);
171   shutdown_task_id = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
172 }
173
174
175 /**
176  * Functions with this signature are called whenever a client
177  * is connected on the network level.
178  *
179  * @param cls closure
180  * @param client identification of the client
181  */
182 static void
183 client_connected (void *cls, struct GNUNET_SERVER_Client *client)
184 {
185   if (NULL == client)
186   {
187     GNUNET_break (0 == nconn);
188     return;
189   }
190   GNUNET_SERVER_client_persist_ (client);
191   nconn++;
192 }
193
194
195 /**
196  * Testbed setup
197  *
198  * @param cls closure
199  * @param server the initialized server
200  * @param cfg configuration to use
201  */
202 static void
203 logger_run (void *cls, struct GNUNET_SERVER_Handle *server,
204              const struct GNUNET_CONFIGURATION_Handle *cfg)
205 {
206   static const struct GNUNET_SERVER_MessageHandler message_handlers[] = {
207     {&handle_log_msg, NULL, GNUNET_MESSAGE_TYPE_TESTBED_LOGGER_MSG, 0},
208     {NULL, NULL, 0, 0}
209   };
210   char *dir;
211   char *fn;
212   char *hname;
213   size_t hname_len;
214   pid_t pid;
215
216   if (GNUNET_OK !=
217       GNUNET_CONFIGURATION_get_value_filename (cfg, "TESTBED-LOGGER", "DIR",
218                                                &dir))
219   {
220     LOG (GNUNET_ERROR_TYPE_ERROR, "Not logging directory definied.  Exiting\n");
221     GNUNET_SCHEDULER_shutdown ();
222     return;
223   }
224   pid = getpid ();
225   hname_len = GNUNET_OS_get_hostname_max_length ();
226   hname = GNUNET_malloc (hname_len);
227   if (0 != gethostname (hname, hname_len))
228   {
229     LOG (GNUNET_ERROR_TYPE_ERROR, "Cannot get hostname.  Exiting\n");
230     GNUNET_free (hname);
231     GNUNET_free (dir);
232     GNUNET_SCHEDULER_shutdown ();
233     return;
234   }
235   (void) GNUNET_asprintf (&fn, "%s/%.*s_%jd.dat", dir, hname_len, hname,
236                           (intmax_t) pid);
237   GNUNET_free (hname);
238   GNUNET_free (dir);
239   if (NULL == (bio = GNUNET_BIO_write_open (fn)))
240   {
241     GNUNET_free (fn);
242     GNUNET_SCHEDULER_shutdown ();
243     return;
244   }
245   GNUNET_free (fn);
246   GNUNET_SERVER_add_handlers (server, message_handlers);
247   GNUNET_SERVER_connect_notify (server, &client_connected, NULL);
248   GNUNET_SERVER_disconnect_notify (server, &client_disconnected, NULL);
249   shutdown_task_id =
250       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
251                                     &shutdown_task, NULL);
252   LOG_DEBUG ("TESTBED-LOGGER startup complete\n");
253 }
254
255
256 /**
257  * The starting point of execution
258  */
259 int
260 main (int argc, char *const *argv)
261 {
262   //sleep (15);                 /* Debugging */
263   return (GNUNET_OK ==
264           GNUNET_SERVICE_run (argc, argv, "testbed-logger",
265                               GNUNET_SERVICE_OPTION_NONE,
266                               &logger_run, NULL)) ? 0 : 1;
267 }
268
269 /* end of gnunet-service-testbed.c */