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