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