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_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   memset(&un, 0, sizeof(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       GNUNET_free(message);
578       return ssize;
579     }
580 #if DEBUG_UNIX
581   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
582               "UNIX transmit %u-byte message to %s (%d: %s)\n",
583               (unsigned int) ssize,
584               GNUNET_a2s (sb, sbs),
585               (int) sent,
586               (sent < 0) ? STRERROR (errno) : "ok");
587 #endif
588   if (cont != NULL)
589     {
590       if (sent == GNUNET_SYSERR)
591         cont (cont_cls, target, GNUNET_SYSERR);
592       else
593         {
594           cont (cont_cls, target, GNUNET_OK);
595         }
596     }
597
598   if (incoming_retry_context != NULL)
599     {
600       GNUNET_free(incoming_retry_context->msg);
601       GNUNET_free(incoming_retry_context->addr);
602       GNUNET_free(incoming_retry_context);
603     }
604
605   GNUNET_free (message);
606   return sent;
607 }
608
609
610 /**
611  * Function that can be used by the transport service to transmit
612  * a message using the plugin.
613  *
614  * @param cls closure
615  * @param target who should receive this message (ignored by UNIX)
616  * @param msgbuf one or more GNUNET_MessageHeader(s) strung together
617  * @param msgbuf_size the size of the msgbuf to send
618  * @param priority how important is the message (ignored by UNIX)
619  * @param timeout when should we time out (give up) if we can not transmit?
620  * @param session identifier used for this session (can be NULL)
621  * @param addr the addr to send the message to, needs to be a sockaddr for us
622  * @param addrlen the len of addr
623  * @param force_address not used, we had better have an address to send to
624  *        because we are stateless!!
625  * @param cont continuation to call once the message has
626  *        been transmitted (or if the transport is ready
627  *        for the next transmission call; or if the
628  *        peer disconnected...)
629  * @param cont_cls closure for cont
630  *
631  * @return the number of bytes written (may return 0 and the message can
632  *         still be transmitted later!)
633  */
634 static ssize_t
635 unix_plugin_send (void *cls,
636                      const struct GNUNET_PeerIdentity *target,
637                      const char *msgbuf,
638                      size_t msgbuf_size,
639                      unsigned int priority,
640                      struct GNUNET_TIME_Relative timeout,
641                      struct Session *session,
642                      const void *addr,
643                      size_t addrlen,
644                      int force_address,
645                      GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls)
646 {
647   struct Plugin *plugin = cls;
648   ssize_t sent;
649
650   if (force_address == GNUNET_SYSERR)
651     return GNUNET_SYSERR;
652   GNUNET_assert (NULL == session);
653
654 #if DEBUG_UNIX
655   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Asked to send message to `%s'\n", (char *)addr);
656 #endif
657   sent = unix_real_send(cls,
658                         NULL,
659                         plugin->unix_sock.desc,
660                         target,
661                         msgbuf, msgbuf_size,
662                         priority, timeout, addr, addrlen,
663                         cont, cont_cls);
664 #if DEBUG_UNIX
665   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Sent %d bytes to `%s'\n", sent, (char *)addr);
666 #endif
667   if (sent == GNUNET_SYSERR)
668     return 0;
669   return sent;
670 }
671
672
673 static void
674 add_to_address_list (struct Plugin *plugin,
675                      const void *arg,
676                      size_t arg_size)
677 {
678   struct LocalAddrList *lal;
679
680   lal = plugin->lal_head;
681   while (NULL != lal)
682     {
683       if ( (lal->size == arg_size) &&
684            (0 == memcmp (&lal[1], arg, arg_size)) )
685         return;
686       lal = lal->next;
687     }
688   lal = GNUNET_malloc (sizeof (struct LocalAddrList) + arg_size);
689   lal->size = arg_size;
690   memcpy (&lal[1], arg, arg_size);
691   GNUNET_CONTAINER_DLL_insert (plugin->lal_head,
692                                plugin->lal_tail,
693                                lal);
694 }
695
696
697 /**
698  * Demultiplexer for UNIX messages
699  *
700  * @param plugin the main plugin for this transport
701  * @param sender from which peer the message was received
702  * @param currhdr pointer to the header of the message
703  * @param un the address from which the message was received
704  * @param fromlen the length of the address
705  */
706 static void
707 unix_demultiplexer(struct Plugin *plugin,
708                    struct GNUNET_PeerIdentity *sender,
709                    const struct GNUNET_MessageHeader *currhdr,
710                    const struct sockaddr_un *un,
711                    size_t fromlen)
712 {
713   struct GNUNET_TRANSPORT_ATS_Information distance[2];
714
715   distance[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
716   distance[0].value = htonl (UNIX_DIRECT_DISTANCE);
717   distance[1].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
718   distance[1].value = htonl (0);
719
720   GNUNET_assert(fromlen >= sizeof(struct sockaddr_un));
721
722 #if DEBUG_UNIX
723   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Received message from %s\n", un->sun_path);
724 #endif
725   plugin->env->receive (plugin->env->cls, sender, currhdr,
726                        (const struct GNUNET_TRANSPORT_ATS_Information *) &distance, 2,
727                               NULL, un->sun_path, strlen(un->sun_path) + 1);
728 }
729
730
731 /*
732  * @param cls the plugin handle
733  * @param tc the scheduling context (for rescheduling this function again)
734  *
735  * We have been notified that our writeset has something to read.  We don't
736  * know which socket needs to be read, so we have to check each one
737  * Then reschedule this function to be called again once more is available.
738  *
739  */
740 static void
741 unix_plugin_select (void *cls,
742                     const struct GNUNET_SCHEDULER_TaskContext *tc)
743 {
744   struct Plugin *plugin = cls;
745   char buf[65536];
746   struct UNIXMessage *msg;
747   struct GNUNET_PeerIdentity sender;
748   struct sockaddr_un un;
749   socklen_t addrlen;
750   ssize_t ret;
751   int offset;
752   int tsize;
753   char *msgbuf;
754   const struct GNUNET_MessageHeader *currhdr;
755   uint16_t csize;
756
757   plugin->select_task = GNUNET_SCHEDULER_NO_TASK;
758   if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
759     return;
760
761   addrlen = sizeof(un);
762   memset(&un, 0, sizeof(un));
763   GNUNET_assert (GNUNET_NETWORK_fdset_isset (tc->read_ready, plugin->unix_sock.desc));
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       plugin->select_task =
772         GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
773                                      GNUNET_SCHEDULER_NO_TASK,
774                                      GNUNET_TIME_UNIT_FOREVER_REL, plugin->rs,
775                                      NULL, &unix_plugin_select, plugin);
776       return;
777     }
778   else
779   {
780 #if LINUX
781     un.sun_path[0] = '/';
782 #endif
783 #if DEBUG_UNIX
784     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Read %d bytes from socket %s\n", ret, &un.sun_path[0]);
785 #endif
786   }
787
788   GNUNET_assert (AF_UNIX == (un.sun_family));
789
790   msg = (struct UNIXMessage *) buf;
791   csize = ntohs (msg->header.size);
792   if ( (csize < sizeof (struct UNIXMessage)) ||
793        (csize > ret) )
794     {
795       GNUNET_break_op (0);
796       plugin->select_task =
797         GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
798                                      GNUNET_SCHEDULER_NO_TASK,
799                                      GNUNET_TIME_UNIT_FOREVER_REL, plugin->rs,
800                                      NULL, &unix_plugin_select, plugin);
801       return;
802     }
803   msgbuf = (char *)&msg[1];
804   memcpy (&sender, &msg->sender, sizeof (struct GNUNET_PeerIdentity));
805   offset = 0;
806   tsize = csize - sizeof (struct UNIXMessage);
807   while (offset + sizeof (struct GNUNET_MessageHeader) <= tsize)
808     {
809       currhdr = (struct GNUNET_MessageHeader *)&msgbuf[offset];
810       csize = ntohs (currhdr->size);
811       if ( (csize < sizeof (struct GNUNET_MessageHeader)) ||
812            (csize > tsize - offset) )
813         {
814           GNUNET_break_op (0);
815           break;
816         }
817       unix_demultiplexer(plugin, &sender, currhdr,
818                          &un, sizeof(un));
819       offset += csize;
820     }
821   plugin->select_task =
822     GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
823                                  GNUNET_SCHEDULER_NO_TASK,
824                                  GNUNET_TIME_UNIT_FOREVER_REL, plugin->rs,
825                                  NULL, &unix_plugin_select, plugin);
826 }
827
828 /**
829  * Create a slew of UNIX sockets.  If possible, use IPv6 and IPv4.
830  *
831  * @param cls closure for server start, should be a struct Plugin *
832  * @return number of sockets created or GNUNET_SYSERR on error
833 */
834 static int
835 unix_transport_server_start (void *cls)
836 {
837   struct Plugin *plugin = cls;
838
839   struct sockaddr *serverAddr;
840   socklen_t addrlen;
841   int sockets_created;
842   struct sockaddr_un un;
843   size_t slen;
844
845   memset(&un, 0, sizeof(un));
846   un.sun_family = AF_UNIX;
847   slen = strlen (plugin->unix_socket_path) + 1;
848
849   GNUNET_assert(slen < sizeof(un.sun_path));
850   memcpy (un.sun_path, plugin->unix_socket_path, slen);
851   un.sun_path[slen] = '\0';
852   slen += sizeof (sa_family_t);
853   serverAddr = (struct sockaddr*) &un;
854   addrlen = slen;
855   sockets_created = 0;
856 #if LINUX
857   un.sun_path[0] = '\0';
858 #endif
859
860   plugin->unix_sock.desc = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_DGRAM, 0);
861   if (NULL == plugin->unix_sock.desc)
862     {
863       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "socket");
864     }
865   else
866     {
867       if (GNUNET_NETWORK_socket_bind (plugin->unix_sock.desc, serverAddr, addrlen) !=
868              GNUNET_OK)
869         {
870 #if DEBUG_UNIX
871           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
872                            "UNIX Binding failed!\n");
873 #endif
874         }
875       else
876         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Bound to `%s'\n", &un.sun_path[0]);
877       if (plugin->unix_sock.desc != NULL)
878         sockets_created++;
879     }
880
881   plugin->rs = GNUNET_NETWORK_fdset_create ();
882   GNUNET_NETWORK_fdset_zero (plugin->rs);
883   GNUNET_NETWORK_fdset_set (plugin->rs,
884                             plugin->unix_sock.desc);
885
886   plugin->select_task =
887     GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
888                                  GNUNET_SCHEDULER_NO_TASK,
889                                  GNUNET_TIME_UNIT_FOREVER_REL, plugin->rs,
890                                  NULL, &unix_plugin_select, plugin);
891   return sockets_created;
892 }
893
894
895 /**
896  * Function that will be called to check if a binary address for this
897  * plugin is well-formed and corresponds to an address for THIS peer
898  * (as per our configuration).  Naturally, if absolutely necessary,
899  * plugins can be a bit conservative in their answer, but in general
900  * plugins should make sure that the address does not redirect
901  * traffic to a 3rd party that might try to man-in-the-middle our
902  * traffic.
903  *
904  * @param cls closure, should be our handle to the Plugin
905  * @param addr pointer to the address
906  * @param addrlen length of addr
907  * @return GNUNET_OK if this is a plausible address for this peer
908  *         and transport, GNUNET_SYSERR if not
909  *
910  */
911 static int
912 unix_check_address (void *cls,
913                    const void *addr,
914                    size_t addrlen)
915 {
916
917 #if DEBUG_UNIX
918   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
919                    "Informing transport service about my address `%s'\n",
920                    (char *)addr);
921 #endif
922   return GNUNET_OK;
923 }
924
925
926 /**
927  * Append our port and forward the result.
928  */
929 static void
930 append_port (void *cls, const char *hostname)
931 {
932   struct PrettyPrinterContext *ppc = cls;
933   char *ret;
934
935   if (hostname == NULL)
936     {
937       ppc->asc (ppc->asc_cls, NULL);
938       GNUNET_free (ppc);
939       return;
940     }
941   GNUNET_asprintf (&ret, "%s:%d", hostname, ppc->port);
942   ppc->asc (ppc->asc_cls, ret);
943   GNUNET_free (ret);
944 }
945
946
947 /**
948  * Convert the transports address to a nice, human-readable
949  * format.
950  *
951  * @param cls closure
952  * @param type name of the transport that generated the address
953  * @param addr one of the addresses of the host, NULL for the last address
954  *        the specific address format depends on the transport
955  * @param addrlen length of the address
956  * @param numeric should (IP) addresses be displayed in numeric form?
957  * @param timeout after how long should we give up?
958  * @param asc function to call on each string
959  * @param asc_cls closure for asc
960  */
961 static void
962 unix_plugin_address_pretty_printer (void *cls,
963                                    const char *type,
964                                    const void *addr,
965                                    size_t addrlen,
966                                    int numeric,
967                                    struct GNUNET_TIME_Relative timeout,
968                                    GNUNET_TRANSPORT_AddressStringCallback asc,
969                                    void *asc_cls)
970 {
971   struct Plugin *plugin = cls;
972   struct PrettyPrinterContext *ppc;
973   const void *sb;
974   size_t sbs;
975   struct sockaddr_in a4;
976   struct sockaddr_in6 a6;
977   const struct IPv4UdpAddress *u4;
978   const struct IPv6UdpAddress *u6;
979   uint16_t port;
980
981   if (addrlen == sizeof (struct IPv6UdpAddress))
982     {
983       u6 = addr;
984       memset (&a6, 0, sizeof (a6));
985       a6.sin6_family = AF_INET6;
986       a6.sin6_port = u6->u6_port;
987       memcpy (&a6.sin6_addr,
988               &u6->ipv6_addr,
989               sizeof (struct in6_addr));
990       port = ntohs (u6->u6_port);
991       sb = &a6;
992       sbs = sizeof (a6);
993     }
994   else if (addrlen == sizeof (struct IPv4UdpAddress))
995     {
996       u4 = addr;
997       memset (&a4, 0, sizeof (a4));
998       a4.sin_family = AF_INET;
999       a4.sin_port = u4->u_port;
1000       a4.sin_addr.s_addr = u4->ipv4_addr;
1001       port = ntohs (u4->u_port);
1002       sb = &a4;
1003       sbs = sizeof (a4);
1004     }
1005   else
1006     {
1007       /* invalid address */
1008       GNUNET_break_op (0);
1009       asc (asc_cls, NULL);
1010       return;
1011     }
1012   ppc = GNUNET_malloc (sizeof (struct PrettyPrinterContext));
1013   ppc->asc = asc;
1014   ppc->asc_cls = asc_cls;
1015   ppc->port = port;
1016   GNUNET_RESOLVER_hostname_get (plugin->env->cfg,
1017                                 sb,
1018                                 sbs,
1019                                 !numeric, timeout, &append_port, ppc);
1020 }
1021
1022 /**
1023  * Function called for a quick conversion of the binary address to
1024  * a numeric address.  Note that the caller must not free the
1025  * address and that the next call to this function is allowed
1026  * to override the address again.
1027  *
1028  * @param cls closure
1029  * @param addr binary address
1030  * @param addrlen length of the address
1031  * @return string representing the same address
1032  */
1033 static const char*
1034 unix_address_to_string (void *cls,
1035                        const void *addr,
1036                        size_t addrlen)
1037 {
1038   static char rbuf[INET6_ADDRSTRLEN + 10];
1039   char buf[INET6_ADDRSTRLEN];
1040   const void *sb;
1041   struct in_addr a4;
1042   struct in6_addr a6;
1043   const struct IPv4UdpAddress *t4;
1044   const struct IPv6UdpAddress *t6;
1045   int af;
1046   uint16_t port;
1047
1048   if (addrlen == sizeof (struct IPv6UdpAddress))
1049     {
1050       t6 = addr;
1051       af = AF_INET6;
1052       port = ntohs (t6->u6_port);
1053       memcpy (&a6, &t6->ipv6_addr, sizeof (a6));
1054       sb = &a6;
1055     }
1056   else if (addrlen == sizeof (struct IPv4UdpAddress))
1057     {
1058       t4 = addr;
1059       af = AF_INET;
1060       port = ntohs (t4->u_port);
1061       memcpy (&a4, &t4->ipv4_addr, sizeof (a4));
1062       sb = &a4;
1063     }
1064   else
1065     return NULL;
1066   inet_ntop (af, sb, buf, INET6_ADDRSTRLEN);
1067   GNUNET_snprintf (rbuf,
1068                    sizeof (rbuf),
1069                    "%s:%u",
1070                    buf,
1071                    port);
1072   return rbuf;
1073 }
1074
1075 /**
1076  * The exported method. Makes the core api available via a global and
1077  * returns the unix transport API.
1078  */
1079 void *
1080 libgnunet_plugin_transport_unix_init (void *cls)
1081 {
1082   struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
1083   unsigned long long port;
1084   struct GNUNET_TRANSPORT_PluginFunctions *api;
1085   struct Plugin *plugin;
1086   int sockets_created;
1087
1088   if (GNUNET_OK !=
1089       GNUNET_CONFIGURATION_get_value_number (env->cfg,
1090                                              "transport-unix",
1091                                              "PORT",
1092                                              &port))
1093     port = UNIX_NAT_DEFAULT_PORT;
1094   else if (port > 65535)
1095     {
1096       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1097                   _("Given `%s' option is out of range: %llu > %u\n"),
1098                   "PORT",
1099                   port,
1100                   65535);
1101       return NULL;
1102     }
1103
1104
1105   plugin = GNUNET_malloc (sizeof (struct Plugin));
1106   plugin->port = port;
1107   plugin->env = env;
1108   GNUNET_asprintf(&plugin->unix_socket_path, "/tmp/unix-plugin-sock.%d", plugin->port);
1109
1110   api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions));
1111   api->cls = plugin;
1112
1113   api->send = &unix_plugin_send;
1114   api->disconnect = &unix_disconnect;
1115   api->address_pretty_printer = &unix_plugin_address_pretty_printer;
1116   api->address_to_string = &unix_address_to_string;
1117   api->check_address = &unix_check_address;
1118
1119   add_to_address_list (plugin, plugin->unix_socket_path, strlen(plugin->unix_socket_path) + 1);
1120
1121   sockets_created = unix_transport_server_start (plugin);
1122   if (sockets_created == 0)
1123     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1124                 _("Failed to open UNIX sockets\n"));
1125
1126   plugin->env->notify_address(plugin->env->cls,
1127                               "unix",
1128                               plugin->unix_socket_path,
1129                               strlen(plugin->unix_socket_path) + 1,
1130                               GNUNET_TIME_UNIT_FOREVER_REL);
1131   return api;
1132 }
1133
1134 void *
1135 libgnunet_plugin_transport_unix_done (void *cls)
1136 {
1137   struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
1138   struct Plugin *plugin = api->cls;
1139   struct LocalAddrList *lal;
1140
1141   unix_transport_server_stop (plugin);
1142
1143   GNUNET_NETWORK_fdset_destroy (plugin->rs);
1144   while (NULL != (lal = plugin->lal_head))
1145     {
1146       GNUNET_CONTAINER_DLL_remove (plugin->lal_head,
1147                                    plugin->lal_tail,
1148                                    lal);
1149       GNUNET_free (lal);
1150     }
1151   GNUNET_free (plugin);
1152   GNUNET_free (api);
1153   return NULL;
1154 }
1155
1156 /* end of plugin_transport_unix.c */