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