change
[oweals/gnunet.git] / src / transport / plugin_transport_unix.c
1 /*
2      This file is part of GNUnet
3      (C) 2010 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
30 #include "platform.h"
31 #include "gnunet_hello_lib.h"
32 #include "gnunet_connection_lib.h"
33 #include "gnunet_container_lib.h"
34 #include "gnunet_os_lib.h"
35 #include "gnunet_peerinfo_service.h"
36 #include "gnunet_protocols.h"
37 #include "gnunet_resolver_service.h"
38 #include "gnunet_server_lib.h"
39 #include "gnunet_signatures.h"
40 #include "gnunet_statistics_service.h"
41 #include "gnunet_transport_service.h"
42 #include "gnunet_transport_plugin.h"
43 #include "transport.h"
44
45 #define MAX_PROBES 20
46
47 #define LOG(kind,...) GNUNET_log_from (kind, "transport-unix",__VA_ARGS__)
48
49 /*
50  * Transport cost to peer, always 1 for UNIX (direct connection)
51  */
52 #define UNIX_DIRECT_DISTANCE 1
53
54 #define DEFAULT_NAT_PORT 0
55
56 /**
57  * How long until we give up on transmitting the welcome message?
58  */
59 #define HOSTNAME_RESOLVE_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
60
61 /**
62  * Starting port for listening and sending, eventually a config value
63  */
64 #define UNIX_NAT_DEFAULT_PORT 22086
65
66 GNUNET_NETWORK_STRUCT_BEGIN
67
68 /**
69  * UNIX Message-Packet header.
70  */
71 struct UNIXMessage
72 {
73   /**
74    * Message header.
75    */
76   struct GNUNET_MessageHeader header;
77
78   /**
79    * What is the identity of the sender (GNUNET_hash of public key)
80    */
81   struct GNUNET_PeerIdentity sender;
82
83 };
84
85 struct Session
86 {
87   struct GNUNET_PeerIdentity target;
88
89   void *addr;
90   size_t addrlen;
91
92   /**
93    * Session timeout task
94    */
95   GNUNET_SCHEDULER_TaskIdentifier timeout_task;
96
97   struct Plugin * plugin;
98 };
99
100 struct UNIXMessageWrapper
101 {
102   struct UNIXMessageWrapper *next;
103   struct UNIXMessageWrapper *prev;
104
105   struct UNIXMessage * msg;
106   size_t msgsize;
107   size_t payload;
108
109   struct GNUNET_TIME_Relative timeout;
110   unsigned int priority;
111
112   struct Session *session;
113   GNUNET_TRANSPORT_TransmitContinuation cont;
114   void *cont_cls;
115 };
116
117 /* Forward definition */
118 struct Plugin;
119
120
121 /**
122  * UNIX NAT "Session"
123  */
124 struct PeerSession
125 {
126
127   /**
128    * Stored in a linked list.
129    */
130   struct PeerSession *next;
131
132   /**
133    * Pointer to the global plugin struct.
134    */
135   struct Plugin *plugin;
136
137   /**
138    * To whom are we talking to (set to our identity
139    * if we are still waiting for the welcome message)
140    */
141   struct GNUNET_PeerIdentity target;
142
143   /**
144    * Address of the other peer (either based on our 'connect'
145    * call or on our 'accept' call).
146    */
147   void *connect_addr;
148
149   /**
150    * Length of connect_addr.
151    */
152   size_t connect_alen;
153
154   /**
155    * Are we still expecting the welcome message? (GNUNET_YES/GNUNET_NO)
156    */
157   int expecting_welcome;
158
159   /**
160    * From which socket do we need to send to this peer?
161    */
162   struct GNUNET_NETWORK_Handle *sock;
163
164   /*
165    * Queue of messages for this peer, in the case that
166    * we have to await a connection...
167    */
168   struct MessageQueue *messages;
169
170 };
171
172 /**
173  * Information we keep for each of our listen sockets.
174  */
175 struct UNIX_Sock_Info
176 {
177   /**
178    * The network handle
179    */
180   struct GNUNET_NETWORK_Handle *desc;
181
182   /**
183    * The port we bound to
184    */
185   uint16_t port;
186 };
187
188
189 /**
190  * Encapsulation of all of the state of the plugin.
191  */
192 struct Plugin
193 {
194   /**
195    * Our environment.
196    */
197   struct GNUNET_TRANSPORT_PluginEnvironment *env;
198
199   /**
200    * Sessions
201    */
202   struct GNUNET_CONTAINER_MultiHashMap *session_map;
203
204   /**
205    * ID of task used to update our addresses when one expires.
206    */
207   GNUNET_SCHEDULER_TaskIdentifier address_update_task;
208
209   /**
210    * ID of select task
211    */
212   GNUNET_SCHEDULER_TaskIdentifier select_task;
213
214   /**
215    * Integer to append to unix domain socket.
216    */
217   uint16_t port;
218
219   /**
220    * FD Read set
221    */
222   struct GNUNET_NETWORK_FDSet *rs;
223
224   /**
225    * FD Write set
226    */
227   struct GNUNET_NETWORK_FDSet *ws;
228
229   int with_ws;
230
231   /**
232    * socket that we transmit all data with
233    */
234   struct UNIX_Sock_Info unix_sock;
235
236   /**
237    * Path of our unix domain socket (/tmp/unix-plugin-PORT)
238    */
239   char *unix_socket_path;
240
241   struct UNIXMessageWrapper *msg_head;
242   struct UNIXMessageWrapper *msg_tail;
243
244   /**
245    * ATS network
246    */
247   struct GNUNET_ATS_Information ats_network;
248
249   unsigned int bytes_in_queue;
250   unsigned int bytes_in_sent;
251   unsigned int bytes_in_recv;
252   unsigned int bytes_discarded;
253 };
254
255 /**
256  * Start session timeout
257  */
258 static void
259 start_session_timeout (struct Session *s);
260
261 /**
262  * Increment session timeout due to activity
263  */
264 static void
265 reschedule_session_timeout (struct Session *s);
266
267 /**
268  * Cancel timeout
269  */
270 static void
271 stop_session_timeout (struct Session *s);
272
273
274 static void
275 unix_plugin_select (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
276
277
278 static void
279 reschedule_select (struct Plugin * plugin)
280 {
281
282   if (plugin->select_task != GNUNET_SCHEDULER_NO_TASK)
283   {
284     GNUNET_SCHEDULER_cancel (plugin->select_task);
285     plugin->select_task = GNUNET_SCHEDULER_NO_TASK;
286   }
287
288   if (NULL != plugin->msg_head)
289   {
290     plugin->select_task =
291       GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
292                                    GNUNET_TIME_UNIT_FOREVER_REL,
293                                    plugin->rs,
294                                    plugin->ws,
295                                    &unix_plugin_select, plugin);
296     plugin->with_ws = GNUNET_YES;
297   }
298   else
299   {
300     plugin->select_task =
301       GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
302                                    GNUNET_TIME_UNIT_FOREVER_REL,
303                                    plugin->rs,
304                                    NULL,
305                                    &unix_plugin_select, plugin);
306     plugin->with_ws = GNUNET_NO;
307   }
308 }
309
310 struct LookupCtx
311 {
312   struct Session *s;
313   const struct sockaddr_un *addr;
314 };
315
316 int lookup_session_it (void *cls,
317                        const struct GNUNET_HashCode * key,
318                        void *value)
319 {
320   struct LookupCtx *lctx = cls;
321   struct Session *t = value;
322
323   if (0 == strcmp (t->addr, lctx->addr->sun_path))
324   {
325     lctx->s = t;
326     return GNUNET_NO;
327   }
328   return GNUNET_YES;
329 }
330
331
332 static struct Session *
333 lookup_session (struct Plugin *plugin, struct GNUNET_PeerIdentity *sender, const struct sockaddr_un *addr)
334 {
335   struct LookupCtx lctx;
336
337   GNUNET_assert (NULL != plugin);
338   GNUNET_assert (NULL != sender);
339   GNUNET_assert (NULL != addr);
340
341   lctx.s = NULL;
342   lctx.addr = addr;
343
344   GNUNET_CONTAINER_multihashmap_get_multiple (plugin->session_map, &sender->hashPubKey, &lookup_session_it, &lctx);
345
346   return lctx.s;
347 }
348
349 /**
350  * Functions with this signature are called whenever we need
351  * to close a session due to a disconnect or failure to
352  * establish a connection.
353  *
354  * @param s session to close down
355  */
356 static void
357 disconnect_session (struct Session *s)
358 {
359   struct UNIXMessageWrapper *msgw;
360   struct UNIXMessageWrapper *next;
361   struct Plugin * plugin = s->plugin;
362   int removed;
363   GNUNET_assert (plugin != NULL);
364   GNUNET_assert (s != NULL);
365
366   LOG (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting session for peer `%s' `%s' \n", GNUNET_i2s (&s->target), s->addr);
367   stop_session_timeout (s);
368   plugin->env->session_end (plugin->env->cls, &s->target, s);
369
370   msgw = plugin->msg_head;
371   removed = GNUNET_NO;
372   next = plugin->msg_head;
373   while (NULL != next)
374   {
375     msgw = next;
376     next = msgw->next;
377     if (msgw->session != s)
378       continue;
379     GNUNET_CONTAINER_DLL_remove (plugin->msg_head, plugin->msg_tail, msgw);
380     if (NULL != msgw->cont)
381       msgw->cont (msgw->cont_cls,  &msgw->session->target, GNUNET_SYSERR,
382                   msgw->payload, 0);
383     GNUNET_free (msgw->msg);
384     GNUNET_free (msgw);
385     removed = GNUNET_YES;    
386   }
387   if ((GNUNET_YES == removed) && (NULL == plugin->msg_head))
388     reschedule_select (plugin);
389
390   GNUNET_assert (GNUNET_YES ==
391                  GNUNET_CONTAINER_multihashmap_remove(plugin->session_map, &s->target.hashPubKey, s));
392
393   GNUNET_STATISTICS_set(plugin->env->stats,
394                         "# UNIX sessions active",
395                         GNUNET_CONTAINER_multihashmap_size(plugin->session_map),
396                         GNUNET_NO);
397
398   GNUNET_free (s);
399 }
400
401 static int
402 get_session_delete_it (void *cls, const struct GNUNET_HashCode * key, void *value)
403 {
404   struct Session *s = value;
405   disconnect_session (s);
406   return GNUNET_YES;
407 }
408
409
410 /**
411  * Disconnect from a remote node.  Clean up session if we have one for this peer
412  *
413  * @param cls closure for this call (should be handle to Plugin)
414  * @param target the peeridentity of the peer to disconnect
415  * @return GNUNET_OK on success, GNUNET_SYSERR if the operation failed
416  */
417 static void
418 unix_disconnect (void *cls, const struct GNUNET_PeerIdentity *target)
419 {
420   struct Plugin *plugin = cls;
421   GNUNET_assert (plugin != NULL);
422
423   GNUNET_CONTAINER_multihashmap_get_multiple (plugin->session_map, &target->hashPubKey, &get_session_delete_it, plugin);
424   return;
425 }
426
427 /**
428  * Shutdown the server process (stop receiving inbound traffic). Maybe
429  * restarted later!
430  *
431  * @param cls Handle to the plugin for this transport
432  *
433  * @return returns the number of sockets successfully closed,
434  *         should equal the number of sockets successfully opened
435  */
436 static int
437 unix_transport_server_stop (void *cls)
438 {
439   struct Plugin *plugin = cls;
440   struct UNIXMessageWrapper * msgw;
441
442   while (NULL != (msgw = plugin->msg_head))
443   {
444     GNUNET_CONTAINER_DLL_remove (plugin->msg_head, plugin->msg_tail, msgw);
445     if (msgw->cont != NULL)
446       msgw->cont (msgw->cont_cls,  &msgw->session->target, GNUNET_SYSERR,
447                   msgw->payload, 0);
448     GNUNET_free (msgw->msg);
449     GNUNET_free (msgw);
450   }
451
452   if (plugin->select_task != GNUNET_SCHEDULER_NO_TASK)
453   {
454     GNUNET_SCHEDULER_cancel (plugin->select_task);
455     plugin->select_task = GNUNET_SCHEDULER_NO_TASK;
456   }
457
458   if (NULL != plugin->unix_sock.desc)
459   {
460     GNUNET_break (GNUNET_OK ==
461                   GNUNET_NETWORK_socket_close (plugin->unix_sock.desc));
462     plugin->unix_sock.desc = NULL;
463     plugin->with_ws = GNUNET_NO;
464   }
465   return GNUNET_OK;
466 }
467
468
469 /**
470  * Actually send out the message, assume we've got the address and
471  * send_handle squared away!
472  *
473  * @param cls closure
474  * @param send_handle which handle to send message on
475  * @param target who should receive this message (ignored by UNIX)
476  * @param msgbuf one or more GNUNET_MessageHeader(s) strung together
477  * @param msgbuf_size the size of the msgbuf to send
478  * @param priority how important is the message (ignored by UNIX)
479  * @param timeout when should we time out (give up) if we can not transmit?
480  * @param addr the addr to send the message to, needs to be a sockaddr for us
481  * @param addrlen the len of addr
482  * @param payload bytes payload to send
483  * @param cont continuation to call once the message has
484  *        been transmitted (or if the transport is ready
485  *        for the next transmission call; or if the
486  *        peer disconnected...)
487  * @param cont_cls closure for cont
488  *
489  * @return the number of bytes written, -1 on errors
490  */
491 static ssize_t
492 unix_real_send (void *cls,
493                 struct GNUNET_NETWORK_Handle *send_handle,
494                 const struct GNUNET_PeerIdentity *target, const char *msgbuf,
495                 size_t msgbuf_size, unsigned int priority,
496                 struct GNUNET_TIME_Relative timeout,
497                 const void *addr,
498                 size_t addrlen,
499                 size_t payload,
500                 GNUNET_TRANSPORT_TransmitContinuation cont,
501                 void *cont_cls)
502 {
503   struct Plugin *plugin = cls;
504   ssize_t sent;
505   const void *sb;
506   size_t sbs;
507   struct sockaddr_un un;
508   size_t slen;
509
510   GNUNET_assert (NULL != plugin);
511
512   if (send_handle == NULL)
513   {
514     /* We do not have a send handle */
515     GNUNET_break (0);
516     if (cont != NULL)
517       cont (cont_cls, target, GNUNET_SYSERR, payload, 0);
518     return -1;
519   }
520   if ((addr == NULL) || (addrlen == 0))
521   {
522     /* Can never send if we don't have an address */
523     GNUNET_break (0);
524     if (cont != NULL)
525       cont (cont_cls, target, GNUNET_SYSERR, payload, 0);
526     return -1;
527   }
528
529   /* Prepare address */
530   memset (&un, 0, sizeof (un));
531   un.sun_family = AF_UNIX;
532   slen = strlen (addr) + 1;
533   if (slen >= sizeof (un.sun_path))
534     slen = sizeof (un.sun_path) - 1;
535   GNUNET_assert (slen < sizeof (un.sun_path));
536   memcpy (un.sun_path, addr, slen);
537   un.sun_path[slen] = '\0';
538   slen = sizeof (struct sockaddr_un);
539 #if LINUX
540   un.sun_path[0] = '\0';
541 #endif
542 #if HAVE_SOCKADDR_IN_SIN_LEN
543   un.sun_len = (u_char) slen;
544 #endif
545   sb = (struct sockaddr *) &un;
546   sbs = slen;
547
548   /* Send the data */
549   sent = 0;
550   sent = GNUNET_NETWORK_socket_sendto (send_handle, msgbuf, msgbuf_size, sb, sbs);
551
552   if ((GNUNET_SYSERR == sent) && ((errno == EAGAIN) || (errno == ENOBUFS)))
553   {
554     /* We have to retry later: retry */
555     return 0;
556   }
557
558   if ((GNUNET_SYSERR == sent) && (errno == EMSGSIZE))
559   {
560     socklen_t size = 0;
561     socklen_t len = sizeof (size);
562
563     GNUNET_NETWORK_socket_getsockopt ((struct GNUNET_NETWORK_Handle *)
564                                       send_handle, SOL_SOCKET, SO_SNDBUF, &size,
565                                       &len);
566
567     if (size < msgbuf_size)
568     {
569       LOG (GNUNET_ERROR_TYPE_DEBUG,
570                   "Trying to increase socket buffer size from %i to %i for message size %i\n",
571                   size,
572                   ((msgbuf_size / 1000) + 2) * 1000,
573                   msgbuf_size);
574       size = ((msgbuf_size / 1000) + 2) * 1000;
575       if (GNUNET_NETWORK_socket_setsockopt
576           ((struct GNUNET_NETWORK_Handle *) send_handle, SOL_SOCKET, SO_SNDBUF,
577            &size, sizeof (size)) == GNUNET_OK)
578       {
579         /* Increased buffer size, retry sending */
580         return 0;
581       }
582       else
583       {
584         /* Could not increase buffer size: error, no retry */
585         GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "setsockopt");
586         return -1;
587       }
588     }
589     else
590     {
591       /* Buffer is bigger than message:  error, no retry
592        * This should never happen!*/
593       GNUNET_break (0);
594       return -1;
595     }
596   }
597
598   LOG (GNUNET_ERROR_TYPE_DEBUG,
599               "UNIX transmit %u-byte message to %s (%d: %s)\n",
600               (unsigned int) msgbuf_size, GNUNET_a2s (sb, sbs), (int) sent,
601               (sent < 0) ? STRERROR (errno) : "ok");
602
603   /* Calling continuation */
604   if (cont != NULL)
605   {
606     if (sent == GNUNET_SYSERR)
607       cont (cont_cls, target, GNUNET_SYSERR, payload, 0);
608     else if (sent > 0)
609       cont (cont_cls, target, GNUNET_OK, payload, msgbuf_size);
610     else
611       GNUNET_break (0);
612   }
613
614   /* return number of bytes successfully sent */
615   if (sent > 0)
616     return sent;
617   if (sent == 0)
618   {
619     /* That should never happen */
620     GNUNET_break (0);
621     return -1;
622   }
623   /* failed and retry: return 0 */
624   if (GNUNET_SYSERR == sent)
625     return 0;
626   /* default */
627   return -1;
628 }
629
630 struct gsi_ctx
631 {
632   char *address;
633   size_t addrlen;
634   struct Session *res;
635 };
636
637
638 static int
639 get_session_it (void *cls, const struct GNUNET_HashCode * key, void *value)
640 {
641   struct gsi_ctx *gsi = cls;
642   struct Session *s = value;
643
644   LOG (GNUNET_ERROR_TYPE_DEBUG, "Comparing session %s %s\n", gsi->address, s->addr);
645   if ((gsi->addrlen == s->addrlen) &&
646       (0 == memcmp (gsi->address, s->addr, s->addrlen)))
647   {
648     gsi->res = s;
649     return GNUNET_NO;
650   }
651   return GNUNET_YES;
652 }
653
654 /**
655  * Creates a new outbound session the transport service will use to send data to the
656  * peer
657  *
658  * @param cls the plugin
659  * @param address the address
660  * @return the session or NULL of max connections exceeded
661  */
662 static struct Session *
663 unix_plugin_get_session (void *cls,
664                   const struct GNUNET_HELLO_Address *address)
665 {
666   struct Session * s = NULL;
667   struct Plugin *plugin = cls;
668   struct gsi_ctx gsi;
669
670   /* Checks */
671   GNUNET_assert (plugin != NULL);
672   GNUNET_assert (address != NULL);
673
674   /* Check if already existing */
675   gsi.address = (char *) address->address;
676   gsi.addrlen = address->address_length;
677   gsi.res = NULL;
678   GNUNET_CONTAINER_multihashmap_get_multiple (plugin->session_map, &address->peer.hashPubKey, &get_session_it, &gsi);
679   if (gsi.res != NULL)
680   {
681     LOG (GNUNET_ERROR_TYPE_DEBUG, "Found existing session\n");
682     return gsi.res;
683   }
684
685   /* Create a new session */
686   s = GNUNET_malloc (sizeof (struct Session) + address->address_length);
687   s->addr = &s[1];
688   s->addrlen = address->address_length;
689   s->plugin = plugin;
690   memcpy(s->addr, address->address, s->addrlen);
691   memcpy(&s->target, &address->peer, sizeof (struct GNUNET_PeerIdentity));
692
693   start_session_timeout (s);
694
695   GNUNET_CONTAINER_multihashmap_put (plugin->session_map,
696       &address->peer.hashPubKey, s,
697       GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
698
699   GNUNET_STATISTICS_set(plugin->env->stats,
700                         "# UNIX sessions active",
701                         GNUNET_CONTAINER_multihashmap_size(plugin->session_map),
702                         GNUNET_NO);
703   LOG (GNUNET_ERROR_TYPE_DEBUG, "Creating new session\n");
704   return s;
705 }
706
707 /*
708  * @param cls the plugin handle
709  * @param tc the scheduling context (for rescheduling this function again)
710  *
711  * We have been notified that our writeset has something to read.  We don't
712  * know which socket needs to be read, so we have to check each one
713  * Then reschedule this function to be called again once more is available.
714  *
715  */
716 static void
717 unix_plugin_select (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
718
719 /**
720  * Function that can be used by the transport service to transmit
721  * a message using the plugin.   Note that in the case of a
722  * peer disconnecting, the continuation MUST be called
723  * prior to the disconnect notification itself.  This function
724  * will be called with this peer's HELLO message to initiate
725  * a fresh connection to another peer.
726  *
727  * @param cls closure
728  * @param session which session must be used
729  * @param msgbuf the message to transmit
730  * @param msgbuf_size number of bytes in 'msgbuf'
731  * @param priority how important is the message (most plugins will
732  *                 ignore message priority and just FIFO)
733  * @param to how long to wait at most for the transmission (does not
734  *                require plugins to discard the message after the timeout,
735  *                just advisory for the desired delay; most plugins will ignore
736  *                this as well)
737  * @param cont continuation to call once the message has
738  *        been transmitted (or if the transport is ready
739  *        for the next transmission call; or if the
740  *        peer disconnected...); can be NULL
741  * @param cont_cls closure for cont
742  * @return number of bytes used (on the physical network, with overheads);
743  *         -1 on hard errors (i.e. address invalid); 0 is a legal value
744  *         and does NOT mean that the message was not transmitted (DV)
745  */
746 static ssize_t
747 unix_plugin_send (void *cls,
748                   struct Session *session,
749                   const char *msgbuf, size_t msgbuf_size,
750                   unsigned int priority,
751                   struct GNUNET_TIME_Relative to,
752                   GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls)
753 {
754   struct Plugin *plugin = cls;
755   struct UNIXMessageWrapper *wrapper;
756   struct UNIXMessage *message;
757   int ssize;
758   
759   GNUNET_assert (plugin != NULL);
760   GNUNET_assert (session != NULL);
761
762   if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_contains_value(plugin->session_map,
763       &session->target.hashPubKey, session))
764   {
765     LOG (GNUNET_ERROR_TYPE_ERROR, "Invalid session for peer `%s' `%s'\n",
766                 GNUNET_i2s (&session->target),
767                 (char *) session->addr);
768     GNUNET_break (0);
769
770     return GNUNET_SYSERR;
771   }
772   LOG (GNUNET_ERROR_TYPE_DEBUG, "Sending %u bytes with session for peer `%s' `%s'\n",
773                 msgbuf_size,
774         GNUNET_i2s (&session->target),
775         (char *) session->addr);
776
777   ssize = sizeof (struct UNIXMessage) + msgbuf_size;
778   message = GNUNET_malloc (sizeof (struct UNIXMessage) + msgbuf_size);
779   message->header.size = htons (ssize);
780   message->header.type = htons (0);
781   memcpy (&message->sender, plugin->env->my_identity,
782           sizeof (struct GNUNET_PeerIdentity));
783   memcpy (&message[1], msgbuf, msgbuf_size);
784
785   reschedule_session_timeout (session);
786
787   wrapper = GNUNET_malloc (sizeof (struct UNIXMessageWrapper));
788   wrapper->msg = message;
789   wrapper->msgsize = ssize;
790   wrapper->payload = msgbuf_size;
791   wrapper->priority = priority;
792   wrapper->timeout = to;
793   wrapper->cont = cont;
794   wrapper->cont_cls = cont_cls;
795   wrapper->session = session;
796
797   GNUNET_CONTAINER_DLL_insert(plugin->msg_head, plugin->msg_tail, wrapper);
798
799   plugin->bytes_in_queue += ssize;
800   GNUNET_STATISTICS_set (plugin->env->stats,"# bytes currently in UNIX buffers",
801       plugin->bytes_in_queue, GNUNET_NO);
802
803   LOG (GNUNET_ERROR_TYPE_DEBUG, "Sent %d bytes to `%s'\n", ssize,
804               (char *) session->addr);
805   if (plugin->with_ws == GNUNET_NO)
806   {
807     reschedule_select (plugin);
808   }
809
810   return ssize;
811 }
812
813
814 /**
815  * Demultiplexer for UNIX messages
816  *
817  * @param plugin the main plugin for this transport
818  * @param sender from which peer the message was received
819  * @param currhdr pointer to the header of the message
820  * @param un the address from which the message was received
821  * @param fromlen the length of the address
822  */
823 static void
824 unix_demultiplexer (struct Plugin *plugin, struct GNUNET_PeerIdentity *sender,
825                     const struct GNUNET_MessageHeader *currhdr,
826                     const struct sockaddr_un *un, size_t fromlen)
827 {
828   struct GNUNET_ATS_Information ats[2];
829   struct Session *s = NULL;
830   struct GNUNET_HELLO_Address * addr;
831
832   ats[0].type = htonl (GNUNET_ATS_QUALITY_NET_DISTANCE);
833   ats[0].value = htonl (UNIX_DIRECT_DISTANCE);
834   ats[1] = plugin->ats_network;
835   GNUNET_break (ntohl(plugin->ats_network.value) != GNUNET_ATS_NET_UNSPECIFIED);
836
837   GNUNET_assert (fromlen >= sizeof (struct sockaddr_un));
838
839   LOG (GNUNET_ERROR_TYPE_DEBUG, "Received message from %s\n",
840               un->sun_path);
841
842
843
844   plugin->bytes_in_recv += ntohs(currhdr->size);
845   GNUNET_STATISTICS_set (plugin->env->stats,"# bytes received via UNIX",
846       plugin->bytes_in_recv, GNUNET_NO);
847
848   addr = GNUNET_HELLO_address_allocate(sender, "unix", un->sun_path, strlen (un->sun_path) + 1);
849   s = lookup_session (plugin, sender, un);
850   if (NULL == s)
851     s = unix_plugin_get_session (plugin, addr);
852   reschedule_session_timeout (s);
853
854   plugin->env->receive (plugin->env->cls, sender, currhdr,
855                         (const struct GNUNET_ATS_Information *) &ats, 2,
856                         s, un->sun_path, strlen (un->sun_path) + 1);
857   GNUNET_free (addr);
858 }
859
860
861 static void
862 unix_plugin_select_read (struct Plugin * plugin)
863 {
864   char buf[65536] GNUNET_ALIGN;
865   struct UNIXMessage *msg;
866   struct GNUNET_PeerIdentity sender;
867   struct sockaddr_un un;
868   socklen_t addrlen;
869   ssize_t ret;
870   int offset;
871   int tsize;
872   char *msgbuf;
873   const struct GNUNET_MessageHeader *currhdr;
874   uint16_t csize;
875
876   addrlen = sizeof (un);
877   memset (&un, 0, sizeof (un));
878
879   ret =
880       GNUNET_NETWORK_socket_recvfrom (plugin->unix_sock.desc, buf, sizeof (buf),
881                                       (struct sockaddr *) &un, &addrlen);
882
883   if ((GNUNET_SYSERR == ret) && ((errno == EAGAIN) || (errno == ENOBUFS)))
884     return;
885
886   if (ret == GNUNET_SYSERR)
887   {
888     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "recvfrom");
889     return;
890   }
891   else
892   {
893 #if LINUX
894     un.sun_path[0] = '/';
895 #endif
896     LOG (GNUNET_ERROR_TYPE_DEBUG, "Read %d bytes from socket %s\n", ret,
897                 &un.sun_path[0]);
898   }
899
900   GNUNET_assert (AF_UNIX == (un.sun_family));
901
902   msg = (struct UNIXMessage *) buf;
903   csize = ntohs (msg->header.size);
904   if ((csize < sizeof (struct UNIXMessage)) || (csize > ret))
905   {
906     GNUNET_break_op (0);
907     return;
908   }
909   msgbuf = (char *) &msg[1];
910   memcpy (&sender, &msg->sender, sizeof (struct GNUNET_PeerIdentity));
911   offset = 0;
912   tsize = csize - sizeof (struct UNIXMessage);
913   while (offset + sizeof (struct GNUNET_MessageHeader) <= tsize)
914   {
915     currhdr = (struct GNUNET_MessageHeader *) &msgbuf[offset];
916     csize = ntohs (currhdr->size);
917     if ((csize < sizeof (struct GNUNET_MessageHeader)) ||
918         (csize > tsize - offset))
919     {
920       GNUNET_break_op (0);
921       break;
922     }
923
924     unix_demultiplexer (plugin, &sender, currhdr, &un, sizeof (un));
925     offset += csize;
926   }
927 }
928
929
930 static void
931 unix_plugin_select_write (struct Plugin * plugin)
932 {
933   static int retry_counter;
934   int sent = 0;
935   struct UNIXMessageWrapper * msgw = plugin->msg_head;
936
937   sent = unix_real_send (plugin,
938                          plugin->unix_sock.desc,
939                          &msgw->session->target,
940                          (const char *) msgw->msg,
941                          msgw->msgsize,
942                          msgw->priority,
943                          msgw->timeout,
944                          msgw->session->addr,
945                          msgw->session->addrlen,
946                          msgw->payload,
947                          msgw->cont, msgw->cont_cls);
948
949   if (sent == 0)
950   {
951     /* failed and retry */
952     retry_counter++;
953     GNUNET_STATISTICS_set (plugin->env->stats,"# UNIX retry attempt",
954         retry_counter, GNUNET_NO);
955     return;
956   }
957
958   if (retry_counter > 0 )
959   {
960     /* no retry: reset counter */
961     retry_counter = 0;
962     GNUNET_STATISTICS_set (plugin->env->stats,"# UNIX retry attempt",
963         retry_counter, GNUNET_NO);
964   }
965
966   if (sent == -1)
967   {
968     /* failed and no retry */
969     GNUNET_CONTAINER_DLL_remove(plugin->msg_head, plugin->msg_tail, msgw);
970
971     GNUNET_assert (plugin->bytes_in_queue >= msgw->msgsize);
972     plugin->bytes_in_queue -= msgw->msgsize;
973     GNUNET_STATISTICS_set (plugin->env->stats, "# bytes currently in UNIX buffers",
974         plugin->bytes_in_queue, GNUNET_NO);
975     plugin->bytes_discarded += msgw->msgsize;
976     GNUNET_STATISTICS_set (plugin->env->stats,"# UNIX bytes discarded",
977         plugin->bytes_discarded, GNUNET_NO);
978
979     GNUNET_free (msgw->msg);
980     GNUNET_free (msgw);
981     return;
982   }
983
984   if (sent > 0)
985   {
986     /* successfully sent bytes */
987     GNUNET_CONTAINER_DLL_remove(plugin->msg_head, plugin->msg_tail, msgw);
988
989     GNUNET_assert (plugin->bytes_in_queue >= msgw->msgsize);
990     plugin->bytes_in_queue -= msgw->msgsize;
991     GNUNET_STATISTICS_set (plugin->env->stats,"# bytes currently in UNIX buffers",
992         plugin->bytes_in_queue, GNUNET_NO);
993     plugin->bytes_in_sent += msgw->msgsize;
994     GNUNET_STATISTICS_set (plugin->env->stats,"# bytes transmitted via UNIX",
995         plugin->bytes_in_sent, GNUNET_NO);
996
997     GNUNET_free (msgw->msg);
998     GNUNET_free (msgw);
999     return;
1000   }
1001
1002 }
1003
1004
1005 /**
1006  * We have been notified that our writeset has something to read.  We don't
1007  * know which socket needs to be read, so we have to check each one
1008  * Then reschedule this function to be called again once more is available.
1009  *
1010  * @param cls the plugin handle
1011  * @param tc the scheduling context (for rescheduling this function again)
1012  */
1013 static void
1014 unix_plugin_select (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1015 {
1016   struct Plugin *plugin = cls;
1017
1018   plugin->select_task = GNUNET_SCHEDULER_NO_TASK;
1019   if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
1020     return;
1021
1022   if ((tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY) != 0)
1023   {
1024     /* Ready to send data */
1025     GNUNET_assert (GNUNET_NETWORK_fdset_isset
1026                    (tc->write_ready, plugin->unix_sock.desc));
1027     if (plugin->msg_head != NULL)
1028       unix_plugin_select_write (plugin);
1029   }
1030
1031   if ((tc->reason & GNUNET_SCHEDULER_REASON_READ_READY) != 0)
1032   {
1033     /* Ready to receive data */
1034     GNUNET_assert (GNUNET_NETWORK_fdset_isset
1035                    (tc->read_ready, plugin->unix_sock.desc));
1036     unix_plugin_select_read (plugin);
1037   }
1038
1039   reschedule_select (plugin);
1040 }
1041
1042
1043 /**
1044  * Create a slew of UNIX sockets.  If possible, use IPv6 and IPv4.
1045  *
1046  * @param cls closure for server start, should be a struct Plugin *
1047  * @return number of sockets created or GNUNET_SYSERR on error
1048  */
1049 static int
1050 unix_transport_server_start (void *cls)
1051 {
1052   struct Plugin *plugin = cls;
1053   struct sockaddr *serverAddr;
1054   socklen_t addrlen;
1055   struct sockaddr_un un;
1056   size_t slen;
1057
1058   memset (&un, 0, sizeof (un));
1059   un.sun_family = AF_UNIX;
1060   slen = strlen (plugin->unix_socket_path) + 1;
1061   if (slen >= sizeof (un.sun_path))
1062     slen = sizeof (un.sun_path) - 1;
1063
1064   memcpy (un.sun_path, plugin->unix_socket_path, slen);
1065   un.sun_path[slen] = '\0';
1066   slen = sizeof (struct sockaddr_un);
1067 #if HAVE_SOCKADDR_IN_SIN_LEN
1068   un.sun_len = (u_char) slen;
1069 #endif
1070
1071   serverAddr = (struct sockaddr *) &un;
1072   addrlen = slen;
1073 #if LINUX
1074   un.sun_path[0] = '\0';
1075 #endif
1076   plugin->ats_network = plugin->env->get_address_type (plugin->env->cls, serverAddr, addrlen);
1077   plugin->unix_sock.desc =
1078       GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_DGRAM, 0);
1079   if (NULL == plugin->unix_sock.desc)
1080   {
1081     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket");
1082     return GNUNET_SYSERR;
1083   }
1084   if (GNUNET_NETWORK_socket_bind (plugin->unix_sock.desc, serverAddr, addrlen)
1085       != GNUNET_OK)
1086   {
1087     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "bind");
1088     GNUNET_NETWORK_socket_close (plugin->unix_sock.desc);
1089     plugin->unix_sock.desc = NULL;
1090     return GNUNET_SYSERR;
1091   }
1092   LOG (GNUNET_ERROR_TYPE_DEBUG, "Bound to `%s'\n", plugin->unix_socket_path);
1093   plugin->rs = GNUNET_NETWORK_fdset_create ();
1094   plugin->ws = GNUNET_NETWORK_fdset_create ();
1095   GNUNET_NETWORK_fdset_zero (plugin->rs);
1096   GNUNET_NETWORK_fdset_zero (plugin->ws);
1097   GNUNET_NETWORK_fdset_set (plugin->rs, plugin->unix_sock.desc);
1098   GNUNET_NETWORK_fdset_set (plugin->ws, plugin->unix_sock.desc);
1099
1100   reschedule_select (plugin);
1101
1102   return 1;
1103 }
1104
1105
1106 /**
1107  * Function that will be called to check if a binary address for this
1108  * plugin is well-formed and corresponds to an address for THIS peer
1109  * (as per our configuration).  Naturally, if absolutely necessary,
1110  * plugins can be a bit conservative in their answer, but in general
1111  * plugins should make sure that the address does not redirect
1112  * traffic to a 3rd party that might try to man-in-the-middle our
1113  * traffic.
1114  *
1115  * @param cls closure, should be our handle to the Plugin
1116  * @param addr pointer to the address
1117  * @param addrlen length of addr
1118  * @return GNUNET_OK if this is a plausible address for this peer
1119  *         and transport, GNUNET_SYSERR if not
1120  *
1121  */
1122 static int
1123 unix_check_address (void *cls, const void *addr, size_t addrlen)
1124 {
1125   LOG (GNUNET_ERROR_TYPE_DEBUG,
1126               "Informing transport service about my address `%s'\n",
1127               (char *) addr);
1128   return GNUNET_OK;
1129 }
1130
1131
1132 /**
1133  * Convert the transports address to a nice, human-readable
1134  * format.
1135  *
1136  * @param cls closure
1137  * @param type name of the transport that generated the address
1138  * @param addr one of the addresses of the host, NULL for the last address
1139  *        the specific address format depends on the transport
1140  * @param addrlen length of the address
1141  * @param numeric should (IP) addresses be displayed in numeric form?
1142  * @param timeout after how long should we give up?
1143  * @param asc function to call on each string
1144  * @param asc_cls closure for asc
1145  */
1146 static void
1147 unix_plugin_address_pretty_printer (void *cls, const char *type,
1148                                     const void *addr, size_t addrlen,
1149                                     int numeric,
1150                                     struct GNUNET_TIME_Relative timeout,
1151                                     GNUNET_TRANSPORT_AddressStringCallback asc,
1152                                     void *asc_cls)
1153 {
1154   if ((NULL != addr) && (addrlen > 0))
1155   {
1156     asc (asc_cls, (const char *) addr);
1157   }
1158   else
1159   {
1160     GNUNET_break (0);
1161     asc (asc_cls, "<invalid UNIX address>");
1162   }
1163   asc (asc_cls, NULL);
1164 }
1165
1166
1167 /**
1168  * Function called to convert a string address to
1169  * a binary address.
1170  *
1171  * @param cls closure ('struct Plugin*')
1172  * @param addr string address
1173  * @param addrlen length of the address (strlen(addr) + '\0')
1174  * @param buf location to store the buffer
1175  *        If the function returns GNUNET_SYSERR, its contents are undefined.
1176  * @param added length of created address
1177  * @return GNUNET_OK on success, GNUNET_SYSERR on failure
1178  */
1179 static int
1180 unix_string_to_address (void *cls, const char *addr, uint16_t addrlen,
1181     void **buf, size_t *added)
1182 {
1183   if ((NULL == addr) || (0 == addrlen))
1184   {
1185     GNUNET_break (0);
1186     return GNUNET_SYSERR;
1187   }
1188
1189   if ('\0' != addr[addrlen - 1])
1190   {
1191     GNUNET_break (0);
1192     return GNUNET_SYSERR;
1193   }
1194
1195   if (strlen (addr) != addrlen - 1)
1196   {
1197     GNUNET_break (0);
1198     return GNUNET_SYSERR;
1199   }
1200
1201   (*buf) = strdup (addr);
1202   (*added) = strlen (addr) + 1;
1203   return GNUNET_OK;
1204 }
1205
1206
1207 /**
1208  * Function called for a quick conversion of the binary address to
1209  * a numeric address.  Note that the caller must not free the
1210  * address and that the next call to this function is allowed
1211  * to override the address again.
1212  *
1213  * @param cls closure
1214  * @param addr binary address
1215  * @param addrlen length of the address
1216  * @return string representing the same address
1217  */
1218 static const char *
1219 unix_address_to_string (void *cls, const void *addr, size_t addrlen)
1220 {
1221   if ((addr != NULL) && (addrlen > 0))
1222     return (const char *) addr;
1223   return NULL;
1224 }
1225
1226
1227 /**
1228  * Notify transport service about address
1229  *
1230  * @param cls the plugin
1231  * @param tc unused
1232  */
1233 static void
1234 address_notification (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1235 {
1236   struct Plugin *plugin = cls;
1237
1238   plugin->env->notify_address (plugin->env->cls, GNUNET_YES,
1239                                plugin->unix_socket_path,
1240                                strlen (plugin->unix_socket_path) + 1,
1241                                "unix");
1242 }
1243
1244
1245 /**
1246  * Session was idle, so disconnect it
1247  */
1248 static void
1249 session_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1250 {
1251   GNUNET_assert (NULL != cls);
1252   struct Session *s = cls;
1253
1254   s->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1255   LOG (GNUNET_ERROR_TYPE_DEBUG,
1256               "Session %p was idle for %llu ms, disconnecting\n",
1257               s, (unsigned long long) GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value);
1258   /* call session destroy function */
1259   disconnect_session(s);
1260 }
1261
1262
1263 /**
1264  * Start session timeout
1265  */
1266 static void
1267 start_session_timeout (struct Session *s)
1268 {
1269   GNUNET_assert (NULL != s);
1270   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == s->timeout_task);
1271   s->timeout_task =  GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1272                                                    &session_timeout,
1273                                                    s);
1274   LOG (GNUNET_ERROR_TYPE_DEBUG,
1275               "Timeout for session %p set to %llu ms\n",
1276               s,  (unsigned long long) GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value);
1277 }
1278
1279
1280 /**
1281  * Increment session timeout due to activity
1282  */
1283 static void
1284 reschedule_session_timeout (struct Session *s)
1285 {
1286   GNUNET_assert (NULL != s);
1287   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != s->timeout_task);
1288
1289   GNUNET_SCHEDULER_cancel (s->timeout_task);
1290   s->timeout_task =  GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1291                                                    &session_timeout,
1292                                                    s);
1293   LOG (GNUNET_ERROR_TYPE_DEBUG,
1294               "Timeout rescheduled for session %p set to %llu ms\n",
1295               s, (unsigned long long) GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value);
1296 }
1297
1298
1299 /**
1300  * Cancel timeout
1301  */
1302 static void
1303 stop_session_timeout (struct Session *s)
1304 {
1305   GNUNET_assert (NULL != s);
1306
1307   if (GNUNET_SCHEDULER_NO_TASK != s->timeout_task)
1308   {
1309     GNUNET_SCHEDULER_cancel (s->timeout_task);
1310     s->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1311     LOG (GNUNET_ERROR_TYPE_DEBUG,
1312                 "Timeout stopped for session %p canceled\n",
1313                 s, (unsigned long long) GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value);
1314   }
1315 }
1316
1317 /**
1318  * The exported method. Makes the core api available via a global and
1319  * returns the unix transport API.
1320  */
1321 void *
1322 libgnunet_plugin_transport_unix_init (void *cls)
1323 {
1324   struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
1325   unsigned long long port;
1326   struct GNUNET_TRANSPORT_PluginFunctions *api;
1327   struct Plugin *plugin;
1328   int sockets_created;
1329
1330   if (NULL == env->receive)
1331   {
1332     /* run in 'stub' mode (i.e. as part of gnunet-peerinfo), don't fully
1333        initialze the plugin or the API */
1334     api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions));
1335     api->cls = NULL;
1336     api->address_pretty_printer = &unix_plugin_address_pretty_printer;
1337     api->address_to_string = &unix_address_to_string;
1338     api->string_to_address = &unix_string_to_address;
1339     return api;
1340   }
1341   GNUNET_assert( NULL != env->stats);
1342
1343   if (GNUNET_OK !=
1344       GNUNET_CONFIGURATION_get_value_number (env->cfg, "transport-unix", "PORT",
1345                                              &port))
1346     port = UNIX_NAT_DEFAULT_PORT;
1347   plugin = GNUNET_malloc (sizeof (struct Plugin));
1348   plugin->port = port;
1349   plugin->env = env;
1350   GNUNET_asprintf (&plugin->unix_socket_path, "/tmp/unix-plugin-sock.%d",
1351                    plugin->port);
1352
1353   api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions));
1354   api->cls = plugin;
1355
1356   api->get_session = &unix_plugin_get_session;
1357   api->send = &unix_plugin_send;
1358   api->disconnect = &unix_disconnect;
1359   api->address_pretty_printer = &unix_plugin_address_pretty_printer;
1360   api->address_to_string = &unix_address_to_string;
1361   api->check_address = &unix_check_address;
1362   api->string_to_address = &unix_string_to_address;
1363   sockets_created = unix_transport_server_start (plugin);
1364   if (sockets_created == 0)
1365     LOG (GNUNET_ERROR_TYPE_WARNING, _("Failed to open UNIX sockets\n"));
1366
1367   plugin->session_map = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
1368
1369   GNUNET_SCHEDULER_add_now (address_notification, plugin);
1370   return api;
1371 }
1372
1373 void *
1374 libgnunet_plugin_transport_unix_done (void *cls)
1375 {
1376   struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
1377   struct Plugin *plugin = api->cls;
1378
1379   if (NULL == plugin)
1380   {
1381     GNUNET_free (api);
1382     return NULL;
1383   }
1384
1385   plugin->env->notify_address (plugin->env->cls, GNUNET_NO,
1386                                plugin->unix_socket_path,
1387                                strlen (plugin->unix_socket_path) + 1,
1388                                "unix");
1389
1390   unix_transport_server_stop (plugin);
1391
1392
1393   GNUNET_CONTAINER_multihashmap_iterate (plugin->session_map, &get_session_delete_it, plugin);
1394   GNUNET_CONTAINER_multihashmap_destroy (plugin->session_map);
1395
1396
1397   if (NULL != plugin->rs)
1398     GNUNET_NETWORK_fdset_destroy (plugin->rs);
1399   if (NULL != plugin->ws)
1400     GNUNET_NETWORK_fdset_destroy (plugin->ws);
1401   GNUNET_free (plugin->unix_socket_path);
1402   GNUNET_free (plugin);
1403   GNUNET_free (api);
1404   return NULL;
1405 }
1406
1407 /* end of plugin_transport_unix.c */