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