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