Moving regex profiler config to contrib
[oweals/gnunet.git] / src / mesh / gnunet-service-regexprofiler.c
1 /*
2      This file is part of GNUnet.
3      (C) 2010, 2011, 2012 Christian Grothoff
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 mesh/gnunet-service-regexprofiler.c
23  * @brief service that uses mesh to announce a regular expression. Used in
24  * conjunction with gnunet-regex-profiler to announce regexes on serveral peers
25  * without the need to explicitly connect to the mesh service running on the
26  * peer from within the profiler.
27  * @author Maximilian Szengel
28  */
29 #include "platform.h"
30 #include "gnunet_mesh_service.h"
31 #include "gnunet_statistics_service.h"
32
33 /**
34  * Return value from 'main'.
35  */
36 static int global_ret;
37
38 /**
39  * Configuration we use.
40  */
41 static const struct GNUNET_CONFIGURATION_Handle *cfg;
42
43 /**
44  * Handle to server.
45  */
46 static struct GNUNET_SERVER_Handle *server_handle;
47
48 /**
49  * Handle to the statistics service.
50  */
51 static struct GNUNET_STATISTICS_Handle *stats_handle;
52
53 /**
54  * Peer's mesh handle.
55  */
56 struct GNUNET_MESH_Handle *mesh_handle;
57
58 /**
59  * Peer's mesh tunnel handle.
60  */
61 struct GNUNET_MESH_Tunnel *mesh_tunnel_handle;
62
63 /**
64  * Maximal path compression length for regex announcing.
65  */
66 static unsigned long long max_path_compression;
67
68 /**
69  * Name of the file containing policies that this peer should announce. One
70  * policy per line.
71  */
72 static char * policy_filename;
73
74
75 /**
76  * Task run during shutdown.
77  *
78  * @param cls unused
79  * @param tc unused
80  */
81 static void
82 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
83 {
84   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "shutting down\n");
85
86   if (NULL != mesh_tunnel_handle)
87   {
88     GNUNET_MESH_tunnel_destroy (mesh_tunnel_handle);
89     mesh_tunnel_handle = NULL;
90   }
91
92   if (NULL != mesh_handle)
93   {
94     GNUNET_MESH_disconnect (mesh_handle);
95     mesh_handle = NULL;
96   }
97
98   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "shut down\n");
99 }
100
101
102 /**
103  * Method called whenever a peer has disconnected from the tunnel.
104  * Implementations of this callback must NOT call
105  * GNUNET_MESH_tunnel_destroy immediately, but instead schedule those
106  * to run in some other task later.  However, calling
107  * "GNUNET_MESH_notify_transmit_ready_cancel" is allowed.
108  *
109  * @param cls closure
110  * @param peer_id peer identity the tunnel stopped working with
111  */
112 static void
113 mesh_peer_disconnect_handler (void *cls,
114                               const struct GNUNET_PeerIdentity * peer_id)
115 {
116   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Mesh peer disconnect handler.\n");
117   GNUNET_STATISTICS_update (stats_handle, "# peers disconnected", 1, GNUNET_NO);
118 }
119
120
121 /**
122  * Method called whenever a peer has connected to the tunnel.
123  *
124  * @param cls closure
125  * @param peer_id peer identity the tunnel was created to, NULL on timeout
126  * @param atsi performance data for the connection
127  *
128  */
129 static void
130 mesh_peer_connect_handler (void *cls,
131                            const struct GNUNET_PeerIdentity* peer_id,
132                            const struct GNUNET_ATS_Information * atsi)
133 {
134   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Mesh peer connect handler.\n");
135   GNUNET_STATISTICS_update (stats_handle, "# peers connected", 1, GNUNET_NO);
136 }
137
138
139 /**
140  * Announce the given regular expression using Mesh and the path compression
141  * length read from config.
142  *
143  * @param regex regular expression to announce on this peer's mesh.
144  */
145 static void
146 announce_regex (const char * regex)
147 {
148   if (NULL == regex || 0 == strlen (regex))
149   {
150     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Cannot announce empty regex\n");
151     return;
152   }
153
154   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Announcing regex: %s\n", regex);
155   GNUNET_STATISTICS_update (stats_handle, "# regexes announced", 1, GNUNET_NO);
156   GNUNET_MESH_announce_regex (mesh_handle, regex, (unsigned int)max_path_compression);
157 }
158
159
160 /**
161  * Main function that will be run by the scheduler.
162  *
163  * @param cls closure
164  * @param server the initialized server
165  * @param cfg_ configuration
166  */
167 static void
168 run (void *cls,
169      struct GNUNET_SERVER_Handle *server,
170      const struct GNUNET_CONFIGURATION_Handle *cfg_)
171 {
172   char *regex;
173   char *data;
174   char *buf;
175   uint64_t filesize;
176   unsigned int offset;
177   GNUNET_MESH_ApplicationType app;
178
179   static struct GNUNET_MESH_MessageHandler handlers[] = {
180     {NULL, 0, 0}
181   };
182
183   cfg = cfg_;
184
185   if (GNUNET_OK !=
186       GNUNET_CONFIGURATION_get_value_number (cfg, "REGEXPROFILER", "MAX_PATH_COMPRESSION",
187                                              &max_path_compression))
188   {
189     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
190                 _
191                 ("%s service is lacking key configuration settings (%s).  Exiting.\n"),
192                 "regexprofiler", "max_path_compression");
193     global_ret = GNUNET_SYSERR;
194     GNUNET_SCHEDULER_shutdown ();
195     return;
196   }
197
198   if (GNUNET_OK !=
199       GNUNET_CONFIGURATION_get_value_filename (cfg, "REGEXPROFILER", "POLICY_FILE",
200                                                &policy_filename))
201   {
202     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
203                 _
204                 ("%s service is lacking key configuration settings (%s).  Exiting.\n"),
205                 "regexprofiler", "policy_file");
206     global_ret = GNUNET_SYSERR;
207     GNUNET_SCHEDULER_shutdown ();
208     return;
209   }
210
211   stats_handle = GNUNET_STATISTICS_create ("regexprofiler", cfg);
212
213   app = (GNUNET_MESH_ApplicationType)0;
214
215   mesh_tunnel_handle = GNUNET_MESH_tunnel_create (mesh_handle,
216                                                   NULL,
217                                                   &mesh_peer_connect_handler,
218                                                   &mesh_peer_disconnect_handler,
219                                                   NULL);
220
221   mesh_handle =
222     GNUNET_MESH_connect (cfg, mesh_tunnel_handle, NULL, NULL, handlers, &app);
223
224   /* Announcing regexes from policy_filename */
225   if (GNUNET_YES != GNUNET_DISK_file_test (policy_filename))
226   {
227     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
228                 "Could not find policy file %s\n", policy_filename);
229     return;
230   }
231   if (GNUNET_OK != GNUNET_DISK_file_size (policy_filename, &filesize, GNUNET_YES, GNUNET_YES))
232     filesize = 0;
233   if (0 == filesize)
234   {
235     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Policy file %s is empty.\n", policy_filename);
236     return;
237   }
238   data = GNUNET_malloc (filesize);
239   if (filesize != GNUNET_DISK_fn_read (policy_filename, data, filesize))
240   {
241     GNUNET_free (data);
242     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not read policy file %s.\n",
243                 policy_filename);
244     return;
245   }
246   buf = data;
247   offset = 0;
248   regex = NULL;
249   while (offset < (filesize - 1))
250   {
251     offset++;
252     if (((data[offset] == '\n')) && (buf != &data[offset]))
253     {
254       data[offset] = '\0';
255       regex = buf;
256       GNUNET_assert (NULL != regex);
257       announce_regex (regex);
258       buf = &data[offset + 1];
259     }
260     else if ((data[offset] == '\n') || (data[offset] == '\0'))
261           buf = &data[offset + 1];
262   }
263   GNUNET_free (data);
264
265
266   GNUNET_SERVER_suspend (server_handle);
267   /* Scheduled the task to clean up when shutdown is called */
268   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
269                                 NULL);
270 }
271
272
273 /**
274  * The main function of the regexprofiler service.
275  *
276  * @param argc number of arguments from the command line
277  * @param argv command line arguments
278  * @return 0 ok, 1 on error
279  */
280 int
281 main (int argc, char *const *argv)
282 {
283   return (GNUNET_OK ==
284           GNUNET_SERVICE_run (argc, argv, "regexprofiler",
285                               GNUNET_SERVICE_OPTION_NONE,
286                               &run, NULL)) ? global_ret : 1;
287 }
288
289 /* end of gnunet-service-regexprofiler.c */