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