2 This file is part of GNUnet
3 Copyright (C) 2010-2014, 2018 GNUnet e.V.
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.
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.
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/>.
18 SPDX-License-Identifier: AGPL3.0-or-later
22 * @file transport/gnunet-communicator-unix.c
23 * @brief Transport plugin using unix domain sockets (!)
24 * Clearly, can only be used locally on Unix/Linux hosts...
25 * ONLY INTENDED FOR TESTING!!!
26 * @author Christian Grothoff
27 * @author Nathan Evans
30 #include "gnunet_util_lib.h"
31 #include "gnunet_protocols.h"
32 #include "gnunet_constants.h"
33 #include "gnunet_nt_lib.h"
34 #include "gnunet_statistics_service.h"
35 #include "gnunet_transport_communication_service.h"
38 * How many messages do we keep at most in the queue to the
39 * transport service before we start to drop (default,
40 * can be changed via the configuration file).
41 * Should be _below_ the level of the communicator API, as
42 * otherwise we may read messages just to have them dropped
43 * by the communicator API.
45 #define DEFAULT_MAX_QUEUE_LENGTH 8
48 * Address prefix used by the communicator.
50 #define COMMUNICATOR_ADDRESS_PREFIX "unix"
53 * Configuration section used by the communicator.
55 #define COMMUNICATOR_CONFIG_SECTION "communicator-unix"
60 #define UNIX_MTU UINT16_MAX
62 GNUNET_NETWORK_STRUCT_BEGIN
65 * UNIX Message-Packet header.
72 struct GNUNET_MessageHeader header;
75 * What is the identity of the sender (GNUNET_hash of public key)
77 struct GNUNET_PeerIdentity sender;
81 GNUNET_NETWORK_STRUCT_END
91 * Queues with pending messages (!) are kept in a DLL.
96 * Queues with pending messages (!) are kept in a DLL.
101 * To whom are we talking to.
103 struct GNUNET_PeerIdentity target;
106 * Address of the other peer.
108 struct sockaddr_un *address;
111 * Length of the address.
113 socklen_t address_len;
116 * Message currently scheduled for transmission, non-NULL if and only
117 * if this queue is in the #queue_head DLL.
119 const struct GNUNET_MessageHeader *msg;
122 * Message queue we are providing for the #ch.
124 struct GNUNET_MQ_Handle *mq;
127 * handle for this queue with the #ch.
129 struct GNUNET_TRANSPORT_QueueHandle *qh;
132 * Number of bytes we currently have in our write queue.
134 unsigned long long bytes_in_queue;
137 * Timeout for this queue.
139 struct GNUNET_TIME_Absolute timeout;
142 * Queue timeout task.
144 struct GNUNET_SCHEDULER_Task *timeout_task;
152 static struct GNUNET_SCHEDULER_Task *read_task;
157 static struct GNUNET_SCHEDULER_Task *write_task;
160 * Number of messages we currently have in our queues towards the transport service.
162 static unsigned long long delivering_messages;
165 * Maximum queue length before we stop reading towards the transport service.
167 static unsigned long long max_queue_length;
170 * For logging statistics.
172 static struct GNUNET_STATISTICS_Handle *stats;
177 static struct GNUNET_TRANSPORT_CommunicatorHandle *ch;
180 * Queues (map from peer identity to `struct Queue`)
182 static struct GNUNET_CONTAINER_MultiPeerMap *queue_map;
185 * Head of queue of messages to transmit.
187 static struct Queue *queue_head;
190 * Tail of queue of messages to transmit.
192 static struct Queue *queue_tail;
195 * socket that we transmit all data with
197 static struct GNUNET_NETWORK_Handle *unix_sock;
200 * Handle to the operation that publishes our address.
202 static struct GNUNET_TRANSPORT_AddressIdentifier *ai;
206 * Functions with this signature are called whenever we need
207 * to close a queue due to a disconnect or failure to
208 * establish a connection.
210 * @param queue queue to close down
213 queue_destroy (struct Queue *queue)
215 struct GNUNET_MQ_Handle *mq;
217 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
218 "Disconnecting queue for peer `%s'\n",
219 GNUNET_i2s (&queue->target));
220 if (0 != queue->bytes_in_queue)
222 GNUNET_CONTAINER_DLL_remove (queue_head,
225 queue->bytes_in_queue = 0;
227 if (NULL != (mq = queue->mq))
230 GNUNET_MQ_destroy (mq);
232 GNUNET_assert (GNUNET_YES ==
233 GNUNET_CONTAINER_multipeermap_remove (queue_map,
236 GNUNET_STATISTICS_set (stats,
238 GNUNET_CONTAINER_multipeermap_size (queue_map),
240 if (NULL != queue->timeout_task)
242 GNUNET_SCHEDULER_cancel (queue->timeout_task);
243 queue->timeout_task = NULL;
245 GNUNET_free (queue->address);
251 * Queue was idle for too long, so disconnect it
253 * @param cls the `struct Queue *` to disconnect
256 queue_timeout (void *cls)
258 struct Queue *queue = cls;
259 struct GNUNET_TIME_Relative left;
261 queue->timeout_task = NULL;
262 left = GNUNET_TIME_absolute_get_remaining (queue->timeout);
263 if (0 != left.rel_value_us)
265 /* not actually our turn yet, but let's at least update
266 the monitor, it may think we're about to die ... */
268 = GNUNET_SCHEDULER_add_delayed (left,
273 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
274 "Queue %p was idle for %s, disconnecting\n",
276 GNUNET_STRINGS_relative_time_to_string (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
278 queue_destroy (queue);
283 * Increment queue timeout due to activity. We do not immediately
284 * notify the monitor here as that might generate excessive
287 * @param queue queue for which the timeout should be rescheduled
290 reschedule_queue_timeout (struct Queue *queue)
292 GNUNET_assert (NULL != queue->timeout_task);
294 = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
299 * Convert unix path to a `struct sockaddr_un *`
301 * @param unixpath path to convert
302 * @param[out] sock_len set to the length of the address
303 * @param is_abstract is this an abstract @a unixpath
304 * @return converted unix path
306 static struct sockaddr_un *
307 unix_address_to_sockaddr (const char *unixpath,
310 struct sockaddr_un *un;
313 GNUNET_assert (0 < strlen (unixpath)); /* sanity check */
314 un = GNUNET_new (struct sockaddr_un);
315 un->sun_family = AF_UNIX;
316 slen = strlen (unixpath);
317 if (slen >= sizeof (un->sun_path))
318 slen = sizeof (un->sun_path) - 1;
319 GNUNET_memcpy (un->sun_path,
322 un->sun_path[slen] = '\0';
323 slen = sizeof (struct sockaddr_un);
324 #if HAVE_SOCKADDR_UN_SUN_LEN
325 un->sun_len = (u_char) slen;
328 if ('@' == un->sun_path[0])
329 un->sun_path[0] = '\0';
335 * Closure to #lookup_queue_it().
340 * Location to store the queue, if found.
345 * Address we are looking for.
347 const struct sockaddr_un *un;
350 * Number of bytes in @a un
357 * Function called to find a queue by address.
359 * @param cls the `struct LookupCtx *`
360 * @param key peer we are looking for (unused)
361 * @param value a queue
362 * @return #GNUNET_YES if not found (continue looking), #GNUNET_NO on success
365 lookup_queue_it (void *cls,
366 const struct GNUNET_PeerIdentity *key,
369 struct LookupCtx *lctx = cls;
370 struct Queue *queue = value;
372 if ( (queue->address_len = lctx->un_len) &&
373 (0 == memcmp (lctx->un,
375 queue->address_len)) )
385 * Find an existing queue by address.
387 * @param plugin the plugin
388 * @param address the address to find
389 * @return NULL if queue was not found
391 static struct Queue *
392 lookup_queue (const struct GNUNET_PeerIdentity *peer,
393 const struct sockaddr_un *un,
396 struct LookupCtx lctx;
399 lctx.un_len = un_len;
400 GNUNET_CONTAINER_multipeermap_get_multiple (queue_map,
409 * We have been notified that our socket is ready to write.
410 * Then reschedule this function to be called again once more is available.
415 select_write_cb (void *cls)
417 struct Queue *queue = queue_tail;
418 const struct GNUNET_MessageHeader *msg = queue->msg;
419 size_t msg_size = ntohs (msg->size);
422 /* take queue of the ready list */
424 GNUNET_CONTAINER_DLL_remove (queue_head,
427 if (NULL != queue_head)
429 GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
436 GNUNET_MQ_impl_send_continue (queue->mq);
439 sent = GNUNET_NETWORK_socket_sendto (unix_sock,
442 (const struct sockaddr *) queue->address,
444 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
445 "UNIX transmitted message to %s (%d/%u: %s)\n",
446 GNUNET_i2s (&queue->target),
448 (unsigned int) msg_size,
449 (sent < 0) ? STRERROR (errno) : "ok");
452 GNUNET_STATISTICS_update (stats,
456 reschedule_queue_timeout (queue);
457 return; /* all good */
459 GNUNET_STATISTICS_update (stats,
460 "# network transmission failures",
467 /* We should retry later... */
468 GNUNET_log_strerror (GNUNET_ERROR_TYPE_DEBUG,
474 socklen_t len = sizeof (size);
476 GNUNET_NETWORK_socket_getsockopt (unix_sock,
481 if (size > ntohs (msg->size))
483 /* Buffer is bigger than message: error, no retry
484 * This should never happen!*/
488 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
489 "Trying to increase socket buffer size from %u to %u for message size %u\n",
491 (unsigned int) ((msg_size / 1000) + 2) * 1000,
492 (unsigned int) msg_size);
493 size = ((msg_size / 1000) + 2) * 1000;
495 GNUNET_NETWORK_socket_setsockopt (unix_sock,
500 goto resend; /* Increased buffer size, retry sending */
501 /* Ok, then just try very modest increase */
504 GNUNET_NETWORK_socket_setsockopt (unix_sock,
509 goto resend; /* Increased buffer size, retry sending */
510 /* Could not increase buffer size: error, no retry */
511 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
516 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
524 * Signature of functions implementing the sending functionality of a
527 * @param mq the message queue
528 * @param msg the message to send
529 * @param impl_state our `struct Queue`
532 mq_send (struct GNUNET_MQ_Handle *mq,
533 const struct GNUNET_MessageHeader *msg,
536 struct Queue *queue = impl_state;
538 GNUNET_assert (mq == queue->mq);
539 GNUNET_assert (NULL == queue->msg);
541 GNUNET_CONTAINER_DLL_insert (queue_head,
544 GNUNET_assert (NULL != unix_sock);
545 if (NULL == write_task)
547 GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
555 * Signature of functions implementing the destruction of a message
556 * queue. Implementations must not free @a mq, but should take care
559 * @param mq the message queue to destroy
560 * @param impl_state our `struct Queue`
563 mq_destroy (struct GNUNET_MQ_Handle *mq,
566 struct Queue *queue = impl_state;
571 queue_destroy (queue);
577 * Implementation function that cancels the currently sent message.
579 * @param mq message queue
580 * @param impl_state our `struct Queue`
583 mq_cancel (struct GNUNET_MQ_Handle *mq,
586 struct Queue *queue = impl_state;
588 GNUNET_assert (NULL != queue->msg);
590 GNUNET_CONTAINER_DLL_remove (queue_head,
593 GNUNET_assert (NULL != write_task);
594 if (NULL == queue_head)
596 GNUNET_SCHEDULER_cancel (write_task);
603 * Generic error handler, called with the appropriate
604 * error code and the same closure specified at the creation of
606 * Not every message queue implementation supports an error handler.
608 * @param cls our `struct Queue`
609 * @param error error code
613 enum GNUNET_MQ_Error error)
615 struct Queue *queue = cls;
617 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
618 "UNIX MQ error in queue to %s: %d\n",
619 GNUNET_i2s (&queue->target),
621 queue_destroy (queue);
626 * Creates a new outbound queue the transport service will use to send
627 * data to another peer.
629 * @param peer the target peer
630 * @param cs inbound or outbound queue
631 * @param un the address
632 * @param un_len number of bytes in @a un
633 * @return the queue or NULL of max connections exceeded
635 static struct Queue *
636 setup_queue (const struct GNUNET_PeerIdentity *target,
637 enum GNUNET_TRANSPORT_ConnectionStatus cs,
638 const struct sockaddr_un *un,
643 queue = GNUNET_new (struct Queue);
644 queue->target = *target;
645 queue->address = GNUNET_memdup (un,
647 queue->address_len = un_len;
648 (void) GNUNET_CONTAINER_multipeermap_put (queue_map,
651 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
652 GNUNET_STATISTICS_set (stats,
654 GNUNET_CONTAINER_multipeermap_size (queue_map),
656 queue->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
658 = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
662 = GNUNET_MQ_queue_for_callbacks (&mq_send,
672 if ('\0' == un->sun_path[0])
673 GNUNET_asprintf (&foreign_addr,
675 COMMUNICATOR_ADDRESS_PREFIX,
678 GNUNET_asprintf (&foreign_addr,
680 COMMUNICATOR_ADDRESS_PREFIX,
683 = GNUNET_TRANSPORT_communicator_mq_add (ch,
690 GNUNET_free (foreign_addr);
697 * We have been notified that our socket has something to read. Do the
698 * read and reschedule this function to be called again once more is
704 select_read_cb (void *cls);
708 * Function called when message was successfully passed to
709 * transport service. Continue read activity.
712 * @param success #GNUNET_OK on success
715 receive_complete_cb (void *cls,
718 delivering_messages--;
719 if (GNUNET_OK != success)
720 GNUNET_STATISTICS_update (stats,
721 "# transport transmission failures",
724 GNUNET_assert (NULL != unix_sock);
725 if ( (NULL == read_task) &&
726 (delivering_messages < max_queue_length) )
727 read_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
735 * We have been notified that our socket has something to read. Do the
736 * read and reschedule this function to be called again once more is
742 select_read_cb (void *cls)
744 char buf[65536] GNUNET_ALIGN;
746 const struct UNIXMessage *msg;
747 struct sockaddr_un un;
752 GNUNET_assert (NULL != unix_sock);
753 read_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
757 addrlen = sizeof (un);
761 ret = GNUNET_NETWORK_socket_recvfrom (unix_sock,
764 (struct sockaddr *) &un,
767 ( (EAGAIN == errno) ||
768 (ENOBUFS == errno) ) )
772 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
776 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
777 "Read %d bytes from socket %s\n",
780 GNUNET_assert (AF_UNIX == (un.sun_family));
781 msg = (struct UNIXMessage *) buf;
782 msize = ntohs (msg->header.size);
783 if ( (msize < sizeof (struct UNIXMessage)) ||
789 queue = lookup_queue (&msg->sender,
793 queue = setup_queue (&msg->sender,
794 GNUNET_TRANSPORT_CS_INBOUND,
798 reschedule_queue_timeout (queue);
801 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
802 _("Maximum number of UNIX connections exceeded, dropping incoming message\n"));
808 uint16_t tsize = msize - sizeof (struct UNIXMessage);
809 const char *msgbuf = (const char *) &msg[1];
811 while (offset + sizeof (struct GNUNET_MessageHeader) <= tsize)
813 const struct GNUNET_MessageHeader *currhdr;
814 struct GNUNET_MessageHeader al_hdr;
817 currhdr = (const struct GNUNET_MessageHeader *) &msgbuf[offset];
818 /* ensure aligned access */
822 csize = ntohs (al_hdr.size);
823 if ( (csize < sizeof (struct GNUNET_MessageHeader)) ||
824 (csize > tsize - offset))
829 ret = GNUNET_TRANSPORT_communicator_receive (ch,
832 GNUNET_TIME_UNIT_FOREVER_REL,
833 &receive_complete_cb,
835 if (GNUNET_SYSERR == ret)
836 return; /* transport not up */
837 if (GNUNET_NO == ret)
839 delivering_messages++;
843 if (delivering_messages >= max_queue_length)
845 /* we should try to apply 'back pressure' */
846 GNUNET_SCHEDULER_cancel (read_task);
853 * Function called by the transport service to initialize a
854 * message queue given address information about another peer.
855 * If and when the communication channel is established, the
856 * communicator must call #GNUNET_TRANSPORT_communicator_mq_add()
857 * to notify the service that the channel is now up. It is
858 * the responsibility of the communicator to manage sane
859 * retries and timeouts for any @a peer/@a address combination
860 * provided by the transport service. Timeouts and retries
861 * do not need to be signalled to the transport service.
864 * @param peer identity of the other peer
865 * @param address where to send the message, human-readable
866 * communicator-specific format, 0-terminated, UTF-8
867 * @return #GNUNET_OK on success, #GNUNET_SYSERR if the provided address is invalid
871 const struct GNUNET_PeerIdentity *peer,
876 struct sockaddr_un *un;
879 if (0 != strncmp (address,
880 COMMUNICATOR_ADDRESS_PREFIX "-",
881 strlen (COMMUNICATOR_ADDRESS_PREFIX "-")))
884 return GNUNET_SYSERR;
886 path = &address[strlen (COMMUNICATOR_ADDRESS_PREFIX "-")];
887 un = unix_address_to_sockaddr (path,
889 queue = lookup_queue (peer,
894 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
895 "Address `%s' for %s ignored, queue exists\n",
901 queue = setup_queue (peer,
902 GNUNET_TRANSPORT_CS_OUTBOUND,
908 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
909 "Failed to setup queue to %s at `%s'\n",
919 * Iterator over all message queues to clean up.
922 * @param target unused
923 * @param value the queue to destroy
924 * @return #GNUNET_OK to continue to iterate
927 get_queue_delete_it (void *cls,
928 const struct GNUNET_PeerIdentity *target,
931 struct Queue *queue = value;
935 queue_destroy (queue);
941 * Shutdown the UNIX communicator.
943 * @param cls NULL (always)
946 do_shutdown (void *cls)
948 if (NULL != read_task)
950 GNUNET_SCHEDULER_cancel (read_task);
953 if (NULL != write_task)
955 GNUNET_SCHEDULER_cancel (write_task);
958 if (NULL != unix_sock)
960 GNUNET_break (GNUNET_OK ==
961 GNUNET_NETWORK_socket_close (unix_sock));
964 GNUNET_CONTAINER_multipeermap_iterate (queue_map,
965 &get_queue_delete_it,
967 GNUNET_CONTAINER_multipeermap_destroy (queue_map);
970 GNUNET_TRANSPORT_communicator_address_remove (ai);
975 GNUNET_TRANSPORT_communicator_disconnect (ch);
980 GNUNET_STATISTICS_destroy (stats,
988 * Function called when the transport service has received an
989 * acknowledgement for this communicator (!) via a different return
992 * Not applicable for UNIX.
995 * @param sender which peer sent the notification
999 enc_notify_cb (void *cls,
1000 const struct GNUNET_PeerIdentity *sender,
1001 const struct GNUNET_MessageHeader *msg)
1006 GNUNET_break_op (0);
1011 * Setup communicator and launch network interactions.
1013 * @param cls NULL (always)
1014 * @param args remaining command-line arguments
1015 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
1016 * @param cfg configuration
1021 const char *cfgfile,
1022 const struct GNUNET_CONFIGURATION_Handle *cfg)
1024 char *unix_socket_path;
1025 struct sockaddr_un *un;
1031 GNUNET_CONFIGURATION_get_value_filename (cfg,
1032 COMMUNICATOR_CONFIG_SECTION,
1036 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
1037 COMMUNICATOR_CONFIG_SECTION,
1042 GNUNET_CONFIGURATION_get_value_number (cfg,
1043 COMMUNICATOR_CONFIG_SECTION,
1046 max_queue_length = DEFAULT_MAX_QUEUE_LENGTH;
1048 un = unix_address_to_sockaddr (unix_socket_path,
1052 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1053 "Failed to setup UNIX domain socket address with path `%s'\n",
1055 GNUNET_free (unix_socket_path);
1058 unix_sock = GNUNET_NETWORK_socket_create (AF_UNIX,
1061 if (NULL == unix_sock)
1063 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
1066 GNUNET_free (unix_socket_path);
1069 if ( ('\0' != un->sun_path[0]) &&
1071 GNUNET_DISK_directory_create_for_file (un->sun_path)) )
1073 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1074 _("Cannot create path to `%s'\n"),
1076 GNUNET_NETWORK_socket_close (unix_sock);
1079 GNUNET_free (unix_socket_path);
1083 GNUNET_NETWORK_socket_bind (unix_sock,
1084 (const struct sockaddr *) un,
1087 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
1090 GNUNET_NETWORK_socket_close (unix_sock);
1093 GNUNET_free (unix_socket_path);
1097 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1100 stats = GNUNET_STATISTICS_create ("C-UNIX",
1102 GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
1104 read_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
1108 queue_map = GNUNET_CONTAINER_multipeermap_create (10,
1110 ch = GNUNET_TRANSPORT_communicator_connect (cfg,
1111 COMMUNICATOR_CONFIG_SECTION,
1112 COMMUNICATOR_ADDRESS_PREFIX,
1113 GNUNET_TRANSPORT_CC_RELIABLE,
1121 GNUNET_SCHEDULER_shutdown ();
1122 GNUNET_free (unix_socket_path);
1125 GNUNET_asprintf (&my_addr,
1127 COMMUNICATOR_ADDRESS_PREFIX,
1129 GNUNET_free (unix_socket_path);
1130 ai = GNUNET_TRANSPORT_communicator_address_add (ch,
1133 GNUNET_TIME_UNIT_FOREVER_REL);
1134 GNUNET_free (my_addr);
1139 * The main function for the UNIX communicator.
1141 * @param argc number of arguments from the command line
1142 * @param argv command line arguments
1143 * @return 0 ok, 1 on error
1149 static const struct GNUNET_GETOPT_CommandLineOption options[] = {
1150 GNUNET_GETOPT_OPTION_END
1155 GNUNET_STRINGS_get_utf8_args (argc, argv,
1161 GNUNET_PROGRAM_run (argc, argv,
1162 "gnunet-communicator-unix",
1163 _("GNUnet UNIX domain socket communicator"),
1167 GNUNET_free ((void*) argv);
1172 #if defined(LINUX) && defined(__GLIBC__)
1176 * MINIMIZE heap size (way below 128k) since this process doesn't need much.
1178 void __attribute__ ((constructor))
1179 GNUNET_ARM_memory_init ()
1181 mallopt (M_TRIM_THRESHOLD, 4 * 1024);
1182 mallopt (M_TOP_PAD, 1 * 1024);
1187 /* end of gnunet-communicator-unix.c */