big scheduler refactoring, expect some issues
[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   struct GNUNET_OS_Process *server_proc;
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 (GNUNET_TIME_absolute_get_remaining(nextsend),
686                                           &do_transmit, plugin);
687
688   }
689
690
691
692   if (pm->message_size > WLAN_MTU) {
693         size += sizeof(struct FragmentationHeader);
694         // check for retransmission
695         if (GNUNET_TIME_absolute_get_duration(pm->last_ack).rel_value > FRAGMENT_TIMEOUT) {
696                 // TODO retransmit
697                 // be positive and try again later :-D
698                 pm->last_ack = GNUNET_TIME_absolute_get();
699                 // find first missing fragment
700                 exit = 0;
701                 akt = pm->head;
702                 pm->message_pos = 0;
703
704                 //test if ack 0 was already received
705                 while (akt != NULL){
706                         //if fragment is present, take next
707                         if (akt->fragment_num == pm->message_pos) {
708                                 pm->message_pos ++;
709                         }
710                         //next ack is bigger then the fragment number
711                         //in case there is something like this: (acks) 1, 2, 5, 6, ...
712                         //and we send 3 again, the next number should be 4
713                         if (akt->fragment_num > pm->message_pos) {
714                                                                 break;
715                                                         }
716
717                         akt = akt->next;
718
719                 }
720
721
722         }
723
724         copyoffset = (WLAN_MTU - sizeof(struct FragmentationHeader)) * pm->message_pos;
725         fragheader.fragment_off_or_num = pm->message_pos;
726         fragheader.message_id = session->message_id_out;
727
728         // start should be smaller then the packet size
729         //TODO send some other data if everything was send but not all acks are present
730         GNUNET_assert(copyoffset < pm->message_size);
731         copystart = pm->msg + copyoffset;
732
733         //size of the fragment is either the MTU - overhead
734         //or the missing part of the message in case this is the last fragment
735         copysize = GNUNET_MIN(pm->message_size - copyoffset,
736                         WLAN_MTU - sizeof(struct FragmentationHeader));
737         fragheader.header.size = copysize;
738         fragheader.header.type = GNUNET_MESSAGE_TYPE_WLAN_FRAGMENT;
739
740         //get the next missing fragment
741         exit = 0;
742         akt = pm->head;
743         pm->message_pos ++;
744
745         //test if ack was already received
746         while (akt != NULL){
747                 //if fragment is present, take next
748                 if (akt->fragment_num == pm->message_pos) {
749                         pm->message_pos ++;
750                 }
751                 //next ack is bigger then the fragment number
752                 //in case there is something like this: (acks) 1, 2, 5, 6, ...
753                 //and we send 3 again, the next number should be 4
754                 if (akt->fragment_num > pm->message_pos) {
755                                                         break;
756                                                 }
757
758                 akt = akt->next;
759         }
760
761
762         } else {
763         // there is no need to split
764         copystart = pm->msg;
765         copysize = pm->message_size;
766         }
767   size += copysize;
768   size += sizeof(struct RadiotapHeader) + sizeof(struct IeeeHeader)
769                         + sizeof(struct GNUNET_MessageHeader);
770   msgheader = GNUNET_malloc(size);
771   msgheader->size = htons(size - sizeof(struct GNUNET_MessageHeader));
772   msgheader->type = GNUNET_MESSAGE_TYPE_WLAN_HELPER_DATA;
773
774   radioHeader = (struct RadiotapHeader*) &msgheader[1];
775   getRadiotapHeader(radioHeader);
776
777   wlanheader = (struct IeeeHeader *) &radioHeader[1];
778   getWlanHeader(wlanheader);
779
780
781   //could be faster if content is just send and not copyed before
782   //fragmentheader is needed
783   if (pm->message_size > WLAN_MTU){
784   fragheader.message_crc = getcrc16(copystart, copysize);
785   memcpy(&wlanheader[1],&fragheader, sizeof(struct FragmentationHeader));
786   memcpy(&wlanheader[1] + sizeof(struct FragmentationHeader),copystart,copysize);
787   } else {
788   memcpy(&wlanheader[1],copystart,copysize);
789   }
790
791   bytes = GNUNET_DISK_file_write(plugin->server_stdin_handle, msgheader, size);
792
793
794
795
796
797
798
799
800   if (bytes < 1)
801     {
802       return;
803     }
804
805   //plugin->server_read_task =
806   //GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
807   //                                plugin->server_stdout_handle, &wlan_plugin_helper_read, plugin);
808
809 }
810
811
812
813 /**
814  * If we have pending messages, ask the server to
815  * transmit them (schedule the respective tasks, etc.)
816  *
817  * @param Plugin env to get everything needed
818  */
819 static void
820 process_pending_messages (struct Plugin * plugin)
821 {
822   struct Sessionqueue * queue;
823   struct Session * session;
824
825   if (plugin->pending_Sessions == NULL)
826     return;
827
828   queue = plugin->pending_Sessions;
829   //contet should not be empty
830   GNUNET_assert(queue->content != NULL);
831
832   session = queue->content;
833   //pending sessions should have some msg
834   GNUNET_assert(session->pending_messages_head != NULL);
835
836   // GNUNET_TIME_UNIT_FOREVER_REL is needed to clean up old msg
837   plugin->server_write_task
838     = GNUNET_SCHEDULER_add_write_file(GNUNET_TIME_UNIT_FOREVER_REL,
839                                                                                         plugin->server_stdin_handle,
840                                            &do_transmit,
841                                            plugin);
842 }
843
844
845 /**
846  * 32bit CRC
847  *
848  * @param msgbuf pointer tor the data
849  * @param msgbuf_size size of the data
850  *
851  * @return 32bit crc value
852  */
853
854 uint32_t
855 getcrc32 (const char *msgbuf,
856                   size_t msgbuf_size){
857         //TODO calc some crc
858         return 0;
859 }
860
861 /**
862  * 16bit CRC
863  *
864  * @param msgbuf pointer tor the data
865  * @param msgbuf_size size of the data
866  *
867  * @return 16bit crc value
868  */
869
870 uint16_t
871 getcrc16 (const char *msgbuf,
872                   size_t msgbuf_size){
873         //TODO calc some crc
874         return 0;
875 }
876
877 /**
878  * Function that can be used by the transport service to transmit
879  * a message using the plugin.
880  *
881  * @param cls closure
882  * @param target who should receive this message
883  * @param priority how important is the message
884  * @param msgbuf the message to transmit
885  * @param msgbuf_size number of bytes in 'msgbuf'
886  * @param timeout when should we time out 
887  * @param session which session must be used (or NULL for "any")
888  * @param addr the address to use (can be NULL if the plugin
889  *                is "on its own" (i.e. re-use existing TCP connection))
890  * @param addrlen length of the address in bytes
891  * @param force_address GNUNET_YES if the plugin MUST use the given address,
892  *                otherwise the plugin may use other addresses or
893  *                existing connections (if available)
894  * @param cont continuation to call once the message has
895  *        been transmitted (or if the transport is ready
896  *        for the next transmission call; or if the
897  *        peer disconnected...)
898  * @param cont_cls closure for cont
899  * @return number of bytes used (on the physical network, with overheads);
900  *         -1 on hard errors (i.e. address invalid); 0 is a legal value
901  *         and does NOT mean that the message was not transmitted (DV)
902  */
903 static ssize_t
904 wlan_plugin_send (void *cls,
905                   const struct GNUNET_PeerIdentity * target,
906                   const char *msgbuf,
907                   size_t msgbuf_size,
908                   unsigned int priority,
909                   struct GNUNET_TIME_Relative timeout,
910                   struct Session *session,
911                   const void *addr,
912                   size_t addrlen,
913                   int force_address,
914                   GNUNET_TRANSPORT_TransmitContinuation cont,
915                   void *cont_cls)
916 {
917   struct Plugin * plugin = cls;
918   struct PendingMessage * newmsg = NULL;
919   struct WlanHeader * wlanheader = NULL;
920   //check if msglen > 0
921   GNUNET_assert(msgbuf_size > 0);
922
923   //get session if needed
924   if (session == NULL) {
925           if ( wlan_plugin_address_suggested(plugin , addr, addrlen) == GNUNET_OK){
926                   session = get_Session(plugin, addr);
927           } else {
928                   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
929                                         _("Wlan Address len %d is wrong\n"),
930                                          addrlen);
931                   return -1;
932           }
933   }
934
935   //TODO target "problem" not solved
936   session->target = *target;
937
938   //queue message:
939   //first queue session
940   queue_Session(plugin, session);
941
942   //queue message in session
943   newmsg = GNUNET_malloc(sizeof(struct PendingMessage) + msgbuf_size + sizeof(struct WlanHeader));
944   newmsg->msg = (const char*) &newmsg[1];
945   wlanheader = (struct WlanHeader *) &newmsg[1];
946   //copy msg to buffer, not fragmented / segmented yet, but with message header
947   wlanheader->header.size = msgbuf_size;
948   wlanheader->header.type = GNUNET_MESSAGE_TYPE_WLAN_DATA;
949   wlanheader->target = *target;
950   wlanheader->crc = getcrc32(msgbuf, msgbuf_size);
951   memcpy(&wlanheader[1], msgbuf, msgbuf_size);
952   newmsg->transmit_cont = cont;
953   newmsg->transmit_cont_cls = cont_cls;
954   newmsg->timeout = GNUNET_TIME_relative_to_absolute(timeout);
955   newmsg->message_pos = 0;
956   newmsg->message_size = msgbuf_size + sizeof(struct WlanHeader);
957   newmsg->next = NULL;
958
959   //check if queue is empty
960   struct PendingMessage * tailmsg;
961   tailmsg = session->pending_messages_tail;
962
963   //new tail is the new msg
964   session->pending_messages_tail = newmsg;
965   newmsg->prev = tailmsg;
966
967   //test if tail was not NULL (queue is empty)
968   if (tailmsg == NULL){
969           // head should be NULL too
970           GNUNET_assert(session->pending_messages_head == NULL);
971
972           session->pending_messages_head = newmsg;
973
974   } else {
975           //next at the tail should be NULL
976           GNUNET_assert(tailmsg->next == NULL);
977
978           //queue the msg
979           tailmsg->next = newmsg;
980   }
981
982   process_pending_messages(plugin);
983
984
985   //FIXME not the correct size
986   return msgbuf_size;
987
988 }
989
990
991
992 /**
993  * Function that can be used to force the plugin to disconnect
994  * from the given peer and cancel all previous transmissions
995  * (and their continuation).
996  *
997  * @param cls closure
998  * @param target peer from which to disconnect
999  */
1000 static void
1001 wlan_plugin_disconnect (void *cls,
1002                             const struct GNUNET_PeerIdentity *target)
1003 {
1004         struct Plugin *plugin = cls;
1005         struct Sessionqueue * queue = plugin->sessions;
1006         struct Sessionqueue * lastitem = NULL;
1007         struct PendingMessage * pm;
1008
1009         // just look at all the session for the needed one
1010         while (queue != NULL){
1011                 // content is never NULL
1012                 GNUNET_assert (queue->content == NULL);
1013                 if (memcmp(target, &(queue->content->target), sizeof(struct GNUNET_PeerIdentity)) == 0)
1014                   {
1015                         // sesion found
1016                         // remove PendingMessage
1017                         while (queue->content->pending_messages_head != NULL){
1018                                 pm = queue->content->pending_messages_head;
1019                                 free_acks(pm);
1020                                 GNUNET_CONTAINER_DLL_remove(queue->content->pending_messages_head,queue->content->pending_messages_tail, pm);
1021                                 GNUNET_free(pm);
1022
1023                         }
1024
1025                         GNUNET_free(queue->content);
1026                         GNUNET_CONTAINER_DLL_remove(plugin->sessions, plugin->sessions_tail, queue);
1027                         GNUNET_free(queue);
1028
1029                         return;
1030                   }
1031                 // try next
1032                 lastitem = queue;
1033                 queue = queue->next;
1034         }
1035 }
1036
1037
1038 /**
1039  * Convert the transports address to a nice, human-readable
1040  * format.
1041  *
1042  * @param cls closure
1043  * @param type name of the transport that generated the address
1044  * @param addr one of the addresses of the host, NULL for the last address
1045  *        the specific address format depends on the transport
1046  * @param addrlen length of the address
1047  * @param numeric should (IP) addresses be displayed in numeric form?
1048  * @param timeout after how long should we give up?
1049  * @param asc function to call on each string
1050  * @param asc_cls closure for asc
1051  */
1052 static void
1053 wlan_plugin_address_pretty_printer (void *cls,
1054                                     const char *type,
1055                                     const void *addr,
1056                                     size_t addrlen,
1057                                     int numeric,
1058                                     struct GNUNET_TIME_Relative timeout,
1059                                     GNUNET_TRANSPORT_AddressStringCallback
1060                                     asc, void *asc_cls)
1061 {
1062   char ret[92];
1063   const unsigned char * input;
1064   
1065   GNUNET_assert(cls !=NULL);
1066   if (addrlen != 6)
1067     {
1068       /* invalid address (MAC addresses have 6 bytes) */
1069       GNUNET_break (0);
1070       asc (asc_cls, NULL);
1071       return;
1072     }
1073   input = (const unsigned char*) addr;
1074   GNUNET_snprintf (ret, 
1075                    sizeof (ret),
1076                    "%s Mac-Adress %X:%X:%X:%X:%X:%X",
1077                    PROTOCOL_PREFIX, 
1078                    input[0], input[1], input[2], input[3], input[4], input[5]);  
1079   asc (asc_cls, ret);
1080 }
1081
1082
1083
1084 /**
1085  * Another peer has suggested an address for this
1086  * peer and transport plugin.  Check that this could be a valid
1087  * address.  If so, consider adding it to the list
1088  * of addresses.
1089  *
1090  * @param cls closure
1091  * @param addr pointer to the address
1092  * @param addrlen length of addr
1093  * @return GNUNET_OK if this is a plausible address for this peer
1094  *         and transport
1095  */
1096
1097
1098 static int
1099 wlan_plugin_address_suggested (void *cls,
1100                                    const void *addr,
1101                                    size_t addrlen)
1102 {
1103   //struct Plugin *plugin = cls;
1104
1105   /* check if the address is plausible; if so,
1106      add it to our list! */
1107
1108   GNUNET_assert(cls !=NULL);
1109   //FIXME mitm is not checked
1110   //Mac Adress has 6 bytes
1111   if (addrlen == 6){
1112     /* TODO check for bad addresses like milticast, broadcast, etc */
1113     return GNUNET_OK;
1114   } else {
1115     return GNUNET_SYSERR;
1116   }
1117
1118   return GNUNET_SYSERR;
1119 }
1120
1121
1122 /**
1123  * Function called for a quick conversion of the binary address to
1124  * a numeric address.  Note that the caller must not free the 
1125  * address and that the next call to this function is allowed
1126  * to override the address again.
1127  *
1128  * @param cls closure
1129  * @param addr binary address
1130  * @param addrlen length of the address
1131  * @return string representing the same address 
1132  */
1133 static const char* 
1134 wlan_plugin_address_to_string (void *cls,
1135                                const void *addr,
1136                                size_t addrlen)
1137 {
1138   char ret[92];
1139   const unsigned char * input;
1140   
1141   GNUNET_assert(cls !=NULL);
1142   if (addrlen != 6)
1143     {
1144       /* invalid address (MAC addresses have 6 bytes) */
1145       GNUNET_break (0);
1146       return NULL;
1147     }
1148   input = (const unsigned char*) addr;
1149   GNUNET_snprintf (ret, 
1150                    sizeof (ret),
1151                    "%s Mac-Adress %X:%X:%X:%X:%X:%X",
1152                    PROTOCOL_PREFIX, 
1153                    input[0], input[1], input[2], input[3], input[4], input[5]);  
1154   return GNUNET_strdup (ret);
1155 }
1156
1157
1158
1159 /**
1160  * Function used for to process the data from the suid process
1161  */
1162 //TODO doxigen
1163
1164 static void
1165 wlan_process_helper (void *cls,
1166                       void *client,
1167                       const struct GNUNET_MessageHeader *hdr)
1168 {
1169   struct Plugin *plugin = cls;
1170   if (hdr->type == GNUNET_MESSAGE_TYPE_WLAN_HELPER_DATA){
1171     //TODO DATA
1172   } else if (hdr->type == GNUNET_MESSAGE_TYPE_WLAN_ADVERTISEMENT){
1173     //TODO ADV
1174   } else if (hdr->type == GNUNET_MESSAGE_TYPE_WLAN_HELPER_CONTROL){
1175     //TODO Control
1176     if (hdr->size == 6){
1177       plugin->mac_address = GNUNET_malloc(6);
1178       memcpy(plugin->mac_address, &hdr[1],6);
1179       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Notifying transport of address %s\n", wlan_plugin_address_to_string(cls, plugin->mac_address, hdr->size));
1180       plugin->env->notify_address (plugin->env->cls,
1181                                       "wlan",
1182                                       &plugin->mac_address, sizeof(plugin->mac_address),
1183                                       GNUNET_TIME_UNIT_FOREVER_REL);
1184     } else {
1185       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Wrong wlan mac address %s\n", plugin->mac_address);
1186     }
1187
1188
1189   } else {
1190     // TODO Wrong data?
1191   }
1192 }
1193
1194
1195 static void
1196 wlan_plugin_helper_read (void *cls,
1197                          const struct GNUNET_SCHEDULER_TaskContext *tc)
1198 {
1199   struct Plugin *plugin = cls;
1200   char mybuf[WLAN_MTU]; 
1201   ssize_t bytes;
1202
1203   if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
1204     return;
1205   bytes = GNUNET_DISK_file_read (plugin->server_stdout_handle, 
1206                                  mybuf, sizeof(mybuf));
1207   if (bytes <= 0)
1208     {
1209 #if DEBUG_TCP_NAT
1210       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1211                       _("Finished reading from wlan-helper stdout with code: %d\n"), bytes);
1212 #endif
1213       return;
1214     }
1215   GNUNET_SERVER_mst_receive(plugin->consoltoken, NULL,
1216                             mybuf, bytes, 0, GNUNET_NO);
1217
1218 }
1219
1220
1221 /**
1222  * Start the gnunet-wlan-helper process.
1223  *
1224  * @param plugin the transport plugin
1225  *
1226  * @return GNUNET_YES if process was started, GNUNET_SYSERR on error
1227  */
1228 static int
1229 wlan_transport_start_wlan_helper (struct Plugin *plugin)
1230 {
1231
1232   plugin->server_stdout = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_NO, GNUNET_YES);
1233   if (plugin->server_stdout == NULL)
1234     return GNUNET_SYSERR;
1235
1236   plugin->server_stdin = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO);
1237     if (plugin->server_stdin == NULL)
1238       return GNUNET_SYSERR;
1239
1240 #if DEBUG_TCP_NAT
1241   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1242                    "Starting gnunet-wlan-helper process cmd: %s %s\n", "gnunet-wlan-helper", plugin->interface);
1243 #endif
1244   /* Start the server process */
1245   plugin->server_proc = GNUNET_OS_start_process(plugin->server_stdin, plugin->server_stdout, "gnunet-transport-wlan-helper", "gnunet-transport-wlan-helper", plugin->interface, NULL);
1246   if (plugin->server_proc == NULL)
1247     {
1248 #if DEBUG_TCP_NAT
1249     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1250                      "Failed to start gnunet-wlan-helper process\n");
1251 #endif
1252       return GNUNET_SYSERR;
1253     }
1254   /* Close the write end of the read pipe */
1255   GNUNET_DISK_pipe_close_end(plugin->server_stdout, GNUNET_DISK_PIPE_END_WRITE);
1256
1257   /* Close the read end of the write pipe */
1258   GNUNET_DISK_pipe_close_end(plugin->server_stdin, GNUNET_DISK_PIPE_END_READ);
1259
1260   plugin->server_stdout_handle = GNUNET_DISK_pipe_handle(plugin->server_stdout, GNUNET_DISK_PIPE_END_READ);
1261   plugin->server_stdin_handle = GNUNET_DISK_pipe_handle(plugin->server_stdin, GNUNET_DISK_PIPE_END_WRITE);
1262
1263   plugin->server_read_task =
1264   GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
1265                                   plugin->server_stdout_handle, &wlan_plugin_helper_read, plugin);
1266   return GNUNET_YES;
1267 }
1268
1269
1270
1271 /**
1272  * Entry point for the plugin.
1273  *
1274  * @param cls closure, the 'struct GNUNET_TRANSPORT_PluginEnvironment*'
1275  * @return the 'struct GNUNET_TRANSPORT_PluginFunctions*' or NULL on error
1276  */
1277 void *
1278 gnunet_plugin_transport_wlan_init (void *cls)
1279 {
1280   struct GNUNET_SERVICE_Context *service;
1281   struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
1282   struct GNUNET_TRANSPORT_PluginFunctions *api;
1283   struct Plugin *plugin;
1284
1285   GNUNET_assert(cls !=NULL);
1286
1287   service = GNUNET_SERVICE_start ("transport-wlan", env->cfg);
1288         if (service == NULL){
1289                 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1290                            _("Failed to start service for `%s' transport plugin.\n"),
1291                            "wlan");
1292                 return NULL;
1293         }
1294
1295   plugin = GNUNET_malloc (sizeof (struct Plugin));
1296   plugin->env = env;
1297   plugin->pendingsessions = 0;
1298
1299   wlan_transport_start_wlan_helper(plugin);
1300   plugin->consoltoken = GNUNET_SERVER_mst_create(&wlan_process_helper,plugin);
1301
1302   //plugin->sessions = GNUNET_malloc (sizeof (struct Sessionqueue));
1303   //plugin->pending_Sessions = GNUNET_malloc (sizeof (struct Sessionqueue));
1304
1305   api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions));
1306   api->cls = plugin;
1307   api->send = &wlan_plugin_send;
1308   api->disconnect = &wlan_plugin_disconnect;
1309   api->address_pretty_printer = &wlan_plugin_address_pretty_printer;
1310   api->check_address = &wlan_plugin_address_suggested;
1311   api->address_to_string = &wlan_plugin_address_to_string;
1312
1313   start_next_message_id();
1314
1315   return api;
1316 }
1317
1318
1319 /**
1320  * Exit point from the plugin.
1321  */
1322 //TODO doxigen
1323 void *
1324 gnunet_plugin_transport_wlan_done (void *cls)
1325 {
1326   struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
1327   struct Plugin *plugin = api->cls;
1328
1329   GNUNET_assert(cls !=NULL);
1330
1331   GNUNET_free_non_null(plugin->mac_address);
1332   GNUNET_free (plugin);
1333   GNUNET_free (api);
1334   return NULL;
1335 }
1336
1337 /* end of plugin_transport_wlan.c */