fix div by zero
[oweals/gnunet.git] / src / transport / gnunet-helper-transport-wlan-dummy.c
1 /*
2  This file is part of GNUnet.
3  Copyright (C) 2010, 2012 GNUnet e.V.
4
5  GNUnet is free software: you can redistribute it and/or modify it
6  under the terms of the GNU Affero General Public License as published
7  by the Free Software Foundation, either version 3 of the License,
8  or (at your 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  Affero General Public License for more details.
14
15  You should have received a copy of the GNU Affero General Public License
16  along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 /**
19  * @file transport/gnunet-helper-transport-wlan-dummy.c
20  * @brief helper for the testcases for plugin_transport_wlan.c
21  * @author David Brodski
22  */
23 #include "platform.h"
24 #include "gnunet_protocols.h"
25 #include "gnunet_util_lib.h"
26 #include "plugin_transport_wlan.h"
27
28 /**
29  * Name of the fifo to use for IPC with the other dummy process.
30  */
31 #define FIFO_FILE1 "/tmp/test-transport/api-wlan-p1/WLAN_FIFO_in"
32
33 /**
34  * Name of the fifo to use for IPC with the other dummy process.
35  */
36 #define FIFO_FILE2 "/tmp/test-transport/api-wlan-p1/WLAN_FIFO_out"
37
38 /**
39  * Maximum size of a message allowed in either direction
40  * (used for our receive and sent buffers).
41  */
42 #define MAXLINE 4096
43
44
45 /**
46  * IO buffer used for buffering data in transit.
47  */
48 struct SendBuffer
49 {
50
51   /**
52    * How many bytes that were stored in 'buf' did we already write to the
53    * destination?  Always smaller than 'size'.
54    */
55   size_t pos;
56
57   /**
58    * How many bytes of data are stored in 'buf' for transmission right now?
59    * Data always starts at offset 0 and extends to 'size'.
60    */
61   size_t size;
62
63   /**
64    * Buffered data; twice the maximum allowed message size as we add some
65    * headers.
66    */
67   char buf[MAXLINE * 2];
68 };
69
70
71 /**
72  * Flag set to 1 if we are to terminate, otherwise 0.
73  */
74 static int closeprog;
75
76
77 /**
78  * We're being killed, clean up.
79  *
80  * @param sig killing signal
81  */
82 static void
83 sigfunc (int sig)
84 {
85   closeprog = 1;
86   (void) unlink (FIFO_FILE1);
87   (void) unlink (FIFO_FILE2);
88 }
89
90
91 /**
92  * Create control message for plugin
93  *
94  * @param buffer pointer to buffer for the message
95  * @param mac pointer to the mac address
96  * @return number of bytes written
97  */
98 static int
99 send_mac_to_plugin (char *buffer, struct GNUNET_TRANSPORT_WLAN_MacAddress *mac)
100 {
101
102   struct GNUNET_TRANSPORT_WLAN_HelperControlMessage macmsg;
103
104   GNUNET_memcpy (&macmsg.mac,
105           (char *) mac,
106           sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress));
107   macmsg.hdr.size = htons (sizeof (struct GNUNET_TRANSPORT_WLAN_HelperControlMessage));
108   macmsg.hdr.type = htons (GNUNET_MESSAGE_TYPE_WLAN_HELPER_CONTROL);
109   GNUNET_memcpy (buffer,
110           &macmsg,
111           sizeof (struct GNUNET_TRANSPORT_WLAN_HelperControlMessage));
112   return sizeof (struct GNUNET_TRANSPORT_WLAN_HelperControlMessage);
113 }
114
115
116 /**
117  * We got a message from the FIFO, check it, convert the message
118  * type to the output forward and copy it to the buffer for stdout.
119  *
120  * @param cls the 'struct SendBuffer' to copy the converted message to
121  * @param hdr inbound message from the FIFO
122  * @return #GNUNET_OK on success,
123  *    #GNUNET_NO to stop further processing (no error)
124  *    #GNUNET_SYSERR to stop further processing with error
125  */
126 static int
127 stdin_send (void *cls,
128             const struct GNUNET_MessageHeader *hdr)
129 {
130   struct SendBuffer *write_pout = cls;
131   const struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *in;
132   size_t payload_size;
133   struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage newheader;
134   uint16_t sendsize;
135
136   sendsize = ntohs (hdr->size);
137   in = (const struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *) hdr;
138   if ( (GNUNET_MESSAGE_TYPE_WLAN_DATA_TO_HELPER != ntohs (hdr->type)) ||
139        (sizeof (struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage) > sendsize) )
140   {
141     FPRINTF (stderr, "%s", "Received malformed message\n");
142     exit (1);
143   }
144   payload_size = sendsize - sizeof (struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage);
145   if ((payload_size + sizeof (struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage) + write_pout->size) > MAXLINE * 2)
146   {
147     FPRINTF (stderr, "%s",  "Packet too big for buffer\n");
148     exit (1);
149   }
150   memset (&newheader, 0, sizeof (newheader));
151   newheader.header.size = htons (payload_size + sizeof (newheader));
152   newheader.header.type = htons (GNUNET_MESSAGE_TYPE_WLAN_DATA_FROM_HELPER);
153   newheader.frame = in->frame;
154   GNUNET_memcpy (write_pout->buf + write_pout->size,
155           &newheader,
156           sizeof (newheader));
157   write_pout->size += sizeof (newheader);
158   GNUNET_memcpy (write_pout->buf + write_pout->size,
159           &in[1],
160           payload_size);
161   write_pout->size += payload_size;
162   return GNUNET_OK;
163 }
164
165
166 /**
167  * We read a full message from stdin.  Copy it to our send buffer.
168  *
169  * @param cls the 'struct SendBuffer' to copy to
170  * @param hdr the message we received to copy to the buffer
171  * @return #GNUNET_OK on success,
172  *    #GNUNET_NO to stop further processing (no error)
173  *    #GNUNET_SYSERR to stop further processing with error
174  */
175 static int
176 file_in_send (void *cls,
177               const struct GNUNET_MessageHeader *hdr)
178 {
179   struct SendBuffer *write_std = cls;
180   uint16_t sendsize;
181
182   sendsize = ntohs (hdr->size);
183   if ((sendsize + write_std->size) > MAXLINE * 2)
184   {
185     FPRINTF (stderr, "%s", "Packet too big for buffer\n");
186     exit (1);
187   }
188   GNUNET_memcpy (write_std->buf + write_std->size, hdr, sendsize);
189   write_std->size += sendsize;
190   return GNUNET_OK;
191 }
192
193
194 /**
195  * Main function of a program that pretends to be a WLAN card.
196  *
197  * @param argc should be 2
198  * @param argv either '1' or '2', depending on which of the two cards this dummy is to emulate
199  * @return 1 on error, 0 if terminated normally via signal
200  */
201 int
202 main (int argc, char *argv[])
203 {
204   struct stat st;
205   int erg;
206   FILE *fpin = NULL;
207   FILE *fpout = NULL;
208   int fdpin;
209   int fdpout;
210   char readbuf[MAXLINE];
211   int readsize;
212   struct SendBuffer write_std;
213   struct SendBuffer write_pout;
214   int ret;
215   int maxfd;
216   fd_set rfds;
217   fd_set wfds;
218   struct timeval tv;
219   int retval;
220   struct GNUNET_MessageStreamTokenizer *stdin_mst = NULL;
221   struct GNUNET_MessageStreamTokenizer *file_in_mst = NULL;
222   struct GNUNET_TRANSPORT_WLAN_MacAddress macaddr;
223   int first;
224
225   if ( (2 != argc) ||
226        ((0 != strcmp (argv[1], "1")) && (0 != strcmp (argv[1], "2"))) )
227   {
228     FPRINTF (stderr,
229              "%s",
230              "This program must be started with the operating mode (1 or 2) as the only argument.\n");
231     return 1;
232   }
233
234   /* make the fifos if needed */
235   umask (0);
236   if ( (GNUNET_OK != GNUNET_DISK_directory_create_for_file (FIFO_FILE1)) ||
237        (GNUNET_OK != GNUNET_DISK_directory_create_for_file (FIFO_FILE2)) )
238   {
239     FPRINTF (stderr,
240              "Failed to create directory for file `%s'\n",
241              FIFO_FILE1);
242     return 1;
243   }
244   if (0 == strcmp (argv[1], "1") )
245   {
246     if (0 != stat (FIFO_FILE1, &st))
247     {
248       erg = mkfifo (FIFO_FILE1, 0666);
249       if ( (0 != erg) && (EEXIST != errno) )
250         FPRINTF (stderr, "Error in mkfifo(%s): %s\n", FIFO_FILE1,
251                  strerror (errno));
252     }
253   }
254   else
255   {
256     if (0 != stat (FIFO_FILE2, &st))
257     {
258         GNUNET_break (0 == (erg = mkfifo (FIFO_FILE2, 0666)));
259       if ( (0 != erg) && (EEXIST != errno) )
260         FPRINTF (stderr,
261                  "Error in mkfifo(%s): %s\n",
262                  FIFO_FILE2,
263                  strerror (errno));
264     }
265   }
266
267   if (0 == strcmp (argv[1], "1"))
268   {
269     first = 1;
270     fpin = fopen (FIFO_FILE1, "r");
271     if (NULL == fpin)
272     {
273       FPRINTF (stderr,
274                "fopen of read FIFO_FILE1 failed: %s\n",
275                STRERROR (errno));
276       goto end;
277     }
278     if (NULL == (fpout = fopen (FIFO_FILE2, "w")))
279     {
280       GNUNET_break (0 == mkfifo (FIFO_FILE2, 0666));
281       fpout = fopen (FIFO_FILE2, "w");
282     }
283     if (NULL == fpout)
284     {
285       FPRINTF (stderr,
286                "fopen of write FIFO_FILE2 failed: %s\n",
287                STRERROR (errno));
288       goto end;
289     }
290   }
291   else
292   {
293     first = 0;
294     if (NULL == (fpout = fopen (FIFO_FILE1, "w")))
295     {
296         GNUNET_break (0 == mkfifo (FIFO_FILE1, 0666));
297       fpout = fopen (FIFO_FILE1, "w");
298     }
299     if (NULL == fpout)
300     {
301       FPRINTF (stderr,
302                "fopen of write FIFO_FILE1 failed: %s\n",
303                STRERROR (errno));
304       goto end;
305     }
306     fpin = fopen (FIFO_FILE2, "r");
307     if (NULL == fpin)
308     {
309       FPRINTF (stderr,
310                "fopen of read FIFO_FILE2 failed: %s\n",
311                STRERROR (errno));
312       goto end;
313     }
314   }
315
316   fdpin = fileno (fpin);
317   GNUNET_assert (fpin >= 0);
318   if (fdpin >= FD_SETSIZE)
319   {
320     FPRINTF (stderr,
321              "File fdpin number too large (%d > %u)\n",
322              fdpin,
323              (unsigned int) FD_SETSIZE);
324     goto end;
325   }
326
327   fdpout = fileno (fpout);
328   GNUNET_assert (fdpout >= 0);
329
330   if (fdpout >= FD_SETSIZE)
331   {
332     FPRINTF (stderr,
333              "File fdpout number too large (%d > %u)\n",
334              fdpout,
335              (unsigned int) FD_SETSIZE);
336     goto end;
337   }
338
339   signal (SIGINT, &sigfunc);
340   signal (SIGTERM, &sigfunc);
341   signal (GNUNET_TERM_SIG, &sigfunc);
342
343   write_std.size = 0;
344   write_std.pos = 0;
345   write_pout.size = 0;
346   write_pout.pos = 0;
347   stdin_mst = GNUNET_MST_create (&stdin_send, &write_pout);
348   file_in_mst = GNUNET_MST_create (&file_in_send, &write_std);
349
350   /* Send 'random' mac address */
351   macaddr.mac[0] = 0x13;
352   macaddr.mac[1] = 0x22;
353   macaddr.mac[2] = 0x33;
354   macaddr.mac[3] = 0x44;
355   macaddr.mac[4] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG, 256);
356   macaddr.mac[5] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, 256);
357   write_std.size = send_mac_to_plugin (write_std.buf, &macaddr);
358
359   while (0 == closeprog)
360   {
361     maxfd = -1;
362     tv.tv_sec = 5;
363     tv.tv_usec = 0;
364
365     FD_ZERO (&rfds);
366     FD_ZERO (&wfds);
367     /* if output queue is empty, read */
368     if (0 == write_pout.size)
369     {
370       FD_SET (STDIN_FILENO, &rfds);
371       maxfd = MAX (STDIN_FILENO, maxfd);
372     }
373     if (0 == write_std.size)
374     {
375       FD_SET (fdpin, &rfds);
376       maxfd = MAX (fdpin, maxfd);
377     }
378
379     /* if there is something to write, try to write */
380     if (0 < write_std.size)
381     {
382       FD_SET (STDOUT_FILENO, &wfds);
383       maxfd = MAX (maxfd, STDOUT_FILENO);
384     }
385     if (0 < write_pout.size)
386     {
387       FD_SET (fdpout, &wfds);
388       maxfd = MAX (maxfd, fdpout);
389     }
390
391     retval = select (maxfd + 1, &rfds, &wfds, NULL, &tv);
392     if ((-1 == retval) && (EINTR == errno))
393       continue;
394     if (0 > retval)
395     {
396       FPRINTF (stderr, "select failed: %s\n", STRERROR (errno));
397       closeprog = 1;
398       break;
399     }
400
401     if (FD_ISSET (STDOUT_FILENO, &wfds))
402     {
403       ret =
404           write (STDOUT_FILENO, write_std.buf + write_std.pos,
405                  write_std.size - write_std.pos);
406       if (0 > ret)
407       {
408         closeprog = 1;
409         FPRINTF (stderr, "Write ERROR to STDOUT_FILENO: %s\n",
410                  STRERROR (errno));
411         break;
412       }
413       else
414       {
415         write_std.pos += ret;
416         /* check if finished writing */
417         if (write_std.pos == write_std.size)
418         {
419           write_std.pos = 0;
420           write_std.size = 0;
421         }
422       }
423     }
424
425     if (FD_ISSET (fdpout, &wfds))
426     {
427       ret =
428           write (fdpout, write_pout.buf + write_pout.pos,
429                  write_pout.size - write_pout.pos);
430
431       if (0 > ret)
432       {
433         closeprog = 1;
434         FPRINTF (stderr, "Write ERROR to fdpout failed: %s\n", STRERROR (errno));
435       }
436       else
437       {
438         write_pout.pos += ret;
439         /* check if finished writing */
440         if (write_pout.pos == write_pout.size)
441         {
442           write_pout.pos = 0;
443           write_pout.size = 0;
444         }
445       }
446     }
447
448     if (FD_ISSET (STDIN_FILENO, &rfds))
449     {
450       readsize = read (STDIN_FILENO, readbuf, sizeof (readbuf));
451
452       if (0 > readsize)
453       {
454         closeprog = 1;
455         FPRINTF (stderr, "Error reading from STDIN_FILENO: %s\n",
456                  STRERROR (errno));
457       }
458       else if (0 < readsize)
459       {
460         GNUNET_MST_from_buffer (stdin_mst,
461                                 readbuf, readsize,
462                                 GNUNET_NO, GNUNET_NO);
463
464       }
465       else
466       {
467         /* eof */
468         closeprog = 1;
469       }
470     }
471
472     if (FD_ISSET (fdpin, &rfds))
473     {
474       readsize = read (fdpin, readbuf, sizeof (readbuf));
475       if (0 > readsize)
476       {
477         closeprog = 1;
478         FPRINTF (stderr, "Error reading from fdpin: %s\n", STRERROR (errno));
479         break;
480       }
481       else if (0 < readsize)
482       {
483         GNUNET_MST_from_buffer (file_in_mst,
484                                 readbuf, readsize,
485                                 GNUNET_NO, GNUNET_NO);
486       }
487       else
488       {
489         /* eof */
490         closeprog = 1;
491       }
492     }
493   }
494
495 end:
496   /* clean up */
497   if (NULL != stdin_mst)
498     GNUNET_MST_destroy (stdin_mst);
499   if (NULL != file_in_mst)
500     GNUNET_MST_destroy (file_in_mst);
501
502   if (NULL != fpout)
503     fclose (fpout);
504   if (NULL != fpin)
505     fclose (fpin);
506   if (1 == first)
507   {
508     (void) unlink (FIFO_FILE1);
509     (void) unlink (FIFO_FILE2);
510   }
511   return 0;
512 }