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