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