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