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