0001602: A patch to fix process spawning with redirected std streams
[oweals/gnunet.git] / src / transport / plugin_transport_wlan.c
1 /*
2      This file is part of GNUnet
3      (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 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_wlan.c
23  * @brief template for a new transport service
24  * @author Christian Grothoff
25  */
26
27 #include "platform.h"
28 #include "gnunet_protocols.h"
29 #include "gnunet_util_lib.h"
30 #include "gnunet_statistics_service.h"
31 #include "gnunet_transport_service.h"
32 #include "plugin_transport.h"
33
34 #define PROTOCOL_PREFIX "wlan"
35
36 #define DEBUG_wlan GNUNET_NO
37
38 /**
39  * After how long do we expire an address that we
40  * learned from another peer if it is not reconfirmed
41  * by anyone?
42  */
43 #define LEARNED_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 6)
44
45
46 /**
47  * Encapsulation of all of the state of the plugin.
48  */
49 struct Plugin;
50
51
52 /**
53  * Session handle for connections.
54  */
55 struct Session
56 {
57
58   /**
59    * Stored in a linked list.
60    */
61   struct Session *next;
62
63   /**
64    * Pointer to the global plugin struct.
65    */
66   struct Plugin *plugin;
67
68   /**
69    * The client (used to identify this connection)
70    */
71   /* void *client; */
72
73   /**
74    * Continuation function to call once the transmission buffer
75    * has again space available.  NULL if there is no
76    * continuation to call.
77    */
78   GNUNET_TRANSPORT_TransmitContinuation transmit_cont;
79
80   /**
81    * Closure for transmit_cont.
82    */
83   void *transmit_cont_cls;
84
85   /**
86    * To whom are we talking to (set to our identity
87    * if we are still waiting for the welcome message)
88    */
89   struct GNUNET_PeerIdentity sender;
90
91   /**
92    * At what time did we reset last_received last?
93    */
94   struct GNUNET_TIME_Absolute last_quota_update;
95
96   /**
97    * How many bytes have we received since the "last_quota_update"
98    * timestamp?
99    */
100   uint64_t last_received;
101
102   /**
103    * Number of bytes per ms that this peer is allowed
104    * to send to us.
105    */
106   uint32_t quota;
107
108 };
109
110 /**
111  * Encapsulation of all of the state of the plugin.
112  */
113 struct Plugin
114 {
115   /**
116    * Our environment.
117    */
118   struct GNUNET_TRANSPORT_PluginEnvironment *env;
119
120   /**
121    * List of open sessions.
122    * TODO?
123    */
124   struct Session *sessions;
125
126   /**
127    * encapsulation to the local wlan server prog
128    */
129
130   struct GNUNET_SERVER_MessageStreamTokenizer * consoltoken;
131
132   /**
133    * encapsulation of the data
134    */
135
136   struct GNUNET_SERVER_MessageStreamTokenizer * datatoken;
137
138   /**
139    * stdout pipe handle for the gnunet-wlan-helper process
140    */
141   struct GNUNET_DISK_PipeHandle *server_stdout;
142
143   /**
144    * stdout file handle for the gnunet-wlan-helper process
145    */
146   const struct GNUNET_DISK_FileHandle *server_stdout_handle;
147
148   /**
149    * stdin pipe handle for the gnunet-wlan-helper process
150    */
151   struct GNUNET_DISK_PipeHandle *server_stdin;
152
153   /**
154    * stdin file handle for the gnunet-wlan-helper process
155    */
156   const struct GNUNET_DISK_FileHandle *server_stdin_handle;
157
158   /**
159    * ID of select gnunet-nat-server std read task
160    */
161   GNUNET_SCHEDULER_TaskIdentifier server_read_task;
162
163   /**
164    * The process id of the server process (if behind NAT)
165    */
166   pid_t server_pid;
167
168   /**
169    * The interface of the wlan card given to us by the user.
170    */
171   char *interface;
172
173   /**
174    * The mac_address of the wlan card given to us by the helper.
175    */
176   char *mac_address;
177
178 };
179
180 struct Plugin* plugin;
181
182 /**
183  * Function that can be used by the transport service to transmit
184  * a message using the plugin.
185  *
186  * @param cls closure
187  * @param target who should receive this message
188  * @param priority how important is the message
189  * @param msgbuf the message to transmit
190  * @param msgbuf_size number of bytes in 'msgbuf'
191  * @param timeout when should we time out 
192  * @param session which session must be used (or NULL for "any")
193  * @param addr the address to use (can be NULL if the plugin
194  *                is "on its own" (i.e. re-use existing TCP connection))
195  * @param addrlen length of the address in bytes
196  * @param force_address GNUNET_YES if the plugin MUST use the given address,
197  *                otherwise the plugin may use other addresses or
198  *                existing connections (if available)
199  * @param cont continuation to call once the message has
200  *        been transmitted (or if the transport is ready
201  *        for the next transmission call; or if the
202  *        peer disconnected...)
203  * @param cont_cls closure for cont
204  * @return number of bytes used (on the physical network, with overheads);
205  *         -1 on hard errors (i.e. address invalid); 0 is a legal value
206  *         and does NOT mean that the message was not transmitted (DV)
207  */
208 static ssize_t
209 wlan_plugin_send (void *cls,
210                       const struct GNUNET_PeerIdentity *
211                       target,
212                       const char *msgbuf,
213                       size_t msgbuf_size,
214                       unsigned int priority,
215                       struct GNUNET_TIME_Relative timeout,
216                       struct Session *session,
217                       const void *addr,
218                       size_t addrlen,
219                       int force_address,
220                       GNUNET_TRANSPORT_TransmitContinuation
221                       cont, void *cont_cls)
222 {
223   int bytes_sent = 0;
224   /*  struct Plugin *plugin = cls; */
225   return bytes_sent;
226 }
227
228
229
230 /**
231  * Function that can be used to force the plugin to disconnect
232  * from the given peer and cancel all previous transmissions
233  * (and their continuationc).
234  *
235  * @param cls closure
236  * @param target peer from which to disconnect
237  */
238 static void
239 wlan_plugin_disconnect (void *cls,
240                             const struct GNUNET_PeerIdentity *target)
241 {
242   // struct Plugin *plugin = cls;
243   // FIXME
244 }
245
246
247 /**
248  * Convert the transports address to a nice, human-readable
249  * format.
250  *
251  * @param cls closure
252  * @param type name of the transport that generated the address
253  * @param addr one of the addresses of the host, NULL for the last address
254  *        the specific address format depends on the transport
255  * @param addrlen length of the address
256  * @param numeric should (IP) addresses be displayed in numeric form?
257  * @param timeout after how long should we give up?
258  * @param asc function to call on each string
259  * @param asc_cls closure for asc
260  */
261 static void
262 wlan_plugin_address_pretty_printer (void *cls,
263                                     const char *type,
264                                     const void *addr,
265                                     size_t addrlen,
266                                     int numeric,
267                                     struct GNUNET_TIME_Relative timeout,
268                                     GNUNET_TRANSPORT_AddressStringCallback
269                                     asc, void *asc_cls)
270 {
271   char ret[92];
272   const unsigned char * input;
273   
274   GNUNET_assert(cls !=NULL);
275   if (addrlen != 6)
276     {
277       /* invalid address (MAC addresses have 6 bytes) */
278       GNUNET_break (0);
279       asc (asc_cls, NULL);
280       return;
281     }
282   input = (const unsigned char*) addr;
283   GNUNET_snprintf (ret, 
284                    sizeof (ret),
285                    "%s Mac-Adress %X:%X:%X:%X:%X:%X",
286                    PROTOCOL_PREFIX, 
287                    input[0], input[1], input[2], input[3], input[4], input[5]);  
288   asc (asc_cls, ret);
289 }
290
291
292
293 /**
294  * Another peer has suggested an address for this
295  * peer and transport plugin.  Check that this could be a valid
296  * address.  If so, consider adding it to the list
297  * of addresses.
298  *
299  * @param cls closure
300  * @param addr pointer to the address
301  * @param addrlen length of addr
302  * @return GNUNET_OK if this is a plausible address for this peer
303  *         and transport
304  */
305 static int
306 wlan_plugin_address_suggested (void *cls,
307                                    const void *addr,
308                                    size_t addrlen)
309 {
310   /* struct Plugin *plugin = cls; */
311
312   /* check if the address is plausible; if so,
313      add it to our list! */
314
315   GNUNET_assert(cls !=NULL);
316
317   //Mac Adress has 6 bytes
318   if (addrlen == 6){
319     /* TODO check for bad addresses like milticast, broadcast, etc */
320     return GNUNET_OK;
321   } else {
322     return GNUNET_SYSERR;
323   }
324
325 }
326
327
328 /**
329  * Function called for a quick conversion of the binary address to
330  * a numeric address.  Note that the caller must not free the 
331  * address and that the next call to this function is allowed
332  * to override the address again.
333  *
334  * @param cls closure
335  * @param addr binary address
336  * @param addrlen length of the address
337  * @return string representing the same address 
338  */
339 static const char* 
340 wlan_plugin_address_to_string (void *cls,
341                                const void *addr,
342                                size_t addrlen)
343 {
344   char ret[92];
345   const unsigned char * input;
346   
347   GNUNET_assert(cls !=NULL);
348   if (addrlen != 6)
349     {
350       /* invalid address (MAC addresses have 6 bytes) */
351       GNUNET_break (0);
352       return NULL;
353     }
354   input = (const unsigned char*) addr;
355   GNUNET_snprintf (ret, 
356                    sizeof (ret),
357                    "%s Mac-Adress %X:%X:%X:%X:%X:%X",
358                    PROTOCOL_PREFIX, 
359                    input[0], input[1], input[2], input[3], input[4], input[5]);  
360   return GNUNET_strdup (ret);
361 }
362
363
364 #if 0
365 /**
366  * Function for used to process the data from the suid process
367  */
368 static void
369 wlan_process_helper (void *cls,
370                       void *client_identity,
371                       struct GNUNET_MessageHeader *hdr)
372 {
373   if (hdr->type == GNUNET_MESSAGE_TYPE_WLAN_HELPER_DATA){
374     //TODO DATA
375   } else if (hdr->type == GNUNET_MESSAGE_TYPE_WLAN_HELPER_ADVERTISEMENT){
376     //TODO ADV
377   } else if (hdr->type == GNUNET_MESSAGE_TYPE_WLAN_HELPER_CONTROL){
378     //TODO Control
379     if (hdr->size == 6){
380       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Notifying transport of address %s\n", wlan_plugin_address_to_string(cls, plugin->mac_address, hdr->size));
381       plugin->env->notify_address (plugin->env->cls,
382                                       "wlan",
383                                       &plugin->mac_address, sizeof(plugin->mac_address), GNUNET_TIME_UNIT_FOREVER_REL);
384     } else {
385       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Wrong wlan mac address %s\n", plugin->mac_address);
386     }
387
388
389   } else {
390     // TODO Wrong data?
391   }
392 }
393
394
395 static void
396 wlan_plugin_helper_read (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
397 {
398   struct Plugin *plugin = cls;
399   char mybuf[3000]; //max size of packet from helper
400   ssize_t bytes;
401   //memset(&mybuf, 0, sizeof(mybuf)); //?
402
403   if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
404     return;
405
406   bytes = GNUNET_DISK_file_read(plugin->server_stdout_handle, &mybuf, sizeof(mybuf));
407
408   if (bytes < 1)
409     {
410 #if DEBUG_TCP_NAT
411       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
412                       _("Finished reading from wlan-helper stdout with code: %d\n"), bytes);
413 #endif
414       return;
415     }
416
417   plugin->server_read_task =
418   GNUNET_SCHEDULER_add_read_file (plugin->env->sched,
419                                   GNUNET_TIME_UNIT_FOREVER_REL,
420                                   plugin->server_stdout_handle, &wlan_plugin_helper_read, plugin);
421
422 }
423
424
425 /**
426  * Start the gnunet-wlan-helper process for users behind NAT.
427  *
428  * @param plugin the transport plugin
429  *
430  * @return GNUNET_YES if process was started, GNUNET_SYSERR on error
431  */
432 static int
433 wlan_transport_start_wlan_helper(struct Plugin *plugin)
434 {
435
436   plugin->server_stdout = (GNUNET_YES, GNUNET_NO, GNUNET_YES);
437   if (plugin->server_stdout == NULL)
438     return GNUNET_SYSERR;
439
440   plugin->server_stdin = GNUNET_DISK_pipe(GNUNET_YES, GNUNET_YES, GNUNET_NO);
441     if (plugin->server_stdin == NULL)
442       return GNUNET_SYSERR;
443
444 #if DEBUG_TCP_NAT
445   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
446                    "Starting gnunet-wlan-helper process cmd: %s %s\n", "gnunet-wlan-helper", plugin->interface);
447 #endif
448   /* Start the server process */
449   plugin->server_pid = GNUNET_OS_start_process(plugin->server_stdin, plugin->server_stdout, "gnunet-transport-wlan-helper", "gnunet-transport-wlan-helper", plugin->interface, NULL);
450   if (plugin->server_pid == GNUNET_SYSERR)
451     {
452 #if DEBUG_TCP_NAT
453     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
454                      "Failed to start gnunet-wlan-helper process\n");
455 #endif
456       return GNUNET_SYSERR;
457     }
458   /* Close the write end of the read pipe */
459   GNUNET_DISK_pipe_close_end(plugin->server_stdout, GNUNET_DISK_PIPE_END_WRITE);
460
461   /* Close the read end of the write pipe */
462   GNUNET_DISK_pipe_close_end(plugin->server_stdout, GNUNET_DISK_PIPE_END_READ);
463
464   plugin->server_stdout_handle = GNUNET_DISK_pipe_handle(plugin->server_stdout, GNUNET_DISK_PIPE_END_READ);
465   plugin->server_stdin_handle = GNUNET_DISK_pipe_handle(plugin->server_stdin, GNUNET_DISK_PIPE_END_WRITE);
466
467   plugin->server_read_task =
468   GNUNET_SCHEDULER_add_read_file (plugin->env->sched,
469                                   GNUNET_TIME_UNIT_FOREVER_REL,
470                                   plugin->server_stdout_handle, &wlan_plugin_helper_read, plugin);
471   return GNUNET_YES;
472 }
473
474
475
476 #endif
477
478
479 /**
480  * Entry point for the plugin.
481  */
482 void *
483 gnunet_plugin_transport_wlan_init (void *cls)
484 {
485   struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
486   struct GNUNET_TRANSPORT_PluginFunctions *api;
487   struct Plugin *plugin;
488
489   GNUNET_assert(cls !=NULL);
490
491   plugin = GNUNET_malloc (sizeof (struct Plugin));
492   plugin->env = env;
493
494
495   api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions));
496   api->cls = plugin;
497   api->send = &wlan_plugin_send;
498   api->disconnect = &wlan_plugin_disconnect;
499   api->address_pretty_printer = &wlan_plugin_address_pretty_printer;
500   api->check_address = &wlan_plugin_address_suggested;
501   api->address_to_string = &wlan_plugin_address_to_string;
502
503   return api;
504 }
505
506
507 /**
508  * Exit point from the plugin.
509  */
510 void *
511 gnunet_plugin_transport_wlan_done (void *cls)
512 {
513   struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
514   struct Plugin *plugin = api->cls;
515
516   GNUNET_assert(cls !=NULL);
517
518   GNUNET_free (plugin);
519   GNUNET_free (api);
520   return NULL;
521 }
522
523 /* end of plugin_transport_wlan.c */