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/>.
20 * @file transport/gnunet-communicator-unix.c
21 * @brief Transport plugin using unix domain sockets (!)
22 * Clearly, can only be used locally on Unix/Linux hosts...
23 * ONLY INTENDED FOR TESTING!!!
24 * @author Christian Grothoff
25 * @author Nathan Evans
28 #include "gnunet_util_lib.h"
29 #include "gnunet_protocols.h"
30 #include "gnunet_constants.h"
31 #include "gnunet_nt_lib.h"
32 #include "gnunet_statistics_service.h"
33 #include "gnunet_transport_communication_service.h"
36 * How many messages do we keep at most in the queue to the
37 * transport service before we start to drop (default,
38 * can be changed via the configuration file).
39 * Should be _below_ the level of the communicator API, as
40 * otherwise we may read messages just to have them dropped
41 * by the communicator API.
43 #define DEFAULT_MAX_QUEUE_LENGTH 8
46 * Address prefix used by the communicator.
48 #define COMMUNICATOR_ADDRESS_PREFIX "unix"
51 * Configuration section used by the communicator.
53 #define COMMUNICATOR_CONFIG_SECTION "communicator-unix"
58 #define UNIX_MTU UINT16_MAX
60 GNUNET_NETWORK_STRUCT_BEGIN
63 * UNIX Message-Packet header.
70 struct GNUNET_MessageHeader header;
73 * What is the identity of the sender (GNUNET_hash of public key)
75 struct GNUNET_PeerIdentity sender;
79 GNUNET_NETWORK_STRUCT_END
89 * Queues with pending messages (!) are kept in a DLL.
94 * Queues with pending messages (!) are kept in a DLL.
99 * To whom are we talking to.
101 struct GNUNET_PeerIdentity target;
104 * Address of the other peer.
106 struct sockaddr_un *address;
109 * Length of the address.
111 socklen_t address_len;
114 * Message currently scheduled for transmission, non-NULL if and only
115 * if this queue is in the #queue_head DLL.
117 const struct GNUNET_MessageHeader *msg;
120 * Message queue we are providing for the #ch.
122 struct GNUNET_MQ_Handle *mq;
125 * handle for this queue with the #ch.
127 struct GNUNET_TRANSPORT_QueueHandle *qh;
130 * Number of bytes we currently have in our write queue.
132 unsigned long long bytes_in_queue;
135 * Timeout for this queue.
137 struct GNUNET_TIME_Absolute timeout;
140 * Queue timeout task.
142 struct GNUNET_SCHEDULER_Task *timeout_task;
150 static struct GNUNET_SCHEDULER_Task *read_task;
155 static struct GNUNET_SCHEDULER_Task *write_task;
158 * Number of messages we currently have in our queues towards the transport service.
160 static unsigned long long delivering_messages;
163 * Maximum queue length before we stop reading towards the transport service.
165 static unsigned long long max_queue_length;
168 * For logging statistics.
170 static struct GNUNET_STATISTICS_Handle *stats;
175 static struct GNUNET_TRANSPORT_CommunicatorHandle *ch;
178 * Queues (map from peer identity to `struct Queue`)
180 static struct GNUNET_CONTAINER_MultiPeerMap *queue_map;
183 * Head of queue of messages to transmit.
185 static struct Queue *queue_head;
188 * Tail of queue of messages to transmit.
190 static struct Queue *queue_tail;
193 * socket that we transmit all data with
195 static struct GNUNET_NETWORK_Handle *unix_sock;
198 * Handle to the operation that publishes our address.
200 static struct GNUNET_TRANSPORT_AddressIdentifier *ai;
204 * Functions with this signature are called whenever we need
205 * to close a queue due to a disconnect or failure to
206 * establish a connection.
208 * @param queue queue to close down
211 queue_destroy (struct Queue *queue)
213 struct GNUNET_MQ_Handle *mq;
215 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
216 "Disconnecting queue for peer `%s'\n",
217 GNUNET_i2s (&queue->target));
218 if (0 != queue->bytes_in_queue)
220 GNUNET_CONTAINER_DLL_remove (queue_head,
223 queue->bytes_in_queue = 0;
225 if (NULL != (mq = queue->mq))
228 GNUNET_MQ_destroy (mq);
230 GNUNET_assert (GNUNET_YES ==
231 GNUNET_CONTAINER_multipeermap_remove (queue_map,
234 GNUNET_STATISTICS_set (stats,
235 "# UNIX queues active",
236 GNUNET_CONTAINER_multipeermap_size (queue_map),
238 if (NULL != queue->timeout_task)
240 GNUNET_SCHEDULER_cancel (queue->timeout_task);
241 queue->timeout_task = NULL;
243 GNUNET_free (queue->address);
249 * Queue was idle for too long, so disconnect it
251 * @param cls the `struct Queue *` to disconnect
254 queue_timeout (void *cls)
256 struct Queue *queue = cls;
257 struct GNUNET_TIME_Relative left;
259 queue->timeout_task = NULL;
260 left = GNUNET_TIME_absolute_get_remaining (queue->timeout);
261 if (0 != left.rel_value_us)
263 /* not actually our turn yet, but let's at least update
264 the monitor, it may think we're about to die ... */
266 = GNUNET_SCHEDULER_add_delayed (left,
271 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
272 "Queue %p was idle for %s, disconnecting\n",
274 GNUNET_STRINGS_relative_time_to_string (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
276 queue_destroy (queue);
281 * Increment queue timeout due to activity. We do not immediately
282 * notify the monitor here as that might generate excessive
285 * @param queue queue for which the timeout should be rescheduled
288 reschedule_queue_timeout (struct Queue *queue)
290 GNUNET_assert (NULL != queue->timeout_task);
292 = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
297 * Convert unix path to a `struct sockaddr_un *`
299 * @param unixpath path to convert
300 * @param[out] sock_len set to the length of the address
301 * @param is_abstract is this an abstract @a unixpath
302 * @return converted unix path
304 static struct sockaddr_un *
305 unix_address_to_sockaddr (const char *unixpath,
308 struct sockaddr_un *un;
311 GNUNET_assert (0 < strlen (unixpath)); /* sanity check */
312 un = GNUNET_new (struct sockaddr_un);
313 un->sun_family = AF_UNIX;
314 slen = strlen (unixpath);
315 if (slen >= sizeof (un->sun_path))
316 slen = sizeof (un->sun_path) - 1;
317 GNUNET_memcpy (un->sun_path,
320 un->sun_path[slen] = '\0';
321 slen = sizeof (struct sockaddr_un);
322 #if HAVE_SOCKADDR_UN_SUN_LEN
323 un->sun_len = (u_char) slen;
326 if ('@' == un->sun_path[0])
327 un->sun_path[0] = '\0';
333 * Closure to #lookup_queue_it().
338 * Location to store the queue, if found.
343 * Address we are looking for.
345 const struct sockaddr_un *un;
348 * Number of bytes in @a un
355 * Function called to find a queue by address.
357 * @param cls the `struct LookupCtx *`
358 * @param key peer we are looking for (unused)
359 * @param value a queue
360 * @return #GNUNET_YES if not found (continue looking), #GNUNET_NO on success
363 lookup_queue_it (void *cls,
364 const struct GNUNET_PeerIdentity *key,
367 struct LookupCtx *lctx = cls;
368 struct Queue *queue = value;
370 if ( (queue->address_len = lctx->un_len) &&
371 (0 == memcmp (lctx->un,
373 queue->address_len)) )
383 * Find an existing queue by address.
385 * @param plugin the plugin
386 * @param address the address to find
387 * @return NULL if queue was not found
389 static struct Queue *
390 lookup_queue (const struct GNUNET_PeerIdentity *peer,
391 const struct sockaddr_un *un,
394 struct LookupCtx lctx;
397 lctx.un_len = un_len;
398 GNUNET_CONTAINER_multipeermap_get_multiple (queue_map,
407 * We have been notified that our socket is ready to write.
408 * Then reschedule this function to be called again once more is available.
413 select_write_cb (void *cls)
415 struct Queue *queue = queue_tail;
416 const struct GNUNET_MessageHeader *msg = queue->msg;
417 size_t msg_size = ntohs (msg->size);
420 /* take queue of the ready list */
422 GNUNET_CONTAINER_DLL_remove (queue_head,
425 if (NULL != queue_head)
427 GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
434 GNUNET_MQ_impl_send_continue (queue->mq);
437 sent = GNUNET_NETWORK_socket_sendto (unix_sock,
440 (const struct sockaddr *) queue->address,
442 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
443 "UNIX transmitted message to %s (%d/%u: %s)\n",
444 GNUNET_i2s (&queue->target),
446 (unsigned int) msg_size,
447 (sent < 0) ? STRERROR (errno) : "ok");
450 GNUNET_STATISTICS_update (stats,
454 reschedule_queue_timeout (queue);
455 return; /* all good */
457 GNUNET_STATISTICS_update (stats,
458 "# network transmission failures",
465 /* We should retry later... */
466 GNUNET_log_strerror (GNUNET_ERROR_TYPE_DEBUG,
472 socklen_t len = sizeof (size);
474 GNUNET_NETWORK_socket_getsockopt (unix_sock,
479 if (size > ntohs (msg->size))
481 /* Buffer is bigger than message: error, no retry
482 * This should never happen!*/
486 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
487 "Trying to increase socket buffer size from %u to %u for message size %u\n",
489 (unsigned int) ((msg_size / 1000) + 2) * 1000,
490 (unsigned int) msg_size);
491 size = ((msg_size / 1000) + 2) * 1000;
493 GNUNET_NETWORK_socket_setsockopt (unix_sock,
498 goto resend; /* Increased buffer size, retry sending */
499 /* Ok, then just try very modest increase */
502 GNUNET_NETWORK_socket_setsockopt (unix_sock,
507 goto resend; /* Increased buffer size, retry sending */
508 /* Could not increase buffer size: error, no retry */
509 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
514 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
522 * Signature of functions implementing the sending functionality of a
525 * @param mq the message queue
526 * @param msg the message to send
527 * @param impl_state our `struct Queue`
530 mq_send (struct GNUNET_MQ_Handle *mq,
531 const struct GNUNET_MessageHeader *msg,
534 struct Queue *queue = impl_state;
536 GNUNET_assert (mq == queue->mq);
537 GNUNET_assert (NULL == queue->msg);
539 GNUNET_CONTAINER_DLL_insert (queue_head,
542 GNUNET_assert (NULL != unix_sock);
543 if (NULL == write_task)
545 GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
553 * Signature of functions implementing the destruction of a message
554 * queue. Implementations must not free @a mq, but should take care
557 * @param mq the message queue to destroy
558 * @param impl_state our `struct Queue`
561 mq_destroy (struct GNUNET_MQ_Handle *mq,
564 struct Queue *queue = impl_state;
569 queue_destroy (queue);
575 * Implementation function that cancels the currently sent message.
577 * @param mq message queue
578 * @param impl_state our `struct Queue`
581 mq_cancel (struct GNUNET_MQ_Handle *mq,
584 struct Queue *queue = impl_state;
586 GNUNET_assert (NULL != queue->msg);
588 GNUNET_CONTAINER_DLL_remove (queue_head,
591 GNUNET_assert (NULL != write_task);
592 if (NULL == queue_head)
594 GNUNET_SCHEDULER_cancel (write_task);
601 * Generic error handler, called with the appropriate
602 * error code and the same closure specified at the creation of
604 * Not every message queue implementation supports an error handler.
606 * @param cls our `struct Queue`
607 * @param error error code
611 enum GNUNET_MQ_Error error)
613 struct Queue *queue = cls;
615 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
616 "UNIX MQ error in queue to %s: %d\n",
617 GNUNET_i2s (&queue->target),
619 queue_destroy (queue);
624 * Creates a new outbound queue the transport service will use to send
625 * data to another peer.
627 * @param peer the target peer
628 * @param cs inbound or outbound queue
629 * @param un the address
630 * @param un_len number of bytes in @a un
631 * @return the queue or NULL of max connections exceeded
633 static struct Queue *
634 setup_queue (const struct GNUNET_PeerIdentity *target,
635 enum GNUNET_TRANSPORT_ConnectionStatus cs,
636 const struct sockaddr_un *un,
641 queue = GNUNET_new (struct Queue);
642 queue->target = *target;
643 queue->address = GNUNET_memdup (un,
645 queue->address_len = un_len;
646 (void) GNUNET_CONTAINER_multipeermap_put (queue_map,
649 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
650 GNUNET_STATISTICS_set (stats,
652 GNUNET_CONTAINER_multipeermap_size (queue_map),
654 queue->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
656 = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
660 = GNUNET_MQ_queue_for_callbacks (&mq_send,
670 if ('\0' == un->sun_path[0])
671 GNUNET_asprintf (&foreign_addr,
673 COMMUNICATOR_ADDRESS_PREFIX,
676 GNUNET_asprintf (&foreign_addr,
678 COMMUNICATOR_ADDRESS_PREFIX,
681 = GNUNET_TRANSPORT_communicator_mq_add (ch,
689 GNUNET_free (foreign_addr);
696 * We have been notified that our socket has something to read. Do the
697 * read and reschedule this function to be called again once more is
703 select_read_cb (void *cls);
707 * Function called when message was successfully passed to
708 * transport service. Continue read activity.
711 * @param success #GNUNET_OK on success
714 receive_complete_cb (void *cls,
717 delivering_messages--;
718 if (GNUNET_OK != success)
719 GNUNET_STATISTICS_update (stats,
720 "# transport transmission failures",
723 GNUNET_assert (NULL != unix_sock);
724 if ( (NULL == read_task) &&
725 (delivering_messages < max_queue_length) )
726 read_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
734 * We have been notified that our socket has something to read. Do the
735 * read and reschedule this function to be called again once more is
741 select_read_cb (void *cls)
743 char buf[65536] GNUNET_ALIGN;
745 const struct UNIXMessage *msg;
746 struct sockaddr_un un;
751 GNUNET_assert (NULL != unix_sock);
752 read_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
756 addrlen = sizeof (un);
760 ret = GNUNET_NETWORK_socket_recvfrom (unix_sock,
763 (struct sockaddr *) &un,
766 ( (EAGAIN == errno) ||
767 (ENOBUFS == errno) ) )
771 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
775 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
776 "Read %d bytes from socket %s\n",
779 GNUNET_assert (AF_UNIX == (un.sun_family));
780 msg = (struct UNIXMessage *) buf;
781 msize = ntohs (msg->header.size);
782 if ( (msize < sizeof (struct UNIXMessage)) ||
788 queue = lookup_queue (&msg->sender,
792 queue = setup_queue (&msg->sender,
793 GNUNET_TRANSPORT_CS_INBOUND,
797 reschedule_queue_timeout (queue);
800 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
801 _("Maximum number of UNIX connections exceeded, dropping incoming message\n"));
807 uint16_t tsize = msize - sizeof (struct UNIXMessage);
808 const char *msgbuf = (const char *) &msg[1];
810 while (offset + sizeof (struct GNUNET_MessageHeader) <= tsize)
812 const struct GNUNET_MessageHeader *currhdr;
813 struct GNUNET_MessageHeader al_hdr;
816 currhdr = (const struct GNUNET_MessageHeader *) &msgbuf[offset];
817 /* ensure aligned access */
821 csize = ntohs (al_hdr.size);
822 if ( (csize < sizeof (struct GNUNET_MessageHeader)) ||
823 (csize > tsize - offset))
828 ret = GNUNET_TRANSPORT_communicator_receive (ch,
831 &receive_complete_cb,
833 if (GNUNET_SYSERR == ret)
834 return; /* transport not up */
835 if (GNUNET_NO == ret)
837 delivering_messages++;
841 if (delivering_messages >= max_queue_length)
843 /* we should try to apply 'back pressure' */
844 GNUNET_SCHEDULER_cancel (read_task);
851 * Function called by the transport service to initialize a
852 * message queue given address information about another peer.
853 * If and when the communication channel is established, the
854 * communicator must call #GNUNET_TRANSPORT_communicator_mq_add()
855 * to notify the service that the channel is now up. It is
856 * the responsibility of the communicator to manage sane
857 * retries and timeouts for any @a peer/@a address combination
858 * provided by the transport service. Timeouts and retries
859 * do not need to be signalled to the transport service.
862 * @param peer identity of the other peer
863 * @param address where to send the message, human-readable
864 * communicator-specific format, 0-terminated, UTF-8
865 * @return #GNUNET_OK on success, #GNUNET_SYSERR if the provided address is invalid
869 const struct GNUNET_PeerIdentity *peer,
874 struct sockaddr_un *un;
877 if (0 != strncmp (address,
878 COMMUNICATOR_ADDRESS_PREFIX "-",
879 strlen (COMMUNICATOR_ADDRESS_PREFIX "-")))
882 return GNUNET_SYSERR;
884 path = &address[strlen (COMMUNICATOR_ADDRESS_PREFIX "-")];
885 un = unix_address_to_sockaddr (path,
887 queue = lookup_queue (peer,
892 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
893 "Address `%s' for %s ignored, queue exists\n",
899 queue = setup_queue (peer,
900 GNUNET_TRANSPORT_CS_OUTBOUND,
906 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
907 "Failed to setup queue to %s at `%s'\n",
917 * Iterator over all message queues to clean up.
920 * @param target unused
921 * @param value the queue to destroy
922 * @return #GNUNET_OK to continue to iterate
925 get_queue_delete_it (void *cls,
926 const struct GNUNET_PeerIdentity *target,
929 struct Queue *queue = value;
933 queue_destroy (queue);
939 * Shutdown the UNIX communicator.
941 * @param cls NULL (always)
944 do_shutdown (void *cls)
946 if (NULL != read_task)
948 GNUNET_SCHEDULER_cancel (read_task);
951 if (NULL != write_task)
953 GNUNET_SCHEDULER_cancel (write_task);
956 if (NULL != unix_sock)
958 GNUNET_break (GNUNET_OK ==
959 GNUNET_NETWORK_socket_close (unix_sock));
962 GNUNET_CONTAINER_multipeermap_iterate (queue_map,
963 &get_queue_delete_it,
965 GNUNET_CONTAINER_multipeermap_destroy (queue_map);
968 GNUNET_TRANSPORT_communicator_address_remove (ai);
973 GNUNET_TRANSPORT_communicator_disconnect (ch);
978 GNUNET_STATISTICS_destroy (stats,
986 * Function called when the transport service has received an
987 * acknowledgement for this communicator (!) via a different return
990 * Not applicable for UNIX.
993 * @param sender which peer sent the notification
997 enc_notify_cb (void *cls,
998 const struct GNUNET_PeerIdentity *sender,
999 const struct GNUNET_MessageHeader *msg)
1004 GNUNET_break_op (0);
1009 * Setup communicator and launch network interactions.
1011 * @param cls NULL (always)
1012 * @param args remaining command-line arguments
1013 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
1014 * @param cfg configuration
1019 const char *cfgfile,
1020 const struct GNUNET_CONFIGURATION_Handle *cfg)
1022 char *unix_socket_path;
1023 struct sockaddr_un *un;
1029 GNUNET_CONFIGURATION_get_value_filename (cfg,
1030 COMMUNICATOR_CONFIG_SECTION,
1034 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
1035 COMMUNICATOR_CONFIG_SECTION,
1040 GNUNET_CONFIGURATION_get_value_number (cfg,
1041 COMMUNICATOR_CONFIG_SECTION,
1044 max_queue_length = DEFAULT_MAX_QUEUE_LENGTH;
1046 un = unix_address_to_sockaddr (unix_socket_path,
1050 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1051 "Failed to setup UNIX domain socket address with path `%s'\n",
1053 GNUNET_free (unix_socket_path);
1056 unix_sock = GNUNET_NETWORK_socket_create (AF_UNIX,
1059 if (NULL == unix_sock)
1061 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
1064 GNUNET_free (unix_socket_path);
1067 if ( ('\0' != un->sun_path[0]) &&
1069 GNUNET_DISK_directory_create_for_file (un->sun_path)) )
1071 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1072 _("Cannot create path to `%s'\n"),
1074 GNUNET_NETWORK_socket_close (unix_sock);
1077 GNUNET_free (unix_socket_path);
1081 GNUNET_NETWORK_socket_bind (unix_sock,
1082 (const struct sockaddr *) un,
1085 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
1088 GNUNET_NETWORK_socket_close (unix_sock);
1091 GNUNET_free (unix_socket_path);
1095 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1098 stats = GNUNET_STATISTICS_create ("C-UNIX",
1100 GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
1102 read_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
1106 queue_map = GNUNET_CONTAINER_multipeermap_create (10,
1108 ch = GNUNET_TRANSPORT_communicator_connect (cfg,
1109 COMMUNICATOR_CONFIG_SECTION,
1110 COMMUNICATOR_ADDRESS_PREFIX,
1111 GNUNET_TRANSPORT_CC_RELIABLE,
1119 GNUNET_SCHEDULER_shutdown ();
1120 GNUNET_free (unix_socket_path);
1123 GNUNET_asprintf (&my_addr,
1125 COMMUNICATOR_ADDRESS_PREFIX,
1127 GNUNET_free (unix_socket_path);
1128 ai = GNUNET_TRANSPORT_communicator_address_add (ch,
1131 GNUNET_TIME_UNIT_FOREVER_REL);
1132 GNUNET_free (my_addr);
1137 * The main function for the UNIX communicator.
1139 * @param argc number of arguments from the command line
1140 * @param argv command line arguments
1141 * @return 0 ok, 1 on error
1147 static const struct GNUNET_GETOPT_CommandLineOption options[] = {
1148 GNUNET_GETOPT_OPTION_END
1153 GNUNET_STRINGS_get_utf8_args (argc, argv,
1159 GNUNET_PROGRAM_run (argc, argv,
1160 "gnunet-communicator-unix",
1161 _("GNUnet UNIX domain socket communicator"),
1165 GNUNET_free ((void*) argv);
1170 #if defined(LINUX) && defined(__GLIBC__)
1174 * MINIMIZE heap size (way below 128k) since this process doesn't need much.
1176 void __attribute__ ((constructor))
1177 GNUNET_ARM_memory_init ()
1179 mallopt (M_TRIM_THRESHOLD, 4 * 1024);
1180 mallopt (M_TOP_PAD, 1 * 1024);
1185 /* end of gnunet-communicator-unix.c */