diff options
author | Christian Grothoff <christian@grothoff.org> | 2011-12-07 14:53:57 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2011-12-07 14:53:57 +0000 |
commit | 360a11e64931f3c0430f4b3dc46a8d3745bb0a10 (patch) | |
tree | c99d6d2092ee180eb6e755569e9329e3925031a9 /src/arm | |
parent | a07507e69721a1ee257ed758ce1561a4391660c7 (diff) | |
download | gnunet-360a11e64931f3c0430f4b3dc46a8d3745bb0a10.tar.gz gnunet-360a11e64931f3c0430f4b3dc46a8d3745bb0a10.zip |
-moving interceptor.c code into main arm file
Diffstat (limited to 'src/arm')
-rw-r--r-- | src/arm/Makefile.am | 3 | ||||
-rw-r--r-- | src/arm/gnunet-service-arm.c | 621 | ||||
-rw-r--r-- | src/arm/gnunet-service-arm.h | 55 | ||||
-rw-r--r-- | src/arm/gnunet-service-arm_interceptor.c | 408 |
4 files changed, 492 insertions, 595 deletions
diff --git a/src/arm/Makefile.am b/src/arm/Makefile.am index 9ed8bbe15..7d96ba594 100644 --- a/src/arm/Makefile.am +++ b/src/arm/Makefile.am | |||
@@ -41,8 +41,7 @@ gnunet_arm_DEPENDENCIES = \ | |||
41 | libgnunetarm.la | 41 | libgnunetarm.la |
42 | 42 | ||
43 | gnunet_service_arm_SOURCES = \ | 43 | gnunet_service_arm_SOURCES = \ |
44 | gnunet-service-arm.c gnunet-service-arm.h \ | 44 | gnunet-service-arm.c |
45 | gnunet-service-arm_interceptor.c | ||
46 | gnunet_service_arm_LDADD = \ | 45 | gnunet_service_arm_LDADD = \ |
47 | $(top_builddir)/src/util/libgnunetutil.la \ | 46 | $(top_builddir)/src/util/libgnunetutil.la \ |
48 | $(GN_LIBINTL) | 47 | $(GN_LIBINTL) |
diff --git a/src/arm/gnunet-service-arm.c b/src/arm/gnunet-service-arm.c index d99020d84..74bbd76c2 100644 --- a/src/arm/gnunet-service-arm.c +++ b/src/arm/gnunet-service-arm.c | |||
@@ -35,7 +35,6 @@ | |||
35 | #include "platform.h" | 35 | #include "platform.h" |
36 | #include "gnunet_util_lib.h" | 36 | #include "gnunet_util_lib.h" |
37 | #include "gnunet_protocols.h" | 37 | #include "gnunet_protocols.h" |
38 | #include "gnunet-service-arm.h" | ||
39 | #include "arm.h" | 38 | #include "arm.h" |
40 | 39 | ||
41 | 40 | ||
@@ -150,6 +149,67 @@ static GNUNET_SCHEDULER_TaskIdentifier child_death_task; | |||
150 | */ | 149 | */ |
151 | static GNUNET_SCHEDULER_TaskIdentifier child_restart_task; | 150 | static GNUNET_SCHEDULER_TaskIdentifier child_restart_task; |
152 | 151 | ||
152 | /** | ||
153 | * | ||
154 | */ | ||
155 | struct ServiceListeningInfo | ||
156 | { | ||
157 | /** | ||
158 | * This is a linked list. | ||
159 | */ | ||
160 | struct ServiceListeningInfo *next; | ||
161 | |||
162 | /** | ||
163 | * This is a linked list. | ||
164 | */ | ||
165 | struct ServiceListeningInfo *prev; | ||
166 | |||
167 | /** | ||
168 | * Name of the service being forwarded. | ||
169 | */ | ||
170 | char *serviceName; | ||
171 | |||
172 | /** | ||
173 | * | ||
174 | */ | ||
175 | struct sockaddr *service_addr; | ||
176 | |||
177 | /** | ||
178 | * | ||
179 | */ | ||
180 | socklen_t service_addr_len; | ||
181 | |||
182 | /** | ||
183 | * Our listening socket. | ||
184 | */ | ||
185 | struct GNUNET_NETWORK_Handle *listeningSocket; | ||
186 | |||
187 | /** | ||
188 | * Task doing the accepting. | ||
189 | */ | ||
190 | GNUNET_SCHEDULER_TaskIdentifier acceptTask; | ||
191 | }; | ||
192 | |||
193 | |||
194 | /** | ||
195 | * Array with the names of the services started by default. | ||
196 | */ | ||
197 | static char **defaultServicesList; | ||
198 | |||
199 | /** | ||
200 | * Size of the defaultServicesList array. | ||
201 | */ | ||
202 | static unsigned int numDefaultServices; | ||
203 | |||
204 | /** | ||
205 | * | ||
206 | */ | ||
207 | static struct ServiceListeningInfo *serviceListeningInfoList_head; | ||
208 | |||
209 | /** | ||
210 | * | ||
211 | */ | ||
212 | static struct ServiceListeningInfo *serviceListeningInfoList_tail; | ||
153 | 213 | ||
154 | 214 | ||
155 | /** | 215 | /** |
@@ -181,36 +241,181 @@ static int in_shutdown; | |||
181 | static struct GNUNET_SERVER_Handle *server; | 241 | static struct GNUNET_SERVER_Handle *server; |
182 | 242 | ||
183 | 243 | ||
244 | #include "do_start_process.c" | ||
245 | |||
246 | |||
184 | /** | 247 | /** |
185 | * If the configuration file changes, restart tasks that depended on that | 248 | * Actually start the process for the given service. |
186 | * option. | ||
187 | * | 249 | * |
188 | * @param cls closure, NULL if we need to self-restart | 250 | * @param sl identifies service to start |
189 | * @param tc context | 251 | * @param lsocks -1 terminated list of listen sockets to pass (systemd style), or NULL |
190 | */ | 252 | */ |
191 | static void | 253 | static void |
192 | config_change_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | 254 | start_process (struct ServiceList *sl, const SOCKTYPE *lsocks) |
193 | { | 255 | { |
194 | struct ServiceList *pos; | 256 | char *loprefix; |
195 | struct stat sbuf; | 257 | char *options; |
258 | char *optpos; | ||
259 | char *optend; | ||
260 | const char *next; | ||
261 | int use_debug; | ||
262 | char b; | ||
263 | char *val; | ||
196 | 264 | ||
197 | pos = running_head; | 265 | /* start service */ |
198 | while (pos != NULL) | 266 | if (GNUNET_OK != |
267 | GNUNET_CONFIGURATION_get_value_string (cfg, sl->name, "PREFIX", | ||
268 | &loprefix)) | ||
269 | loprefix = GNUNET_strdup (prefix_command); | ||
270 | if (GNUNET_OK != | ||
271 | GNUNET_CONFIGURATION_get_value_string (cfg, sl->name, "OPTIONS", | ||
272 | &options)) | ||
199 | { | 273 | { |
200 | /* FIXME: this test for config change may be a bit too coarse grained */ | 274 | options = GNUNET_strdup (final_option); |
201 | if ((0 == STAT (pos->config, &sbuf)) && (pos->mtime < sbuf.st_mtime) && | 275 | if (NULL == strstr (options, "%")) |
202 | (pos->proc != NULL)) | ||
203 | { | 276 | { |
204 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | 277 | /* replace '{}' with service name */ |
205 | _ | 278 | while (NULL != (optpos = strstr (options, "{}"))) |
206 | ("Restarting service `%s' due to configuration file change.\n")); | 279 | { |
207 | if (0 != GNUNET_OS_process_kill (pos->proc, SIGTERM)) | 280 | optpos[0] = '%'; |
208 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); | 281 | optpos[1] = 's'; |
209 | else | 282 | GNUNET_asprintf (&optpos, options, sl->name); |
210 | pos->backoff = GNUNET_TIME_UNIT_MILLISECONDS; | 283 | GNUNET_free (options); |
284 | options = optpos; | ||
285 | } | ||
286 | /* replace '$PATH' with value associated with "PATH" */ | ||
287 | while (NULL != (optpos = strstr (options, "$"))) | ||
288 | { | ||
289 | optend = optpos + 1; | ||
290 | while (isupper ((unsigned char) *optend)) | ||
291 | optend++; | ||
292 | b = *optend; | ||
293 | if ('\0' == b) | ||
294 | next = ""; | ||
295 | else | ||
296 | next = optend + 1; | ||
297 | *optend = '\0'; | ||
298 | if (GNUNET_OK != | ||
299 | GNUNET_CONFIGURATION_get_value_string (cfg, "PATHS", optpos + 1, | ||
300 | &val)) | ||
301 | val = GNUNET_strdup (""); | ||
302 | *optpos = '\0'; | ||
303 | GNUNET_asprintf (&optpos, "%s%s%c%s", options, val, b, next); | ||
304 | GNUNET_free (options); | ||
305 | GNUNET_free (val); | ||
306 | options = optpos; | ||
307 | } | ||
211 | } | 308 | } |
212 | pos = pos->next; | ||
213 | } | 309 | } |
310 | use_debug = GNUNET_CONFIGURATION_get_value_yesno (cfg, sl->name, "DEBUG"); | ||
311 | |||
312 | #if DEBUG_ARM | ||
313 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
314 | "Starting service `%s' using binary `%s' and configuration `%s'\n", | ||
315 | sl->name, sl->binary, sl->config); | ||
316 | #endif | ||
317 | if (GNUNET_YES == use_debug) | ||
318 | sl->proc = | ||
319 | do_start_process (lsocks, loprefix, sl->binary, "-c", sl->config, "-L", | ||
320 | "DEBUG", options, NULL); | ||
321 | else | ||
322 | sl->proc = | ||
323 | do_start_process (lsocks, loprefix, sl->binary, "-c", sl->config, | ||
324 | options, NULL); | ||
325 | if (sl->proc == NULL) | ||
326 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to start service `%s'\n"), | ||
327 | sl->name); | ||
328 | else | ||
329 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Starting service `%s'\n"), sl->name); | ||
330 | GNUNET_free (loprefix); | ||
331 | GNUNET_free (options); | ||
332 | } | ||
333 | |||
334 | |||
335 | /** | ||
336 | * Put the default services represented by a space separated string into an array of strings | ||
337 | * | ||
338 | * @param services space separated string of default services | ||
339 | */ | ||
340 | static void | ||
341 | addDefaultServicesToList (const char *services) | ||
342 | { | ||
343 | unsigned int i; | ||
344 | const char *token; | ||
345 | char *s; | ||
346 | |||
347 | if (strlen (services) == 0) | ||
348 | return; | ||
349 | s = GNUNET_strdup (services); | ||
350 | token = strtok (s, " "); | ||
351 | while (NULL != token) | ||
352 | { | ||
353 | numDefaultServices++; | ||
354 | token = strtok (NULL, " "); | ||
355 | } | ||
356 | GNUNET_free (s); | ||
357 | |||
358 | defaultServicesList = GNUNET_malloc (numDefaultServices * sizeof (char *)); | ||
359 | i = 0; | ||
360 | s = GNUNET_strdup (services); | ||
361 | token = strtok (s, " "); | ||
362 | while (NULL != token) | ||
363 | { | ||
364 | defaultServicesList[i++] = GNUNET_strdup (token); | ||
365 | token = strtok (NULL, " "); | ||
366 | } | ||
367 | GNUNET_free (s); | ||
368 | GNUNET_assert (i == numDefaultServices); | ||
369 | } | ||
370 | |||
371 | |||
372 | /** | ||
373 | * Checks whether the serviceName is in the list of default services | ||
374 | * | ||
375 | * @param serviceName string to check its existance in the list | ||
376 | * @return GNUNET_YES if the service is started by default | ||
377 | */ | ||
378 | static int | ||
379 | isInDefaultList (const char *serviceName) | ||
380 | { | ||
381 | unsigned int i; | ||
382 | |||
383 | for (i = 0; i < numDefaultServices; i++) | ||
384 | if (strcmp (serviceName, defaultServicesList[i]) == 0) | ||
385 | return GNUNET_YES; | ||
386 | return GNUNET_NO; | ||
387 | } | ||
388 | |||
389 | |||
390 | /** | ||
391 | * | ||
392 | */ | ||
393 | static int | ||
394 | stop_listening (const char *serviceName) | ||
395 | { | ||
396 | struct ServiceListeningInfo *pos; | ||
397 | struct ServiceListeningInfo *next; | ||
398 | int ret; | ||
399 | |||
400 | ret = GNUNET_NO; | ||
401 | next = serviceListeningInfoList_head; | ||
402 | while (NULL != (pos = next)) | ||
403 | { | ||
404 | next = pos->next; | ||
405 | if ((serviceName != NULL) && (strcmp (pos->serviceName, serviceName) != 0)) | ||
406 | continue; | ||
407 | if (pos->acceptTask != GNUNET_SCHEDULER_NO_TASK) | ||
408 | GNUNET_SCHEDULER_cancel (pos->acceptTask); | ||
409 | GNUNET_break (GNUNET_OK == | ||
410 | GNUNET_NETWORK_socket_close (pos->listeningSocket)); | ||
411 | GNUNET_CONTAINER_DLL_remove (serviceListeningInfoList_head, | ||
412 | serviceListeningInfoList_tail, pos); | ||
413 | GNUNET_free (pos->serviceName); | ||
414 | GNUNET_free (pos->service_addr); | ||
415 | GNUNET_free (pos); | ||
416 | ret = GNUNET_OK; | ||
417 | } | ||
418 | return ret; | ||
214 | } | 419 | } |
215 | 420 | ||
216 | 421 | ||
@@ -306,113 +511,6 @@ find_service (const char *name) | |||
306 | 511 | ||
307 | 512 | ||
308 | /** | 513 | /** |
309 | * Remove and free an entry in the service list. | ||
310 | * | ||
311 | * @param pos entry to free | ||
312 | */ | ||
313 | static void | ||
314 | free_service (struct ServiceList *pos) | ||
315 | { | ||
316 | GNUNET_CONTAINER_DLL_remove (running_head, running_tail, pos); | ||
317 | GNUNET_free_non_null (pos->config); | ||
318 | GNUNET_free_non_null (pos->binary); | ||
319 | GNUNET_free (pos->name); | ||
320 | GNUNET_free (pos); | ||
321 | } | ||
322 | |||
323 | |||
324 | #include "do_start_process.c" | ||
325 | |||
326 | |||
327 | /** | ||
328 | * Actually start the process for the given service. | ||
329 | * | ||
330 | * @param sl identifies service to start | ||
331 | * @param lsocks -1 terminated list of listen sockets to pass (systemd style), or NULL | ||
332 | */ | ||
333 | static void | ||
334 | start_process (struct ServiceList *sl, const SOCKTYPE *lsocks) | ||
335 | { | ||
336 | char *loprefix; | ||
337 | char *options; | ||
338 | char *optpos; | ||
339 | char *optend; | ||
340 | const char *next; | ||
341 | int use_debug; | ||
342 | char b; | ||
343 | char *val; | ||
344 | |||
345 | /* start service */ | ||
346 | if (GNUNET_OK != | ||
347 | GNUNET_CONFIGURATION_get_value_string (cfg, sl->name, "PREFIX", | ||
348 | &loprefix)) | ||
349 | loprefix = GNUNET_strdup (prefix_command); | ||
350 | if (GNUNET_OK != | ||
351 | GNUNET_CONFIGURATION_get_value_string (cfg, sl->name, "OPTIONS", | ||
352 | &options)) | ||
353 | { | ||
354 | options = GNUNET_strdup (final_option); | ||
355 | if (NULL == strstr (options, "%")) | ||
356 | { | ||
357 | /* replace '{}' with service name */ | ||
358 | while (NULL != (optpos = strstr (options, "{}"))) | ||
359 | { | ||
360 | optpos[0] = '%'; | ||
361 | optpos[1] = 's'; | ||
362 | GNUNET_asprintf (&optpos, options, sl->name); | ||
363 | GNUNET_free (options); | ||
364 | options = optpos; | ||
365 | } | ||
366 | /* replace '$PATH' with value associated with "PATH" */ | ||
367 | while (NULL != (optpos = strstr (options, "$"))) | ||
368 | { | ||
369 | optend = optpos + 1; | ||
370 | while (isupper ((unsigned char) *optend)) | ||
371 | optend++; | ||
372 | b = *optend; | ||
373 | if ('\0' == b) | ||
374 | next = ""; | ||
375 | else | ||
376 | next = optend + 1; | ||
377 | *optend = '\0'; | ||
378 | if (GNUNET_OK != | ||
379 | GNUNET_CONFIGURATION_get_value_string (cfg, "PATHS", optpos + 1, | ||
380 | &val)) | ||
381 | val = GNUNET_strdup (""); | ||
382 | *optpos = '\0'; | ||
383 | GNUNET_asprintf (&optpos, "%s%s%c%s", options, val, b, next); | ||
384 | GNUNET_free (options); | ||
385 | GNUNET_free (val); | ||
386 | options = optpos; | ||
387 | } | ||
388 | } | ||
389 | } | ||
390 | use_debug = GNUNET_CONFIGURATION_get_value_yesno (cfg, sl->name, "DEBUG"); | ||
391 | |||
392 | #if DEBUG_ARM | ||
393 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
394 | "Starting service `%s' using binary `%s' and configuration `%s'\n", | ||
395 | sl->name, sl->binary, sl->config); | ||
396 | #endif | ||
397 | if (GNUNET_YES == use_debug) | ||
398 | sl->proc = | ||
399 | do_start_process (lsocks, loprefix, sl->binary, "-c", sl->config, "-L", | ||
400 | "DEBUG", options, NULL); | ||
401 | else | ||
402 | sl->proc = | ||
403 | do_start_process (lsocks, loprefix, sl->binary, "-c", sl->config, | ||
404 | options, NULL); | ||
405 | if (sl->proc == NULL) | ||
406 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to start service `%s'\n"), | ||
407 | sl->name); | ||
408 | else | ||
409 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Starting service `%s'\n"), sl->name); | ||
410 | GNUNET_free (loprefix); | ||
411 | GNUNET_free (options); | ||
412 | } | ||
413 | |||
414 | |||
415 | /** | ||
416 | * Start the specified service. | 514 | * Start the specified service. |
417 | * | 515 | * |
418 | * @param client who is asking for this | 516 | * @param client who is asking for this |
@@ -420,7 +518,7 @@ start_process (struct ServiceList *sl, const SOCKTYPE *lsocks) | |||
420 | * @param lsocks -1 terminated list of listen sockets to pass (systemd style), or NULL | 518 | * @param lsocks -1 terminated list of listen sockets to pass (systemd style), or NULL |
421 | * @return GNUNET_OK on success, GNUNET_SYSERR on error | 519 | * @return GNUNET_OK on success, GNUNET_SYSERR on error |
422 | */ | 520 | */ |
423 | int | 521 | static int |
424 | start_service (struct GNUNET_SERVER_Client *client, const char *servicename, | 522 | start_service (struct GNUNET_SERVER_Client *client, const char *servicename, |
425 | const SOCKTYPE *lsocks) | 523 | const SOCKTYPE *lsocks) |
426 | { | 524 | { |
@@ -485,6 +583,269 @@ start_service (struct GNUNET_SERVER_Client *client, const char *servicename, | |||
485 | 583 | ||
486 | 584 | ||
487 | /** | 585 | /** |
586 | * First connection has come to the listening socket associated with the service, | ||
587 | * create the service in order to relay the incoming connection to it | ||
588 | * | ||
589 | * @param cls callback data, struct ServiceListeningInfo describing a listen socket | ||
590 | * @param tc context | ||
591 | */ | ||
592 | static void | ||
593 | acceptConnection (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
594 | { | ||
595 | struct ServiceListeningInfo *sli = cls; | ||
596 | struct ServiceListeningInfo *pos; | ||
597 | struct ServiceListeningInfo *next; | ||
598 | SOCKTYPE *lsocks; | ||
599 | unsigned int ls; | ||
600 | |||
601 | sli->acceptTask = GNUNET_SCHEDULER_NO_TASK; | ||
602 | if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason)) | ||
603 | return; | ||
604 | GNUNET_CONTAINER_DLL_remove (serviceListeningInfoList_head, | ||
605 | serviceListeningInfoList_tail, sli); | ||
606 | lsocks = NULL; | ||
607 | ls = 0; | ||
608 | next = serviceListeningInfoList_head; | ||
609 | while (NULL != (pos = next)) | ||
610 | { | ||
611 | next = pos->next; | ||
612 | if (0 == strcmp (pos->serviceName, sli->serviceName)) | ||
613 | { | ||
614 | GNUNET_array_append (lsocks, ls, | ||
615 | GNUNET_NETWORK_get_fd (pos->listeningSocket)); | ||
616 | GNUNET_free (pos->listeningSocket); /* deliberately no closing! */ | ||
617 | GNUNET_free (pos->service_addr); | ||
618 | GNUNET_free (pos->serviceName); | ||
619 | GNUNET_SCHEDULER_cancel (pos->acceptTask); | ||
620 | GNUNET_CONTAINER_DLL_remove (serviceListeningInfoList_head, | ||
621 | serviceListeningInfoList_tail, pos); | ||
622 | GNUNET_free (pos); | ||
623 | } | ||
624 | } | ||
625 | GNUNET_array_append (lsocks, ls, | ||
626 | GNUNET_NETWORK_get_fd (sli->listeningSocket)); | ||
627 | GNUNET_free (sli->listeningSocket); /* deliberately no closing! */ | ||
628 | GNUNET_free (sli->service_addr); | ||
629 | #if WINDOWS | ||
630 | GNUNET_array_append (lsocks, ls, INVALID_SOCKET); | ||
631 | #else | ||
632 | GNUNET_array_append (lsocks, ls, -1); | ||
633 | #endif | ||
634 | start_service (NULL, sli->serviceName, lsocks); | ||
635 | ls = 0; | ||
636 | while (lsocks[ls] != -1) | ||
637 | #if WINDOWS | ||
638 | GNUNET_break (0 == closesocket (lsocks[ls++])); | ||
639 | #else | ||
640 | GNUNET_break (0 == close (lsocks[ls++])); | ||
641 | #endif | ||
642 | GNUNET_array_grow (lsocks, ls, 0); | ||
643 | GNUNET_free (sli->serviceName); | ||
644 | GNUNET_free (sli); | ||
645 | } | ||
646 | |||
647 | |||
648 | /** | ||
649 | * Creating a listening socket for each of the service's addresses and | ||
650 | * wait for the first incoming connection to it | ||
651 | * | ||
652 | * @param sa address associated with the service | ||
653 | * @param addr_len length of sa | ||
654 | * @param serviceName the name of the service in question | ||
655 | */ | ||
656 | static void | ||
657 | createListeningSocket (struct sockaddr *sa, socklen_t addr_len, | ||
658 | const char *serviceName) | ||
659 | { | ||
660 | const static int on = 1; | ||
661 | struct GNUNET_NETWORK_Handle *sock; | ||
662 | struct ServiceListeningInfo *serviceListeningInfo; | ||
663 | |||
664 | switch (sa->sa_family) | ||
665 | { | ||
666 | case AF_INET: | ||
667 | sock = GNUNET_NETWORK_socket_create (PF_INET, SOCK_STREAM, 0); | ||
668 | break; | ||
669 | case AF_INET6: | ||
670 | sock = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0); | ||
671 | break; | ||
672 | case AF_UNIX: | ||
673 | if (strcmp (GNUNET_a2s (sa, addr_len), "@") == 0) /* Do not bind to blank UNIX path! */ | ||
674 | return; | ||
675 | sock = GNUNET_NETWORK_socket_create (PF_UNIX, SOCK_STREAM, 0); | ||
676 | break; | ||
677 | default: | ||
678 | GNUNET_break (0); | ||
679 | sock = NULL; | ||
680 | errno = EAFNOSUPPORT; | ||
681 | break; | ||
682 | } | ||
683 | if (NULL == sock) | ||
684 | { | ||
685 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
686 | _("Unable to create socket for service `%s': %s\n"), | ||
687 | serviceName, STRERROR (errno)); | ||
688 | GNUNET_free (sa); | ||
689 | return; | ||
690 | } | ||
691 | if (GNUNET_NETWORK_socket_setsockopt | ||
692 | (sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) != GNUNET_OK) | ||
693 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
694 | "setsockopt"); | ||
695 | #ifdef IPV6_V6ONLY | ||
696 | if ((sa->sa_family == AF_INET6) && | ||
697 | (GNUNET_NETWORK_socket_setsockopt | ||
698 | (sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof (on)) != GNUNET_OK)) | ||
699 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
700 | "setsockopt"); | ||
701 | #endif | ||
702 | |||
703 | if (GNUNET_NETWORK_socket_bind (sock, (const struct sockaddr *) sa, addr_len) | ||
704 | != GNUNET_OK) | ||
705 | { | ||
706 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
707 | _ | ||
708 | ("Unable to bind listening socket for service `%s' to address `%s': %s\n"), | ||
709 | serviceName, GNUNET_a2s (sa, addr_len), STRERROR (errno)); | ||
710 | GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock)); | ||
711 | GNUNET_free (sa); | ||
712 | return; | ||
713 | } | ||
714 | if (GNUNET_NETWORK_socket_listen (sock, 5) != GNUNET_OK) | ||
715 | { | ||
716 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "listen"); | ||
717 | GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock)); | ||
718 | GNUNET_free (sa); | ||
719 | return; | ||
720 | } | ||
721 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
722 | _("ARM now monitors connections to service `%s' at `%s'\n"), | ||
723 | serviceName, GNUNET_a2s (sa, addr_len)); | ||
724 | serviceListeningInfo = GNUNET_malloc (sizeof (struct ServiceListeningInfo)); | ||
725 | serviceListeningInfo->serviceName = GNUNET_strdup (serviceName); | ||
726 | serviceListeningInfo->service_addr = sa; | ||
727 | serviceListeningInfo->service_addr_len = addr_len; | ||
728 | serviceListeningInfo->listeningSocket = sock; | ||
729 | serviceListeningInfo->acceptTask = | ||
730 | GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, sock, | ||
731 | &acceptConnection, serviceListeningInfo); | ||
732 | GNUNET_CONTAINER_DLL_insert (serviceListeningInfoList_head, | ||
733 | serviceListeningInfoList_tail, | ||
734 | serviceListeningInfo); | ||
735 | } | ||
736 | |||
737 | |||
738 | /** | ||
739 | * Callback function, checks whether the current tokens are representing a service, | ||
740 | * gets its addresses and create listening socket for it. | ||
741 | * | ||
742 | * @param cls callback data, not used | ||
743 | * @param section configuration section | ||
744 | * @param option configuration option | ||
745 | * @param value the option's value | ||
746 | */ | ||
747 | static void | ||
748 | checkPortNumberCB (void *cls, const char *section, const char *option, | ||
749 | const char *value) | ||
750 | { | ||
751 | struct sockaddr **addrs; | ||
752 | socklen_t *addr_lens; | ||
753 | int ret; | ||
754 | unsigned int i; | ||
755 | |||
756 | if ((strcasecmp (section, "arm") == 0) || | ||
757 | (strcasecmp (option, "AUTOSTART") != 0) || | ||
758 | (strcasecmp (value, "YES") != 0) || | ||
759 | (isInDefaultList (section) == GNUNET_YES)) | ||
760 | return; | ||
761 | if (0 >= | ||
762 | (ret = | ||
763 | GNUNET_SERVICE_get_server_addresses (section, cfg, &addrs, &addr_lens))) | ||
764 | return; | ||
765 | /* this will free (or capture) addrs[i] */ | ||
766 | for (i = 0; i < ret; i++) | ||
767 | createListeningSocket (addrs[i], addr_lens[i], section); | ||
768 | GNUNET_free (addrs); | ||
769 | GNUNET_free (addr_lens); | ||
770 | } | ||
771 | |||
772 | |||
773 | /** | ||
774 | * Entry point to the Service Manager | ||
775 | * | ||
776 | * @param configurationHandle configuration to use to get services | ||
777 | */ | ||
778 | static void | ||
779 | prepare_services (const struct GNUNET_CONFIGURATION_Handle *configurationHandle) | ||
780 | { | ||
781 | char *defaultServicesString; | ||
782 | |||
783 | cfg = configurationHandle; | ||
784 | /* Split the default services into a list */ | ||
785 | if (GNUNET_OK == | ||
786 | GNUNET_CONFIGURATION_get_value_string (cfg, "arm", "DEFAULTSERVICES", | ||
787 | &defaultServicesString)) | ||
788 | { | ||
789 | addDefaultServicesToList (defaultServicesString); | ||
790 | GNUNET_free (defaultServicesString); | ||
791 | } | ||
792 | /* Spot the services from the configuration and create a listening | ||
793 | * socket for each */ | ||
794 | GNUNET_CONFIGURATION_iterate (cfg, &checkPortNumberCB, NULL); | ||
795 | } | ||
796 | |||
797 | |||
798 | |||
799 | /** | ||
800 | * If the configuration file changes, restart tasks that depended on that | ||
801 | * option. | ||
802 | * | ||
803 | * @param cls closure, NULL if we need to self-restart | ||
804 | * @param tc context | ||
805 | */ | ||
806 | static void | ||
807 | config_change_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
808 | { | ||
809 | struct ServiceList *pos; | ||
810 | struct stat sbuf; | ||
811 | |||
812 | pos = running_head; | ||
813 | while (pos != NULL) | ||
814 | { | ||
815 | /* FIXME: this test for config change may be a bit too coarse grained */ | ||
816 | if ((0 == STAT (pos->config, &sbuf)) && (pos->mtime < sbuf.st_mtime) && | ||
817 | (pos->proc != NULL)) | ||
818 | { | ||
819 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
820 | _ | ||
821 | ("Restarting service `%s' due to configuration file change.\n")); | ||
822 | if (0 != GNUNET_OS_process_kill (pos->proc, SIGTERM)) | ||
823 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); | ||
824 | else | ||
825 | pos->backoff = GNUNET_TIME_UNIT_MILLISECONDS; | ||
826 | } | ||
827 | pos = pos->next; | ||
828 | } | ||
829 | } | ||
830 | |||
831 | |||
832 | /** | ||
833 | * Remove and free an entry in the service list. | ||
834 | * | ||
835 | * @param pos entry to free | ||
836 | */ | ||
837 | static void | ||
838 | free_service (struct ServiceList *pos) | ||
839 | { | ||
840 | GNUNET_CONTAINER_DLL_remove (running_head, running_tail, pos); | ||
841 | GNUNET_free_non_null (pos->config); | ||
842 | GNUNET_free_non_null (pos->binary); | ||
843 | GNUNET_free (pos->name); | ||
844 | GNUNET_free (pos); | ||
845 | } | ||
846 | |||
847 | |||
848 | /** | ||
488 | * Stop the specified service. | 849 | * Stop the specified service. |
489 | * | 850 | * |
490 | * @param client who is asking for this | 851 | * @param client who is asking for this |
@@ -992,7 +1353,7 @@ run (void *cls, struct GNUNET_SERVER_Handle *serv, | |||
992 | } | 1353 | } |
993 | 1354 | ||
994 | /* create listening sockets for future services */ | 1355 | /* create listening sockets for future services */ |
995 | prepareServices (cfg); | 1356 | prepare_services (cfg); |
996 | 1357 | ||
997 | /* process client requests */ | 1358 | /* process client requests */ |
998 | GNUNET_SERVER_add_handlers (server, handlers); | 1359 | GNUNET_SERVER_add_handlers (server, handlers); |
diff --git a/src/arm/gnunet-service-arm.h b/src/arm/gnunet-service-arm.h deleted file mode 100644 index 8b17ec816..000000000 --- a/src/arm/gnunet-service-arm.h +++ /dev/null | |||
@@ -1,55 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2010 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 arm/gnunet-service-arm.h | ||
23 | * @brief function prototypes for gnunet_service_arm.c, and gnunet_service_manager.c | ||
24 | * @author Safey Abdel Halim | ||
25 | */ | ||
26 | |||
27 | #ifndef GNUNET_SERVICE_ARM__H | ||
28 | #define GNUNET_SERVICE_ARM__H | ||
29 | |||
30 | /** | ||
31 | * Start the specified service. | ||
32 | * | ||
33 | * @param client who is asking for this | ||
34 | * @param servicename name of the service to start | ||
35 | * @param lsocks -1 terminated list of listen sockets to pass (systemd style), or NULL | ||
36 | * @return GNUNET_OK on success | ||
37 | */ | ||
38 | int | ||
39 | start_service (struct GNUNET_SERVER_Client *client, const char *servicename, | ||
40 | const SOCKTYPE *lsocks); | ||
41 | |||
42 | /** | ||
43 | * Stop listening for connections to a service. | ||
44 | * | ||
45 | * @param serviceName name of service to stop listening for | ||
46 | * @return GNUNET_OK if we stopped to listen, GNUNET_NO if we were | ||
47 | * not listening | ||
48 | */ | ||
49 | int | ||
50 | stop_listening (const char *serviceName); | ||
51 | |||
52 | void | ||
53 | prepareServices (const struct GNUNET_CONFIGURATION_Handle *configurationHandle); | ||
54 | |||
55 | #endif | ||
diff --git a/src/arm/gnunet-service-arm_interceptor.c b/src/arm/gnunet-service-arm_interceptor.c deleted file mode 100644 index 8d312e28c..000000000 --- a/src/arm/gnunet-service-arm_interceptor.c +++ /dev/null | |||
@@ -1,408 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2009, 2010, 2011 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 | * @file arm/gnunet-service-arm_interceptor.c | ||
22 | * @brief listen to incoming connections from clients to services, | ||
23 | * start services for which incoming an incoming connection occur, | ||
24 | * and relay communication between the client and the service for | ||
25 | * that first incoming connection. | ||
26 | * | ||
27 | * @author Safey Abdel Halim | ||
28 | * @author Christian Grothoff | ||
29 | */ | ||
30 | |||
31 | #include "platform.h" | ||
32 | #include "gnunet_service_lib.h" | ||
33 | #include "gnunet_configuration_lib.h" | ||
34 | #include "gnunet_constants.h" | ||
35 | #include "gnunet_client_lib.h" | ||
36 | #include "gnunet_container_lib.h" | ||
37 | #include "gnunet-service-arm.h" | ||
38 | |||
39 | |||
40 | #define DEBUG_SERVICE_MANAGER GNUNET_EXTRA_LOGGING | ||
41 | |||
42 | /** | ||
43 | * | ||
44 | */ | ||
45 | struct ServiceListeningInfo | ||
46 | { | ||
47 | /** | ||
48 | * This is a linked list. | ||
49 | */ | ||
50 | struct ServiceListeningInfo *next; | ||
51 | |||
52 | /** | ||
53 | * This is a linked list. | ||
54 | */ | ||
55 | struct ServiceListeningInfo *prev; | ||
56 | |||
57 | /** | ||
58 | * Name of the service being forwarded. | ||
59 | */ | ||
60 | char *serviceName; | ||
61 | |||
62 | /** | ||
63 | * | ||
64 | */ | ||
65 | struct sockaddr *service_addr; | ||
66 | |||
67 | /** | ||
68 | * | ||
69 | */ | ||
70 | socklen_t service_addr_len; | ||
71 | |||
72 | /** | ||
73 | * Our listening socket. | ||
74 | */ | ||
75 | struct GNUNET_NETWORK_Handle *listeningSocket; | ||
76 | |||
77 | /** | ||
78 | * Task doing the accepting. | ||
79 | */ | ||
80 | GNUNET_SCHEDULER_TaskIdentifier acceptTask; | ||
81 | }; | ||
82 | |||
83 | |||
84 | /** | ||
85 | * Array with the names of the services started by default. | ||
86 | */ | ||
87 | static char **defaultServicesList; | ||
88 | |||
89 | /** | ||
90 | * Size of the defaultServicesList array. | ||
91 | */ | ||
92 | static unsigned int numDefaultServices; | ||
93 | |||
94 | /** | ||
95 | * | ||
96 | */ | ||
97 | static const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
98 | |||
99 | /** | ||
100 | * | ||
101 | */ | ||
102 | static struct ServiceListeningInfo *serviceListeningInfoList_head; | ||
103 | |||
104 | /** | ||
105 | * | ||
106 | */ | ||
107 | static struct ServiceListeningInfo *serviceListeningInfoList_tail; | ||
108 | |||
109 | |||
110 | /** | ||
111 | * Put the default services represented by a space separated string into an array of strings | ||
112 | * | ||
113 | * @param services space separated string of default services | ||
114 | */ | ||
115 | static void | ||
116 | addDefaultServicesToList (const char *services) | ||
117 | { | ||
118 | unsigned int i; | ||
119 | const char *token; | ||
120 | char *s; | ||
121 | |||
122 | if (strlen (services) == 0) | ||
123 | return; | ||
124 | s = GNUNET_strdup (services); | ||
125 | token = strtok (s, " "); | ||
126 | while (NULL != token) | ||
127 | { | ||
128 | numDefaultServices++; | ||
129 | token = strtok (NULL, " "); | ||
130 | } | ||
131 | GNUNET_free (s); | ||
132 | |||
133 | defaultServicesList = GNUNET_malloc (numDefaultServices * sizeof (char *)); | ||
134 | i = 0; | ||
135 | s = GNUNET_strdup (services); | ||
136 | token = strtok (s, " "); | ||
137 | while (NULL != token) | ||
138 | { | ||
139 | defaultServicesList[i++] = GNUNET_strdup (token); | ||
140 | token = strtok (NULL, " "); | ||
141 | } | ||
142 | GNUNET_free (s); | ||
143 | GNUNET_assert (i == numDefaultServices); | ||
144 | } | ||
145 | |||
146 | /** | ||
147 | * Checks whether the serviceName is in the list of default services | ||
148 | * | ||
149 | * @param serviceName string to check its existance in the list | ||
150 | * @return GNUNET_YES if the service is started by default | ||
151 | */ | ||
152 | static int | ||
153 | isInDefaultList (const char *serviceName) | ||
154 | { | ||
155 | unsigned int i; | ||
156 | |||
157 | for (i = 0; i < numDefaultServices; i++) | ||
158 | if (strcmp (serviceName, defaultServicesList[i]) == 0) | ||
159 | return GNUNET_YES; | ||
160 | return GNUNET_NO; | ||
161 | } | ||
162 | |||
163 | |||
164 | /** | ||
165 | * | ||
166 | */ | ||
167 | int | ||
168 | stop_listening (const char *serviceName) | ||
169 | { | ||
170 | struct ServiceListeningInfo *pos; | ||
171 | struct ServiceListeningInfo *next; | ||
172 | int ret; | ||
173 | |||
174 | ret = GNUNET_NO; | ||
175 | next = serviceListeningInfoList_head; | ||
176 | while (NULL != (pos = next)) | ||
177 | { | ||
178 | next = pos->next; | ||
179 | if ((serviceName != NULL) && (strcmp (pos->serviceName, serviceName) != 0)) | ||
180 | continue; | ||
181 | if (pos->acceptTask != GNUNET_SCHEDULER_NO_TASK) | ||
182 | GNUNET_SCHEDULER_cancel (pos->acceptTask); | ||
183 | GNUNET_break (GNUNET_OK == | ||
184 | GNUNET_NETWORK_socket_close (pos->listeningSocket)); | ||
185 | GNUNET_CONTAINER_DLL_remove (serviceListeningInfoList_head, | ||
186 | serviceListeningInfoList_tail, pos); | ||
187 | GNUNET_free (pos->serviceName); | ||
188 | GNUNET_free (pos->service_addr); | ||
189 | GNUNET_free (pos); | ||
190 | ret = GNUNET_OK; | ||
191 | } | ||
192 | return ret; | ||
193 | } | ||
194 | |||
195 | |||
196 | /** | ||
197 | * First connection has come to the listening socket associated with the service, | ||
198 | * create the service in order to relay the incoming connection to it | ||
199 | * | ||
200 | * @param cls callback data, struct ServiceListeningInfo describing a listen socket | ||
201 | * @param tc context | ||
202 | */ | ||
203 | static void | ||
204 | acceptConnection (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
205 | { | ||
206 | struct ServiceListeningInfo *sli = cls; | ||
207 | struct ServiceListeningInfo *pos; | ||
208 | struct ServiceListeningInfo *next; | ||
209 | SOCKTYPE *lsocks; | ||
210 | unsigned int ls; | ||
211 | |||
212 | sli->acceptTask = GNUNET_SCHEDULER_NO_TASK; | ||
213 | if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason)) | ||
214 | return; | ||
215 | GNUNET_CONTAINER_DLL_remove (serviceListeningInfoList_head, | ||
216 | serviceListeningInfoList_tail, sli); | ||
217 | lsocks = NULL; | ||
218 | ls = 0; | ||
219 | next = serviceListeningInfoList_head; | ||
220 | while (NULL != (pos = next)) | ||
221 | { | ||
222 | next = pos->next; | ||
223 | if (0 == strcmp (pos->serviceName, sli->serviceName)) | ||
224 | { | ||
225 | GNUNET_array_append (lsocks, ls, | ||
226 | GNUNET_NETWORK_get_fd (pos->listeningSocket)); | ||
227 | GNUNET_free (pos->listeningSocket); /* deliberately no closing! */ | ||
228 | GNUNET_free (pos->service_addr); | ||
229 | GNUNET_free (pos->serviceName); | ||
230 | GNUNET_SCHEDULER_cancel (pos->acceptTask); | ||
231 | GNUNET_CONTAINER_DLL_remove (serviceListeningInfoList_head, | ||
232 | serviceListeningInfoList_tail, pos); | ||
233 | GNUNET_free (pos); | ||
234 | } | ||
235 | } | ||
236 | GNUNET_array_append (lsocks, ls, | ||
237 | GNUNET_NETWORK_get_fd (sli->listeningSocket)); | ||
238 | GNUNET_free (sli->listeningSocket); /* deliberately no closing! */ | ||
239 | GNUNET_free (sli->service_addr); | ||
240 | #if WINDOWS | ||
241 | GNUNET_array_append (lsocks, ls, INVALID_SOCKET); | ||
242 | #else | ||
243 | GNUNET_array_append (lsocks, ls, -1); | ||
244 | #endif | ||
245 | start_service (NULL, sli->serviceName, lsocks); | ||
246 | ls = 0; | ||
247 | while (lsocks[ls] != -1) | ||
248 | #if WINDOWS | ||
249 | GNUNET_break (0 == closesocket (lsocks[ls++])); | ||
250 | #else | ||
251 | GNUNET_break (0 == close (lsocks[ls++])); | ||
252 | #endif | ||
253 | GNUNET_array_grow (lsocks, ls, 0); | ||
254 | GNUNET_free (sli->serviceName); | ||
255 | GNUNET_free (sli); | ||
256 | } | ||
257 | |||
258 | |||
259 | /** | ||
260 | * Creating a listening socket for each of the service's addresses and | ||
261 | * wait for the first incoming connection to it | ||
262 | * | ||
263 | * @param sa address associated with the service | ||
264 | * @param addr_len length of sa | ||
265 | * @param serviceName the name of the service in question | ||
266 | */ | ||
267 | static void | ||
268 | createListeningSocket (struct sockaddr *sa, socklen_t addr_len, | ||
269 | const char *serviceName) | ||
270 | { | ||
271 | const static int on = 1; | ||
272 | struct GNUNET_NETWORK_Handle *sock; | ||
273 | struct ServiceListeningInfo *serviceListeningInfo; | ||
274 | |||
275 | switch (sa->sa_family) | ||
276 | { | ||
277 | case AF_INET: | ||
278 | sock = GNUNET_NETWORK_socket_create (PF_INET, SOCK_STREAM, 0); | ||
279 | break; | ||
280 | case AF_INET6: | ||
281 | sock = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0); | ||
282 | break; | ||
283 | case AF_UNIX: | ||
284 | if (strcmp (GNUNET_a2s (sa, addr_len), "@") == 0) /* Do not bind to blank UNIX path! */ | ||
285 | return; | ||
286 | sock = GNUNET_NETWORK_socket_create (PF_UNIX, SOCK_STREAM, 0); | ||
287 | break; | ||
288 | default: | ||
289 | GNUNET_break (0); | ||
290 | sock = NULL; | ||
291 | errno = EAFNOSUPPORT; | ||
292 | break; | ||
293 | } | ||
294 | if (NULL == sock) | ||
295 | { | ||
296 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
297 | _("Unable to create socket for service `%s': %s\n"), | ||
298 | serviceName, STRERROR (errno)); | ||
299 | GNUNET_free (sa); | ||
300 | return; | ||
301 | } | ||
302 | if (GNUNET_NETWORK_socket_setsockopt | ||
303 | (sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) != GNUNET_OK) | ||
304 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
305 | "setsockopt"); | ||
306 | #ifdef IPV6_V6ONLY | ||
307 | if ((sa->sa_family == AF_INET6) && | ||
308 | (GNUNET_NETWORK_socket_setsockopt | ||
309 | (sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof (on)) != GNUNET_OK)) | ||
310 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
311 | "setsockopt"); | ||
312 | #endif | ||
313 | |||
314 | if (GNUNET_NETWORK_socket_bind (sock, (const struct sockaddr *) sa, addr_len) | ||
315 | != GNUNET_OK) | ||
316 | { | ||
317 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
318 | _ | ||
319 | ("Unable to bind listening socket for service `%s' to address `%s': %s\n"), | ||
320 | serviceName, GNUNET_a2s (sa, addr_len), STRERROR (errno)); | ||
321 | GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock)); | ||
322 | GNUNET_free (sa); | ||
323 | return; | ||
324 | } | ||
325 | if (GNUNET_NETWORK_socket_listen (sock, 5) != GNUNET_OK) | ||
326 | { | ||
327 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "listen"); | ||
328 | GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock)); | ||
329 | GNUNET_free (sa); | ||
330 | return; | ||
331 | } | ||
332 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
333 | _("ARM now monitors connections to service `%s' at `%s'\n"), | ||
334 | serviceName, GNUNET_a2s (sa, addr_len)); | ||
335 | serviceListeningInfo = GNUNET_malloc (sizeof (struct ServiceListeningInfo)); | ||
336 | serviceListeningInfo->serviceName = GNUNET_strdup (serviceName); | ||
337 | serviceListeningInfo->service_addr = sa; | ||
338 | serviceListeningInfo->service_addr_len = addr_len; | ||
339 | serviceListeningInfo->listeningSocket = sock; | ||
340 | serviceListeningInfo->acceptTask = | ||
341 | GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, sock, | ||
342 | &acceptConnection, serviceListeningInfo); | ||
343 | GNUNET_CONTAINER_DLL_insert (serviceListeningInfoList_head, | ||
344 | serviceListeningInfoList_tail, | ||
345 | serviceListeningInfo); | ||
346 | } | ||
347 | |||
348 | |||
349 | /** | ||
350 | * Callback function, checks whether the current tokens are representing a service, | ||
351 | * gets its addresses and create listening socket for it. | ||
352 | * | ||
353 | * @param cls callback data, not used | ||
354 | * @param section configuration section | ||
355 | * @param option configuration option | ||
356 | * @param value the option's value | ||
357 | */ | ||
358 | static void | ||
359 | checkPortNumberCB (void *cls, const char *section, const char *option, | ||
360 | const char *value) | ||
361 | { | ||
362 | struct sockaddr **addrs; | ||
363 | socklen_t *addr_lens; | ||
364 | int ret; | ||
365 | unsigned int i; | ||
366 | |||
367 | if ((strcasecmp (section, "arm") == 0) || | ||
368 | (strcasecmp (option, "AUTOSTART") != 0) || | ||
369 | (strcasecmp (value, "YES") != 0) || | ||
370 | (isInDefaultList (section) == GNUNET_YES)) | ||
371 | return; | ||
372 | if (0 >= | ||
373 | (ret = | ||
374 | GNUNET_SERVICE_get_server_addresses (section, cfg, &addrs, &addr_lens))) | ||
375 | return; | ||
376 | /* this will free (or capture) addrs[i] */ | ||
377 | for (i = 0; i < ret; i++) | ||
378 | createListeningSocket (addrs[i], addr_lens[i], section); | ||
379 | GNUNET_free (addrs); | ||
380 | GNUNET_free (addr_lens); | ||
381 | } | ||
382 | |||
383 | |||
384 | /** | ||
385 | * Entry point to the Service Manager | ||
386 | * | ||
387 | * @param configurationHandle configuration to use to get services | ||
388 | */ | ||
389 | void | ||
390 | prepareServices (const struct GNUNET_CONFIGURATION_Handle *configurationHandle) | ||
391 | { | ||
392 | char *defaultServicesString; | ||
393 | |||
394 | cfg = configurationHandle; | ||
395 | /* Split the default services into a list */ | ||
396 | if (GNUNET_OK == | ||
397 | GNUNET_CONFIGURATION_get_value_string (cfg, "arm", "DEFAULTSERVICES", | ||
398 | &defaultServicesString)) | ||
399 | { | ||
400 | addDefaultServicesToList (defaultServicesString); | ||
401 | GNUNET_free (defaultServicesString); | ||
402 | } | ||
403 | /* Spot the services from the configuration and create a listening | ||
404 | * socket for each */ | ||
405 | GNUNET_CONFIGURATION_iterate (cfg, &checkPortNumberCB, NULL); | ||
406 | } | ||
407 | |||
408 | /* end of gnunet-service-arm_interceptor.c */ | ||