54cc3f8642cf54f20b86e38444d8508a9259e87e
[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 transport plugin for wlan
24  * @author David Brodski
25  */
26
27 #include "platform.h"
28 #include "gnunet_hello_lib.h"
29 #include "gnunet_protocols.h"
30 #include "gnunet_util_lib.h"
31 #include "gnunet_statistics_service.h"
32 #include "gnunet_transport_service.h"
33 #include "plugin_transport.h"
34 #include "plugin_transport_wlan.h"
35 #include "gnunet_common.h"
36 #include "gnunet_crypto_lib.h"
37
38 #define PROTOCOL_PREFIX "wlan"
39
40 /**
41  * Max size of packet from helper
42  */
43 #define WLAN_MTU 3000
44
45 /**
46  * Time until retransmission of a fragment in ms
47  */
48
49 #define FRAGMENT_TIMEOUT 1000
50
51
52 #define DEBUG_wlan GNUNET_NO
53
54 /**
55  * After how long do we expire an address that we
56  * learned from another peer if it is not reconfirmed
57  * by anyone?
58  */
59 #define LEARNED_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 6)
60
61 /**
62  * Initial handshake message for a session.
63  */
64 struct WelcomeMessage
65 {
66   /**
67    * Type is GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME.
68    */
69   struct GNUNET_MessageHeader header;
70
71   /**
72    * Identity of the node connecting (TCP client)
73    */
74   struct GNUNET_PeerIdentity clientIdentity;
75
76 };
77
78 /**
79  * Encapsulation of all of the state of the plugin.
80  */
81 struct Plugin
82 {
83   /**
84    * Our environment.
85    */
86   struct GNUNET_TRANSPORT_PluginEnvironment *env;
87
88   /**
89    * List of open sessions. head
90    */
91   struct Sessionqueue *sessions;
92
93   /**
94    * List of open sessions. tail
95    */
96   struct Sessionqueue *sessions_tail;
97
98   /**
99    * encapsulation to the local wlan server prog
100    */
101
102   struct GNUNET_SERVER_MessageStreamTokenizer * consoltoken;
103
104
105   /**
106    * stdout pipe handle for the gnunet-wlan-helper process
107    */
108   struct GNUNET_DISK_PipeHandle *server_stdout;
109
110   /**
111    * stdout file handle for the gnunet-wlan-helper process
112    */
113   const struct GNUNET_DISK_FileHandle *server_stdout_handle;
114
115   /**
116    * stdin pipe handle for the gnunet-wlan-helper process
117    */
118   struct GNUNET_DISK_PipeHandle *server_stdin;
119
120   /**
121    * stdin file handle for the gnunet-wlan-helper process
122    */
123   const struct GNUNET_DISK_FileHandle *server_stdin_handle;
124
125   /**
126    * ID of select gnunet-nat-server std read task
127    */
128   GNUNET_SCHEDULER_TaskIdentifier server_read_task;
129
130   /**
131      * ID of select gnunet-nat-server std read task
132      */
133   GNUNET_SCHEDULER_TaskIdentifier server_write_task;
134
135   /**
136    * The process id of the server process (if behind NAT)
137    */
138   pid_t server_pid;
139
140   /**
141    * The interface of the wlan card given to us by the user.
142    */
143   char *interface;
144
145   /**
146    * The mac_address of the wlan card given to us by the helper.
147    */
148   char *mac_address;
149
150   /**
151    * Sessions currently pending for transmission
152    * to this peer, if any.
153    */
154   struct Sessionqueue * pending_Sessions;
155
156   /**
157     * Sessions currently pending for transmission
158     * to this peer (tail), if any.
159     */
160   struct Sessionqueue * pending_Sessions_tail;
161
162   /**
163    * number of pending sessions
164    */
165   uint pendingsessions;
166
167 };
168
169 //TODO doxigen
170
171 struct Sessionqueue
172 {
173         struct Sessionqueue * next;
174         struct Sessionqueue * prev;
175         struct Session * content;
176 };
177
178 //TODO doxigen
179
180 struct FragmentQueue
181 {
182         struct FragmentQueue * next;
183         struct FragmentQueue * prev;
184         int fragment_num;
185 };
186
187 /**
188  * Session handle for connections.
189  */
190 struct Session
191 {
192
193   /**
194    * API requirement.
195    */
196   struct SessionHeader header;
197
198   /**
199    * Pointer to the global plugin struct.
200    */
201   struct Plugin *plugin;
202
203   /**
204    * Messages currently pending for transmission
205    * to this peer, if any.
206    */
207   struct PendingMessage *pending_messages_head;
208
209   /**
210    * Messages currently pending for transmission
211    * to this peer, if any.
212    */
213   struct PendingMessage *pending_messages_tail;
214
215   /**
216    * To whom are we talking to (set to our identity
217    * if we are still waiting for the welcome message)
218    */
219   struct GNUNET_PeerIdentity target;
220
221   /**
222    * encapsulation of the data
223    */
224   //struct GNUNET_SERVER_MessageStreamTokenizer * datatoken;
225
226   /**
227    * peer mac address
228    */
229   char addr[6];
230
231   /**
232    * Address of the other peer (either based on our 'connect'
233    * call or on our 'accept' call).
234    */
235   void *connect_addr;
236
237   /**
238    * Last activity on this connection.  Used to select preferred
239    * connection.
240    */
241   struct GNUNET_TIME_Absolute last_activity;
242
243   /**
244    * current number for message incoming , to distinguish between the messages
245    */
246   uint32_t message_id_in;
247
248   /**
249    * current number for message outgoing, to distinguish between the messages
250    */
251   uint32_t message_id_out;
252
253
254 };
255
256 /**
257  * Information kept for each message that is yet to
258  * be transmitted.
259  */
260 struct PendingMessage
261 {
262
263   /**
264    * This is a doubly-linked list.
265    */
266   struct PendingMessage *next;
267
268   /**
269    * This is a doubly-linked list.
270    */
271   struct PendingMessage *prev;
272
273   /**
274    * The pending message
275    */
276   const char *msg;
277
278   /**
279    * Continuation function to call once the message
280    * has been sent.  Can be NULL if there is no
281    * continuation to call.
282    */
283   GNUNET_TRANSPORT_TransmitContinuation transmit_cont;
284
285   /**
286    * Cls for transmit_cont
287    */
288   void * transmit_cont_cls;
289
290   /**
291    * Timeout value for the pending message.
292    */
293   struct GNUNET_TIME_Absolute timeout;
294
295   /**
296    * Timeout value for the pending fragments.
297    * Stores the time when the last msg fragment ack was received
298    */
299   struct GNUNET_TIME_Absolute last_ack;
300
301   /**
302    * Sorted queue with the acks received for fragments; head
303    */
304
305   struct FragmentQueue * head;
306
307   /**
308    * Sorted queue with the acks received for fragments; tail
309    */
310
311   struct FragmentQueue * tail;
312
313   /**
314    * Size of the message
315    */
316   size_t message_size;
317
318   /**
319    * pos / next fragment number in the message, for fragmentation/segmentation,
320    * some acks can be missing but there is still time
321    */
322   uint32_t message_pos;
323 };
324
325
326 /**
327  * Header for messages which need fragmentation
328  */
329 struct WlanHeader
330 {
331
332   struct GNUNET_MessageHeader header;
333
334   /**
335    * checksum/error correction
336    */
337   uint32_t crc GNUNET_PACKED;
338
339   /**
340    * To whom are we talking to (set to our identity
341    * if we are still waiting for the welcome message)
342    */
343   struct GNUNET_PeerIdentity target;
344
345   // followed by payload
346
347 };
348
349 /**
350  * Header for messages which need fragmentation
351  */
352 struct FragmentationHeader
353 {
354
355   struct GNUNET_MessageHeader header;
356
357   /**
358    * To whom are we talking to (set to our identity
359    * if we are still waiting for the welcome message)
360    */
361   // struct GNUNET_PeerIdentity target GNUNET_PACKED;
362
363   /**
364    * ID of message, to distinguish between the messages, picked randomly.
365    */
366   uint32_t message_id GNUNET_PACKED;
367
368   /**
369    * Offset or number of this fragment, for fragmentation/segmentation (design choice, TBD)
370    */
371   uint16_t fragment_off_or_num GNUNET_PACKED;
372
373   /**
374    * CRC of fragment (for error checking)
375    */
376   uint16_t message_crc GNUNET_PACKED;
377
378   /**
379    * Flags
380    * // 0x1 ack => Use two different message types in header.type! (FRAG_MESSAGE; FRAG_ACK)
381    * // 0x2 has data (not only ack)
382    * // 0x4 last fragment of message
383    * // 0x8 new message
384    */
385   //  uint32_t flags GNUNET_PACKED;
386
387   /**
388    * checksum/error correction
389    */
390   // uint32_t crc GNUNET_PACKED;
391
392   // followed by payload unless ACK
393
394 };
395
396 //enum { ACK_FRAGMENT = 1, DATA_FRAGMENT = 2, LAST_FRAGMENT = 4, NEW_MESSAGE = 8 };
397
398 int getRadiotapHeader (struct RadiotapHeader * Header);
399 int getWlanHeader (struct IeeeHeader * Header);
400 static int wlan_plugin_address_suggested (void *cls,
401                                    const void *addr,
402                                    size_t addrlen);
403 uint16_t getcrc16 (const char *msgbuf, size_t msgbuf_size);
404
405 /**
406  * get the next message number, at the moment just a random one
407  *
408  */
409 //TODO doxigen
410 uint32_t
411 get_next_message_id()
412 {
413         return GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX);
414 }
415
416 /**
417  * start next message number generator
418  */
419 //TODO doxigen
420 void
421 start_next_message_id()
422 {
423         //GNUNET_CRYPTO_random_init;
424 }
425
426
427 /**
428  * get Session from address
429  *
430  */
431 //TODO doxigen
432 //TODO add other possibilities to find the right session (are there other?)
433 static struct Session *
434 get_Session (struct Plugin *plugin,
435              const char * addr)
436 {
437         struct Sessionqueue * queue = plugin->sessions;
438         struct Sessionqueue * lastitem = NULL;
439
440
441         //just look at all the session for the needed one
442         while (queue != NULL){
443                 // content is never NULL
444                 GNUNET_assert (queue->content == NULL);
445                 char * addr2 = queue->content->addr;
446                 if (memcmp(addr, addr2, 6) == 0)
447                   {
448                     //sesion found
449                     return queue->content;
450                   }
451                 // try next
452                 lastitem = queue;
453                 queue = queue->next;
454         }
455         // new session
456         queue = GNUNET_malloc (sizeof (struct Sessionqueue));
457
458         GNUNET_CONTAINER_DLL_insert(plugin->sessions, plugin->sessions_tail, queue);
459
460         queue->content = GNUNET_malloc (sizeof (struct Session));
461         queue->content->plugin = plugin;
462         memcpy(queue->content->addr, addr, 6);
463         queue->content->message_id_out = get_next_message_id();
464
465         //queue welcome message for new sessions, not realy needed
466         //struct WelcomeMessage welcome;
467         struct PendingMessage *pm;
468         pm = GNUNET_malloc (sizeof (struct PendingMessage) + GNUNET_HELLO_size(* (plugin->env->our_hello)));
469         pm->msg = (const char*) &pm[1];
470         pm->message_size = GNUNET_HELLO_size(* (plugin->env->our_hello));
471         //welcome.header.size = htons (GNUNET_HELLO_size(* (plugin->env->our_hello)));
472         //welcome.header.type = htons (GNUNET_MESSAGE_TYPE_WLAN_ADVERTISEMENT);
473         //welcome.clientIdentity = *plugin->env->my_identity;
474         memcpy (&pm[1], * plugin->env->our_hello, GNUNET_HELLO_size(* (plugin->env->our_hello)));
475         pm->timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
476         GNUNET_CONTAINER_DLL_insert ((queue->content)->pending_messages_head,
477                                            (queue->content)->pending_messages_tail,
478                                        pm);
479         plugin->pendingsessions ++;
480         GNUNET_CONTAINER_DLL_insert_after(plugin->pending_Sessions, plugin->pending_Sessions_tail, plugin->pending_Sessions_tail, queue);
481         return queue->content;
482
483 }
484
485 /**
486  * Queue the session to send data
487  */
488 //TODO doxigen
489 static void
490 queue_Session (struct Plugin *plugin,
491                 struct Session * session)
492 {
493         struct Sessionqueue * queue = plugin->pending_Sessions;
494         struct Sessionqueue * lastitem = NULL;
495
496         while (queue != NULL){
497                 // content is never NULL
498                 GNUNET_assert (queue->content == NULL);
499                 // is session already in queue?
500                 if (session == queue->content){
501                         return;
502                 }
503                 // try next
504                 lastitem = queue;
505                 queue = queue->next;
506         }
507
508         // Session is not in the queue
509
510         queue = GNUNET_malloc (sizeof (struct Sessionqueue));
511         queue->content = session;
512
513         //insert at the tail
514         GNUNET_CONTAINER_DLL_insert_after (plugin->pending_Sessions,
515                         plugin->pending_Sessions_tail,
516                         plugin->pending_Sessions_tail, queue);
517         plugin->pendingsessions ++;
518
519 }
520
521 //TODO doxigen
522 static void
523 free_acks (struct PendingMessage * pm){
524         struct FragmentQueue * fq;
525         while (pm->head != NULL){
526                 fq = pm->head;
527                 GNUNET_CONTAINER_DLL_remove(pm->head, pm->tail, fq);
528                 GNUNET_free(fq);
529         }
530 }
531
532 /**
533  * Function called to when wlan helper is ready to get some data
534  *
535  * @param cls closure
536  * @param GNUNET_SCHEDULER_TaskContext
537  */
538
539 static void
540 do_transmit (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
541 {
542   struct Plugin * plugin = cls;
543   ssize_t bytes;
544
545   if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
546     return;
547
548   struct Session * session;
549   struct Sessionqueue * queue;
550   struct PendingMessage * pm;
551   struct IeeeHeader * wlanheader;
552   struct RadiotapHeader * radioHeader;
553   struct GNUNET_MessageHeader * msgheader;
554   struct FragmentationHeader fragheader;
555   uint16_t size = 0;
556   const char * copystart = NULL;
557   uint16_t copysize = 0;
558   uint copyoffset = 0;
559   struct FragmentQueue * akt = NULL;
560   int exit = 0;
561
562   int i = 0;
563
564   struct GNUNET_TIME_Absolute nextsend;
565   struct GNUNET_TIME_Relative timeout;
566   struct Sessionqueue * nextsession = NULL;
567
568   timeout.rel_value = FRAGMENT_TIMEOUT;
569   nextsend = GNUNET_TIME_absolute_get_forever();
570
571   queue = plugin->pending_Sessions;
572
573   // check if the are some pending sessions/messages ...
574   GNUNET_assert(queue != NULL);
575
576   session = queue->content;
577   GNUNET_assert(session != NULL);
578
579   pm = session->pending_messages_head;
580   GNUNET_assert(pm != NULL);
581
582   // get next valid session
583   // check if this session is only waiting to receive the acks for an already send fragments to finish it
584   // timeout is not reached
585   for (i = 0; i < plugin->pendingsessions; i++){
586
587           // check if the are some pending sessions/messages ...
588           GNUNET_assert(queue != NULL);
589
590           session = queue->content;
591           GNUNET_assert(session != NULL);
592
593           pm = session->pending_messages_head;
594           GNUNET_assert(pm != NULL);
595
596           //save next session
597           nextsession = queue->next;
598           // test if message timed out
599           while (GNUNET_TIME_absolute_get_remaining(pm->timeout).rel_value == 0){
600                   //remove message
601                   //free the acks
602                   free_acks (pm);
603                   //call the cont func that it did not work
604                   if (pm->transmit_cont != NULL)
605                           pm->transmit_cont (pm->transmit_cont_cls,
606                                                 &(session->target), GNUNET_SYSERR);
607                   //remove the message
608                   GNUNET_CONTAINER_DLL_remove (session->pending_messages_head,
609                                                                           session->pending_messages_tail,
610                                                                           pm);
611                   GNUNET_free(pm);
612
613                   //test if there are no more messages pending for this session
614                   if (session->pending_messages_head == NULL){
615
616                           //test if tail is null too
617                           GNUNET_assert(session->pending_messages_tail == NULL);
618
619                           plugin->pendingsessions --;
620                           GNUNET_CONTAINER_DLL_remove (plugin->pending_Sessions, plugin->pending_Sessions_tail, queue);
621                           GNUNET_free(queue);
622                           queue = NULL;
623                           break;
624
625                   } else {
626                           pm = session->pending_messages_head;
627                   }
628
629           }
630           // restore next session if necessary
631           if (queue == NULL){
632                   queue = nextsession;
633                   nextsession = NULL;
634                   //there are no more messages in this session
635                   continue;
636           }
637           nextsession = NULL;
638
639           // test if retransmit is needed
640           if (GNUNET_TIME_absolute_get_duration(pm->last_ack).rel_value < FRAGMENT_TIMEOUT) {
641                   // get last offset for this message
642                   copyoffset = pm->message_size /(WLAN_MTU - sizeof(struct FragmentationHeader));
643                   // one more is the end
644                   copyoffset ++;
645                   // test if it is not the end
646                   if (copyoffset > pm->message_pos){
647                           nextsession = queue;
648                           break;
649                   }
650
651                   nextsend = GNUNET_TIME_absolute_min(GNUNET_TIME_absolute_add(pm->last_ack, timeout), nextsend);
652
653                   GNUNET_CONTAINER_DLL_remove (plugin->pending_Sessions, plugin->pending_Sessions_tail, queue);
654                   //insert at the tail
655                   GNUNET_CONTAINER_DLL_insert_after (plugin->pending_Sessions,
656                                   plugin->pending_Sessions_tail,
657                                   plugin->pending_Sessions_tail, queue);
658
659                   //get next pending session
660                   queue = queue->next;
661
662           } else {
663                   // retransmit
664                   nextsession = queue;
665                   break;
666           }
667   }
668
669
670   //test if there is one session to send something
671   if (nextsession != NULL){
672           queue = nextsession;
673
674             // check if the are some pending sessions/messages ...
675             GNUNET_assert(queue != NULL);
676
677             session = queue->content;
678             GNUNET_assert(session != NULL);
679
680             pm = session->pending_messages_head;
681             GNUNET_assert(pm != NULL);
682   } else {
683           //nothing to send at the moment
684           plugin->server_read_task =
685                           GNUNET_SCHEDULER_add_delayed (plugin->env->sched,
686                                           GNUNET_TIME_absolute_get_remaining(nextsend),
687                                           &do_transmit, plugin);
688
689   }
690
691
692
693   if (pm->message_size > WLAN_MTU) {
694         size += sizeof(struct FragmentationHeader);
695         // check for retransmission
696         if (GNUNET_TIME_absolute_get_duration(pm->last_ack).rel_value > FRAGMENT_TIMEOUT) {
697                 // TODO retransmit
698                 // be positive and try again later :-D
699                 pm->last_ack = GNUNET_TIME_absolute_get();
700                 // find first missing fragment
701                 exit = 0;
702                 akt = pm->head;
703                 pm->message_pos = 0;
704
705                 //test if ack 0 was already received
706                 while (akt != NULL){
707                         //if fragment is present, take next
708                         if (akt->fragment_num == pm->message_pos) {
709                                 pm->message_pos ++;
710                         }
711                         //next ack is bigger then the fragment number
712                         //in case there is something like this: (acks) 1, 2, 5, 6, ...
713                         //and we send 3 again, the next number should be 4
714                         if (akt->fragment_num > pm->message_pos) {
715                                                                 break;
716                                                         }
717
718                         akt = akt->next;
719
720                 }
721
722
723         }
724
725         copyoffset = (WLAN_MTU - sizeof(struct FragmentationHeader)) * pm->message_pos;
726         fragheader.fragment_off_or_num = pm->message_pos;
727         fragheader.message_id = session->message_id_out;
728
729         // start should be smaller then the packet size
730         //TODO send some other data if everything was send but not all acks are present
731         GNUNET_assert(copyoffset < pm->message_size);
732         copystart = pm->msg + copyoffset;
733
734         //size of the fragment is either the MTU - overhead
735         //or the missing part of the message in case this is the last fragment
736         copysize = GNUNET_MIN(pm->message_size - copyoffset,
737                         WLAN_MTU - sizeof(struct FragmentationHeader));
738         fragheader.header.size = copysize;
739         fragheader.header.type = GNUNET_MESSAGE_TYPE_WLAN_FRAGMENT;
740
741         //get the next missing fragment
742         exit = 0;
743         akt = pm->head;
744         pm->message_pos ++;
745
746         //test if ack was already received
747         while (akt != NULL){
748                 //if fragment is present, take next
749                 if (akt->fragment_num == pm->message_pos) {
750                         pm->message_pos ++;
751                 }
752                 //next ack is bigger then the fragment number
753                 //in case there is something like this: (acks) 1, 2, 5, 6, ...
754                 //and we send 3 again, the next number should be 4
755                 if (akt->fragment_num > pm->message_pos) {
756                                                         break;
757                                                 }
758
759                 akt = akt->next;
760         }
761
762
763         } else {
764         // there is no need to split
765         copystart = pm->msg;
766         copysize = pm->message_size;
767         }
768   size += copysize;
769   size += sizeof(struct RadiotapHeader) + sizeof(struct IeeeHeader)
770                         + sizeof(struct GNUNET_MessageHeader);
771   msgheader = GNUNET_malloc(size);
772   msgheader->size = htons(size - sizeof(struct GNUNET_MessageHeader));
773   msgheader->type = GNUNET_MESSAGE_TYPE_WLAN_HELPER_DATA;
774
775   radioHeader = (struct RadiotapHeader*) &msgheader[1];
776   getRadiotapHeader(radioHeader);
777
778   wlanheader = (struct IeeeHeader *) &radioHeader[1];
779   getWlanHeader(wlanheader);
780
781
782   //could be faster if content is just send and not copyed before
783   //fragmentheader is needed
784   if (pm->message_size > WLAN_MTU){
785   fragheader.message_crc = getcrc16(copystart, copysize);
786   memcpy(&wlanheader[1],&fragheader, sizeof(struct FragmentationHeader));
787   memcpy(&wlanheader[1] + sizeof(struct FragmentationHeader),copystart,copysize);
788   } else {
789   memcpy(&wlanheader[1],copystart,copysize);
790   }
791
792   bytes = GNUNET_DISK_file_write(plugin->server_stdin_handle, msgheader, size);
793
794
795
796
797
798
799
800
801   if (bytes < 1)
802     {
803       return;
804     }
805
806   //plugin->server_read_task =
807   //GNUNET_SCHEDULER_add_read_file (plugin->env->sched,
808   //                                GNUNET_TIME_UNIT_FOREVER_REL,
809   //                                plugin->server_stdout_handle, &wlan_plugin_helper_read, plugin);
810
811 }
812
813
814
815 /**
816  * If we have pending messages, ask the server to
817  * transmit them (schedule the respective tasks, etc.)
818  *
819  * @param Plugin env to get everything needed
820  */
821 static void
822 process_pending_messages (struct Plugin * plugin)
823 {
824   struct Sessionqueue * queue;
825   struct Session * session;
826
827   if (plugin->pending_Sessions == NULL)
828     return;
829
830   queue = plugin->pending_Sessions;
831   //contet should not be empty
832   GNUNET_assert(queue->content != NULL);
833
834   session = queue->content;
835   //pending sessions should have some msg
836   GNUNET_assert(session->pending_messages_head != NULL);
837
838   // GNUNET_TIME_UNIT_FOREVER_REL is needed to clean up old msg
839   plugin->server_write_task
840     = GNUNET_SCHEDULER_add_write_file(plugin->env->sched,
841                                                                                         GNUNET_TIME_UNIT_FOREVER_REL,
842                                                                                         plugin->server_stdin_handle,
843                                            &do_transmit,
844                                            plugin);
845 }
846
847
848 /**
849  * 32bit CRC
850  *
851  * @param msgbuf pointer tor the data
852  * @param msgbuf_size size of the data
853  *
854  * @return 32bit crc value
855  */
856
857 uint32_t
858 getcrc32 (const char *msgbuf,
859                   size_t msgbuf_size){
860         //TODO calc some crc
861         return 0;
862 }
863
864 /**
865  * 16bit CRC
866  *
867  * @param msgbuf pointer tor the data
868  * @param msgbuf_size size of the data
869  *
870  * @return 16bit crc value
871  */
872
873 uint16_t
874 getcrc16 (const char *msgbuf,
875                   size_t msgbuf_size){
876         //TODO calc some crc
877         return 0;
878 }
879
880 /**
881  * Function that can be used by the transport service to transmit
882  * a message using the plugin.
883  *
884  * @param cls closure
885  * @param target who should receive this message
886  * @param priority how important is the message
887  * @param msgbuf the message to transmit
888  * @param msgbuf_size number of bytes in 'msgbuf'
889  * @param timeout when should we time out 
890  * @param session which session must be used (or NULL for "any")
891  * @param addr the address to use (can be NULL if the plugin
892  *                is "on its own" (i.e. re-use existing TCP connection))
893  * @param addrlen length of the address in bytes
894  * @param force_address GNUNET_YES if the plugin MUST use the given address,
895  *                otherwise the plugin may use other addresses or
896  *                existing connections (if available)
897  * @param cont continuation to call once the message has
898  *        been transmitted (or if the transport is ready
899  *        for the next transmission call; or if the
900  *        peer disconnected...)
901  * @param cont_cls closure for cont
902  * @return number of bytes used (on the physical network, with overheads);
903  *         -1 on hard errors (i.e. address invalid); 0 is a legal value
904  *         and does NOT mean that the message was not transmitted (DV)
905  */
906 static ssize_t
907 wlan_plugin_send (void *cls,
908                   const struct GNUNET_PeerIdentity * target,
909                   const char *msgbuf,
910                   size_t msgbuf_size,
911                   unsigned int priority,
912                   struct GNUNET_TIME_Relative timeout,
913                   struct Session *session,
914                   const void *addr,
915                   size_t addrlen,
916                   int force_address,
917                   GNUNET_TRANSPORT_TransmitContinuation cont,
918                   void *cont_cls)
919 {
920   struct Plugin * plugin = cls;
921   struct PendingMessage * newmsg = NULL;
922   struct WlanHeader * wlanheader = NULL;
923   //check if msglen > 0
924   GNUNET_assert(msgbuf_size > 0);
925
926   //get session if needed
927   if (session == NULL) {
928           if ( wlan_plugin_address_suggested(plugin , addr, addrlen) == GNUNET_OK){
929                   session = get_Session(plugin, addr);
930           } else {
931                   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
932                                         _("Wlan Address len %d is wrong\n"),
933                                          addrlen);
934                   return -1;
935           }
936   }
937
938   //TODO target "problem" not solved
939   session->target = *target;
940
941   //queue message:
942   //first queue session
943   queue_Session(plugin, session);
944
945   //queue message in session
946   newmsg = GNUNET_malloc(sizeof(struct PendingMessage) + msgbuf_size + sizeof(struct WlanHeader));
947   newmsg->msg = (const char*) &newmsg[1];
948   wlanheader = (struct WlanHeader *) &newmsg[1];
949   //copy msg to buffer, not fragmented / segmented yet, but with message header
950   wlanheader->header.size = msgbuf_size;
951   wlanheader->header.type = GNUNET_MESSAGE_TYPE_WLAN_DATA;
952   wlanheader->target = *target;
953   wlanheader->crc = getcrc32(msgbuf, msgbuf_size);
954   memcpy(&wlanheader[1], msgbuf, msgbuf_size);
955   newmsg->transmit_cont = cont;
956   newmsg->transmit_cont_cls = cont_cls;
957   newmsg->timeout = GNUNET_TIME_relative_to_absolute(timeout);
958   newmsg->message_pos = 0;
959   newmsg->message_size = msgbuf_size + sizeof(struct WlanHeader);
960   newmsg->next = NULL;
961
962   //check if queue is empty
963   struct PendingMessage * tailmsg;
964   tailmsg = session->pending_messages_tail;
965
966   //new tail is the new msg
967   session->pending_messages_tail = newmsg;
968   newmsg->prev = tailmsg;
969
970   //test if tail was not NULL (queue is empty)
971   if (tailmsg == NULL){
972           // head should be NULL too
973           GNUNET_assert(session->pending_messages_head == NULL);
974
975           session->pending_messages_head = newmsg;
976
977   } else {
978           //next at the tail should be NULL
979           GNUNET_assert(tailmsg->next == NULL);
980
981           //queue the msg
982           tailmsg->next = newmsg;
983   }
984
985   process_pending_messages(plugin);
986
987
988   //FIXME not the correct size
989   return msgbuf_size;
990
991 }
992
993
994
995 /**
996  * Function that can be used to force the plugin to disconnect
997  * from the given peer and cancel all previous transmissions
998  * (and their continuation).
999  *
1000  * @param cls closure
1001  * @param target peer from which to disconnect
1002  */
1003 static void
1004 wlan_plugin_disconnect (void *cls,
1005                             const struct GNUNET_PeerIdentity *target)
1006 {
1007         struct Plugin *plugin = cls;
1008         struct Sessionqueue * queue = plugin->sessions;
1009         struct Sessionqueue * lastitem = NULL;
1010         struct PendingMessage * pm;
1011
1012         // just look at all the session for the needed one
1013         while (queue != NULL){
1014                 // content is never NULL
1015                 GNUNET_assert (queue->content == NULL);
1016                 if (memcmp(target, &(queue->content->target), sizeof(struct GNUNET_PeerIdentity)) == 0)
1017                   {
1018                         // sesion found
1019                         // remove PendingMessage
1020                         while (queue->content->pending_messages_head != NULL){
1021                                 pm = queue->content->pending_messages_head;
1022                                 free_acks(pm);
1023                                 GNUNET_CONTAINER_DLL_remove(queue->content->pending_messages_head,queue->content->pending_messages_tail, pm);
1024                                 GNUNET_free(pm);
1025
1026                         }
1027
1028                         GNUNET_free(queue->content);
1029                         GNUNET_CONTAINER_DLL_remove(plugin->sessions, plugin->sessions_tail, queue);
1030                         GNUNET_free(queue);
1031
1032                         return;
1033                   }
1034                 // try next
1035                 lastitem = queue;
1036                 queue = queue->next;
1037         }
1038 }
1039
1040
1041 /**
1042  * Convert the transports address to a nice, human-readable
1043  * format.
1044  *
1045  * @param cls closure
1046  * @param type name of the transport that generated the address
1047  * @param addr one of the addresses of the host, NULL for the last address
1048  *        the specific address format depends on the transport
1049  * @param addrlen length of the address
1050  * @param numeric should (IP) addresses be displayed in numeric form?
1051  * @param timeout after how long should we give up?
1052  * @param asc function to call on each string
1053  * @param asc_cls closure for asc
1054  */
1055 static void
1056 wlan_plugin_address_pretty_printer (void *cls,
1057                                     const char *type,
1058                                     const void *addr,
1059                                     size_t addrlen,
1060                                     int numeric,
1061                                     struct GNUNET_TIME_Relative timeout,
1062                                     GNUNET_TRANSPORT_AddressStringCallback
1063                                     asc, void *asc_cls)
1064 {
1065   char ret[92];
1066   const unsigned char * input;
1067   
1068   GNUNET_assert(cls !=NULL);
1069   if (addrlen != 6)
1070     {
1071       /* invalid address (MAC addresses have 6 bytes) */
1072       GNUNET_break (0);
1073       asc (asc_cls, NULL);
1074       return;
1075     }
1076   input = (const unsigned char*) addr;
1077   GNUNET_snprintf (ret, 
1078                    sizeof (ret),
1079                    "%s Mac-Adress %X:%X:%X:%X:%X:%X",
1080                    PROTOCOL_PREFIX, 
1081                    input[0], input[1], input[2], input[3], input[4], input[5]);  
1082   asc (asc_cls, ret);
1083 }
1084
1085
1086
1087 /**
1088  * Another peer has suggested an address for this
1089  * peer and transport plugin.  Check that this could be a valid
1090  * address.  If so, consider adding it to the list
1091  * of addresses.
1092  *
1093  * @param cls closure
1094  * @param addr pointer to the address
1095  * @param addrlen length of addr
1096  * @return GNUNET_OK if this is a plausible address for this peer
1097  *         and transport
1098  */
1099
1100
1101 static int
1102 wlan_plugin_address_suggested (void *cls,
1103                                    const void *addr,
1104                                    size_t addrlen)
1105 {
1106   //struct Plugin *plugin = cls;
1107
1108   /* check if the address is plausible; if so,
1109      add it to our list! */
1110
1111   GNUNET_assert(cls !=NULL);
1112   //FIXME mitm is not checked
1113   //Mac Adress has 6 bytes
1114   if (addrlen == 6){
1115     /* TODO check for bad addresses like milticast, broadcast, etc */
1116     return GNUNET_OK;
1117   } else {
1118     return GNUNET_SYSERR;
1119   }
1120
1121   return GNUNET_SYSERR;
1122 }
1123
1124
1125 /**
1126  * Function called for a quick conversion of the binary address to
1127  * a numeric address.  Note that the caller must not free the 
1128  * address and that the next call to this function is allowed
1129  * to override the address again.
1130  *
1131  * @param cls closure
1132  * @param addr binary address
1133  * @param addrlen length of the address
1134  * @return string representing the same address 
1135  */
1136 static const char* 
1137 wlan_plugin_address_to_string (void *cls,
1138                                const void *addr,
1139                                size_t addrlen)
1140 {
1141   char ret[92];
1142   const unsigned char * input;
1143   
1144   GNUNET_assert(cls !=NULL);
1145   if (addrlen != 6)
1146     {
1147       /* invalid address (MAC addresses have 6 bytes) */
1148       GNUNET_break (0);
1149       return NULL;
1150     }
1151   input = (const unsigned char*) addr;
1152   GNUNET_snprintf (ret, 
1153                    sizeof (ret),
1154                    "%s Mac-Adress %X:%X:%X:%X:%X:%X",
1155                    PROTOCOL_PREFIX, 
1156                    input[0], input[1], input[2], input[3], input[4], input[5]);  
1157   return GNUNET_strdup (ret);
1158 }
1159
1160
1161
1162 /**
1163  * Function used for to process the data from the suid process
1164  */
1165 //TODO doxigen
1166
1167 static void
1168 wlan_process_helper (void *cls,
1169                       void *client,
1170                       const struct GNUNET_MessageHeader *hdr)
1171 {
1172   struct Plugin *plugin = cls;
1173   if (hdr->type == GNUNET_MESSAGE_TYPE_WLAN_HELPER_DATA){
1174     //TODO DATA
1175   } else if (hdr->type == GNUNET_MESSAGE_TYPE_WLAN_ADVERTISEMENT){
1176     //TODO ADV
1177   } else if (hdr->type == GNUNET_MESSAGE_TYPE_WLAN_HELPER_CONTROL){
1178     //TODO Control
1179     if (hdr->size == 6){
1180       plugin->mac_address = GNUNET_malloc(6);
1181       memcpy(plugin->mac_address, &hdr[1],6);
1182       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Notifying transport of address %s\n", wlan_plugin_address_to_string(cls, plugin->mac_address, hdr->size));
1183       plugin->env->notify_address (plugin->env->cls,
1184                                       "wlan",
1185                                       &plugin->mac_address, sizeof(plugin->mac_address),
1186                                       GNUNET_TIME_UNIT_FOREVER_REL);
1187     } else {
1188       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Wrong wlan mac address %s\n", plugin->mac_address);
1189     }
1190
1191
1192   } else {
1193     // TODO Wrong data?
1194   }
1195 }
1196
1197
1198 static void
1199 wlan_plugin_helper_read (void *cls,
1200                          const struct GNUNET_SCHEDULER_TaskContext *tc)
1201 {
1202   struct Plugin *plugin = cls;
1203   char mybuf[WLAN_MTU]; 
1204   ssize_t bytes;
1205
1206   if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
1207     return;
1208   bytes = GNUNET_DISK_file_read (plugin->server_stdout_handle, 
1209                                  mybuf, sizeof(mybuf));
1210   if (bytes <= 0)
1211     {
1212 #if DEBUG_TCP_NAT
1213       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1214                       _("Finished reading from wlan-helper stdout with code: %d\n"), bytes);
1215 #endif
1216       return;
1217     }
1218   GNUNET_SERVER_mst_receive(plugin->consoltoken, NULL,
1219                             mybuf, bytes, 0, GNUNET_NO);
1220
1221 }
1222
1223
1224 /**
1225  * Start the gnunet-wlan-helper process.
1226  *
1227  * @param plugin the transport plugin
1228  *
1229  * @return GNUNET_YES if process was started, GNUNET_SYSERR on error
1230  */
1231 static int
1232 wlan_transport_start_wlan_helper (struct Plugin *plugin)
1233 {
1234
1235   plugin->server_stdout = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_NO, GNUNET_YES);
1236   if (plugin->server_stdout == NULL)
1237     return GNUNET_SYSERR;
1238
1239   plugin->server_stdin = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO);
1240     if (plugin->server_stdin == NULL)
1241       return GNUNET_SYSERR;
1242
1243 #if DEBUG_TCP_NAT
1244   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1245                    "Starting gnunet-wlan-helper process cmd: %s %s\n", "gnunet-wlan-helper", plugin->interface);
1246 #endif
1247   /* Start the server process */
1248   plugin->server_pid = GNUNET_OS_start_process(plugin->server_stdin, plugin->server_stdout, "gnunet-transport-wlan-helper", "gnunet-transport-wlan-helper", plugin->interface, NULL);
1249   if (plugin->server_pid == GNUNET_SYSERR)
1250     {
1251 #if DEBUG_TCP_NAT
1252     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1253                      "Failed to start gnunet-wlan-helper process\n");
1254 #endif
1255       return GNUNET_SYSERR;
1256     }
1257   /* Close the write end of the read pipe */
1258   GNUNET_DISK_pipe_close_end(plugin->server_stdout, GNUNET_DISK_PIPE_END_WRITE);
1259
1260   /* Close the read end of the write pipe */
1261   GNUNET_DISK_pipe_close_end(plugin->server_stdin, GNUNET_DISK_PIPE_END_READ);
1262
1263   plugin->server_stdout_handle = GNUNET_DISK_pipe_handle(plugin->server_stdout, GNUNET_DISK_PIPE_END_READ);
1264   plugin->server_stdin_handle = GNUNET_DISK_pipe_handle(plugin->server_stdin, GNUNET_DISK_PIPE_END_WRITE);
1265
1266   plugin->server_read_task =
1267   GNUNET_SCHEDULER_add_read_file (plugin->env->sched,
1268                                   GNUNET_TIME_UNIT_FOREVER_REL,
1269                                   plugin->server_stdout_handle, &wlan_plugin_helper_read, plugin);
1270   return GNUNET_YES;
1271 }
1272
1273
1274
1275 /**
1276  * Entry point for the plugin.
1277  *
1278  * @param cls closure, the 'struct GNUNET_TRANSPORT_PluginEnvironment*'
1279  * @return the 'struct GNUNET_TRANSPORT_PluginFunctions*' or NULL on error
1280  */
1281 void *
1282 gnunet_plugin_transport_wlan_init (void *cls)
1283 {
1284   struct GNUNET_SERVICE_Context *service;
1285   struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
1286   struct GNUNET_TRANSPORT_PluginFunctions *api;
1287   struct Plugin *plugin;
1288
1289   GNUNET_assert(cls !=NULL);
1290
1291   service = GNUNET_SERVICE_start ("transport-wlan", env->sched, env->cfg);
1292         if (service == NULL){
1293                 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1294                            _("Failed to start service for `%s' transport plugin.\n"),
1295                            "wlan");
1296                 return NULL;
1297         }
1298
1299   plugin = GNUNET_malloc (sizeof (struct Plugin));
1300   plugin->env = env;
1301   plugin->pendingsessions = 0;
1302
1303   wlan_transport_start_wlan_helper(plugin);
1304   plugin->consoltoken = GNUNET_SERVER_mst_create(&wlan_process_helper,plugin);
1305
1306   //plugin->sessions = GNUNET_malloc (sizeof (struct Sessionqueue));
1307   //plugin->pending_Sessions = GNUNET_malloc (sizeof (struct Sessionqueue));
1308
1309   api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions));
1310   api->cls = plugin;
1311   api->send = &wlan_plugin_send;
1312   api->disconnect = &wlan_plugin_disconnect;
1313   api->address_pretty_printer = &wlan_plugin_address_pretty_printer;
1314   api->check_address = &wlan_plugin_address_suggested;
1315   api->address_to_string = &wlan_plugin_address_to_string;
1316
1317   start_next_message_id();
1318
1319   return api;
1320 }
1321
1322
1323 /**
1324  * Exit point from the plugin.
1325  */
1326 //TODO doxigen
1327 void *
1328 gnunet_plugin_transport_wlan_done (void *cls)
1329 {
1330   struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
1331   struct Plugin *plugin = api->cls;
1332
1333   GNUNET_assert(cls !=NULL);
1334
1335   GNUNET_free_non_null(plugin->mac_address);
1336   GNUNET_free (plugin);
1337   GNUNET_free (api);
1338   return NULL;
1339 }
1340
1341 /* end of plugin_transport_wlan.c */