removing legacy send functions from plugins and renaming new send function
[oweals/gnunet.git] / src / transport / plugin_transport_unix.c
1 /*
2      This file is part of GNUnet
3      (C) 2010 Christian Grothoff (and other contributing authors)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20
21 /**
22  * @file transport/plugin_transport_unix.c
23  * @brief Transport plugin using unix domain sockets (!)
24  *        Clearly, can only be used locally on Unix/Linux hosts...
25  *        ONLY INTENDED FOR TESTING!!!
26  * @author Christian Grothoff
27  * @author Nathan Evans
28  */
29
30 #include "platform.h"
31 #include "gnunet_hello_lib.h"
32 #include "gnunet_connection_lib.h"
33 #include "gnunet_container_lib.h"
34 #include "gnunet_os_lib.h"
35 #include "gnunet_peerinfo_service.h"
36 #include "gnunet_protocols.h"
37 #include "gnunet_resolver_service.h"
38 #include "gnunet_server_lib.h"
39 #include "gnunet_signatures.h"
40 #include "gnunet_statistics_service.h"
41 #include "gnunet_transport_service.h"
42 #include "gnunet_transport_plugin.h"
43 #include "transport.h"
44
45 #define DEBUG_UNIX GNUNET_EXTRALOGGING
46 #define DETAILS GNUNET_NO
47
48 #define MAX_PROBES 20
49
50 /*
51  * Transport cost to peer, always 1 for UNIX (direct connection)
52  */
53 #define UNIX_DIRECT_DISTANCE 1
54
55 #define DEFAULT_NAT_PORT 0
56
57 /**
58  * How long until we give up on transmitting the welcome message?
59  */
60 #define HOSTNAME_RESOLVE_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
61
62 /**
63  * Starting port for listening and sending, eventually a config value
64  */
65 #define UNIX_NAT_DEFAULT_PORT 22086
66
67 #define MAX_RETRIES 5
68
69 GNUNET_NETWORK_STRUCT_BEGIN
70
71 /**
72  * UNIX Message-Packet header.
73  */
74 struct UNIXMessage
75 {
76   /**
77    * Message header.
78    */
79   struct GNUNET_MessageHeader header;
80
81   /**
82    * What is the identity of the sender (GNUNET_hash of public key)
83    */
84   struct GNUNET_PeerIdentity sender;
85
86 };
87
88 struct Session
89 {
90   void *addr;
91   size_t addrlen;
92   struct GNUNET_PeerIdentity target;
93 };
94
95 struct UNIXMessageWrapper
96 {
97   struct UNIXMessageWrapper *next;
98   struct UNIXMessageWrapper *prev;
99
100   struct UNIXMessage * msg;
101   size_t msgsize;
102
103   int retry_counter;
104
105   struct GNUNET_TIME_Relative timeout;
106   unsigned int priority;
107
108   struct Session *session;
109   GNUNET_TRANSPORT_TransmitContinuation cont;
110   void *cont_cls;
111 };
112
113 /* Forward definition */
114 struct Plugin;
115
116
117 /**
118  * UNIX NAT "Session"
119  */
120 struct PeerSession
121 {
122
123   /**
124    * Stored in a linked list.
125    */
126   struct PeerSession *next;
127
128   /**
129    * Pointer to the global plugin struct.
130    */
131   struct Plugin *plugin;
132
133   /**
134    * To whom are we talking to (set to our identity
135    * if we are still waiting for the welcome message)
136    */
137   struct GNUNET_PeerIdentity target;
138
139   /**
140    * Address of the other peer (either based on our 'connect'
141    * call or on our 'accept' call).
142    */
143   void *connect_addr;
144
145   /**
146    * Length of connect_addr.
147    */
148   size_t connect_alen;
149
150   /**
151    * Are we still expecting the welcome message? (GNUNET_YES/GNUNET_NO)
152    */
153   int expecting_welcome;
154
155   /**
156    * From which socket do we need to send to this peer?
157    */
158   struct GNUNET_NETWORK_Handle *sock;
159
160   /*
161    * Queue of messages for this peer, in the case that
162    * we have to await a connection...
163    */
164   struct MessageQueue *messages;
165
166 };
167
168 /**
169  * Information we keep for each of our listen sockets.
170  */
171 struct UNIX_Sock_Info
172 {
173   /**
174    * The network handle
175    */
176   struct GNUNET_NETWORK_Handle *desc;
177
178   /**
179    * The port we bound to
180    */
181   uint16_t port;
182 };
183
184
185 /**
186  * Encapsulation of all of the state of the plugin.
187  */
188 struct Plugin
189 {
190   /**
191    * Our environment.
192    */
193   struct GNUNET_TRANSPORT_PluginEnvironment *env;
194
195   /*
196    * Session of peers with whom we are currently connected
197    */
198   struct PeerSession *sessions;
199
200   /*
201    * Sessions
202    */
203   struct GNUNET_CONTAINER_MultiHashMap *session_map;
204
205   /**
206    * ID of task used to update our addresses when one expires.
207    */
208   GNUNET_SCHEDULER_TaskIdentifier address_update_task;
209
210   /**
211    * ID of select task
212    */
213   GNUNET_SCHEDULER_TaskIdentifier select_task;
214
215   /**
216    * Integer to append to unix domain socket.
217    */
218   uint16_t port;
219
220   /**
221    * FD Read set
222    */
223   struct GNUNET_NETWORK_FDSet *rs;
224
225   /**
226    * FD Write set
227    */
228   struct GNUNET_NETWORK_FDSet *ws;
229
230   /**
231    * socket that we transmit all data with
232    */
233   struct UNIX_Sock_Info unix_sock;
234
235   /**
236    * Path of our unix domain socket (/tmp/unix-plugin-PORT)
237    */
238   char *unix_socket_path;
239
240   struct UNIXMessageWrapper *msg_head;
241   struct UNIXMessageWrapper *msg_tail;
242
243   /**
244    * ATS network
245    */
246   struct GNUNET_ATS_Information ats_network;
247 };
248
249
250 static int
251 get_session_delete_it (void *cls, const GNUNET_HashCode * key, void *value)
252 {
253   struct Session *s = value;
254   struct Plugin *plugin = cls;
255   GNUNET_assert (plugin != NULL);
256
257 #if DEBUG_UNIX
258   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleting session for peer `%s' `%s' \n", GNUNET_i2s (&s->target), s->addr);
259 #endif
260
261   plugin->env->session_end (plugin->env->cls, &s->target, s);
262
263   GNUNET_assert (GNUNET_YES ==
264                  GNUNET_CONTAINER_multihashmap_remove(plugin->session_map, &s->target.hashPubKey, s));
265
266   GNUNET_free (s);
267
268   return GNUNET_YES;
269 }
270
271 /**
272  * Disconnect from a remote node.  Clean up session if we have one for this peer
273  *
274  * @param cls closure for this call (should be handle to Plugin)
275  * @param target the peeridentity of the peer to disconnect
276  * @return GNUNET_OK on success, GNUNET_SYSERR if the operation failed
277  */
278 void
279 unix_disconnect (void *cls, const struct GNUNET_PeerIdentity *target)
280 {
281   struct Plugin *plugin = cls;
282   GNUNET_assert (plugin != NULL);
283
284   GNUNET_CONTAINER_multihashmap_get_multiple (plugin->session_map, &target->hashPubKey, &get_session_delete_it, plugin);
285   return;
286 }
287
288 /**
289  * Shutdown the server process (stop receiving inbound traffic). Maybe
290  * restarted later!
291  *
292  * @param cls Handle to the plugin for this transport
293  *
294  * @return returns the number of sockets successfully closed,
295  *         should equal the number of sockets successfully opened
296  */
297 static int
298 unix_transport_server_stop (void *cls)
299 {
300   struct Plugin *plugin = cls;
301
302   struct UNIXMessageWrapper * msgw = plugin->msg_head;
303
304   while (NULL != (msgw = plugin->msg_head))
305   {
306     GNUNET_CONTAINER_DLL_remove (plugin->msg_head, plugin->msg_tail, msgw);
307     if (msgw->cont != NULL)
308       msgw->cont (msgw->cont_cls,  &msgw->session->target, GNUNET_SYSERR);
309     GNUNET_free (msgw->msg);
310     GNUNET_free (msgw);
311   }
312
313   if (plugin->select_task != GNUNET_SCHEDULER_NO_TASK)
314   {
315     GNUNET_SCHEDULER_cancel (plugin->select_task);
316     plugin->select_task = GNUNET_SCHEDULER_NO_TASK;
317   }
318
319   GNUNET_break (GNUNET_OK ==
320                 GNUNET_NETWORK_socket_close (plugin->unix_sock.desc));
321   plugin->unix_sock.desc = NULL;
322
323   return GNUNET_OK;
324 }
325
326
327 struct PeerSession *
328 find_session (struct Plugin *plugin, const struct GNUNET_PeerIdentity *peer)
329 {
330   struct PeerSession *pos;
331
332   pos = plugin->sessions;
333   while (pos != NULL)
334   {
335     if (memcmp (&pos->target, peer, sizeof (struct GNUNET_PeerIdentity)) == 0)
336       return pos;
337     pos = pos->next;
338   }
339
340   return pos;
341 }
342
343
344 /**
345  * Actually send out the message, assume we've got the address and
346  * send_handle squared away!
347  *
348  * @param cls closure
349  * @param incoming_retry_context the retry context to use
350  * @param send_handle which handle to send message on
351  * @param target who should receive this message (ignored by UNIX)
352  * @param msgbuf one or more GNUNET_MessageHeader(s) strung together
353  * @param msgbuf_size the size of the msgbuf to send
354  * @param priority how important is the message (ignored by UNIX)
355  * @param timeout when should we time out (give up) if we can not transmit?
356  * @param addr the addr to send the message to, needs to be a sockaddr for us
357  * @param addrlen the len of addr
358  * @param cont continuation to call once the message has
359  *        been transmitted (or if the transport is ready
360  *        for the next transmission call; or if the
361  *        peer disconnected...)
362  * @param cont_cls closure for cont
363  *
364  * @return the number of bytes written, -1 on errors
365  */
366 static ssize_t
367 unix_real_send (void *cls,
368                 struct GNUNET_NETWORK_Handle *send_handle,
369                 const struct GNUNET_PeerIdentity *target, const char *msgbuf,
370                 size_t msgbuf_size, unsigned int priority,
371                 struct GNUNET_TIME_Relative timeout, const void *addr,
372                 size_t addrlen, GNUNET_TRANSPORT_TransmitContinuation cont,
373                 void *cont_cls)
374 {
375
376   ssize_t sent;
377   const void *sb;
378   size_t sbs;
379   struct sockaddr_un un;
380   size_t slen;
381   int retry;
382
383   if (send_handle == NULL)
384   {
385 #if DEBUG_UNIX
386     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
387                 "unix_real_send with send_handle NULL!\n");
388 #endif
389     /* failed to open send socket for AF */
390     if (cont != NULL)
391       cont (cont_cls, target, GNUNET_SYSERR);
392     return 0;
393   }
394   if ((addr == NULL) || (addrlen == 0))
395   {
396 #if DEBUG_UNIX
397     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
398                 "unix_real_send called without address, returning!\n");
399 #endif
400     if (cont != NULL)
401       cont (cont_cls, target, GNUNET_SYSERR);
402     return 0;                   /* Can never send if we don't have an address!! */
403   }
404
405   memset (&un, 0, sizeof (un));
406   un.sun_family = AF_UNIX;
407   slen = strlen (addr) + 1;
408   if (slen >= sizeof (un.sun_path))
409     slen = sizeof (un.sun_path) - 1;
410   sent = 0;
411   GNUNET_assert (slen < sizeof (un.sun_path));
412   memcpy (un.sun_path, addr, slen);
413   un.sun_path[slen] = '\0';
414   slen = sizeof (struct sockaddr_un);
415 #if LINUX
416   un.sun_path[0] = '\0';
417 #endif
418 #if HAVE_SOCKADDR_IN_SIN_LEN
419   un.sun_len = (u_char) slen;
420 #endif
421   sb = (struct sockaddr *) &un;
422   sbs = slen;
423   retry = GNUNET_NO;
424   sent = GNUNET_NETWORK_socket_sendto (send_handle, msgbuf, msgbuf_size, sb, sbs);
425
426   if ((GNUNET_SYSERR == sent) && ((errno == EAGAIN) || (errno == ENOBUFS)))
427     retry = GNUNET_YES;
428
429   if ((GNUNET_SYSERR == sent) && (errno == EMSGSIZE))
430   {
431     socklen_t size = 0;
432     socklen_t len = sizeof (size);
433
434     GNUNET_NETWORK_socket_getsockopt ((struct GNUNET_NETWORK_Handle *)
435                                       send_handle, SOL_SOCKET, SO_SNDBUF, &size,
436                                       &len);
437
438     if (size < msgbuf_size)
439     {
440 #if DEBUG_UNIX
441       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
442                   "Trying to increase socket buffer size from %i to %i for message size %i\n",
443                   size, ((msgbuf_size / 1000) + 2) * 1000, msgbuf_size);
444 #endif
445       size = ((msgbuf_size / 1000) + 2) * 1000;
446       if (GNUNET_NETWORK_socket_setsockopt
447           ((struct GNUNET_NETWORK_Handle *) send_handle, SOL_SOCKET, SO_SNDBUF,
448            &size, sizeof (size)) == GNUNET_OK)
449         retry = GNUNET_YES;
450       else
451         GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "setsockopt");
452     }
453   }
454
455 #if DEBUG_UNIX
456   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
457               "UNIX transmit %u-byte message to %s (%d: %s)\n",
458               (unsigned int) msgbuf_size, GNUNET_a2s (sb, sbs), (int) sent,
459               (sent < 0) ? STRERROR (errno) : "ok");
460 #endif
461   /* Calling continuation */
462   if (cont != NULL)
463   {
464     if ((sent == GNUNET_SYSERR) && (retry == GNUNET_NO))
465       cont (cont_cls, target, GNUNET_SYSERR);
466     if (sent > 0)
467       cont (cont_cls, target, GNUNET_OK);
468   }
469
470   /* return number of bytes successfully sent */
471   if (sent > 0)
472     return sent;
473   /* failed and retry: return 0 */
474   if ((GNUNET_SYSERR == sent) && (retry == GNUNET_YES))
475     return 0;
476   /* failed and no retry: return -1 */
477   if ((GNUNET_SYSERR == sent) && (retry == GNUNET_NO))
478     return -1;
479
480   return sent;
481 }
482
483 struct gsi_ctx
484 {
485   char *address;
486   size_t addrlen;
487   struct Session *res;
488 };
489
490 static int
491 get_session_it (void *cls, const GNUNET_HashCode * key, void *value)
492 {
493   struct gsi_ctx *gsi = cls;
494   struct Session *s = value;
495
496 #if DEBUG_UNIX
497   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Comparing session %s %s\n", gsi->address, s->addr);
498 #endif
499   if ((gsi->addrlen == s->addrlen) &&
500       (0 == memcmp (gsi->address, s->addr, s->addrlen)))
501   {
502     gsi->res = s;
503     return GNUNET_NO;
504   }
505   return GNUNET_YES;
506 }
507
508 /**
509  * Creates a new outbound session the transport service will use to send data to the
510  * peer
511  *
512  * @param cls the plugin
513  * @param address the address
514  * @return the session or NULL of max connections exceeded
515  */
516 static struct Session *
517 unix_plugin_get_session (void *cls,
518                   const struct GNUNET_HELLO_Address *address)
519 {
520   struct Session * s = NULL;
521   struct Plugin *plugin = cls;
522   struct gsi_ctx gsi;
523
524   /* Checks */
525   GNUNET_assert (plugin != NULL);
526   GNUNET_assert (address != NULL);
527
528   /* Check if already existing */
529   gsi.address = (char *) address->address;
530   gsi.addrlen = address->address_length;
531   gsi.res = NULL;
532   GNUNET_CONTAINER_multihashmap_get_multiple (plugin->session_map, &address->peer.hashPubKey, &get_session_it, &gsi);
533   if (gsi.res != NULL)
534   {
535 #if DEBUG_UNIX
536     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found existing session\n");
537 #endif
538     return gsi.res;
539   }
540
541   /* Create a new session */
542
543   s = GNUNET_malloc (sizeof (struct Session) + address->address_length);
544   s->addr = &s[1];
545   s->addrlen = address->address_length;
546   memcpy(s->addr, address->address, s->addrlen);
547   memcpy(&s->target, &address->peer, sizeof (struct GNUNET_PeerIdentity));
548
549   GNUNET_CONTAINER_multihashmap_put (plugin->session_map,
550       &address->peer.hashPubKey, s,
551       GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
552 #if DEBUG_UNIX
553     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating new session\n");
554 #endif
555
556   return s;
557 }
558
559 /**
560  * Function that can be used by the transport service to transmit
561  * a message using the plugin.   Note that in the case of a
562  * peer disconnecting, the continuation MUST be called
563  * prior to the disconnect notification itself.  This function
564  * will be called with this peer's HELLO message to initiate
565  * a fresh connection to another peer.
566  *
567  * @param cls closure
568  * @param session which session must be used
569  * @param msgbuf the message to transmit
570  * @param msgbuf_size number of bytes in 'msgbuf'
571  * @param priority how important is the message (most plugins will
572  *                 ignore message priority and just FIFO)
573  * @param to how long to wait at most for the transmission (does not
574  *                require plugins to discard the message after the timeout,
575  *                just advisory for the desired delay; most plugins will ignore
576  *                this as well)
577  * @param cont continuation to call once the message has
578  *        been transmitted (or if the transport is ready
579  *        for the next transmission call; or if the
580  *        peer disconnected...); can be NULL
581  * @param cont_cls closure for cont
582  * @return number of bytes used (on the physical network, with overheads);
583  *         -1 on hard errors (i.e. address invalid); 0 is a legal value
584  *         and does NOT mean that the message was not transmitted (DV)
585  */
586 static ssize_t
587 unix_plugin_send (void *cls,
588                   struct Session *session,
589                   const char *msgbuf, size_t msgbuf_size,
590                   unsigned int priority,
591                   struct GNUNET_TIME_Relative to,
592                   GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls)
593 {
594   struct Plugin *plugin = cls;
595   struct UNIXMessageWrapper *wrapper;
596   struct UNIXMessage *message;
597   int ssize;
598
599   GNUNET_assert (plugin != NULL);
600   GNUNET_assert (session != NULL);
601
602   if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_contains_value(plugin->session_map,
603       &session->target.hashPubKey, session))
604   {
605     GNUNET_break (0);
606     return GNUNET_SYSERR;
607   }
608
609   ssize = sizeof (struct UNIXMessage) + msgbuf_size;
610   message = GNUNET_malloc (sizeof (struct UNIXMessage) + msgbuf_size);
611   message->header.size = htons (ssize);
612   message->header.type = htons (0);
613   memcpy (&message->sender, plugin->env->my_identity,
614           sizeof (struct GNUNET_PeerIdentity));
615   memcpy (&message[1], msgbuf, msgbuf_size);
616
617   wrapper = GNUNET_malloc (sizeof (struct UNIXMessageWrapper));
618   wrapper->msg = message;
619   wrapper->msgsize = ssize;
620   wrapper->priority = priority;
621   wrapper->timeout = to;
622   wrapper->cont = cont;
623   wrapper->cont_cls = cont_cls;
624   wrapper->retry_counter = 0;
625   wrapper->session = session;
626
627   GNUNET_CONTAINER_DLL_insert(plugin->msg_head, plugin->msg_tail, wrapper);
628
629 #if DEBUG_UNIX
630   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sent %d bytes to `%s'\n", ssize,
631               (char *) session->addr);
632 #endif
633
634   return ssize;
635 }
636
637
638 /**
639  * Demultiplexer for UNIX messages
640  *
641  * @param plugin the main plugin for this transport
642  * @param sender from which peer the message was received
643  * @param currhdr pointer to the header of the message
644  * @param un the address from which the message was received
645  * @param fromlen the length of the address
646  */
647 static void
648 unix_demultiplexer (struct Plugin *plugin, struct GNUNET_PeerIdentity *sender,
649                     const struct GNUNET_MessageHeader *currhdr,
650                     const struct sockaddr_un *un, size_t fromlen)
651 {
652   struct GNUNET_ATS_Information ats[2];
653
654   ats[0].type = htonl (GNUNET_ATS_QUALITY_NET_DISTANCE);
655   ats[0].value = htonl (UNIX_DIRECT_DISTANCE);
656   ats[1] = plugin->ats_network;
657   GNUNET_break (ntohl(plugin->ats_network.value) != GNUNET_ATS_NET_UNSPECIFIED);
658
659   GNUNET_assert (fromlen >= sizeof (struct sockaddr_un));
660
661 #if DEBUG_UNIX
662   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received message from %s\n",
663               un->sun_path);
664 #endif
665   plugin->env->receive (plugin->env->cls, sender, currhdr,
666                         (const struct GNUNET_ATS_Information *) &ats, 2,
667                         NULL, un->sun_path, strlen (un->sun_path) + 1);
668 }
669
670
671 static void
672 unix_plugin_select_read (struct Plugin * plugin)
673 {
674   char buf[65536];
675   struct UNIXMessage *msg;
676   struct GNUNET_PeerIdentity sender;
677   struct sockaddr_un un;
678   socklen_t addrlen;
679   ssize_t ret;
680   int offset;
681   int tsize;
682   char *msgbuf;
683   const struct GNUNET_MessageHeader *currhdr;
684   uint16_t csize;
685
686   addrlen = sizeof (un);
687   memset (&un, 0, sizeof (un));
688
689   ret =
690       GNUNET_NETWORK_socket_recvfrom (plugin->unix_sock.desc, buf, sizeof (buf),
691                                       (struct sockaddr *) &un, &addrlen);
692
693   if (ret == GNUNET_SYSERR)
694   {
695     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "recvfrom");
696     return;
697   }
698   else
699   {
700 #if LINUX
701     un.sun_path[0] = '/';
702 #endif
703 #if DEBUG_UNIX
704     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Read %d bytes from socket %s\n", ret,
705                 &un.sun_path[0]);
706 #endif
707   }
708
709   GNUNET_assert (AF_UNIX == (un.sun_family));
710
711   msg = (struct UNIXMessage *) buf;
712   csize = ntohs (msg->header.size);
713   if ((csize < sizeof (struct UNIXMessage)) || (csize > ret))
714   {
715     GNUNET_break_op (0);
716     return;
717   }
718   msgbuf = (char *) &msg[1];
719   memcpy (&sender, &msg->sender, sizeof (struct GNUNET_PeerIdentity));
720   offset = 0;
721   tsize = csize - sizeof (struct UNIXMessage);
722   while (offset + sizeof (struct GNUNET_MessageHeader) <= tsize)
723   {
724     currhdr = (struct GNUNET_MessageHeader *) &msgbuf[offset];
725     csize = ntohs (currhdr->size);
726     if ((csize < sizeof (struct GNUNET_MessageHeader)) ||
727         (csize > tsize - offset))
728     {
729       GNUNET_break_op (0);
730       break;
731     }
732     unix_demultiplexer (plugin, &sender, currhdr, &un, sizeof (un));
733     offset += csize;
734   }
735 }
736
737 static void
738 unix_plugin_select_write (struct Plugin * plugin)
739 {
740   int sent = 0;
741   struct UNIXMessageWrapper * msgw = plugin->msg_head;
742
743   sent = unix_real_send (plugin,
744                          plugin->unix_sock.desc,
745                          &msgw->session->target,
746                          (const char *) msgw->msg,
747                          msgw->msgsize,
748                          msgw->priority,
749                          msgw->timeout,
750                          msgw->session->addr,
751                          msgw->session->addrlen,
752                          msgw->cont, msgw->cont_cls);
753
754   /* successfully sent bytes */
755   if (sent > 0)
756   {
757     GNUNET_CONTAINER_DLL_remove(plugin->msg_head, plugin->msg_tail, msgw);
758     GNUNET_free (msgw->msg);
759     GNUNET_free (msgw);
760     return;
761   }
762
763   /* max retries */
764   if (msgw->retry_counter > MAX_RETRIES)
765   {
766     msgw->cont (msgw->cont_cls, &msgw->session->target, GNUNET_SYSERR);
767     GNUNET_CONTAINER_DLL_remove(plugin->msg_head, plugin->msg_tail, msgw);
768     GNUNET_break (0);
769     GNUNET_free (msgw->msg);
770     GNUNET_free (msgw);
771     return;
772   }
773
774   /* failed and no retry */
775   if (sent == -1)
776   {
777     GNUNET_CONTAINER_DLL_remove(plugin->msg_head, plugin->msg_tail, msgw);
778     GNUNET_free (msgw->msg);
779     GNUNET_free (msgw);
780     return;
781   }
782
783   /* failed and retry */
784   if (sent == 0)
785   {
786     msgw->retry_counter++;
787     return;
788   }
789
790 }
791
792 /*
793  * @param cls the plugin handle
794  * @param tc the scheduling context (for rescheduling this function again)
795  *
796  * We have been notified that our writeset has something to read.  We don't
797  * know which socket needs to be read, so we have to check each one
798  * Then reschedule this function to be called again once more is available.
799  *
800  */
801 static void
802 unix_plugin_select (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
803 {
804   struct Plugin *plugin = cls;
805
806   plugin->select_task = GNUNET_SCHEDULER_NO_TASK;
807   if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
808     return;
809
810
811   if ((tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY) != 0)
812   {
813     GNUNET_assert (GNUNET_NETWORK_fdset_isset
814                    (tc->write_ready, plugin->unix_sock.desc));
815     if (plugin->msg_head != NULL)
816       unix_plugin_select_write (plugin);
817   }
818
819   if ((tc->reason & GNUNET_SCHEDULER_REASON_READ_READY) != 0)
820   {
821     GNUNET_assert (GNUNET_NETWORK_fdset_isset
822                    (tc->read_ready, plugin->unix_sock.desc));
823     unix_plugin_select_read (plugin);
824   }
825
826   plugin->select_task =
827       GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
828                                    GNUNET_SCHEDULER_NO_TASK,
829                                    GNUNET_TIME_UNIT_FOREVER_REL, plugin->rs,
830                                    plugin->ws, &unix_plugin_select, plugin);
831 }
832
833 /**
834  * Create a slew of UNIX sockets.  If possible, use IPv6 and IPv4.
835  *
836  * @param cls closure for server start, should be a struct Plugin *
837  * @return number of sockets created or GNUNET_SYSERR on error
838 */
839 static int
840 unix_transport_server_start (void *cls)
841 {
842   struct Plugin *plugin = cls;
843   struct sockaddr *serverAddr;
844   socklen_t addrlen;
845   struct sockaddr_un un;
846   size_t slen;
847
848   memset (&un, 0, sizeof (un));
849   un.sun_family = AF_UNIX;
850   slen = strlen (plugin->unix_socket_path) + 1;
851   if (slen >= sizeof (un.sun_path))
852     slen = sizeof (un.sun_path) - 1;
853
854   memcpy (un.sun_path, plugin->unix_socket_path, slen);
855   un.sun_path[slen] = '\0';
856   slen = sizeof (struct sockaddr_un);
857 #if HAVE_SOCKADDR_IN_SIN_LEN
858   un.sun_len = (u_char) slen;
859 #endif
860
861   serverAddr = (struct sockaddr *) &un;
862   addrlen = slen;
863 #if LINUX
864   un.sun_path[0] = '\0';
865 #endif
866   plugin->ats_network = plugin->env->get_address_type (plugin->env->cls, serverAddr, addrlen);
867   plugin->unix_sock.desc =
868       GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_DGRAM, 0);
869   if (NULL == plugin->unix_sock.desc)
870   {
871     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket");
872     return GNUNET_SYSERR;
873   }
874   if (GNUNET_NETWORK_socket_bind (plugin->unix_sock.desc, serverAddr, addrlen)
875       != GNUNET_OK)
876   {
877     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "bind");
878     GNUNET_NETWORK_socket_close (plugin->unix_sock.desc);
879     plugin->unix_sock.desc = NULL;
880     return GNUNET_SYSERR;
881   }
882 #if DEBUG_UNIX
883   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "unix", "Bound to `%s'\n",
884                    &un.sun_path[0]);
885 #endif
886   plugin->rs = GNUNET_NETWORK_fdset_create ();
887   plugin->ws = GNUNET_NETWORK_fdset_create ();
888   GNUNET_NETWORK_fdset_zero (plugin->rs);
889   GNUNET_NETWORK_fdset_zero (plugin->ws);
890   GNUNET_NETWORK_fdset_set (plugin->rs, plugin->unix_sock.desc);
891   GNUNET_NETWORK_fdset_set (plugin->ws, plugin->unix_sock.desc);
892
893   plugin->select_task =
894       GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
895                                    GNUNET_SCHEDULER_NO_TASK,
896                                    GNUNET_TIME_UNIT_FOREVER_REL, plugin->rs,
897                                    plugin->ws, &unix_plugin_select, plugin);
898   return 1;
899 }
900
901
902 /**
903  * Function that will be called to check if a binary address for this
904  * plugin is well-formed and corresponds to an address for THIS peer
905  * (as per our configuration).  Naturally, if absolutely necessary,
906  * plugins can be a bit conservative in their answer, but in general
907  * plugins should make sure that the address does not redirect
908  * traffic to a 3rd party that might try to man-in-the-middle our
909  * traffic.
910  *
911  * @param cls closure, should be our handle to the Plugin
912  * @param addr pointer to the address
913  * @param addrlen length of addr
914  * @return GNUNET_OK if this is a plausible address for this peer
915  *         and transport, GNUNET_SYSERR if not
916  *
917  */
918 static int
919 unix_check_address (void *cls, const void *addr, size_t addrlen)
920 {
921
922 #if DEBUG_UNIX
923   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
924               "Informing transport service about my address `%s'\n",
925               (char *) addr);
926 #endif
927   return GNUNET_OK;
928 }
929
930
931 /**
932  * Convert the transports address to a nice, human-readable
933  * format.
934  *
935  * @param cls closure
936  * @param type name of the transport that generated the address
937  * @param addr one of the addresses of the host, NULL for the last address
938  *        the specific address format depends on the transport
939  * @param addrlen length of the address
940  * @param numeric should (IP) addresses be displayed in numeric form?
941  * @param timeout after how long should we give up?
942  * @param asc function to call on each string
943  * @param asc_cls closure for asc
944  */
945 static void
946 unix_plugin_address_pretty_printer (void *cls, const char *type,
947                                     const void *addr, size_t addrlen,
948                                     int numeric,
949                                     struct GNUNET_TIME_Relative timeout,
950                                     GNUNET_TRANSPORT_AddressStringCallback asc,
951                                     void *asc_cls)
952 {
953   if ((addr != NULL) && (addrlen > 0))
954     asc (asc_cls, (const char *) addr);
955   else
956   {
957     GNUNET_break (0);
958     asc (asc_cls, "Invalid UNIX address");
959   }
960
961 }
962
963 /**
964  * Function called for a quick conversion of the binary address to
965  * a numeric address.  Note that the caller must not free the
966  * address and that the next call to this function is allowed
967  * to override the address again.
968  *
969  * @param cls closure
970  * @param addr binary address
971  * @param addrlen length of the address
972  * @return string representing the same address
973  */
974 static const char *
975 unix_address_to_string (void *cls, const void *addr, size_t addrlen)
976 {
977   if ((addr != NULL) && (addrlen > 0))
978     return (const char *) addr;
979   else
980     return NULL;
981 }
982
983 /**
984  * Notify transport service about address
985  *
986  * @param cls the plugin
987  * @param tc unused
988  */
989 static void
990 address_notification (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
991 {
992   struct Plugin *plugin = cls;
993
994   plugin->env->notify_address (plugin->env->cls, GNUNET_YES,
995                                plugin->unix_socket_path,
996                                strlen (plugin->unix_socket_path) + 1);
997 }
998
999 /**
1000  * The exported method. Makes the core api available via a global and
1001  * returns the unix transport API.
1002  */
1003 void *
1004 libgnunet_plugin_transport_unix_init (void *cls)
1005 {
1006   struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
1007   unsigned long long port;
1008   struct GNUNET_TRANSPORT_PluginFunctions *api;
1009   struct Plugin *plugin;
1010   int sockets_created;
1011
1012   if (GNUNET_OK !=
1013       GNUNET_CONFIGURATION_get_value_number (env->cfg, "transport-unix", "PORT",
1014                                              &port))
1015     port = UNIX_NAT_DEFAULT_PORT;
1016   plugin = GNUNET_malloc (sizeof (struct Plugin));
1017   plugin->port = port;
1018   plugin->env = env;
1019   GNUNET_asprintf (&plugin->unix_socket_path, "/tmp/unix-plugin-sock.%d",
1020                    plugin->port);
1021
1022   api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions));
1023   api->cls = plugin;
1024
1025   api->get_session = &unix_plugin_get_session;
1026   api->send = &unix_plugin_send;
1027   api->disconnect = &unix_disconnect;
1028   api->address_pretty_printer = &unix_plugin_address_pretty_printer;
1029   api->address_to_string = &unix_address_to_string;
1030   api->check_address = &unix_check_address;
1031   sockets_created = unix_transport_server_start (plugin);
1032   if (sockets_created == 0)
1033     GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Failed to open UNIX sockets\n"));
1034
1035   plugin->session_map = GNUNET_CONTAINER_multihashmap_create(10);
1036
1037   GNUNET_SCHEDULER_add_now (address_notification, plugin);
1038   return api;
1039 }
1040
1041 void *
1042 libgnunet_plugin_transport_unix_done (void *cls)
1043 {
1044   struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
1045   struct Plugin *plugin = api->cls;
1046
1047   unix_transport_server_stop (plugin);
1048
1049   GNUNET_CONTAINER_multihashmap_iterate (plugin->session_map, &get_session_delete_it, plugin);
1050   GNUNET_CONTAINER_multihashmap_destroy (plugin->session_map);
1051
1052   GNUNET_NETWORK_fdset_destroy (plugin->rs);
1053   GNUNET_NETWORK_fdset_destroy (plugin->ws);
1054   GNUNET_free (plugin->unix_socket_path);
1055   GNUNET_free (plugin);
1056   GNUNET_free (api);
1057   return NULL;
1058 }
1059
1060 /* end of plugin_transport_unix.c */