paragraph for gnunet devs that don't know how to use the web
[oweals/gnunet.git] / src / testbed-logger / gnunet-service-testbed-logger.c
1 /*
2   This file is part of GNUnet.
3   Copyright (C) 2008--2013 GNUnet e.V.
4
5   GNUnet is free software: you can redistribute it and/or modify it
6   under the terms of the GNU Affero General Public License as published
7   by the Free Software Foundation, either version 3 of the License,
8   or (at your 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   Affero General Public License for more details.
14  
15   You should have received a copy of the GNU Affero General Public License
16   along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 /**
20  * @file testbed-logger/gnunet-service-testbed-logger.c
21  * @brief service for collecting messages and writing to a file
22  * @author Sree Harsha Totakura
23  */
24
25 #include "platform.h"
26 #include "gnunet_util_lib.h"
27
28 /**
29  * Generic logging shorthand
30  */
31 #define LOG(type, ...)                         \
32   GNUNET_log (type, __VA_ARGS__)
33
34 /**
35  * Debug logging shorthand
36  */
37 #define LOG_DEBUG(...)                          \
38   LOG (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
39
40 /**
41  * Handle for buffered writing.
42  */
43 struct GNUNET_BIO_WriteHandle *bio;
44
45 /**
46  * The number of connections we have
47  */
48 static unsigned int nconn;
49
50 /**
51  * Are we shutting down?
52  */
53 static int in_shutdown;
54
55
56 /**
57  * Check #GNUNET_MESSAGE_TYPE_TESTBED_LOGGER_MSG messages
58  *
59  * @param cls client identification of the client
60  * @param msg the actual message
61  * @return #GNUNET_OK (they are all always OK)
62  */
63 static int
64 check_log_msg (void *cls,
65                const struct GNUNET_MessageHeader *msg)
66 {
67   return GNUNET_OK;
68 }
69
70
71 /**
72  * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_LOGGER_MSG messages
73  *
74  * @param cls client identification of the client
75  * @param msg the actual message
76  */
77 static void
78 handle_log_msg (void *cls,
79                 const struct GNUNET_MessageHeader *msg)
80 {
81   struct GNUNET_SERVICE_Client *client = cls;
82   uint16_t ms;
83
84   ms = ntohs (msg->size) - sizeof (struct GNUNET_MessageHeader);
85   GNUNET_BIO_write (bio,
86                     &msg[1],
87                     ms);
88   GNUNET_SERVICE_client_continue (client);
89 }
90
91
92 /**
93  * Task to clean up and shutdown nicely
94  *
95  * @param cls NULL
96  */
97 static void
98 shutdown_task (void *cls)
99 {
100   in_shutdown = GNUNET_YES;
101   if (0 != nconn)
102   {
103     /* Delay shutdown if there are active connections */
104     GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
105                                    NULL);
106     return;
107   }
108   GNUNET_break (GNUNET_OK ==
109                 GNUNET_BIO_write_close (bio));
110 }
111
112
113 /**
114  * Callback called when a client connects to the service.
115  *
116  * @param cls closure for the service
117  * @param c the new client that connected to the service
118  * @param mq the message queue used to send messages to the client
119  * @return @a c
120  */
121 static void *
122 client_connect_cb (void *cls,
123                    struct GNUNET_SERVICE_Client *c,
124                    struct GNUNET_MQ_Handle *mq)
125 {
126   /* FIXME: is this really what we want here? */
127   GNUNET_SERVICE_client_persist (c);
128   nconn++;
129   return c;
130 }
131
132
133 /**
134  * Callback called when a client disconnected from the service
135  *
136  * @param cls closure for the service
137  * @param c the client that disconnected
138  * @param internal_cls should be equal to @a c
139  */
140 static void
141 client_disconnect_cb (void *cls,
142                       struct GNUNET_SERVICE_Client *c,
143                       void *internal_cls)
144 {
145   nconn--;
146   if (GNUNET_YES == in_shutdown)
147     GNUNET_SCHEDULER_shutdown ();
148   GNUNET_assert (c == internal_cls);
149 }
150
151
152 /**
153  * Testbed setup
154  *
155  * @param cls closure
156  * @param cfg configuration to use
157  * @param service the initialized service
158  */
159 static void
160 logger_run (void *cls,
161             const struct GNUNET_CONFIGURATION_Handle *cfg,
162             struct GNUNET_SERVICE_Handle *service)
163 {
164   char *dir;
165   char *fn;
166   char *hname;
167   size_t hname_len;
168   pid_t pid;
169
170   if (GNUNET_OK !=
171       GNUNET_CONFIGURATION_get_value_filename (cfg,
172                                                "TESTBED-LOGGER",
173                                                "DIR",
174                                                &dir))
175   {
176     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
177                                "TESTBED-LOGGER",
178                                "DIR");
179     GNUNET_SCHEDULER_shutdown ();
180     return;
181   }
182   pid = getpid ();
183   hname_len = GNUNET_OS_get_hostname_max_length ();
184   hname = GNUNET_malloc (hname_len);
185   if (0 != gethostname (hname,
186                         hname_len))
187   {
188     LOG (GNUNET_ERROR_TYPE_ERROR,
189          "Cannot get hostname.  Exiting\n");
190     GNUNET_free (hname);
191     GNUNET_free (dir);
192     GNUNET_SCHEDULER_shutdown ();
193     return;
194   }
195   GNUNET_asprintf (&fn,
196                    "%s/%.*s_%jd.dat",
197                    dir,
198                    hname_len,
199                    hname,
200                    (intmax_t) pid);
201   GNUNET_free (hname);
202   GNUNET_free (dir);
203   if (NULL == (bio = GNUNET_BIO_write_open (fn)))
204   {
205     GNUNET_free (fn);
206     GNUNET_SCHEDULER_shutdown ();
207     return;
208   }
209   GNUNET_free (fn);
210   GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
211                                  NULL);
212   LOG_DEBUG ("TESTBED-LOGGER startup complete\n");
213 }
214
215
216 /**
217  * Define "main" method using service macro.
218  */
219 GNUNET_SERVICE_MAIN
220 ("testbed-logger",
221  GNUNET_SERVICE_OPTION_NONE,
222  &logger_run,
223  &client_connect_cb,
224  &client_disconnect_cb,
225  NULL,
226  GNUNET_MQ_hd_var_size (log_msg,
227                         GNUNET_MESSAGE_TYPE_TESTBED_LOGGER_MSG,
228                         struct GNUNET_MessageHeader,
229                         NULL),
230  GNUNET_MQ_handler_end ());
231
232
233 /* end of gnunet-service-testbed-logger.c */