test_echo_tcp_socket_options.c: add tests for TCP_INFO
[anoopcs/socket_wrapper.git] / tests / echo_srv.c
1 #include "config.h"
2
3 #include <errno.h>
4
5 #include <sys/types.h>
6 #include <sys/socket.h>
7 #include <sys/stat.h>
8 #include <sys/wait.h>
9
10 #include <arpa/inet.h>
11 #include <netinet/in.h>
12 #include <netinet/tcp.h>
13 #ifdef HAVE_NETINET_TCP_FSM_H
14 #include <netinet/tcp_fsm.h>
15 #endif
16 #include <netdb.h>
17 #include <resolv.h>
18
19 #include <fcntl.h>
20 #include <getopt.h>
21 #include <unistd.h>
22
23 #include <string.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <stdbool.h>
27
28 #ifndef PIDFILE
29 #define PIDFILE     "echo_srv.pid"
30 #endif  /* PIDFILE */
31
32 #define ECHO_SRV_IPV4 "127.0.0.10"
33 /* socket wrapper IPv6 prefix  fd00::5357:5fxx */
34 #define ECHO_SRV_IPV6 "fd00::5357:5f0a"
35
36 #define DFL_PORT    7
37 #define BACKLOG     16
38
39 #ifndef BUFSIZE
40 #define BUFSIZE     0x20000 /* 128K */
41 #endif /* BUFSIZE */
42
43 #ifndef discard_const
44 #define discard_const(ptr) ((void *)((uintptr_t)(ptr)))
45 #endif
46
47 #ifndef discard_const_p
48 #define discard_const_p(type, ptr) ((type *)discard_const(ptr))
49 #endif
50
51 #ifndef ZERO_STRUCT
52 #define ZERO_STRUCT(x) memset((char *)&(x), 0, sizeof(x))
53 #endif
54
55 struct torture_address {
56         socklen_t sa_socklen;
57         union {
58                 struct sockaddr s;
59                 struct sockaddr_in in;
60 #ifdef HAVE_IPV6
61                 struct sockaddr_in6 in6;
62 #endif
63                 struct sockaddr_storage ss;
64         } sa;
65 };
66
67 struct echo_srv_opts {
68     int port;
69     int socktype;
70     bool daemon;
71     char *bind;
72     const char *pidfile;
73 };
74
75 #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
76
77 #if defined(IP_PKTINFO) || defined(IP_RECVDSTADDR) || defined(IPV6_PKTINFO)
78 union pktinfo {
79 #ifdef HAVE_STRUCT_IN6_PKTINFO
80         struct in6_pktinfo pkt6;
81 #endif
82 #ifdef HAVE_STRUCT_IN_PKTINFO
83         struct in_pktinfo pkt4;
84 #elif defined(IP_RECVDSTADDR)
85         struct in_addr pkt4;
86 #endif
87         char c;
88 };
89
90 #define HAVE_UNION_PKTINFO 1
91 #endif /* IP_PKTINFO || IP_RECVDSTADDR || IPV6_PKTINFO */
92
93 static const char *echo_server_address(int family)
94 {
95         switch (family) {
96         case AF_INET: {
97                 const char *ip4 = getenv("TORTURE_SERVER_ADDRESS_IPV4");
98
99                 if (ip4 != NULL && ip4[0] != '\0') {
100                         return ip4;
101                 }
102
103                 return ECHO_SRV_IPV4;
104         }
105 #ifdef HAVE_IPV6
106         case AF_INET6: {
107                 const char *ip6 = getenv("TORTURE_SERVER_ADDRESS_IPV6");
108
109                 if (ip6 != NULL && ip6[0] != '\0') {
110                         return ip6;
111                 }
112
113                 return ECHO_SRV_IPV6;
114         }
115 #endif
116         default:
117                 return NULL;
118         }
119
120         return NULL;
121 }
122 #endif /* HAVE_STRUCT_MSGHDR_MSG_CONTROL */
123
124 static void _assert_return_code(int rc,
125                                 int err,
126                                 const char * const file,
127                                 const int line)
128 {
129         if (rc < 0) {
130                 fprintf(stderr, "Fatal error: %s\n", strerror(err));
131                 fprintf(stderr, "%s:%d", file, line);
132
133                 abort();
134         }
135 }
136 #define assert_return_code(rc, err) \
137         _assert_return_code(rc, err, __FILE__, __LINE__)
138
139
140 static int pidfile(const char *path)
141 {
142     int err;
143     int fd;
144     char pid_str[32] = { 0 };
145     ssize_t nwritten;
146     size_t len;
147
148     fd = open(path, O_RDONLY, 0644);
149     err = errno;
150     if (fd != -1) {
151         close(fd);
152         return EEXIST;
153     } else if (err != ENOENT) {
154         return err;
155     }
156
157     fd = open(path, O_CREAT | O_WRONLY | O_EXCL, 0644);
158     err = errno;
159     if (fd == -1) {
160         return err;
161     }
162
163     snprintf(pid_str, sizeof(pid_str) -1, "%u\n", (unsigned int) getpid());
164     len = strlen(pid_str);
165
166     nwritten = write(fd, pid_str, len);
167     close(fd);
168     if (nwritten != (ssize_t)len) {
169         return EIO;
170     }
171
172     return 0;
173 }
174
175 static int become_daemon(void)
176 {
177     int ret;
178     pid_t child_pid;
179     int fd;
180     int i;
181
182     if (getppid() == 1) {
183         return 0;
184     }
185
186     child_pid = fork();
187     if (child_pid == -1) {
188         ret = errno;
189         perror("fork");
190         return ret;
191     } else if (child_pid > 0) {
192         exit(0);
193     }
194
195     /* If a working directory was defined, go there */
196 #ifdef WORKING_DIR
197     chdir(WORKING_DIR);
198 #endif
199
200     ret = setsid();
201     if (ret == -1) {
202         ret = errno;
203         perror("setsid");
204         return ret;
205     }
206
207     for (i = 0; i < 3; i++) {
208         close(i);
209
210         fd = open("/dev/null", O_RDWR, 0);
211         if (fd < 0) {
212             fd = open("/dev/null", O_WRONLY, 0);
213         }
214         if (fd < 0) {
215             ret = errno;
216             perror("Can't open /dev/null");
217             return ret;
218         }
219         if (fd != i) {
220             perror("Didn't get correct fd");
221             close(fd);
222             return EINVAL;
223         }
224     }
225
226     umask(0177);
227     return 0;
228 }
229
230 static void set_sock_pktinfo(int sock, int family)
231 {
232         int sockopt = 1;
233         int option = 0;
234         int proto = 0;
235         int rc;
236
237         switch(family) {
238         case AF_INET:
239                 proto = IPPROTO_IP;
240 #ifdef IP_PKTINFO
241                 option = IP_PKTINFO;
242 #elif IP_RECVDSTADDR
243                 option = IP_RECVDSTADDR;
244 #else
245                 return;
246 #endif /* IP_PKTINFO */
247                 break;
248 #ifdef HAVE_IPV6
249 #ifdef IPV6_RECVPKTINFO
250         case AF_INET6:
251                 proto = IPPROTO_IPV6;
252                 option = IPV6_RECVPKTINFO;
253                 break;
254 #endif /* IPV6_RECVPKTINFO */
255 #endif /* HAVE_IPV6 */
256         default:
257                 return;
258         }
259
260         rc = setsockopt(sock, proto, option, &sockopt, sizeof(sockopt));
261         assert_return_code(rc, errno);
262 }
263
264 /* Returns 0 on success, errno on failure. If successful,
265  * sock is a ready to use socket */
266 static int setup_srv(struct echo_srv_opts *opts, int *_sock)
267 {
268     struct addrinfo hints;
269     struct addrinfo *res, *ri;
270     char svc[6];
271     int ret;
272     int sock;
273
274     memset(&hints, 0, sizeof(hints));
275     hints.ai_family = AF_UNSPEC;
276     hints.ai_socktype = opts->socktype;
277     hints.ai_flags = AI_PASSIVE;
278
279     snprintf(svc, sizeof(svc), "%d", opts->port);
280
281     ret = getaddrinfo(opts->bind, svc, &hints, &res);
282     if (ret != 0) {
283         return errno;
284     }
285
286     for (ri = res; ri != NULL; ri = ri->ai_next) {
287         sock = socket(ri->ai_family, ri->ai_socktype,
288                       ri->ai_protocol);
289         if (sock == -1) {
290             ret = errno;
291             freeaddrinfo(res);
292             perror("socket");
293             return ret;
294         }
295
296         if (ri->ai_socktype == SOCK_DGRAM) {
297             set_sock_pktinfo(sock, ri->ai_family);
298         }
299
300         ret = bind(sock, ri->ai_addr, ri->ai_addrlen);
301         if (ret == 0) {
302             break;
303         }
304
305         close(sock);
306     }
307     freeaddrinfo(res);
308
309     if (ri == NULL) {
310         fprintf(stderr, "Could not bind\n");
311         return EFAULT;
312     }
313
314     if (opts->socktype == SOCK_STREAM) {
315         ret = listen(sock, BACKLOG);
316         if (ret == -1) {
317             ret = errno;
318             close(sock);
319             perror("listen");
320             return ret;
321         }
322 #ifdef TCP_INFO
323         {
324             struct tcp_info info;
325             socklen_t optlen = sizeof(info);
326
327             ZERO_STRUCT(info);
328             ret = getsockopt(sock, IPPROTO_TCP, TCP_INFO, &info, &optlen);
329             if (ret == -1) {
330                 ret = errno;
331                 perror("TCP_INFO failed");
332                 close(sock);
333                 return ret;
334             }
335 #ifdef HAVE_NETINET_TCP_FSM_H
336 /* This is FreeBSD */
337 # define __TCP_LISTEN TCPS_LISTEN
338 #else
339 /* This is Linux */
340 # define __TCP_LISTEN TCP_LISTEN
341 #endif
342             if (info.tcpi_state != __TCP_LISTEN) {
343                 errno = ret = ERANGE;
344                 perror("not __TCP_LISTEN => ERANGE...");
345                 close(sock);
346                 return ret;
347             }
348         }
349 #endif /* TCP_INFO */
350     }
351
352     *_sock = sock;
353     return 0;
354 }
355
356 static int socket_dup(int s)
357 {
358     struct torture_address cli_addr1 = {
359         .sa_socklen = sizeof(struct sockaddr_storage),
360     };
361     struct torture_address srv_addr1 = {
362         .sa_socklen = sizeof(struct sockaddr_storage),
363     };
364
365     struct torture_address cli_addr2 = {
366         .sa_socklen = sizeof(struct sockaddr_storage),
367     };
368     struct torture_address srv_addr2 = {
369         .sa_socklen = sizeof(struct sockaddr_storage),
370     };
371
372     struct torture_address cli_addr3 = {
373         .sa_socklen = sizeof(struct sockaddr_storage),
374     };
375     struct torture_address srv_addr3 = {
376         .sa_socklen = sizeof(struct sockaddr_storage),
377     };
378
379     int s2;
380     int rc;
381
382     rc = getsockname(s, &srv_addr1.sa.s, &srv_addr1.sa_socklen);
383     if (rc == -1) {
384         perror("getsockname");
385         return -1;
386     }
387
388     rc = getpeername(s, &cli_addr1.sa.s, &cli_addr1.sa_socklen);
389     if (rc == -1) {
390         perror("getpeername");
391         return -1;
392     }
393
394     if (cli_addr1.sa.ss.ss_family != srv_addr1.sa.ss.ss_family) {
395         perror("client/server family mismatch");
396         return -1;
397     }
398
399     /* Test dup */
400     s2 = dup(s);
401     if (s2 == -1) {
402         perror("dup");
403         return -1;
404     }
405     close(s);
406
407     rc = getsockname(s2, &srv_addr2.sa.s, &srv_addr2.sa_socklen);
408     if (rc == -1) {
409         perror("getsockname");
410         close(s2);
411         return -1;
412     }
413
414     rc = getpeername(s2, &cli_addr2.sa.s, &cli_addr2.sa_socklen);
415     if (rc == -1) {
416         perror("getpeername");
417         close(s2);
418         return -1;
419     }
420
421     if (cli_addr1.sa_socklen != cli_addr2.sa_socklen ||
422         srv_addr1.sa_socklen != srv_addr2.sa_socklen) {
423         perror("length mismatch");
424         close(s2);
425         return -1;
426     }
427
428     switch(cli_addr1.sa.ss.ss_family) {
429     case AF_INET: {
430         rc = memcmp(&cli_addr1.sa.in, &cli_addr2.sa.in, sizeof(struct sockaddr_in));
431         if (rc != 0) {
432             perror("client mismatch");
433         }
434
435         rc = memcmp(&srv_addr1.sa.in, &srv_addr2.sa.in, sizeof(struct sockaddr_in));
436         if (rc != 0) {
437             perror("server mismatch");
438         }
439         break;
440     }
441 #ifdef HAVE_IPV6
442     case AF_INET6: {
443         rc = memcmp(&cli_addr1.sa.in6, &cli_addr2.sa.in6, sizeof(struct sockaddr_in6));
444         if (rc != 0) {
445             perror("client mismatch");
446         }
447
448         rc = memcmp(&srv_addr1.sa.in6, &srv_addr2.sa.in6, sizeof(struct sockaddr_in6));
449         if (rc != 0) {
450             perror("server mismatch");
451         }
452         break;
453     }
454 #endif
455     default:
456         perror("family mismatch");
457         close(s2);
458         return -1;
459     }
460
461     /* Test dup2 */
462     s = dup2(s2, s);
463     close(s2);
464     if (s == -1) {
465         perror("dup");
466         return -1;
467     }
468
469     rc = getsockname(s, &srv_addr3.sa.s, &srv_addr3.sa_socklen);
470     if (rc == -1) {
471         perror("getsockname");
472         close(s);
473         return -1;
474     }
475
476     rc = getpeername(s, &cli_addr3.sa.s, &cli_addr3.sa_socklen);
477     if (rc == -1) {
478         perror("getpeername");
479         close(s);
480         return -1;
481     }
482
483     if (cli_addr2.sa_socklen != cli_addr3.sa_socklen ||
484         srv_addr2.sa_socklen != srv_addr3.sa_socklen) {
485         perror("length mismatch");
486         close(s);
487         return -1;
488     }
489
490     switch(cli_addr2.sa.ss.ss_family) {
491     case AF_INET: {
492         rc = memcmp(&cli_addr1.sa.in, &cli_addr2.sa.in, sizeof(struct sockaddr_in));
493         if (rc != 0) {
494             perror("client mismatch");
495         }
496
497         rc = memcmp(&srv_addr1.sa.in, &srv_addr2.sa.in, sizeof(struct sockaddr_in));
498         if (rc != 0) {
499             perror("server mismatch");
500         }
501         break;
502     }
503 #ifdef HAVE_IPV6
504     case AF_INET6: {
505         rc = memcmp(&cli_addr1.sa.in6, &cli_addr2.sa.in6, sizeof(struct sockaddr_in6));
506         if (rc != 0) {
507             perror("client mismatch");
508         }
509
510         rc = memcmp(&srv_addr1.sa.in6, &srv_addr2.sa.in6, sizeof(struct sockaddr_in6));
511         if (rc != 0) {
512             perror("server mismatch");
513         }
514         break;
515     }
516 #endif
517     default:
518         perror("family mismatch");
519         close(s);
520         return -1;
521     }
522
523     return s;
524 }
525
526 static void echo_tcp(int sock)
527 {
528     struct torture_address addr = {
529         .sa_socklen = sizeof(struct sockaddr_storage),
530     };
531
532     char buf[BUFSIZE];
533     ssize_t bret;
534
535     int client_sock = -1;
536     int s;
537     pid_t pid;
538
539     while (1) {
540         s = accept(sock, &addr.sa.s, &addr.sa_socklen);
541         if (s == -1) {
542             perror("accept");
543             goto done;
544         }
545
546         pid = fork();
547         if (pid == -1) {
548             perror("fork");
549         } else if (pid == 0) {
550             close(sock);
551             client_sock = socket_dup(s);
552             if (client_sock == -1) {
553                 perror("socket_dup");
554                 goto done;
555             }
556
557             while (1) {
558                 bret = recv(client_sock, buf, BUFSIZE, 0);
559                 if (bret == -1) {
560                     perror("recv");
561                     goto done;
562                 } else if (bret == 0) {
563                     break;
564                 }
565
566                 bret = send(client_sock, buf, bret, 0);
567                 if (bret == -1) {
568                     perror("send");
569                     goto done;
570                 }
571             }
572             close(s);
573             exit(0);
574         }
575         waitpid(-1, NULL, 0);
576         close(s);
577     }
578
579 done:
580     if (client_sock != -1) {
581         close(client_sock);
582     }
583 }
584
585 static ssize_t echo_udp_recv_from_to(int sock,
586                                      void *buf, size_t buflen, int flags,
587                                      struct torture_address *from,
588                                      struct torture_address *to)
589 {
590         struct msghdr rmsg;
591         struct iovec riov;
592         ssize_t ret;
593
594 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL) && defined(HAVE_UNION_PKTINFO)
595         size_t cmlen = CMSG_LEN(sizeof(union pktinfo));
596         char cmsg[cmlen];
597 #endif /* HAVE_STRUCT_MSGHDR_MSG_CONTROL */
598
599         riov.iov_base = buf;
600         riov.iov_len = buflen;
601
602         ZERO_STRUCT(rmsg);
603
604         rmsg.msg_name = &from->sa.s;
605         rmsg.msg_namelen = from->sa_socklen;
606
607         rmsg.msg_iov = &riov;
608         rmsg.msg_iovlen = 1;
609
610 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL) && defined(HAVE_UNION_PKTINFO)
611         memset(cmsg, 0, cmlen);
612
613         rmsg.msg_control = cmsg;
614         rmsg.msg_controllen = cmlen;
615 #endif
616
617         ret = recvmsg(sock, &rmsg, flags);
618         if (ret < 0) {
619                 return ret;
620         }
621         from->sa_socklen = rmsg.msg_namelen;
622
623 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL) && defined(HAVE_UNION_PKTINFO)
624         if (rmsg.msg_controllen > 0) {
625                 struct cmsghdr *cmsgptr;
626
627                 cmsgptr = CMSG_FIRSTHDR(&rmsg);
628                 while (cmsgptr != NULL) {
629                         const char *p;
630
631 #if defined(IP_PKTINFO) && defined(HAVE_STRUCT_IN_PKTINFO)
632                         if (cmsgptr->cmsg_level == IPPROTO_IP &&
633                                         cmsgptr->cmsg_type == IP_PKTINFO) {
634                                 char ip[INET_ADDRSTRLEN] = { 0 };
635                                 struct in_pktinfo *pkt;
636                                 void *cmsg_cast_ptr = CMSG_DATA(cmsgptr);
637
638                                 pkt = (struct in_pktinfo *)cmsg_cast_ptr;
639
640                                 to->sa.in.sin_family = AF_INET;
641                                 to->sa.in.sin_addr = pkt->ipi_addr;
642                                 to->sa_socklen = sizeof(struct sockaddr_in);
643
644                                 p = inet_ntop(AF_INET, &to->sa.in.sin_addr, ip, sizeof(ip));
645                                 if (p == 0) {
646                                         fprintf(stderr, "Failed to convert IP address");
647                                         abort();
648                                 }
649
650                                 if (strcmp(ip, echo_server_address(AF_INET)) != 0) {
651                                         fprintf(stderr, "Wrong IP received");
652                                         abort();
653                                 }
654                         }
655 #endif /* IP_PKTINFO */
656 #ifdef IP_RECVDSTADDR
657                         if (cmsgptr->cmsg_level == IPPROTO_IP &&
658                             cmsgptr->cmsg_type == IP_RECVDSTADDR) {
659                                 char ip[INET_ADDRSTRLEN] = { 0 };
660                                 struct in_addr *addr;
661                                 void *cmsg_cast_ptr = CMSG_DATA(cmsgptr);
662
663                                 addr = (struct in_addr *)cmsg_cast_ptr;
664
665                                 to->sa.in.sin_family = AF_INET;
666                                 to->sa.in.sin_addr = *addr;
667                                 to->sa_socklen = sizeof(struct sockaddr_in);
668
669                                 p = inet_ntop(AF_INET, &to->sa.in.sin_addr, ip, sizeof(ip));
670                                 if (p == 0) {
671                                         fprintf(stderr, "Failed to convert IP address");
672                                         abort();
673                                 }
674
675                                 if (strcmp(ip, echo_server_address(AF_INET)) != 0) {
676                                         fprintf(stderr, "Wrong IP received");
677                                         abort();
678                                 }
679                         }
680 #endif /* IP_RECVDSTADDR */
681 #if defined(IPV6_PKTINFO) && defined(HAVE_STRUCT_IN6_PKTINFO)
682                         if (cmsgptr->cmsg_level == IPPROTO_IPV6 &&
683                                         cmsgptr->cmsg_type == IPV6_PKTINFO) {
684                                 char ip[INET6_ADDRSTRLEN] = { 0 };
685                                 struct in6_pktinfo *pkt6;
686                                 void *cmsg_cast_ptr = CMSG_DATA(cmsgptr);
687
688                                 pkt6 = (struct in6_pktinfo *)cmsg_cast_ptr;
689
690                                 to->sa.in6.sin6_family = AF_INET6;
691                                 to->sa.in6.sin6_addr = pkt6->ipi6_addr;
692
693                                 p = inet_ntop(AF_INET6, &to->sa.in6.sin6_addr, ip, sizeof(ip));
694                                 if (p == 0) {
695                                         fprintf(stderr, "Failed to convert IP address");
696                                         abort();
697                                 }
698
699                                 if (strcmp(ip, echo_server_address(AF_INET6)) != 0) {
700                                         fprintf(stderr, "Wrong IP received");
701                                         abort();
702                                 }
703                         }
704 #endif /* IPV6_PKTINFO */
705                         cmsgptr = CMSG_NXTHDR(&rmsg, cmsgptr);
706                 }
707         } else {
708                 fprintf(stderr, "Failed to receive pktinfo");
709                 abort();
710         }
711 #endif /* HAVE_STRUCT_MSGHDR_MSG_CONTROL && HAVE_UNION_PKTINFO */
712
713         return ret;
714 }
715
716 static ssize_t echo_udp_send_to_from(int sock,
717                                      void *buf, size_t buflen, int flags,
718                                      struct sockaddr *to, socklen_t tolen,
719                                      struct sockaddr *from, socklen_t fromlen)
720 {
721         struct msghdr msg;
722         struct iovec iov;
723         ssize_t ret;
724
725 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL) && defined(HAVE_UNION_PKTINFO)
726         size_t clen = CMSG_SPACE(sizeof(union pktinfo));
727         char cbuf[clen];
728         struct cmsghdr *cmsgptr;
729 #else
730         (void)from; /* unused */
731         (void)fromlen; /* unused */
732 #endif /* HAVE_STRUCT_MSGHDR_MSG_CONTROL && HAVE_UNION_PKTINFO */
733
734         iov.iov_base = buf;
735         iov.iov_len = buflen;
736
737         ZERO_STRUCT(msg);
738
739         msg.msg_name = to;
740         msg.msg_namelen = tolen;
741
742         msg.msg_iov = &iov;
743         msg.msg_iovlen = 1;
744
745 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL) && defined(HAVE_UNION_PKTINFO)
746         memset(cbuf, 0, clen);
747
748         msg.msg_control = cbuf;
749         msg.msg_controllen = clen;
750
751         cmsgptr = CMSG_FIRSTHDR(&msg);
752         msg.msg_controllen = 0;
753
754         switch (from->sa_family) {
755 #if defined(IP_PKTINFO) || defined(IP_SENDSRCADDR)
756         case AF_INET: {
757                 void *cmsg_cast_ptr = CMSG_DATA(cmsgptr);
758 #ifdef IP_PKTINFO
759                 struct in_pktinfo *p = (struct in_pktinfo *)cmsg_cast_ptr;
760 #elif defined(IP_SENDSRCADDR)
761                 struct in_addr *p = (struct in_addr *)cmsg_cast_ptr;
762 #endif
763                 const struct sockaddr_in *from4 =
764                         (const struct sockaddr_in *)(const void *)from;
765
766                 if (fromlen != sizeof(struct sockaddr_in)) {
767                         break;
768                 }
769
770                 cmsgptr->cmsg_level = IPPROTO_IP;
771 #ifdef IP_PKTINFO
772                 cmsgptr->cmsg_type = IP_PKTINFO;
773                 p->ipi_spec_dst = from4->sin_addr;
774 #elif defined(IP_SENDSRCADDR)
775                 cmsgptr->cmsg_type = IP_SENDSRCADDR;
776                 *p = from4->sin_addr;
777 #endif
778                 cmsgptr->cmsg_len = CMSG_LEN(sizeof(*p));
779
780                 msg.msg_controllen = CMSG_SPACE(sizeof(*p));
781
782                 break;
783         }
784 #endif /* IP_PKTINFO || IP_SENDSRCADDR */
785 #ifdef IPV6_PKTINFO
786         case AF_INET6: {
787         void *cast_ptr = CMSG_DATA(cmsgptr);
788                 struct in6_pktinfo *p = (struct in6_pktinfo *)cast_ptr;
789                 const struct sockaddr_in6 *from6 =
790                         (const struct sockaddr_in6 *)(const void *)from;
791
792                 if (fromlen != sizeof(struct sockaddr_in6)) {
793                         break;
794                 }
795
796                 cmsgptr->cmsg_level = IPPROTO_IPV6;
797                 cmsgptr->cmsg_type = IPV6_PKTINFO;
798                 cmsgptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
799
800                 p->ipi6_addr = from6->sin6_addr;
801
802                 msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
803
804                 break;
805         }
806 #endif /* IPV6_PKTINFO */
807         default:
808                 break;
809         }
810 #endif /* HAVE_STRUCT_MSGHDR_MSG_CONTROL && HAVE_UNION_PKTINFO */
811
812         ret = sendmsg(sock, &msg, flags);
813
814         return ret;
815 }
816
817 static void echo_udp(int sock)
818 {
819     struct torture_address saddr = {
820         .sa_socklen = sizeof(struct sockaddr_storage),
821     };
822     struct torture_address daddr = {
823         .sa_socklen = sizeof(struct sockaddr_storage),
824     };
825     ssize_t bret;
826     char buf[BUFSIZE];
827
828     while (1) {
829         bret = echo_udp_recv_from_to(sock,
830                                      buf,
831                                      BUFSIZE,
832                                      0,
833                                      &saddr,
834                                      &daddr);
835         if (bret == -1) {
836             perror("recvfrom");
837             continue;
838         }
839
840         bret = echo_udp_send_to_from(sock,
841                                      buf,
842                                      bret,
843                                      0,
844                                      &saddr.sa.s,
845                                      saddr.sa_socklen,
846                                      &daddr.sa.s,
847                                      daddr.sa_socklen);
848         if (bret == -1) {
849             perror("sendto");
850             continue;
851         }
852     }
853 }
854
855 static void echo(int sock, struct echo_srv_opts *opts)
856 {
857     switch (opts->socktype) {
858         case SOCK_STREAM:
859             echo_tcp(sock);
860             return;
861         case SOCK_DGRAM:
862             echo_udp(sock);
863             return;
864         default:
865             fprintf(stderr, "Unsupported protocol\n");
866             return;
867     }
868 }
869
870 int main(int argc, char **argv)
871 {
872     int ret;
873     int sock = -1;
874     struct echo_srv_opts opts;
875     int opt;
876     int optindex;
877     static struct option long_options[] = {
878         { discard_const_p(char, "tcp"),         no_argument,            0,  't' },
879         { discard_const_p(char, "udp"),         no_argument,            0,  'u' },
880         { discard_const_p(char, "bind-addr"),   required_argument,      0,  'b' },
881         { discard_const_p(char, "port"),        required_argument,      0,  'p' },
882         { discard_const_p(char, "daemon"),      no_argument,            0,  'D' },
883         { discard_const_p(char, "pid"),         required_argument,      0,  0 },
884         {0,             0,                                              0,  0 }
885     };
886
887     opts.port = DFL_PORT;
888     opts.socktype = SOCK_STREAM;
889     opts.bind = NULL;
890     opts.pidfile = PIDFILE;
891     opts.daemon = false;
892
893     while ((opt = getopt_long(argc, argv, "Dutp:b:",
894                               long_options, &optindex)) != -1) {
895         switch (opt) {
896             case 0:
897                 if (optindex == 5) {
898                     opts.pidfile = optarg;
899                 }
900                 break;
901             case 'p':
902                 opts.port = atoi(optarg);
903                 break;
904             case 'b':
905                 opts.bind = optarg;
906                 break;
907             case 'u':
908                 opts.socktype = SOCK_DGRAM;
909                 break;
910             case 't':
911                 opts.socktype = SOCK_STREAM;
912                 break;
913             case 'D':
914                 opts.daemon = true;
915                 break;
916             default: /* '?' */
917                 fprintf(stderr, "Usage: %s [-p port] [-u] [-t] [-b bind_addr] " \
918                                 "[-D] [--pid pidfile]\n"
919                                 "-t makes the server listen on TCP\n"
920                                 "-u makes the server listen on UDP\n"
921                                 "-D tells the server to become a daemon and " \
922                                 "write a PIDfile\n"
923                                 "The default port is 7, the default PIDfile is " \
924                                 "echo_srv.pid in the current directory\n",
925                                 argv[0]);
926                 ret = 1;
927                 goto done;
928         }
929     }
930
931     if (opts.daemon) {
932         ret = become_daemon();
933         if (ret != 0) {
934             fprintf(stderr, "Cannot become daemon: %s\n", strerror(ret));
935             goto done;
936         }
937     }
938
939     ret = setup_srv(&opts, &sock);
940     if (ret != 0) {
941         fprintf(stderr, "Cannot setup server: %s\n", strerror(ret));
942         goto done;
943     }
944
945     if (opts.daemon && opts.pidfile != NULL) {
946         ret = pidfile(opts.pidfile);
947         if (ret != 0) {
948             fprintf(stderr, "Cannot create pidfile %s: %s\n",
949                     opts.pidfile, strerror(ret));
950             goto done;
951         }
952     }
953
954     echo(sock, &opts);
955     if (sock >= 0) {
956         close(sock);
957     }
958
959     if (opts.daemon && opts.pidfile != NULL) {
960         unlink(opts.pidfile);
961     }
962
963     ret = 0;
964 done:
965     return ret;
966 }