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