unix domain socket transport, associated test cases
[oweals/gnunet.git] / src / transport / test_transport_api_unreliability.c
1 /*
2      This file is part of GNUnet.
3      (C) 2009, 2010 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  * @file transport/test_transport_api_unreliability.c
22  * @brief test case for transports; ensures messages get
23  *        through, regardless of order
24  *
25  * This test case serves as a base for unreliable
26  * transport test cases to check that the transports
27  * achieve reliable message delivery.
28  */
29 #include "platform.h"
30 #include "gnunet_common.h"
31 #include "gnunet_hello_lib.h"
32 #include "gnunet_getopt_lib.h"
33 #include "gnunet_os_lib.h"
34 #include "gnunet_program_lib.h"
35 #include "gnunet_scheduler_lib.h"
36 #include "gnunet_server_lib.h"
37 #include "gnunet_transport_service.h"
38 #include "gauger.h"
39 #include "transport.h"
40
41 #define VERBOSE GNUNET_NO
42
43 #define VERBOSE_ARM GNUNET_NO
44
45 #define START_ARM GNUNET_YES
46
47 /**
48  * Note that this value must not significantly exceed
49  * 'MAX_PENDING' in 'gnunet-service-transport.c', otherwise
50  * messages may be dropped even for a reliable transport.
51  */
52 #define TOTAL_MSGS (80000 * 3) /* Total messages should be divisible by 8, so we can make a nice bitmap */
53
54 /**
55  * How long until we give up on transmitting the message?
56  */
57 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1500)
58
59 #define UNRELIABLE_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
60
61 #define MTYPE 12345
62
63 struct PeerContext
64 {
65   struct GNUNET_CONFIGURATION_Handle *cfg;
66   struct GNUNET_TRANSPORT_Handle *th;
67   struct GNUNET_PeerIdentity id;
68 #if START_ARM
69   struct GNUNET_OS_Process *arm_proc;
70 #endif
71 };
72
73 static struct PeerContext p1;
74
75 static struct PeerContext p2;
76
77 static int ok;
78
79 static int is_tcp;
80
81 static int is_tcp_nat;
82
83 static int is_http;
84
85 static int is_https;
86
87 static int is_udp;
88
89 static int is_unix;
90
91 static int connected;
92
93 static unsigned long long total_bytes;
94
95 static struct GNUNET_TIME_Absolute start_time;
96
97 static GNUNET_SCHEDULER_TaskIdentifier die_task;
98
99 static char *key_file_p1;
100 static char *cert_file_p1;
101
102 static char *key_file_p2;
103 static char *cert_file_p2;
104
105 static char *test_name;
106
107 static char bitmap[TOTAL_MSGS / 8];
108
109 static int msg_scheduled;
110 static int msg_sent;
111 static int msg_recv_expected;
112 static int msg_recv;
113 static struct GNUNET_TRANSPORT_TransmitHandle * transmit_handle;
114
115 #if VERBOSE
116 #define OKPP do { ok++; fprintf (stderr, "Now at stage %u at %s:%u\n", ok, __FILE__, __LINE__); } while (0)
117 #else
118 #define OKPP do { ok++; } while (0)
119 #endif
120
121 /**
122  * Sets a bit active in the bitmap.
123  *
124  * @param bitIdx which bit to set
125  */
126 static void
127 set_bit (unsigned int bitIdx)
128 {
129   size_t arraySlot;
130   unsigned int targetBit;
131   if (bitIdx > sizeof(bitmap) * 8)
132     {
133       GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "setting bit %d of %d(!)\n", bitIdx, sizeof(bitmap) * 8);
134       return;
135     }
136   GNUNET_assert(bitIdx < sizeof(bitmap) * 8);
137   arraySlot = bitIdx / 8;
138   targetBit = (1L << (bitIdx % 8));
139   bitmap[arraySlot] |= targetBit;
140 }
141
142 /**
143  * Obtain a bit from bitmap.
144  * @param map the bitmap
145  * @param bit index from bitmap
146  *
147  * @return Bit \a bit from hashcode \a code
148  */
149 int
150 get_bit (const char *map, unsigned int bit)
151 {
152   if (bit >= TOTAL_MSGS)
153     {
154       GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "get bit %d of %d(!?!?)\n", bit, sizeof(bitmap) * 8);
155       return 0;
156     }
157   return ((map)[bit >> 3] & (1 << (bit & 7))) > 0;
158 }
159
160 static void
161 end ()
162 {
163   unsigned long long delta;
164   int i;
165   int result;
166   char *value_name;
167
168   result = 0;
169   for (i = 0; i < TOTAL_MSGS; i++)
170     {
171       if (get_bit(bitmap, i) == 0)
172         {
173           GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Did not receive message %d\n", i);
174           result = -1;
175         }
176     }
177
178   GNUNET_SCHEDULER_cancel (die_task);
179   die_task = GNUNET_SCHEDULER_NO_TASK;
180 #if VERBOSE
181   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting from transports!\n");
182 #endif
183   GNUNET_TRANSPORT_disconnect (p1.th);
184   GNUNET_TRANSPORT_disconnect (p2.th);
185 #if VERBOSE
186   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
187               "Transports disconnected, returning success!\n");
188 #endif
189   delta = GNUNET_TIME_absolute_get_duration (start_time).rel_value;
190   GNUNET_asprintf(&value_name, "unreliable_kbs_%s", test_name);
191   GAUGER (value_name, (int)(total_bytes * 1000 / 1024 /delta));
192   GNUNET_free(value_name);
193   fprintf (stderr,
194            "\nThroughput was %llu kb/s\n",
195            total_bytes * 1000 / 1024 / delta);
196   ok = result;
197
198 }
199
200 static void
201 end_unreliably ()
202 {
203   unsigned long long delta;
204   int i;
205   int num_failed;
206   char *value_name;
207   num_failed = 0;
208   for (i = 0; i < TOTAL_MSGS; i++)
209     {
210       if (get_bit(bitmap, i) == 0)
211         {
212           GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Did not receive message %d\n", i);
213           num_failed++;
214         }
215     }
216
217   die_task = GNUNET_SCHEDULER_NO_TASK;
218 #if VERBOSE
219   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting from transports!\n");
220 #endif
221   GNUNET_TRANSPORT_disconnect (p1.th);
222   GNUNET_TRANSPORT_disconnect (p2.th);
223 #if VERBOSE
224   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
225               "Transports disconnected, returning success!\n");
226 #endif
227   delta = GNUNET_TIME_absolute_get_duration (start_time).rel_value;
228   fprintf (stderr,
229            "\nThroughput was %llu kb/s\n",
230            total_bytes * 1000 / 1024 / delta);
231   GNUNET_asprintf(&value_name, "unreliable_kbs_%s", test_name);
232   GAUGER (value_name, (int)(total_bytes * 1000 / 1024 /delta));
233   GNUNET_free(value_name);
234   GNUNET_asprintf(&value_name, "unreliable_failed_%s", test_name);
235   GAUGER (value_name, (int)num_failed);
236   GNUNET_free(value_name);
237   GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Had %d failed messages!\n", num_failed);
238   ok = 0;
239
240 }
241
242
243
244 static void
245 stop_arm (struct PeerContext *p)
246 {
247 #if START_ARM
248   if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM))
249     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
250   GNUNET_OS_process_wait (p->arm_proc);
251   GNUNET_OS_process_close (p->arm_proc);
252   p->arm_proc = NULL;
253 #endif
254   GNUNET_CONFIGURATION_destroy (p->cfg);
255 }
256
257
258 static void
259 end_badly (void *cls,
260            const struct GNUNET_SCHEDULER_TaskContext *tc)
261 {
262   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
263                   "Reliability failed: \nLast message sent %u \nNext message scheduled %u\nLast message received %u\nMessage expected %u \n ", msg_sent, msg_scheduled, msg_recv, msg_recv_expected);
264   GNUNET_break (0);
265   GNUNET_TRANSPORT_disconnect (p1.th);
266   GNUNET_TRANSPORT_disconnect (p2.th);
267   ok = 1;
268 }
269
270
271 struct TestMessage
272 {
273   struct GNUNET_MessageHeader header;
274   uint32_t num;
275 };
276
277
278 static unsigned int
279 get_size (unsigned int iter)
280 {
281   unsigned int ret;
282
283   if (iter < 60000)
284     return iter + sizeof (struct TestMessage);
285   ret = (iter * iter * iter);
286   return sizeof (struct TestMessage) + (ret % 60000);
287 }
288
289
290 static void
291 notify_receive (void *cls,
292                 const struct GNUNET_PeerIdentity *peer,
293                 const struct GNUNET_MessageHeader *message,
294                 const struct GNUNET_TRANSPORT_ATS_Information *ats,
295                 uint32_t ats_count)
296 {
297   static int n;
298   unsigned int s;
299   char cbuf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1];
300   const struct TestMessage *hdr;
301
302   hdr = (const struct TestMessage*) message;
303
304   if (MTYPE != ntohs (message->type))
305     return;
306   msg_recv_expected = n;
307   msg_recv = ntohl(hdr->num);
308   s = get_size (ntohl(hdr->num));
309
310   if (ntohs (message->size) != s)
311     {
312       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
313                   "Expected message %u of size %u, got %u bytes of message %u\n",
314                   ntohl(hdr->num), s,
315                   ntohs (message->size),
316                   ntohl (hdr->num));
317       GNUNET_SCHEDULER_cancel (die_task);
318       die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL);
319       return;
320     }
321
322   memset (cbuf, ntohl(hdr->num), s - sizeof (struct TestMessage));
323   if (0 != memcmp (cbuf,
324                    &hdr[1],
325                    s - sizeof (struct TestMessage)))
326     {
327       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
328                   "Expected message %u with bits %u, but body did not match\n",
329                   ntohl(hdr->num), (unsigned char) n);
330       GNUNET_SCHEDULER_cancel (die_task);
331       die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL);
332       return;
333     }
334 #if VERBOSE
335   if (ntohl(hdr->num) % 5 == 0)
336     {
337       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
338                   "Got message %u of size %u\n",
339                   ntohl (hdr->num),
340                   ntohs (message->size));
341     }
342 #endif
343   n++;
344   set_bit(ntohl(hdr->num));
345   if (0 == (n % (5000)))
346     {
347       fprintf (stderr, ".");
348       GNUNET_SCHEDULER_cancel (die_task);
349       die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
350                                                &end_badly,
351                                                NULL);
352     }
353   if (n == TOTAL_MSGS)
354     end ();
355 }
356
357
358 static size_t
359 notify_ready (void *cls, size_t size, void *buf)
360 {
361   static int n;
362   char *cbuf = buf;
363   struct TestMessage hdr;
364   unsigned int s;
365   unsigned int ret;
366
367   if (buf == NULL)
368     {
369       GNUNET_break (0);
370       ok = 42;
371       return 0;
372     }
373   ret = 0;
374   s = get_size (n);
375   GNUNET_assert (size >= s);
376   GNUNET_assert (buf != NULL);
377   cbuf = buf;
378   do
379     {
380       hdr.header.size = htons (s);
381       hdr.header.type = htons (MTYPE);
382       hdr.num = htonl (n);
383       msg_sent = n;
384       memcpy (&cbuf[ret], &hdr, sizeof (struct TestMessage));
385       ret += sizeof (struct TestMessage);
386       memset (&cbuf[ret], n, s - sizeof (struct TestMessage));
387       ret += s - sizeof (struct TestMessage);
388 #if VERBOSE
389       if (n % 5000 == 0)
390         {
391           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
392                       "Sending message %u of size %u\n",
393                       n,
394                       s);
395         }
396 #endif
397       n++;
398       s = get_size (n);
399       if (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 16))
400         break; /* sometimes pack buffer full, sometimes not */
401     }
402   while (size - ret >= s);
403   if (n < TOTAL_MSGS)
404   {
405     GNUNET_TRANSPORT_notify_transmit_ready (p2.th,
406                                             &p1.id,
407                                             s, 0, TIMEOUT,
408                                             &notify_ready,
409                                             NULL);
410     msg_scheduled = n;
411   }
412   else
413     {
414       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "All messages scheduled to be sent!!\n");
415       GNUNET_SCHEDULER_cancel(die_task);
416       die_task = GNUNET_SCHEDULER_add_delayed (UNRELIABLE_TIMEOUT, &end_unreliably, NULL);
417     }
418   if (n % 5000 == 0)
419     {
420       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
421                   "Returning total message block of size %u\n",
422                   ret);
423     }
424   total_bytes += ret;
425   return ret;
426 }
427
428
429 static void
430 notify_connect (void *cls,
431                 const struct GNUNET_PeerIdentity *peer,
432                 const struct GNUNET_TRANSPORT_ATS_Information *ats,
433                 uint32_t ats_count)
434 {
435   if (cls == &p1)
436     {
437       GNUNET_TRANSPORT_set_quota (p1.th,
438                                   &p2.id,
439                                   GNUNET_BANDWIDTH_value_init (1024 * 1024 * 1024),
440                                   GNUNET_BANDWIDTH_value_init (1024 * 1024 * 1024),
441                                   GNUNET_TIME_UNIT_FOREVER_REL,
442                                   NULL, NULL);
443       start_time = GNUNET_TIME_absolute_get ();
444       connected++;
445     }
446   else
447     {
448       GNUNET_TRANSPORT_set_quota (p2.th,
449                                   &p1.id,
450                                   GNUNET_BANDWIDTH_value_init (1024 * 1024 * 1024),
451                                   GNUNET_BANDWIDTH_value_init (1024 * 1024 * 1024),
452                                   GNUNET_TIME_UNIT_FOREVER_REL,
453                                   NULL, NULL);
454       connected++;
455     }
456
457   if (connected == 2)
458     {
459
460           if ((transmit_handle!=NULL) && (cls == NULL))
461                  GNUNET_TRANSPORT_notify_transmit_ready_cancel(transmit_handle);
462           if ((transmit_handle!=NULL) && (cls == &transmit_handle))
463                  transmit_handle=NULL;
464       GNUNET_TRANSPORT_notify_transmit_ready (p2.th,
465                                               &p1.id,
466                                               get_size (0), 0, TIMEOUT,
467                                               &notify_ready,
468                                               NULL);
469     }
470 #if VERBOSE
471   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
472               "Peer `%4s' connected to us (%p)!\n", GNUNET_i2s (peer), cls);
473 #endif
474 }
475
476
477 static void
478 notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
479 {
480 #if VERBOSE
481   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
482               "Peer `%4s' disconnected (%p)!\n",
483               GNUNET_i2s (peer), cls);
484 #endif
485 }
486
487
488 static void
489 setup_peer (struct PeerContext *p, const char *cfgname)
490 {
491   p->cfg = GNUNET_CONFIGURATION_create ();
492 #if START_ARM
493   p->arm_proc = GNUNET_OS_start_process (NULL, NULL,
494                                         "gnunet-service-arm",
495                                         "gnunet-service-arm",
496 #if VERBOSE_ARM
497                                         "-L", "DEBUG",
498 #endif
499                                         "-c", cfgname, NULL);
500 #endif
501   GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname));
502
503   if (is_https)
504   {
505           struct stat sbuf;
506           if (p==&p1)
507           {
508                   if (GNUNET_CONFIGURATION_have_value (p->cfg,
509                                                                                            "transport-https", "KEY_FILE"))
510                                 GNUNET_CONFIGURATION_get_value_string (p->cfg, "transport-https", "KEY_FILE", &key_file_p1);
511                   if (key_file_p1 == NULL)
512                           GNUNET_asprintf(&key_file_p1,"https_p1.key");
513                   if (0 == stat (key_file_p1, &sbuf ))
514                   {
515                           if (0 == remove(key_file_p1))
516                               GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Successfully removed existing private key file `%s'\n",key_file_p1);
517                           else
518                                   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to remove private key file `%s'\n",key_file_p1);
519                   }
520                   if (GNUNET_CONFIGURATION_have_value (p->cfg,"transport-https", "CERT_FILE"))
521                           GNUNET_CONFIGURATION_get_value_string (p->cfg, "transport-https", "CERT_FILE", &cert_file_p1);
522                   if (cert_file_p1 == NULL)
523                           GNUNET_asprintf(&cert_file_p1,"https_p1.cert");
524                   if (0 == stat (cert_file_p1, &sbuf ))
525                   {
526                           if (0 == remove(cert_file_p1))
527                               GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Successfully removed existing certificate file `%s'\n",cert_file_p1);
528                           else
529                                   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to remove existing certificate file `%s'\n",cert_file_p1);
530                   }
531           }
532           else if (p==&p2)
533           {
534                   if (GNUNET_CONFIGURATION_have_value (p->cfg,
535                                                                                            "transport-https", "KEY_FILE"))
536                                 GNUNET_CONFIGURATION_get_value_string (p->cfg, "transport-https", "KEY_FILE", &key_file_p2);
537                   if (key_file_p2 == NULL)
538                           GNUNET_asprintf(&key_file_p2,"https_p2.key");
539                   if (0 == stat (key_file_p2, &sbuf ))
540                   {
541                           if (0 == remove(key_file_p2))
542                               GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Successfully removed existing private key file `%s'\n",key_file_p2);
543                           else
544                                   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to remove private key file `%s'\n",key_file_p2);
545                   }
546                   if (GNUNET_CONFIGURATION_have_value (p->cfg,"transport-https", "CERT_FILE"))
547                           GNUNET_CONFIGURATION_get_value_string (p->cfg, "transport-https", "CERT_FILE", &cert_file_p2);
548                   if (cert_file_p2 == NULL)
549                           GNUNET_asprintf(&cert_file_p2,"https_p2.cert");
550                   if (0 == stat (cert_file_p2, &sbuf ))
551                   {
552                           if (0 == remove(cert_file_p2))
553                               GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Successfully removed existing certificate file `%s'\n",cert_file_p2);
554                           else
555                                   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to remove existing certificate file `%s'\n",cert_file_p2);
556                   }
557           }
558   }
559
560   p->th = GNUNET_TRANSPORT_connect (p->cfg, NULL,
561                                     p,
562                                     &notify_receive,
563                                     &notify_connect,
564                                     &notify_disconnect);
565   GNUNET_assert (p->th != NULL);
566 }
567
568 static size_t
569 notify_ready_connect (void *cls, size_t size, void *buf)
570 {
571   return 0;
572 }
573
574 static void
575 exchange_hello_last (void *cls,
576                      const struct GNUNET_MessageHeader *message)
577 {
578   struct PeerContext *me = cls;
579   transmit_handle = NULL;
580   GNUNET_TRANSPORT_get_hello_cancel (p2.th, &exchange_hello_last, me);
581 #if VERBOSE
582   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
583               "Exchanging HELLO with peer (%p)!\n", cls);
584 #endif
585   GNUNET_assert (ok >= 3);
586   OKPP;
587   GNUNET_assert (message != NULL);
588   GNUNET_assert (GNUNET_OK ==
589                  GNUNET_HELLO_get_id ((const struct GNUNET_HELLO_Message *)
590                                       message, &me->id));
591
592   GNUNET_assert(NULL != (transmit_handle = GNUNET_TRANSPORT_notify_transmit_ready (p2.th,
593                                           &p1.id,
594                                           sizeof (struct GNUNET_MessageHeader), 0,
595                                           TIMEOUT,
596                                           &notify_ready_connect,
597                                           &transmit_handle)));
598
599   /* both HELLOs exchanged, get ready to test transmission! */
600   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
601               "Finished exchanging HELLOs, now waiting for transmission!\n");
602 }
603
604
605 static void
606 exchange_hello (void *cls,
607                 const struct GNUNET_MessageHeader *message)
608 {
609   struct PeerContext *me = cls;
610
611   GNUNET_TRANSPORT_get_hello_cancel (p1.th, &exchange_hello, me);
612 #if VERBOSE
613   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
614               "Exchanging HELLO with peer (%p)!\n", cls);
615 #endif
616   GNUNET_assert (ok >= 2);
617   OKPP;
618   GNUNET_assert (message != NULL);
619   GNUNET_assert (GNUNET_OK ==
620                  GNUNET_HELLO_get_id ((const struct GNUNET_HELLO_Message *)
621                                       message, &me->id));
622
623 #if VERBOSE
624   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
625               "Received HELLO size %d\n",
626               GNUNET_HELLO_size((const struct GNUNET_HELLO_Message *)message));
627 #endif
628   GNUNET_TRANSPORT_offer_hello (p2.th, message);
629   GNUNET_TRANSPORT_get_hello (p2.th, &exchange_hello_last, &p2);
630 }
631
632 /**
633  * Return the actual path to a file found in the current
634  * PATH environment variable.
635  *
636  * @param binary the name of the file to find
637  */
638 static char *
639 get_path_from_PATH (char *binary)
640 {
641   char *path;
642   char *pos;
643   char *end;
644   char *buf;
645   const char *p;
646
647   p = getenv ("PATH");
648   if (p == NULL)
649     {
650       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
651                   _("PATH environment variable is unset.\n"));
652       return NULL;
653     }
654   path = GNUNET_strdup (p);     /* because we write on it */
655   buf = GNUNET_malloc (strlen (path) + 20);
656   pos = path;
657
658   while (NULL != (end = strchr (pos, PATH_SEPARATOR)))
659     {
660       *end = '\0';
661       sprintf (buf, "%s/%s", pos, binary);
662       if (GNUNET_DISK_file_test (buf) == GNUNET_YES)
663         {
664           GNUNET_free (path);
665           return buf;
666         }
667       pos = end + 1;
668     }
669   sprintf (buf, "%s/%s", pos, binary);
670   if (GNUNET_DISK_file_test (buf) == GNUNET_YES)
671     {
672       GNUNET_free (path);
673       return buf;
674     }
675   GNUNET_free (buf);
676   GNUNET_free (path);
677   return NULL;
678 }
679
680 /**
681  * Check whether the suid bit is set on a file.
682  * Attempts to find the file using the current
683  * PATH environment variable as a search path.
684  *
685  * @param binary the name of the file to check
686  *
687  * @return GNUNET_YES if the binary is found and
688  *         can be run properly, GNUNET_NO otherwise
689  */
690 static int
691 check_gnunet_nat_binary(char *binary)
692 {
693   struct stat statbuf;
694   char *p;
695 #ifdef MINGW
696   SOCKET rawsock;
697 #endif
698
699 #ifdef MINGW
700   char *binaryexe;
701   GNUNET_asprintf (&binaryexe, "%s.exe", binary);
702   p = get_path_from_PATH (binaryexe);
703   free (binaryexe);
704 #else
705   p = get_path_from_PATH (binary);
706 #endif
707   if (p == NULL)
708     {
709       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
710                   _("Could not find binary `%s' in PATH!\n"),
711                   binary);
712       return GNUNET_NO;
713     }
714   if (0 != STAT (p, &statbuf))
715     {
716       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
717                   _("stat (%s) failed: %s\n"),
718                   p,
719                   STRERROR (errno));
720       GNUNET_free (p);
721       return GNUNET_SYSERR;
722     }
723   GNUNET_free (p);
724 #ifndef MINGW
725   if ( (0 != (statbuf.st_mode & S_ISUID)) &&
726        (statbuf.st_uid == 0) )
727     return GNUNET_YES;
728   return GNUNET_NO;
729 #else
730   rawsock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP);
731   if (INVALID_SOCKET == rawsock)
732     {
733       DWORD err = GetLastError ();
734       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
735                   "socket (AF_INET, SOCK_RAW, IPPROTO_ICMP) have failed! GLE = %d\n", err);
736       return GNUNET_NO; /* not running as administrator */
737     }
738   closesocket (rawsock);
739   return GNUNET_YES;
740 #endif
741 }
742
743 static void
744 run (void *cls,
745      char *const *args,
746      const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg)
747 {
748   GNUNET_assert (ok == 1);
749   OKPP;
750   die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
751                                            &end_badly,
752                                            NULL);
753   if (is_tcp)
754     {
755       setup_peer (&p1, "test_transport_api_tcp_peer1.conf");
756       setup_peer (&p2, "test_transport_api_tcp_peer2.conf");
757     }
758   else if (is_http)
759     {
760       setup_peer (&p1, "test_transport_api_rel_http_peer1.conf");
761       setup_peer (&p2, "test_transport_api_rel_http_peer2.conf");
762     }
763   else if (is_https)
764     {
765       setup_peer (&p1, "test_transport_api_rel_https_peer1.conf");
766       setup_peer (&p2, "test_transport_api_rel_https_peer2.conf");
767     }
768   else if (is_udp)
769     {
770       setup_peer (&p1, "test_transport_api_udp_peer1.conf");
771       setup_peer (&p2, "test_transport_api_udp_peer2.conf");
772     }
773   else if (is_unix)
774     {
775       setup_peer (&p1, "test_transport_api_unix_peer1.conf");
776       setup_peer (&p2, "test_transport_api_unix_peer2.conf");
777     }
778   else if (is_tcp_nat)
779     {
780       setup_peer (&p1, "test_transport_api_tcp_nat_peer1.conf");
781       setup_peer (&p2, "test_transport_api_tcp_nat_peer2.conf");
782     }
783   else
784     GNUNET_assert (0);
785   GNUNET_assert(p1.th != NULL);
786   GNUNET_assert(p2.th != NULL);
787   GNUNET_TRANSPORT_get_hello (p1.th, &exchange_hello, &p1);
788 }
789
790
791 static int
792 check ()
793 {
794   char *const argv[] = { "test-transport-api-reliability",
795     "-c",
796     "test_transport_api_data.conf",
797 #if VERBOSE
798     "-L", "DEBUG",
799 #endif
800     NULL
801   };
802   struct GNUNET_GETOPT_CommandLineOption options[] = {
803     GNUNET_GETOPT_OPTION_END
804   };
805
806 #if WRITECONFIG
807   setTransportOptions("test_transport_api_data.conf");
808 #endif
809   ok = 1;
810
811   if ((GNUNET_YES == is_tcp_nat) && (check_gnunet_nat_binary("gnunet-nat-server") != GNUNET_YES))
812     {
813       GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Not running NAT test case, binaries not properly installed.\n");
814       return 0;
815     }
816
817   GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1,
818                       argv, "test-transport-api-reliability", "nohelp",
819                       options, &run, &ok);
820   stop_arm (&p1);
821   stop_arm (&p2);
822
823   if (is_https)
824   {
825     struct stat sbuf;
826     if (0 == stat (cert_file_p1, &sbuf ))
827     {
828       if (0 == remove(cert_file_p1))
829         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Successfully removed existing certificate file `%s'\n",cert_file_p1);
830       else
831         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to remove certfile `%s'\n",cert_file_p1);
832     }
833
834     if (0 == stat (key_file_p1, &sbuf ))
835     {
836       if (0 == remove(key_file_p1))
837         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Successfully removed private key file `%s'\n",key_file_p1);
838       else
839         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to private key file `%s'\n",key_file_p1);
840     }
841
842     if (0 == stat (cert_file_p2, &sbuf ))
843     {
844       if (0 == remove(cert_file_p2))
845         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Successfully removed existing certificate file `%s'\n",cert_file_p2);
846       else
847         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to remove certfile `%s'\n",cert_file_p2);
848     }
849
850     if (0 == stat (key_file_p2, &sbuf ))
851     {
852       if (0 == remove(key_file_p2))
853         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Successfully removed private key file `%s'\n",key_file_p2);
854       else
855         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to private key file `%s'\n",key_file_p2);
856     }
857     GNUNET_free(key_file_p1);
858     GNUNET_free(key_file_p2);
859     GNUNET_free(cert_file_p1);
860     GNUNET_free(cert_file_p2);
861   }
862
863   return ok;
864 }
865
866
867 int
868 main (int argc, char *argv[])
869 {
870   int ret;
871 #ifdef MINGW
872   return GNUNET_SYSERR;
873 #endif
874
875   GNUNET_DISK_directory_remove ("/tmp/test-gnunetd-transport-peer-1");
876   GNUNET_DISK_directory_remove ("/tmp/test-gnunetd-transport-peer-2");
877
878   if (strstr(argv[0], "tcp_nat") != NULL)
879     {
880       is_tcp_nat = GNUNET_YES;
881       GNUNET_asprintf(&test_name, "tcp_nat");
882     }
883   else if (strstr(argv[0], "tcp") != NULL)
884     {
885       is_tcp = GNUNET_YES;
886       GNUNET_asprintf(&test_name, "tcp");
887     }
888   else if (strstr(argv[0], "https") != NULL)
889     {
890       is_https = GNUNET_YES;
891       GNUNET_asprintf(&test_name, "https");
892     }
893   else if (strstr(argv[0], "http") != NULL)
894     {
895       is_http = GNUNET_YES;
896       GNUNET_asprintf(&test_name, "http");
897     }
898   else if (strstr(argv[0], "udp") != NULL)
899     {
900       is_udp = GNUNET_YES;
901       GNUNET_asprintf(&test_name, "udp");
902     }
903   else if (strstr(argv[0], "unix") != NULL)
904     {
905       is_unix = GNUNET_YES;
906       GNUNET_asprintf(&test_name, "unix");
907     }
908   GNUNET_log_setup ("test-transport-api-reliability",
909 #if VERBOSE
910                     "DEBUG",
911 #else
912                     "WARNING",
913 #endif
914                     NULL);
915   ret = check ();
916   GNUNET_DISK_directory_remove ("/tmp/test-gnunetd-transport-peer-1");
917   GNUNET_DISK_directory_remove ("/tmp/test-gnunetd-transport-peer-2");
918   GNUNET_free_non_null(test_name);
919   return ret;
920 }
921
922 /* end of test_transport_api_reliability.c */