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