- distribute peers equally among island nodes on SuperMUC
[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 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-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  * Current Transmit Handle; NULL if no notify transmit exists currently
70  */
71 static struct GNUNET_SERVER_TransmitHandle *transmit_handle;
72
73 /**
74  * The message queue head
75  */
76 static struct MessageQueue *mq_head;
77
78 /**
79  * The message queue tail
80  */
81 static struct MessageQueue *mq_tail;
82
83 /**
84  * Handle for buffered writing.
85  */
86 struct GNUNET_BIO_WriteHandle *bio;
87
88 /**
89  * The shutdown task handle
90  */
91 static GNUNET_SCHEDULER_TaskIdentifier shutdown_task_id;
92
93
94 /**
95  * Function called to notify a client about the connection begin ready to queue
96  * more data.  "buf" will be NULL and "size" zero if the connection was closed
97  * for writing in the meantime.
98  *
99  * @param cls NULL
100  * @param size number of bytes available in buf
101  * @param buf where the callee should write the message
102  * @return number of bytes written to buf
103  */
104 static size_t
105 transmit_ready_notify (void *cls, size_t size, void *buf)
106 {
107   struct MessageQueue *mq_entry;
108
109   transmit_handle = NULL;
110   mq_entry = mq_head;
111   GNUNET_assert (NULL != mq_entry);
112   if (0 == size)
113     return 0;
114   GNUNET_assert (ntohs (mq_entry->msg->size) <= size);
115   size = ntohs (mq_entry->msg->size);
116   memcpy (buf, mq_entry->msg, size);
117   GNUNET_free (mq_entry->msg);
118   GNUNET_SERVER_client_drop (mq_entry->client);
119   GNUNET_CONTAINER_DLL_remove (mq_head, mq_tail, mq_entry);
120   GNUNET_free (mq_entry);
121   mq_entry = mq_head;
122   if (NULL != mq_entry)
123     transmit_handle =
124         GNUNET_SERVER_notify_transmit_ready (mq_entry->client,
125                                              ntohs (mq_entry->msg->size),
126                                              GNUNET_TIME_UNIT_FOREVER_REL,
127                                              &transmit_ready_notify, NULL);
128   return size;
129 }
130
131
132 /**
133  * Queues a message in send queue for sending to the service
134  *
135  * @param client the client to whom the queued message has to be sent
136  * @param msg the message to queue
137  */
138 void
139 queue_message (struct GNUNET_SERVER_Client *client,
140                    struct GNUNET_MessageHeader *msg)
141 {
142   struct MessageQueue *mq_entry;
143   uint16_t type;
144   uint16_t size;
145
146   type = ntohs (msg->type);
147   size = ntohs (msg->size);
148   mq_entry = GNUNET_malloc (sizeof (struct MessageQueue));
149   mq_entry->msg = msg;
150   mq_entry->client = client;
151   GNUNET_SERVER_client_keep (client);
152   LOG_DEBUG ("Queueing message of type %u, size %u for sending\n", type,
153              ntohs (msg->size));
154   GNUNET_CONTAINER_DLL_insert_tail (mq_head, mq_tail, mq_entry);
155   if (NULL == transmit_handle)
156     transmit_handle =
157         GNUNET_SERVER_notify_transmit_ready (client, size,
158                                              GNUNET_TIME_UNIT_FOREVER_REL,
159                                              &transmit_ready_notify, NULL);
160 }
161
162
163 /**
164  * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST messages
165  *
166  * @param cls NULL
167  * @param client identification of the client
168  * @param msg the actual message
169  */
170 static void
171 handle_log_msg (void *cls, struct GNUNET_SERVER_Client *client,
172                 const struct GNUNET_MessageHeader *msg)
173 {
174   uint16_t ms;
175
176   ms = ntohs (msg->size);
177   ms -= sizeof (struct GNUNET_MessageHeader);
178   GNUNET_BIO_write (bio, &msg[1], ms);
179   GNUNET_SERVER_receive_done (client, GNUNET_OK);
180 }
181
182
183 /**
184  * Task to clean up and shutdown nicely
185  *
186  * @param cls NULL
187  * @param tc the TaskContext from scheduler
188  */
189 static void
190 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
191 {
192   struct MessageQueue *mq_entry;
193
194   shutdown_task_id = GNUNET_SCHEDULER_NO_TASK;
195   if (NULL != transmit_handle)
196     GNUNET_SERVER_notify_transmit_ready_cancel (transmit_handle);
197   while (NULL != (mq_entry = mq_head))
198   {
199     GNUNET_free (mq_entry->msg);
200     GNUNET_SERVER_client_drop (mq_entry->client);
201     GNUNET_CONTAINER_DLL_remove (mq_head, mq_tail, mq_entry);
202     GNUNET_free (mq_entry);
203   }
204   GNUNET_BIO_write_close (bio);
205 }
206
207
208 /**
209  * Testbed setup
210  *
211  * @param cls closure
212  * @param server the initialized server
213  * @param cfg configuration to use
214  */
215 static void
216 logger_run (void *cls, struct GNUNET_SERVER_Handle *server,
217              const struct GNUNET_CONFIGURATION_Handle *cfg)
218 {
219   static const struct GNUNET_SERVER_MessageHandler message_handlers[] = {
220     {&handle_log_msg, NULL, GNUNET_MESSAGE_TYPE_TESTBED_LOGGER_MSG, 0},
221     {NULL, NULL, 0, 0}
222   };
223   char *dir;
224   char *fn;
225   char *hname;
226   size_t hname_len;
227   pid_t pid;
228
229   if (GNUNET_OK !=
230       GNUNET_CONFIGURATION_get_value_filename (cfg, "TESTBED-LOGGER", "DIR",
231                                                &dir))
232   {
233     LOG (GNUNET_ERROR_TYPE_ERROR, "Not logging directory definied.  Exiting\n");    
234     GNUNET_SCHEDULER_shutdown ();
235     return;
236   }
237   pid = getpid ();
238   hname_len = GNUNET_OS_get_hostname_max_length ();
239   hname = GNUNET_malloc (hname_len);
240   if (0 != gethostname (hname, hname_len))
241   {
242     LOG (GNUNET_ERROR_TYPE_ERROR, "Cannot get hostname.  Exiting\n");
243     GNUNET_free (hname);
244     GNUNET_SCHEDULER_shutdown ();
245     return;
246   }
247   (void) GNUNET_asprintf (&fn, "%s/%.*s_%jd.dat", dir, hname_len, hname,
248                           (intmax_t) pid);
249   GNUNET_free (hname);
250   GNUNET_free (dir);
251   if (NULL == (bio = GNUNET_BIO_write_open (fn)))
252   {
253     GNUNET_free (fn);
254     GNUNET_SCHEDULER_shutdown ();
255     return;
256   }
257   GNUNET_free (fn);
258   GNUNET_SERVER_add_handlers (server, message_handlers);
259   shutdown_task_id =
260       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
261                                     &shutdown_task, NULL);
262   LOG_DEBUG ("TESTBED-LOGGER startup complete\n");
263 }
264
265
266 /**
267  * The starting point of execution
268  */
269 int
270 main (int argc, char *const *argv)
271 {
272   //sleep (15);                 /* Debugging */
273   return (GNUNET_OK ==
274           GNUNET_SERVICE_run (argc, argv, "testbed-logger", 
275                               GNUNET_SERVICE_OPTION_NONE,
276                               &logger_run, NULL)) ? 0 : 1;
277 }
278
279 /* end of gnunet-service-testbed.c */