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