aboutsummaryrefslogtreecommitdiff
path: root/src/arm/gnunet-service-manager.c
diff options
context:
space:
mode:
authorSafey A.Halim <safey.allah@gmail.com>2010-05-10 11:33:03 +0000
committerSafey A.Halim <safey.allah@gmail.com>2010-05-10 11:33:03 +0000
commitbaecca71c8fca88ec3f9db55140861d3dddff9e9 (patch)
tree7bacdcd87f7bcd0692862e58769ce8473a7e375c /src/arm/gnunet-service-manager.c
parent788afbc98ba0bbb1282582a8bd127e609f80d43e (diff)
downloadgnunet-baecca71c8fca88ec3f9db55140861d3dddff9e9.tar.gz
gnunet-baecca71c8fca88ec3f9db55140861d3dddff9e9.zip
gnunet service manager creates listening sockets for services having port fields in their configuration entries and runs those services whenever clients try to connect to them
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}