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