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