diff options
Diffstat (limited to 'src/transport/tcp_service_legacy.c')
-rw-r--r-- | src/transport/tcp_service_legacy.c | 1646 |
1 files changed, 0 insertions, 1646 deletions
diff --git a/src/transport/tcp_service_legacy.c b/src/transport/tcp_service_legacy.c deleted file mode 100644 index 8606b353b..000000000 --- a/src/transport/tcp_service_legacy.c +++ /dev/null | |||
@@ -1,1646 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2009, 2012 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your 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 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file util/service.c | ||
23 | * @brief functions related to starting services | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #include "platform.h" | ||
27 | #include "gnunet_util_lib.h" | ||
28 | #include "gnunet_protocols.h" | ||
29 | #include "gnunet_constants.h" | ||
30 | #include "gnunet_resolver_service.h" | ||
31 | |||
32 | #if HAVE_MALLINFO | ||
33 | #include <malloc.h> | ||
34 | #include "gauger.h" | ||
35 | #endif | ||
36 | |||
37 | |||
38 | /* ******************* access control ******************** */ | ||
39 | |||
40 | /** | ||
41 | * Check if the given IP address is in the list of IP addresses. | ||
42 | * | ||
43 | * @param list a list of networks | ||
44 | * @param add the IP to check (in network byte order) | ||
45 | * @return #GNUNET_NO if the IP is not in the list, #GNUNET_YES if it it is | ||
46 | */ | ||
47 | static int | ||
48 | check_ipv4_listed (const struct GNUNET_STRINGS_IPv4NetworkPolicy *list, | ||
49 | const struct in_addr *add) | ||
50 | { | ||
51 | unsigned int i; | ||
52 | |||
53 | if (NULL == list) | ||
54 | return GNUNET_NO; | ||
55 | i = 0; | ||
56 | while ((list[i].network.s_addr != 0) || (list[i].netmask.s_addr != 0)) | ||
57 | { | ||
58 | if ((add->s_addr & list[i].netmask.s_addr) == | ||
59 | (list[i].network.s_addr & list[i].netmask.s_addr)) | ||
60 | return GNUNET_YES; | ||
61 | i++; | ||
62 | } | ||
63 | return GNUNET_NO; | ||
64 | } | ||
65 | |||
66 | |||
67 | /** | ||
68 | * Check if the given IP address is in the list of IP addresses. | ||
69 | * | ||
70 | * @param list a list of networks | ||
71 | * @param ip the IP to check (in network byte order) | ||
72 | * @return #GNUNET_NO if the IP is not in the list, #GNUNET_YES if it it is | ||
73 | */ | ||
74 | static int | ||
75 | check_ipv6_listed (const struct GNUNET_STRINGS_IPv6NetworkPolicy *list, | ||
76 | const struct in6_addr *ip) | ||
77 | { | ||
78 | unsigned int i; | ||
79 | unsigned int j; | ||
80 | struct in6_addr zero; | ||
81 | |||
82 | if (NULL == list) | ||
83 | return GNUNET_NO; | ||
84 | memset (&zero, 0, sizeof(struct in6_addr)); | ||
85 | i = 0; | ||
86 | NEXT: | ||
87 | while (0 != memcmp (&zero, &list[i].network, sizeof(struct in6_addr))) | ||
88 | { | ||
89 | for (j = 0; j < sizeof(struct in6_addr) / sizeof(int); j++) | ||
90 | if (((((int *) ip)[j] & ((int *) &list[i].netmask)[j])) != | ||
91 | (((int *) &list[i].network)[j] & ((int *) &list[i].netmask)[j])) | ||
92 | { | ||
93 | i++; | ||
94 | goto NEXT; | ||
95 | } | ||
96 | return GNUNET_YES; | ||
97 | } | ||
98 | return GNUNET_NO; | ||
99 | } | ||
100 | |||
101 | |||
102 | /* ****************** service struct ****************** */ | ||
103 | |||
104 | |||
105 | /** | ||
106 | * Context for "service_task". | ||
107 | */ | ||
108 | struct LEGACY_SERVICE_Context | ||
109 | { | ||
110 | /** | ||
111 | * Our configuration. | ||
112 | */ | ||
113 | const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
114 | |||
115 | /** | ||
116 | * Handle for the server. | ||
117 | */ | ||
118 | struct GNUNET_SERVER_Handle *server; | ||
119 | |||
120 | /** | ||
121 | * NULL-terminated array of addresses to bind to, NULL if we got pre-bound | ||
122 | * listen sockets. | ||
123 | */ | ||
124 | struct sockaddr **addrs; | ||
125 | |||
126 | /** | ||
127 | * Name of our service. | ||
128 | */ | ||
129 | const char *service_name; | ||
130 | |||
131 | /** | ||
132 | * Main service-specific task to run. | ||
133 | */ | ||
134 | LEGACY_SERVICE_Main task; | ||
135 | |||
136 | /** | ||
137 | * Closure for @e task. | ||
138 | */ | ||
139 | void *task_cls; | ||
140 | |||
141 | /** | ||
142 | * IPv4 addresses that are not allowed to connect. | ||
143 | */ | ||
144 | struct GNUNET_STRINGS_IPv4NetworkPolicy *v4_denied; | ||
145 | |||
146 | /** | ||
147 | * IPv6 addresses that are not allowed to connect. | ||
148 | */ | ||
149 | struct GNUNET_STRINGS_IPv6NetworkPolicy *v6_denied; | ||
150 | |||
151 | /** | ||
152 | * IPv4 addresses that are allowed to connect (if not | ||
153 | * set, all are allowed). | ||
154 | */ | ||
155 | struct GNUNET_STRINGS_IPv4NetworkPolicy *v4_allowed; | ||
156 | |||
157 | /** | ||
158 | * IPv6 addresses that are allowed to connect (if not | ||
159 | * set, all are allowed). | ||
160 | */ | ||
161 | struct GNUNET_STRINGS_IPv6NetworkPolicy *v6_allowed; | ||
162 | |||
163 | /** | ||
164 | * My (default) message handlers. Adjusted copy | ||
165 | * of "defhandlers". | ||
166 | */ | ||
167 | struct GNUNET_SERVER_MessageHandler *my_handlers; | ||
168 | |||
169 | /** | ||
170 | * Array of the lengths of the entries in addrs. | ||
171 | */ | ||
172 | socklen_t *addrlens; | ||
173 | |||
174 | /** | ||
175 | * NULL-terminated array of listen sockets we should take over. | ||
176 | */ | ||
177 | struct GNUNET_NETWORK_Handle **lsocks; | ||
178 | |||
179 | /** | ||
180 | * Task ID of the shutdown task. | ||
181 | */ | ||
182 | struct GNUNET_SCHEDULER_Task *shutdown_task; | ||
183 | |||
184 | /** | ||
185 | * Idle timeout for server. | ||
186 | */ | ||
187 | struct GNUNET_TIME_Relative timeout; | ||
188 | |||
189 | /** | ||
190 | * Overall success/failure of the service start. | ||
191 | */ | ||
192 | int ret; | ||
193 | |||
194 | /** | ||
195 | * If we are daemonizing, this FD is set to the | ||
196 | * pipe to the parent. Send '.' if we started | ||
197 | * ok, '!' if not. -1 if we are not daemonizing. | ||
198 | */ | ||
199 | int ready_confirm_fd; | ||
200 | |||
201 | /** | ||
202 | * Do we close connections if we receive messages | ||
203 | * for which we have no handler? | ||
204 | */ | ||
205 | int require_found; | ||
206 | |||
207 | /** | ||
208 | * Do we require a matching UID for UNIX domain socket connections? | ||
209 | * #GNUNET_NO means that the UID does not have to match (however, | ||
210 | * @e match_gid may still impose other access control checks). | ||
211 | */ | ||
212 | int match_uid; | ||
213 | |||
214 | /** | ||
215 | * Do we require a matching GID for UNIX domain socket connections? | ||
216 | * Ignored if @e match_uid is #GNUNET_YES. Note that this is about | ||
217 | * checking that the client's UID is in our group OR that the | ||
218 | * client's GID is our GID. If both "match_gid" and @e match_uid are | ||
219 | * #GNUNET_NO, all users on the local system have access. | ||
220 | */ | ||
221 | int match_gid; | ||
222 | |||
223 | /** | ||
224 | * Our options. | ||
225 | */ | ||
226 | enum LEGACY_SERVICE_Options options; | ||
227 | }; | ||
228 | |||
229 | |||
230 | /* ****************** message handlers ****************** */ | ||
231 | |||
232 | /** | ||
233 | * Send a 'TEST' message back to the client. | ||
234 | * | ||
235 | * @param cls the 'struct GNUNET_SERVER_Client' to send TEST to | ||
236 | * @param size number of bytes available in 'buf' | ||
237 | * @param buf where to copy the message | ||
238 | * @return number of bytes written to 'buf' | ||
239 | */ | ||
240 | static size_t | ||
241 | write_test (void *cls, size_t size, void *buf) | ||
242 | { | ||
243 | struct GNUNET_SERVER_Client *client = cls; | ||
244 | struct GNUNET_MessageHeader *msg; | ||
245 | |||
246 | if (size < sizeof(struct GNUNET_MessageHeader)) | ||
247 | { | ||
248 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
249 | return 0; /* client disconnected */ | ||
250 | } | ||
251 | msg = (struct GNUNET_MessageHeader *) buf; | ||
252 | msg->type = htons (GNUNET_MESSAGE_TYPE_TEST); | ||
253 | msg->size = htons (sizeof(struct GNUNET_MessageHeader)); | ||
254 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
255 | return sizeof(struct GNUNET_MessageHeader); | ||
256 | } | ||
257 | |||
258 | |||
259 | /** | ||
260 | * Handler for TEST message. | ||
261 | * | ||
262 | * @param cls closure (refers to service) | ||
263 | * @param client identification of the client | ||
264 | * @param message the actual message | ||
265 | */ | ||
266 | static void | ||
267 | handle_test (void *cls, | ||
268 | struct GNUNET_SERVER_Client *client, | ||
269 | const struct GNUNET_MessageHeader *message) | ||
270 | { | ||
271 | /* simply bounce message back to acknowledge */ | ||
272 | if (NULL == | ||
273 | GNUNET_SERVER_notify_transmit_ready (client, | ||
274 | sizeof(struct GNUNET_MessageHeader), | ||
275 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
276 | &write_test, | ||
277 | client)) | ||
278 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
279 | } | ||
280 | |||
281 | |||
282 | /** | ||
283 | * Default handlers for all services. Will be copied and the | ||
284 | * "callback_cls" fields will be replaced with the specific service | ||
285 | * struct. | ||
286 | */ | ||
287 | static const struct GNUNET_SERVER_MessageHandler defhandlers[] = | ||
288 | { { &handle_test, | ||
289 | NULL, | ||
290 | GNUNET_MESSAGE_TYPE_TEST, | ||
291 | sizeof(struct GNUNET_MessageHeader) }, | ||
292 | { NULL, NULL, 0, 0 } }; | ||
293 | |||
294 | |||
295 | /* ****************** service core routines ************** */ | ||
296 | |||
297 | |||
298 | /** | ||
299 | * Check if access to the service is allowed from the given address. | ||
300 | * | ||
301 | * @param cls closure | ||
302 | * @param uc credentials, if available, otherwise NULL | ||
303 | * @param addr address | ||
304 | * @param addrlen length of address | ||
305 | * @return #GNUNET_YES to allow, #GNUNET_NO to deny, #GNUNET_SYSERR | ||
306 | * for unknown address family (will be denied). | ||
307 | */ | ||
308 | static int | ||
309 | check_access (void *cls, | ||
310 | const struct GNUNET_CONNECTION_Credentials *uc, | ||
311 | const struct sockaddr *addr, | ||
312 | socklen_t addrlen) | ||
313 | { | ||
314 | struct LEGACY_SERVICE_Context *sctx = cls; | ||
315 | const struct sockaddr_in *i4; | ||
316 | const struct sockaddr_in6 *i6; | ||
317 | int ret; | ||
318 | |||
319 | switch (addr->sa_family) | ||
320 | { | ||
321 | case AF_INET: | ||
322 | GNUNET_assert (addrlen == sizeof(struct sockaddr_in)); | ||
323 | i4 = (const struct sockaddr_in *) addr; | ||
324 | ret = ((NULL == sctx->v4_allowed) || | ||
325 | (check_ipv4_listed (sctx->v4_allowed, &i4->sin_addr))) && | ||
326 | ((NULL == sctx->v4_denied) || | ||
327 | (! check_ipv4_listed (sctx->v4_denied, &i4->sin_addr))); | ||
328 | break; | ||
329 | |||
330 | case AF_INET6: | ||
331 | GNUNET_assert (addrlen == sizeof(struct sockaddr_in6)); | ||
332 | i6 = (const struct sockaddr_in6 *) addr; | ||
333 | ret = ((NULL == sctx->v6_allowed) || | ||
334 | (check_ipv6_listed (sctx->v6_allowed, &i6->sin6_addr))) && | ||
335 | ((NULL == sctx->v6_denied) || | ||
336 | (! check_ipv6_listed (sctx->v6_denied, &i6->sin6_addr))); | ||
337 | break; | ||
338 | |||
339 | case AF_UNIX: | ||
340 | ret = GNUNET_OK; /* controlled using file-system ACL now */ | ||
341 | break; | ||
342 | |||
343 | default: | ||
344 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
345 | _ ("Unknown address family %d\n"), | ||
346 | addr->sa_family); | ||
347 | return GNUNET_SYSERR; | ||
348 | } | ||
349 | if (GNUNET_OK != ret) | ||
350 | { | ||
351 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
352 | _ ("Access from `%s' denied to service `%s'\n"), | ||
353 | GNUNET_a2s (addr, addrlen), | ||
354 | sctx->service_name); | ||
355 | } | ||
356 | return ret; | ||
357 | } | ||
358 | |||
359 | |||
360 | /** | ||
361 | * Get the name of the file where we will | ||
362 | * write the PID of the service. | ||
363 | * | ||
364 | * @param sctx service context | ||
365 | * @return name of the file for the process ID | ||
366 | */ | ||
367 | static char * | ||
368 | get_pid_file_name (struct LEGACY_SERVICE_Context *sctx) | ||
369 | { | ||
370 | char *pif; | ||
371 | |||
372 | if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (sctx->cfg, | ||
373 | sctx->service_name, | ||
374 | "PIDFILE", | ||
375 | &pif)) | ||
376 | return NULL; | ||
377 | return pif; | ||
378 | } | ||
379 | |||
380 | |||
381 | /** | ||
382 | * Parse an IPv4 access control list. | ||
383 | * | ||
384 | * @param ret location where to write the ACL (set) | ||
385 | * @param sctx service context to use to get the configuration | ||
386 | * @param option name of the ACL option to parse | ||
387 | * @return #GNUNET_SYSERR on parse error, #GNUNET_OK on success (including | ||
388 | * no ACL configured) | ||
389 | */ | ||
390 | static int | ||
391 | process_acl4 (struct GNUNET_STRINGS_IPv4NetworkPolicy **ret, | ||
392 | struct LEGACY_SERVICE_Context *sctx, | ||
393 | const char *option) | ||
394 | { | ||
395 | char *opt; | ||
396 | |||
397 | if (! GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name, option)) | ||
398 | { | ||
399 | *ret = NULL; | ||
400 | return GNUNET_OK; | ||
401 | } | ||
402 | GNUNET_break (GNUNET_OK == | ||
403 | GNUNET_CONFIGURATION_get_value_string (sctx->cfg, | ||
404 | sctx->service_name, | ||
405 | option, | ||
406 | &opt)); | ||
407 | if (NULL == (*ret = GNUNET_STRINGS_parse_ipv4_policy (opt))) | ||
408 | { | ||
409 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
410 | _ ("Could not parse IPv4 network specification `%s' for `%s:%s'\n"), | ||
411 | opt, | ||
412 | sctx->service_name, | ||
413 | option); | ||
414 | GNUNET_free (opt); | ||
415 | return GNUNET_SYSERR; | ||
416 | } | ||
417 | GNUNET_free (opt); | ||
418 | return GNUNET_OK; | ||
419 | } | ||
420 | |||
421 | |||
422 | /** | ||
423 | * Parse an IPv6 access control list. | ||
424 | * | ||
425 | * @param ret location where to write the ACL (set) | ||
426 | * @param sctx service context to use to get the configuration | ||
427 | * @param option name of the ACL option to parse | ||
428 | * @return #GNUNET_SYSERR on parse error, #GNUNET_OK on success (including | ||
429 | * no ACL configured) | ||
430 | */ | ||
431 | static int | ||
432 | process_acl6 (struct GNUNET_STRINGS_IPv6NetworkPolicy **ret, | ||
433 | struct LEGACY_SERVICE_Context *sctx, | ||
434 | const char *option) | ||
435 | { | ||
436 | char *opt; | ||
437 | |||
438 | if (! GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name, option)) | ||
439 | { | ||
440 | *ret = NULL; | ||
441 | return GNUNET_OK; | ||
442 | } | ||
443 | GNUNET_break (GNUNET_OK == | ||
444 | GNUNET_CONFIGURATION_get_value_string (sctx->cfg, | ||
445 | sctx->service_name, | ||
446 | option, | ||
447 | &opt)); | ||
448 | if (NULL == (*ret = GNUNET_STRINGS_parse_ipv6_policy (opt))) | ||
449 | { | ||
450 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
451 | _ ("Could not parse IPv6 network specification `%s' for `%s:%s'\n"), | ||
452 | opt, | ||
453 | sctx->service_name, | ||
454 | option); | ||
455 | GNUNET_free (opt); | ||
456 | return GNUNET_SYSERR; | ||
457 | } | ||
458 | GNUNET_free (opt); | ||
459 | return GNUNET_OK; | ||
460 | } | ||
461 | |||
462 | |||
463 | /** | ||
464 | * Add the given UNIX domain path as an address to the | ||
465 | * list (as the first entry). | ||
466 | * | ||
467 | * @param saddrs array to update | ||
468 | * @param saddrlens where to store the address length | ||
469 | * @param unixpath path to add | ||
470 | * @param abstract #GNUNET_YES to add an abstract UNIX domain socket. This | ||
471 | * parameter is ignore on systems other than LINUX | ||
472 | */ | ||
473 | static void | ||
474 | add_unixpath (struct sockaddr **saddrs, | ||
475 | socklen_t *saddrlens, | ||
476 | const char *unixpath, | ||
477 | int abstract) | ||
478 | { | ||
479 | #ifdef AF_UNIX | ||
480 | struct sockaddr_un *un; | ||
481 | |||
482 | un = GNUNET_new (struct sockaddr_un); | ||
483 | un->sun_family = AF_UNIX; | ||
484 | GNUNET_strlcpy (un->sun_path, unixpath, sizeof(un->sun_path)); | ||
485 | #ifdef __linux__ | ||
486 | if (GNUNET_YES == abstract) | ||
487 | un->sun_path[0] = '\0'; | ||
488 | #endif | ||
489 | #if HAVE_SOCKADDR_UN_SUN_LEN | ||
490 | un->sun_len = (u_char) sizeof(struct sockaddr_un); | ||
491 | #endif | ||
492 | *saddrs = (struct sockaddr *) un; | ||
493 | *saddrlens = sizeof(struct sockaddr_un); | ||
494 | #else | ||
495 | /* this function should never be called | ||
496 | * unless AF_UNIX is defined! */ | ||
497 | GNUNET_assert (0); | ||
498 | #endif | ||
499 | } | ||
500 | |||
501 | |||
502 | /** | ||
503 | * Get the list of addresses that a server for the given service | ||
504 | * should bind to. | ||
505 | * | ||
506 | * @param service_name name of the service | ||
507 | * @param cfg configuration (which specifies the addresses) | ||
508 | * @param addrs set (call by reference) to an array of pointers to the | ||
509 | * addresses the server should bind to and listen on; the | ||
510 | * array will be NULL-terminated (on success) | ||
511 | * @param addr_lens set (call by reference) to an array of the lengths | ||
512 | * of the respective `struct sockaddr` struct in the @a addrs | ||
513 | * array (on success) | ||
514 | * @return number of addresses found on success, | ||
515 | * #GNUNET_SYSERR if the configuration | ||
516 | * did not specify reasonable finding information or | ||
517 | * if it specified a hostname that could not be resolved; | ||
518 | * #GNUNET_NO if the number of addresses configured is | ||
519 | * zero (in this case, `*addrs` and `*addr_lens` will be | ||
520 | * set to NULL). | ||
521 | */ | ||
522 | int | ||
523 | LEGACY_SERVICE_get_server_addresses ( | ||
524 | const char *service_name, | ||
525 | const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
526 | struct sockaddr ***addrs, | ||
527 | socklen_t **addr_lens) | ||
528 | { | ||
529 | int disablev6; | ||
530 | struct GNUNET_NETWORK_Handle *desc; | ||
531 | unsigned long long port; | ||
532 | char *unixpath; | ||
533 | struct addrinfo hints; | ||
534 | struct addrinfo *res; | ||
535 | struct addrinfo *pos; | ||
536 | struct addrinfo *next; | ||
537 | unsigned int i; | ||
538 | int resi; | ||
539 | int ret; | ||
540 | int abstract; | ||
541 | struct sockaddr **saddrs; | ||
542 | socklen_t *saddrlens; | ||
543 | char *hostname; | ||
544 | |||
545 | *addrs = NULL; | ||
546 | *addr_lens = NULL; | ||
547 | desc = NULL; | ||
548 | if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "DISABLEV6")) | ||
549 | { | ||
550 | if (GNUNET_SYSERR == | ||
551 | (disablev6 = GNUNET_CONFIGURATION_get_value_yesno (cfg, | ||
552 | service_name, | ||
553 | "DISABLEV6"))) | ||
554 | return GNUNET_SYSERR; | ||
555 | } | ||
556 | else | ||
557 | disablev6 = GNUNET_NO; | ||
558 | |||
559 | if (! disablev6) | ||
560 | { | ||
561 | /* probe IPv6 support */ | ||
562 | desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0); | ||
563 | if (NULL == desc) | ||
564 | { | ||
565 | if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) || | ||
566 | (EACCES == errno)) | ||
567 | { | ||
568 | LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket"); | ||
569 | return GNUNET_SYSERR; | ||
570 | } | ||
571 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
572 | _ ( | ||
573 | "Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n"), | ||
574 | service_name, | ||
575 | strerror (errno)); | ||
576 | disablev6 = GNUNET_YES; | ||
577 | } | ||
578 | else | ||
579 | { | ||
580 | GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc)); | ||
581 | desc = NULL; | ||
582 | } | ||
583 | } | ||
584 | |||
585 | port = 0; | ||
586 | if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "PORT")) | ||
587 | { | ||
588 | if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg, | ||
589 | service_name, | ||
590 | "PORT", | ||
591 | &port)) | ||
592 | { | ||
593 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
594 | _ ("Require valid port number for service `%s' in configuration!\n"), | ||
595 | service_name); | ||
596 | } | ||
597 | if (port > 65535) | ||
598 | { | ||
599 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
600 | _ ("Require valid port number for service `%s' in configuration!\n"), | ||
601 | service_name); | ||
602 | return GNUNET_SYSERR; | ||
603 | } | ||
604 | } | ||
605 | |||
606 | if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "BINDTO")) | ||
607 | { | ||
608 | GNUNET_break (GNUNET_OK == | ||
609 | GNUNET_CONFIGURATION_get_value_string (cfg, | ||
610 | service_name, | ||
611 | "BINDTO", | ||
612 | &hostname)); | ||
613 | } | ||
614 | else | ||
615 | hostname = NULL; | ||
616 | |||
617 | unixpath = NULL; | ||
618 | abstract = GNUNET_NO; | ||
619 | #ifdef AF_UNIX | ||
620 | if ((GNUNET_YES == | ||
621 | GNUNET_CONFIGURATION_have_value (cfg, service_name, "UNIXPATH")) && | ||
622 | (GNUNET_OK == GNUNET_CONFIGURATION_get_value_filename (cfg, | ||
623 | service_name, | ||
624 | "UNIXPATH", | ||
625 | &unixpath)) && | ||
626 | (0 < strlen (unixpath))) | ||
627 | { | ||
628 | /* probe UNIX support */ | ||
629 | struct sockaddr_un s_un; | ||
630 | |||
631 | if (strlen (unixpath) >= sizeof(s_un.sun_path)) | ||
632 | { | ||
633 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
634 | _ ("UNIXPATH `%s' too long, maximum length is %llu\n"), | ||
635 | unixpath, | ||
636 | (unsigned long long) sizeof(s_un.sun_path)); | ||
637 | unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath); | ||
638 | LOG (GNUNET_ERROR_TYPE_INFO, _ ("Using `%s' instead\n"), unixpath); | ||
639 | } | ||
640 | #ifdef __linux__ | ||
641 | abstract = GNUNET_CONFIGURATION_get_value_yesno (cfg, | ||
642 | "TESTING", | ||
643 | "USE_ABSTRACT_SOCKETS"); | ||
644 | if (GNUNET_SYSERR == abstract) | ||
645 | abstract = GNUNET_NO; | ||
646 | #endif | ||
647 | if ((GNUNET_YES != abstract) && | ||
648 | (GNUNET_OK != GNUNET_DISK_directory_create_for_file (unixpath))) | ||
649 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "mkdir", unixpath); | ||
650 | } | ||
651 | if (NULL != unixpath) | ||
652 | { | ||
653 | desc = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0); | ||
654 | if (NULL == desc) | ||
655 | { | ||
656 | if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) || | ||
657 | (EACCES == errno)) | ||
658 | { | ||
659 | LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket"); | ||
660 | GNUNET_free (hostname); | ||
661 | GNUNET_free (unixpath); | ||
662 | return GNUNET_SYSERR; | ||
663 | } | ||
664 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
665 | _ ( | ||
666 | "Disabling UNIX domain socket support for service `%s', failed to create UNIX domain socket: %s\n"), | ||
667 | service_name, | ||
668 | strerror (errno)); | ||
669 | GNUNET_free (unixpath); | ||
670 | unixpath = NULL; | ||
671 | } | ||
672 | else | ||
673 | { | ||
674 | GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc)); | ||
675 | desc = NULL; | ||
676 | } | ||
677 | } | ||
678 | #endif | ||
679 | |||
680 | if ((0 == port) && (NULL == unixpath)) | ||
681 | { | ||
682 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
683 | _ ( | ||
684 | "Have neither PORT nor UNIXPATH for service `%s', but one is required\n"), | ||
685 | service_name); | ||
686 | GNUNET_free (hostname); | ||
687 | return GNUNET_SYSERR; | ||
688 | } | ||
689 | if (0 == port) | ||
690 | { | ||
691 | saddrs = GNUNET_malloc (2 * sizeof(struct sockaddr *)); | ||
692 | saddrlens = GNUNET_malloc (2 * sizeof(socklen_t)); | ||
693 | add_unixpath (saddrs, saddrlens, unixpath, abstract); | ||
694 | GNUNET_free (unixpath); | ||
695 | GNUNET_free (hostname); | ||
696 | *addrs = saddrs; | ||
697 | *addr_lens = saddrlens; | ||
698 | return 1; | ||
699 | } | ||
700 | |||
701 | if (NULL != hostname) | ||
702 | { | ||
703 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
704 | "Resolving `%s' since that is where `%s' will bind to.\n", | ||
705 | hostname, | ||
706 | service_name); | ||
707 | memset (&hints, 0, sizeof(struct addrinfo)); | ||
708 | if (disablev6) | ||
709 | hints.ai_family = AF_INET; | ||
710 | hints.ai_protocol = IPPROTO_TCP; | ||
711 | if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) || | ||
712 | (NULL == res)) | ||
713 | { | ||
714 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
715 | _ ("Failed to resolve `%s': %s\n"), | ||
716 | hostname, | ||
717 | gai_strerror (ret)); | ||
718 | GNUNET_free (hostname); | ||
719 | GNUNET_free (unixpath); | ||
720 | return GNUNET_SYSERR; | ||
721 | } | ||
722 | next = res; | ||
723 | i = 0; | ||
724 | while (NULL != (pos = next)) | ||
725 | { | ||
726 | next = pos->ai_next; | ||
727 | if ((disablev6) && (pos->ai_family == AF_INET6)) | ||
728 | continue; | ||
729 | i++; | ||
730 | } | ||
731 | if (0 == i) | ||
732 | { | ||
733 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
734 | _ ("Failed to find %saddress for `%s'.\n"), | ||
735 | disablev6 ? "IPv4 " : "", | ||
736 | hostname); | ||
737 | freeaddrinfo (res); | ||
738 | GNUNET_free (hostname); | ||
739 | GNUNET_free (unixpath); | ||
740 | return GNUNET_SYSERR; | ||
741 | } | ||
742 | resi = i; | ||
743 | if (NULL != unixpath) | ||
744 | resi++; | ||
745 | saddrs = GNUNET_malloc ((resi + 1) * sizeof(struct sockaddr *)); | ||
746 | saddrlens = GNUNET_malloc ((resi + 1) * sizeof(socklen_t)); | ||
747 | i = 0; | ||
748 | if (NULL != unixpath) | ||
749 | { | ||
750 | add_unixpath (saddrs, saddrlens, unixpath, abstract); | ||
751 | i++; | ||
752 | } | ||
753 | next = res; | ||
754 | while (NULL != (pos = next)) | ||
755 | { | ||
756 | next = pos->ai_next; | ||
757 | if ((disablev6) && (AF_INET6 == pos->ai_family)) | ||
758 | continue; | ||
759 | if ((IPPROTO_TCP != pos->ai_protocol) && (0 != pos->ai_protocol)) | ||
760 | continue; /* not TCP */ | ||
761 | if ((SOCK_STREAM != pos->ai_socktype) && (0 != pos->ai_socktype)) | ||
762 | continue; /* huh? */ | ||
763 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
764 | "Service `%s' will bind to `%s'\n", | ||
765 | service_name, | ||
766 | GNUNET_a2s (pos->ai_addr, pos->ai_addrlen)); | ||
767 | if (AF_INET == pos->ai_family) | ||
768 | { | ||
769 | GNUNET_assert (sizeof(struct sockaddr_in) == pos->ai_addrlen); | ||
770 | saddrlens[i] = pos->ai_addrlen; | ||
771 | saddrs[i] = GNUNET_malloc (saddrlens[i]); | ||
772 | GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]); | ||
773 | ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port); | ||
774 | } | ||
775 | else | ||
776 | { | ||
777 | GNUNET_assert (AF_INET6 == pos->ai_family); | ||
778 | GNUNET_assert (sizeof(struct sockaddr_in6) == pos->ai_addrlen); | ||
779 | saddrlens[i] = pos->ai_addrlen; | ||
780 | saddrs[i] = GNUNET_malloc (saddrlens[i]); | ||
781 | GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]); | ||
782 | ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port); | ||
783 | } | ||
784 | i++; | ||
785 | } | ||
786 | GNUNET_free (hostname); | ||
787 | freeaddrinfo (res); | ||
788 | resi = i; | ||
789 | } | ||
790 | else | ||
791 | { | ||
792 | /* will bind against everything, just set port */ | ||
793 | if (disablev6) | ||
794 | { | ||
795 | /* V4-only */ | ||
796 | resi = 1; | ||
797 | if (NULL != unixpath) | ||
798 | resi++; | ||
799 | i = 0; | ||
800 | saddrs = GNUNET_malloc ((resi + 1) * sizeof(struct sockaddr *)); | ||
801 | saddrlens = GNUNET_malloc ((resi + 1) * sizeof(socklen_t)); | ||
802 | if (NULL != unixpath) | ||
803 | { | ||
804 | add_unixpath (saddrs, saddrlens, unixpath, abstract); | ||
805 | i++; | ||
806 | } | ||
807 | saddrlens[i] = sizeof(struct sockaddr_in); | ||
808 | saddrs[i] = GNUNET_malloc (saddrlens[i]); | ||
809 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
810 | ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[i]; | ||
811 | #endif | ||
812 | ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET; | ||
813 | ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port); | ||
814 | } | ||
815 | else | ||
816 | { | ||
817 | /* dual stack */ | ||
818 | resi = 2; | ||
819 | if (NULL != unixpath) | ||
820 | resi++; | ||
821 | saddrs = GNUNET_malloc ((resi + 1) * sizeof(struct sockaddr *)); | ||
822 | saddrlens = GNUNET_malloc ((resi + 1) * sizeof(socklen_t)); | ||
823 | i = 0; | ||
824 | if (NULL != unixpath) | ||
825 | { | ||
826 | add_unixpath (saddrs, saddrlens, unixpath, abstract); | ||
827 | i++; | ||
828 | } | ||
829 | saddrlens[i] = sizeof(struct sockaddr_in6); | ||
830 | saddrs[i] = GNUNET_malloc (saddrlens[i]); | ||
831 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
832 | ((struct sockaddr_in6 *) saddrs[i])->sin6_len = saddrlens[0]; | ||
833 | #endif | ||
834 | ((struct sockaddr_in6 *) saddrs[i])->sin6_family = AF_INET6; | ||
835 | ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port); | ||
836 | i++; | ||
837 | saddrlens[i] = sizeof(struct sockaddr_in); | ||
838 | saddrs[i] = GNUNET_malloc (saddrlens[i]); | ||
839 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
840 | ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[1]; | ||
841 | #endif | ||
842 | ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET; | ||
843 | ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port); | ||
844 | } | ||
845 | } | ||
846 | GNUNET_free (unixpath); | ||
847 | *addrs = saddrs; | ||
848 | *addr_lens = saddrlens; | ||
849 | return resi; | ||
850 | } | ||
851 | |||
852 | |||
853 | /** | ||
854 | * Setup addr, addrlen, idle_timeout | ||
855 | * based on configuration! | ||
856 | * | ||
857 | * Configuration may specify: | ||
858 | * - PORT (where to bind to for TCP) | ||
859 | * - UNIXPATH (where to bind to for UNIX domain sockets) | ||
860 | * - TIMEOUT (after how many ms does an inactive service timeout); | ||
861 | * - DISABLEV6 (disable support for IPv6, otherwise we use dual-stack) | ||
862 | * - BINDTO (hostname or IP address to bind to, otherwise we take everything) | ||
863 | * - ACCEPT_FROM (only allow connections from specified IPv4 subnets) | ||
864 | * - ACCEPT_FROM6 (only allow connections from specified IPv6 subnets) | ||
865 | * - REJECT_FROM (disallow allow connections from specified IPv4 subnets) | ||
866 | * - REJECT_FROM6 (disallow allow connections from specified IPv6 subnets) | ||
867 | * | ||
868 | * @param sctx service context to initialize | ||
869 | * @return #GNUNET_OK if configuration succeeded | ||
870 | */ | ||
871 | static int | ||
872 | setup_service (struct LEGACY_SERVICE_Context *sctx) | ||
873 | { | ||
874 | struct GNUNET_TIME_Relative idleout; | ||
875 | int tolerant; | ||
876 | const char *nfds; | ||
877 | unsigned int cnt; | ||
878 | int flags; | ||
879 | |||
880 | if (GNUNET_CONFIGURATION_have_value (sctx->cfg, | ||
881 | sctx->service_name, | ||
882 | "TIMEOUT")) | ||
883 | { | ||
884 | if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (sctx->cfg, | ||
885 | sctx->service_name, | ||
886 | "TIMEOUT", | ||
887 | &idleout)) | ||
888 | { | ||
889 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
890 | _ ("Specified value for `%s' of service `%s' is invalid\n"), | ||
891 | "TIMEOUT", | ||
892 | sctx->service_name); | ||
893 | return GNUNET_SYSERR; | ||
894 | } | ||
895 | sctx->timeout = idleout; | ||
896 | } | ||
897 | else | ||
898 | sctx->timeout = GNUNET_TIME_UNIT_FOREVER_REL; | ||
899 | |||
900 | if (GNUNET_CONFIGURATION_have_value (sctx->cfg, | ||
901 | sctx->service_name, | ||
902 | "TOLERANT")) | ||
903 | { | ||
904 | if (GNUNET_SYSERR == | ||
905 | (tolerant = GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg, | ||
906 | sctx->service_name, | ||
907 | "TOLERANT"))) | ||
908 | { | ||
909 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
910 | _ ("Specified value for `%s' of service `%s' is invalid\n"), | ||
911 | "TOLERANT", | ||
912 | sctx->service_name); | ||
913 | return GNUNET_SYSERR; | ||
914 | } | ||
915 | } | ||
916 | else | ||
917 | tolerant = GNUNET_NO; | ||
918 | |||
919 | errno = 0; | ||
920 | if ((NULL != (nfds = getenv ("LISTEN_FDS"))) && | ||
921 | (1 == sscanf (nfds, "%u", &cnt)) && (cnt > 0) && (cnt < FD_SETSIZE) && | ||
922 | (cnt + 4 < FD_SETSIZE)) | ||
923 | { | ||
924 | sctx->lsocks = | ||
925 | GNUNET_malloc (sizeof(struct GNUNET_NETWORK_Handle *) * (cnt + 1)); | ||
926 | while (0 < cnt--) | ||
927 | { | ||
928 | flags = fcntl (3 + cnt, F_GETFD); | ||
929 | if ((flags < 0) || (0 != (flags & FD_CLOEXEC)) || | ||
930 | (NULL == | ||
931 | (sctx->lsocks[cnt] = GNUNET_NETWORK_socket_box_native (3 + cnt)))) | ||
932 | { | ||
933 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
934 | _ ( | ||
935 | "Could not access pre-bound socket %u, will try to bind myself\n"), | ||
936 | (unsigned int) 3 + cnt); | ||
937 | cnt++; | ||
938 | while (sctx->lsocks[cnt] != NULL) | ||
939 | GNUNET_break (0 == GNUNET_NETWORK_socket_close (sctx->lsocks[cnt++])); | ||
940 | GNUNET_free (sctx->lsocks); | ||
941 | sctx->lsocks = NULL; | ||
942 | break; | ||
943 | } | ||
944 | } | ||
945 | unsetenv ("LISTEN_FDS"); | ||
946 | } | ||
947 | |||
948 | if ((NULL == sctx->lsocks) && | ||
949 | (GNUNET_SYSERR == LEGACY_SERVICE_get_server_addresses (sctx->service_name, | ||
950 | sctx->cfg, | ||
951 | &sctx->addrs, | ||
952 | &sctx->addrlens))) | ||
953 | return GNUNET_SYSERR; | ||
954 | sctx->require_found = tolerant ? GNUNET_NO : GNUNET_YES; | ||
955 | sctx->match_uid = GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg, | ||
956 | sctx->service_name, | ||
957 | "UNIX_MATCH_UID"); | ||
958 | sctx->match_gid = GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg, | ||
959 | sctx->service_name, | ||
960 | "UNIX_MATCH_GID"); | ||
961 | process_acl4 (&sctx->v4_denied, sctx, "REJECT_FROM"); | ||
962 | process_acl4 (&sctx->v4_allowed, sctx, "ACCEPT_FROM"); | ||
963 | process_acl6 (&sctx->v6_denied, sctx, "REJECT_FROM6"); | ||
964 | process_acl6 (&sctx->v6_allowed, sctx, "ACCEPT_FROM6"); | ||
965 | |||
966 | return GNUNET_OK; | ||
967 | } | ||
968 | |||
969 | |||
970 | /** | ||
971 | * Get the name of the user that'll be used | ||
972 | * to provide the service. | ||
973 | * | ||
974 | * @param sctx service context | ||
975 | * @return value of the 'USERNAME' option | ||
976 | */ | ||
977 | static char * | ||
978 | get_user_name (struct LEGACY_SERVICE_Context *sctx) | ||
979 | { | ||
980 | char *un; | ||
981 | |||
982 | if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (sctx->cfg, | ||
983 | sctx->service_name, | ||
984 | "USERNAME", | ||
985 | &un)) | ||
986 | return NULL; | ||
987 | return un; | ||
988 | } | ||
989 | |||
990 | |||
991 | /** | ||
992 | * Write PID file. | ||
993 | * | ||
994 | * @param sctx service context | ||
995 | * @param pid PID to write (should be equal to 'getpid()' | ||
996 | * @return #GNUNET_OK on success (including no work to be done) | ||
997 | */ | ||
998 | static int | ||
999 | write_pid_file (struct LEGACY_SERVICE_Context *sctx, pid_t pid) | ||
1000 | { | ||
1001 | FILE *pidfd; | ||
1002 | char *pif; | ||
1003 | char *user; | ||
1004 | char *rdir; | ||
1005 | int len; | ||
1006 | |||
1007 | if (NULL == (pif = get_pid_file_name (sctx))) | ||
1008 | return GNUNET_OK; /* no file desired */ | ||
1009 | user = get_user_name (sctx); | ||
1010 | rdir = GNUNET_strdup (pif); | ||
1011 | len = strlen (rdir); | ||
1012 | while ((len > 0) && (rdir[len] != DIR_SEPARATOR)) | ||
1013 | len--; | ||
1014 | rdir[len] = '\0'; | ||
1015 | if (0 != access (rdir, F_OK)) | ||
1016 | { | ||
1017 | /* we get to create a directory -- and claim it | ||
1018 | * as ours! */ | ||
1019 | (void) GNUNET_DISK_directory_create (rdir); | ||
1020 | if ((NULL != user) && (0 < strlen (user))) | ||
1021 | GNUNET_DISK_file_change_owner (rdir, user); | ||
1022 | } | ||
1023 | if (0 != access (rdir, W_OK | X_OK)) | ||
1024 | { | ||
1025 | LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "access", rdir); | ||
1026 | GNUNET_free (rdir); | ||
1027 | GNUNET_free (user); | ||
1028 | GNUNET_free (pif); | ||
1029 | return GNUNET_SYSERR; | ||
1030 | } | ||
1031 | GNUNET_free (rdir); | ||
1032 | pidfd = fopen (pif, "w"); | ||
1033 | if (NULL == pidfd) | ||
1034 | { | ||
1035 | LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "fopen", pif); | ||
1036 | GNUNET_free (pif); | ||
1037 | GNUNET_free (user); | ||
1038 | return GNUNET_SYSERR; | ||
1039 | } | ||
1040 | if (0 > fprintf (pidfd, "%u", pid)) | ||
1041 | LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fprintf", pif); | ||
1042 | GNUNET_break (0 == fclose (pidfd)); | ||
1043 | if ((NULL != user) && (0 < strlen (user))) | ||
1044 | GNUNET_DISK_file_change_owner (pif, user); | ||
1045 | GNUNET_free (user); | ||
1046 | GNUNET_free (pif); | ||
1047 | return GNUNET_OK; | ||
1048 | } | ||
1049 | |||
1050 | |||
1051 | /** | ||
1052 | * Task run during shutdown. Stops the server/service. | ||
1053 | * | ||
1054 | * @param cls the `struct LEGACY_SERVICE_Context` | ||
1055 | */ | ||
1056 | static void | ||
1057 | shutdown_task (void *cls) | ||
1058 | { | ||
1059 | struct LEGACY_SERVICE_Context *service = cls; | ||
1060 | struct GNUNET_SERVER_Handle *server = service->server; | ||
1061 | |||
1062 | service->shutdown_task = NULL; | ||
1063 | if (0 != (service->options & LEGACY_SERVICE_OPTION_SOFT_SHUTDOWN)) | ||
1064 | GNUNET_SERVER_stop_listening (server); | ||
1065 | else | ||
1066 | GNUNET_SERVER_destroy (server); | ||
1067 | } | ||
1068 | |||
1069 | |||
1070 | /** | ||
1071 | * Initial task for the service. | ||
1072 | * | ||
1073 | * @param cls service context | ||
1074 | */ | ||
1075 | static void | ||
1076 | service_task (void *cls) | ||
1077 | { | ||
1078 | struct LEGACY_SERVICE_Context *sctx = cls; | ||
1079 | unsigned int i; | ||
1080 | |||
1081 | GNUNET_RESOLVER_connect (sctx->cfg); | ||
1082 | if (NULL != sctx->lsocks) | ||
1083 | sctx->server = GNUNET_SERVER_create_with_sockets (&check_access, | ||
1084 | sctx, | ||
1085 | sctx->lsocks, | ||
1086 | sctx->timeout, | ||
1087 | sctx->require_found); | ||
1088 | else | ||
1089 | sctx->server = GNUNET_SERVER_create (&check_access, | ||
1090 | sctx, | ||
1091 | sctx->addrs, | ||
1092 | sctx->addrlens, | ||
1093 | sctx->timeout, | ||
1094 | sctx->require_found); | ||
1095 | if (NULL == sctx->server) | ||
1096 | { | ||
1097 | if (NULL != sctx->addrs) | ||
1098 | for (i = 0; NULL != sctx->addrs[i]; i++) | ||
1099 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
1100 | _ ("Failed to start `%s' at `%s'\n"), | ||
1101 | sctx->service_name, | ||
1102 | GNUNET_a2s (sctx->addrs[i], sctx->addrlens[i])); | ||
1103 | sctx->ret = GNUNET_SYSERR; | ||
1104 | return; | ||
1105 | } | ||
1106 | |||
1107 | if (NULL != sctx->addrs) | ||
1108 | for (i = 0; NULL != sctx->addrs[i]; i++) | ||
1109 | if ((AF_UNIX == sctx->addrs[i]->sa_family) && | ||
1110 | ('\0' != ((const struct sockaddr_un *) sctx->addrs[i])->sun_path[0])) | ||
1111 | GNUNET_DISK_fix_permissions (((const struct sockaddr_un *) | ||
1112 | sctx->addrs[i]) | ||
1113 | ->sun_path, | ||
1114 | sctx->match_uid, | ||
1115 | sctx->match_gid); | ||
1116 | |||
1117 | if (0 == (sctx->options & LEGACY_SERVICE_OPTION_MANUAL_SHUTDOWN)) | ||
1118 | { | ||
1119 | /* install a task that will kill the server | ||
1120 | * process if the scheduler ever gets a shutdown signal */ | ||
1121 | sctx->shutdown_task = GNUNET_SCHEDULER_add_shutdown (&shutdown_task, sctx); | ||
1122 | } | ||
1123 | sctx->my_handlers = GNUNET_malloc (sizeof(defhandlers)); | ||
1124 | GNUNET_memcpy (sctx->my_handlers, defhandlers, sizeof(defhandlers)); | ||
1125 | i = 0; | ||
1126 | while (NULL != sctx->my_handlers[i].callback) | ||
1127 | sctx->my_handlers[i++].callback_cls = sctx; | ||
1128 | GNUNET_SERVER_add_handlers (sctx->server, sctx->my_handlers); | ||
1129 | if (-1 != sctx->ready_confirm_fd) | ||
1130 | { | ||
1131 | GNUNET_break (1 == write (sctx->ready_confirm_fd, ".", 1)); | ||
1132 | GNUNET_break (0 == close (sctx->ready_confirm_fd)); | ||
1133 | sctx->ready_confirm_fd = -1; | ||
1134 | write_pid_file (sctx, getpid ()); | ||
1135 | } | ||
1136 | if (NULL != sctx->addrs) | ||
1137 | { | ||
1138 | i = 0; | ||
1139 | while (NULL != sctx->addrs[i]) | ||
1140 | { | ||
1141 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
1142 | _ ("Service `%s' runs at %s\n"), | ||
1143 | sctx->service_name, | ||
1144 | GNUNET_a2s (sctx->addrs[i], sctx->addrlens[i])); | ||
1145 | i++; | ||
1146 | } | ||
1147 | } | ||
1148 | sctx->task (sctx->task_cls, sctx->server, sctx->cfg); | ||
1149 | } | ||
1150 | |||
1151 | |||
1152 | /** | ||
1153 | * Detach from terminal. | ||
1154 | * | ||
1155 | * @param sctx service context | ||
1156 | * @return #GNUNET_OK on success, #GNUNET_SYSERR on error | ||
1157 | */ | ||
1158 | static int | ||
1159 | detach_terminal (struct LEGACY_SERVICE_Context *sctx) | ||
1160 | { | ||
1161 | pid_t pid; | ||
1162 | int nullfd; | ||
1163 | int filedes[2]; | ||
1164 | |||
1165 | if (0 != pipe (filedes)) | ||
1166 | { | ||
1167 | LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "pipe"); | ||
1168 | return GNUNET_SYSERR; | ||
1169 | } | ||
1170 | pid = fork (); | ||
1171 | if (pid < 0) | ||
1172 | { | ||
1173 | LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "fork"); | ||
1174 | return GNUNET_SYSERR; | ||
1175 | } | ||
1176 | if (0 != pid) | ||
1177 | { | ||
1178 | /* Parent */ | ||
1179 | char c; | ||
1180 | |||
1181 | GNUNET_break (0 == close (filedes[1])); | ||
1182 | c = 'X'; | ||
1183 | if (1 != read (filedes[0], &c, sizeof(char))) | ||
1184 | LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "read"); | ||
1185 | fflush (stdout); | ||
1186 | switch (c) | ||
1187 | { | ||
1188 | case '.': | ||
1189 | exit (0); | ||
1190 | |||
1191 | case 'I': | ||
1192 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
1193 | _ ("Service process failed to initialize\n")); | ||
1194 | break; | ||
1195 | |||
1196 | case 'S': | ||
1197 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
1198 | _ ("Service process could not initialize server function\n")); | ||
1199 | break; | ||
1200 | |||
1201 | case 'X': | ||
1202 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
1203 | _ ("Service process failed to report status\n")); | ||
1204 | break; | ||
1205 | } | ||
1206 | exit (1); /* child reported error */ | ||
1207 | } | ||
1208 | GNUNET_break (0 == close (0)); | ||
1209 | GNUNET_break (0 == close (1)); | ||
1210 | GNUNET_break (0 == close (filedes[0])); | ||
1211 | nullfd = open ("/dev/null", O_RDWR | O_APPEND); | ||
1212 | if (nullfd < 0) | ||
1213 | return GNUNET_SYSERR; | ||
1214 | /* set stdin/stdout to /dev/null */ | ||
1215 | if ((dup2 (nullfd, 0) < 0) || (dup2 (nullfd, 1) < 0)) | ||
1216 | { | ||
1217 | LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "dup2"); | ||
1218 | (void) close (nullfd); | ||
1219 | return GNUNET_SYSERR; | ||
1220 | } | ||
1221 | (void) close (nullfd); | ||
1222 | /* Detach from controlling terminal */ | ||
1223 | pid = setsid (); | ||
1224 | if (-1 == pid) | ||
1225 | LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "setsid"); | ||
1226 | sctx->ready_confirm_fd = filedes[1]; | ||
1227 | |||
1228 | return GNUNET_OK; | ||
1229 | } | ||
1230 | |||
1231 | |||
1232 | /** | ||
1233 | * Set user ID. | ||
1234 | * | ||
1235 | * @param sctx service context | ||
1236 | * @return #GNUNET_OK on success, #GNUNET_SYSERR on error | ||
1237 | */ | ||
1238 | static int | ||
1239 | set_user_id (struct LEGACY_SERVICE_Context *sctx) | ||
1240 | { | ||
1241 | char *user; | ||
1242 | |||
1243 | if (NULL == (user = get_user_name (sctx))) | ||
1244 | return GNUNET_OK; /* keep */ | ||
1245 | |||
1246 | struct passwd *pws; | ||
1247 | |||
1248 | errno = 0; | ||
1249 | pws = getpwnam (user); | ||
1250 | if (NULL == pws) | ||
1251 | { | ||
1252 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
1253 | _ ("Cannot obtain information about user `%s': %s\n"), | ||
1254 | user, | ||
1255 | errno == 0 ? _ ("No such user") : strerror (errno)); | ||
1256 | GNUNET_free (user); | ||
1257 | return GNUNET_SYSERR; | ||
1258 | } | ||
1259 | if ((0 != setgid (pws->pw_gid)) || (0 != setegid (pws->pw_gid)) || | ||
1260 | #if HAVE_INITGROUPS | ||
1261 | (0 != initgroups (user, pws->pw_gid)) || | ||
1262 | #endif | ||
1263 | (0 != setuid (pws->pw_uid)) || (0 != seteuid (pws->pw_uid))) | ||
1264 | { | ||
1265 | if ((0 != setregid (pws->pw_gid, pws->pw_gid)) || | ||
1266 | (0 != setreuid (pws->pw_uid, pws->pw_uid))) | ||
1267 | { | ||
1268 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
1269 | _ ("Cannot change user/group to `%s': %s\n"), | ||
1270 | user, | ||
1271 | strerror (errno)); | ||
1272 | GNUNET_free (user); | ||
1273 | return GNUNET_SYSERR; | ||
1274 | } | ||
1275 | } | ||
1276 | |||
1277 | GNUNET_free (user); | ||
1278 | return GNUNET_OK; | ||
1279 | } | ||
1280 | |||
1281 | |||
1282 | /** | ||
1283 | * Delete the PID file that was created by our parent. | ||
1284 | * | ||
1285 | * @param sctx service context | ||
1286 | */ | ||
1287 | static void | ||
1288 | pid_file_delete (struct LEGACY_SERVICE_Context *sctx) | ||
1289 | { | ||
1290 | char *pif = get_pid_file_name (sctx); | ||
1291 | |||
1292 | if (NULL == pif) | ||
1293 | return; /* no PID file */ | ||
1294 | if (0 != unlink (pif)) | ||
1295 | LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "unlink", pif); | ||
1296 | GNUNET_free (pif); | ||
1297 | } | ||
1298 | |||
1299 | |||
1300 | /** | ||
1301 | * Run a standard GNUnet service startup sequence (initialize loggers | ||
1302 | * and configuration, parse options). | ||
1303 | * | ||
1304 | * @param argc number of command line arguments | ||
1305 | * @param argv command line arguments | ||
1306 | * @param service_name our service name | ||
1307 | * @param options service options | ||
1308 | * @param task main task of the service | ||
1309 | * @param task_cls closure for @a task | ||
1310 | * @return #GNUNET_SYSERR on error, #GNUNET_OK | ||
1311 | * if we shutdown nicely | ||
1312 | */ | ||
1313 | int | ||
1314 | LEGACY_SERVICE_run (int argc, | ||
1315 | char *const *argv, | ||
1316 | const char *service_name, | ||
1317 | enum LEGACY_SERVICE_Options options, | ||
1318 | LEGACY_SERVICE_Main task, | ||
1319 | void *task_cls) | ||
1320 | { | ||
1321 | #define HANDLE_ERROR \ | ||
1322 | do \ | ||
1323 | { \ | ||
1324 | GNUNET_break (0); \ | ||
1325 | goto shutdown; \ | ||
1326 | } while (0) | ||
1327 | |||
1328 | int err; | ||
1329 | int ret; | ||
1330 | char *cfg_fn; | ||
1331 | char *opt_cfg_fn; | ||
1332 | char *loglev; | ||
1333 | char *logfile; | ||
1334 | int do_daemonize; | ||
1335 | unsigned int i; | ||
1336 | unsigned long long skew_offset; | ||
1337 | unsigned long long skew_variance; | ||
1338 | long long clock_offset; | ||
1339 | struct LEGACY_SERVICE_Context sctx; | ||
1340 | struct GNUNET_CONFIGURATION_Handle *cfg; | ||
1341 | const char *xdg; | ||
1342 | |||
1343 | struct GNUNET_GETOPT_CommandLineOption service_options[] = | ||
1344 | { GNUNET_GETOPT_option_cfgfile (&opt_cfg_fn), | ||
1345 | GNUNET_GETOPT_option_flag ('d', | ||
1346 | "daemonize", | ||
1347 | gettext_noop ( | ||
1348 | "do daemonize (detach from terminal)"), | ||
1349 | &do_daemonize), | ||
1350 | GNUNET_GETOPT_option_help (NULL), | ||
1351 | GNUNET_GETOPT_option_loglevel (&loglev), | ||
1352 | GNUNET_GETOPT_option_logfile (&logfile), | ||
1353 | GNUNET_GETOPT_option_version (PACKAGE_VERSION " " VCS_VERSION), | ||
1354 | GNUNET_GETOPT_OPTION_END }; | ||
1355 | err = 1; | ||
1356 | do_daemonize = 0; | ||
1357 | logfile = NULL; | ||
1358 | loglev = NULL; | ||
1359 | opt_cfg_fn = NULL; | ||
1360 | xdg = getenv ("XDG_CONFIG_HOME"); | ||
1361 | if (NULL != xdg) | ||
1362 | GNUNET_asprintf (&cfg_fn, | ||
1363 | "%s%s%s", | ||
1364 | xdg, | ||
1365 | DIR_SEPARATOR_STR, | ||
1366 | GNUNET_OS_project_data_get ()->config_file); | ||
1367 | else | ||
1368 | cfg_fn = GNUNET_strdup (GNUNET_OS_project_data_get ()->user_config_file); | ||
1369 | memset (&sctx, 0, sizeof(sctx)); | ||
1370 | sctx.options = options; | ||
1371 | sctx.ready_confirm_fd = -1; | ||
1372 | sctx.ret = GNUNET_OK; | ||
1373 | sctx.timeout = GNUNET_TIME_UNIT_FOREVER_REL; | ||
1374 | sctx.task = task; | ||
1375 | sctx.task_cls = task_cls; | ||
1376 | sctx.service_name = service_name; | ||
1377 | sctx.cfg = cfg = GNUNET_CONFIGURATION_create (); | ||
1378 | |||
1379 | /* setup subsystems */ | ||
1380 | ret = GNUNET_GETOPT_run (service_name, service_options, argc, argv); | ||
1381 | if (GNUNET_SYSERR == ret) | ||
1382 | goto shutdown; | ||
1383 | if (GNUNET_NO == ret) | ||
1384 | { | ||
1385 | err = 0; | ||
1386 | goto shutdown; | ||
1387 | } | ||
1388 | if (GNUNET_OK != GNUNET_log_setup (service_name, loglev, logfile)) | ||
1389 | HANDLE_ERROR; | ||
1390 | if (NULL == opt_cfg_fn) | ||
1391 | opt_cfg_fn = GNUNET_strdup (cfg_fn); | ||
1392 | if (GNUNET_YES == GNUNET_DISK_file_test (opt_cfg_fn)) | ||
1393 | { | ||
1394 | if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, opt_cfg_fn)) | ||
1395 | { | ||
1396 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1397 | _ ("Malformed configuration file `%s', exit ...\n"), | ||
1398 | opt_cfg_fn); | ||
1399 | goto shutdown; | ||
1400 | } | ||
1401 | } | ||
1402 | else | ||
1403 | { | ||
1404 | if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, NULL)) | ||
1405 | { | ||
1406 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1407 | _ ("Malformed configuration, exit ...\n")); | ||
1408 | goto shutdown; | ||
1409 | } | ||
1410 | if (0 != strcmp (opt_cfg_fn, cfg_fn)) | ||
1411 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1412 | _ ("Could not access configuration file `%s'\n"), | ||
1413 | opt_cfg_fn); | ||
1414 | } | ||
1415 | if (GNUNET_OK != setup_service (&sctx)) | ||
1416 | goto shutdown; | ||
1417 | if ((1 == do_daemonize) && (GNUNET_OK != detach_terminal (&sctx))) | ||
1418 | HANDLE_ERROR; | ||
1419 | if (GNUNET_OK != set_user_id (&sctx)) | ||
1420 | goto shutdown; | ||
1421 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1422 | "Service `%s' runs with configuration from `%s'\n", | ||
1423 | service_name, | ||
1424 | opt_cfg_fn); | ||
1425 | if ((GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (sctx.cfg, | ||
1426 | "TESTING", | ||
1427 | "SKEW_OFFSET", | ||
1428 | &skew_offset)) && | ||
1429 | (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (sctx.cfg, | ||
1430 | "TESTING", | ||
1431 | "SKEW_VARIANCE", | ||
1432 | &skew_variance))) | ||
1433 | { | ||
1434 | clock_offset = skew_offset - skew_variance; | ||
1435 | GNUNET_TIME_set_offset (clock_offset); | ||
1436 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Skewing clock by %lld ms\n", clock_offset); | ||
1437 | } | ||
1438 | /* actually run service */ | ||
1439 | err = 0; | ||
1440 | GNUNET_SCHEDULER_run (&service_task, &sctx); | ||
1441 | /* shutdown */ | ||
1442 | if ((1 == do_daemonize) && (NULL != sctx.server)) | ||
1443 | pid_file_delete (&sctx); | ||
1444 | GNUNET_free (sctx.my_handlers); | ||
1445 | |||
1446 | shutdown: | ||
1447 | if (-1 != sctx.ready_confirm_fd) | ||
1448 | { | ||
1449 | if (1 != write (sctx.ready_confirm_fd, err ? "I" : "S", 1)) | ||
1450 | LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "write"); | ||
1451 | GNUNET_break (0 == close (sctx.ready_confirm_fd)); | ||
1452 | } | ||
1453 | #if HAVE_MALLINFO | ||
1454 | { | ||
1455 | char *counter; | ||
1456 | |||
1457 | if ((GNUNET_YES == GNUNET_CONFIGURATION_have_value (sctx.cfg, | ||
1458 | service_name, | ||
1459 | "GAUGER_HEAP")) && | ||
1460 | (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (sctx.cfg, | ||
1461 | service_name, | ||
1462 | "GAUGER_HEAP", | ||
1463 | &counter))) | ||
1464 | { | ||
1465 | struct mallinfo mi; | ||
1466 | |||
1467 | mi = mallinfo (); | ||
1468 | GAUGER (service_name, counter, mi.usmblks, "blocks"); | ||
1469 | GNUNET_free (counter); | ||
1470 | } | ||
1471 | } | ||
1472 | #endif | ||
1473 | GNUNET_CONFIGURATION_destroy (cfg); | ||
1474 | i = 0; | ||
1475 | if (NULL != sctx.addrs) | ||
1476 | while (NULL != sctx.addrs[i]) | ||
1477 | GNUNET_free_nz (sctx.addrs[i++]); | ||
1478 | GNUNET_free (sctx.addrs); | ||
1479 | GNUNET_free (sctx.addrlens); | ||
1480 | GNUNET_free (logfile); | ||
1481 | GNUNET_free (loglev); | ||
1482 | GNUNET_free (cfg_fn); | ||
1483 | GNUNET_free (opt_cfg_fn); | ||
1484 | GNUNET_free (sctx.v4_denied); | ||
1485 | GNUNET_free (sctx.v6_denied); | ||
1486 | GNUNET_free (sctx.v4_allowed); | ||
1487 | GNUNET_free (sctx.v6_allowed); | ||
1488 | |||
1489 | return err ? GNUNET_SYSERR : sctx.ret; | ||
1490 | } | ||
1491 | |||
1492 | |||
1493 | /** | ||
1494 | * Run a service startup sequence within an existing | ||
1495 | * initialized system. | ||
1496 | * | ||
1497 | * @param service_name our service name | ||
1498 | * @param cfg configuration to use | ||
1499 | * @param options service options | ||
1500 | * @return NULL on error, service handle | ||
1501 | */ | ||
1502 | struct LEGACY_SERVICE_Context * | ||
1503 | LEGACY_SERVICE_start (const char *service_name, | ||
1504 | const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
1505 | enum LEGACY_SERVICE_Options options) | ||
1506 | { | ||
1507 | int i; | ||
1508 | struct LEGACY_SERVICE_Context *sctx; | ||
1509 | |||
1510 | sctx = GNUNET_new (struct LEGACY_SERVICE_Context); | ||
1511 | sctx->ready_confirm_fd = -1; /* no daemonizing */ | ||
1512 | sctx->ret = GNUNET_OK; | ||
1513 | sctx->timeout = GNUNET_TIME_UNIT_FOREVER_REL; | ||
1514 | sctx->service_name = service_name; | ||
1515 | sctx->cfg = cfg; | ||
1516 | sctx->options = options; | ||
1517 | |||
1518 | /* setup subsystems */ | ||
1519 | if (GNUNET_OK != setup_service (sctx)) | ||
1520 | { | ||
1521 | LEGACY_SERVICE_stop (sctx); | ||
1522 | return NULL; | ||
1523 | } | ||
1524 | if (NULL != sctx->lsocks) | ||
1525 | sctx->server = GNUNET_SERVER_create_with_sockets (&check_access, | ||
1526 | sctx, | ||
1527 | sctx->lsocks, | ||
1528 | sctx->timeout, | ||
1529 | sctx->require_found); | ||
1530 | else | ||
1531 | sctx->server = GNUNET_SERVER_create (&check_access, | ||
1532 | sctx, | ||
1533 | sctx->addrs, | ||
1534 | sctx->addrlens, | ||
1535 | sctx->timeout, | ||
1536 | sctx->require_found); | ||
1537 | |||
1538 | if (NULL == sctx->server) | ||
1539 | { | ||
1540 | LEGACY_SERVICE_stop (sctx); | ||
1541 | return NULL; | ||
1542 | } | ||
1543 | |||
1544 | if (NULL != sctx->addrs) | ||
1545 | for (i = 0; NULL != sctx->addrs[i]; i++) | ||
1546 | if ((AF_UNIX == sctx->addrs[i]->sa_family) && | ||
1547 | ('\0' != ((const struct sockaddr_un *) sctx->addrs[i])->sun_path[0])) | ||
1548 | GNUNET_DISK_fix_permissions (((const struct sockaddr_un *) | ||
1549 | sctx->addrs[i]) | ||
1550 | ->sun_path, | ||
1551 | sctx->match_uid, | ||
1552 | sctx->match_gid); | ||
1553 | |||
1554 | sctx->my_handlers = GNUNET_malloc (sizeof(defhandlers)); | ||
1555 | GNUNET_memcpy (sctx->my_handlers, defhandlers, sizeof(defhandlers)); | ||
1556 | i = 0; | ||
1557 | while ((sctx->my_handlers[i].callback != NULL)) | ||
1558 | sctx->my_handlers[i++].callback_cls = sctx; | ||
1559 | GNUNET_SERVER_add_handlers (sctx->server, sctx->my_handlers); | ||
1560 | return sctx; | ||
1561 | } | ||
1562 | |||
1563 | |||
1564 | /** | ||
1565 | * Obtain the server used by a service. Note that the server must NOT | ||
1566 | * be destroyed by the caller. | ||
1567 | * | ||
1568 | * @param ctx the service context returned from the start function | ||
1569 | * @return handle to the server for this service, NULL if there is none | ||
1570 | */ | ||
1571 | struct GNUNET_SERVER_Handle * | ||
1572 | LEGACY_SERVICE_get_server (struct LEGACY_SERVICE_Context *ctx) | ||
1573 | { | ||
1574 | return ctx->server; | ||
1575 | } | ||
1576 | |||
1577 | |||
1578 | /** | ||
1579 | * Get the NULL-terminated array of listen sockets for this service. | ||
1580 | * | ||
1581 | * @param ctx service context to query | ||
1582 | * @return NULL if there are no listen sockets, otherwise NULL-terminated | ||
1583 | * array of listen sockets. | ||
1584 | */ | ||
1585 | struct GNUNET_NETWORK_Handle *const * | ||
1586 | LEGACY_SERVICE_get_listen_sockets (struct LEGACY_SERVICE_Context *ctx) | ||
1587 | { | ||
1588 | return ctx->lsocks; | ||
1589 | } | ||
1590 | |||
1591 | |||
1592 | /** | ||
1593 | * Stop a service that was started with "LEGACY_SERVICE_start". | ||
1594 | * | ||
1595 | * @param sctx the service context returned from the start function | ||
1596 | */ | ||
1597 | void | ||
1598 | LEGACY_SERVICE_stop (struct LEGACY_SERVICE_Context *sctx) | ||
1599 | { | ||
1600 | unsigned int i; | ||
1601 | |||
1602 | #if HAVE_MALLINFO | ||
1603 | { | ||
1604 | char *counter; | ||
1605 | |||
1606 | if ((GNUNET_YES == GNUNET_CONFIGURATION_have_value (sctx->cfg, | ||
1607 | sctx->service_name, | ||
1608 | "GAUGER_HEAP")) && | ||
1609 | (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (sctx->cfg, | ||
1610 | sctx->service_name, | ||
1611 | "GAUGER_HEAP", | ||
1612 | &counter))) | ||
1613 | { | ||
1614 | struct mallinfo mi; | ||
1615 | |||
1616 | mi = mallinfo (); | ||
1617 | GAUGER (sctx->service_name, counter, mi.usmblks, "blocks"); | ||
1618 | GNUNET_free (counter); | ||
1619 | } | ||
1620 | } | ||
1621 | #endif | ||
1622 | if (NULL != sctx->shutdown_task) | ||
1623 | { | ||
1624 | GNUNET_SCHEDULER_cancel (sctx->shutdown_task); | ||
1625 | sctx->shutdown_task = NULL; | ||
1626 | } | ||
1627 | if (NULL != sctx->server) | ||
1628 | GNUNET_SERVER_destroy (sctx->server); | ||
1629 | GNUNET_free (sctx->my_handlers); | ||
1630 | if (NULL != sctx->addrs) | ||
1631 | { | ||
1632 | i = 0; | ||
1633 | while (NULL != sctx->addrs[i]) | ||
1634 | GNUNET_free_nz (sctx->addrs[i++]); | ||
1635 | GNUNET_free (sctx->addrs); | ||
1636 | } | ||
1637 | GNUNET_free (sctx->addrlens); | ||
1638 | GNUNET_free (sctx->v4_denied); | ||
1639 | GNUNET_free (sctx->v6_denied); | ||
1640 | GNUNET_free (sctx->v4_allowed); | ||
1641 | GNUNET_free (sctx->v6_allowed); | ||
1642 | GNUNET_free (sctx); | ||
1643 | } | ||
1644 | |||
1645 | |||
1646 | /* end of service.c */ | ||