test-socket-signal: properly handle receive error in receiver
[p2p-testing-infrastructure.git] / Utils / test-socket-signal / receiver.c
1 /*
2  * inet (BSD) socket receiver application
3  *       starts a listener socket that receives data from requesting
4  *       client
5  *
6  * 2010, Razvan Deaconescu
7  */
8
9 #include <stdio.h>
10 #include <string.h>
11 #include <stdlib.h>
12 #include <unistd.h>
13 #include <sys/types.h>
14 #include <sys/socket.h>
15 #include <time.h>
16 #include <getopt.h>
17
18 #include "sock_util.h"
19 #include "utils.h"
20
21
22 #define DEFAULT_LISTEN_PORT             54321
23 #define DEFAULT_SERVER_BACKLOG          5
24 #define DEFAULT_BUFFER_SIZE             1024
25
26 #define PACKET_INDEX_SIZE               sizeof(unsigned long long)
27 #define PACKET_TIMESPEC_SIZE            sizeof(time_t)
28 #define PACKET_PAYLOAD_SIZE             (PACKET_SIZE - PACKET_INDEX_SIZE - PACKET_TIMESPEC_SIZE)
29 #define PACKET_SIZE                     (cmd_args.buffer_size)
30
31 /*
32  * TODO: fix nomenclature (TIMER_BASE_PERIOD, cmd_args.frequency)
33  * run the timer once each TIMER_BASE_PERIOD
34  * this is divided by cmd_args.frequency for a shorter period
35  */
36
37 static struct {
38         unsigned short int listen_port;
39         size_t buffer_size;
40 } cmd_args = {
41         .listen_port = DEFAULT_LISTEN_PORT,
42         .buffer_size = DEFAULT_BUFFER_SIZE,
43 };
44
45 static char *rcv_buf;
46 static char *snd_buf;
47
48 /* connection socket */
49 static int connectfd;
50
51 static void init_buffer_random(char *buf, size_t len)
52 {
53         size_t i;
54
55         srand(time(NULL));
56
57         for (i = 0; i < len-2; i++)
58                 buf[i] = (char) (rand() % 26) + 'a';
59         buf[i] = '\0';
60 }
61
62 static void init_buffers(void)
63 {
64         init_buffer_random(rcv_buf, PACKET_SIZE);
65         init_buffer_random(snd_buf, PACKET_SIZE);
66 }
67
68 static void init(void)
69 {
70         rcv_buf = malloc(PACKET_SIZE * sizeof(char));
71         snd_buf = malloc(PACKET_SIZE * sizeof(char));
72         DIE(snd_buf == NULL, "malloc");
73
74         init_buffers();
75 }
76
77 static void cleanup(void)
78 {
79         free(rcv_buf);
80         free(snd_buf);
81 }
82
83 static void fill_send_buffer(void)
84 {
85         static unsigned long long index = 0;
86         char *ptr;
87         time_t curr_time_secs;
88
89         curr_time_secs = time(NULL);
90
91         ptr = snd_buf + PACKET_PAYLOAD_SIZE;
92         * (unsigned long long *) ptr = index;
93         ptr += PACKET_INDEX_SIZE;
94         * (time_t *) ptr = curr_time_secs;
95
96         printf("[send] index: %llu curr_time_secs: %lu\n", index, curr_time_secs);
97         index++;
98 }
99
100 static ssize_t send_buffer(int sockfd)
101 {
102         return send(sockfd, snd_buf, PACKET_SIZE, 0);
103 }
104
105 static ssize_t receive_buffer(int sockfd)
106 {
107         ssize_t nbytes = 0;
108         ssize_t n;
109
110         while (nbytes < (ssize_t) PACKET_SIZE) {
111                 n = recv(sockfd, rcv_buf, PACKET_SIZE - nbytes, 0);
112                 DIE(n < 0, "recv");
113
114                 if (n == 0)
115                         break;
116                 nbytes += n;
117         }
118
119         return nbytes;
120 }
121
122 static void print_buffer_meta(const char *buf, size_t len)
123 {
124         unsigned long long index;
125         time_t curr_time_secs;
126         time_t sender_time_secs;
127         const char *ptr;
128
129         curr_time_secs = time(NULL);
130
131         ptr = buf + len - PACKET_INDEX_SIZE - PACKET_TIMESPEC_SIZE;
132         index = * (unsigned long long *) ptr;
133         ptr += PACKET_INDEX_SIZE;
134         sender_time_secs = * (time_t *) ptr;
135
136         printf("[recv] index %llu, ", index);
137         if (sender_time_secs > curr_time_secs)
138                 printf("negative latency (weird)\n");
139         else
140                 printf("latency %lu seconds (curr_time = %lu, sender_time = %lu)\n",
141                                 curr_time_secs - sender_time_secs,
142                                 curr_time_secs,
143                                 sender_time_secs);
144 }
145
146 static void usage(const char *argv0)
147 {
148         fprintf(stderr, "Usage: %s [-h | --help] [-p | --port <listen-port>] [-b | --buffer-size <buffer-size>]\n", argv0);
149 }
150
151 static void print_args(void)
152 {
153         printf("listen_port: %hu\n", cmd_args.listen_port);
154         printf("buffer_size: %lu\n", cmd_args.buffer_size);
155 }
156
157 static void parse_args(int argc, char **argv)
158 {
159         int c;
160
161         while (1) {
162                 int option_index = 0;
163                 static struct option long_options[] = {
164                         {"port", 1, NULL, 'p'},
165                         {"buffer-size", 1, NULL, 'b'},
166                         {"help", 0, NULL, 'h'},
167                         {0, 0, 0, 0}
168                 };
169
170                 c = getopt_long(argc, argv, "hp:b:",
171                                 long_options, &option_index);
172                 if (c == -1)
173                         break;
174
175                 switch (c) {
176                 case 0:
177                         printf("option %s", long_options[option_index].name);
178                         if (optarg)
179                                 printf(" with arg %s", optarg);
180                         printf("\n");
181                         break;
182
183                 case 'p':
184                         /* TODO: use strtoul */
185                         cmd_args.listen_port = atoi(optarg);
186                         break;
187
188                 case 'b':
189                         /* TODO: use strtoul */
190                         cmd_args.buffer_size = atoi(optarg);
191                         break;
192
193                 case 'h':
194                         usage(argv[0]);
195                         exit(EXIT_SUCCESS);
196                         break;
197
198                 case '?':
199                         break;
200
201                 default:
202                         printf("?? getopt returned character code 0%o ??\n", c);
203                 }
204         }
205
206         if (optind != argc) {
207                 usage(argv[0]);
208                 exit(EXIT_FAILURE);
209         }
210
211         print_args();
212 }
213
214 int main(int argc, char **argv)
215 {
216         int listenfd;
217         int sockfd;
218         struct sockaddr_in addr;
219         socklen_t addrlen = 0;
220
221         parse_args(argc, argv);
222
223         init();
224
225         listenfd = tcp_listen_connections(cmd_args.listen_port,
226                         DEFAULT_SERVER_BACKLOG);
227         DIE(listenfd < 0, "tcp_listen_connections");
228
229 new_connection:
230         sockfd = accept(listenfd, (SSA *) &addr, &addrlen);
231         DIE(sockfd < 0, "accept");
232
233         while (1) {
234                 ssize_t nbytes;
235
236                 nbytes = receive_buffer(sockfd);
237                 DIE(nbytes < 0, "receive_buffer");
238                 if (nbytes == 0) {
239                         printf("Connection closed.\n");
240                         goto new_connection;
241                 }
242
243                 print_buffer_meta(rcv_buf, PACKET_SIZE);
244         }
245
246         close(sockfd);
247         close(listenfd);
248
249         cleanup();
250
251         return 0;
252 }