aboutsummaryrefslogtreecommitdiff
path: root/src/arm/gnunet-service-manager.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/arm/gnunet-service-manager.c')
-rw-r--r--src/arm/gnunet-service-manager.c787
1 files changed, 787 insertions, 0 deletions
diff --git a/src/arm/gnunet-service-manager.c b/src/arm/gnunet-service-manager.c
new file mode 100644
index 000000000..01ede9f33
--- /dev/null
+++ b/src/arm/gnunet-service-manager.c
@@ -0,0 +1,787 @@
1/*
2 This file is part of GNUnet.
3 (C) 2009 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 2, 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-manager.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 * @author Safey Abdel Halim
27 */
28
29#include "platform.h"
30#include "gnunet_service_lib.h"
31#include "gnunet_configuration_lib.h"
32#include "gnunet_client_lib.h"
33#include "gnunet_container_lib.h"
34#include "gnunet_service_arm_.h"
35
36
37#define DEBUG_SERVICE_MANAGER GNUNET_NO
38#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10)
39#define BUFFER_SIZE (63 * 1024)
40#define REASON_CLIENT 1
41#define REASON_SERVICE 2
42
43static char **defaultServicesList;
44static int numDefaultServices = 0;
45static const struct GNUNET_CONFIGURATION_Handle *cfg;
46static struct GNUNET_SCHEDULER_Handle *scheduler;
47
48struct StartedService
49{
50 const char *serviceName;
51 struct StartedService *next;
52};
53
54static struct StartedService *startedServices = NULL;
55
56
57/* Functions prototypes */
58static void
59receiveFromClient (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
60static void
61receiveFromService (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
62
63
64struct ServiceListeningInfo
65{
66 struct ServiceListeningInfo *next;
67 struct ServiceListeningInfo *prev;
68 const char *serviceName;
69 struct sockaddr *service_addr;
70 socklen_t service_addr_len;
71 struct sockaddr client_addr;
72 socklen_t client_addr_len;
73 struct GNUNET_NETWORK_Handle *listeningSocket;
74 GNUNET_SCHEDULER_TaskIdentifier acceptTask;
75};
76
77static struct ServiceListeningInfo *serviceListeningInfoList_head;
78static struct ServiceListeningInfo *serviceListeningInfoList_tail;
79
80/**
81 * Information of the connection: client-arm-service
82 */
83struct ServiceInfo
84{
85 const char *serviceName;
86 struct GNUNET_NETWORK_Handle *armClientSocket;
87 struct GNUNET_NETWORK_Handle *armServiceSocket;
88 struct sockaddr *service_addr;
89 socklen_t service_addr_len;
90 char clientBuffer[BUFFER_SIZE];
91 ssize_t clientBufferDataLength;
92 char *clientBufferPos;
93 char serviceBuffer[BUFFER_SIZE];
94 ssize_t serviceBufferDataLength;
95 char *serviceBufferPos;
96 GNUNET_SCHEDULER_TaskIdentifier clientReceivingTask;
97 GNUNET_SCHEDULER_TaskIdentifier serviceReceivingTask;
98 GNUNET_SCHEDULER_TaskIdentifier acceptTask;
99};
100
101
102static struct ServiceInfo *
103newServiceInfo (const char *serviceName, struct sockaddr *service_addr,
104 socklen_t service_addr_len)
105{
106 struct ServiceInfo *serviceInfo =
107 GNUNET_malloc (sizeof (struct ServiceInfo));
108 serviceInfo->serviceName = serviceName;
109 serviceInfo->service_addr = service_addr;
110 serviceInfo->service_addr_len = service_addr_len;
111 serviceInfo->serviceBufferPos = serviceInfo->serviceBuffer;
112 serviceInfo->clientBufferPos = serviceInfo->clientBuffer;
113 return serviceInfo;
114}
115
116
117static struct ServiceListeningInfo *
118newServiceListeningInfo (const char *serviceName,
119 struct sockaddr *sa, socklen_t service_addr_len,
120 struct GNUNET_NETWORK_Handle *listeningSocket)
121{
122 struct ServiceListeningInfo *serviceListeningInfo =
123 GNUNET_malloc (sizeof (struct ServiceListeningInfo));
124
125 serviceListeningInfo->client_addr_len =
126 sizeof (serviceListeningInfo->client_addr);
127 serviceListeningInfo->serviceName = serviceName;
128 serviceListeningInfo->service_addr = sa;
129 serviceListeningInfo->service_addr_len = service_addr_len;
130 serviceListeningInfo->listeningSocket = listeningSocket;
131 GNUNET_CONTAINER_DLL_insert (serviceListeningInfoList_head,
132 serviceListeningInfoList_tail,
133 serviceListeningInfo);
134 return serviceListeningInfo;
135}
136
137
138#if DEBUG_SERVICE_MANAGER
139static void
140printDefaultServicesList ()
141{
142 int i;
143 for (i = 0; i < numDefaultServices; i++)
144 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Service: %s\n",
145 defaultServicesList[i]);
146}
147#endif
148
149
150/**
151 * Put the default services represented by a space separated string into an array of strings
152 *
153 * @param services space separated string of default services
154 */
155static void
156addDefaultServicesToList (char *services)
157{
158 int i = 0;
159 char *token;
160
161 /* How many services are there */
162 while (services[i] != '\0')
163 {
164 if (services[i] == ' ')
165 {
166 numDefaultServices++;
167 }
168 i++;
169 }
170 numDefaultServices++;
171 defaultServicesList = GNUNET_malloc (numDefaultServices * sizeof (char *));
172 token = strtok ((char *) services, " ");
173
174 i = 0;
175 while (NULL != token)
176 {
177 defaultServicesList[i++] = token;
178 token = strtok (NULL, " ");
179 }
180}
181
182/**
183 * Checks whether the serviceName is in the list of default services
184 *
185 * @param serviceName string to check its existance in the list
186 */
187static int
188isInDefaultList (const char *serviceName)
189{
190 int i;
191 for (i = 0; i < numDefaultServices; i++)
192 {
193 if (strcmp (serviceName, defaultServicesList[i]) == 0)
194 return GNUNET_YES;
195 }
196 return GNUNET_NO;
197}
198
199
200static int
201isServiceAlreadyStarted (const char *serviceName)
202{
203 struct StartedService *service;
204 service = startedServices;
205 while (NULL != service)
206 {
207 if (strcmp (service->serviceName, serviceName) == 0)
208 return GNUNET_OK;
209 service = service->next;
210 }
211 return GNUNET_NO;
212}
213
214
215static void
216setStartedService (const char *serviceName)
217{
218 if (startedServices == NULL)
219 {
220 startedServices = GNUNET_malloc (sizeof (struct StartedService));
221 startedServices->serviceName = GNUNET_strdup (serviceName);
222 startedServices->next = NULL;
223 }
224 else
225 {
226 struct StartedService *service =
227 GNUNET_malloc (sizeof (struct StartedService));
228 service->serviceName = GNUNET_strdup (serviceName);
229 service->next = startedServices;
230 startedServices = service;
231 }
232}
233
234
235static void
236closeClientAndServiceSockets (struct ServiceInfo *serviceInfo, int reason)
237{
238 if (NULL != serviceInfo->armClientSocket)
239 {
240 if (0 != (REASON_SERVICE & reason))
241 GNUNET_SCHEDULER_cancel (scheduler, serviceInfo->clientReceivingTask);
242 if (GNUNET_SYSERR ==
243 GNUNET_NETWORK_socket_close (serviceInfo->armClientSocket))
244 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "close");
245 serviceInfo->armClientSocket = NULL;
246 }
247 if (NULL != serviceInfo->armServiceSocket)
248 {
249 if (0 != (REASON_CLIENT & reason))
250 GNUNET_SCHEDULER_cancel (scheduler,
251 serviceInfo->serviceReceivingTask);
252
253 if (GNUNET_SYSERR ==
254 GNUNET_NETWORK_socket_close (serviceInfo->armServiceSocket))
255 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "close");
256 serviceInfo->armServiceSocket = NULL;
257 }
258
259 GNUNET_free (serviceInfo);
260}
261
262
263/**
264 * Forward messages sent from service to client
265 *
266 * @param cls callback data, for the communication between client and service
267 * @param tc context
268 */
269static void
270forwardToClient (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
271{
272 struct ServiceInfo *serviceInfo = cls;
273 ssize_t numberOfBytesSent;
274
275 if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason))
276 {
277 /* Ignore shutdown signal, reschedule yourself */
278 GNUNET_SCHEDULER_add_write_net (scheduler, GNUNET_TIME_UNIT_FOREVER_REL,
279 serviceInfo->armClientSocket,
280 &forwardToClient, serviceInfo);
281 return;
282 }
283
284 /* Forwarding service response to client */
285 numberOfBytesSent =
286 GNUNET_NETWORK_socket_send (serviceInfo->armClientSocket,
287 serviceInfo->serviceBufferPos,
288 serviceInfo->serviceBufferDataLength);
289 if ((numberOfBytesSent == GNUNET_SYSERR) || (numberOfBytesSent == 0))
290 {
291 /* Error occured or connection closed by client */
292 closeClientAndServiceSockets (serviceInfo,
293 (REASON_CLIENT & REASON_SERVICE));
294 return;
295 }
296 else if (numberOfBytesSent < serviceInfo->serviceBufferDataLength)
297 {
298 /* Not all service data were sent to client */
299 serviceInfo->serviceBufferPos += numberOfBytesSent;
300 serviceInfo->serviceBufferDataLength =
301 serviceInfo->serviceBufferDataLength - numberOfBytesSent;
302
303 /* Scheduling writing again for completing the remaining data to be sent */
304 GNUNET_SCHEDULER_add_write_net (scheduler, GNUNET_TIME_UNIT_FOREVER_REL,
305 serviceInfo->armClientSocket,
306 &forwardToClient, serviceInfo);
307 }
308 else
309 {
310 /* Data completely sent */
311 serviceInfo->serviceBufferPos = serviceInfo->serviceBuffer;
312 }
313
314 /* Now we are ready to receive more data, rescheduling receiving from Service */
315 serviceInfo->serviceReceivingTask =
316 GNUNET_SCHEDULER_add_read_net (scheduler, GNUNET_TIME_UNIT_FOREVER_REL,
317 serviceInfo->armServiceSocket,
318 &receiveFromService, serviceInfo);
319}
320
321
322/**
323 * Receive service messages sent by the service and forward it to client
324 *
325 * @param cls callback data, serviceInfo struct for the communication between client and service
326 * @param tc context
327 */
328static void
329receiveFromService (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
330{
331
332 struct ServiceInfo *serviceInfo = cls;
333
334 if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason))
335 {
336 /* Neglect shutdown signal, reschedule yourself */
337 serviceInfo->serviceReceivingTask =
338 GNUNET_SCHEDULER_add_read_net (scheduler,
339 GNUNET_TIME_UNIT_FOREVER_REL,
340 serviceInfo->armServiceSocket,
341 &receiveFromService, serviceInfo);
342 return;
343 }
344
345 serviceInfo->serviceBufferDataLength =
346 GNUNET_NETWORK_socket_recv (serviceInfo->armServiceSocket,
347 serviceInfo->serviceBuffer, BUFFER_SIZE);
348
349 if (serviceInfo->serviceBufferDataLength <= 0)
350 {
351 /* The service has closed the connection or an error occured */
352 if (serviceInfo->serviceBufferDataLength == 0)
353 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
354 _("Service `%s' closed connection! \n"),
355 serviceInfo->serviceName);
356 else
357 {
358 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
359 _("Error receiving from service:%d\n"), errno);
360 }
361 closeClientAndServiceSockets (serviceInfo, REASON_SERVICE);
362 return;
363 }
364
365 /* Forwarding Service data to Client */
366 GNUNET_SCHEDULER_add_write_net (scheduler, GNUNET_TIME_UNIT_FOREVER_REL,
367 serviceInfo->armClientSocket,
368 &forwardToClient, serviceInfo);
369}
370
371
372/**
373 * Forward client message to service
374 *
375 * @param cls callback data, serviceInfo struct for the communication between client and service
376 * @param tc context
377 */
378static void
379forwardToService (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
380{
381 struct ServiceInfo *serviceInfo = cls;
382 ssize_t numberOfBytesSent;
383
384 if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason))
385 {
386 /* Neglect shutdown signal, reschedule yourself */
387 GNUNET_SCHEDULER_add_write_net (scheduler, GNUNET_TIME_UNIT_FOREVER_REL,
388 serviceInfo->armServiceSocket,
389 &forwardToService, serviceInfo);
390 return;
391 }
392
393
394 /* Forwarding client's message to service */
395 numberOfBytesSent =
396 GNUNET_NETWORK_socket_send (serviceInfo->armServiceSocket,
397 serviceInfo->clientBufferPos,
398 serviceInfo->clientBufferDataLength);
399 if ((numberOfBytesSent == GNUNET_SYSERR) || (numberOfBytesSent == 0))
400 {
401 /* Error occured or connection closed by service */
402 closeClientAndServiceSockets (serviceInfo,
403 (REASON_CLIENT & REASON_SERVICE));
404 return;
405 }
406 else if (numberOfBytesSent < serviceInfo->clientBufferDataLength)
407 {
408 /* Not all client data were sent to the service */
409 serviceInfo->clientBufferPos += numberOfBytesSent;
410 serviceInfo->clientBufferDataLength =
411 serviceInfo->clientBufferDataLength - numberOfBytesSent;
412
413 /* Scheduling writing again for completing the remaining data to be sent */
414 GNUNET_SCHEDULER_add_write_net (scheduler, GNUNET_TIME_UNIT_FOREVER_REL,
415 serviceInfo->armServiceSocket,
416 &forwardToService, serviceInfo);
417 }
418 else
419 {
420 /* Data completely sent */
421 serviceInfo->clientBufferPos = serviceInfo->clientBuffer;
422 }
423
424 /* Now, we are ready to receive more data. Rescheduling the receiving from client */
425 serviceInfo->clientReceivingTask =
426 GNUNET_SCHEDULER_add_read_net (scheduler, GNUNET_TIME_UNIT_FOREVER_REL,
427 serviceInfo->armClientSocket,
428 &receiveFromClient, serviceInfo);
429}
430
431
432
433/**
434 * Message sent from client to service (faked by ARM, since it's the first connection),
435 * ARM will receive the message and forward it to the running service
436 *
437 * @param cls callback data, serviceInfo struct for the communication between client and service
438 * @param tc context
439 */
440static void
441receiveFromClient (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
442{
443 struct ServiceInfo *serviceInfo = cls;
444
445 if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason))
446 {
447 /* Neglect the shutdown signal, schedule yourself */
448 serviceInfo->clientReceivingTask =
449 GNUNET_SCHEDULER_add_read_net (scheduler,
450 GNUNET_TIME_UNIT_FOREVER_REL,
451 serviceInfo->armClientSocket,
452 &receiveFromClient, serviceInfo);
453 return;
454 }
455
456 /* Receive client's message */
457 serviceInfo->clientBufferDataLength =
458 GNUNET_NETWORK_socket_recv (serviceInfo->armClientSocket,
459 serviceInfo->clientBuffer, BUFFER_SIZE);
460
461 if (serviceInfo->clientBufferDataLength <= 0)
462 {
463 /* The client has closed the connection or and error occured */
464 if (serviceInfo->clientBufferDataLength == 0)
465 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
466 _("Client closed connection with service:`%s'\n"),
467 serviceInfo->serviceName);
468 else
469 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
470 _("Error receiving from client!:%d \n"), errno);
471 closeClientAndServiceSockets (serviceInfo, REASON_CLIENT);
472 return;
473 }
474
475 /* Forwarding request to service */
476 GNUNET_SCHEDULER_add_write_net (scheduler, GNUNET_TIME_UNIT_FOREVER_REL,
477 serviceInfo->armServiceSocket,
478 &forwardToService, serviceInfo);
479}
480
481
482/**
483 * ARM connects to the just created service,
484 * starts the processes for relaying messages between the client and the service
485 *
486 * @param cls callback data, serviceInfo struct for the communication between client and service
487 * @param tc context
488 */
489static void
490connectToService (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
491{
492 struct ServiceInfo *serviceInfo = cls;
493
494 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_TIMEOUT))
495 {
496 /* Service is not up. Unable to proceed */
497 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
498 _("Unable to start service `%s': timeout\n"),
499 serviceInfo->serviceName);
500 closeClientAndServiceSockets (serviceInfo,
501 (REASON_CLIENT & REASON_SERVICE));
502 return;
503 }
504 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
505 {
506 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
507 _("Unable to start service `%s': shutdown\n"),
508 serviceInfo->serviceName);
509 closeClientAndServiceSockets (serviceInfo,
510 (REASON_CLIENT & REASON_SERVICE));
511 return;
512 }
513 GNUNET_break (0 != (tc->reason & GNUNET_SCHEDULER_REASON_PREREQ_DONE));
514 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Service `%s' started\n"),
515 serviceInfo->serviceName);
516
517 /* Now service is up and running, connect to it */
518 serviceInfo->armServiceSocket =
519 GNUNET_NETWORK_socket_create (serviceInfo->service_addr->sa_family,
520 SOCK_STREAM, 0);
521 if (NULL == serviceInfo->armServiceSocket)
522 {
523 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
524 _
525 ("Unable to start service `%s': failed to create socket\n"),
526 serviceInfo->serviceName);
527 closeClientAndServiceSockets (serviceInfo,
528 (REASON_CLIENT & REASON_SERVICE));
529 return;
530 }
531
532 if ((GNUNET_SYSERR ==
533 GNUNET_NETWORK_socket_connect (serviceInfo->armServiceSocket,
534 serviceInfo->service_addr,
535 serviceInfo->service_addr_len))
536 && (EINPROGRESS != errno))
537 {
538 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
539 _("Unable to start service `%s': failed to connect\n"),
540 serviceInfo->serviceName);
541 closeClientAndServiceSockets (serviceInfo,
542 (REASON_CLIENT & REASON_SERVICE));
543 return;
544 }
545 /* Handling requests from client to service */
546 serviceInfo->clientReceivingTask =
547 GNUNET_SCHEDULER_add_read_net (scheduler, GNUNET_TIME_UNIT_FOREVER_REL,
548 serviceInfo->armClientSocket,
549 &receiveFromClient, serviceInfo);
550
551 /* Handling service responses to client */
552 serviceInfo->serviceReceivingTask =
553 GNUNET_SCHEDULER_add_read_net (scheduler, GNUNET_TIME_UNIT_FOREVER_REL,
554 serviceInfo->armServiceSocket,
555 &receiveFromService, serviceInfo);
556}
557
558
559static void
560stopServiceListeningSockets (struct ServiceListeningInfo
561 *serviceListeningInfo)
562{
563 struct ServiceListeningInfo *pos = serviceListeningInfoList_head;
564 struct ServiceListeningInfo *tmp;
565
566 while (NULL != pos)
567 {
568 if ((strcmp (pos->serviceName, serviceListeningInfo->serviceName) == 0)
569 && (pos != serviceListeningInfo))
570 {
571 GNUNET_SCHEDULER_cancel (scheduler, pos->acceptTask);
572 GNUNET_NETWORK_socket_close (pos->listeningSocket);
573 tmp = pos;
574 pos = pos->next;
575 GNUNET_CONTAINER_DLL_remove (serviceListeningInfoList_head,
576 serviceListeningInfoList_tail, tmp);
577 GNUNET_free (tmp->service_addr);
578 GNUNET_free (tmp);
579 continue;
580 }
581 pos = pos->next;
582 }
583}
584
585
586/**
587 * First connection has come to the listening socket associated with the service,
588 * create the service in order to relay the incoming connection to it
589 *
590 * @param cls callback data, serviceInfo struct for the communication between client and service
591 * @param tc context
592 */
593static void
594acceptConnection (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
595{
596 struct ServiceListeningInfo *serviceListeningInfo = cls;
597 struct ServiceInfo *serviceInfo;
598
599 if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason))
600 return;
601
602 if ((NULL == startedServices)
603 || (GNUNET_NO ==
604 isServiceAlreadyStarted (serviceListeningInfo->serviceName)))
605 {
606 /* First request to receive at all, or first request to connect to that service */
607 /* Accept client's connection */
608 serviceInfo =
609 newServiceInfo (serviceListeningInfo->serviceName,
610 serviceListeningInfo->service_addr,
611 serviceListeningInfo->service_addr_len);
612 serviceInfo->armClientSocket =
613 GNUNET_NETWORK_socket_accept (serviceListeningInfo->listeningSocket,
614 &(serviceListeningInfo->client_addr),
615 &(serviceListeningInfo->
616 client_addr_len));
617 if (NULL == serviceInfo->armClientSocket)
618 {
619 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
620 _
621 ("Unable to accept connection for service `%s': Invalid socket\n"),
622 serviceListeningInfo->serviceName);
623 return;
624 }
625
626
627 /*
628 * Close listening socket, start service,
629 * and stop all listening sockets associated with that service
630 * and free their correspondent ServiceInfo objects
631 */
632 GNUNET_NETWORK_socket_close (serviceListeningInfo->listeningSocket);
633 start_service (NULL, serviceListeningInfo->serviceName);
634 setStartedService (serviceListeningInfo->serviceName);
635 stopServiceListeningSockets (serviceListeningInfo);
636
637 /* Notify me when the service is up and running */
638 GNUNET_CLIENT_service_test (scheduler,
639 serviceListeningInfo->serviceName, cfg,
640 TIMEOUT, &connectToService, serviceInfo);
641 }
642}
643
644
645/**
646 * Creating a listening socket for each of the service's addresses and wait for the first incoming connection to it
647 *
648 * @param addrs list of addresses associated with the service
649 * @param addr_lens list containing length for each of the addresses in addrs
650 * @param numOfAddresses length of the addr_lens array
651 * @param serviceName the name of the service in question
652 */
653static void
654createListeningSocket (struct sockaddr **addrs, socklen_t * addr_lens,
655 int numOfAddresses, char *serviceName)
656{
657 int i;
658 struct GNUNET_NETWORK_Handle *socket;
659 struct sockaddr *sa;
660 socklen_t addr_len;
661 struct ServiceListeningInfo *serviceListeningInfo;
662
663 for (i = 0; i < numOfAddresses; i++)
664 {
665 sa = addrs[i];
666 addr_len = addr_lens[i];
667 switch (sa->sa_family)
668 {
669 case AF_INET:
670 socket = GNUNET_NETWORK_socket_create (PF_INET, SOCK_STREAM, 0);
671 break;
672 case AF_INET6:
673 socket = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
674 break;
675 default:
676 socket = NULL;
677 break;
678 }
679 if (NULL == socket)
680 {
681 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
682 "Unable to create socket for service %s", serviceName);
683 continue;
684 }
685
686 /* Bind */
687 if (GNUNET_NETWORK_socket_bind
688 (socket, (const struct sockaddr *) sa, addr_len) != GNUNET_OK)
689 {
690 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
691 _("Unable to bind listening socket for service `%s'\n"),
692 serviceName);
693 continue;
694 }
695
696 /* Listen */
697 if (GNUNET_NETWORK_socket_listen (socket, 5) != GNUNET_OK)
698 {
699 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
700 _("Error listening socket for service `%s'\n"),
701 serviceName);
702 }
703
704 serviceListeningInfo =
705 newServiceListeningInfo (serviceName, sa, addr_len, socket);
706 serviceListeningInfo->listeningSocket = socket;
707 serviceListeningInfo->serviceName = serviceName;
708 serviceListeningInfo->service_addr = sa;
709 serviceListeningInfo->service_addr_len = addr_len;
710
711 /* Wait for the first incoming connection */
712 serviceListeningInfo->acceptTask =
713 GNUNET_SCHEDULER_add_read_net (scheduler,
714 GNUNET_TIME_UNIT_FOREVER_REL, socket,
715 &acceptConnection,
716 serviceListeningInfo);
717 }
718}
719
720/**
721 * Callback function, checks whether the current tokens are representing a service,
722 * gets its addresses and create listening socket for it.
723 *
724 * @param cls callback data, not used
725 * @param section configuration section
726 * @param option configuration option
727 * @param the option's value
728 */
729static void
730checkPortNumberCB (void *cls,
731 const char *section, const char *option, const char *value)
732{
733 /* The service shouldn't be a default service */
734 if ((strcmp (section, "arm") != 0)
735 && (strcmp (option, "PORT") == 0)
736 && (isInDefaultList (section) == GNUNET_NO))
737 {
738 /* then the section is representing a service */
739 struct sockaddr **addrs;
740 socklen_t *addr_lens;
741 int ret;
742
743 ret =
744 GNUNET_SERVICE_get_server_addresses (section, cfg, &addrs,
745 &addr_lens);
746 if (ret == GNUNET_SYSERR)
747 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
748 _("Unable to resolve host name for service `%s'\n"),
749 section);
750 else if (ret != GNUNET_NO)
751 {
752 /* Addresses found for service */
753 createListeningSocket (addrs, addr_lens, ret, (char *) section);
754 }
755 else
756 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
757 _("No addresses for service `%s' in configuration\n"),
758 section);
759 }
760}
761
762/**
763 * Entry point to the Service Manager
764 *
765 * @param configurationHandle configuration to use to get services
766 * @param sched scheduler to handle clients and services communications
767 */
768void
769prepareServices (const struct GNUNET_CONFIGURATION_Handle
770 *configurationHandle, struct GNUNET_SCHEDULER_Handle *sched)
771{
772 char *defaultServicesString;
773 scheduler = sched;
774 cfg = configurationHandle;
775
776 /* Split the default services into a list */
777 GNUNET_CONFIGURATION_get_value_string (cfg, "arm", "DEFAULTSERVICES",
778 &defaultServicesString);
779 addDefaultServicesToList (defaultServicesString);
780
781#if DEBUG_SERVICE_MANAGER
782 printDefaultServicesList ();
783#endif
784
785 /* Spot the services from the configuration and create a listening socket for each */
786 GNUNET_CONFIGURATION_iterate (cfg, &checkPortNumberCB, NULL);
787}