2 This file is part of GNUnet.
3 (C) 2009, 2010 Christian Grothoff (and other contributing authors)
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.
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.
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.
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.
27 * @author Safey Abdel Halim
28 * @author Christian Grothoff
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"
40 #define DEBUG_SERVICE_MANAGER GNUNET_NO
42 #define BUFFER_SIZE (64 * 1024)
45 * Problem forwarding from client to service.
47 #define REASON_CLIENT_TO_SERVICE 1
50 * Problem forwarding from service to client.
52 #define REASON_SERVICE_TO_CLIENT 2
55 * Problem in both directions.
57 #define REASON_ERROR 3
59 struct ForwardedConnection;
64 struct ServiceListeningInfo
67 * This is a linked list.
69 struct ServiceListeningInfo *next;
72 * This is a linked list.
74 struct ServiceListeningInfo *prev;
77 * Name of the service being forwarded.
84 struct sockaddr *service_addr;
89 socklen_t service_addr_len;
92 * Our listening socket.
94 struct GNUNET_NETWORK_Handle *listeningSocket;
99 struct ForwardedConnection *fc;
102 * Task doing the accepting.
104 GNUNET_SCHEDULER_TaskIdentifier acceptTask;
108 * Information of the connection: client-arm-service
110 struct ForwardedConnection
115 struct GNUNET_NETWORK_Handle *armClientSocket;
120 struct GNUNET_NETWORK_Handle *armServiceSocket;
125 struct ServiceListeningInfo *listen_info;
130 char service_to_client_buffer[BUFFER_SIZE];
135 char client_to_service_buffer[BUFFER_SIZE];
140 char client_addr[32];
145 const char *client_to_service_bufferPos;
150 const char *service_to_client_bufferPos;
153 * Timeout for forwarding.
155 struct GNUNET_TIME_Absolute timeout;
158 * Current back-off value.
160 struct GNUNET_TIME_Relative back_off;
163 * Task that tries to initiate forwarding.
165 GNUNET_SCHEDULER_TaskIdentifier start_task;
170 GNUNET_SCHEDULER_TaskIdentifier client_to_service_task;
175 GNUNET_SCHEDULER_TaskIdentifier service_to_client_task;
180 ssize_t client_to_service_bufferDataLength;
185 ssize_t service_to_client_bufferDataLength;
190 socklen_t client_addr_len;
193 * Have we ever successfully written data to the service?
195 int first_write_done;
200 * Array with the names of the services started by default.
202 static char **defaultServicesList;
205 * Size of the defaultServicesList array.
207 static unsigned int numDefaultServices;
212 static const struct GNUNET_CONFIGURATION_Handle *cfg;
217 static struct ServiceListeningInfo *serviceListeningInfoList_head;
222 static struct ServiceListeningInfo *serviceListeningInfoList_tail;
226 * Put the default services represented by a space separated string into an array of strings
228 * @param services space separated string of default services
231 addDefaultServicesToList (const char *services)
237 if (strlen (services) == 0)
239 s = GNUNET_strdup (services);
240 token = strtok (s, " ");
241 while (NULL != token)
243 numDefaultServices++;
244 token = strtok (NULL, " ");
248 defaultServicesList = GNUNET_malloc (numDefaultServices * sizeof (char *));
250 s = GNUNET_strdup (services);
251 token = strtok (s, " ");
252 while (NULL != token)
254 defaultServicesList[i++] = GNUNET_strdup (token);
255 token = strtok (NULL, " ");
258 GNUNET_assert (i == numDefaultServices);
262 * Checks whether the serviceName is in the list of default services
264 * @param serviceName string to check its existance in the list
265 * @return GNUNET_YES if the service is started by default
268 isInDefaultList (const char *serviceName)
271 for (i = 0; i < numDefaultServices; i++)
272 if (strcmp (serviceName, defaultServicesList[i]) == 0)
279 * Close forwarded connection (partial or full).
281 * @param fc connection to close
282 * @param reason which direction to close
285 closeClientAndServiceSockets (struct ForwardedConnection *fc,
288 if (0 != (REASON_SERVICE_TO_CLIENT & reason))
290 #if DEBUG_SERVICE_MANAGER
291 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
292 "Stopping forwarding from service to client\n",
293 fc->listen_info->serviceName);
295 if (fc->service_to_client_task != GNUNET_SCHEDULER_NO_TASK)
297 GNUNET_SCHEDULER_cancel (fc->service_to_client_task);
298 fc->service_to_client_task = GNUNET_SCHEDULER_NO_TASK;
300 if (fc->armClientSocket != NULL)
301 GNUNET_NETWORK_socket_shutdown (fc->armClientSocket,
303 if (fc->armServiceSocket != NULL)
304 GNUNET_NETWORK_socket_shutdown (fc->armServiceSocket,
307 if (0 != (REASON_CLIENT_TO_SERVICE & reason))
309 #if DEBUG_SERVICE_MANAGER
310 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
311 "Stopping forwarding from client to service\n",
312 fc->listen_info->serviceName);
314 if (fc->client_to_service_task != GNUNET_SCHEDULER_NO_TASK)
316 GNUNET_SCHEDULER_cancel (fc->client_to_service_task);
317 fc->client_to_service_task = GNUNET_SCHEDULER_NO_TASK;
319 if (fc->armClientSocket != NULL)
320 GNUNET_NETWORK_socket_shutdown (fc->armClientSocket,
322 if (fc->armServiceSocket != NULL)
323 GNUNET_NETWORK_socket_shutdown (fc->armServiceSocket,
326 if ( (fc->client_to_service_task != GNUNET_SCHEDULER_NO_TASK) ||
327 (fc->service_to_client_task != GNUNET_SCHEDULER_NO_TASK) )
329 #if DEBUG_SERVICE_MANAGER
330 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
331 "Closing forwarding connection (done with both directions)\n");
333 if (fc->start_task != GNUNET_SCHEDULER_NO_TASK)
334 GNUNET_SCHEDULER_cancel (fc->start_task);
335 if ( (NULL != fc->armClientSocket) &&
337 GNUNET_NETWORK_socket_close (fc->armClientSocket)) )
338 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "close");
339 if ( (NULL != fc->armServiceSocket) &&
341 GNUNET_NETWORK_socket_close (fc->armServiceSocket)) )
342 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "close");
343 GNUNET_free (fc->listen_info->serviceName);
344 GNUNET_free (fc->listen_info->service_addr);
345 GNUNET_free (fc->listen_info);
351 * Read data from the client and then forward it to the service.
353 * @param cls callback data, struct ForwardedConnection for the communication between client and service
357 receiveFromClient (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
361 * Receive service messages sent by the service and forward it to client
363 * @param cls callback data, struct ForwardedConnection for the communication between client and service
364 * @param tc scheduler context
367 receiveFromService (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
374 start_forwarding (void *cls,
375 const struct GNUNET_SCHEDULER_TaskContext *tc);
380 * Forward messages sent from service to client
382 * @param cls callback data, struct ForwardedConnection for the communication between client and service
386 forwardToClient (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
388 struct ForwardedConnection *fc = cls;
389 ssize_t numberOfBytesSent;
391 fc->service_to_client_task = GNUNET_SCHEDULER_NO_TASK;
392 if (GNUNET_YES != GNUNET_NETWORK_fdset_isset (tc->write_ready,
393 fc->armClientSocket))
395 fc->service_to_client_task =
396 GNUNET_SCHEDULER_add_write_net (
397 GNUNET_TIME_UNIT_FOREVER_REL,
399 &forwardToClient, fc);
402 /* Forwarding service response to client */
404 GNUNET_NETWORK_socket_send (fc->armClientSocket,
405 fc->service_to_client_bufferPos,
406 fc->service_to_client_bufferDataLength);
407 if (numberOfBytesSent <= 0)
409 if ( (errno != EPIPE) &&
410 (errno != ECONNRESET) )
411 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
412 "Failed to forward %u bytes of data to client: %s\n",
413 fc->service_to_client_bufferDataLength,
415 closeClientAndServiceSockets (fc,
416 REASON_SERVICE_TO_CLIENT);
419 #if DEBUG_SERVICE_MANAGER
420 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
421 "Forwarded %d bytes to client\n",
424 if (numberOfBytesSent < fc->service_to_client_bufferDataLength)
426 fc->service_to_client_bufferPos += numberOfBytesSent;
427 fc->service_to_client_bufferDataLength -= numberOfBytesSent;
428 fc->service_to_client_task =
429 GNUNET_SCHEDULER_add_write_net (
430 GNUNET_TIME_UNIT_FOREVER_REL,
436 fc->service_to_client_task =
437 GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
438 fc->armServiceSocket,
445 * Receive service messages sent by the service and forward it to client
447 * @param cls callback data, struct ForwardedConnection for the communication between client and service
448 * @param tc scheduler context
451 receiveFromService (void *cls,
452 const struct GNUNET_SCHEDULER_TaskContext *tc)
454 struct ForwardedConnection *fc = cls;
455 struct GNUNET_TIME_Relative rem;
457 fc->service_to_client_task = GNUNET_SCHEDULER_NO_TASK;
458 if ( (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) &&
459 (fc->first_write_done != GNUNET_YES) )
461 closeClientAndServiceSockets (fc, REASON_ERROR);
464 if (GNUNET_YES != GNUNET_NETWORK_fdset_isset (tc->read_ready,
465 fc->armServiceSocket))
467 fc->service_to_client_task =
468 GNUNET_SCHEDULER_add_read_net (
469 GNUNET_TIME_UNIT_FOREVER_REL,
470 fc->armServiceSocket,
471 &receiveFromService, fc);
474 fc->service_to_client_bufferPos = fc->service_to_client_buffer;
475 fc->service_to_client_bufferDataLength =
476 GNUNET_NETWORK_socket_recv (fc->armServiceSocket,
477 fc->service_to_client_buffer,
479 if (fc->service_to_client_bufferDataLength <= 0)
481 #if DEBUG_SERVICE_MANAGER
482 if (fc->service_to_client_bufferDataLength == 0)
484 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
485 "Service `%s' stopped sending data.\n",
486 fc->listen_info->serviceName);
489 if (fc->first_write_done != GNUNET_YES)
491 fc->service_to_client_bufferDataLength = 0;
492 GNUNET_break (GNUNET_OK ==
493 GNUNET_NETWORK_socket_close (fc->armServiceSocket));
494 fc->armServiceSocket = NULL;
495 if ( (fc->client_to_service_bufferDataLength > 0) &&
496 (fc->client_to_service_task != GNUNET_SCHEDULER_NO_TASK) )
498 GNUNET_SCHEDULER_cancel (fc->client_to_service_task);
499 fc->client_to_service_task = GNUNET_SCHEDULER_NO_TASK;
501 fc->back_off = GNUNET_TIME_relative_multiply (fc->back_off, 2);
502 #if DEBUG_SERVICE_MANAGER
503 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
504 "Failed to connected to service `%s' at `%s', will try again in %llu ms\n",
505 fc->listen_info->serviceName,
506 GNUNET_a2s (fc->listen_info->service_addr,
507 fc->listen_info->service_addr_len),
508 (unsigned long long) GNUNET_TIME_relative_min (fc->back_off,
511 rem = GNUNET_TIME_absolute_get_remaining (fc->timeout);
512 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == fc->start_task);
514 = GNUNET_SCHEDULER_add_delayed (
515 GNUNET_TIME_relative_min (fc->back_off,
522 #if DEBUG_SERVICE_MANAGER
523 if (fc->service_to_client_bufferDataLength != 0)
524 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
525 "Error receiving from service: %s\n",
528 closeClientAndServiceSockets (fc, REASON_SERVICE_TO_CLIENT);
532 fc->first_write_done = GNUNET_YES;
533 #if DEBUG_SERVICE_MANAGER
534 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
535 "Received %d bytes for client\n",
536 fc->service_to_client_bufferDataLength);
538 fc->service_to_client_task =
539 GNUNET_SCHEDULER_add_write_net (
540 GNUNET_TIME_UNIT_FOREVER_REL,
542 &forwardToClient, fc);
547 * Forward client message to service
549 * @param cls callback data, struct ForwardedConnection for the communication between client and service
550 * @param tc scheduler context
553 forwardToService (void *cls,
554 const struct GNUNET_SCHEDULER_TaskContext *tc)
556 struct ForwardedConnection *fc = cls;
557 ssize_t numberOfBytesSent;
558 struct GNUNET_TIME_Relative rem;
560 fc->client_to_service_task = GNUNET_SCHEDULER_NO_TASK;
561 if ( (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) &&
562 (fc->first_write_done != GNUNET_YES) )
564 closeClientAndServiceSockets (fc, REASON_ERROR);
567 if (GNUNET_YES != GNUNET_NETWORK_fdset_isset (tc->write_ready,
568 fc->armServiceSocket))
570 fc->client_to_service_task =
571 GNUNET_SCHEDULER_add_write_net (
572 GNUNET_TIME_UNIT_FOREVER_REL,
573 fc->armServiceSocket,
574 &forwardToService, fc);
578 GNUNET_NETWORK_socket_send (fc->armServiceSocket,
579 fc->client_to_service_bufferPos,
580 fc->client_to_service_bufferDataLength);
581 if (numberOfBytesSent <= 0)
583 if (GNUNET_YES != fc->first_write_done)
585 GNUNET_break (GNUNET_OK ==
586 GNUNET_NETWORK_socket_close (fc->armServiceSocket));
587 fc->armServiceSocket = NULL;
588 if ( (fc->service_to_client_bufferDataLength == 0) &&
589 (fc->service_to_client_task != GNUNET_SCHEDULER_NO_TASK) )
591 GNUNET_SCHEDULER_cancel (fc->service_to_client_task);
592 fc->service_to_client_task = GNUNET_SCHEDULER_NO_TASK;
594 fc->back_off = GNUNET_TIME_relative_multiply (fc->back_off, 2);
595 #if DEBUG_SERVICE_MANAGER
596 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
597 "Failed to connect to service `%s' at `%s', will try again in %llu ms\n",
598 fc->listen_info->serviceName,
599 GNUNET_a2s (fc->listen_info->service_addr,
600 fc->listen_info->service_addr_len),
601 (unsigned long long) GNUNET_TIME_relative_min (fc->back_off,
604 rem = GNUNET_TIME_absolute_get_remaining (fc->timeout);
605 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == fc->start_task);
607 = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_min (fc->back_off,
614 if ( (errno != EPIPE) &&
615 (errno != ECONNRESET) )
616 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
617 "Failed to forward data to service: %s\n",
619 closeClientAndServiceSockets (fc,
620 REASON_CLIENT_TO_SERVICE);
624 #if DEBUG_SERVICE_MANAGER
625 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
626 "Forwarded %d bytes to service\n",
629 fc->first_write_done = GNUNET_YES;
630 if (numberOfBytesSent < fc->client_to_service_bufferDataLength)
632 fc->client_to_service_bufferPos += numberOfBytesSent;
633 fc->client_to_service_bufferDataLength -= numberOfBytesSent;
634 fc->client_to_service_task =
635 GNUNET_SCHEDULER_add_write_net (
636 GNUNET_TIME_UNIT_FOREVER_REL,
637 fc->armServiceSocket,
638 &forwardToService, fc);
641 fc->client_to_service_task =
642 GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
644 &receiveFromClient, fc);
649 * Read data from the client and then forward it to the service.
651 * @param cls callback data, struct ForwardedConnection for the communication between client and service
655 receiveFromClient (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
657 struct ForwardedConnection *fc = cls;
659 fc->client_to_service_task = GNUNET_SCHEDULER_NO_TASK;
660 if (GNUNET_YES != GNUNET_NETWORK_fdset_isset (tc->read_ready,
661 fc->armClientSocket))
663 fc->client_to_service_task =
664 GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
666 &receiveFromClient, fc);
669 fc->client_to_service_bufferPos = fc->client_to_service_buffer;
670 fc->client_to_service_bufferDataLength =
671 GNUNET_NETWORK_socket_recv (fc->armClientSocket,
672 fc->client_to_service_buffer,
674 if (fc->client_to_service_bufferDataLength <= 0)
676 if (fc->client_to_service_bufferDataLength == 0)
678 #if DEBUG_SERVICE_MANAGER
679 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
680 "Client closed connection with service `%s'\n",
681 fc->listen_info->serviceName);
686 #if DEBUG_SERVICE_MANAGER
687 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
688 "Error receiving from client: %s\n",
692 closeClientAndServiceSockets (fc, REASON_CLIENT_TO_SERVICE);
695 #if DEBUG_SERVICE_MANAGER
696 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
697 "Received %d bytes for service\n",
698 fc->client_to_service_bufferDataLength);
700 if (fc->armServiceSocket != NULL)
701 fc->client_to_service_task =
702 GNUNET_SCHEDULER_add_write_net (
703 GNUNET_TIME_UNIT_FOREVER_REL,
704 fc->armServiceSocket,
705 &forwardToService, fc);
710 fc_acceptConnection (void *cls,
711 const struct GNUNET_SCHEDULER_TaskContext *tc)
713 struct ServiceListeningInfo *sli = cls;
714 struct ForwardedConnection *fc = sli->fc;
716 if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY))
718 GNUNET_assert (GNUNET_OK == GNUNET_NETWORK_socket_close (sli->listeningSocket));
719 closeClientAndServiceSockets (fc, REASON_ERROR);
723 #if DEBUG_SERVICE_MANAGER
724 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
725 "Connected to service, now starting forwarding\n");
727 fc->armServiceSocket = sli->listeningSocket;
728 GNUNET_free (fc->listen_info->service_addr);
729 fc->listen_info->service_addr = sli->service_addr;
730 fc->listen_info->service_addr_len = sli->service_addr_len;
731 if (fc->client_to_service_task == GNUNET_SCHEDULER_NO_TASK)
733 if (fc->client_to_service_bufferDataLength == 0)
734 fc->client_to_service_task =
735 GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
737 &receiveFromClient, fc);
739 fc->client_to_service_task =
740 GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
741 fc->armServiceSocket,
742 &forwardToService, fc);
744 if (fc->service_to_client_task == GNUNET_SCHEDULER_NO_TASK)
746 if (fc->service_to_client_bufferDataLength == 0)
747 fc->service_to_client_task =
748 GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
749 fc->armServiceSocket,
750 &receiveFromService, fc);
752 fc->service_to_client_task =
753 GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
755 &forwardToClient, fc);
761 static struct ServiceListeningInfo *
762 service_try_to_connect (const struct sockaddr *addr,
765 struct ForwardedConnection *fc)
767 struct GNUNET_NETWORK_Handle *sock;
768 struct ServiceListeningInfo *serviceListeningInfo;
770 sock = GNUNET_NETWORK_socket_create (pf, SOCK_STREAM, 0);
773 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "socket");
776 if ( (GNUNET_SYSERR == GNUNET_NETWORK_socket_connect (sock, addr, addrlen)) &&
777 (errno != EINPROGRESS) )
779 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "connect");
780 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
783 serviceListeningInfo = GNUNET_malloc (sizeof (struct ServiceListeningInfo));
784 serviceListeningInfo->serviceName = NULL;
785 serviceListeningInfo->service_addr = GNUNET_malloc (addrlen);
786 memcpy (serviceListeningInfo->service_addr,
789 serviceListeningInfo->service_addr_len = addrlen;
790 serviceListeningInfo->listeningSocket = sock;
791 serviceListeningInfo->fc = fc;
792 serviceListeningInfo->acceptTask =
793 GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
794 serviceListeningInfo->listeningSocket,
795 &fc_acceptConnection, serviceListeningInfo);
796 return serviceListeningInfo;
804 start_forwarding (void *cls,
805 const struct GNUNET_SCHEDULER_TaskContext *tc)
807 struct ForwardedConnection *fc = cls;
808 struct ServiceListeningInfo *sc;
809 struct sockaddr_in target_ipv4;
810 struct sockaddr_in6 target_ipv6;
811 const struct sockaddr_in *v4;
812 const struct sockaddr_in6 *v6;
813 char listen_address[INET6_ADDRSTRLEN];
815 fc->start_task = GNUNET_SCHEDULER_NO_TASK;
817 (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) )
819 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
820 _("Unable to forward to service `%s': shutdown\n"),
821 fc->listen_info->serviceName);
822 closeClientAndServiceSockets (fc, REASON_ERROR);
825 if (0 == GNUNET_TIME_absolute_get_remaining (fc->timeout).rel_value)
827 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
828 _("Unable to forward to service `%s': timeout before connect\n"),
829 fc->listen_info->serviceName);
830 closeClientAndServiceSockets (fc, REASON_ERROR);
833 switch (fc->listen_info->service_addr->sa_family)
837 closeClientAndServiceSockets (fc, REASON_ERROR);
840 v4 = (const struct sockaddr_in *) fc->listen_info->service_addr;
841 inet_ntop (fc->listen_info->service_addr->sa_family,
842 (const void *) &v4->sin_addr,
845 if (0 == strncmp (listen_address, "0.0.0.0", 7))
847 /* connect to [::1] and 127.0.0.1 instead of [::] and 0.0.0.0 */
848 memset (&target_ipv4, 0, sizeof (target_ipv4));
849 inet_pton (AF_INET, "127.0.0.1", &target_ipv4.sin_addr);
850 target_ipv4.sin_family = AF_INET;
851 target_ipv4.sin_port = v4->sin_port;
854 sc = service_try_to_connect ((const struct sockaddr*) v4,
856 sizeof (struct sockaddr_in),
860 v6 = (struct sockaddr_in6 *)fc->listen_info->service_addr;
861 inet_ntop (fc->listen_info->service_addr->sa_family,
862 (const void *) &v6->sin6_addr,
865 if ( (strncmp (listen_address, "[::]:", 5) == 0) || (strncmp (listen_address, "::", 2) == 0) )
867 memset (&target_ipv6, 0, sizeof (target_ipv6));
868 target_ipv6.sin6_addr = in6addr_loopback;
869 target_ipv6.sin6_family = AF_INET6;
870 target_ipv6.sin6_port = v6->sin6_port;
873 sc = service_try_to_connect ((const struct sockaddr*) v6,
875 sizeof (struct sockaddr_in6),
879 sc = service_try_to_connect (fc->listen_info->service_addr,
881 fc->listen_info->service_addr_len,
886 closeClientAndServiceSockets (fc, REASON_ERROR);
891 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
892 _ ("Unable to start service `%s': %s\n"),
893 fc->listen_info->serviceName,
895 closeClientAndServiceSockets (fc, REASON_ERROR);
905 stop_listening (const char *serviceName)
907 struct ServiceListeningInfo *pos;
908 struct ServiceListeningInfo *next;
912 next = serviceListeningInfoList_head;
913 while (NULL != (pos = next))
916 if ( (serviceName != NULL) &&
917 (strcmp (pos->serviceName, serviceName) != 0) )
919 if (pos->acceptTask != GNUNET_SCHEDULER_NO_TASK)
920 GNUNET_SCHEDULER_cancel (pos->acceptTask);
921 GNUNET_break (GNUNET_OK ==
922 GNUNET_NETWORK_socket_close (pos->listeningSocket));
923 GNUNET_CONTAINER_DLL_remove (serviceListeningInfoList_head,
924 serviceListeningInfoList_tail,
926 GNUNET_free (pos->serviceName);
927 GNUNET_free (pos->service_addr);
935 * First connection has come to the listening socket associated with the service,
936 * create the service in order to relay the incoming connection to it
938 * @param cls callback data, struct ServiceListeningInfo describing a listen socket
942 acceptConnection (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
946 accept_and_forward (struct ServiceListeningInfo *serviceListeningInfo)
948 struct ForwardedConnection *fc;
950 fc = GNUNET_malloc (sizeof (struct ForwardedConnection));
951 fc->listen_info = serviceListeningInfo;
952 fc->service_to_client_bufferPos = fc->service_to_client_buffer;
953 fc->client_to_service_bufferPos = fc->client_to_service_buffer;
954 fc->client_addr_len = sizeof (fc->client_addr);
955 fc->armClientSocket = GNUNET_NETWORK_socket_accept (serviceListeningInfo->listeningSocket,
956 (struct sockaddr*) fc->client_addr,
957 &fc->client_addr_len);
958 if (NULL == fc->armClientSocket)
960 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
961 _("Unable to accept connection for service `%s': %s\n"),
962 serviceListeningInfo->serviceName,
965 GNUNET_CONTAINER_DLL_insert (serviceListeningInfoList_head,
966 serviceListeningInfoList_tail,
967 serviceListeningInfo);
968 serviceListeningInfo->acceptTask =
969 GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
970 serviceListeningInfo->listeningSocket,
972 serviceListeningInfo);
975 GNUNET_break (GNUNET_OK ==
976 GNUNET_NETWORK_socket_close (serviceListeningInfo->listeningSocket));
977 start_service (NULL, serviceListeningInfo->serviceName, NULL);
978 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
979 _("Service `%s' started\n"),
980 fc->listen_info->serviceName);
981 fc->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_SERVICE_TIMEOUT);
982 fc->back_off = GNUNET_TIME_UNIT_MILLISECONDS;
983 fc->client_to_service_task =
984 GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
986 &receiveFromClient, fc);
987 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == fc->start_task);
989 = GNUNET_SCHEDULER_add_now (&start_forwarding,
995 * First connection has come to the listening socket associated with the service,
996 * create the service in order to relay the incoming connection to it
998 * @param cls callback data, struct ServiceListeningInfo describing a listen socket
1002 acceptConnection (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1004 struct ServiceListeningInfo *sli = cls;
1005 struct ServiceListeningInfo *pos;
1006 struct ServiceListeningInfo *next;
1011 sli->acceptTask = GNUNET_SCHEDULER_NO_TASK;
1012 if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason))
1014 GNUNET_CONTAINER_DLL_remove (serviceListeningInfoList_head,
1015 serviceListeningInfoList_tail,
1018 use_lsocks = GNUNET_NO;
1019 if (GNUNET_YES == GNUNET_CONFIGURATION_have_value (cfg,
1021 "DISABLE_SOCKET_FORWARDING"))
1022 use_lsocks = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1024 "DISABLE_SOCKET_FORWARDING");
1026 use_lsocks = GNUNET_YES;
1028 if (GNUNET_NO != use_lsocks)
1030 accept_and_forward (sli);
1035 next = serviceListeningInfoList_head;
1036 while (NULL != (pos = next))
1039 if (0 == strcmp (pos->serviceName,
1042 GNUNET_array_append (lsocks, ls,
1043 GNUNET_NETWORK_get_fd (pos->listeningSocket));
1044 GNUNET_free (pos->listeningSocket); /* deliberately no closing! */
1045 GNUNET_free (pos->service_addr);
1046 GNUNET_free (pos->serviceName);
1047 GNUNET_SCHEDULER_cancel (pos->acceptTask);
1048 GNUNET_CONTAINER_DLL_remove (serviceListeningInfoList_head,
1049 serviceListeningInfoList_tail,
1054 GNUNET_array_append (lsocks, ls,
1055 GNUNET_NETWORK_get_fd (sli->listeningSocket));
1056 GNUNET_free (sli->listeningSocket); /* deliberately no closing! */
1057 GNUNET_free (sli->service_addr);
1058 GNUNET_array_append (lsocks, ls, -1);
1059 start_service (NULL,
1063 while (lsocks[ls] != -1)
1064 GNUNET_break (0 == close (lsocks[ls++]));
1065 GNUNET_array_grow (lsocks, ls, 0);
1066 GNUNET_free (sli->serviceName);
1072 * Creating a listening socket for each of the service's addresses and
1073 * wait for the first incoming connection to it
1075 * @param sa address associated with the service
1076 * @param addr_len length of sa
1077 * @param serviceName the name of the service in question
1080 createListeningSocket (struct sockaddr *sa,
1082 const char *serviceName)
1084 const static int on = 1;
1085 struct GNUNET_NETWORK_Handle *sock;
1086 struct ServiceListeningInfo *serviceListeningInfo;
1088 switch (sa->sa_family)
1091 sock = GNUNET_NETWORK_socket_create (PF_INET, SOCK_STREAM, 0);
1094 sock = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
1097 if (strcmp(GNUNET_a2s (sa, addr_len), "@") == 0) /* Do not bind to blank UNIX path! */
1099 sock = GNUNET_NETWORK_socket_create (PF_UNIX, SOCK_STREAM, 0);
1104 errno = EAFNOSUPPORT;
1109 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1110 _("Unable to create socket for service `%s': %s\n"),
1116 if (GNUNET_NETWORK_socket_setsockopt
1117 (sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) != GNUNET_OK)
1118 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1121 if ( (sa->sa_family == AF_INET6) &&
1122 (GNUNET_NETWORK_socket_setsockopt
1123 (sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof (on)) != GNUNET_OK))
1124 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1128 if (GNUNET_NETWORK_socket_bind
1129 (sock, (const struct sockaddr *) sa, addr_len) != GNUNET_OK)
1131 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1132 _("Unable to bind listening socket for service `%s' to address `%s': %s\n"),
1134 GNUNET_a2s (sa, addr_len),
1136 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
1140 if (GNUNET_NETWORK_socket_listen (sock, 5) != GNUNET_OK)
1142 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
1144 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
1148 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1149 _("ARM now monitors connections to service `%s' at `%s'\n"),
1151 GNUNET_a2s (sa, addr_len));
1152 serviceListeningInfo = GNUNET_malloc (sizeof (struct ServiceListeningInfo));
1153 serviceListeningInfo->serviceName = GNUNET_strdup (serviceName);
1154 serviceListeningInfo->service_addr = sa;
1155 serviceListeningInfo->service_addr_len = addr_len;
1156 serviceListeningInfo->listeningSocket = sock;
1157 serviceListeningInfo->acceptTask =
1158 GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, sock,
1160 serviceListeningInfo);
1161 GNUNET_CONTAINER_DLL_insert (serviceListeningInfoList_head,
1162 serviceListeningInfoList_tail,
1163 serviceListeningInfo);
1168 * Callback function, checks whether the current tokens are representing a service,
1169 * gets its addresses and create listening socket for it.
1171 * @param cls callback data, not used
1172 * @param section configuration section
1173 * @param option configuration option
1174 * @param value the option's value
1177 checkPortNumberCB (void *cls,
1178 const char *section,
1182 struct sockaddr **addrs;
1183 socklen_t *addr_lens;
1187 if ( (strcasecmp (section, "arm") == 0) ||
1188 (strcasecmp (option, "AUTOSTART") != 0) ||
1189 (strcasecmp (value, "YES") != 0) ||
1190 (isInDefaultList (section) == GNUNET_YES) )
1192 if (0 >= (ret = GNUNET_SERVICE_get_server_addresses (section, cfg, &addrs,
1195 /* this will free (or capture) addrs[i] */
1196 for (i = 0; i < ret; i++)
1197 createListeningSocket (addrs[i], addr_lens[i], section);
1198 GNUNET_free (addrs);
1199 GNUNET_free (addr_lens);
1204 * Entry point to the Service Manager
1206 * @param configurationHandle configuration to use to get services
1209 prepareServices (const struct GNUNET_CONFIGURATION_Handle
1210 *configurationHandle)
1212 char *defaultServicesString;
1214 cfg = configurationHandle;
1215 /* Split the default services into a list */
1217 GNUNET_CONFIGURATION_get_value_string (cfg, "arm", "DEFAULTSERVICES",
1218 &defaultServicesString))
1220 addDefaultServicesToList (defaultServicesString);
1221 GNUNET_free (defaultServicesString);
1223 /* Spot the services from the configuration and create a listening
1225 GNUNET_CONFIGURATION_iterate (cfg, &checkPortNumberCB, NULL);
1228 /* end of gnunet-service-arm_interceptor.c */