diff options
author | Christian Grothoff <christian@grothoff.org> | 2016-09-18 09:14:29 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2016-09-18 09:14:29 +0000 |
commit | 1e880e697c98d6dc8c35d2160cdc4bd0270692c1 (patch) | |
tree | 3530a18da4d1c6ba12f7cf297d0b4ab6d475d579 /src/util | |
parent | 271b944f00a551d9b9ebb7a57197c22d1d33ff56 (diff) | |
download | gnunet-1e880e697c98d6dc8c35d2160cdc4bd0270692c1.tar.gz gnunet-1e880e697c98d6dc8c35d2160cdc4bd0270692c1.zip |
getting service_new.c to compile, albeit it is not yet complete
Diffstat (limited to 'src/util')
-rw-r--r-- | src/util/Makefile.am | 1 | ||||
-rw-r--r-- | src/util/service_new.c | 780 |
2 files changed, 625 insertions, 156 deletions
diff --git a/src/util/Makefile.am b/src/util/Makefile.am index 6822d539d..b7e60022f 100644 --- a/src/util/Makefile.am +++ b/src/util/Makefile.am | |||
@@ -109,6 +109,7 @@ libgnunetutil_la_SOURCES = \ | |||
109 | server_nc.c \ | 109 | server_nc.c \ |
110 | server_tc.c \ | 110 | server_tc.c \ |
111 | service.c \ | 111 | service.c \ |
112 | service_new.c \ | ||
112 | signal.c \ | 113 | signal.c \ |
113 | strings.c \ | 114 | strings.c \ |
114 | time.c \ | 115 | time.c \ |
diff --git a/src/util/service_new.c b/src/util/service_new.c index 9608fbf22..e11d7687e 100644 --- a/src/util/service_new.c +++ b/src/util/service_new.c | |||
@@ -28,6 +28,19 @@ | |||
28 | #include "gnunet_protocols.h" | 28 | #include "gnunet_protocols.h" |
29 | #include "gnunet_constants.h" | 29 | #include "gnunet_constants.h" |
30 | #include "gnunet_resolver_service.h" | 30 | #include "gnunet_resolver_service.h" |
31 | #include "speedup.h" | ||
32 | |||
33 | #if HAVE_MALLINFO | ||
34 | #include <malloc.h> | ||
35 | #include "gauger.h" | ||
36 | #endif | ||
37 | |||
38 | |||
39 | #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) | ||
40 | |||
41 | #define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall) | ||
42 | |||
43 | #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename) | ||
31 | 44 | ||
32 | 45 | ||
33 | /** | 46 | /** |
@@ -191,13 +204,6 @@ struct GNUNET_SERVICE_Handle | |||
191 | int ret; | 204 | int ret; |
192 | 205 | ||
193 | /** | 206 | /** |
194 | * Inherited listening sockets, only | ||
195 | * used during initialization. | ||
196 | * FIXME: remove from struct | ||
197 | */ | ||
198 | struct GNUNET_NETWORK_Handle **lsocks; | ||
199 | |||
200 | /** | ||
201 | * If GNUNET_YES, consider unknown message types an error where the | 207 | * If GNUNET_YES, consider unknown message types an error where the |
202 | * client is disconnected. | 208 | * client is disconnected. |
203 | * FIXME: remove? | 209 | * FIXME: remove? |
@@ -320,8 +326,6 @@ static void | |||
320 | service_shutdown (void *cls) | 326 | service_shutdown (void *cls) |
321 | { | 327 | { |
322 | struct GNUNET_SERVICE_Handle *sh = cls; | 328 | struct GNUNET_SERVICE_Handle *sh = cls; |
323 | struct GNUNET_SERVICE_Client *client; | ||
324 | int alive; | ||
325 | 329 | ||
326 | switch (sh->options) | 330 | switch (sh->options) |
327 | { | 331 | { |
@@ -394,7 +398,9 @@ process_acl4 (struct GNUNET_STRINGS_IPv4NetworkPolicy **ret, | |||
394 | { | 398 | { |
395 | LOG (GNUNET_ERROR_TYPE_WARNING, | 399 | LOG (GNUNET_ERROR_TYPE_WARNING, |
396 | _("Could not parse IPv4 network specification `%s' for `%s:%s'\n"), | 400 | _("Could not parse IPv4 network specification `%s' for `%s:%s'\n"), |
397 | opt, sh->service_name, option); | 401 | opt, |
402 | sh->service_name, | ||
403 | option); | ||
398 | GNUNET_free (opt); | 404 | GNUNET_free (opt); |
399 | return GNUNET_SYSERR; | 405 | return GNUNET_SYSERR; |
400 | } | 406 | } |
@@ -442,6 +448,45 @@ process_acl6 (struct GNUNET_STRINGS_IPv6NetworkPolicy **ret, | |||
442 | 448 | ||
443 | 449 | ||
444 | /** | 450 | /** |
451 | * Add the given UNIX domain path as an address to the | ||
452 | * list (as the first entry). | ||
453 | * | ||
454 | * @param saddrs array to update | ||
455 | * @param saddrlens where to store the address length | ||
456 | * @param unixpath path to add | ||
457 | * @param abstract #GNUNET_YES to add an abstract UNIX domain socket. This | ||
458 | * parameter is ignore on systems other than LINUX | ||
459 | */ | ||
460 | static void | ||
461 | add_unixpath (struct sockaddr **saddrs, | ||
462 | socklen_t *saddrlens, | ||
463 | const char *unixpath, | ||
464 | int abstract) | ||
465 | { | ||
466 | #ifdef AF_UNIX | ||
467 | struct sockaddr_un *un; | ||
468 | |||
469 | un = GNUNET_new (struct sockaddr_un); | ||
470 | un->sun_family = AF_UNIX; | ||
471 | strncpy (un->sun_path, unixpath, sizeof (un->sun_path) - 1); | ||
472 | #ifdef LINUX | ||
473 | if (GNUNET_YES == abstract) | ||
474 | un->sun_path[0] = '\0'; | ||
475 | #endif | ||
476 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
477 | un->sun_len = (u_char) sizeof (struct sockaddr_un); | ||
478 | #endif | ||
479 | *saddrs = (struct sockaddr *) un; | ||
480 | *saddrlens = sizeof (struct sockaddr_un); | ||
481 | #else | ||
482 | /* this function should never be called | ||
483 | * unless AF_UNIX is defined! */ | ||
484 | GNUNET_assert (0); | ||
485 | #endif | ||
486 | } | ||
487 | |||
488 | |||
489 | /** | ||
445 | * Get the list of addresses that a server for the given service | 490 | * Get the list of addresses that a server for the given service |
446 | * should bind to. | 491 | * should bind to. |
447 | * | 492 | * |
@@ -463,9 +508,9 @@ process_acl6 (struct GNUNET_STRINGS_IPv6NetworkPolicy **ret, | |||
463 | */ | 508 | */ |
464 | static int | 509 | static int |
465 | get_server_addresses (const char *service_name, | 510 | get_server_addresses (const char *service_name, |
466 | const struct GNUNET_CONFIGURATION_Handle *cfg, | 511 | const struct GNUNET_CONFIGURATION_Handle *cfg, |
467 | struct sockaddr ***addrs, | 512 | struct sockaddr ***addrs, |
468 | socklen_t ** addr_lens) | 513 | socklen_t **addr_lens) |
469 | { | 514 | { |
470 | int disablev6; | 515 | int disablev6; |
471 | struct GNUNET_NETWORK_Handle *desc; | 516 | struct GNUNET_NETWORK_Handle *desc; |
@@ -486,11 +531,15 @@ get_server_addresses (const char *service_name, | |||
486 | *addrs = NULL; | 531 | *addrs = NULL; |
487 | *addr_lens = NULL; | 532 | *addr_lens = NULL; |
488 | desc = NULL; | 533 | desc = NULL; |
489 | if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "DISABLEV6")) | 534 | if (GNUNET_CONFIGURATION_have_value (cfg, |
535 | service_name, | ||
536 | "DISABLEV6")) | ||
490 | { | 537 | { |
491 | if (GNUNET_SYSERR == | 538 | if (GNUNET_SYSERR == |
492 | (disablev6 = | 539 | (disablev6 = |
493 | GNUNET_CONFIGURATION_get_value_yesno (cfg, service_name, "DISABLEV6"))) | 540 | GNUNET_CONFIGURATION_get_value_yesno (cfg, |
541 | service_name, | ||
542 | "DISABLEV6"))) | ||
494 | return GNUNET_SYSERR; | 543 | return GNUNET_SYSERR; |
495 | } | 544 | } |
496 | else | 545 | else |
@@ -499,18 +548,24 @@ get_server_addresses (const char *service_name, | |||
499 | if (! disablev6) | 548 | if (! disablev6) |
500 | { | 549 | { |
501 | /* probe IPv6 support */ | 550 | /* probe IPv6 support */ |
502 | desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0); | 551 | desc = GNUNET_NETWORK_socket_create (PF_INET6, |
552 | SOCK_STREAM, | ||
553 | 0); | ||
503 | if (NULL == desc) | 554 | if (NULL == desc) |
504 | { | 555 | { |
505 | if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) || | 556 | if ((ENOBUFS == errno) || |
557 | (ENOMEM == errno) || | ||
558 | (ENFILE == errno) || | ||
506 | (EACCES == errno)) | 559 | (EACCES == errno)) |
507 | { | 560 | { |
508 | LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket"); | 561 | LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, |
562 | "socket"); | ||
509 | return GNUNET_SYSERR; | 563 | return GNUNET_SYSERR; |
510 | } | 564 | } |
511 | LOG (GNUNET_ERROR_TYPE_INFO, | 565 | LOG (GNUNET_ERROR_TYPE_INFO, |
512 | _("Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n"), | 566 | _("Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n"), |
513 | service_name, STRERROR (errno)); | 567 | service_name, |
568 | STRERROR (errno)); | ||
514 | disablev6 = GNUNET_YES; | 569 | disablev6 = GNUNET_YES; |
515 | } | 570 | } |
516 | else | 571 | else |
@@ -521,11 +576,15 @@ get_server_addresses (const char *service_name, | |||
521 | } | 576 | } |
522 | 577 | ||
523 | port = 0; | 578 | port = 0; |
524 | if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "PORT")) | 579 | if (GNUNET_CONFIGURATION_have_value (cfg, |
580 | service_name, | ||
581 | "PORT")) | ||
525 | { | 582 | { |
526 | if (GNUNET_OK != | 583 | if (GNUNET_OK != |
527 | GNUNET_CONFIGURATION_get_value_number (cfg, service_name, | 584 | GNUNET_CONFIGURATION_get_value_number (cfg, |
528 | "PORT", &port)) | 585 | service_name, |
586 | "PORT", | ||
587 | &port)) | ||
529 | { | 588 | { |
530 | LOG (GNUNET_ERROR_TYPE_ERROR, | 589 | LOG (GNUNET_ERROR_TYPE_ERROR, |
531 | _("Require valid port number for service `%s' in configuration!\n"), | 590 | _("Require valid port number for service `%s' in configuration!\n"), |
@@ -540,11 +599,15 @@ get_server_addresses (const char *service_name, | |||
540 | } | 599 | } |
541 | } | 600 | } |
542 | 601 | ||
543 | if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "BINDTO")) | 602 | if (GNUNET_CONFIGURATION_have_value (cfg, |
603 | service_name, | ||
604 | "BINDTO")) | ||
544 | { | 605 | { |
545 | GNUNET_break (GNUNET_OK == | 606 | GNUNET_break (GNUNET_OK == |
546 | GNUNET_CONFIGURATION_get_value_string (cfg, service_name, | 607 | GNUNET_CONFIGURATION_get_value_string (cfg, |
547 | "BINDTO", &hostname)); | 608 | service_name, |
609 | "BINDTO", | ||
610 | &hostname)); | ||
548 | } | 611 | } |
549 | else | 612 | else |
550 | hostname = NULL; | 613 | hostname = NULL; |
@@ -553,10 +616,14 @@ get_server_addresses (const char *service_name, | |||
553 | abstract = GNUNET_NO; | 616 | abstract = GNUNET_NO; |
554 | #ifdef AF_UNIX | 617 | #ifdef AF_UNIX |
555 | if ((GNUNET_YES == | 618 | if ((GNUNET_YES == |
556 | GNUNET_CONFIGURATION_have_value (cfg, service_name, "UNIXPATH")) && | 619 | GNUNET_CONFIGURATION_have_value (cfg, |
620 | service_name, | ||
621 | "UNIXPATH")) && | ||
557 | (GNUNET_OK == | 622 | (GNUNET_OK == |
558 | GNUNET_CONFIGURATION_get_value_filename (cfg, service_name, "UNIXPATH", | 623 | GNUNET_CONFIGURATION_get_value_filename (cfg, |
559 | &unixpath)) && | 624 | service_name, |
625 | "UNIXPATH", | ||
626 | &unixpath)) && | ||
560 | (0 < strlen (unixpath))) | 627 | (0 < strlen (unixpath))) |
561 | { | 628 | { |
562 | /* probe UNIX support */ | 629 | /* probe UNIX support */ |
@@ -565,7 +632,8 @@ get_server_addresses (const char *service_name, | |||
565 | if (strlen (unixpath) >= sizeof (s_un.sun_path)) | 632 | if (strlen (unixpath) >= sizeof (s_un.sun_path)) |
566 | { | 633 | { |
567 | LOG (GNUNET_ERROR_TYPE_WARNING, | 634 | LOG (GNUNET_ERROR_TYPE_WARNING, |
568 | _("UNIXPATH `%s' too long, maximum length is %llu\n"), unixpath, | 635 | _("UNIXPATH `%s' too long, maximum length is %llu\n"), |
636 | unixpath, | ||
569 | (unsigned long long) sizeof (s_un.sun_path)); | 637 | (unsigned long long) sizeof (s_un.sun_path)); |
570 | unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath); | 638 | unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath); |
571 | LOG (GNUNET_ERROR_TYPE_INFO, | 639 | LOG (GNUNET_ERROR_TYPE_INFO, |
@@ -588,13 +656,18 @@ get_server_addresses (const char *service_name, | |||
588 | } | 656 | } |
589 | if (NULL != unixpath) | 657 | if (NULL != unixpath) |
590 | { | 658 | { |
591 | desc = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0); | 659 | desc = GNUNET_NETWORK_socket_create (AF_UNIX, |
660 | SOCK_STREAM, | ||
661 | 0); | ||
592 | if (NULL == desc) | 662 | if (NULL == desc) |
593 | { | 663 | { |
594 | if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) || | 664 | if ((ENOBUFS == errno) || |
665 | (ENOMEM == errno) || | ||
666 | (ENFILE == errno) || | ||
595 | (EACCES == errno)) | 667 | (EACCES == errno)) |
596 | { | 668 | { |
597 | LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket"); | 669 | LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, |
670 | "socket"); | ||
598 | GNUNET_free_non_null (hostname); | 671 | GNUNET_free_non_null (hostname); |
599 | GNUNET_free (unixpath); | 672 | GNUNET_free (unixpath); |
600 | return GNUNET_SYSERR; | 673 | return GNUNET_SYSERR; |
@@ -624,9 +697,14 @@ get_server_addresses (const char *service_name, | |||
624 | } | 697 | } |
625 | if (0 == port) | 698 | if (0 == port) |
626 | { | 699 | { |
627 | saddrs = GNUNET_malloc (2 * sizeof (struct sockaddr *)); | 700 | saddrs = GNUNET_new_array (2, |
628 | saddrlens = GNUNET_malloc (2 * sizeof (socklen_t)); | 701 | struct sockaddr *); |
629 | add_unixpath (saddrs, saddrlens, unixpath, abstract); | 702 | saddrlens = GNUNET_new_array (2, |
703 | socklen_t); | ||
704 | add_unixpath (saddrs, | ||
705 | saddrlens, | ||
706 | unixpath, | ||
707 | abstract); | ||
630 | GNUNET_free_non_null (unixpath); | 708 | GNUNET_free_non_null (unixpath); |
631 | GNUNET_free_non_null (hostname); | 709 | GNUNET_free_non_null (hostname); |
632 | *addrs = saddrs; | 710 | *addrs = saddrs; |
@@ -640,11 +718,16 @@ get_server_addresses (const char *service_name, | |||
640 | "Resolving `%s' since that is where `%s' will bind to.\n", | 718 | "Resolving `%s' since that is where `%s' will bind to.\n", |
641 | hostname, | 719 | hostname, |
642 | service_name); | 720 | service_name); |
643 | memset (&hints, 0, sizeof (struct addrinfo)); | 721 | memset (&hints, |
722 | 0, | ||
723 | sizeof (struct addrinfo)); | ||
644 | if (disablev6) | 724 | if (disablev6) |
645 | hints.ai_family = AF_INET; | 725 | hints.ai_family = AF_INET; |
646 | hints.ai_protocol = IPPROTO_TCP; | 726 | hints.ai_protocol = IPPROTO_TCP; |
647 | if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) || | 727 | if ((0 != (ret = getaddrinfo (hostname, |
728 | NULL, | ||
729 | &hints, | ||
730 | &res))) || | ||
648 | (NULL == res)) | 731 | (NULL == res)) |
649 | { | 732 | { |
650 | LOG (GNUNET_ERROR_TYPE_ERROR, | 733 | LOG (GNUNET_ERROR_TYPE_ERROR, |
@@ -660,7 +743,8 @@ get_server_addresses (const char *service_name, | |||
660 | while (NULL != (pos = next)) | 743 | while (NULL != (pos = next)) |
661 | { | 744 | { |
662 | next = pos->ai_next; | 745 | next = pos->ai_next; |
663 | if ((disablev6) && (pos->ai_family == AF_INET6)) | 746 | if ( (disablev6) && |
747 | (pos->ai_family == AF_INET6) ) | ||
664 | continue; | 748 | continue; |
665 | i++; | 749 | i++; |
666 | } | 750 | } |
@@ -678,32 +762,45 @@ get_server_addresses (const char *service_name, | |||
678 | resi = i; | 762 | resi = i; |
679 | if (NULL != unixpath) | 763 | if (NULL != unixpath) |
680 | resi++; | 764 | resi++; |
681 | saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *)); | 765 | saddrs = GNUNET_new_array (resi + 1, |
682 | saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t)); | 766 | struct sockaddr *); |
767 | saddrlens = GNUNET_new_array (resi + 1, | ||
768 | socklen_t); | ||
683 | i = 0; | 769 | i = 0; |
684 | if (NULL != unixpath) | 770 | if (NULL != unixpath) |
685 | { | 771 | { |
686 | add_unixpath (saddrs, saddrlens, unixpath, abstract); | 772 | add_unixpath (saddrs, |
773 | saddrlens, | ||
774 | unixpath, | ||
775 | abstract); | ||
687 | i++; | 776 | i++; |
688 | } | 777 | } |
689 | next = res; | 778 | next = res; |
690 | while (NULL != (pos = next)) | 779 | while (NULL != (pos = next)) |
691 | { | 780 | { |
692 | next = pos->ai_next; | 781 | next = pos->ai_next; |
693 | if ((disablev6) && (AF_INET6 == pos->ai_family)) | 782 | if ( (disablev6) && |
783 | (AF_INET6 == pos->ai_family) ) | ||
694 | continue; | 784 | continue; |
695 | if ((IPPROTO_TCP != pos->ai_protocol) && (0 != pos->ai_protocol)) | 785 | if ( (IPPROTO_TCP != pos->ai_protocol) && |
786 | (0 != pos->ai_protocol) ) | ||
696 | continue; /* not TCP */ | 787 | continue; /* not TCP */ |
697 | if ((SOCK_STREAM != pos->ai_socktype) && (0 != pos->ai_socktype)) | 788 | if ( (SOCK_STREAM != pos->ai_socktype) && |
789 | (0 != pos->ai_socktype) ) | ||
698 | continue; /* huh? */ | 790 | continue; /* huh? */ |
699 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Service `%s' will bind to `%s'\n", | 791 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
700 | service_name, GNUNET_a2s (pos->ai_addr, pos->ai_addrlen)); | 792 | "Service `%s' will bind to `%s'\n", |
793 | service_name, | ||
794 | GNUNET_a2s (pos->ai_addr, | ||
795 | pos->ai_addrlen)); | ||
701 | if (AF_INET == pos->ai_family) | 796 | if (AF_INET == pos->ai_family) |
702 | { | 797 | { |
703 | GNUNET_assert (sizeof (struct sockaddr_in) == pos->ai_addrlen); | 798 | GNUNET_assert (sizeof (struct sockaddr_in) == pos->ai_addrlen); |
704 | saddrlens[i] = pos->ai_addrlen; | 799 | saddrlens[i] = pos->ai_addrlen; |
705 | saddrs[i] = GNUNET_malloc (saddrlens[i]); | 800 | saddrs[i] = GNUNET_malloc (saddrlens[i]); |
706 | GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]); | 801 | GNUNET_memcpy (saddrs[i], |
802 | pos->ai_addr, | ||
803 | saddrlens[i]); | ||
707 | ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port); | 804 | ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port); |
708 | } | 805 | } |
709 | else | 806 | else |
@@ -712,7 +809,9 @@ get_server_addresses (const char *service_name, | |||
712 | GNUNET_assert (sizeof (struct sockaddr_in6) == pos->ai_addrlen); | 809 | GNUNET_assert (sizeof (struct sockaddr_in6) == pos->ai_addrlen); |
713 | saddrlens[i] = pos->ai_addrlen; | 810 | saddrlens[i] = pos->ai_addrlen; |
714 | saddrs[i] = GNUNET_malloc (saddrlens[i]); | 811 | saddrs[i] = GNUNET_malloc (saddrlens[i]); |
715 | GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]); | 812 | GNUNET_memcpy (saddrs[i], |
813 | pos->ai_addr, | ||
814 | saddrlens[i]); | ||
716 | ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port); | 815 | ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port); |
717 | } | 816 | } |
718 | i++; | 817 | i++; |
@@ -731,11 +830,16 @@ get_server_addresses (const char *service_name, | |||
731 | if (NULL != unixpath) | 830 | if (NULL != unixpath) |
732 | resi++; | 831 | resi++; |
733 | i = 0; | 832 | i = 0; |
734 | saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *)); | 833 | saddrs = GNUNET_new_array (resi + 1, |
735 | saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t)); | 834 | struct sockaddr *); |
835 | saddrlens = GNUNET_new_array (resi + 1, | ||
836 | socklen_t); | ||
736 | if (NULL != unixpath) | 837 | if (NULL != unixpath) |
737 | { | 838 | { |
738 | add_unixpath (saddrs, saddrlens, unixpath, abstract); | 839 | add_unixpath (saddrs, |
840 | saddrlens, | ||
841 | unixpath, | ||
842 | abstract); | ||
739 | i++; | 843 | i++; |
740 | } | 844 | } |
741 | saddrlens[i] = sizeof (struct sockaddr_in); | 845 | saddrlens[i] = sizeof (struct sockaddr_in); |
@@ -752,12 +856,17 @@ get_server_addresses (const char *service_name, | |||
752 | resi = 2; | 856 | resi = 2; |
753 | if (NULL != unixpath) | 857 | if (NULL != unixpath) |
754 | resi++; | 858 | resi++; |
755 | saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *)); | 859 | saddrs = GNUNET_new_array (resi + 1, |
756 | saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t)); | 860 | struct sockaddr *); |
861 | saddrlens = GNUNET_new_array (resi + 1, | ||
862 | socklen_t); | ||
757 | i = 0; | 863 | i = 0; |
758 | if (NULL != unixpath) | 864 | if (NULL != unixpath) |
759 | { | 865 | { |
760 | add_unixpath (saddrs, saddrlens, unixpath, abstract); | 866 | add_unixpath (saddrs, |
867 | saddrlens, | ||
868 | unixpath, | ||
869 | abstract); | ||
761 | i++; | 870 | i++; |
762 | } | 871 | } |
763 | saddrlens[i] = sizeof (struct sockaddr_in6); | 872 | saddrlens[i] = sizeof (struct sockaddr_in6); |
@@ -789,12 +898,13 @@ get_server_addresses (const char *service_name, | |||
789 | * Read listen sockets from the parent process (ARM). | 898 | * Read listen sockets from the parent process (ARM). |
790 | * | 899 | * |
791 | * @param sh service context to initialize | 900 | * @param sh service context to initialize |
792 | * @return #GNUNET_YES if ok, #GNUNET_NO if not ok (must bind yourself), | 901 | * @return NULL-terminated array of sockets on success, |
793 | * and #GNUNET_SYSERR on error. | 902 | * NULL if not ok (must bind yourself) |
794 | */ | 903 | */ |
795 | static int | 904 | static struct GNUNET_NETWORK_Handle ** |
796 | receive_sockets_from_parent (struct GNUNET_SERVICE_Handle *sh) | 905 | receive_sockets_from_parent (struct GNUNET_SERVICE_Handle *sh) |
797 | { | 906 | { |
907 | static struct GNUNET_NETWORK_Handle **lsocks; | ||
798 | const char *env_buf; | 908 | const char *env_buf; |
799 | int fail; | 909 | int fail; |
800 | uint64_t count; | 910 | uint64_t count; |
@@ -802,15 +912,19 @@ receive_sockets_from_parent (struct GNUNET_SERVICE_Handle *sh) | |||
802 | HANDLE lsocks_pipe; | 912 | HANDLE lsocks_pipe; |
803 | 913 | ||
804 | env_buf = getenv ("GNUNET_OS_READ_LSOCKS"); | 914 | env_buf = getenv ("GNUNET_OS_READ_LSOCKS"); |
805 | if ((NULL == env_buf) || (strlen (env_buf) <= 0)) | 915 | if ( (NULL == env_buf) || |
806 | return GNUNET_NO; | 916 | (strlen (env_buf) <= 0) ) |
917 | return NULL; | ||
807 | /* Using W32 API directly here, because this pipe will | 918 | /* Using W32 API directly here, because this pipe will |
808 | * never be used outside of this function, and it's just too much of a bother | 919 | * never be used outside of this function, and it's just too much of a bother |
809 | * to create a GNUnet API that boxes a HANDLE (the way it is done with socks) | 920 | * to create a GNUnet API that boxes a HANDLE (the way it is done with socks) |
810 | */ | 921 | */ |
811 | lsocks_pipe = (HANDLE) strtoul (env_buf, NULL, 10); | 922 | lsocks_pipe = (HANDLE) strtoul (env_buf, |
812 | if ( (0 == lsocks_pipe) || (INVALID_HANDLE_VALUE == lsocks_pipe)) | 923 | NULL, |
813 | return GNUNET_NO; | 924 | 10); |
925 | if ( (0 == lsocks_pipe) || | ||
926 | (INVALID_HANDLE_VALUE == lsocks_pipe)) | ||
927 | return NULL; | ||
814 | fail = 1; | 928 | fail = 1; |
815 | do | 929 | do |
816 | { | 930 | { |
@@ -818,11 +932,17 @@ receive_sockets_from_parent (struct GNUNET_SERVICE_Handle *sh) | |||
818 | int fail2; | 932 | int fail2; |
819 | DWORD rd; | 933 | DWORD rd; |
820 | 934 | ||
821 | ret = ReadFile (lsocks_pipe, &count, sizeof (count), &rd, NULL); | 935 | ret = ReadFile (lsocks_pipe, |
822 | if ((0 == ret) || (sizeof (count) != rd) || (0 == count)) | 936 | &count, |
937 | sizeof (count), | ||
938 | &rd, | ||
939 | NULL); | ||
940 | if ( (0 == ret) || | ||
941 | (sizeof (count) != rd) || | ||
942 | (0 == count) ) | ||
823 | break; | 943 | break; |
824 | sh->lsocks = | 944 | lsocks = GNUNET_new_array (count + 1, |
825 | GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle *) * (count + 1)); | 945 | struct GNUNET_NETWORK_Handle *); |
826 | 946 | ||
827 | fail2 = 1; | 947 | fail2 = 1; |
828 | for (i = 0; i < count; i++) | 948 | for (i = 0; i < count; i++) |
@@ -831,39 +951,53 @@ receive_sockets_from_parent (struct GNUNET_SERVICE_Handle *sh) | |||
831 | uint64_t size; | 951 | uint64_t size; |
832 | SOCKET s; | 952 | SOCKET s; |
833 | 953 | ||
834 | ret = ReadFile (lsocks_pipe, &size, sizeof (size), &rd, NULL); | 954 | ret = ReadFile (lsocks_pipe, |
835 | if ( (0 == ret) || (sizeof (size) != rd) || (sizeof (pi) != size) ) | 955 | &size, |
956 | sizeof (size), | ||
957 | &rd, | ||
958 | NULL); | ||
959 | if ( (0 == ret) || | ||
960 | (sizeof (size) != rd) || | ||
961 | (sizeof (pi) != size) ) | ||
836 | break; | 962 | break; |
837 | ret = ReadFile (lsocks_pipe, &pi, sizeof (pi), &rd, NULL); | 963 | ret = ReadFile (lsocks_pipe, |
838 | if ( (0 == ret) || (sizeof (pi) != rd)) | 964 | &pi, |
965 | sizeof (pi), | ||
966 | &rd, | ||
967 | NULL); | ||
968 | if ( (0 == ret) || | ||
969 | (sizeof (pi) != rd)) | ||
839 | break; | 970 | break; |
840 | s = WSASocketA (pi.iAddressFamily, pi.iSocketType, pi.iProtocol, &pi, 0, WSA_FLAG_OVERLAPPED); | 971 | s = WSASocketA (pi.iAddressFamily, |
841 | sh->lsocks[i] = GNUNET_NETWORK_socket_box_native (s); | 972 | pi.iSocketType, |
842 | if (NULL == sh->lsocks[i]) | 973 | pi.iProtocol, |
974 | &pi, | ||
975 | 0, | ||
976 | WSA_FLAG_OVERLAPPED); | ||
977 | lsocks[i] = GNUNET_NETWORK_socket_box_native (s); | ||
978 | if (NULL == lsocks[i]) | ||
843 | break; | 979 | break; |
844 | else if (i == count - 1) | 980 | else if (i == count - 1) |
845 | fail2 = 0; | 981 | fail2 = 0; |
846 | } | 982 | } |
847 | if (fail2) | 983 | if (fail2) |
848 | break; | 984 | break; |
849 | sh->lsocks[count] = NULL; | 985 | lsocks[count] = NULL; |
850 | fail = 0; | 986 | fail = 0; |
851 | } | 987 | } |
852 | while (fail); | 988 | while (fail); |
853 | |||
854 | CloseHandle (lsocks_pipe); | 989 | CloseHandle (lsocks_pipe); |
855 | 990 | ||
856 | if (fail) | 991 | if (fail) |
857 | { | 992 | { |
858 | LOG (GNUNET_ERROR_TYPE_ERROR, | 993 | LOG (GNUNET_ERROR_TYPE_ERROR, |
859 | _("Could not access a pre-bound socket, will try to bind myself\n")); | 994 | _("Could not access a pre-bound socket, will try to bind myself\n")); |
860 | for (i = 0; (i < count) && (NULL != sh->lsocks[i]); i++) | 995 | for (i = 0; (i < count) && (NULL != lsocks[i]); i++) |
861 | GNUNET_break (0 == GNUNET_NETWORK_socket_close (sh->lsocks[i])); | 996 | GNUNET_break (0 == GNUNET_NETWORK_socket_close (lsocks[i])); |
862 | GNUNET_free_non_null (sh->lsocks); | 997 | GNUNET_free (lsocks); |
863 | sh->lsocks = NULL; | 998 | return NULL; |
864 | return GNUNET_NO; | ||
865 | } | 999 | } |
866 | return GNUNET_YES; | 1000 | return lsocks; |
867 | } | 1001 | } |
868 | #endif | 1002 | #endif |
869 | 1003 | ||
@@ -899,15 +1033,20 @@ open_listen_socket (const struct sockaddr *server_addr, | |||
899 | port = 0; | 1033 | port = 0; |
900 | break; | 1034 | break; |
901 | } | 1035 | } |
902 | sock = GNUNET_NETWORK_socket_create (server_addr->sa_family, SOCK_STREAM, 0); | 1036 | sock = GNUNET_NETWORK_socket_create (server_addr->sa_family, |
1037 | SOCK_STREAM, | ||
1038 | 0); | ||
903 | if (NULL == sock) | 1039 | if (NULL == sock) |
904 | { | 1040 | { |
905 | LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket"); | 1041 | LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, |
1042 | "socket"); | ||
906 | errno = 0; | 1043 | errno = 0; |
907 | return NULL; | 1044 | return NULL; |
908 | } | 1045 | } |
909 | /* bind the socket */ | 1046 | /* bind the socket */ |
910 | if (GNUNET_OK != GNUNET_NETWORK_socket_bind (sock, server_addr, socklen)) | 1047 | if (GNUNET_OK != GNUNET_NETWORK_socket_bind (sock, |
1048 | server_addr, | ||
1049 | socklen)) | ||
911 | { | 1050 | { |
912 | eno = errno; | 1051 | eno = errno; |
913 | if (EADDRINUSE != errno) | 1052 | if (EADDRINUSE != errno) |
@@ -945,7 +1084,8 @@ open_listen_socket (const struct sockaddr *server_addr, | |||
945 | errno = eno; | 1084 | errno = eno; |
946 | return NULL; | 1085 | return NULL; |
947 | } | 1086 | } |
948 | if (GNUNET_OK != GNUNET_NETWORK_socket_listen (sock, 5)) | 1087 | if (GNUNET_OK != GNUNET_NETWORK_socket_listen (sock, |
1088 | 5)) | ||
949 | { | 1089 | { |
950 | LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, | 1090 | LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, |
951 | "listen"); | 1091 | "listen"); |
@@ -961,8 +1101,6 @@ open_listen_socket (const struct sockaddr *server_addr, | |||
961 | } | 1101 | } |
962 | 1102 | ||
963 | 1103 | ||
964 | |||
965 | |||
966 | /** | 1104 | /** |
967 | * Setup service handle | 1105 | * Setup service handle |
968 | * | 1106 | * |
@@ -982,9 +1120,8 @@ open_listen_socket (const struct sockaddr *server_addr, | |||
982 | static int | 1120 | static int |
983 | setup_service (struct GNUNET_SERVICE_Handle *sh) | 1121 | setup_service (struct GNUNET_SERVICE_Handle *sh) |
984 | { | 1122 | { |
985 | struct GNUNET_TIME_Relative idleout; | ||
986 | int tolerant; | 1123 | int tolerant; |
987 | 1124 | struct GNUNET_NETWORK_Handle **lsocks; | |
988 | #ifndef MINGW | 1125 | #ifndef MINGW |
989 | const char *nfds; | 1126 | const char *nfds; |
990 | unsigned int cnt; | 1127 | unsigned int cnt; |
@@ -992,72 +1129,85 @@ setup_service (struct GNUNET_SERVICE_Handle *sh) | |||
992 | #endif | 1129 | #endif |
993 | 1130 | ||
994 | if (GNUNET_CONFIGURATION_have_value | 1131 | if (GNUNET_CONFIGURATION_have_value |
995 | (sh->cfg, sh->service_name, "TOLERANT")) | 1132 | (sh->cfg, |
1133 | sh->service_name, | ||
1134 | "TOLERANT")) | ||
996 | { | 1135 | { |
997 | if (GNUNET_SYSERR == | 1136 | if (GNUNET_SYSERR == |
998 | (tolerant = | 1137 | (tolerant = |
999 | GNUNET_CONFIGURATION_get_value_yesno (sh->cfg, sh->service_name, | 1138 | GNUNET_CONFIGURATION_get_value_yesno (sh->cfg, |
1139 | sh->service_name, | ||
1000 | "TOLERANT"))) | 1140 | "TOLERANT"))) |
1001 | { | 1141 | { |
1002 | LOG (GNUNET_ERROR_TYPE_ERROR, | 1142 | LOG (GNUNET_ERROR_TYPE_ERROR, |
1003 | _("Specified value for `%s' of service `%s' is invalid\n"), | 1143 | _("Specified value for `%s' of service `%s' is invalid\n"), |
1004 | "TOLERANT", sh->service_name); | 1144 | "TOLERANT", |
1145 | sh->service_name); | ||
1005 | return GNUNET_SYSERR; | 1146 | return GNUNET_SYSERR; |
1006 | } | 1147 | } |
1007 | } | 1148 | } |
1008 | else | 1149 | else |
1009 | tolerant = GNUNET_NO; | 1150 | tolerant = GNUNET_NO; |
1010 | 1151 | ||
1152 | lsocks = NULL; | ||
1011 | #ifndef MINGW | 1153 | #ifndef MINGW |
1012 | errno = 0; | 1154 | errno = 0; |
1013 | if ((NULL != (nfds = getenv ("LISTEN_FDS"))) && | 1155 | if ( (NULL != (nfds = getenv ("LISTEN_FDS"))) && |
1014 | (1 == SSCANF (nfds, "%u", &cnt)) && (cnt > 0) && (cnt < FD_SETSIZE) && | 1156 | (1 == SSCANF (nfds, |
1015 | (cnt + 4 < FD_SETSIZE)) | 1157 | "%u", |
1158 | &cnt)) && | ||
1159 | (cnt > 0) && | ||
1160 | (cnt < FD_SETSIZE) && | ||
1161 | (cnt + 4 < FD_SETSIZE) ) | ||
1016 | { | 1162 | { |
1017 | sh->lsocks = | 1163 | lsocks = GNUNET_new_array (cnt + 1, |
1018 | GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle *) * (cnt + 1)); | 1164 | struct GNUNET_NETWORK_Handle *); |
1019 | while (0 < cnt--) | 1165 | while (0 < cnt--) |
1020 | { | 1166 | { |
1021 | flags = fcntl (3 + cnt, F_GETFD); | 1167 | flags = fcntl (3 + cnt, |
1022 | if ((flags < 0) || (0 != (flags & FD_CLOEXEC)) || | 1168 | F_GETFD); |
1023 | (NULL == | 1169 | if ( (flags < 0) || |
1024 | (sh->lsocks[cnt] = GNUNET_NETWORK_socket_box_native (3 + cnt)))) | 1170 | (0 != (flags & FD_CLOEXEC)) || |
1171 | (NULL == | ||
1172 | (lsocks[cnt] = GNUNET_NETWORK_socket_box_native (3 + cnt)))) | ||
1025 | { | 1173 | { |
1026 | LOG (GNUNET_ERROR_TYPE_ERROR, | 1174 | LOG (GNUNET_ERROR_TYPE_ERROR, |
1027 | _ | 1175 | _("Could not access pre-bound socket %u, will try to bind myself\n"), |
1028 | ("Could not access pre-bound socket %u, will try to bind myself\n"), | ||
1029 | (unsigned int) 3 + cnt); | 1176 | (unsigned int) 3 + cnt); |
1030 | cnt++; | 1177 | cnt++; |
1031 | while (sh->lsocks[cnt] != NULL) | 1178 | while (NULL != lsocks[cnt]) |
1032 | GNUNET_break (0 == GNUNET_NETWORK_socket_close (sh->lsocks[cnt++])); | 1179 | GNUNET_break (0 == GNUNET_NETWORK_socket_close (lsocks[cnt++])); |
1033 | GNUNET_free (sh->lsocks); | 1180 | GNUNET_free (lsocks); |
1034 | sh->lsocks = NULL; | 1181 | lsocks = NULL; |
1035 | break; | 1182 | break; |
1036 | } | 1183 | } |
1037 | } | 1184 | } |
1038 | unsetenv ("LISTEN_FDS"); | 1185 | unsetenv ("LISTEN_FDS"); |
1039 | } | 1186 | } |
1040 | #else | 1187 | #else |
1041 | if (getenv ("GNUNET_OS_READ_LSOCKS") != NULL) | 1188 | if (NULL != getenv ("GNUNET_OS_READ_LSOCKS")) |
1042 | { | 1189 | { |
1043 | receive_sockets_from_parent (sh); | 1190 | lsocks = receive_sockets_from_parent (sh); |
1044 | putenv ("GNUNET_OS_READ_LSOCKS="); | 1191 | putenv ("GNUNET_OS_READ_LSOCKS="); |
1045 | } | 1192 | } |
1046 | #endif | 1193 | #endif |
1047 | 1194 | ||
1048 | if (NULL != sh->lsocks) | 1195 | if (NULL != lsocks) |
1049 | { | 1196 | { |
1050 | /* listen only on inherited sockets if we have any */ | 1197 | /* listen only on inherited sockets if we have any */ |
1051 | struct GNUNET_NETWORK_Handle **ls = sh->lsocks; | 1198 | struct GNUNET_NETWORK_Handle **ls; |
1052 | for (; NULL != *ls; ls++) | 1199 | |
1200 | for (ls = lsocks; NULL != *ls; ls++) | ||
1053 | { | 1201 | { |
1054 | struct ServiceListenContext *slc; | 1202 | struct ServiceListenContext *slc; |
1055 | 1203 | ||
1056 | slc = GNUNET_new (struct ServiceListenContext); | 1204 | slc = GNUNET_new (struct ServiceListenContext); |
1057 | slc->listen_socket = *ls; | 1205 | slc->listen_socket = *ls; |
1058 | GNUNET_CONTAINER_DLL_insert (sh->slc_head, sh->slc_tail, slc); | 1206 | GNUNET_CONTAINER_DLL_insert (sh->slc_head, |
1207 | sh->slc_tail, | ||
1208 | slc); | ||
1059 | } | 1209 | } |
1060 | GNUNET_free_non_null (sh->lsocks); | 1210 | GNUNET_free (lsocks); |
1061 | } | 1211 | } |
1062 | else | 1212 | else |
1063 | { | 1213 | { |
@@ -1065,8 +1215,10 @@ setup_service (struct GNUNET_SERVICE_Handle *sh) | |||
1065 | socklen_t *addrlens; | 1215 | socklen_t *addrlens; |
1066 | int num; | 1216 | int num; |
1067 | 1217 | ||
1068 | num = get_server_addresses (sh->service_name, sh->cfg, | 1218 | num = get_server_addresses (sh->service_name, |
1069 | &addrs, &addrlens); | 1219 | sh->cfg, |
1220 | &addrs, | ||
1221 | &addrlens); | ||
1070 | if (GNUNET_SYSERR == num) | 1222 | if (GNUNET_SYSERR == num) |
1071 | return GNUNET_SYSERR; | 1223 | return GNUNET_SYSERR; |
1072 | 1224 | ||
@@ -1075,24 +1227,246 @@ setup_service (struct GNUNET_SERVICE_Handle *sh) | |||
1075 | struct ServiceListenContext *slc; | 1227 | struct ServiceListenContext *slc; |
1076 | 1228 | ||
1077 | slc = GNUNET_new (struct ServiceListenContext); | 1229 | slc = GNUNET_new (struct ServiceListenContext); |
1078 | slc->listen_socket = open_listen_socket (addrs[i], addrlens[i]); | 1230 | slc->listen_socket = open_listen_socket (addrs[i], |
1231 | addrlens[i]); | ||
1079 | GNUNET_break (NULL != slc->listen_socket); | 1232 | GNUNET_break (NULL != slc->listen_socket); |
1080 | GNUNET_CONTAINER_DLL_insert (sh->slc_head, sh->slc_tail, slc); | 1233 | GNUNET_CONTAINER_DLL_insert (sh->slc_head, |
1234 | sh->slc_tail, | ||
1235 | slc); | ||
1081 | } | 1236 | } |
1082 | } | 1237 | } |
1083 | 1238 | ||
1084 | sh->require_found = tolerant ? GNUNET_NO : GNUNET_YES; | 1239 | sh->require_found = tolerant ? GNUNET_NO : GNUNET_YES; |
1085 | sh->match_uid = | 1240 | sh->match_uid = |
1086 | GNUNET_CONFIGURATION_get_value_yesno (sh->cfg, sh->service_name, | 1241 | GNUNET_CONFIGURATION_get_value_yesno (sh->cfg, |
1242 | sh->service_name, | ||
1087 | "UNIX_MATCH_UID"); | 1243 | "UNIX_MATCH_UID"); |
1088 | sh->match_gid = | 1244 | sh->match_gid = |
1089 | GNUNET_CONFIGURATION_get_value_yesno (sh->cfg, sh->service_name, | 1245 | GNUNET_CONFIGURATION_get_value_yesno (sh->cfg, |
1246 | sh->service_name, | ||
1090 | "UNIX_MATCH_GID"); | 1247 | "UNIX_MATCH_GID"); |
1091 | process_acl4 (&sh->v4_denied, sh, "REJECT_FROM"); | 1248 | process_acl4 (&sh->v4_denied, |
1092 | process_acl4 (&sh->v4_allowed, sh, "ACCEPT_FROM"); | 1249 | sh, |
1093 | process_acl6 (&sh->v6_denied, sh, "REJECT_FROM6"); | 1250 | "REJECT_FROM"); |
1094 | process_acl6 (&sh->v6_allowed, sh, "ACCEPT_FROM6"); | 1251 | process_acl4 (&sh->v4_allowed, |
1252 | sh, | ||
1253 | "ACCEPT_FROM"); | ||
1254 | process_acl6 (&sh->v6_denied, | ||
1255 | sh, | ||
1256 | "REJECT_FROM6"); | ||
1257 | process_acl6 (&sh->v6_allowed, | ||
1258 | sh, | ||
1259 | "ACCEPT_FROM6"); | ||
1260 | return GNUNET_OK; | ||
1261 | } | ||
1262 | |||
1263 | |||
1264 | /** | ||
1265 | * Get the name of the user that'll be used | ||
1266 | * to provide the service. | ||
1267 | * | ||
1268 | * @param sh service context | ||
1269 | * @return value of the 'USERNAME' option | ||
1270 | */ | ||
1271 | static char * | ||
1272 | get_user_name (struct GNUNET_SERVICE_Handle *sh) | ||
1273 | { | ||
1274 | char *un; | ||
1275 | |||
1276 | if (GNUNET_OK != | ||
1277 | GNUNET_CONFIGURATION_get_value_filename (sh->cfg, | ||
1278 | sh->service_name, | ||
1279 | "USERNAME", | ||
1280 | &un)) | ||
1281 | return NULL; | ||
1282 | return un; | ||
1283 | } | ||
1284 | |||
1285 | |||
1286 | /** | ||
1287 | * Set user ID. | ||
1288 | * | ||
1289 | * @param sh service context | ||
1290 | * @return #GNUNET_OK on success, #GNUNET_SYSERR on error | ||
1291 | */ | ||
1292 | static int | ||
1293 | set_user_id (struct GNUNET_SERVICE_Handle *sh) | ||
1294 | { | ||
1295 | char *user; | ||
1296 | |||
1297 | if (NULL == (user = get_user_name (sh))) | ||
1298 | return GNUNET_OK; /* keep */ | ||
1299 | #ifndef MINGW | ||
1300 | struct passwd *pws; | ||
1301 | |||
1302 | errno = 0; | ||
1303 | pws = getpwnam (user); | ||
1304 | if (NULL == pws) | ||
1305 | { | ||
1306 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
1307 | _("Cannot obtain information about user `%s': %s\n"), | ||
1308 | user, | ||
1309 | errno == 0 ? _("No such user") : STRERROR (errno)); | ||
1310 | GNUNET_free (user); | ||
1311 | return GNUNET_SYSERR; | ||
1312 | } | ||
1313 | if ( (0 != setgid (pws->pw_gid)) || | ||
1314 | (0 != setegid (pws->pw_gid)) || | ||
1315 | #if HAVE_INITGROUPS | ||
1316 | (0 != initgroups (user, | ||
1317 | pws->pw_gid)) || | ||
1318 | #endif | ||
1319 | (0 != setuid (pws->pw_uid)) || | ||
1320 | (0 != seteuid (pws->pw_uid))) | ||
1321 | { | ||
1322 | if ((0 != setregid (pws->pw_gid, | ||
1323 | pws->pw_gid)) || | ||
1324 | (0 != setreuid (pws->pw_uid, | ||
1325 | pws->pw_uid))) | ||
1326 | { | ||
1327 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
1328 | _("Cannot change user/group to `%s': %s\n"), | ||
1329 | user, | ||
1330 | STRERROR (errno)); | ||
1331 | GNUNET_free (user); | ||
1332 | return GNUNET_SYSERR; | ||
1333 | } | ||
1334 | } | ||
1335 | #endif | ||
1336 | GNUNET_free (user); | ||
1337 | return GNUNET_OK; | ||
1338 | } | ||
1339 | |||
1340 | |||
1341 | /** | ||
1342 | * Get the name of the file where we will | ||
1343 | * write the PID of the service. | ||
1344 | * | ||
1345 | * @param sh service context | ||
1346 | * @return name of the file for the process ID | ||
1347 | */ | ||
1348 | static char * | ||
1349 | get_pid_file_name (struct GNUNET_SERVICE_Handle *sh) | ||
1350 | { | ||
1351 | char *pif; | ||
1352 | |||
1353 | if (GNUNET_OK != | ||
1354 | GNUNET_CONFIGURATION_get_value_filename (sh->cfg, | ||
1355 | sh->service_name, | ||
1356 | "PIDFILE", | ||
1357 | &pif)) | ||
1358 | return NULL; | ||
1359 | return pif; | ||
1360 | } | ||
1361 | |||
1362 | |||
1363 | /** | ||
1364 | * Delete the PID file that was created by our parent. | ||
1365 | * | ||
1366 | * @param sh service context | ||
1367 | */ | ||
1368 | static void | ||
1369 | pid_file_delete (struct GNUNET_SERVICE_Handle *sh) | ||
1370 | { | ||
1371 | char *pif = get_pid_file_name (sh); | ||
1372 | |||
1373 | if (NULL == pif) | ||
1374 | return; /* no PID file */ | ||
1375 | if (0 != UNLINK (pif)) | ||
1376 | LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, | ||
1377 | "unlink", | ||
1378 | pif); | ||
1379 | GNUNET_free (pif); | ||
1380 | } | ||
1381 | |||
1095 | 1382 | ||
1383 | /** | ||
1384 | * Detach from terminal. | ||
1385 | * | ||
1386 | * @param sh service context | ||
1387 | * @return #GNUNET_OK on success, #GNUNET_SYSERR on error | ||
1388 | */ | ||
1389 | static int | ||
1390 | detach_terminal (struct GNUNET_SERVICE_Handle *sh) | ||
1391 | { | ||
1392 | #ifndef MINGW | ||
1393 | pid_t pid; | ||
1394 | int nullfd; | ||
1395 | int filedes[2]; | ||
1396 | |||
1397 | if (0 != PIPE (filedes)) | ||
1398 | { | ||
1399 | LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, | ||
1400 | "pipe"); | ||
1401 | return GNUNET_SYSERR; | ||
1402 | } | ||
1403 | pid = fork (); | ||
1404 | if (pid < 0) | ||
1405 | { | ||
1406 | LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, | ||
1407 | "fork"); | ||
1408 | return GNUNET_SYSERR; | ||
1409 | } | ||
1410 | if (0 != pid) | ||
1411 | { | ||
1412 | /* Parent */ | ||
1413 | char c; | ||
1414 | |||
1415 | GNUNET_break (0 == CLOSE (filedes[1])); | ||
1416 | c = 'X'; | ||
1417 | if (1 != READ (filedes[0], | ||
1418 | &c, | ||
1419 | sizeof (char))) | ||
1420 | LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, | ||
1421 | "read"); | ||
1422 | fflush (stdout); | ||
1423 | switch (c) | ||
1424 | { | ||
1425 | case '.': | ||
1426 | exit (0); | ||
1427 | case 'I': | ||
1428 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
1429 | _("Service process failed to initialize\n")); | ||
1430 | break; | ||
1431 | case 'S': | ||
1432 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
1433 | _("Service process could not initialize server function\n")); | ||
1434 | break; | ||
1435 | case 'X': | ||
1436 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
1437 | _("Service process failed to report status\n")); | ||
1438 | break; | ||
1439 | } | ||
1440 | exit (1); /* child reported error */ | ||
1441 | } | ||
1442 | GNUNET_break (0 == CLOSE (0)); | ||
1443 | GNUNET_break (0 == CLOSE (1)); | ||
1444 | GNUNET_break (0 == CLOSE (filedes[0])); | ||
1445 | nullfd = OPEN ("/dev/null", | ||
1446 | O_RDWR | O_APPEND); | ||
1447 | if (nullfd < 0) | ||
1448 | return GNUNET_SYSERR; | ||
1449 | /* set stdin/stdout to /dev/null */ | ||
1450 | if ( (dup2 (nullfd, 0) < 0) || | ||
1451 | (dup2 (nullfd, 1) < 0) ) | ||
1452 | { | ||
1453 | LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, | ||
1454 | "dup2"); | ||
1455 | (void) CLOSE (nullfd); | ||
1456 | return GNUNET_SYSERR; | ||
1457 | } | ||
1458 | (void) CLOSE (nullfd); | ||
1459 | /* Detach from controlling terminal */ | ||
1460 | pid = setsid (); | ||
1461 | if (-1 == pid) | ||
1462 | LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, | ||
1463 | "setsid"); | ||
1464 | sh->ready_confirm_fd = filedes[1]; | ||
1465 | #else | ||
1466 | /* FIXME: we probably need to do something else | ||
1467 | * elsewhere in order to fork the process itself... */ | ||
1468 | FreeConsole (); | ||
1469 | #endif | ||
1096 | return GNUNET_OK; | 1470 | return GNUNET_OK; |
1097 | } | 1471 | } |
1098 | 1472 | ||
@@ -1156,7 +1530,6 @@ GNUNET_SERVICE_ruN_ (int argc, | |||
1156 | const char *xdg; | 1530 | const char *xdg; |
1157 | char *logfile; | 1531 | char *logfile; |
1158 | int do_daemonize; | 1532 | int do_daemonize; |
1159 | unsigned int i; | ||
1160 | unsigned long long skew_offset; | 1533 | unsigned long long skew_offset; |
1161 | unsigned long long skew_variance; | 1534 | unsigned long long skew_variance; |
1162 | long long clock_offset; | 1535 | long long clock_offset; |
@@ -1195,7 +1568,10 @@ GNUNET_SERVICE_ruN_ (int argc, | |||
1195 | sh.handlers = handlers; | 1568 | sh.handlers = handlers; |
1196 | 1569 | ||
1197 | /* setup subsystems */ | 1570 | /* setup subsystems */ |
1198 | ret = GNUNET_GETOPT_run (service_name, service_options, argc, argv); | 1571 | ret = GNUNET_GETOPT_run (service_name, |
1572 | service_options, | ||
1573 | argc, | ||
1574 | argv); | ||
1199 | if (GNUNET_SYSERR == ret) | 1575 | if (GNUNET_SYSERR == ret) |
1200 | goto shutdown; | 1576 | goto shutdown; |
1201 | if (GNUNET_NO == ret) | 1577 | if (GNUNET_NO == ret) |
@@ -1203,7 +1579,9 @@ GNUNET_SERVICE_ruN_ (int argc, | |||
1203 | err = 0; | 1579 | err = 0; |
1204 | goto shutdown; | 1580 | goto shutdown; |
1205 | } | 1581 | } |
1206 | if (GNUNET_OK != GNUNET_log_setup (service_name, loglev, logfile)) | 1582 | if (GNUNET_OK != GNUNET_log_setup (service_name, |
1583 | loglev, | ||
1584 | logfile)) | ||
1207 | { | 1585 | { |
1208 | GNUNET_break (0); | 1586 | GNUNET_break (0); |
1209 | goto shutdown; | 1587 | goto shutdown; |
@@ -1212,7 +1590,8 @@ GNUNET_SERVICE_ruN_ (int argc, | |||
1212 | opt_cfg_filename = GNUNET_strdup (cfg_filename); | 1590 | opt_cfg_filename = GNUNET_strdup (cfg_filename); |
1213 | if (GNUNET_YES == GNUNET_DISK_file_test (opt_cfg_filename)) | 1591 | if (GNUNET_YES == GNUNET_DISK_file_test (opt_cfg_filename)) |
1214 | { | 1592 | { |
1215 | if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, opt_cfg_filename)) | 1593 | if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, |
1594 | opt_cfg_filename)) | ||
1216 | { | 1595 | { |
1217 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | 1596 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, |
1218 | _("Malformed configuration file `%s', exit ...\n"), | 1597 | _("Malformed configuration file `%s', exit ...\n"), |
@@ -1222,20 +1601,23 @@ GNUNET_SERVICE_ruN_ (int argc, | |||
1222 | } | 1601 | } |
1223 | else | 1602 | else |
1224 | { | 1603 | { |
1225 | if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, NULL)) | 1604 | if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, |
1605 | NULL)) | ||
1226 | { | 1606 | { |
1227 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | 1607 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, |
1228 | _("Malformed configuration, exit ...\n")); | 1608 | _("Malformed configuration, exit ...\n")); |
1229 | goto shutdown; | 1609 | goto shutdown; |
1230 | } | 1610 | } |
1231 | if (0 != strcmp (opt_cfg_filename, cfg_filename)) | 1611 | if (0 != strcmp (opt_cfg_filename, |
1612 | cfg_filename)) | ||
1232 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | 1613 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, |
1233 | _("Could not access configuration file `%s'\n"), | 1614 | _("Could not access configuration file `%s'\n"), |
1234 | opt_cfg_filename); | 1615 | opt_cfg_filename); |
1235 | } | 1616 | } |
1236 | if (GNUNET_OK != setup_service (&sh)) | 1617 | if (GNUNET_OK != setup_service (&sh)) |
1237 | goto shutdown; | 1618 | goto shutdown; |
1238 | if ((1 == do_daemonize) && (GNUNET_OK != detach_terminal (&sh))) | 1619 | if ( (1 == do_daemonize) && |
1620 | (GNUNET_OK != detach_terminal (&sh)) ) | ||
1239 | { | 1621 | { |
1240 | GNUNET_break (0); | 1622 | GNUNET_break (0); |
1241 | goto shutdown; | 1623 | goto shutdown; |
@@ -1247,19 +1629,26 @@ GNUNET_SERVICE_ruN_ (int argc, | |||
1247 | service_name, | 1629 | service_name, |
1248 | opt_cfg_filename); | 1630 | opt_cfg_filename); |
1249 | if ((GNUNET_OK == | 1631 | if ((GNUNET_OK == |
1250 | GNUNET_CONFIGURATION_get_value_number (sh.cfg, "TESTING", | 1632 | GNUNET_CONFIGURATION_get_value_number (sh.cfg, |
1251 | "SKEW_OFFSET", &skew_offset)) && | 1633 | "TESTING", |
1634 | "SKEW_OFFSET", | ||
1635 | &skew_offset)) && | ||
1252 | (GNUNET_OK == | 1636 | (GNUNET_OK == |
1253 | GNUNET_CONFIGURATION_get_value_number (sh.cfg, "TESTING", | 1637 | GNUNET_CONFIGURATION_get_value_number (sh.cfg, |
1254 | "SKEW_VARIANCE", &skew_variance))) | 1638 | "TESTING", |
1639 | "SKEW_VARIANCE", | ||
1640 | &skew_variance))) | ||
1255 | { | 1641 | { |
1256 | clock_offset = skew_offset - skew_variance; | 1642 | clock_offset = skew_offset - skew_variance; |
1257 | GNUNET_TIME_set_offset (clock_offset); | 1643 | GNUNET_TIME_set_offset (clock_offset); |
1258 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Skewing clock by %dll ms\n", clock_offset); | 1644 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
1645 | "Skewing clock by %dll ms\n", | ||
1646 | clock_offset); | ||
1259 | } | 1647 | } |
1260 | /* actually run service */ | 1648 | /* actually run service */ |
1261 | err = 0; | 1649 | err = 0; |
1262 | GNUNET_SCHEDULER_run (&service_main, &sh); | 1650 | GNUNET_SCHEDULER_run (&service_main, |
1651 | &sh); | ||
1263 | /* shutdown */ | 1652 | /* shutdown */ |
1264 | if (1 == do_daemonize) | 1653 | if (1 == do_daemonize) |
1265 | pid_file_delete (&sh); | 1654 | pid_file_delete (&sh); |
@@ -1276,17 +1665,22 @@ shutdown: | |||
1276 | char *counter; | 1665 | char *counter; |
1277 | 1666 | ||
1278 | if ( (GNUNET_YES == | 1667 | if ( (GNUNET_YES == |
1279 | GNUNET_CONFIGURATION_have_value (sh.cfg, service_name, | 1668 | GNUNET_CONFIGURATION_have_value (sh.cfg, |
1669 | service_name, | ||
1280 | "GAUGER_HEAP")) && | 1670 | "GAUGER_HEAP")) && |
1281 | (GNUNET_OK == | 1671 | (GNUNET_OK == |
1282 | GNUNET_CONFIGURATION_get_value_string (sh.cfg, service_name, | 1672 | GNUNET_CONFIGURATION_get_value_string (sh.cfg, |
1673 | service_name, | ||
1283 | "GAUGER_HEAP", | 1674 | "GAUGER_HEAP", |
1284 | &counter)) ) | 1675 | &counter)) ) |
1285 | { | 1676 | { |
1286 | struct mallinfo mi; | 1677 | struct mallinfo mi; |
1287 | 1678 | ||
1288 | mi = mallinfo (); | 1679 | mi = mallinfo (); |
1289 | GAUGER (service_name, counter, mi.usmblks, "blocks"); | 1680 | GAUGER (service_name, |
1681 | counter, | ||
1682 | mi.usmblks, | ||
1683 | "blocks"); | ||
1290 | GNUNET_free (counter); | 1684 | GNUNET_free (counter); |
1291 | } | 1685 | } |
1292 | } | 1686 | } |
@@ -1297,6 +1691,7 @@ shutdown: | |||
1297 | while (NULL != sh.slc_head) | 1691 | while (NULL != sh.slc_head) |
1298 | { | 1692 | { |
1299 | struct ServiceListenContext *slc = sh.slc_head; | 1693 | struct ServiceListenContext *slc = sh.slc_head; |
1694 | |||
1300 | sh.slc_head = slc->next; | 1695 | sh.slc_head = slc->next; |
1301 | // FIXME: destroy slc | 1696 | // FIXME: destroy slc |
1302 | GNUNET_free (slc); | 1697 | GNUNET_free (slc); |
@@ -1329,10 +1724,10 @@ GNUNET_SERVICE_suspend (struct GNUNET_SERVICE_Handle *sh) | |||
1329 | for (slc = sh->slc_head; NULL != slc; slc = slc->next) | 1724 | for (slc = sh->slc_head; NULL != slc; slc = slc->next) |
1330 | { | 1725 | { |
1331 | if (NULL != slc->listen_task) | 1726 | if (NULL != slc->listen_task) |
1332 | { | 1727 | { |
1333 | GNUNET_SCHEDULER_cancel (slc->listen_task); | 1728 | GNUNET_SCHEDULER_cancel (slc->listen_task); |
1334 | slc->listen_task = NULL; | 1729 | slc->listen_task = NULL; |
1335 | } | 1730 | } |
1336 | } | 1731 | } |
1337 | } | 1732 | } |
1338 | 1733 | ||
@@ -1470,9 +1865,78 @@ start_client (struct GNUNET_SERVICE_Handle *sh, | |||
1470 | client->mq); | 1865 | client->mq); |
1471 | GNUNET_MQ_set_handlers_closure (client->mq, | 1866 | GNUNET_MQ_set_handlers_closure (client->mq, |
1472 | client->user_context); | 1867 | client->user_context); |
1473 | client->recv_task = GNUNET_SCHEDULER_add_read (client->sock, | 1868 | client->recv_task |
1474 | &service_client_recv, | 1869 | = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, |
1475 | client); | 1870 | client->sock, |
1871 | &service_client_recv, | ||
1872 | client); | ||
1873 | } | ||
1874 | |||
1875 | |||
1876 | /** | ||
1877 | * Check if the given IP address is in the list of IP addresses. | ||
1878 | * | ||
1879 | * @param list a list of networks | ||
1880 | * @param add the IP to check (in network byte order) | ||
1881 | * @return #GNUNET_NO if the IP is not in the list, #GNUNET_YES if it it is | ||
1882 | */ | ||
1883 | static int | ||
1884 | check_ipv4_listed (const struct GNUNET_STRINGS_IPv4NetworkPolicy *list, | ||
1885 | const struct in_addr *add) | ||
1886 | { | ||
1887 | unsigned int i; | ||
1888 | |||
1889 | if (NULL == list) | ||
1890 | return GNUNET_NO; | ||
1891 | i = 0; | ||
1892 | while ( (0 != list[i].network.s_addr) || | ||
1893 | (0 != list[i].netmask.s_addr) ) | ||
1894 | { | ||
1895 | if ((add->s_addr & list[i].netmask.s_addr) == | ||
1896 | (list[i].network.s_addr & list[i].netmask.s_addr)) | ||
1897 | return GNUNET_YES; | ||
1898 | i++; | ||
1899 | } | ||
1900 | return GNUNET_NO; | ||
1901 | } | ||
1902 | |||
1903 | |||
1904 | /** | ||
1905 | * Check if the given IP address is in the list of IP addresses. | ||
1906 | * | ||
1907 | * @param list a list of networks | ||
1908 | * @param ip the IP to check (in network byte order) | ||
1909 | * @return #GNUNET_NO if the IP is not in the list, #GNUNET_YES if it it is | ||
1910 | */ | ||
1911 | static int | ||
1912 | check_ipv6_listed (const struct GNUNET_STRINGS_IPv6NetworkPolicy *list, | ||
1913 | const struct in6_addr *ip) | ||
1914 | { | ||
1915 | unsigned int i; | ||
1916 | unsigned int j; | ||
1917 | struct in6_addr zero; | ||
1918 | |||
1919 | if (NULL == list) | ||
1920 | return GNUNET_NO; | ||
1921 | memset (&zero, | ||
1922 | 0, | ||
1923 | sizeof (struct in6_addr)); | ||
1924 | i = 0; | ||
1925 | NEXT: | ||
1926 | while (0 != memcmp (&zero, | ||
1927 | &list[i].network, | ||
1928 | sizeof (struct in6_addr))) | ||
1929 | { | ||
1930 | for (j = 0; j < sizeof (struct in6_addr) / sizeof (int); j++) | ||
1931 | if (((((int *) ip)[j] & ((int *) &list[i].netmask)[j])) != | ||
1932 | (((int *) &list[i].network)[j] & ((int *) &list[i].netmask)[j])) | ||
1933 | { | ||
1934 | i++; | ||
1935 | goto NEXT; | ||
1936 | } | ||
1937 | return GNUNET_YES; | ||
1938 | } | ||
1939 | return GNUNET_NO; | ||
1476 | } | 1940 | } |
1477 | 1941 | ||
1478 | 1942 | ||
@@ -1492,8 +1956,8 @@ accept_client (void *cls) | |||
1492 | while (1) | 1956 | while (1) |
1493 | { | 1957 | { |
1494 | struct GNUNET_NETWORK_Handle *sock; | 1958 | struct GNUNET_NETWORK_Handle *sock; |
1495 | struct sockaddr_in *v4; | 1959 | const struct sockaddr_in *v4; |
1496 | struct sockaddr_in6 *v6; | 1960 | const struct sockaddr_in6 *v6; |
1497 | struct sockaddr_storage sa; | 1961 | struct sockaddr_storage sa; |
1498 | socklen_t addrlen; | 1962 | socklen_t addrlen; |
1499 | int ok; | 1963 | int ok; |
@@ -1535,7 +1999,7 @@ accept_client (void *cls) | |||
1535 | LOG (GNUNET_ERROR_TYPE_WARNING, | 1999 | LOG (GNUNET_ERROR_TYPE_WARNING, |
1536 | _("Unknown address family %d\n"), | 2000 | _("Unknown address family %d\n"), |
1537 | sa.ss_family); | 2001 | sa.ss_family); |
1538 | return GNUNET_SYSERR; | 2002 | return; |
1539 | } | 2003 | } |
1540 | if (! ok) | 2004 | if (! ok) |
1541 | { | 2005 | { |
@@ -1553,9 +2017,11 @@ accept_client (void *cls) | |||
1553 | start_client (slc->sh, | 2017 | start_client (slc->sh, |
1554 | sock); | 2018 | sock); |
1555 | } | 2019 | } |
1556 | slc->listen_task = GNUNET_SCHEDULER_add_read (slc->listen_socket, | 2020 | slc->listen_task |
1557 | &accept_client, | 2021 | = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, |
1558 | slc); | 2022 | slc->listen_socket, |
2023 | &accept_client, | ||
2024 | slc); | ||
1559 | } | 2025 | } |
1560 | 2026 | ||
1561 | 2027 | ||
@@ -1572,9 +2038,11 @@ GNUNET_SERVICE_resume (struct GNUNET_SERVICE_Handle *sh) | |||
1572 | for (slc = sh->slc_head; NULL != slc; slc = slc->next) | 2038 | for (slc = sh->slc_head; NULL != slc; slc = slc->next) |
1573 | { | 2039 | { |
1574 | GNUNET_assert (NULL == slc->listen_task); | 2040 | GNUNET_assert (NULL == slc->listen_task); |
1575 | slc->listen_task = GNUNET_SCHEDULER_add_read (slc->listen_socket, | 2041 | slc->listen_task |
1576 | &accept_client, | 2042 | = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, |
1577 | slc); | 2043 | slc->listen_socket, |
2044 | &accept_client, | ||
2045 | slc); | ||
1578 | } | 2046 | } |
1579 | } | 2047 | } |
1580 | 2048 | ||