acdfe0a55c4c4c0106e810dac47bcc3d7cecef55
[oweals/gnunet.git] / src / arm / gnunet-service-arm_interceptor.c
1 /*
2      This file is part of GNUnet.
3      (C) 2009, 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  * @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_NO
41
42 #define BUFFER_SIZE (64 * 1024)
43
44 /**
45  * Problem forwarding from client to service.
46  */
47 #define REASON_CLIENT_TO_SERVICE 1
48
49 /**
50  * Problem forwarding from service to client.
51  */
52 #define REASON_SERVICE_TO_CLIENT 2
53
54 /**
55  * Problem in both directions.
56  */
57 #define REASON_ERROR 3
58
59
60 /**
61  *
62  */
63 struct ServiceListeningInfo
64 {
65   /**
66    * This is a linked list.
67    */
68   struct ServiceListeningInfo *next;
69
70   /**
71    * This is a linked list.
72    */
73   struct ServiceListeningInfo *prev;
74
75   /**
76    * Name of the service being forwarded.
77    */
78   char *serviceName;
79
80   /**
81    *
82    */
83   struct sockaddr *service_addr;
84
85   /**
86    *
87    */
88   socklen_t service_addr_len;
89
90   /**
91    * Our listening socket.
92    */
93   struct GNUNET_NETWORK_Handle *listeningSocket;
94
95   /**
96    * Task doing the accepting.
97    */
98   GNUNET_SCHEDULER_TaskIdentifier acceptTask;
99 };
100
101 /**
102  * Information of the connection: client-arm-service
103  */
104 struct ForwardedConnection
105 {
106   /**
107    *
108    */
109   struct GNUNET_NETWORK_Handle *armClientSocket;
110
111   /**
112    *
113    */
114   struct GNUNET_NETWORK_Handle *armServiceSocket;
115
116   /**
117    *
118    */
119   struct ServiceListeningInfo *listen_info;
120
121   /**
122    *
123    */
124   char service_to_client_buffer[BUFFER_SIZE];
125
126   /**
127    *
128    */
129   char client_to_service_buffer[BUFFER_SIZE];
130
131   /**
132    *
133    */
134   char client_addr[32];
135
136   /**
137    *
138    */
139   const char *client_to_service_bufferPos;
140
141   /**
142    *
143    */
144   const char *service_to_client_bufferPos;
145
146   /**
147    * Timeout for forwarding.
148    */
149   struct GNUNET_TIME_Absolute timeout;
150   
151   /**
152    * Current back-off value.
153    */
154   struct GNUNET_TIME_Relative back_off;
155   
156   /**
157    * Task that tries to initiate forwarding.
158    */
159   GNUNET_SCHEDULER_TaskIdentifier start_task;
160
161   /**
162    *
163    */
164   GNUNET_SCHEDULER_TaskIdentifier client_to_service_task;
165
166   /**
167    *
168    */
169   GNUNET_SCHEDULER_TaskIdentifier service_to_client_task;
170
171   /**
172    *
173    */
174   ssize_t client_to_service_bufferDataLength;
175
176   /**
177    *
178    */
179   ssize_t service_to_client_bufferDataLength;
180
181   /**
182    *
183    */
184   socklen_t client_addr_len;
185
186   /**
187    * Have we ever successfully written data to the service?
188    */
189   int first_write_done;
190
191   /**
192    * Service connection attempts for IPv4
193    */
194   struct ServiceListeningInfo *service_connect_ipv4;
195
196   /**
197    * Service connection attempts for IPv6
198    */
199   struct ServiceListeningInfo *service_connect_ipv6;
200 };
201
202 /**
203  * Array with the names of the services started by default.
204  */
205 static char **defaultServicesList;
206
207 /**
208  * Size of the defaultServicesList array.
209  */
210 static unsigned int numDefaultServices;
211
212 /**
213  *
214  */
215 static const struct GNUNET_CONFIGURATION_Handle *cfg;
216
217 /**
218  *
219  */
220 static struct ServiceListeningInfo *serviceListeningInfoList_head;
221
222 /**
223  *
224  */
225 static struct ServiceListeningInfo *serviceListeningInfoList_tail;
226
227
228 /**
229  * Put the default services represented by a space separated string into an array of strings
230  * 
231  * @param services space separated string of default services
232  */
233 static void
234 addDefaultServicesToList (const char *services)
235 {
236   unsigned int i;
237   const char *token;
238   char *s;
239
240   if (strlen (services) == 0)
241     return;
242   s = GNUNET_strdup (services);
243   token = strtok (s, " ");
244   while (NULL != token)
245     {
246       numDefaultServices++;
247       token = strtok (NULL, " ");
248     }
249   GNUNET_free (s);
250
251   defaultServicesList = GNUNET_malloc (numDefaultServices * sizeof (char *));
252   i = 0;
253   s = GNUNET_strdup (services);
254   token = strtok (s, " ");
255   while (NULL != token)
256     {
257       defaultServicesList[i++] = GNUNET_strdup (token);
258       token = strtok (NULL, " ");
259     }
260   GNUNET_free (s);
261   GNUNET_assert (i == numDefaultServices);
262 }
263
264 /**
265  * Checks whether the serviceName is in the list of default services
266  * 
267  * @param serviceName string to check its existance in the list
268  * @return GNUNET_YES if the service is started by default
269  */
270 static int
271 isInDefaultList (const char *serviceName)
272 {
273   unsigned int i;
274   for (i = 0; i < numDefaultServices; i++)
275     if (strcmp (serviceName, defaultServicesList[i]) == 0)
276       return GNUNET_YES;    
277   return GNUNET_NO;
278 }
279
280
281 /**
282  * Close forwarded connection (partial or full).
283  *
284  * @param fc connection to close 
285  * @param reason which direction to close
286  */
287 static void
288 closeClientAndServiceSockets (struct ForwardedConnection *fc, 
289                               int reason)
290 {
291   if (0 != (REASON_SERVICE_TO_CLIENT & reason)) 
292     {      
293 #if DEBUG_SERVICE_MANAGER
294       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
295                   "Stopping forwarding from service to client\n",
296                   fc->listen_info->serviceName);
297 #endif
298       if (fc->service_to_client_task != GNUNET_SCHEDULER_NO_TASK)
299         {
300           GNUNET_SCHEDULER_cancel (fc->service_to_client_task);
301           fc->service_to_client_task = GNUNET_SCHEDULER_NO_TASK;
302         }
303       if (fc->armClientSocket != NULL)
304         GNUNET_NETWORK_socket_shutdown (fc->armClientSocket,
305                                         SHUT_WR);
306       if (fc->armServiceSocket != NULL)
307         GNUNET_NETWORK_socket_shutdown (fc->armServiceSocket,
308                                         SHUT_RD);
309     }
310   if (0 != (REASON_CLIENT_TO_SERVICE & reason)) 
311     {
312 #if DEBUG_SERVICE_MANAGER
313       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
314                   "Stopping forwarding from client to service\n",
315                   fc->listen_info->serviceName);
316 #endif
317       if (fc->client_to_service_task != GNUNET_SCHEDULER_NO_TASK) 
318         {
319           GNUNET_SCHEDULER_cancel (                                fc->client_to_service_task);
320           fc->client_to_service_task = GNUNET_SCHEDULER_NO_TASK;
321         }
322       if (fc->armClientSocket != NULL)
323         GNUNET_NETWORK_socket_shutdown (fc->armClientSocket,
324                                         SHUT_RD);
325       if (fc->armServiceSocket != NULL)
326         GNUNET_NETWORK_socket_shutdown (fc->armServiceSocket,
327                                         SHUT_WR);
328     }
329   if ( (fc->client_to_service_task != GNUNET_SCHEDULER_NO_TASK) ||
330        (fc->service_to_client_task != GNUNET_SCHEDULER_NO_TASK) )
331     return;
332 #if DEBUG_SERVICE_MANAGER
333   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
334               "Closing forwarding connection (done with both directions)\n");
335 #endif
336   if (fc->start_task != GNUNET_SCHEDULER_NO_TASK)
337     GNUNET_SCHEDULER_cancel (                        fc->start_task);
338   if ( (NULL != fc->armClientSocket) &&
339        (GNUNET_SYSERR ==
340         GNUNET_NETWORK_socket_close (fc->armClientSocket)) )
341     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "close");
342   if ( (NULL != fc->armServiceSocket) &&
343        (GNUNET_SYSERR ==
344         GNUNET_NETWORK_socket_close (fc->armServiceSocket)) )
345     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "close");
346   GNUNET_free (fc->listen_info->serviceName);              
347   GNUNET_free (fc->listen_info->service_addr);
348   GNUNET_free (fc->listen_info);        
349   GNUNET_free (fc);
350 }
351
352
353 /**
354  * Read data from the client and then forward it to the service.
355  * 
356  * @param cls callback data,   struct ForwardedConnection for the communication between client and service
357  * @param tc context 
358  */
359 static void
360 receiveFromClient (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
361
362
363 /**
364  * Receive service messages sent by the service and forward it to client
365  * 
366  * @param cls callback data, struct ForwardedConnection for the communication between client and service
367  * @param tc scheduler context
368  */
369 static void
370 receiveFromService (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
371
372
373 /**
374  *
375  */
376 static void
377 start_forwarding (void *cls,
378                   const struct GNUNET_SCHEDULER_TaskContext *tc);
379
380
381
382 /**
383  * Forward messages sent from service to client
384  * 
385  * @param cls callback data, struct ForwardedConnection for the communication between client and service
386  * @param tc context
387  */
388 static void
389 forwardToClient (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
390 {
391   struct ForwardedConnection *fc = cls;
392   ssize_t numberOfBytesSent;
393
394   fc->service_to_client_task = GNUNET_SCHEDULER_NO_TASK;
395   if (GNUNET_YES != GNUNET_NETWORK_fdset_isset (tc->write_ready,
396                                                 fc->armClientSocket))
397     {
398       fc->service_to_client_task = 
399         GNUNET_SCHEDULER_add_write_net (
400                                         GNUNET_TIME_UNIT_FOREVER_REL,
401                                         fc->armClientSocket,
402                                         &forwardToClient, fc);
403       return;
404     }
405   /* Forwarding service response to client */
406   numberOfBytesSent =
407     GNUNET_NETWORK_socket_send (fc->armClientSocket,
408                                 fc->service_to_client_bufferPos,
409                                 fc->service_to_client_bufferDataLength);
410   if (numberOfBytesSent <= 0)
411     {
412       if ( (errno != EPIPE) &&
413            (errno != ECONNRESET) )
414         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
415                     "Failed to forward %u bytes of data to client: %s\n",
416                     fc->service_to_client_bufferDataLength,
417                     STRERROR (errno));
418       closeClientAndServiceSockets (fc,
419                                     REASON_SERVICE_TO_CLIENT);
420       return;
421     }
422 #if DEBUG_SERVICE_MANAGER
423   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
424               "Forwarded %d bytes to client\n",
425               numberOfBytesSent);
426 #endif
427   if (numberOfBytesSent < fc->service_to_client_bufferDataLength)
428     {
429       fc->service_to_client_bufferPos += numberOfBytesSent;
430       fc->service_to_client_bufferDataLength -= numberOfBytesSent;
431       fc->service_to_client_task = 
432         GNUNET_SCHEDULER_add_write_net (
433                                         GNUNET_TIME_UNIT_FOREVER_REL,
434                                         fc->armClientSocket,
435                                         &forwardToClient, 
436                                         fc);
437       return;
438     }
439   fc->service_to_client_task =
440     GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
441                                    fc->armServiceSocket,
442                                    &receiveFromService, 
443                                    fc);
444 }
445
446
447 /**
448  * Receive service messages sent by the service and forward it to client
449  * 
450  * @param cls callback data, struct ForwardedConnection for the communication between client and service
451  * @param tc scheduler context
452  */
453 static void
454 receiveFromService (void *cls, 
455                     const struct GNUNET_SCHEDULER_TaskContext *tc)
456 {
457   struct ForwardedConnection *fc = cls;
458   struct GNUNET_TIME_Relative rem;
459
460   fc->service_to_client_task = GNUNET_SCHEDULER_NO_TASK;
461   if ( (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) &&
462        (fc->first_write_done != GNUNET_YES) )
463     {
464       closeClientAndServiceSockets (fc, REASON_ERROR);
465       return;
466     }
467   if (GNUNET_YES != GNUNET_NETWORK_fdset_isset (tc->read_ready,
468                                                 fc->armServiceSocket))
469     {
470       fc->service_to_client_task =
471         GNUNET_SCHEDULER_add_read_net (
472                                        GNUNET_TIME_UNIT_FOREVER_REL,
473                                        fc->armServiceSocket,
474                                        &receiveFromService, fc);
475       return;
476     }
477   fc->service_to_client_bufferPos = fc->service_to_client_buffer;
478   fc->service_to_client_bufferDataLength =
479     GNUNET_NETWORK_socket_recv (fc->armServiceSocket,
480                                 fc->service_to_client_buffer, 
481                                 BUFFER_SIZE);
482   if (fc->service_to_client_bufferDataLength <= 0)
483     {
484 #if DEBUG_SERVICE_MANAGER
485       if (fc->service_to_client_bufferDataLength == 0)
486         {
487           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
488                       "Service `%s' stopped sending data.\n",
489                       fc->listen_info->serviceName);
490         }
491 #endif
492       if (fc->first_write_done != GNUNET_YES)
493         {
494           fc->service_to_client_bufferDataLength = 0;
495           GNUNET_break (GNUNET_OK ==
496                         GNUNET_NETWORK_socket_close (fc->armServiceSocket));
497           fc->armServiceSocket = NULL;
498           if ( (fc->client_to_service_bufferDataLength > 0) &&
499                (fc->client_to_service_task != GNUNET_SCHEDULER_NO_TASK) )
500             {
501               GNUNET_SCHEDULER_cancel (fc->client_to_service_task);
502               fc->client_to_service_task = GNUNET_SCHEDULER_NO_TASK;
503             }
504           fc->back_off = GNUNET_TIME_relative_multiply (fc->back_off, 2);
505 #if DEBUG_SERVICE_MANAGER
506           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
507                       "Failed to connected to service `%s' at `%s', will try again in %llu ms\n",
508                       fc->listen_info->serviceName,
509                       GNUNET_a2s (fc->listen_info->service_addr,
510                                   fc->listen_info->service_addr_len),
511                       (unsigned long long) GNUNET_TIME_relative_min (fc->back_off,
512                                                                      rem).rel_value);
513 #endif
514           rem = GNUNET_TIME_absolute_get_remaining (fc->timeout);
515           GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == fc->start_task);
516           fc->start_task
517             = GNUNET_SCHEDULER_add_delayed (
518                                             GNUNET_TIME_relative_min (fc->back_off,
519                                                                       rem),
520                                             &start_forwarding,
521                                             fc);
522         }
523       else
524         {
525 #if DEBUG_SERVICE_MANAGER
526           if (fc->service_to_client_bufferDataLength != 0)
527             GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
528                         "Error receiving from service: %s\n", 
529                         STRERROR (errno));
530 #endif
531           closeClientAndServiceSockets (fc, REASON_SERVICE_TO_CLIENT);
532         }
533       return;
534     }
535   fc->first_write_done = GNUNET_YES;
536 #if DEBUG_SERVICE_MANAGER
537   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
538               "Received %d bytes for client\n",
539               fc->service_to_client_bufferDataLength);
540 #endif
541   fc->service_to_client_task = 
542     GNUNET_SCHEDULER_add_write_net (
543                                     GNUNET_TIME_UNIT_FOREVER_REL,
544                                     fc->armClientSocket,
545                                     &forwardToClient, fc);
546 }
547
548
549 /**
550  * Forward client message to service
551  * 
552  * @param cls callback data, struct ForwardedConnection for the communication between client and service
553  * @param tc scheduler context
554  */
555 static void
556 forwardToService (void *cls, 
557                   const struct GNUNET_SCHEDULER_TaskContext *tc)
558 {
559   struct ForwardedConnection *fc = cls;
560   ssize_t numberOfBytesSent;
561   struct GNUNET_TIME_Relative rem;
562
563   fc->client_to_service_task = GNUNET_SCHEDULER_NO_TASK;
564   if ( (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) &&
565        (fc->first_write_done != GNUNET_YES) )
566     {
567       closeClientAndServiceSockets (fc, REASON_ERROR);
568       return;
569     }
570   if (GNUNET_YES != GNUNET_NETWORK_fdset_isset (tc->write_ready,
571                                                 fc->armServiceSocket))
572     {
573       fc->client_to_service_task = 
574         GNUNET_SCHEDULER_add_write_net (
575                                         GNUNET_TIME_UNIT_FOREVER_REL,
576                                         fc->armServiceSocket,
577                                         &forwardToService, fc);
578       return;
579     }
580   numberOfBytesSent =
581     GNUNET_NETWORK_socket_send (fc->armServiceSocket,
582                                 fc->client_to_service_bufferPos,
583                                 fc->client_to_service_bufferDataLength);
584   if (numberOfBytesSent <= 0)
585     {
586       if (GNUNET_YES != fc->first_write_done)
587         {
588           GNUNET_break (GNUNET_OK ==
589                         GNUNET_NETWORK_socket_close (fc->armServiceSocket));
590           fc->armServiceSocket = NULL;
591           if ( (fc->service_to_client_bufferDataLength == 0) &&
592                (fc->service_to_client_task != GNUNET_SCHEDULER_NO_TASK) )
593             {
594               GNUNET_SCHEDULER_cancel (fc->service_to_client_task);
595               fc->service_to_client_task = GNUNET_SCHEDULER_NO_TASK;
596             }
597           fc->back_off = GNUNET_TIME_relative_multiply (fc->back_off, 2);
598 #if DEBUG_SERVICE_MANAGER
599           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
600                       "Failed to connect to service `%s' at `%s', will try again in %llu ms\n",
601                       fc->listen_info->serviceName,
602                       GNUNET_a2s (fc->listen_info->service_addr,
603                                   fc->listen_info->service_addr_len),
604                       (unsigned long long) GNUNET_TIME_relative_min (fc->back_off,
605                                                                      rem).rel_value);
606 #endif
607           rem = GNUNET_TIME_absolute_get_remaining (fc->timeout);
608           GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == fc->start_task);
609           fc->start_task 
610             = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_min (fc->back_off,
611                                                                       rem),
612                                             &start_forwarding,
613                                             fc);
614         }
615       else
616         {
617           if ( (errno != EPIPE) &&
618                (errno != ECONNRESET) )
619             GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
620                         "Failed to forward data to service: %s\n",
621                         STRERROR (errno));
622           closeClientAndServiceSockets (fc,
623                                         REASON_CLIENT_TO_SERVICE);
624         }
625       return;
626     }
627 #if DEBUG_SERVICE_MANAGER
628   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
629               "Forwarded %d bytes to service\n",
630               numberOfBytesSent);
631 #endif
632   fc->first_write_done = GNUNET_YES;
633   if (numberOfBytesSent < fc->client_to_service_bufferDataLength)
634     {
635       fc->client_to_service_bufferPos += numberOfBytesSent;
636       fc->client_to_service_bufferDataLength -= numberOfBytesSent;
637       fc->client_to_service_task = 
638         GNUNET_SCHEDULER_add_write_net (
639                                         GNUNET_TIME_UNIT_FOREVER_REL,
640                                         fc->armServiceSocket,
641                                         &forwardToService, fc);
642       return;
643     }
644   fc->client_to_service_task =
645     GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
646                                    fc->armClientSocket,
647                                    &receiveFromClient, fc);
648 }
649
650
651 /**
652  * Read data from the client and then forward it to the service.
653  * 
654  * @param cls callback data,   struct ForwardedConnection for the communication between client and service
655  * @param tc context 
656  */
657 static void
658 receiveFromClient (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
659 {
660   struct ForwardedConnection *fc = cls;
661
662   fc->client_to_service_task = GNUNET_SCHEDULER_NO_TASK;
663   if (GNUNET_YES != GNUNET_NETWORK_fdset_isset (tc->read_ready,
664                                                 fc->armClientSocket))
665     {
666       fc->client_to_service_task =
667         GNUNET_SCHEDULER_add_read_net (
668                                        GNUNET_TIME_UNIT_FOREVER_REL,
669                                        fc->armClientSocket,
670                                        &receiveFromClient, fc);
671       return;
672     }
673   fc->client_to_service_bufferPos = fc->client_to_service_buffer;
674   fc->client_to_service_bufferDataLength =
675     GNUNET_NETWORK_socket_recv (fc->armClientSocket,
676                                 fc->client_to_service_buffer, 
677                                 BUFFER_SIZE);
678   if (fc->client_to_service_bufferDataLength <= 0)
679     {
680       if (fc->client_to_service_bufferDataLength == 0)
681         {
682 #if DEBUG_SERVICE_MANAGER
683           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
684                       "Client closed connection with service `%s'\n",
685                       fc->listen_info->serviceName);
686 #endif
687         }
688       else
689         {
690 #if DEBUG_SERVICE_MANAGER
691           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
692                       "Error receiving from client: %s\n",
693                       STRERROR (errno));
694 #endif
695         }
696       closeClientAndServiceSockets (fc, REASON_CLIENT_TO_SERVICE);
697       return;
698     }
699 #if DEBUG_SERVICE_MANAGER
700   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
701               "Received %d bytes for service\n",
702               fc->client_to_service_bufferDataLength);
703 #endif
704   if (fc->armServiceSocket != NULL)        
705     fc->client_to_service_task = 
706       GNUNET_SCHEDULER_add_write_net (
707                                       GNUNET_TIME_UNIT_FOREVER_REL,
708                                       fc->armServiceSocket,
709                                       &forwardToService, fc);
710 }
711
712
713 static void
714 fc_acceptConnection_ipv4 (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
715
716 static void
717 fc_acceptConnection_ipv6 (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
718
719
720 static void
721 fc_acceptConnection (void *cls, 
722                      const struct GNUNET_SCHEDULER_TaskContext *tc, 
723                      int is_ipv4)
724 {
725   struct ForwardedConnection *fc = cls;
726   struct ServiceListeningInfo *sli;
727
728   if (is_ipv4)
729     sli = fc->service_connect_ipv4;
730   else 
731     sli = fc->service_connect_ipv6;
732
733   if ( (tc->reason & (GNUNET_SCHEDULER_REASON_SHUTDOWN | GNUNET_SCHEDULER_REASON_TIMEOUT | GNUNET_SCHEDULER_REASON_PREREQ_DONE)) || 
734        ((tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY) && fc->armServiceSocket) )
735     {
736       GNUNET_NETWORK_socket_close (sli->listeningSocket);
737       if (is_ipv4)
738         fc->service_connect_ipv4 = NULL;
739       else
740         fc->service_connect_ipv6 = NULL;
741     }
742   else if (tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY)
743     {
744 #if DEBUG_SERVICE_MANAGER
745       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
746                   "Connected to service, now starting forwarding\n");
747 #endif
748       fc->armServiceSocket = sli->listeningSocket;
749       if ( (GNUNET_YES == is_ipv4) && (fc->service_connect_ipv6 != NULL) )
750         {
751           GNUNET_SCHEDULER_cancel (fc->service_connect_ipv6->acceptTask);
752           fc->service_connect_ipv6->acceptTask = GNUNET_SCHEDULER_add_now (fc_acceptConnection_ipv6, fc);
753         }
754       else if ( (GNUNET_NO == is_ipv4) && (fc->service_connect_ipv4 != NULL) )
755         {
756           GNUNET_SCHEDULER_cancel (fc->service_connect_ipv4->acceptTask);
757           fc->service_connect_ipv4->acceptTask = GNUNET_SCHEDULER_add_now (fc_acceptConnection_ipv4, fc);
758         }
759       GNUNET_free (fc->listen_info->service_addr);
760       fc->listen_info->service_addr = sli->service_addr;
761       fc->listen_info->service_addr_len = sli->service_addr_len;
762       /* fc->listen_info->listeningSocket is it closed already ?*/
763       if (fc->client_to_service_task == GNUNET_SCHEDULER_NO_TASK)
764         {
765           if (fc->client_to_service_bufferDataLength == 0) 
766             fc->client_to_service_task =
767               GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
768                                              fc->armClientSocket,
769                                              &receiveFromClient, fc);
770           else
771             fc->client_to_service_task = 
772               GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
773                                               fc->armServiceSocket,
774                                               &forwardToService, fc);
775         }
776       if (fc->service_to_client_task == GNUNET_SCHEDULER_NO_TASK)
777         {
778           if (fc->service_to_client_bufferDataLength == 0) 
779             fc->service_to_client_task =
780               GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
781                                              fc->armServiceSocket,
782                                              &receiveFromService, fc);
783           else
784             fc->service_to_client_task = 
785               GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
786                                               fc->armClientSocket,
787                                               &forwardToClient, fc);
788         }
789     }
790   else
791     {
792       GNUNET_break (0);
793     }
794   GNUNET_free (sli);
795 }
796
797
798 static void
799 fc_acceptConnection_ipv4 (void *cls,
800                           const struct GNUNET_SCHEDULER_TaskContext *tc)
801 {
802   fc_acceptConnection (cls, tc, GNUNET_YES);
803 }
804
805
806 static void
807 fc_acceptConnection_ipv6 (void *cls,
808                           const struct GNUNET_SCHEDULER_TaskContext *tc)
809 {
810   fc_acceptConnection (cls, tc, GNUNET_NO);
811 }
812
813
814 static int
815 service_try_to_connect (const struct sockaddr *addr, 
816                         socklen_t addrlen, 
817                         struct ForwardedConnection *fc)
818 {
819   struct GNUNET_NETWORK_Handle *sock;
820   struct ServiceListeningInfo *serviceListeningInfo;
821
822   sock = GNUNET_NETWORK_socket_create (AF_INET, SOCK_STREAM, 0);
823   if (sock == NULL)
824     {
825       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to create a socket\n");
826       return 1;
827     }
828   
829   if ( (GNUNET_SYSERR == GNUNET_NETWORK_socket_connect (sock, addr, addrlen)) &&
830        (errno != EINPROGRESS) )
831     {
832       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to connect\n");
833       GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
834       return 1;
835     }
836   
837   serviceListeningInfo = GNUNET_malloc (sizeof (struct ServiceListeningInfo));
838   serviceListeningInfo->serviceName = NULL;
839   serviceListeningInfo->service_addr = GNUNET_malloc (addrlen);
840   memcpy (serviceListeningInfo->service_addr,
841           addr,
842           addrlen);
843   serviceListeningInfo->service_addr_len = addrlen;
844   serviceListeningInfo->listeningSocket = sock;
845
846   switch (addrlen)
847     {
848     case sizeof (struct sockaddr_in):
849       fc->service_connect_ipv4 = serviceListeningInfo;
850       serviceListeningInfo->acceptTask =
851         GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
852                                         serviceListeningInfo->listeningSocket,
853                                         &fc_acceptConnection_ipv4, fc);
854       break;
855     case sizeof (struct sockaddr_in6):
856       fc->service_connect_ipv6 = serviceListeningInfo;
857       serviceListeningInfo->acceptTask =
858         GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
859                                         serviceListeningInfo->listeningSocket,
860                                         &fc_acceptConnection_ipv6, fc);
861       break;
862     default:
863       GNUNET_break (0);
864       return 1;
865     }
866   return 0;
867 }
868
869
870 /**
871  *
872  */
873 static void
874 start_forwarding (void *cls,
875                   const struct GNUNET_SCHEDULER_TaskContext *tc)
876 {
877   struct ForwardedConnection *fc = cls;
878   struct GNUNET_TIME_Relative rem;
879   int failures;
880   int is_zero;
881   int is_ipv4;
882   int is_ipv6;
883   struct sockaddr_in target_ipv4;
884   struct sockaddr_in6 target_ipv6;
885   const struct sockaddr *v4;
886   const struct sockaddr *v6;
887   char listen_address[INET_ADDRSTRLEN];
888   uint16_t listening_port; /* in big endian */
889
890   fc->start_task = GNUNET_SCHEDULER_NO_TASK;
891   if ( (NULL != tc) &&
892        (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) )
893     {
894       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
895                   _("Unable to forward to service `%s': shutdown\n"),
896                   fc->listen_info->serviceName);
897       closeClientAndServiceSockets (fc, REASON_ERROR);
898       return;
899     }
900   rem = GNUNET_TIME_absolute_get_remaining (fc->timeout);
901   if (rem.rel_value == 0)
902     {
903       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
904                   _("Unable to forward to service `%s': timeout before connect\n"),
905                   fc->listen_info->serviceName);
906       closeClientAndServiceSockets (fc, REASON_ERROR);
907       return;
908     }
909   switch (fc->listen_info->service_addr->sa_family)
910     {
911     case AF_INET:
912       inet_ntop (fc->listen_info->service_addr->sa_family, 
913                  (const void *) &((struct sockaddr_in *) fc->listen_info->service_addr)->sin_addr, 
914                  listen_address,
915                  INET_ADDRSTRLEN);
916       is_zero = (strncmp (listen_address, "0.0.0.0:", 8) == 0) || (strncmp (listen_address, "0.0.0.0", 7) == 0);
917       is_ipv4 = GNUNET_YES;
918       is_ipv6 = GNUNET_NO;
919       listening_port = ((struct sockaddr_in *)fc->listen_info->service_addr)->sin_port;
920       break;
921     case AF_INET6:
922       inet_ntop (fc->listen_info->service_addr->sa_family, 
923                  (const void *) &((struct sockaddr_in6 *) fc->listen_info->service_addr)->sin6_addr, 
924                  listen_address, 
925                  INET6_ADDRSTRLEN);
926       is_zero = (strncmp (listen_address, "[::]:", 5) == 0) || (strncmp (listen_address, "::", 2) == 0);
927       is_ipv4 = GNUNET_NO;
928       is_ipv6 = GNUNET_YES;
929       listening_port = ((struct sockaddr_in6 *)fc->listen_info->service_addr)->sin6_port;
930       break;
931     default:
932       GNUNET_break (0);
933       closeClientAndServiceSockets (fc, REASON_ERROR);
934       return;
935     }
936   
937   fc->service_connect_ipv4 = NULL;
938   fc->service_connect_ipv6 = NULL;
939   v4 = NULL;
940   v6 = NULL;
941   if (is_zero)
942     {
943       /* connect to [::1] and 127.0.0.1 instead of [::] and 0.0.0.0 */
944       memset (&target_ipv4, 0, sizeof (target_ipv4));
945       inet_pton (AF_INET, "127.0.0.1", &target_ipv4.sin_addr);
946       target_ipv4.sin_family = AF_INET;
947       target_ipv4.sin_port = listening_port;
948       v4 = (const struct sockaddr *) &target_ipv4;
949       is_ipv4 = GNUNET_YES;
950       
951       memset (&target_ipv6, 0, sizeof (target_ipv6));
952       inet_pton (AF_INET6, "::1", &target_ipv6.sin6_addr);
953       target_ipv6.sin6_family = AF_INET6;
954       target_ipv6.sin6_port = listening_port;
955       is_ipv6 = GNUNET_YES;
956       v6 = (const struct sockaddr *) &target_ipv6;
957     }
958   else
959     {
960       if (is_ipv4)
961         v4 = (const struct sockaddr*) fc->listen_info->service_addr;
962       if (is_ipv6) 
963         v6 = (const struct sockaddr*) fc->listen_info->service_addr;
964     }
965   failures = 0;
966   if (is_ipv4)
967     failures += service_try_to_connect (v4,
968                                         sizeof (struct sockaddr_in), 
969                                         fc);
970   if (is_ipv6)
971     failures += service_try_to_connect (v6,
972                                         sizeof (struct sockaddr_in6), 
973                                         fc);
974   if (is_ipv4 + is_ipv6 == failures)
975     {
976       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
977                   _ ("Unable to start service `%s': %s\n"),
978                   fc->listen_info->serviceName,
979                   STRERROR (errno));
980       closeClientAndServiceSockets (fc, REASON_ERROR);
981       return;
982     }
983 }
984
985
986 /**
987  *
988  */
989 int
990 stop_listening (const char *serviceName)
991 {
992   struct ServiceListeningInfo *pos;
993   struct ServiceListeningInfo *next;
994   int ret;
995   
996   ret = GNUNET_NO;
997   next = serviceListeningInfoList_head;
998   while (NULL != (pos = next))
999     {
1000       next = pos->next;
1001       if ( (serviceName != NULL) &&
1002            (strcmp (pos->serviceName, serviceName) != 0) )
1003         continue;
1004       if (pos->acceptTask != GNUNET_SCHEDULER_NO_TASK)
1005         GNUNET_SCHEDULER_cancel (pos->acceptTask);
1006       GNUNET_break (GNUNET_OK ==
1007                     GNUNET_NETWORK_socket_close (pos->listeningSocket));
1008       GNUNET_CONTAINER_DLL_remove (serviceListeningInfoList_head,
1009                                    serviceListeningInfoList_tail, 
1010                                    pos);
1011       GNUNET_free (pos->serviceName);              
1012       GNUNET_free (pos->service_addr);
1013       GNUNET_free (pos); 
1014       ret = GNUNET_OK;
1015     }
1016   return ret;
1017 }
1018
1019 /**
1020  * First connection has come to the listening socket associated with the service,
1021  * create the service in order to relay the incoming connection to it
1022  * 
1023  * @param cls callback data, struct ServiceListeningInfo describing a listen socket
1024  * @param tc context 
1025  */
1026 static void
1027 acceptConnection (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
1028
1029
1030 static void
1031 accept_and_forward (struct ServiceListeningInfo *serviceListeningInfo)
1032 {
1033   struct ForwardedConnection *fc;
1034
1035   fc = GNUNET_malloc (sizeof (struct ForwardedConnection));
1036   fc->listen_info = serviceListeningInfo;
1037   fc->service_to_client_bufferPos = fc->service_to_client_buffer;
1038   fc->client_to_service_bufferPos = fc->client_to_service_buffer;
1039   fc->client_addr_len = sizeof (fc->client_addr);
1040   fc->armClientSocket = GNUNET_NETWORK_socket_accept (serviceListeningInfo->listeningSocket,
1041                                                       (struct sockaddr*) fc->client_addr,
1042                                                       &fc->client_addr_len);
1043   if (NULL == fc->armClientSocket)
1044     {
1045       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1046                   _("Unable to accept connection for service `%s': %s\n"),
1047                   serviceListeningInfo->serviceName,
1048                   STRERROR (errno));
1049       GNUNET_free (fc);
1050       GNUNET_CONTAINER_DLL_insert (serviceListeningInfoList_head,
1051                                    serviceListeningInfoList_tail, 
1052                                    serviceListeningInfo); 
1053       serviceListeningInfo->acceptTask =
1054         GNUNET_SCHEDULER_add_read_net (
1055                                        GNUNET_TIME_UNIT_FOREVER_REL, 
1056                                        serviceListeningInfo->listeningSocket,
1057                                        &acceptConnection,
1058                                        serviceListeningInfo);
1059       return;
1060     }
1061   GNUNET_break (GNUNET_OK ==
1062                 GNUNET_NETWORK_socket_close (serviceListeningInfo->listeningSocket));
1063   start_service (NULL, serviceListeningInfo->serviceName, NULL);
1064   GNUNET_log (GNUNET_ERROR_TYPE_INFO, 
1065               _("Service `%s' started\n"),
1066               fc->listen_info->serviceName);
1067   fc->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_SERVICE_TIMEOUT);
1068   fc->back_off = GNUNET_TIME_UNIT_MILLISECONDS;
1069   fc->client_to_service_task =
1070     GNUNET_SCHEDULER_add_read_net (
1071                                    GNUNET_TIME_UNIT_FOREVER_REL,
1072                                    fc->armClientSocket,
1073                                    &receiveFromClient, fc);
1074   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == fc->start_task);
1075   fc->start_task 
1076     = GNUNET_SCHEDULER_add_now (&start_forwarding,
1077                                 fc);
1078 }
1079
1080
1081 /**
1082  * First connection has come to the listening socket associated with the service,
1083  * create the service in order to relay the incoming connection to it
1084  * 
1085  * @param cls callback data, struct ServiceListeningInfo describing a listen socket
1086  * @param tc context 
1087  */
1088 static void
1089 acceptConnection (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1090 {
1091   struct ServiceListeningInfo *sli = cls;
1092   struct ServiceListeningInfo *pos;
1093   struct ServiceListeningInfo *next;
1094   int *lsocks;
1095   unsigned int ls;
1096   int use_lsocks;
1097
1098   sli->acceptTask = GNUNET_SCHEDULER_NO_TASK;
1099   if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason))
1100     return;
1101   GNUNET_CONTAINER_DLL_remove (serviceListeningInfoList_head,
1102                                serviceListeningInfoList_tail, 
1103                                sli);  
1104 #ifndef MINGW
1105   use_lsocks = GNUNET_NO;
1106   if (GNUNET_YES == GNUNET_CONFIGURATION_have_value (cfg,
1107                                                      sli->serviceName,
1108                                                      "DISABLE_SOCKET_FORWARDING"))
1109     use_lsocks = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1110                                                        sli->serviceName,
1111                                                        "DISABLE_SOCKET_FORWARDING");
1112 #else
1113   use_lsocks = GNUNET_YES;
1114 #endif
1115   if (GNUNET_NO != use_lsocks)
1116     {
1117       accept_and_forward (sli);
1118       return;
1119     }
1120   lsocks = NULL;
1121   ls = 0;
1122   next = serviceListeningInfoList_head;
1123   while (NULL != (pos = next))
1124     {
1125       next = pos->next;
1126       if (0 == strcmp (pos->serviceName,
1127                        sli->serviceName))
1128         {
1129           GNUNET_array_append (lsocks, ls, 
1130                                GNUNET_NETWORK_get_fd (pos->listeningSocket));     
1131           GNUNET_free (pos->listeningSocket); /* deliberately no closing! */
1132           GNUNET_free (pos->service_addr);
1133           GNUNET_free (pos->serviceName);
1134           GNUNET_SCHEDULER_cancel (                                pos->acceptTask);
1135           GNUNET_CONTAINER_DLL_remove (serviceListeningInfoList_head,
1136                                        serviceListeningInfoList_tail, 
1137                                        pos);
1138           GNUNET_free (pos);
1139         }
1140     }
1141   GNUNET_array_append (lsocks, ls, 
1142                        GNUNET_NETWORK_get_fd (sli->listeningSocket));
1143   GNUNET_free (sli->listeningSocket); /* deliberately no closing! */
1144   GNUNET_free (sli->service_addr);
1145   GNUNET_array_append (lsocks, ls, -1);
1146   start_service (NULL, 
1147                  sli->serviceName,
1148                  lsocks);
1149   ls = 0;
1150   while (lsocks[ls] != -1)
1151     GNUNET_break (0 == close (lsocks[ls++]));      
1152   GNUNET_array_grow (lsocks, ls, 0);
1153   GNUNET_free (sli->serviceName);
1154   GNUNET_free (sli); 
1155 }
1156
1157
1158 /**
1159  * Creating a listening socket for each of the service's addresses and
1160  * wait for the first incoming connection to it
1161  * 
1162  * @param sa address associated with the service
1163  * @param addr_len length of sa
1164  * @param serviceName the name of the service in question
1165  */
1166 static void
1167 createListeningSocket (struct sockaddr *sa, 
1168                        socklen_t addr_len,
1169                        const char *serviceName)
1170 {
1171   const static int on = 1;
1172   struct GNUNET_NETWORK_Handle *sock;
1173   struct ServiceListeningInfo *serviceListeningInfo;
1174
1175   switch (sa->sa_family)
1176     {
1177     case AF_INET:
1178       sock = GNUNET_NETWORK_socket_create (PF_INET, SOCK_STREAM, 0);
1179       break;
1180     case AF_INET6:
1181       sock = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
1182       break;
1183     case AF_UNIX:
1184       sock = GNUNET_NETWORK_socket_create (PF_UNIX, SOCK_STREAM, 0);
1185       break;
1186     default:
1187       GNUNET_break (0);
1188       sock = NULL;
1189       errno = EAFNOSUPPORT;
1190       break;
1191     }
1192   if (NULL == sock)
1193     {
1194       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1195                   _("Unable to create socket for service `%s': %s\n"),
1196                   serviceName,
1197                   STRERROR (errno));
1198       GNUNET_free (sa);
1199       return;
1200     }
1201   if (GNUNET_NETWORK_socket_setsockopt
1202       (sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) != GNUNET_OK)
1203     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1204                          "setsockopt");
1205 #ifdef IPV6_V6ONLY
1206   if ( (sa->sa_family == AF_INET6) &&
1207        (GNUNET_NETWORK_socket_setsockopt
1208         (sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof (on)) != GNUNET_OK))
1209     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1210                          "setsockopt");
1211 #endif
1212
1213   if (GNUNET_NETWORK_socket_bind
1214       (sock, (const struct sockaddr *) sa, addr_len) != GNUNET_OK)
1215     {
1216       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1217                   _("Unable to bind listening socket for service `%s' to address `%s': %s\n"),
1218                   serviceName,
1219                   GNUNET_a2s (sa, addr_len),
1220                   STRERROR (errno));
1221       GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
1222       GNUNET_free (sa);
1223       return;
1224     }
1225   if (GNUNET_NETWORK_socket_listen (sock, 5) != GNUNET_OK)
1226     {
1227       GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
1228                            "listen");
1229       GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
1230       GNUNET_free (sa);
1231       return;
1232     }
1233   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1234               _("ARM now monitors connections to service `%s' at `%s'\n"),
1235               serviceName,
1236               GNUNET_a2s (sa, addr_len));
1237   serviceListeningInfo = GNUNET_malloc (sizeof (struct ServiceListeningInfo));
1238   serviceListeningInfo->serviceName = GNUNET_strdup (serviceName);
1239   serviceListeningInfo->service_addr = sa;
1240   serviceListeningInfo->service_addr_len = addr_len;
1241   serviceListeningInfo->listeningSocket = sock;
1242   serviceListeningInfo->acceptTask =
1243     GNUNET_SCHEDULER_add_read_net (
1244                                    GNUNET_TIME_UNIT_FOREVER_REL, sock,
1245                                    &acceptConnection,
1246                                    serviceListeningInfo);
1247   GNUNET_CONTAINER_DLL_insert (serviceListeningInfoList_head,
1248                                serviceListeningInfoList_tail,
1249                                serviceListeningInfo);
1250 }
1251
1252
1253 /**
1254  * Callback function, checks whether the current tokens are representing a service,
1255  * gets its addresses and create listening socket for it.
1256  * 
1257  * @param cls callback data, not used
1258  * @param section configuration section
1259  * @param option configuration option
1260  * @param value the option's value
1261  */
1262 static void
1263 checkPortNumberCB (void *cls,
1264                    const char *section, 
1265                    const char *option, 
1266                    const char *value)
1267 {
1268   struct sockaddr **addrs;
1269   socklen_t *addr_lens;
1270   int ret;
1271   unsigned int i;
1272   
1273   if ( (strcasecmp (section, "arm") == 0) ||
1274        (strcasecmp (option, "AUTOSTART") != 0) ||
1275        (strcasecmp (value, "YES") != 0) ||
1276        (isInDefaultList (section) == GNUNET_YES) )
1277     return;
1278   if (0 >= (ret = GNUNET_SERVICE_get_server_addresses (section, cfg, &addrs,
1279                                                        &addr_lens)))
1280     return;
1281   /* this will free (or capture) addrs[i] */
1282   for (i = 0; i < ret; i++)
1283     createListeningSocket (addrs[i], addr_lens[i], section);
1284   GNUNET_free (addrs);
1285   GNUNET_free (addr_lens);
1286 }
1287
1288
1289 /**
1290  * Entry point to the Service Manager
1291  *
1292  * @param configurationHandle configuration to use to get services
1293  */
1294 void
1295 prepareServices (const struct GNUNET_CONFIGURATION_Handle
1296                  *configurationHandle)
1297 {
1298   char *defaultServicesString;
1299
1300   cfg = configurationHandle;
1301   /* Split the default services into a list */
1302   if (GNUNET_OK ==
1303       GNUNET_CONFIGURATION_get_value_string (cfg, "arm", "DEFAULTSERVICES",
1304                                              &defaultServicesString))
1305     {
1306       addDefaultServicesToList (defaultServicesString);
1307       GNUNET_free (defaultServicesString);    
1308     }
1309   /* Spot the services from the configuration and create a listening
1310      socket for each */
1311   GNUNET_CONFIGURATION_iterate (cfg, &checkPortNumberCB, NULL);
1312 }
1313
1314 /* end of gnunet-service-arm_interceptor.c */