uncrustify as demanded.
[oweals/gnunet.git] / src / transport / plugin_transport_unix.c
1 /*
2      This file is part of GNUnet
3      Copyright (C) 2010-2014 GNUnet e.V.
4
5      GNUnet is free software: you can redistribute it and/or modify it
6      under the terms of the GNU Affero General Public License as published
7      by the Free Software Foundation, either version 3 of the License,
8      or (at your option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      Affero General Public License for more details.
14
15      You should have received a copy of the GNU Affero General Public License
16      along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18      SPDX-License-Identifier: AGPL3.0-or-later
19  */
20
21 /**
22  * @file transport/plugin_transport_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
28  */
29 #include "platform.h"
30 #include "gnunet_util_lib.h"
31 #include "gnunet_hello_lib.h"
32 #include "gnunet_protocols.h"
33 #include "gnunet_statistics_service.h"
34 #include "gnunet_transport_service.h"
35 #include "gnunet_transport_plugin.h"
36 #include "transport.h"
37
38
39 /**
40  * Return code we give on 'send' if we failed to send right now
41  * but it makes sense to retry later. (Note: we might want to
42  * move this to the plugin API!?).
43  */
44 #define RETRY 0
45
46 /**
47  * Name of the plugin.
48  */
49 #define PLUGIN_NAME "unix"
50
51 /**
52  * Options for UNIX Domain addresses.
53  */
54 enum UNIX_ADDRESS_OPTIONS {
55   /**
56    * No special options.
57    */
58   UNIX_OPTIONS_NONE = 0,
59
60   /**
61    * Linux abstract domain sockets should be used.
62    */
63   UNIX_OPTIONS_USE_ABSTRACT_SOCKETS = 1
64 };
65
66
67 /**
68  * How long until we give up on transmitting the welcome message?
69  */
70 #define HOSTNAME_RESOLVE_TIMEOUT \
71   GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 5)
72
73 #define LOG(kind, ...) GNUNET_log_from(kind, "transport-unix", __VA_ARGS__)
74
75
76 GNUNET_NETWORK_STRUCT_BEGIN
77
78 /**
79  * Binary format for an UNIX Domain Socket address in GNUnet.
80  */
81 struct UnixAddress {
82   /**
83    * Options to use for the address, in NBO
84    */
85   uint32_t options GNUNET_PACKED;
86
87   /**
88    * Length of the address (path length), in NBO
89    */
90   uint32_t addrlen GNUNET_PACKED;
91
92   /* followed by actual path */
93 };
94
95
96 /**
97  * UNIX Message-Packet header.
98  */
99 struct UNIXMessage {
100   /**
101    * Message header.
102    */
103   struct GNUNET_MessageHeader header;
104
105   /**
106    * What is the identity of the sender (GNUNET_hash of public key)
107    */
108   struct GNUNET_PeerIdentity sender;
109 };
110
111 GNUNET_NETWORK_STRUCT_END
112
113
114 /**
115  * Information we track for a message awaiting transmission.
116  */
117 struct UNIXMessageWrapper {
118   /**
119    * We keep messages in a doubly linked list.
120    */
121   struct UNIXMessageWrapper *next;
122
123   /**
124    * We keep messages in a doubly linked list.
125    */
126   struct UNIXMessageWrapper *prev;
127
128   /**
129    * The actual payload (allocated separately right now).
130    */
131   struct UNIXMessage *msg;
132
133   /**
134    * Session this message belongs to.
135    */
136   struct GNUNET_ATS_Session *session;
137
138   /**
139    * Function to call upon transmission.
140    */
141   GNUNET_TRANSPORT_TransmitContinuation cont;
142
143   /**
144    * Closure for @e cont.
145    */
146   void *cont_cls;
147
148   /**
149    * Timeout for this message.
150    */
151   struct GNUNET_TIME_Absolute timeout;
152
153   /**
154    * Number of bytes in @e msg.
155    */
156   size_t msgsize;
157
158   /**
159    * Number of bytes of payload encapsulated in @e msg.
160    */
161   size_t payload;
162
163   /**
164    * Priority of the message (ignored, just dragged along in UNIX).
165    */
166   unsigned int priority;
167 };
168
169
170 /**
171  * Handle for a session.
172  */
173 struct GNUNET_ATS_Session {
174   /**
175    * Sessions with pending messages (!) are kept in a DLL.
176    */
177   struct GNUNET_ATS_Session *next;
178
179   /**
180    * Sessions with pending messages (!) are kept in a DLL.
181    */
182   struct GNUNET_ATS_Session *prev;
183
184   /**
185    * To whom are we talking to (set to our identity
186    * if we are still waiting for the welcome message).
187    *
188    * FIXME: information duplicated with 'peer' in address!
189    */
190   struct GNUNET_PeerIdentity target;
191
192   /**
193    * Pointer to the global plugin struct.
194    */
195   struct Plugin *plugin;
196
197   /**
198    * Address of the other peer.
199    */
200   struct GNUNET_HELLO_Address *address;
201
202   /**
203    * Number of bytes we currently have in our write queue.
204    */
205   unsigned long long bytes_in_queue;
206
207   /**
208    * Timeout for this session.
209    */
210   struct GNUNET_TIME_Absolute timeout;
211
212   /**
213    * Session timeout task.
214    */
215   struct GNUNET_SCHEDULER_Task *timeout_task;
216
217   /**
218    * Number of messages we currently have in our write queue.
219    */
220   unsigned int msgs_in_queue;
221 };
222
223
224 /**
225  * Encapsulation of all of the state of the plugin.
226  */
227 struct Plugin;
228
229
230 /**
231  * Information we keep for each of our listen sockets.
232  */
233 struct UNIX_Sock_Info {
234   /**
235    * The network handle
236    */
237   struct GNUNET_NETWORK_Handle *desc;
238 };
239
240
241 /**
242  * Encapsulation of all of the state of the plugin.
243  */
244 struct Plugin {
245   /**
246    * ID of task used to update our addresses when one expires.
247    */
248   struct GNUNET_SCHEDULER_Task *address_update_task;
249
250   /**
251    * ID of read task
252    */
253   struct GNUNET_SCHEDULER_Task *read_task;
254
255   /**
256    * ID of write task
257    */
258   struct GNUNET_SCHEDULER_Task *write_task;
259
260   /**
261    * Number of bytes we currently have in our write queues.
262    */
263   unsigned long long bytes_in_queue;
264
265   /**
266    * Our environment.
267    */
268   struct GNUNET_TRANSPORT_PluginEnvironment *env;
269
270   /**
271    * Sessions (map from peer identity to `struct GNUNET_ATS_Session`)
272    */
273   struct GNUNET_CONTAINER_MultiPeerMap *session_map;
274
275   /**
276    * Head of queue of messages to transmit.
277    */
278   struct UNIXMessageWrapper *msg_head;
279
280   /**
281    * Tail of queue of messages to transmit.
282    */
283   struct UNIXMessageWrapper *msg_tail;
284
285   /**
286    * Path of our unix domain socket (/tmp/unix-plugin)
287    */
288   char *unix_socket_path;
289
290   /**
291    * Function to call about session status changes.
292    */
293   GNUNET_TRANSPORT_SessionInfoCallback sic;
294
295   /**
296    * Closure for @e sic.
297    */
298   void *sic_cls;
299
300   /**
301    * socket that we transmit all data with
302    */
303   struct UNIX_Sock_Info unix_sock;
304
305   /**
306    * Address options in HBO
307    */
308   uint32_t myoptions;
309
310   /**
311    * Are we using an abstract UNIX domain socket?
312    */
313   int is_abstract;
314 };
315
316
317 /**
318  * If a session monitor is attached, notify it about the new
319  * session state.
320  *
321  * @param plugin our plugin
322  * @param session session that changed state
323  * @param state new state of the session
324  */
325 static void
326 notify_session_monitor(struct Plugin *plugin,
327                        struct GNUNET_ATS_Session *session,
328                        enum GNUNET_TRANSPORT_SessionState state)
329 {
330   struct GNUNET_TRANSPORT_SessionInfo info;
331
332   if (NULL == plugin->sic)
333     return;
334   memset(&info, 0, sizeof(info));
335   info.state = state;
336   info.is_inbound = GNUNET_SYSERR; /* hard to say */
337   info.num_msg_pending = session->msgs_in_queue;
338   info.num_bytes_pending = session->bytes_in_queue;
339   /* info.receive_delay remains zero as this is not supported by UNIX
340      (cannot selectively not receive from 'some' peer while continuing
341      to receive from others) */
342   info.session_timeout = session->timeout;
343   info.address = session->address;
344   plugin->sic(plugin->sic_cls, session, &info);
345 }
346
347
348 /**
349  * Function called for a quick conversion of the binary address to
350  * a numeric address.  Note that the caller must not free the
351  * address and that the next call to this function is allowed
352  * to override the address again.
353  *
354  * @param cls closure
355  * @param addr binary address
356  * @param addrlen length of the @a addr
357  * @return string representing the same address
358  */
359 static const char *
360 unix_plugin_address_to_string(void *cls, const void *addr, size_t addrlen)
361 {
362   static char rbuf[1024];
363   struct UnixAddress *ua = (struct UnixAddress *)addr;
364   char *addrstr;
365   size_t addr_str_len;
366   unsigned int off;
367
368   if ((NULL == addr) || (sizeof(struct UnixAddress) > addrlen))
369     {
370       GNUNET_break(0);
371       return NULL;
372     }
373   addrstr = (char *)&ua[1];
374   addr_str_len = ntohl(ua->addrlen);
375
376   if (addr_str_len != addrlen - sizeof(struct UnixAddress))
377     {
378       GNUNET_break(0);
379       return NULL;
380     }
381   if ('\0' != addrstr[addr_str_len - 1])
382     {
383       GNUNET_break(0);
384       return NULL;
385     }
386   if (strlen(addrstr) + 1 != addr_str_len)
387     {
388       GNUNET_break(0);
389       return NULL;
390     }
391
392   off = 0;
393   if ('\0' == addrstr[0])
394     off++;
395   memset(rbuf, 0, sizeof(rbuf));
396   GNUNET_snprintf(rbuf,
397                   sizeof(rbuf) - 1,
398                   "%s.%u.%s%.*s",
399                   PLUGIN_NAME,
400                   ntohl(ua->options),
401                   (off == 1) ? "@" : "",
402                   (int)(addr_str_len - off),
403                   &addrstr[off]);
404   return rbuf;
405 }
406
407
408 /**
409  * Functions with this signature are called whenever we need
410  * to close a session due to a disconnect or failure to
411  * establish a connection.
412  *
413  * @param cls closure with the `struct Plugin *`
414  * @param session session to close down
415  * @return #GNUNET_OK on success
416  */
417 static int
418 unix_plugin_session_disconnect(void *cls, struct GNUNET_ATS_Session *session)
419 {
420   struct Plugin *plugin = cls;
421   struct UNIXMessageWrapper *msgw;
422   struct UNIXMessageWrapper *next;
423
424   LOG(GNUNET_ERROR_TYPE_DEBUG,
425       "Disconnecting session for peer `%s' `%s'\n",
426       GNUNET_i2s(&session->target),
427       unix_plugin_address_to_string(NULL,
428                                     session->address->address,
429                                     session->address->address_length));
430   plugin->env->session_end(plugin->env->cls, session->address, session);
431   next = plugin->msg_head;
432   while (NULL != next)
433     {
434       msgw = next;
435       next = msgw->next;
436       if (msgw->session != session)
437         continue;
438       GNUNET_CONTAINER_DLL_remove(plugin->msg_head, plugin->msg_tail, msgw);
439       session->msgs_in_queue--;
440       GNUNET_assert(session->bytes_in_queue >= msgw->msgsize);
441       session->bytes_in_queue -= msgw->msgsize;
442       GNUNET_assert(plugin->bytes_in_queue >= msgw->msgsize);
443       plugin->bytes_in_queue -= msgw->msgsize;
444       if (NULL != msgw->cont)
445         msgw->cont(msgw->cont_cls,
446                    &msgw->session->target,
447                    GNUNET_SYSERR,
448                    msgw->payload,
449                    0);
450       GNUNET_free(msgw->msg);
451       GNUNET_free(msgw);
452     }
453   GNUNET_assert(GNUNET_YES ==
454                 GNUNET_CONTAINER_multipeermap_remove(plugin->session_map,
455                                                      &session->target,
456                                                      session));
457   GNUNET_STATISTICS_set(plugin->env->stats,
458                         "# UNIX sessions active",
459                         GNUNET_CONTAINER_multipeermap_size(
460                           plugin->session_map),
461                         GNUNET_NO);
462   if (NULL != session->timeout_task)
463     {
464       GNUNET_SCHEDULER_cancel(session->timeout_task);
465       session->timeout_task = NULL;
466       session->timeout = GNUNET_TIME_UNIT_ZERO_ABS;
467     }
468   notify_session_monitor(plugin, session, GNUNET_TRANSPORT_SS_DONE);
469   GNUNET_HELLO_address_free(session->address);
470   GNUNET_break(0 == session->bytes_in_queue);
471   GNUNET_break(0 == session->msgs_in_queue);
472   GNUNET_free(session);
473   return GNUNET_OK;
474 }
475
476
477 /**
478  * Session was idle for too long, so disconnect it
479  *
480  * @param cls the `struct GNUNET_ATS_Session *` to disconnect
481  */
482 static void
483 session_timeout(void *cls)
484 {
485   struct GNUNET_ATS_Session *session = cls;
486   struct GNUNET_TIME_Relative left;
487
488   session->timeout_task = NULL;
489   left = GNUNET_TIME_absolute_get_remaining(session->timeout);
490   if (0 != left.rel_value_us)
491     {
492       /* not actually our turn yet, but let's at least update
493          the monitor, it may think we're about to die ... */
494       notify_session_monitor(session->plugin,
495                              session,
496                              GNUNET_TRANSPORT_SS_UPDATE);
497       session->timeout_task =
498         GNUNET_SCHEDULER_add_delayed(left, &session_timeout, session);
499       return;
500     }
501   LOG(GNUNET_ERROR_TYPE_DEBUG,
502       "Session %p was idle for %s, disconnecting\n",
503       session,
504       GNUNET_STRINGS_relative_time_to_string(
505         GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
506         GNUNET_YES));
507   unix_plugin_session_disconnect(session->plugin, session);
508 }
509
510
511 /**
512  * Increment session timeout due to activity.  We do not immediately
513  * notify the monitor here as that might generate excessive
514  * signalling.
515  *
516  * @param session session for which the timeout should be rescheduled
517  */
518 static void
519 reschedule_session_timeout(struct GNUNET_ATS_Session *session)
520 {
521   GNUNET_assert(NULL != session->timeout_task);
522   session->timeout =
523     GNUNET_TIME_relative_to_absolute(GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
524 }
525
526
527 /**
528  * Convert unix path to a `struct sockaddr_un *`
529  *
530  * @param unixpath path to convert
531  * @param[out] sock_len set to the length of the address
532  * @return converted unix path
533  */
534 static struct sockaddr_un *
535 unix_address_to_sockaddr(const char *unixpath, socklen_t *sock_len)
536 {
537   struct sockaddr_un *un;
538   size_t slen;
539
540   GNUNET_assert(0 < strlen(unixpath));   /* sanity check */
541   un = GNUNET_new(struct sockaddr_un);
542   un->sun_family = AF_UNIX;
543   slen = strlen(unixpath);
544   if (slen >= sizeof(un->sun_path))
545     slen = sizeof(un->sun_path) - 1;
546   GNUNET_memcpy(un->sun_path, unixpath, slen);
547   un->sun_path[slen] = '\0';
548   slen = sizeof(struct sockaddr_un);
549 #if HAVE_SOCKADDR_UN_SUN_LEN
550   un->sun_len = (u_char)slen;
551 #endif
552   (*sock_len) = slen;
553   return un;
554 }
555
556
557 /**
558  * Closure to #lookup_session_it().
559  */
560 struct LookupCtx {
561   /**
562    * Location to store the session, if found.
563    */
564   struct GNUNET_ATS_Session *res;
565
566   /**
567    * Address we are looking for.
568    */
569   const struct GNUNET_HELLO_Address *address;
570 };
571
572
573 /**
574  * Function called to find a session by address.
575  *
576  * @param cls the `struct LookupCtx *`
577  * @param key peer we are looking for (unused)
578  * @param value a session
579  * @return #GNUNET_YES if not found (continue looking), #GNUNET_NO on success
580  */
581 static int
582 lookup_session_it(void *cls,
583                   const struct GNUNET_PeerIdentity *key,
584                   void *value)
585 {
586   struct LookupCtx *lctx = cls;
587   struct GNUNET_ATS_Session *session = value;
588
589   if (0 == GNUNET_HELLO_address_cmp(lctx->address, session->address))
590     {
591       lctx->res = session;
592       return GNUNET_NO;
593     }
594   return GNUNET_YES;
595 }
596
597
598 /**
599  * Find an existing session by address.
600  *
601  * @param plugin the plugin
602  * @param address the address to find
603  * @return NULL if session was not found
604  */
605 static struct GNUNET_ATS_Session *
606 lookup_session(struct Plugin *plugin,
607                const struct GNUNET_HELLO_Address *address)
608 {
609   struct LookupCtx lctx;
610
611   lctx.address = address;
612   lctx.res = NULL;
613   GNUNET_CONTAINER_multipeermap_get_multiple(plugin->session_map,
614                                              &address->peer,
615                                              &lookup_session_it,
616                                              &lctx);
617   return lctx.res;
618 }
619
620
621 /**
622  * Function that is called to get the keepalive factor.
623  * #GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT is divided by this number to
624  * calculate the interval between keepalive packets.
625  *
626  * @param cls closure with the `struct Plugin`
627  * @return keepalive factor
628  */
629 static unsigned int
630 unix_plugin_query_keepalive_factor(void *cls)
631 {
632   return 3;
633 }
634
635
636 /**
637  * Actually send out the message, assume we've got the address and
638  * send_handle squared away!
639  *
640  * @param cls closure
641  * @param send_handle which handle to send message on
642  * @param target who should receive this message (ignored by UNIX)
643  * @param msgbuf one or more GNUNET_MessageHeader(s) strung together
644  * @param msgbuf_size the size of the @a msgbuf to send
645  * @param priority how important is the message (ignored by UNIX)
646  * @param timeout when should we time out (give up) if we can not transmit?
647  * @param addr the addr to send the message to, needs to be a sockaddr for us
648  * @param addrlen the len of @a addr
649  * @param payload bytes payload to send
650  * @param cont continuation to call once the message has
651  *        been transmitted (or if the transport is ready
652  *        for the next transmission call; or if the
653  *        peer disconnected...)
654  * @param cont_cls closure for @a cont
655  * @return on success the number of bytes written, RETRY for retry, -1 on errors
656  */
657 static ssize_t
658 unix_real_send(void *cls,
659                struct GNUNET_NETWORK_Handle *send_handle,
660                const struct GNUNET_PeerIdentity *target,
661                const char *msgbuf,
662                size_t msgbuf_size,
663                unsigned int priority,
664                struct GNUNET_TIME_Absolute timeout,
665                const struct UnixAddress *addr,
666                size_t addrlen,
667                size_t payload,
668                GNUNET_TRANSPORT_TransmitContinuation cont,
669                void *cont_cls)
670 {
671   struct Plugin *plugin = cls;
672   ssize_t sent;
673   struct sockaddr_un *un;
674   socklen_t un_len;
675   const char *unixpath;
676
677   if (NULL == send_handle)
678     {
679       GNUNET_break(0); /* We do not have a send handle */
680       return GNUNET_SYSERR;
681     }
682   if ((NULL == addr) || (0 == addrlen))
683     {
684       GNUNET_break(0); /* Can never send if we don't have an address */
685       return GNUNET_SYSERR;
686     }
687
688   /* Prepare address */
689   unixpath = (const char *)&addr[1];
690   if (NULL == (un = unix_address_to_sockaddr(unixpath, &un_len)))
691     {
692       GNUNET_break(0);
693       return -1;
694     }
695
696   if ((GNUNET_YES == plugin->is_abstract) &&
697       (0 != (UNIX_OPTIONS_USE_ABSTRACT_SOCKETS & ntohl(addr->options))))
698     {
699       un->sun_path[0] = '\0';
700     }
701 resend:
702   /* Send the data */
703   sent = GNUNET_NETWORK_socket_sendto(send_handle,
704                                       msgbuf,
705                                       msgbuf_size,
706                                       (const struct sockaddr *)un,
707                                       un_len);
708   if (GNUNET_SYSERR == sent)
709     {
710       if ((EAGAIN == errno) || (ENOBUFS == errno))
711         {
712           GNUNET_free(un);
713           return RETRY; /* We have to retry later  */
714         }
715       if (EMSGSIZE == errno)
716         {
717           socklen_t size = 0;
718           socklen_t len = sizeof(size);
719
720           GNUNET_NETWORK_socket_getsockopt((struct GNUNET_NETWORK_Handle *)
721                                            send_handle,
722                                            SOL_SOCKET,
723                                            SO_SNDBUF,
724                                            &size,
725                                            &len);
726           if (size < msgbuf_size)
727             {
728               LOG(GNUNET_ERROR_TYPE_DEBUG,
729                   "Trying to increase socket buffer size from %u to %u for message size %u\n",
730                   (unsigned int)size,
731                   (unsigned int)((msgbuf_size / 1000) + 2) * 1000,
732                   (unsigned int)msgbuf_size);
733               size = ((msgbuf_size / 1000) + 2) * 1000;
734               if (GNUNET_OK ==
735                   GNUNET_NETWORK_socket_setsockopt((struct GNUNET_NETWORK_Handle *)
736                                                    send_handle,
737                                                    SOL_SOCKET,
738                                                    SO_SNDBUF,
739                                                    &size,
740                                                    sizeof(size)))
741                 goto resend; /* Increased buffer size, retry sending */
742               else
743                 {
744                   /* Could not increase buffer size: error, no retry */
745                   GNUNET_log_strerror(GNUNET_ERROR_TYPE_ERROR, "setsockopt");
746                   GNUNET_free(un);
747                   return GNUNET_SYSERR;
748                 }
749             }
750           else
751             {
752               /* Buffer is bigger than message:  error, no retry
753                * This should never happen!*/
754               GNUNET_break(0);
755               GNUNET_free(un);
756               return GNUNET_SYSERR;
757             }
758         }
759     }
760
761   LOG(GNUNET_ERROR_TYPE_DEBUG,
762       "UNIX transmitted %u-byte message to %s (%d: %s)\n",
763       (unsigned int)msgbuf_size,
764       GNUNET_a2s((const struct sockaddr *)un, un_len),
765       (int)sent,
766       (sent < 0) ? strerror(errno) : "ok");
767   GNUNET_free(un);
768   return sent;
769 }
770
771
772 /**
773  * Function obtain the network type for a session
774  *
775  * @param cls closure ('struct Plugin*')
776  * @param session the session
777  * @return the network type in HBO or #GNUNET_SYSERR
778  */
779 static enum GNUNET_NetworkType
780 unix_plugin_get_network(void *cls, struct GNUNET_ATS_Session *session)
781 {
782   GNUNET_assert(NULL != session);
783   return GNUNET_NT_LOOPBACK;
784 }
785
786
787 /**
788  * Function obtain the network type for a session
789  *
790  * @param cls closure (`struct Plugin *`)
791  * @param address the address
792  * @return the network type
793  */
794 static enum GNUNET_NetworkType
795 unix_plugin_get_network_for_address(void *cls,
796                                     const struct GNUNET_HELLO_Address *address)
797 {
798   return GNUNET_NT_LOOPBACK;
799 }
800
801
802 /**
803  * Creates a new outbound session the transport service will use to send data to the
804  * peer
805  *
806  * @param cls the plugin
807  * @param address the address
808  * @return the session or NULL of max connections exceeded
809  */
810 static struct GNUNET_ATS_Session *
811 unix_plugin_get_session(void *cls, const struct GNUNET_HELLO_Address *address)
812 {
813   struct Plugin *plugin = cls;
814   struct GNUNET_ATS_Session *session;
815   struct UnixAddress *ua;
816   char *addrstr;
817   uint32_t addr_str_len;
818   uint32_t addr_option;
819
820   ua = (struct UnixAddress *)address->address;
821   if ((NULL == address->address) || (0 == address->address_length) ||
822       (sizeof(struct UnixAddress) > address->address_length))
823     {
824       GNUNET_break(0);
825       return NULL;
826     }
827   addrstr = (char *)&ua[1];
828   addr_str_len = ntohl(ua->addrlen);
829   addr_option = ntohl(ua->options);
830
831   if ((0 != (UNIX_OPTIONS_USE_ABSTRACT_SOCKETS & addr_option)) &&
832       (GNUNET_NO == plugin->is_abstract))
833     {
834       return NULL;
835     }
836
837   if (addr_str_len != address->address_length - sizeof(struct UnixAddress))
838     {
839       return NULL; /* This can be a legacy address */
840     }
841
842   if ('\0' != addrstr[addr_str_len - 1])
843     {
844       GNUNET_break(0);
845       return NULL;
846     }
847   if (strlen(addrstr) + 1 != addr_str_len)
848     {
849       GNUNET_break(0);
850       return NULL;
851     }
852
853   /* Check if a session for this address already exists */
854   if (NULL != (session = lookup_session(plugin, address)))
855     {
856       LOG(GNUNET_ERROR_TYPE_DEBUG,
857           "Found existing session %p for address `%s'\n",
858           session,
859           unix_plugin_address_to_string(NULL,
860                                         address->address,
861                                         address->address_length));
862       return session;
863     }
864
865   /* create a new session */
866   session = GNUNET_new(struct GNUNET_ATS_Session);
867   session->target = address->peer;
868   session->address = GNUNET_HELLO_address_copy(address);
869   session->plugin = plugin;
870   session->timeout =
871     GNUNET_TIME_relative_to_absolute(GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
872   session->timeout_task =
873     GNUNET_SCHEDULER_add_delayed(GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
874                                  &session_timeout,
875                                  session);
876   LOG(GNUNET_ERROR_TYPE_DEBUG,
877       "Creating a new session %p for address `%s'\n",
878       session,
879       unix_plugin_address_to_string(NULL,
880                                     address->address,
881                                     address->address_length));
882   (void)GNUNET_CONTAINER_multipeermap_put(
883     plugin->session_map,
884     &address->peer,
885     session,
886     GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
887   GNUNET_STATISTICS_set(plugin->env->stats,
888                         "# UNIX sessions active",
889                         GNUNET_CONTAINER_multipeermap_size(
890                           plugin->session_map),
891                         GNUNET_NO);
892   notify_session_monitor(plugin, session, GNUNET_TRANSPORT_SS_INIT);
893   notify_session_monitor(plugin, session, GNUNET_TRANSPORT_SS_UP);
894   return session;
895 }
896
897
898 /**
899  * Function that will be called whenever the transport service wants
900  * to notify the plugin that a session is still active and in use and
901  * therefore the session timeout for this session has to be updated
902  *
903  * @param cls closure with the `struct Plugin *`
904  * @param peer which peer was the session for
905  * @param session which session is being updated
906  */
907 static void
908 unix_plugin_update_session_timeout(void *cls,
909                                    const struct GNUNET_PeerIdentity *peer,
910                                    struct GNUNET_ATS_Session *session)
911 {
912   struct Plugin *plugin = cls;
913
914   if (GNUNET_OK !=
915       GNUNET_CONTAINER_multipeermap_contains_value(plugin->session_map,
916                                                    &session->target,
917                                                    session))
918     {
919       GNUNET_break(0);
920       return;
921     }
922   reschedule_session_timeout(session);
923 }
924
925
926 /**
927  * Demultiplexer for UNIX messages
928  *
929  * @param plugin the main plugin for this transport
930  * @param sender from which peer the message was received
931  * @param currhdr pointer to the header of the message
932  * @param ua address to look for
933  * @param ua_len length of the address @a ua
934  */
935 static void
936 unix_demultiplexer(struct Plugin *plugin,
937                    struct GNUNET_PeerIdentity *sender,
938                    const struct GNUNET_MessageHeader *currhdr,
939                    const struct UnixAddress *ua,
940                    size_t ua_len)
941 {
942   struct GNUNET_ATS_Session *session;
943   struct GNUNET_HELLO_Address *address;
944
945   GNUNET_assert(ua_len >= sizeof(struct UnixAddress));
946   LOG(GNUNET_ERROR_TYPE_DEBUG,
947       "Received message from %s\n",
948       unix_plugin_address_to_string(NULL, ua, ua_len));
949   GNUNET_STATISTICS_update(plugin->env->stats,
950                            "# bytes received via UNIX",
951                            ntohs(currhdr->size),
952                            GNUNET_NO);
953
954   /* Look for existing session */
955   address = GNUNET_HELLO_address_allocate(
956     sender,
957     PLUGIN_NAME,
958     ua,
959     ua_len,
960     GNUNET_HELLO_ADDRESS_INFO_NONE); /* UNIX does not have "inbound" sessions */
961   session = lookup_session(plugin, address);
962   if (NULL == session)
963     {
964       session = unix_plugin_get_session(plugin, address);
965       /* Notify transport and ATS about new inbound session */
966       plugin->env->session_start(NULL,
967                                  session->address,
968                                  session,
969                                  GNUNET_NT_LOOPBACK);
970     }
971   else
972     {
973       reschedule_session_timeout(session);
974     }
975   GNUNET_HELLO_address_free(address);
976   plugin->env->receive(plugin->env->cls, session->address, session, currhdr);
977 }
978
979
980 /**
981  * Read from UNIX domain socket (it is ready).
982  *
983  * @param plugin the plugin
984  */
985 static void
986 unix_plugin_do_read(struct Plugin *plugin)
987 {
988   char buf[65536] GNUNET_ALIGN;
989   struct UnixAddress *ua;
990   struct UNIXMessage *msg;
991   struct GNUNET_PeerIdentity sender;
992   struct sockaddr_un un;
993   socklen_t addrlen;
994   ssize_t ret;
995   int offset;
996   int tsize;
997   int is_abstract;
998   char *msgbuf;
999   const struct GNUNET_MessageHeader *currhdr;
1000   uint16_t csize;
1001   size_t ua_len;
1002
1003   addrlen = sizeof(un);
1004   memset(&un, 0, sizeof(un));
1005   ret = GNUNET_NETWORK_socket_recvfrom(plugin->unix_sock.desc,
1006                                        buf,
1007                                        sizeof(buf),
1008                                        (struct sockaddr *)&un,
1009                                        &addrlen);
1010   if ((GNUNET_SYSERR == ret) && ((errno == EAGAIN) || (errno == ENOBUFS)))
1011     return;
1012   if (GNUNET_SYSERR == ret)
1013     {
1014       GNUNET_log_strerror(GNUNET_ERROR_TYPE_WARNING, "recvfrom");
1015       return;
1016     }
1017   else
1018     {
1019       LOG(GNUNET_ERROR_TYPE_DEBUG,
1020           "Read %d bytes from socket %s\n",
1021           (int)ret,
1022           un.sun_path);
1023     }
1024
1025   GNUNET_assert(AF_UNIX == (un.sun_family));
1026   is_abstract = GNUNET_NO;
1027   if ('\0' == un.sun_path[0])
1028     {
1029       un.sun_path[0] = '@';
1030       is_abstract = GNUNET_YES;
1031     }
1032
1033   ua_len = sizeof(struct UnixAddress) + strlen(un.sun_path) + 1;
1034   ua = GNUNET_malloc(ua_len);
1035   ua->addrlen = htonl(strlen(&un.sun_path[0]) + 1);
1036   GNUNET_memcpy(&ua[1], &un.sun_path[0], strlen(un.sun_path) + 1);
1037   if (is_abstract)
1038     ua->options = htonl(UNIX_OPTIONS_USE_ABSTRACT_SOCKETS);
1039   else
1040     ua->options = htonl(UNIX_OPTIONS_NONE);
1041
1042   msg = (struct UNIXMessage *)buf;
1043   csize = ntohs(msg->header.size);
1044   if ((csize < sizeof(struct UNIXMessage)) || (csize > ret))
1045     {
1046       GNUNET_break_op(0);
1047       GNUNET_free(ua);
1048       return;
1049     }
1050   msgbuf = (char *)&msg[1];
1051   GNUNET_memcpy(&sender, &msg->sender, sizeof(struct GNUNET_PeerIdentity));
1052   offset = 0;
1053   tsize = csize - sizeof(struct UNIXMessage);
1054   while (offset + sizeof(struct GNUNET_MessageHeader) <= tsize)
1055     {
1056       currhdr = (struct GNUNET_MessageHeader *)&msgbuf[offset];
1057       csize = ntohs(currhdr->size);
1058       if ((csize < sizeof(struct GNUNET_MessageHeader)) ||
1059           (csize > tsize - offset))
1060         {
1061           GNUNET_break_op(0);
1062           break;
1063         }
1064       unix_demultiplexer(plugin, &sender, currhdr, ua, ua_len);
1065       offset += csize;
1066     }
1067   GNUNET_free(ua);
1068 }
1069
1070
1071 /**
1072  * Write to UNIX domain socket (it is ready).
1073  *
1074  * @param plugin handle to the plugin
1075  */
1076 static void
1077 unix_plugin_do_write(struct Plugin *plugin)
1078 {
1079   ssize_t sent = 0;
1080   struct UNIXMessageWrapper *msgw;
1081   struct GNUNET_ATS_Session *session;
1082   int did_delete;
1083
1084   session = NULL;
1085   did_delete = GNUNET_NO;
1086   while (NULL != (msgw = plugin->msg_head))
1087     {
1088       if (GNUNET_TIME_absolute_get_remaining(msgw->timeout).rel_value_us > 0)
1089         break; /* Message is ready for sending */
1090       /* Message has a timeout */
1091       did_delete = GNUNET_YES;
1092       LOG(GNUNET_ERROR_TYPE_DEBUG,
1093           "Timeout for message with %u bytes \n",
1094           (unsigned int)msgw->msgsize);
1095       GNUNET_CONTAINER_DLL_remove(plugin->msg_head, plugin->msg_tail, msgw);
1096       session = msgw->session;
1097       session->msgs_in_queue--;
1098       GNUNET_assert(session->bytes_in_queue >= msgw->msgsize);
1099       session->bytes_in_queue -= msgw->msgsize;
1100       GNUNET_assert(plugin->bytes_in_queue >= msgw->msgsize);
1101       plugin->bytes_in_queue -= msgw->msgsize;
1102       GNUNET_STATISTICS_set(plugin->env->stats,
1103                             "# bytes currently in UNIX buffers",
1104                             plugin->bytes_in_queue,
1105                             GNUNET_NO);
1106       GNUNET_STATISTICS_update(plugin->env->stats,
1107                                "# UNIX bytes discarded",
1108                                msgw->msgsize,
1109                                GNUNET_NO);
1110       if (NULL != msgw->cont)
1111         msgw->cont(msgw->cont_cls,
1112                    &msgw->session->target,
1113                    GNUNET_SYSERR,
1114                    msgw->payload,
1115                    0);
1116       GNUNET_free(msgw->msg);
1117       GNUNET_free(msgw);
1118     }
1119   if (NULL == msgw)
1120     {
1121       if (GNUNET_YES == did_delete)
1122         notify_session_monitor(plugin, session, GNUNET_TRANSPORT_SS_UPDATE);
1123       return; /* Nothing to send at the moment */
1124     }
1125   session = msgw->session;
1126   sent = unix_real_send(plugin,
1127                         plugin->unix_sock.desc,
1128                         &session->target,
1129                         (const char *)msgw->msg,
1130                         msgw->msgsize,
1131                         msgw->priority,
1132                         msgw->timeout,
1133                         msgw->session->address->address,
1134                         msgw->session->address->address_length,
1135                         msgw->payload,
1136                         msgw->cont,
1137                         msgw->cont_cls);
1138   if (RETRY == sent)
1139     {
1140       GNUNET_STATISTICS_update(plugin->env->stats,
1141                                "# UNIX retry attempts",
1142                                1,
1143                                GNUNET_NO);
1144       notify_session_monitor(plugin, session, GNUNET_TRANSPORT_SS_UPDATE);
1145       return;
1146     }
1147   GNUNET_CONTAINER_DLL_remove(plugin->msg_head, plugin->msg_tail, msgw);
1148   session->msgs_in_queue--;
1149   GNUNET_assert(session->bytes_in_queue >= msgw->msgsize);
1150   session->bytes_in_queue -= msgw->msgsize;
1151   GNUNET_assert(plugin->bytes_in_queue >= msgw->msgsize);
1152   plugin->bytes_in_queue -= msgw->msgsize;
1153   GNUNET_STATISTICS_set(plugin->env->stats,
1154                         "# bytes currently in UNIX buffers",
1155                         plugin->bytes_in_queue,
1156                         GNUNET_NO);
1157   notify_session_monitor(plugin, session, GNUNET_TRANSPORT_SS_UPDATE);
1158   if (GNUNET_SYSERR == sent)
1159     {
1160       /* failed and no retry */
1161       if (NULL != msgw->cont)
1162         msgw->cont(msgw->cont_cls,
1163                    &msgw->session->target,
1164                    GNUNET_SYSERR,
1165                    msgw->payload,
1166                    0);
1167       GNUNET_STATISTICS_update(plugin->env->stats,
1168                                "# UNIX bytes discarded",
1169                                msgw->msgsize,
1170                                GNUNET_NO);
1171       GNUNET_free(msgw->msg);
1172       GNUNET_free(msgw);
1173       return;
1174     }
1175   /* successfully sent bytes */
1176   GNUNET_break(sent > 0);
1177   GNUNET_STATISTICS_update(plugin->env->stats,
1178                            "# bytes transmitted via UNIX",
1179                            msgw->msgsize,
1180                            GNUNET_NO);
1181   if (NULL != msgw->cont)
1182     msgw->cont(msgw->cont_cls,
1183                &msgw->session->target,
1184                GNUNET_OK,
1185                msgw->payload,
1186                msgw->msgsize);
1187   GNUNET_free(msgw->msg);
1188   GNUNET_free(msgw);
1189 }
1190
1191
1192 /**
1193  * We have been notified that our socket has something to read.
1194  * Then reschedule this function to be called again once more is available.
1195  *
1196  * @param cls the plugin handle
1197  */
1198 static void
1199 unix_plugin_select_read(void *cls)
1200 {
1201   struct Plugin *plugin = cls;
1202   const struct GNUNET_SCHEDULER_TaskContext *tc;
1203
1204   plugin->read_task = NULL;
1205   tc = GNUNET_SCHEDULER_get_task_context();
1206   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY))
1207     unix_plugin_do_read(plugin);
1208   plugin->read_task =
1209     GNUNET_SCHEDULER_add_read_net(GNUNET_TIME_UNIT_FOREVER_REL,
1210                                   plugin->unix_sock.desc,
1211                                   &unix_plugin_select_read,
1212                                   plugin);
1213 }
1214
1215
1216 /**
1217  * We have been notified that our socket is ready to write.
1218  * Then reschedule this function to be called again once more is available.
1219  *
1220  * @param cls the plugin handle
1221  */
1222 static void
1223 unix_plugin_select_write(void *cls)
1224 {
1225   struct Plugin *plugin = cls;
1226   const struct GNUNET_SCHEDULER_TaskContext *tc;
1227
1228   plugin->write_task = NULL;
1229   tc = GNUNET_SCHEDULER_get_task_context();
1230   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY))
1231     unix_plugin_do_write(plugin);
1232   if (NULL == plugin->msg_head)
1233     return; /* write queue empty */
1234   plugin->write_task =
1235     GNUNET_SCHEDULER_add_write_net(GNUNET_TIME_UNIT_FOREVER_REL,
1236                                    plugin->unix_sock.desc,
1237                                    &unix_plugin_select_write,
1238                                    plugin);
1239 }
1240
1241
1242 /**
1243  * Function that can be used by the transport service to transmit
1244  * a message using the plugin.   Note that in the case of a
1245  * peer disconnecting, the continuation MUST be called
1246  * prior to the disconnect notification itself.  This function
1247  * will be called with this peer's HELLO message to initiate
1248  * a fresh connection to another peer.
1249  *
1250  * @param cls closure
1251  * @param session which session must be used
1252  * @param msgbuf the message to transmit
1253  * @param msgbuf_size number of bytes in @a msgbuf
1254  * @param priority how important is the message (most plugins will
1255  *                 ignore message priority and just FIFO)
1256  * @param to how long to wait at most for the transmission (does not
1257  *                require plugins to discard the message after the timeout,
1258  *                just advisory for the desired delay; most plugins will ignore
1259  *                this as well)
1260  * @param cont continuation to call once the message has
1261  *        been transmitted (or if the transport is ready
1262  *        for the next transmission call; or if the
1263  *        peer disconnected...); can be NULL
1264  * @param cont_cls closure for @a cont
1265  * @return number of bytes used (on the physical network, with overheads);
1266  *         -1 on hard errors (i.e. address invalid); 0 is a legal value
1267  *         and does NOT mean that the message was not transmitted (DV)
1268  */
1269 static ssize_t
1270 unix_plugin_send(void *cls,
1271                  struct GNUNET_ATS_Session *session,
1272                  const char *msgbuf,
1273                  size_t msgbuf_size,
1274                  unsigned int priority,
1275                  struct GNUNET_TIME_Relative to,
1276                  GNUNET_TRANSPORT_TransmitContinuation cont,
1277                  void *cont_cls)
1278 {
1279   struct Plugin *plugin = cls;
1280   struct UNIXMessageWrapper *wrapper;
1281   struct UNIXMessage *message;
1282   int ssize;
1283
1284   if (GNUNET_OK !=
1285       GNUNET_CONTAINER_multipeermap_contains_value(plugin->session_map,
1286                                                    &session->target,
1287                                                    session))
1288     {
1289       LOG(GNUNET_ERROR_TYPE_ERROR,
1290           "Invalid session for peer `%s' `%s'\n",
1291           GNUNET_i2s(&session->target),
1292           unix_plugin_address_to_string(NULL,
1293                                         session->address->address,
1294                                         session->address->address_length));
1295       GNUNET_break(0);
1296       return GNUNET_SYSERR;
1297     }
1298   LOG(GNUNET_ERROR_TYPE_DEBUG,
1299       "Sending %u bytes with session for peer `%s' `%s'\n",
1300       msgbuf_size,
1301       GNUNET_i2s(&session->target),
1302       unix_plugin_address_to_string(NULL,
1303                                     session->address->address,
1304                                     session->address->address_length));
1305   ssize = sizeof(struct UNIXMessage) + msgbuf_size;
1306   message = GNUNET_malloc(sizeof(struct UNIXMessage) + msgbuf_size);
1307   message->header.size = htons(ssize);
1308   message->header.type = htons(0);
1309   GNUNET_memcpy(&message->sender,
1310                 plugin->env->my_identity,
1311                 sizeof(struct GNUNET_PeerIdentity));
1312   GNUNET_memcpy(&message[1], msgbuf, msgbuf_size);
1313   wrapper = GNUNET_new(struct UNIXMessageWrapper);
1314   wrapper->msg = message;
1315   wrapper->msgsize = ssize;
1316   wrapper->payload = msgbuf_size;
1317   wrapper->priority = priority;
1318   wrapper->timeout = GNUNET_TIME_absolute_add(GNUNET_TIME_absolute_get(), to);
1319   wrapper->cont = cont;
1320   wrapper->cont_cls = cont_cls;
1321   wrapper->session = session;
1322   GNUNET_CONTAINER_DLL_insert_tail(plugin->msg_head,
1323                                    plugin->msg_tail,
1324                                    wrapper);
1325   plugin->bytes_in_queue += ssize;
1326   session->bytes_in_queue += ssize;
1327   session->msgs_in_queue++;
1328   GNUNET_STATISTICS_set(plugin->env->stats,
1329                         "# bytes currently in UNIX buffers",
1330                         plugin->bytes_in_queue,
1331                         GNUNET_NO);
1332   notify_session_monitor(plugin, session, GNUNET_TRANSPORT_SS_UPDATE);
1333   if (NULL == plugin->write_task)
1334     plugin->write_task =
1335       GNUNET_SCHEDULER_add_write_net(GNUNET_TIME_UNIT_FOREVER_REL,
1336                                      plugin->unix_sock.desc,
1337                                      &unix_plugin_select_write,
1338                                      plugin);
1339   return ssize;
1340 }
1341
1342
1343 /**
1344  * Create a slew of UNIX sockets.  If possible, use IPv6 and IPv4.
1345  *
1346  * @param cls closure for server start, should be a `struct Plugin *`
1347  * @return number of sockets created or #GNUNET_SYSERR on error
1348  */
1349 static int
1350 unix_transport_server_start(void *cls)
1351 {
1352   struct Plugin *plugin = cls;
1353   struct sockaddr_un *un;
1354   socklen_t un_len;
1355
1356   un = unix_address_to_sockaddr(plugin->unix_socket_path, &un_len);
1357   if (GNUNET_YES == plugin->is_abstract)
1358     {
1359       plugin->unix_socket_path[0] = '@';
1360       un->sun_path[0] = '\0';
1361     }
1362   plugin->unix_sock.desc =
1363     GNUNET_NETWORK_socket_create(AF_UNIX, SOCK_DGRAM, 0);
1364   if (NULL == plugin->unix_sock.desc)
1365     {
1366       GNUNET_log_strerror(GNUNET_ERROR_TYPE_ERROR, "socket");
1367       GNUNET_free(un);
1368       return GNUNET_SYSERR;
1369     }
1370   if ('\0' != un->sun_path[0])
1371     {
1372       if (GNUNET_OK != GNUNET_DISK_directory_create_for_file(un->sun_path))
1373         {
1374           LOG(GNUNET_ERROR_TYPE_ERROR,
1375               _("Cannot create path to `%s'\n"),
1376               un->sun_path);
1377           GNUNET_NETWORK_socket_close(plugin->unix_sock.desc);
1378           plugin->unix_sock.desc = NULL;
1379           GNUNET_free(un);
1380           return GNUNET_SYSERR;
1381         }
1382     }
1383   if (GNUNET_OK != GNUNET_NETWORK_socket_bind(plugin->unix_sock.desc,
1384                                               (const struct sockaddr *)un,
1385                                               un_len))
1386     {
1387       GNUNET_log_strerror(GNUNET_ERROR_TYPE_ERROR, "bind");
1388       LOG(GNUNET_ERROR_TYPE_ERROR, _("Cannot bind to `%s'\n"), un->sun_path);
1389       GNUNET_NETWORK_socket_close(plugin->unix_sock.desc);
1390       plugin->unix_sock.desc = NULL;
1391       GNUNET_free(un);
1392       return GNUNET_SYSERR;
1393     }
1394   LOG(GNUNET_ERROR_TYPE_DEBUG, "Bound to `%s'\n", plugin->unix_socket_path);
1395   plugin->read_task =
1396     GNUNET_SCHEDULER_add_read_net(GNUNET_TIME_UNIT_FOREVER_REL,
1397                                   plugin->unix_sock.desc,
1398                                   &unix_plugin_select_read,
1399                                   plugin);
1400   GNUNET_free(un);
1401   return 1;
1402 }
1403
1404
1405 /**
1406  * Function that will be called to check if a binary address for this
1407  * plugin is well-formed and corresponds to an address for THIS peer
1408  * (as per our configuration).  Naturally, if absolutely necessary,
1409  * plugins can be a bit conservative in their answer, but in general
1410  * plugins should make sure that the address does not redirect
1411  * traffic to a 3rd party that might try to man-in-the-middle our
1412  * traffic.
1413  *
1414  * @param cls closure, should be our handle to the Plugin
1415  * @param addr pointer to the address
1416  * @param addrlen length of @a addr
1417  * @return #GNUNET_OK if this is a plausible address for this peer
1418  *         and transport, #GNUNET_SYSERR if not
1419  *
1420  */
1421 static int
1422 unix_plugin_check_address(void *cls, const void *addr, size_t addrlen)
1423 {
1424   struct Plugin *plugin = cls;
1425   const struct UnixAddress *ua = addr;
1426   char *addrstr;
1427   size_t addr_str_len;
1428
1429   if ((NULL == addr) || (0 == addrlen) ||
1430       (sizeof(struct UnixAddress) > addrlen))
1431     {
1432       GNUNET_break(0);
1433       return GNUNET_SYSERR;
1434     }
1435   addrstr = (char *)&ua[1];
1436   addr_str_len = ntohl(ua->addrlen);
1437   if ('\0' != addrstr[addr_str_len - 1])
1438     {
1439       GNUNET_break(0);
1440       return GNUNET_SYSERR;
1441     }
1442   if (strlen(addrstr) + 1 != addr_str_len)
1443     {
1444       GNUNET_break(0);
1445       return GNUNET_SYSERR;
1446     }
1447
1448   if (0 == strcmp(plugin->unix_socket_path, addrstr))
1449     return GNUNET_OK;
1450   return GNUNET_SYSERR;
1451 }
1452
1453
1454 /**
1455  * Convert the transports address to a nice, human-readable
1456  * format.
1457  *
1458  * @param cls closure
1459  * @param type name of the transport that generated the address
1460  * @param addr one of the addresses of the host, NULL for the last address
1461  *        the specific address format depends on the transport
1462  * @param addrlen length of the @a addr
1463  * @param numeric should (IP) addresses be displayed in numeric form?
1464  * @param timeout after how long should we give up?
1465  * @param asc function to call on each string
1466  * @param asc_cls closure for @a asc
1467  */
1468 static void
1469 unix_plugin_address_pretty_printer(void *cls,
1470                                    const char *type,
1471                                    const void *addr,
1472                                    size_t addrlen,
1473                                    int numeric,
1474                                    struct GNUNET_TIME_Relative timeout,
1475                                    GNUNET_TRANSPORT_AddressStringCallback asc,
1476                                    void *asc_cls)
1477 {
1478   const char *ret;
1479
1480   if ((NULL != addr) && (addrlen > 0))
1481     ret = unix_plugin_address_to_string(NULL, addr, addrlen);
1482   else
1483     ret = NULL;
1484   asc(asc_cls, ret, (NULL == ret) ? GNUNET_SYSERR : GNUNET_OK);
1485   asc(asc_cls, NULL, GNUNET_OK);
1486 }
1487
1488
1489 /**
1490  * Function called to convert a string address to
1491  * a binary address.
1492  *
1493  * @param cls closure (`struct Plugin *`)
1494  * @param addr string address
1495  * @param addrlen length of the @a addr (strlen(addr) + '\0')
1496  * @param buf location to store the buffer
1497  *        If the function returns #GNUNET_SYSERR, its contents are undefined.
1498  * @param added length of created address
1499  * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
1500  */
1501 static int
1502 unix_plugin_string_to_address(void *cls,
1503                               const char *addr,
1504                               uint16_t addrlen,
1505                               void **buf,
1506                               size_t *added)
1507 {
1508   struct UnixAddress *ua;
1509   char *address;
1510   char *plugin;
1511   char *optionstr;
1512   uint32_t options;
1513   size_t ua_size;
1514
1515   /* Format unix.options.address */
1516   address = NULL;
1517   plugin = NULL;
1518   optionstr = NULL;
1519
1520   if ((NULL == addr) || (addrlen == 0))
1521     {
1522       GNUNET_break(0);
1523       return GNUNET_SYSERR;
1524     }
1525   if ('\0' != addr[addrlen - 1])
1526     {
1527       GNUNET_break(0);
1528       return GNUNET_SYSERR;
1529     }
1530   if (strlen(addr) != addrlen - 1)
1531     {
1532       GNUNET_break(0);
1533       return GNUNET_SYSERR;
1534     }
1535   plugin = GNUNET_strdup(addr);
1536   optionstr = strchr(plugin, '.');
1537   if (NULL == optionstr)
1538     {
1539       GNUNET_break(0);
1540       GNUNET_free(plugin);
1541       return GNUNET_SYSERR;
1542     }
1543   optionstr[0] = '\0';
1544   optionstr++;
1545   options = atol(optionstr);
1546   address = strchr(optionstr, '.');
1547   if (NULL == address)
1548     {
1549       GNUNET_break(0);
1550       GNUNET_free(plugin);
1551       return GNUNET_SYSERR;
1552     }
1553   address[0] = '\0';
1554   address++;
1555   if (0 != strcmp(plugin, PLUGIN_NAME))
1556     {
1557       GNUNET_break(0);
1558       GNUNET_free(plugin);
1559       return GNUNET_SYSERR;
1560     }
1561
1562   ua_size = sizeof(struct UnixAddress) + strlen(address) + 1;
1563   ua = GNUNET_malloc(ua_size);
1564   ua->options = htonl(options);
1565   ua->addrlen = htonl(strlen(address) + 1);
1566   GNUNET_memcpy(&ua[1], address, strlen(address) + 1);
1567   GNUNET_free(plugin);
1568
1569   (*buf) = ua;
1570   (*added) = ua_size;
1571   return GNUNET_OK;
1572 }
1573
1574
1575 /**
1576  * Notify transport service about address
1577  *
1578  * @param cls the plugin
1579  */
1580 static void
1581 address_notification(void *cls)
1582 {
1583   struct Plugin *plugin = cls;
1584   struct GNUNET_HELLO_Address *address;
1585   size_t len;
1586   struct UnixAddress *ua;
1587   char *unix_path;
1588
1589   len = sizeof(struct UnixAddress) + strlen(plugin->unix_socket_path) + 1;
1590   ua = GNUNET_malloc(len);
1591   ua->options = htonl(plugin->myoptions);
1592   ua->addrlen = htonl(strlen(plugin->unix_socket_path) + 1);
1593   unix_path = (char *)&ua[1];
1594   GNUNET_memcpy(unix_path,
1595                 plugin->unix_socket_path,
1596                 strlen(plugin->unix_socket_path) + 1);
1597
1598   plugin->address_update_task = NULL;
1599   address = GNUNET_HELLO_address_allocate(plugin->env->my_identity,
1600                                           PLUGIN_NAME,
1601                                           ua,
1602                                           len,
1603                                           GNUNET_HELLO_ADDRESS_INFO_NONE);
1604   plugin->env->notify_address(plugin->env->cls, GNUNET_YES, address);
1605   GNUNET_free(ua);
1606   GNUNET_free(address);
1607 }
1608
1609
1610 /**
1611  * Function called on sessions to disconnect
1612  *
1613  * @param cls the plugin
1614  * @param key peer identity (unused)
1615  * @param value the `struct GNUNET_ATS_Session *` to disconnect
1616  * @return #GNUNET_YES (always, continue to iterate)
1617  */
1618 static int
1619 get_session_delete_it(void *cls,
1620                       const struct GNUNET_PeerIdentity *key,
1621                       void *value)
1622 {
1623   struct Plugin *plugin = cls;
1624   struct GNUNET_ATS_Session *session = value;
1625
1626   unix_plugin_session_disconnect(plugin, session);
1627   return GNUNET_YES;
1628 }
1629
1630
1631 /**
1632  * Disconnect from a remote node.  Clean up session if we have one for this peer
1633  *
1634  * @param cls closure for this call (should be handle to Plugin)
1635  * @param target the peeridentity of the peer to disconnect
1636  * @return #GNUNET_OK on success, #GNUNET_SYSERR if the operation failed
1637  */
1638 static void
1639 unix_plugin_peer_disconnect(void *cls,
1640                             const struct GNUNET_PeerIdentity *target)
1641 {
1642   struct Plugin *plugin = cls;
1643
1644   GNUNET_CONTAINER_multipeermap_get_multiple(plugin->session_map,
1645                                              target,
1646                                              &get_session_delete_it,
1647                                              plugin);
1648 }
1649
1650
1651 /**
1652  * Return information about the given session to the
1653  * monitor callback.
1654  *
1655  * @param cls the `struct Plugin` with the monitor callback (`sic`)
1656  * @param peer peer we send information about
1657  * @param value our `struct GNUNET_ATS_Session` to send information about
1658  * @return #GNUNET_OK (continue to iterate)
1659  */
1660 static int
1661 send_session_info_iter(void *cls,
1662                        const struct GNUNET_PeerIdentity *peer,
1663                        void *value)
1664 {
1665   struct Plugin *plugin = cls;
1666   struct GNUNET_ATS_Session *session = value;
1667
1668   notify_session_monitor(plugin, session, GNUNET_TRANSPORT_SS_INIT);
1669   notify_session_monitor(plugin, session, GNUNET_TRANSPORT_SS_UP);
1670   return GNUNET_OK;
1671 }
1672
1673
1674 /**
1675  * Begin monitoring sessions of a plugin.  There can only
1676  * be one active monitor per plugin (i.e. if there are
1677  * multiple monitors, the transport service needs to
1678  * multiplex the generated events over all of them).
1679  *
1680  * @param cls closure of the plugin
1681  * @param sic callback to invoke, NULL to disable monitor;
1682  *            plugin will being by iterating over all active
1683  *            sessions immediately and then enter monitor mode
1684  * @param sic_cls closure for @a sic
1685  */
1686 static void
1687 unix_plugin_setup_monitor(void *cls,
1688                           GNUNET_TRANSPORT_SessionInfoCallback sic,
1689                           void *sic_cls)
1690 {
1691   struct Plugin *plugin = cls;
1692
1693   plugin->sic = sic;
1694   plugin->sic_cls = sic_cls;
1695   if (NULL != sic)
1696     {
1697       GNUNET_CONTAINER_multipeermap_iterate(plugin->session_map,
1698                                             &send_session_info_iter,
1699                                             plugin);
1700       /* signal end of first iteration */
1701       sic(sic_cls, NULL, NULL);
1702     }
1703 }
1704
1705
1706 /**
1707  * The exported method.  Initializes the plugin and returns a
1708  * struct with the callbacks.
1709  *
1710  * @param cls the plugin's execution environment
1711  * @return NULL on error, plugin functions otherwise
1712  */
1713 void *
1714 libgnunet_plugin_transport_unix_init(void *cls)
1715 {
1716   struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
1717   struct GNUNET_TRANSPORT_PluginFunctions *api;
1718   struct Plugin *plugin;
1719   int sockets_created;
1720
1721   if (NULL == env->receive)
1722     {
1723       /* run in 'stub' mode (i.e. as part of gnunet-peerinfo), don't fully
1724          initialze the plugin or the API */
1725       api = GNUNET_new(struct GNUNET_TRANSPORT_PluginFunctions);
1726       api->cls = NULL;
1727       api->address_pretty_printer = &unix_plugin_address_pretty_printer;
1728       api->address_to_string = &unix_plugin_address_to_string;
1729       api->string_to_address = &unix_plugin_string_to_address;
1730       return api;
1731     }
1732
1733   plugin = GNUNET_new(struct Plugin);
1734   if (GNUNET_OK !=
1735       GNUNET_CONFIGURATION_get_value_filename(env->cfg,
1736                                               "transport-unix",
1737                                               "UNIXPATH",
1738                                               &plugin->unix_socket_path))
1739     {
1740       GNUNET_log_config_missing(GNUNET_ERROR_TYPE_ERROR,
1741                                 "transport-unix",
1742                                 "UNIXPATH");
1743       GNUNET_free(plugin);
1744       return NULL;
1745     }
1746
1747   plugin->env = env;
1748
1749   /* Initialize my flags */
1750 #ifdef LINUX
1751   plugin->is_abstract =
1752     GNUNET_CONFIGURATION_get_value_yesno(plugin->env->cfg,
1753                                          "testing",
1754                                          "USE_ABSTRACT_SOCKETS");
1755 #endif
1756   plugin->myoptions = UNIX_OPTIONS_NONE;
1757   if (GNUNET_YES == plugin->is_abstract)
1758     plugin->myoptions = UNIX_OPTIONS_USE_ABSTRACT_SOCKETS;
1759
1760   api = GNUNET_new(struct GNUNET_TRANSPORT_PluginFunctions);
1761   api->cls = plugin;
1762   api->get_session = &unix_plugin_get_session;
1763   api->send = &unix_plugin_send;
1764   api->disconnect_peer = &unix_plugin_peer_disconnect;
1765   api->disconnect_session = &unix_plugin_session_disconnect;
1766   api->query_keepalive_factor = &unix_plugin_query_keepalive_factor;
1767   api->address_pretty_printer = &unix_plugin_address_pretty_printer;
1768   api->address_to_string = &unix_plugin_address_to_string;
1769   api->check_address = &unix_plugin_check_address;
1770   api->string_to_address = &unix_plugin_string_to_address;
1771   api->get_network = &unix_plugin_get_network;
1772   api->get_network_for_address = &unix_plugin_get_network_for_address;
1773   api->update_session_timeout = &unix_plugin_update_session_timeout;
1774   api->setup_monitor = &unix_plugin_setup_monitor;
1775   sockets_created = unix_transport_server_start(plugin);
1776   if ((0 == sockets_created) || (GNUNET_SYSERR == sockets_created))
1777     {
1778       LOG(GNUNET_ERROR_TYPE_WARNING, _("Failed to open UNIX listen socket\n"));
1779       GNUNET_free(api);
1780       GNUNET_free(plugin->unix_socket_path);
1781       GNUNET_free(plugin);
1782       return NULL;
1783     }
1784   plugin->session_map = GNUNET_CONTAINER_multipeermap_create(10, GNUNET_NO);
1785   plugin->address_update_task =
1786     GNUNET_SCHEDULER_add_now(&address_notification, plugin);
1787   return api;
1788 }
1789
1790
1791 /**
1792  * Shutdown the plugin.
1793  *
1794  * @param cls the plugin API returned from the initialization function
1795  * @return NULL (always)
1796  */
1797 void *
1798 libgnunet_plugin_transport_unix_done(void *cls)
1799 {
1800   struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
1801   struct Plugin *plugin = api->cls;
1802   struct GNUNET_HELLO_Address *address;
1803   struct UNIXMessageWrapper *msgw;
1804   struct UnixAddress *ua;
1805   size_t len;
1806   struct GNUNET_ATS_Session *session;
1807
1808   if (NULL == plugin)
1809     {
1810       GNUNET_free(api);
1811       return NULL;
1812     }
1813   len = sizeof(struct UnixAddress) + strlen(plugin->unix_socket_path) + 1;
1814   ua = GNUNET_malloc(len);
1815   ua->options = htonl(plugin->myoptions);
1816   ua->addrlen = htonl(strlen(plugin->unix_socket_path) + 1);
1817   GNUNET_memcpy(&ua[1],
1818                 plugin->unix_socket_path,
1819                 strlen(plugin->unix_socket_path) + 1);
1820   address = GNUNET_HELLO_address_allocate(plugin->env->my_identity,
1821                                           PLUGIN_NAME,
1822                                           ua,
1823                                           len,
1824                                           GNUNET_HELLO_ADDRESS_INFO_NONE);
1825   plugin->env->notify_address(plugin->env->cls, GNUNET_NO, address);
1826
1827   GNUNET_free(address);
1828   GNUNET_free(ua);
1829
1830   while (NULL != (msgw = plugin->msg_head))
1831     {
1832       GNUNET_CONTAINER_DLL_remove(plugin->msg_head, plugin->msg_tail, msgw);
1833       session = msgw->session;
1834       session->msgs_in_queue--;
1835       GNUNET_assert(session->bytes_in_queue >= msgw->msgsize);
1836       session->bytes_in_queue -= msgw->msgsize;
1837       GNUNET_assert(plugin->bytes_in_queue >= msgw->msgsize);
1838       plugin->bytes_in_queue -= msgw->msgsize;
1839       if (NULL != msgw->cont)
1840         msgw->cont(msgw->cont_cls,
1841                    &msgw->session->target,
1842                    GNUNET_SYSERR,
1843                    msgw->payload,
1844                    0);
1845       GNUNET_free(msgw->msg);
1846       GNUNET_free(msgw);
1847     }
1848
1849   if (NULL != plugin->read_task)
1850     {
1851       GNUNET_SCHEDULER_cancel(plugin->read_task);
1852       plugin->read_task = NULL;
1853     }
1854   if (NULL != plugin->write_task)
1855     {
1856       GNUNET_SCHEDULER_cancel(plugin->write_task);
1857       plugin->write_task = NULL;
1858     }
1859   if (NULL != plugin->address_update_task)
1860     {
1861       GNUNET_SCHEDULER_cancel(plugin->address_update_task);
1862       plugin->address_update_task = NULL;
1863     }
1864   if (NULL != plugin->unix_sock.desc)
1865     {
1866       GNUNET_break(GNUNET_OK ==
1867                    GNUNET_NETWORK_socket_close(plugin->unix_sock.desc));
1868       plugin->unix_sock.desc = NULL;
1869     }
1870   GNUNET_CONTAINER_multipeermap_iterate(plugin->session_map,
1871                                         &get_session_delete_it,
1872                                         plugin);
1873   GNUNET_CONTAINER_multipeermap_destroy(plugin->session_map);
1874   GNUNET_break(0 == plugin->bytes_in_queue);
1875   GNUNET_free(plugin->unix_socket_path);
1876   GNUNET_free(plugin);
1877   GNUNET_free(api);
1878   return NULL;
1879 }
1880
1881 /* end of plugin_transport_unix.c */