Add files for swift over UDP.
[swifty.git] / src / libswift_udp / nat_test_server.c
1 /*
2  *  nat_test_server.c
3  *  NAT type testing (server).
4  *
5  *  Created by Gertjan Halkes.
6  *  Copyright 2010 Delft University of Technology. All rights reserved.
7  *
8  */
9
10 //FIXME: add timestamp to log output
11
12 #include <stdlib.h>
13 #include <stdio.h>
14 #include <stdarg.h>
15 #include <unistd.h>
16 #include <sys/time.h>
17 #include <sys/types.h>
18 #include <sys/socket.h>
19 #include <netinet/ip.h>
20 #include <arpa/inet.h>
21 #include <errno.h>
22
23 #define REQUEST_MAGIC 0x5a9e5fa1
24 #define REPLY_MAGIC 0xa655c5d5
25 #define REPLY_SEC_MAGIC 0x85e4a5ca
26
27 static int has_secondary;
28
29 /** Alert the user of a fatal error and quit.
30     @param fmt The format string for the message. See fprintf(3) for details.
31     @param ... The arguments for printing.
32 */
33 void fatal(const char *fmt, ...) {
34     va_list args;
35
36     va_start(args, fmt);
37     vfprintf(stderr, fmt, args);
38     va_end(args);
39     exit(EXIT_FAILURE);
40 }
41
42 const char *getTimestamp(void) {
43     static char timeBuffer[1024];
44     struct timeval now;
45     double nowF;
46
47     gettimeofday(&now, NULL);
48     nowF = (double) now.tv_sec + (double) now.tv_usec / 1000000;
49     snprintf(timeBuffer, 1024, "%.4f", nowF);
50     return timeBuffer;
51 }
52
53 int main(int argc, char *argv[]) {
54     struct sockaddr_in local, remote, secondary;
55     uint32_t packet[3];
56     int c, sock, sock2, sock3, sock4;
57     ssize_t result;
58
59     local.sin_addr.s_addr = INADDR_ANY;
60
61     while ((c = getopt(argc, argv, "s:")) > 0) {
62         switch (c) {
63             case 's':
64                 has_secondary = 1;
65                 secondary.sin_addr.s_addr = inet_addr(optarg);
66                 break;
67             default:
68                 fatal("Unknown option %c\n", c);
69                 break;
70         }
71     }
72
73     if (argc - optind != 3)
74         fatal("Usage: nat_test_server [<options>] <primary address> <primary port> <secondary port>\n");
75
76     local.sin_family = AF_INET;
77     local.sin_addr.s_addr = inet_addr(argv[optind++]);
78     local.sin_port = htons(atoi(argv[optind++]));
79
80     if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0)
81         fatal("Error opening primary socket: %m\n");
82     if (bind(sock, (struct sockaddr *) &local, sizeof(local)) < 0)
83         fatal("Error binding primary socket: %m\n");
84
85     if (has_secondary) {
86         secondary.sin_family = AF_INET;
87         secondary.sin_port = local.sin_port;
88
89         if ((sock3 = socket(PF_INET, SOCK_DGRAM, 0)) < 0)
90             fatal("Error opening primary socket on secondary address: %m\n");
91         if (bind(sock3, (struct sockaddr *) &secondary, sizeof(secondary)) < 0)
92             fatal("Error binding primary socket on secondary address: %m\n");
93     }
94
95     local.sin_port = htons(atoi(argv[optind++]));
96
97     if ((sock2 = socket(PF_INET, SOCK_DGRAM, 0)) < 0)
98         fatal("Error opening secondary socket: %m\n");
99     if (bind(sock2, (struct sockaddr *) &local, sizeof(local)) < 0)
100         fatal("Error binding secondary socket: %m\n");
101
102     if (has_secondary) {
103         secondary.sin_port = local.sin_port;
104
105         if ((sock4 = socket(PF_INET, SOCK_DGRAM, 0)) < 0)
106             fatal("Error opening secondary socket on secondary address: %m\n");
107         if (bind(sock4, (struct sockaddr *) &secondary, sizeof(secondary)) < 0)
108             fatal("Error binding secondary socket on secondary address: %m\n");
109     }
110
111     while (1) {
112         socklen_t socklen = sizeof(remote);
113         if ((result = recvfrom(sock, &packet, sizeof(packet), 0, (struct sockaddr *) &remote, &socklen)) < 0) {
114             if (errno == EAGAIN)
115                 continue;
116             fatal("%s: Error receiving packet: %m\n", getTimestamp());
117         } else if (result != 4 || ntohl(packet[0]) != REQUEST_MAGIC) {
118             fprintf(stderr, "Strange packet received from %s\n", inet_ntoa(remote.sin_addr));
119         } else {
120             fprintf(stderr, "%s: Received packet from %s:%d\n", getTimestamp(), inet_ntoa(remote.sin_addr), ntohs(remote.sin_port));
121             packet[0] = htonl(REPLY_MAGIC);
122             packet[1] = remote.sin_addr.s_addr;
123             *(uint16_t *)(packet + 2) = remote.sin_port;
124     retry:
125             if (sendto(sock, packet, 10, 0, (const struct sockaddr *) &remote, socklen) < 10) {
126                 if (errno == EAGAIN)
127                     goto retry;
128                 fprintf(stderr, "%s: Error sending packet on primary socket: %m\n", getTimestamp());
129             }
130     retry2:
131             if (sendto(sock2, packet, 10, 0, (const struct sockaddr *) &remote, socklen) < 10) {
132                 if (errno == EAGAIN)
133                     goto retry2;
134                 fprintf(stderr, "%s: Error sending packet on secondary socket: %m\n", getTimestamp());
135             }
136
137             if (has_secondary) {
138                 packet[0] = htonl(REPLY_SEC_MAGIC);
139         retry3:
140                 if (sendto(sock3, packet, 4, 0, (const struct sockaddr *) &remote, socklen) < 4) {
141                     if (errno == EAGAIN)
142                         goto retry3;
143                     fprintf(stderr, "%s: Error sending packet on primary socket on secondary address: %m\n", getTimestamp());
144                 }
145         retry4:
146                 if (sendto(sock4, packet, 4, 0, (const struct sockaddr *) &remote, socklen) < 4) {
147                     if (errno == EAGAIN)
148                         goto retry4;
149                     fprintf(stderr, "%s: Error sending packet on secondary socket on secondary address: %m\n", getTimestamp());
150                 }
151             }
152
153         }
154     }
155     return 0;
156 }