-indentation
[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
344 static struct sockaddr_un *
345 unix_address_to_sockaddr (const char *unixpath,
346                           socklen_t *sock_len)
347 {
348   struct sockaddr_un *un;
349   size_t slen;
350
351   GNUNET_assert (0 < strlen (unixpath));        /* sanity check */
352   un = GNUNET_new (struct sockaddr_un);
353   un->sun_family = AF_UNIX;
354   slen = strlen (unixpath);
355   if (slen >= sizeof (un->sun_path))
356     slen = sizeof (un->sun_path) - 1;
357   memcpy (un->sun_path, unixpath, slen);
358   un->sun_path[slen] = '\0';
359   slen = sizeof (struct sockaddr_un);
360 #if HAVE_SOCKADDR_IN_SIN_LEN
361   un->sun_len = (u_char) slen;
362 #endif
363   (*sock_len) = slen;
364   return un;
365 }
366
367
368 /**
369  * Function called for a quick conversion of the binary address to
370  * a numeric address.  Note that the caller must not free the
371  * address and that the next call to this function is allowed
372  * to override the address again.
373  *
374  * @param cls closure
375  * @param addr binary address
376  * @param addrlen length of the @a addr
377  * @return string representing the same address
378  */
379 static const char *
380 unix_address_to_string (void *cls,
381                         const void *addr,
382                         size_t addrlen)
383 {
384   static char rbuf[1024];
385   struct UnixAddress *ua = (struct UnixAddress *) addr;
386   char *addrstr;
387   size_t addr_str_len;
388   unsigned int off;
389
390   if ((NULL == addr) || (sizeof (struct UnixAddress) > addrlen))
391   {
392     GNUNET_break(0);
393     return NULL;
394   }
395   addrstr = (char *) &ua[1];
396   addr_str_len = ntohl (ua->addrlen);
397
398   if (addr_str_len != addrlen - sizeof(struct UnixAddress))
399   {
400     GNUNET_break(0);
401     return NULL;
402   }
403
404   if ('\0' != addrstr[addr_str_len - 1])
405   {
406     GNUNET_break(0);
407     return NULL;
408   }
409   if (strlen (addrstr) + 1 != addr_str_len)
410   {
411     GNUNET_break(0);
412     return NULL;
413   }
414
415   off = 0;
416   if ('\0' == addrstr[0])
417     off++;
418   memset (rbuf, 0, sizeof (rbuf));
419   GNUNET_snprintf (rbuf,
420                    sizeof (rbuf) - 1,
421                    "%s.%u.%s%.*s",
422                    PLUGIN_NAME,
423                    ntohl (ua->options),
424                    (off == 1) ? "@" : "",
425                    (int) (addr_str_len - off),
426                    &addrstr[off]);
427   return rbuf;
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,
551                                s->address->address,
552                                s->address->address_length));
553   plugin->env->session_end (plugin->env->cls, s->address, s);
554   removed = GNUNET_NO;
555   next = plugin->msg_head;
556   while (NULL != next)
557   {
558     msgw = next;
559     next = msgw->next;
560     if (msgw->session != s)
561       continue;
562     GNUNET_CONTAINER_DLL_remove (plugin->msg_head, plugin->msg_tail, msgw);
563     if (NULL != msgw->cont)
564       msgw->cont (msgw->cont_cls,  &msgw->session->target, GNUNET_SYSERR,
565                   msgw->payload, 0);
566     GNUNET_free (msgw->msg);
567     GNUNET_free (msgw);
568     removed = GNUNET_YES;
569   }
570   GNUNET_assert (GNUNET_YES ==
571                  GNUNET_CONTAINER_multipeermap_remove (plugin->session_map,
572                                                        &s->target,
573                                                        s));
574   GNUNET_STATISTICS_set (plugin->env->stats,
575                          "# UNIX sessions active",
576                          GNUNET_CONTAINER_multipeermap_size (plugin->session_map),
577                          GNUNET_NO);
578   if ((GNUNET_YES == removed) && (NULL == plugin->msg_head))
579     reschedule_select (plugin);
580   if (GNUNET_SCHEDULER_NO_TASK != s->timeout_task)
581   {
582     GNUNET_SCHEDULER_cancel (s->timeout_task);
583     s->timeout_task = GNUNET_SCHEDULER_NO_TASK;
584   }
585   GNUNET_HELLO_address_free (s->address);
586   GNUNET_free (s);
587   return GNUNET_OK;
588 }
589
590
591 /**
592  * Function that is called to get the keepalive factor.
593  * GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT is divided by this number to
594  * calculate the interval between keepalive packets.
595  *
596  * @param cls closure with the `struct Plugin`
597  * @return keepalive factor
598  */
599 static unsigned int
600 unix_query_keepalive_factor (void *cls)
601 {
602   return 3;
603 }
604
605
606 /**
607  * Actually send out the message, assume we've got the address and
608  * send_handle squared away!
609  *
610  * @param cls closure
611  * @param send_handle which handle to send message on
612  * @param target who should receive this message (ignored by UNIX)
613  * @param msgbuf one or more GNUNET_MessageHeader(s) strung together
614  * @param msgbuf_size the size of the msgbuf to send
615  * @param priority how important is the message (ignored by UNIX)
616  * @param timeout when should we time out (give up) if we can not transmit?
617  * @param addr the addr to send the message to, needs to be a sockaddr for us
618  * @param addrlen the len of @a addr
619  * @param payload bytes payload to send
620  * @param cont continuation to call once the message has
621  *        been transmitted (or if the transport is ready
622  *        for the next transmission call; or if the
623  *        peer disconnected...)
624  * @param cont_cls closure for @a cont
625  * @return on success the number of bytes written, RETRY for retry, -1 on errors
626  */
627 static ssize_t
628 unix_real_send (void *cls,
629                 struct GNUNET_NETWORK_Handle *send_handle,
630                 const struct GNUNET_PeerIdentity *target, const char *msgbuf,
631                 size_t msgbuf_size, unsigned int priority,
632                 struct GNUNET_TIME_Absolute timeout,
633                 const struct UnixAddress *addr,
634                 size_t addrlen,
635                 size_t payload,
636                 GNUNET_TRANSPORT_TransmitContinuation cont,
637                 void *cont_cls)
638 {
639   struct Plugin *plugin = cls;
640   ssize_t sent;
641   struct sockaddr_un *un;
642   socklen_t un_len;
643   const char *unixpath;
644
645   GNUNET_assert (NULL != plugin);
646   if (NULL == send_handle)
647   {
648     GNUNET_break (0); /* We do not have a send handle */
649     return GNUNET_SYSERR;
650   }
651   if ((NULL == addr) || (0 == addrlen))
652   {
653     GNUNET_break (0); /* Can never send if we don't have an address */
654     return GNUNET_SYSERR;
655   }
656
657   /* Prepare address */
658   unixpath = (const char *)  &addr[1];
659   if (NULL == (un = unix_address_to_sockaddr (unixpath,
660                                               &un_len)))
661   {
662     GNUNET_break (0);
663     return -1;
664   }
665
666   if ((GNUNET_YES == plugin->abstract) &&
667       (0 != (UNIX_OPTIONS_USE_ABSTRACT_SOCKETS & ntohl(addr->options) )) )
668   {
669     un->sun_path[0] = '\0';
670   }
671 resend:
672   /* Send the data */
673   sent = GNUNET_NETWORK_socket_sendto (send_handle, msgbuf, msgbuf_size,
674       (const struct sockaddr *) un, un_len);
675   if (GNUNET_SYSERR == sent)
676   {
677     if ( (EAGAIN == errno) ||
678          (ENOBUFS == errno) )
679     {
680       GNUNET_free (un);
681       return RETRY; /* We have to retry later  */
682     }
683     if (EMSGSIZE == errno)
684     {
685       socklen_t size = 0;
686       socklen_t len = sizeof (size);
687
688       GNUNET_NETWORK_socket_getsockopt ((struct GNUNET_NETWORK_Handle *)
689                                         send_handle, SOL_SOCKET, SO_SNDBUF, &size,
690                                         &len);
691       if (size < msgbuf_size)
692       {
693         LOG (GNUNET_ERROR_TYPE_DEBUG,
694                     "Trying to increase socket buffer size from %i to %i for message size %i\n",
695                     size, ((msgbuf_size / 1000) + 2) * 1000, msgbuf_size);
696         size = ((msgbuf_size / 1000) + 2) * 1000;
697         if (GNUNET_OK == GNUNET_NETWORK_socket_setsockopt
698             ((struct GNUNET_NETWORK_Handle *) send_handle, SOL_SOCKET, SO_SNDBUF,
699              &size, sizeof (size)))
700           goto resend; /* Increased buffer size, retry sending */
701         else
702         {
703           /* Could not increase buffer size: error, no retry */
704           GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "setsockopt");
705           GNUNET_free (un);
706           return GNUNET_SYSERR;
707         }
708       }
709       else
710       {
711         /* Buffer is bigger than message:  error, no retry
712          * This should never happen!*/
713         GNUNET_break (0);
714         GNUNET_free (un);
715         return GNUNET_SYSERR;
716       }
717     }
718   }
719
720   LOG (GNUNET_ERROR_TYPE_DEBUG,
721        "UNIX transmit %u-byte message to %s (%d: %s)\n",
722        (unsigned int) msgbuf_size,
723        GNUNET_a2s ((const struct sockaddr *)un, un_len),
724        (int) sent,
725        (sent < 0) ? STRERROR (errno) : "ok");
726   GNUNET_free (un);
727   return sent;
728 }
729
730
731 /**
732  * Closure for 'get_session_it'.
733  */
734 struct GetSessionIteratorContext
735 {
736   /**
737    * Location to store the session, if found.
738    */
739   struct Session *res;
740
741   /**
742    * Address information.
743    */
744   const struct GNUNET_HELLO_Address *address;
745 };
746
747
748 /**
749  * Function called to find a session by address.
750  *
751  * @param cls the 'struct LookupCtx'
752  * @param key peer we are looking for (unused)
753  * @param value a session
754  * @return #GNUNET_YES if not found (continue looking), #GNUNET_NO on success
755  */
756 static int
757 get_session_it (void *cls,
758                 const struct GNUNET_PeerIdentity *key,
759                 void *value)
760 {
761   struct GetSessionIteratorContext *gsi = cls;
762   struct Session *s = value;
763
764   if (0 == GNUNET_HELLO_address_cmp(s->address, gsi->address))
765   {
766     gsi->res = s;
767     return GNUNET_NO;
768   }
769   return GNUNET_YES;
770 }
771
772
773 /**
774  * Session was idle for too long, so disconnect it
775  *
776  * @param cls the 'struct Session' to disconnect
777  * @param tc scheduler context
778  */
779 static void
780 session_timeout (void *cls,
781                  const struct GNUNET_SCHEDULER_TaskContext *tc)
782 {
783   struct Session *s = cls;
784
785   s->timeout_task = GNUNET_SCHEDULER_NO_TASK;
786   LOG (GNUNET_ERROR_TYPE_DEBUG,
787        "Session %p was idle for %s, disconnecting\n",
788        s,
789        GNUNET_STRINGS_relative_time_to_string (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
790                                                GNUNET_YES));
791   unix_session_disconnect (s->plugin, s);
792 }
793
794
795 /**
796  * Function obtain the network type for a session
797  *
798  * @param cls closure ('struct Plugin*')
799  * @param session the session
800  * @return the network type in HBO or #GNUNET_SYSERR
801  */
802 static enum GNUNET_ATS_Network_Type
803 unix_get_network (void *cls,
804                   struct Session *session)
805 {
806   GNUNET_assert (NULL != session);
807   return GNUNET_ATS_NET_LOOPBACK;
808 }
809
810
811 /**
812  * Creates a new outbound session the transport service will use to send data to the
813  * peer
814  *
815  * @param cls the plugin
816  * @param address the address
817  * @return the session or NULL of max connections exceeded
818  */
819 static struct Session *
820 unix_plugin_get_session (void *cls,
821                          const struct GNUNET_HELLO_Address *address)
822 {
823   struct Plugin *plugin = cls;
824   struct Session *s;
825   struct GetSessionIteratorContext gsi;
826   struct UnixAddress *ua;
827   char * addrstr;
828   uint32_t addr_str_len;
829   uint32_t addr_option;
830
831   GNUNET_assert (NULL != plugin);
832   GNUNET_assert (NULL != address);
833
834   ua = (struct UnixAddress *) address->address;
835   if ((NULL == address->address) || (0 == address->address_length) ||
836                 (sizeof (struct UnixAddress) > address->address_length))
837   {
838     GNUNET_break (0);
839     return NULL;
840   }
841   addrstr = (char *) &ua[1];
842   addr_str_len = ntohl (ua->addrlen);
843   addr_option = ntohl (ua->options);
844
845   if ( (0 != (UNIX_OPTIONS_USE_ABSTRACT_SOCKETS & addr_option)) &&
846     (GNUNET_NO == plugin->abstract))
847   {
848     return NULL;
849   }
850
851   if (addr_str_len != address->address_length - sizeof (struct UnixAddress))
852   {
853     return NULL; /* This can be a legacy address */
854   }
855
856   if ('\0' != addrstr[addr_str_len - 1])
857   {
858     GNUNET_break (0);
859     return NULL;
860   }
861   if (strlen (addrstr) + 1 != addr_str_len)
862   {
863     GNUNET_break (0);
864     return NULL;
865   }
866
867   /* Check if already existing */
868   gsi.address = address;
869   gsi.res = NULL;
870   GNUNET_CONTAINER_multipeermap_get_multiple (plugin->session_map,
871                                               &address->peer,
872                                               &get_session_it, &gsi);
873   if (NULL != gsi.res)
874   {
875     LOG (GNUNET_ERROR_TYPE_DEBUG,
876          "Found existing session %p for address `%s'\n",
877          gsi.res,
878          unix_address_to_string (NULL, address->address, address->address_length));
879     return gsi.res;
880   }
881
882   /* create a new session */
883   s = GNUNET_new (struct Session);
884   s->target = address->peer;
885   s->address = GNUNET_HELLO_address_copy (address);
886   s->plugin = plugin;
887   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == s->timeout_task);
888   s->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
889                                                   &session_timeout,
890                                                   s);
891   LOG (GNUNET_ERROR_TYPE_DEBUG,
892        "Creating a new session %p for address `%s'\n",
893        s,
894        unix_address_to_string (NULL,
895                                address->address,
896                                address->address_length));
897   (void) GNUNET_CONTAINER_multipeermap_put (plugin->session_map,
898                                             &address->peer, s,
899                                             GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
900   GNUNET_STATISTICS_set (plugin->env->stats,
901                          "# UNIX sessions active",
902                          GNUNET_CONTAINER_multipeermap_size (plugin->session_map),
903                          GNUNET_NO);
904   return s;
905 }
906
907 static void
908 unix_plugin_update_session_timeout (void *cls,
909                                   const struct GNUNET_PeerIdentity *peer,
910                                   struct Session *session)
911 {
912   struct Plugin *plugin = cls;
913
914   if (GNUNET_OK !=
915       GNUNET_CONTAINER_multipeermap_contains_value (plugin->session_map,
916                                                     &session->target,
917                                                     session))
918     return;
919   reschedule_session_timeout (session);
920 }
921
922 /**
923  * Function that can be used by the transport service to transmit
924  * a message using the plugin.   Note that in the case of a
925  * peer disconnecting, the continuation MUST be called
926  * prior to the disconnect notification itself.  This function
927  * will be called with this peer's HELLO message to initiate
928  * a fresh connection to another peer.
929  *
930  * @param cls closure
931  * @param session which session must be used
932  * @param msgbuf the message to transmit
933  * @param msgbuf_size number of bytes in @a msgbuf
934  * @param priority how important is the message (most plugins will
935  *                 ignore message priority and just FIFO)
936  * @param to how long to wait at most for the transmission (does not
937  *                require plugins to discard the message after the timeout,
938  *                just advisory for the desired delay; most plugins will ignore
939  *                this as well)
940  * @param cont continuation to call once the message has
941  *        been transmitted (or if the transport is ready
942  *        for the next transmission call; or if the
943  *        peer disconnected...); can be NULL
944  * @param cont_cls closure for @a cont
945  * @return number of bytes used (on the physical network, with overheads);
946  *         -1 on hard errors (i.e. address invalid); 0 is a legal value
947  *         and does NOT mean that the message was not transmitted (DV)
948  */
949 static ssize_t
950 unix_plugin_send (void *cls,
951                   struct Session *session,
952                   const char *msgbuf, size_t msgbuf_size,
953                   unsigned int priority,
954                   struct GNUNET_TIME_Relative to,
955                   GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls)
956 {
957   struct Plugin *plugin = cls;
958   struct UNIXMessageWrapper *wrapper;
959   struct UNIXMessage *message;
960   int ssize;
961
962   if (GNUNET_OK !=
963       GNUNET_CONTAINER_multipeermap_contains_value (plugin->session_map,
964                                                     &session->target,
965                                                     session))
966   {
967     LOG (GNUNET_ERROR_TYPE_ERROR,
968          "Invalid session for peer `%s' `%s'\n",
969          GNUNET_i2s (&session->target),
970          unix_address_to_string(NULL,
971                                 session->address->address,
972                                 session->address->address_length));
973     GNUNET_break (0);
974     return GNUNET_SYSERR;
975   }
976   LOG (GNUNET_ERROR_TYPE_DEBUG,
977        "Sending %u bytes with session for peer `%s' `%s'\n",
978        msgbuf_size,
979        GNUNET_i2s (&session->target),
980        unix_address_to_string (NULL,
981                                session->address->address,
982                                session->address->address_length));
983   ssize = sizeof (struct UNIXMessage) + msgbuf_size;
984   message = GNUNET_malloc (sizeof (struct UNIXMessage) + msgbuf_size);
985   message->header.size = htons (ssize);
986   message->header.type = htons (0);
987   memcpy (&message->sender, plugin->env->my_identity,
988           sizeof (struct GNUNET_PeerIdentity));
989   memcpy (&message[1], msgbuf, msgbuf_size);
990
991   wrapper = GNUNET_new (struct UNIXMessageWrapper);
992   wrapper->msg = message;
993   wrapper->msgsize = ssize;
994   wrapper->payload = msgbuf_size;
995   wrapper->priority = priority;
996   wrapper->timeout = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get(), to);
997   wrapper->cont = cont;
998   wrapper->cont_cls = cont_cls;
999   wrapper->session = session;
1000   GNUNET_CONTAINER_DLL_insert (plugin->msg_head,
1001                                plugin->msg_tail,
1002                                wrapper);
1003   plugin->bytes_in_queue += ssize;
1004   GNUNET_STATISTICS_set (plugin->env->stats,
1005                          "# bytes currently in UNIX buffers",
1006                          plugin->bytes_in_queue,
1007                          GNUNET_NO);
1008   if (GNUNET_NO == plugin->with_ws)
1009     reschedule_select (plugin);
1010   return ssize;
1011 }
1012
1013
1014 /**
1015  * Demultiplexer for UNIX messages
1016  *
1017  * @param plugin the main plugin for this transport
1018  * @param sender from which peer the message was received
1019  * @param currhdr pointer to the header of the message
1020  * @param ua address to look for
1021  * @param ua_len length of the address @a ua
1022  */
1023 static void
1024 unix_demultiplexer (struct Plugin *plugin, struct GNUNET_PeerIdentity *sender,
1025                     const struct GNUNET_MessageHeader *currhdr,
1026                     const struct UnixAddress *ua, size_t ua_len)
1027 {
1028   struct Session *s = NULL;
1029   struct GNUNET_HELLO_Address *address;
1030
1031   GNUNET_break (ntohl(plugin->ats_network.value) != GNUNET_ATS_NET_UNSPECIFIED);
1032   GNUNET_assert (ua_len >= sizeof (struct UnixAddress));
1033   LOG (GNUNET_ERROR_TYPE_DEBUG,
1034        "Received message from %s\n",
1035        unix_address_to_string (NULL, ua, ua_len));
1036   GNUNET_STATISTICS_update (plugin->env->stats,
1037                             "# bytes received via UNIX",
1038                             ntohs (currhdr->size),
1039                             GNUNET_NO);
1040
1041   /* Look for existing session */
1042   address = GNUNET_HELLO_address_allocate (sender, PLUGIN_NAME, ua, ua_len,
1043       GNUNET_HELLO_ADDRESS_INFO_NONE); /* UNIX does not have "inbound" sessions */
1044   s = lookup_session (plugin, address);
1045
1046   if (NULL == s)
1047   {
1048     s = unix_plugin_get_session (plugin, address);
1049     /* Notify transport and ATS about new inbound session */
1050     plugin->env->session_start (NULL, s->address, s, &plugin->ats_network, 1);
1051   }
1052   GNUNET_HELLO_address_free (address);
1053   reschedule_session_timeout (s);
1054
1055   plugin->env->receive (plugin->env->cls, s->address, s, currhdr);
1056   plugin->env->update_address_metrics (plugin->env->cls, s->address, s,
1057                                        &plugin->ats_network, 1);
1058 }
1059
1060
1061 /**
1062  * Read from UNIX domain socket (it is ready).
1063  *
1064  * @param plugin the plugin
1065  */
1066 static void
1067 unix_plugin_select_read (struct Plugin *plugin)
1068 {
1069   char buf[65536] GNUNET_ALIGN;
1070   struct UnixAddress *ua;
1071   struct UNIXMessage *msg;
1072   struct GNUNET_PeerIdentity sender;
1073   struct sockaddr_un un;
1074   socklen_t addrlen;
1075   ssize_t ret;
1076   int offset;
1077   int tsize;
1078   int is_abstract;
1079   char *msgbuf;
1080   const struct GNUNET_MessageHeader *currhdr;
1081   uint16_t csize;
1082   size_t ua_len;
1083
1084   addrlen = sizeof (un);
1085   memset (&un, 0, sizeof (un));
1086
1087   ret =
1088       GNUNET_NETWORK_socket_recvfrom (plugin->unix_sock.desc, buf, sizeof (buf),
1089                                       (struct sockaddr *) &un, &addrlen);
1090
1091   if ((GNUNET_SYSERR == ret) && ((errno == EAGAIN) || (errno == ENOBUFS)))
1092     return;
1093
1094   if (ret == GNUNET_SYSERR)
1095   {
1096     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "recvfrom");
1097     return;
1098   }
1099   else
1100   {
1101     LOG (GNUNET_ERROR_TYPE_DEBUG,
1102          "Read %d bytes from socket %s\n",
1103          (int) ret,
1104          un.sun_path);
1105   }
1106
1107   GNUNET_assert (AF_UNIX == (un.sun_family));
1108   is_abstract = GNUNET_NO;
1109   if ('\0' == un.sun_path[0])
1110   {
1111     un.sun_path[0] = '@';
1112     is_abstract = GNUNET_YES;
1113   }
1114
1115   ua_len = sizeof (struct UnixAddress) + strlen (un.sun_path) + 1;
1116   ua = GNUNET_malloc (ua_len);
1117   ua->addrlen = htonl (strlen (&un.sun_path[0]) +1);
1118   memcpy (&ua[1], &un.sun_path[0], strlen (un.sun_path) + 1);
1119   if (is_abstract)
1120     ua->options = htonl(UNIX_OPTIONS_USE_ABSTRACT_SOCKETS);
1121   else
1122     ua->options = htonl(UNIX_OPTIONS_NONE);
1123
1124   msg = (struct UNIXMessage *) buf;
1125   csize = ntohs (msg->header.size);
1126   if ((csize < sizeof (struct UNIXMessage)) || (csize > ret))
1127   {
1128     GNUNET_break_op (0);
1129     GNUNET_free (ua);
1130     return;
1131   }
1132   msgbuf = (char *) &msg[1];
1133   memcpy (&sender, &msg->sender, sizeof (struct GNUNET_PeerIdentity));
1134   offset = 0;
1135   tsize = csize - sizeof (struct UNIXMessage);
1136   while (offset + sizeof (struct GNUNET_MessageHeader) <= tsize)
1137   {
1138     currhdr = (struct GNUNET_MessageHeader *) &msgbuf[offset];
1139     csize = ntohs (currhdr->size);
1140     if ((csize < sizeof (struct GNUNET_MessageHeader)) ||
1141         (csize > tsize - offset))
1142     {
1143       GNUNET_break_op (0);
1144       break;
1145     }
1146     unix_demultiplexer (plugin, &sender, currhdr, ua, ua_len);
1147     offset += csize;
1148   }
1149   GNUNET_free (ua);
1150 }
1151
1152
1153 /**
1154  * Write to UNIX domain socket (it is ready).
1155  *
1156  * @param plugin the plugin
1157  */
1158 static void
1159 unix_plugin_select_write (struct Plugin *plugin)
1160 {
1161   int sent = 0;
1162   struct UNIXMessageWrapper * msgw;
1163
1164   while (NULL != (msgw = plugin->msg_tail))
1165   {
1166     if (GNUNET_TIME_absolute_get_remaining (msgw->timeout).rel_value_us > 0)
1167       break; /* Message is ready for sending */
1168     /* Message has a timeout */
1169     LOG (GNUNET_ERROR_TYPE_DEBUG,
1170          "Timeout for message with %u bytes \n",
1171          (unsigned int) msgw->msgsize);
1172     GNUNET_CONTAINER_DLL_remove (plugin->msg_head, plugin->msg_tail, msgw);
1173     plugin->bytes_in_queue -= msgw->msgsize;
1174     GNUNET_STATISTICS_set (plugin->env->stats,
1175                            "# bytes currently in UNIX buffers",
1176                            plugin->bytes_in_queue, GNUNET_NO);
1177     GNUNET_STATISTICS_update (plugin->env->stats,
1178                               "# UNIX bytes discarded",
1179                               msgw->msgsize,
1180                               GNUNET_NO);
1181     if (NULL != msgw->cont)
1182       msgw->cont (msgw->cont_cls,
1183                   &msgw->session->target,
1184                   GNUNET_SYSERR,
1185                   msgw->payload,
1186                   0);
1187     GNUNET_free (msgw->msg);
1188     GNUNET_free (msgw);
1189   }
1190   if (NULL == msgw)
1191     return; /* Nothing to send at the moment */
1192
1193   sent = unix_real_send (plugin,
1194                          plugin->unix_sock.desc,
1195                          &msgw->session->target,
1196                          (const char *) msgw->msg,
1197                          msgw->msgsize,
1198                          msgw->priority,
1199                          msgw->timeout,
1200                          msgw->session->address->address,
1201                          msgw->session->address->address_length,
1202                          msgw->payload,
1203                          msgw->cont, msgw->cont_cls);
1204
1205   if (RETRY == sent)
1206   {
1207     GNUNET_STATISTICS_update (plugin->env->stats,
1208                               "# UNIX retry attempts",
1209                               1, GNUNET_NO);
1210     return;
1211   }
1212   if (GNUNET_SYSERR == sent)
1213   {
1214     /* failed and no retry */
1215     if (NULL != msgw->cont)
1216       msgw->cont (msgw->cont_cls, &msgw->session->target, GNUNET_SYSERR, msgw->payload, 0);
1217
1218     GNUNET_CONTAINER_DLL_remove(plugin->msg_head, plugin->msg_tail, msgw);
1219
1220     GNUNET_assert (plugin->bytes_in_queue >= msgw->msgsize);
1221     plugin->bytes_in_queue -= msgw->msgsize;
1222     GNUNET_STATISTICS_set (plugin->env->stats,
1223                            "# bytes currently in UNIX buffers",
1224                            plugin->bytes_in_queue, GNUNET_NO);
1225     GNUNET_STATISTICS_update (plugin->env->stats,
1226                               "# UNIX bytes discarded",
1227                               msgw->msgsize,
1228                               GNUNET_NO);
1229
1230     GNUNET_free (msgw->msg);
1231     GNUNET_free (msgw);
1232     return;
1233   }
1234   /* successfully sent bytes */
1235   GNUNET_break (sent > 0);
1236   GNUNET_CONTAINER_DLL_remove (plugin->msg_head,
1237                                plugin->msg_tail,
1238                                msgw);
1239   GNUNET_assert (plugin->bytes_in_queue >= msgw->msgsize);
1240   plugin->bytes_in_queue -= msgw->msgsize;
1241   GNUNET_STATISTICS_set (plugin->env->stats,
1242                          "# bytes currently in UNIX buffers",
1243                          plugin->bytes_in_queue,
1244                          GNUNET_NO);
1245   GNUNET_STATISTICS_update (plugin->env->stats,
1246                             "# bytes transmitted via UNIX",
1247                             msgw->msgsize,
1248                             GNUNET_NO);
1249   if (NULL != msgw->cont)
1250     msgw->cont (msgw->cont_cls, &msgw->session->target,
1251                 GNUNET_OK,
1252                 msgw->payload,
1253                 msgw->msgsize);
1254   GNUNET_free (msgw->msg);
1255   GNUNET_free (msgw);
1256 }
1257
1258
1259 /**
1260  * We have been notified that our writeset has something to read.  We don't
1261  * know which socket needs to be read, so we have to check each one
1262  * Then reschedule this function to be called again once more is available.
1263  *
1264  * @param cls the plugin handle
1265  * @param tc the scheduling context (for rescheduling this function again)
1266  */
1267 static void
1268 unix_plugin_select (void *cls,
1269                     const struct GNUNET_SCHEDULER_TaskContext *tc)
1270 {
1271   struct Plugin *plugin = cls;
1272
1273   plugin->select_task = GNUNET_SCHEDULER_NO_TASK;
1274   if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
1275     return;
1276
1277   if ((tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY) != 0)
1278   {
1279     /* Ready to send data */
1280     GNUNET_assert (GNUNET_NETWORK_fdset_isset
1281                    (tc->write_ready, plugin->unix_sock.desc));
1282     if (NULL != plugin->msg_head)
1283       unix_plugin_select_write (plugin);
1284   }
1285
1286   if ((tc->reason & GNUNET_SCHEDULER_REASON_READ_READY) != 0)
1287   {
1288     /* Ready to receive data */
1289     GNUNET_assert (GNUNET_NETWORK_fdset_isset
1290                    (tc->read_ready, plugin->unix_sock.desc));
1291     unix_plugin_select_read (plugin);
1292   }
1293   reschedule_select (plugin);
1294 }
1295
1296
1297 /**
1298  * Create a slew of UNIX sockets.  If possible, use IPv6 and IPv4.
1299  *
1300  * @param cls closure for server start, should be a struct Plugin *
1301  * @return number of sockets created or #GNUNET_SYSERR on error
1302  */
1303 static int
1304 unix_transport_server_start (void *cls)
1305 {
1306   struct Plugin *plugin = cls;
1307   struct sockaddr_un *un;
1308   socklen_t un_len;
1309
1310   un = unix_address_to_sockaddr (plugin->unix_socket_path,
1311                                  &un_len);
1312   if (GNUNET_YES == plugin->abstract)
1313   {
1314     plugin->unix_socket_path[0] = '@';
1315     un->sun_path[0] = '\0';
1316   }
1317   plugin->ats_network = plugin->env->get_address_type (plugin->env->cls, (const struct sockaddr *) un, un_len);
1318   plugin->unix_sock.desc =
1319       GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_DGRAM, 0);
1320   if (NULL == plugin->unix_sock.desc)
1321   {
1322     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket");
1323     return GNUNET_SYSERR;
1324   }
1325   if ('\0' != un->sun_path[0])
1326   {
1327     if (GNUNET_OK != GNUNET_DISK_directory_create_for_file (un->sun_path))
1328     {
1329       LOG (GNUNET_ERROR_TYPE_ERROR, _("Cannot create path to `%s'\n"),
1330           un->sun_path);
1331       GNUNET_NETWORK_socket_close (plugin->unix_sock.desc);
1332       plugin->unix_sock.desc = NULL;
1333       GNUNET_free (un);
1334       return GNUNET_SYSERR;
1335     }
1336   }
1337   if (GNUNET_OK !=
1338       GNUNET_NETWORK_socket_bind (plugin->unix_sock.desc, (const struct sockaddr *)  un, un_len))
1339   {
1340     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "bind");
1341     GNUNET_NETWORK_socket_close (plugin->unix_sock.desc);
1342     plugin->unix_sock.desc = NULL;
1343     GNUNET_free (un);
1344     return GNUNET_SYSERR;
1345   }
1346   LOG (GNUNET_ERROR_TYPE_DEBUG, "Bound to `%s'\n", plugin->unix_socket_path);
1347   plugin->rs = GNUNET_NETWORK_fdset_create ();
1348   plugin->ws = GNUNET_NETWORK_fdset_create ();
1349   GNUNET_NETWORK_fdset_zero (plugin->rs);
1350   GNUNET_NETWORK_fdset_zero (plugin->ws);
1351   GNUNET_NETWORK_fdset_set (plugin->rs, plugin->unix_sock.desc);
1352   GNUNET_NETWORK_fdset_set (plugin->ws, plugin->unix_sock.desc);
1353
1354   reschedule_select (plugin);
1355   GNUNET_free (un);
1356   return 1;
1357 }
1358
1359
1360 /**
1361  * Function that will be called to check if a binary address for this
1362  * plugin is well-formed and corresponds to an address for THIS peer
1363  * (as per our configuration).  Naturally, if absolutely necessary,
1364  * plugins can be a bit conservative in their answer, but in general
1365  * plugins should make sure that the address does not redirect
1366  * traffic to a 3rd party that might try to man-in-the-middle our
1367  * traffic.
1368  *
1369  * @param cls closure, should be our handle to the Plugin
1370  * @param addr pointer to the address
1371  * @param addrlen length of addr
1372  * @return GNUNET_OK if this is a plausible address for this peer
1373  *         and transport, GNUNET_SYSERR if not
1374  *
1375  */
1376 static int
1377 unix_check_address (void *cls, const void *addr, size_t addrlen)
1378 {
1379   struct Plugin* plugin = cls;
1380   struct UnixAddress *ua = (struct UnixAddress *) addr;
1381   char *addrstr;
1382   size_t addr_str_len;
1383
1384   if ((NULL == addr) || (0 == addrlen) || (sizeof (struct UnixAddress) > addrlen))
1385   {
1386     GNUNET_break (0);
1387     return GNUNET_SYSERR;
1388   }
1389         addrstr = (char *) &ua[1];
1390         addr_str_len = ntohl (ua->addrlen);
1391   if ('\0' != addrstr[addr_str_len - 1])
1392   {
1393     GNUNET_break (0);
1394     return GNUNET_SYSERR;
1395   }
1396   if (strlen (addrstr) + 1 != addr_str_len)
1397   {
1398     GNUNET_break (0);
1399     return GNUNET_SYSERR;
1400   }
1401
1402   if (0 == strcmp (plugin->unix_socket_path, addrstr))
1403         return GNUNET_OK;
1404   return GNUNET_SYSERR;
1405 }
1406
1407
1408 /**
1409  * Convert the transports address to a nice, human-readable
1410  * format.
1411  *
1412  * @param cls closure
1413  * @param type name of the transport that generated the address
1414  * @param addr one of the addresses of the host, NULL for the last address
1415  *        the specific address format depends on the transport
1416  * @param addrlen length of the @a addr
1417  * @param numeric should (IP) addresses be displayed in numeric form?
1418  * @param timeout after how long should we give up?
1419  * @param asc function to call on each string
1420  * @param asc_cls closure for @a asc
1421  */
1422 static void
1423 unix_plugin_address_pretty_printer (void *cls, const char *type,
1424                                     const void *addr, size_t addrlen,
1425                                     int numeric,
1426                                     struct GNUNET_TIME_Relative timeout,
1427                                     GNUNET_TRANSPORT_AddressStringCallback asc,
1428                                     void *asc_cls)
1429 {
1430   const char *ret;
1431
1432   if ( (NULL != addr) && (addrlen > 0))
1433     ret = unix_address_to_string (NULL,
1434                                   addr,
1435                                   addrlen);
1436   else
1437     ret = NULL;
1438   asc (asc_cls,
1439        ret,
1440        (NULL == ret) ? GNUNET_SYSERR : GNUNET_OK);
1441   asc (asc_cls, NULL, GNUNET_OK);
1442 }
1443
1444
1445 /**
1446  * Function called to convert a string address to
1447  * a binary address.
1448  *
1449  * @param cls closure (`struct Plugin *`)
1450  * @param addr string address
1451  * @param addrlen length of the @a addr (strlen(addr) + '\0')
1452  * @param buf location to store the buffer
1453  *        If the function returns #GNUNET_SYSERR, its contents are undefined.
1454  * @param added length of created address
1455  * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
1456  */
1457 static int
1458 unix_string_to_address (void *cls,
1459                         const char *addr, uint16_t addrlen,
1460                         void **buf, size_t *added)
1461 {
1462   struct UnixAddress *ua;
1463   char *address;
1464   char *plugin;
1465   char *optionstr;
1466   uint32_t options;
1467   size_t ua_size;
1468
1469   /* Format unix.options.address */
1470   address = NULL;
1471   plugin = NULL;
1472   optionstr = NULL;
1473
1474   if ((NULL == addr) || (addrlen == 0))
1475   {
1476     GNUNET_break (0);
1477     return GNUNET_SYSERR;
1478   }
1479   if ('\0' != addr[addrlen - 1])
1480   {
1481     GNUNET_break (0);
1482     return GNUNET_SYSERR;
1483   }
1484   if (strlen (addr) != addrlen - 1)
1485   {
1486     GNUNET_break (0);
1487     return GNUNET_SYSERR;
1488   }
1489   plugin = GNUNET_strdup (addr);
1490   optionstr = strchr (plugin, '.');
1491   if (NULL == optionstr)
1492   {
1493     GNUNET_break (0);
1494     GNUNET_free (plugin);
1495     return GNUNET_SYSERR;
1496   }
1497   optionstr[0] = '\0';
1498   optionstr++;
1499   options = atol (optionstr);
1500   address = strchr (optionstr, '.');
1501   if (NULL == address)
1502   {
1503     GNUNET_break (0);
1504     GNUNET_free (plugin);
1505     return GNUNET_SYSERR;
1506   }
1507   address[0] = '\0';
1508   address++;
1509   if (0 != strcmp(plugin, PLUGIN_NAME))
1510   {
1511     GNUNET_break (0);
1512     GNUNET_free (plugin);
1513     return GNUNET_SYSERR;
1514   }
1515
1516   ua_size = sizeof (struct UnixAddress) + strlen (address) + 1;
1517   ua = GNUNET_malloc (ua_size);
1518   ua->options = htonl (options);
1519   ua->addrlen = htonl (strlen (address) + 1);
1520   memcpy (&ua[1], address, strlen (address) + 1);
1521   GNUNET_free (plugin);
1522
1523   (*buf) = ua;
1524   (*added) = ua_size;
1525   return GNUNET_OK;
1526 }
1527
1528
1529 /**
1530  * Notify transport service about address
1531  *
1532  * @param cls the plugin
1533  * @param tc unused
1534  */
1535 static void
1536 address_notification (void *cls,
1537                       const struct GNUNET_SCHEDULER_TaskContext *tc)
1538 {
1539   struct Plugin *plugin = cls;
1540   struct GNUNET_HELLO_Address *address;
1541   size_t len;
1542   struct UnixAddress *ua;
1543   char *unix_path;
1544
1545   len = sizeof (struct UnixAddress) + strlen (plugin->unix_socket_path) + 1;
1546   ua = GNUNET_malloc (len);
1547   ua->options = htonl (plugin->myoptions);
1548   ua->addrlen = htonl(strlen (plugin->unix_socket_path) + 1);
1549   unix_path = (char *) &ua[1];
1550   memcpy (unix_path, plugin->unix_socket_path, strlen (plugin->unix_socket_path) + 1);
1551
1552   plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
1553   address = GNUNET_HELLO_address_allocate (plugin->env->my_identity,
1554       PLUGIN_NAME, ua, len, GNUNET_HELLO_ADDRESS_INFO_NONE);
1555
1556   plugin->env->notify_address (plugin->env->cls, GNUNET_YES, address);
1557   GNUNET_free (ua);
1558   GNUNET_free (address);
1559 }
1560
1561
1562 /**
1563  * Increment session timeout due to activity
1564  *
1565  * @param s session for which the timeout should be rescheduled
1566  */
1567 static void
1568 reschedule_session_timeout (struct Session *s)
1569 {
1570   GNUNET_assert (NULL != s);
1571   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != s->timeout_task);
1572   GNUNET_SCHEDULER_cancel (s->timeout_task);
1573   s->timeout_task =  GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1574                                                    &session_timeout,
1575                                                    s);
1576   LOG (GNUNET_ERROR_TYPE_DEBUG,
1577        "Timeout rescheduled for session %p set to %s\n",
1578        s,
1579        GNUNET_STRINGS_relative_time_to_string (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1580                                                GNUNET_YES));
1581 }
1582
1583
1584 /**
1585  * Function called on sessions to disconnect
1586  *
1587  * @param cls the plugin
1588  * @param key peer identity (unused)
1589  * @param value the `struct Session *` to disconnect
1590  * @return #GNUNET_YES (always, continue to iterate)
1591  */
1592 static int
1593 get_session_delete_it (void *cls,
1594                        const struct GNUNET_PeerIdentity *key,
1595                        void *value)
1596 {
1597   struct Plugin *plugin = cls;
1598   struct Session *s = value;
1599
1600   unix_session_disconnect (plugin, s);
1601   return GNUNET_YES;
1602 }
1603
1604
1605 /**
1606  * Disconnect from a remote node.  Clean up session if we have one for this peer
1607  *
1608  * @param cls closure for this call (should be handle to Plugin)
1609  * @param target the peeridentity of the peer to disconnect
1610  * @return #GNUNET_OK on success, #GNUNET_SYSERR if the operation failed
1611  */
1612 static void
1613 unix_peer_disconnect (void *cls,
1614                       const struct GNUNET_PeerIdentity *target)
1615 {
1616   struct Plugin *plugin = cls;
1617
1618   GNUNET_assert (plugin != NULL);
1619   GNUNET_CONTAINER_multipeermap_get_multiple (plugin->session_map,
1620                                               target,
1621                                               &get_session_delete_it, plugin);
1622 }
1623
1624
1625 /**
1626  * The exported method.  Initializes the plugin and returns a
1627  * struct with the callbacks.
1628  *
1629  * @param cls the plugin's execution environment
1630  * @return NULL on error, plugin functions otherwise
1631  */
1632 void *
1633 libgnunet_plugin_transport_unix_init (void *cls)
1634 {
1635   struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
1636   struct GNUNET_TRANSPORT_PluginFunctions *api;
1637   struct Plugin *plugin;
1638   int sockets_created;
1639
1640   if (NULL == env->receive)
1641   {
1642     /* run in 'stub' mode (i.e. as part of gnunet-peerinfo), don't fully
1643        initialze the plugin or the API */
1644     api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
1645     api->cls = NULL;
1646     api->address_pretty_printer = &unix_plugin_address_pretty_printer;
1647     api->address_to_string = &unix_address_to_string;
1648     api->string_to_address = &unix_string_to_address;
1649     return api;
1650   }
1651
1652   plugin = GNUNET_new (struct Plugin);
1653   if (GNUNET_OK !=
1654       GNUNET_CONFIGURATION_get_value_filename(env->cfg, "transport-unix", "UNIXPATH",
1655                                              &plugin->unix_socket_path))
1656   {
1657     LOG (GNUNET_ERROR_TYPE_ERROR,
1658          _("No UNIXPATH given in configuration!\n"));
1659     GNUNET_free (plugin);
1660     return NULL;
1661   }
1662
1663   plugin->env = env;
1664
1665   /* Initialize my flags */
1666 #ifdef LINUX
1667     plugin->abstract = GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg,
1668         "testing", "USE_ABSTRACT_SOCKETS");
1669 #endif
1670   plugin->myoptions = UNIX_OPTIONS_NONE;
1671   if (GNUNET_YES == plugin->abstract)
1672   {
1673     plugin->myoptions = UNIX_OPTIONS_USE_ABSTRACT_SOCKETS;
1674   }
1675
1676   api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
1677   api->cls = plugin;
1678
1679   api->get_session = &unix_plugin_get_session;
1680   api->send = &unix_plugin_send;
1681   api->disconnect_peer = &unix_peer_disconnect;
1682   api->disconnect_session = &unix_session_disconnect;
1683   api->query_keepalive_factor = &unix_query_keepalive_factor;
1684   api->address_pretty_printer = &unix_plugin_address_pretty_printer;
1685   api->address_to_string = &unix_address_to_string;
1686   api->check_address = &unix_check_address;
1687   api->string_to_address = &unix_string_to_address;
1688   api->get_network = &unix_get_network;
1689   api->update_session_timeout = &unix_plugin_update_session_timeout;
1690   sockets_created = unix_transport_server_start (plugin);
1691   if ((0 == sockets_created) || (GNUNET_SYSERR == sockets_created))
1692   {
1693     LOG (GNUNET_ERROR_TYPE_WARNING,
1694          _("Failed to open UNIX listen socket\n"));
1695     GNUNET_free (api);
1696     GNUNET_free (plugin->unix_socket_path);
1697     GNUNET_free (plugin);
1698     return NULL;
1699   }
1700   plugin->session_map = GNUNET_CONTAINER_multipeermap_create (10, GNUNET_NO);
1701   plugin->address_update_task = GNUNET_SCHEDULER_add_now (&address_notification, plugin);
1702   return api;
1703 }
1704
1705
1706 /**
1707  * Shutdown the plugin.
1708  *
1709  * @param cls the plugin API returned from the initialization function
1710  * @return NULL (always)
1711  */
1712 void *
1713 libgnunet_plugin_transport_unix_done (void *cls)
1714 {
1715   struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
1716   struct Plugin *plugin = api->cls;
1717   struct GNUNET_HELLO_Address *address;
1718   struct UNIXMessageWrapper * msgw;
1719   struct UnixAddress *ua;
1720   size_t len;
1721
1722   if (NULL == plugin)
1723   {
1724     GNUNET_free (api);
1725     return NULL;
1726   }
1727
1728   len = sizeof (struct UnixAddress) + strlen (plugin->unix_socket_path) + 1;
1729   ua = GNUNET_malloc (len);
1730   ua->options = htonl (plugin->myoptions);
1731   ua->addrlen = htonl(strlen (plugin->unix_socket_path) + 1);
1732   memcpy (&ua[1], plugin->unix_socket_path, strlen (plugin->unix_socket_path) + 1);
1733   address = GNUNET_HELLO_address_allocate (plugin->env->my_identity,
1734       PLUGIN_NAME, ua, len, GNUNET_HELLO_ADDRESS_INFO_NONE);
1735   plugin->env->notify_address (plugin->env->cls, GNUNET_NO, address);
1736
1737   GNUNET_free (address);
1738   GNUNET_free (ua);
1739
1740   while (NULL != (msgw = plugin->msg_head))
1741   {
1742     GNUNET_CONTAINER_DLL_remove (plugin->msg_head, plugin->msg_tail, msgw);
1743     if (msgw->cont != NULL)
1744       msgw->cont (msgw->cont_cls,  &msgw->session->target, GNUNET_SYSERR,
1745                   msgw->payload, 0);
1746     GNUNET_free (msgw->msg);
1747     GNUNET_free (msgw);
1748   }
1749
1750   if (GNUNET_SCHEDULER_NO_TASK != plugin->select_task)
1751   {
1752     GNUNET_SCHEDULER_cancel (plugin->select_task);
1753     plugin->select_task = GNUNET_SCHEDULER_NO_TASK;
1754   }
1755   if (GNUNET_SCHEDULER_NO_TASK != plugin->address_update_task)
1756   {
1757     GNUNET_SCHEDULER_cancel (plugin->address_update_task);
1758     plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
1759   }
1760   if (NULL != plugin->unix_sock.desc)
1761   {
1762     GNUNET_break (GNUNET_OK ==
1763                   GNUNET_NETWORK_socket_close (plugin->unix_sock.desc));
1764     plugin->unix_sock.desc = NULL;
1765     plugin->with_ws = GNUNET_NO;
1766   }
1767   GNUNET_CONTAINER_multipeermap_iterate (plugin->session_map,
1768                                          &get_session_delete_it, plugin);
1769   GNUNET_CONTAINER_multipeermap_destroy (plugin->session_map);
1770   if (NULL != plugin->rs)
1771     GNUNET_NETWORK_fdset_destroy (plugin->rs);
1772   if (NULL != plugin->ws)
1773     GNUNET_NETWORK_fdset_destroy (plugin->ws);
1774   GNUNET_free (plugin->unix_socket_path);
1775   GNUNET_free (plugin);
1776   GNUNET_free (api);
1777   return NULL;
1778 }
1779
1780 /* end of plugin_transport_unix.c */