6 #include <sys/socket.h>
10 #include <arpa/inet.h>
11 #include <netinet/in.h>
25 #define PIDFILE "echo_srv.pid"
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"
36 #define BUFSIZE 0x20000 /* 128K */
40 #define discard_const(ptr) ((void *)((uintptr_t)(ptr)))
43 #ifndef discard_const_p
44 #define discard_const_p(type, ptr) ((type *)discard_const(ptr))
48 #define ZERO_STRUCT(x) memset((char *)&(x), 0, sizeof(x))
51 struct torture_address {
55 struct sockaddr_in in;
57 struct sockaddr_in6 in6;
59 struct sockaddr_storage ss;
63 struct echo_srv_opts {
71 #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
73 #if defined(IP_PKTINFO) || defined(IP_RECVDSTADDR) || defined(IPV6_PKTINFO)
75 #ifdef HAVE_STRUCT_IN6_PKTINFO
76 struct in6_pktinfo pkt6;
78 #ifdef HAVE_STRUCT_IN_PKTINFO
79 struct in_pktinfo pkt4;
80 #elif defined(IP_RECVDSTADDR)
86 #define HAVE_UNION_PKTINFO 1
87 #endif /* IP_PKTINFO || IP_RECVDSTADDR || IPV6_PKTINFO */
89 static const char *echo_server_address(int family)
93 const char *ip4 = getenv("TORTURE_SERVER_ADDRESS_IPV4");
95 if (ip4 != NULL && ip4[0] != '\0') {
103 const char *ip6 = getenv("TORTURE_SERVER_ADDRESS_IPV6");
105 if (ip6 != NULL && ip6[0] != '\0') {
109 return ECHO_SRV_IPV6;
118 #endif /* HAVE_STRUCT_MSGHDR_MSG_CONTROL */
120 static void _assert_return_code(int rc,
122 const char * const file,
126 fprintf(stderr, "Fatal error: %s\n", strerror(err));
127 fprintf(stderr, "%s:%d", file, line);
132 #define assert_return_code(rc, err) \
133 _assert_return_code(rc, err, __FILE__, __LINE__)
136 static int pidfile(const char *path)
140 char pid_str[32] = { 0 };
144 fd = open(path, O_RDONLY, 0644);
149 } else if (err != ENOENT) {
153 fd = open(path, O_CREAT | O_WRONLY | O_EXCL, 0644);
159 snprintf(pid_str, sizeof(pid_str) -1, "%u\n", (unsigned int) getpid());
160 len = strlen(pid_str);
162 nwritten = write(fd, pid_str, len);
164 if (nwritten != (ssize_t)len) {
171 static int become_daemon(void)
178 if (getppid() == 1) {
183 if (child_pid == -1) {
187 } else if (child_pid > 0) {
191 /* If a working directory was defined, go there */
203 for (i = 0; i < 3; i++) {
206 fd = open("/dev/null", O_RDWR, 0);
208 fd = open("/dev/null", O_WRONLY, 0);
212 perror("Can't open /dev/null");
216 perror("Didn't get correct fd");
226 static void set_sock_pktinfo(int sock, int family)
239 option = IP_RECVDSTADDR;
242 #endif /* IP_PKTINFO */
245 #ifdef IPV6_RECVPKTINFO
247 proto = IPPROTO_IPV6;
248 option = IPV6_RECVPKTINFO;
250 #endif /* IPV6_RECVPKTINFO */
251 #endif /* HAVE_IPV6 */
256 rc = setsockopt(sock, proto, option, &sockopt, sizeof(sockopt));
257 assert_return_code(rc, errno);
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)
264 struct addrinfo hints;
265 struct addrinfo *res, *ri;
270 memset(&hints, 0, sizeof(hints));
271 hints.ai_family = AF_UNSPEC;
272 hints.ai_socktype = opts->socktype;
273 hints.ai_flags = AI_PASSIVE;
275 snprintf(svc, sizeof(svc), "%d", opts->port);
277 ret = getaddrinfo(opts->bind, svc, &hints, &res);
282 for (ri = res; ri != NULL; ri = ri->ai_next) {
283 sock = socket(ri->ai_family, ri->ai_socktype,
292 if (ri->ai_socktype == SOCK_DGRAM) {
293 set_sock_pktinfo(sock, ri->ai_family);
296 ret = bind(sock, ri->ai_addr, ri->ai_addrlen);
306 fprintf(stderr, "Could not bind\n");
310 if (opts->socktype == SOCK_STREAM) {
311 ret = listen(sock, BACKLOG);
324 static int socket_dup(int s)
326 struct torture_address cli_addr1 = {
327 .sa_socklen = sizeof(struct sockaddr_storage),
329 struct torture_address srv_addr1 = {
330 .sa_socklen = sizeof(struct sockaddr_storage),
333 struct torture_address cli_addr2 = {
334 .sa_socklen = sizeof(struct sockaddr_storage),
336 struct torture_address srv_addr2 = {
337 .sa_socklen = sizeof(struct sockaddr_storage),
340 struct torture_address cli_addr3 = {
341 .sa_socklen = sizeof(struct sockaddr_storage),
343 struct torture_address srv_addr3 = {
344 .sa_socklen = sizeof(struct sockaddr_storage),
350 rc = getsockname(s, &srv_addr1.sa.s, &srv_addr1.sa_socklen);
352 perror("getsockname");
356 rc = getpeername(s, &cli_addr1.sa.s, &cli_addr1.sa_socklen);
358 perror("getpeername");
362 if (cli_addr1.sa.ss.ss_family != srv_addr1.sa.ss.ss_family) {
363 perror("client/server family mismatch");
375 rc = getsockname(s2, &srv_addr2.sa.s, &srv_addr2.sa_socklen);
377 perror("getsockname");
382 rc = getpeername(s2, &cli_addr2.sa.s, &cli_addr2.sa_socklen);
384 perror("getpeername");
389 if (cli_addr1.sa_socklen != cli_addr2.sa_socklen ||
390 srv_addr1.sa_socklen != srv_addr2.sa_socklen) {
391 perror("length mismatch");
396 switch(cli_addr1.sa.ss.ss_family) {
398 rc = memcmp(&cli_addr1.sa.in, &cli_addr2.sa.in, sizeof(struct sockaddr_in));
400 perror("client mismatch");
403 rc = memcmp(&srv_addr1.sa.in, &srv_addr2.sa.in, sizeof(struct sockaddr_in));
405 perror("server mismatch");
411 rc = memcmp(&cli_addr1.sa.in6, &cli_addr2.sa.in6, sizeof(struct sockaddr_in6));
413 perror("client mismatch");
416 rc = memcmp(&srv_addr1.sa.in6, &srv_addr2.sa.in6, sizeof(struct sockaddr_in6));
418 perror("server mismatch");
424 perror("family mismatch");
437 rc = getsockname(s, &srv_addr3.sa.s, &srv_addr3.sa_socklen);
439 perror("getsockname");
444 rc = getpeername(s, &cli_addr3.sa.s, &cli_addr3.sa_socklen);
446 perror("getpeername");
451 if (cli_addr2.sa_socklen != cli_addr3.sa_socklen ||
452 srv_addr2.sa_socklen != srv_addr3.sa_socklen) {
453 perror("length mismatch");
458 switch(cli_addr2.sa.ss.ss_family) {
460 rc = memcmp(&cli_addr1.sa.in, &cli_addr2.sa.in, sizeof(struct sockaddr_in));
462 perror("client mismatch");
465 rc = memcmp(&srv_addr1.sa.in, &srv_addr2.sa.in, sizeof(struct sockaddr_in));
467 perror("server mismatch");
473 rc = memcmp(&cli_addr1.sa.in6, &cli_addr2.sa.in6, sizeof(struct sockaddr_in6));
475 perror("client mismatch");
478 rc = memcmp(&srv_addr1.sa.in6, &srv_addr2.sa.in6, sizeof(struct sockaddr_in6));
480 perror("server mismatch");
486 perror("family mismatch");
494 static void echo_tcp(int sock)
496 struct torture_address addr = {
497 .sa_socklen = sizeof(struct sockaddr_storage),
503 int client_sock = -1;
508 s = accept(sock, &addr.sa.s, &addr.sa_socklen);
517 } else if (pid == 0) {
519 client_sock = socket_dup(s);
520 if (client_sock == -1) {
521 perror("socket_dup");
526 bret = recv(client_sock, buf, BUFSIZE, 0);
530 } else if (bret == 0) {
534 bret = send(client_sock, buf, bret, 0);
543 waitpid(-1, NULL, 0);
548 if (client_sock != -1) {
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)
562 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL) && defined(HAVE_UNION_PKTINFO)
563 size_t cmlen = CMSG_LEN(sizeof(union pktinfo));
565 #endif /* HAVE_STRUCT_MSGHDR_MSG_CONTROL */
568 riov.iov_len = buflen;
572 rmsg.msg_name = &from->sa.s;
573 rmsg.msg_namelen = from->sa_socklen;
575 rmsg.msg_iov = &riov;
578 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL) && defined(HAVE_UNION_PKTINFO)
579 memset(cmsg, 0, cmlen);
581 rmsg.msg_control = cmsg;
582 rmsg.msg_controllen = cmlen;
585 ret = recvmsg(sock, &rmsg, flags);
589 from->sa_socklen = rmsg.msg_namelen;
591 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL) && defined(HAVE_UNION_PKTINFO)
592 if (rmsg.msg_controllen > 0) {
593 struct cmsghdr *cmsgptr;
595 cmsgptr = CMSG_FIRSTHDR(&rmsg);
596 while (cmsgptr != NULL) {
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);
606 pkt = (struct in_pktinfo *)cmsg_cast_ptr;
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);
612 p = inet_ntop(AF_INET, &to->sa.in.sin_addr, ip, sizeof(ip));
614 fprintf(stderr, "Failed to convert IP address");
618 if (strcmp(ip, echo_server_address(AF_INET)) != 0) {
619 fprintf(stderr, "Wrong IP received");
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);
631 addr = (struct in_addr *)cmsg_cast_ptr;
633 to->sa.in.sin_family = AF_INET;
634 to->sa.in.sin_addr = *addr;
635 to->sa_socklen = sizeof(struct sockaddr_in);
637 p = inet_ntop(AF_INET, &to->sa.in.sin_addr, ip, sizeof(ip));
639 fprintf(stderr, "Failed to convert IP address");
643 if (strcmp(ip, echo_server_address(AF_INET)) != 0) {
644 fprintf(stderr, "Wrong IP received");
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);
656 pkt6 = (struct in6_pktinfo *)cmsg_cast_ptr;
658 to->sa.in6.sin6_family = AF_INET6;
659 to->sa.in6.sin6_addr = pkt6->ipi6_addr;
661 p = inet_ntop(AF_INET6, &to->sa.in6.sin6_addr, ip, sizeof(ip));
663 fprintf(stderr, "Failed to convert IP address");
667 if (strcmp(ip, echo_server_address(AF_INET6)) != 0) {
668 fprintf(stderr, "Wrong IP received");
672 #endif /* IPV6_PKTINFO */
673 cmsgptr = CMSG_NXTHDR(&rmsg, cmsgptr);
676 fprintf(stderr, "Failed to receive pktinfo");
679 #endif /* HAVE_STRUCT_MSGHDR_MSG_CONTROL && HAVE_UNION_PKTINFO */
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)
693 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL) && defined(HAVE_UNION_PKTINFO)
694 size_t clen = CMSG_SPACE(sizeof(union pktinfo));
696 struct cmsghdr *cmsgptr;
698 (void)from; /* unused */
699 (void)fromlen; /* unused */
700 #endif /* HAVE_STRUCT_MSGHDR_MSG_CONTROL && HAVE_UNION_PKTINFO */
703 iov.iov_len = buflen;
708 msg.msg_namelen = tolen;
713 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL) && defined(HAVE_UNION_PKTINFO)
714 memset(cbuf, 0, clen);
716 msg.msg_control = cbuf;
717 msg.msg_controllen = clen;
719 cmsgptr = CMSG_FIRSTHDR(&msg);
720 msg.msg_controllen = 0;
722 switch (from->sa_family) {
723 #if defined(IP_PKTINFO) || defined(IP_SENDSRCADDR)
725 void *cmsg_cast_ptr = CMSG_DATA(cmsgptr);
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;
731 const struct sockaddr_in *from4 =
732 (const struct sockaddr_in *)(const void *)from;
734 if (fromlen != sizeof(struct sockaddr_in)) {
738 cmsgptr->cmsg_level = IPPROTO_IP;
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;
746 cmsgptr->cmsg_len = CMSG_LEN(sizeof(*p));
748 msg.msg_controllen = CMSG_SPACE(sizeof(*p));
752 #endif /* IP_PKTINFO || IP_SENDSRCADDR */
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;
760 if (fromlen != sizeof(struct sockaddr_in6)) {
764 cmsgptr->cmsg_level = IPPROTO_IPV6;
765 cmsgptr->cmsg_type = IPV6_PKTINFO;
766 cmsgptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
768 p->ipi6_addr = from6->sin6_addr;
770 msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
774 #endif /* IPV6_PKTINFO */
778 #endif /* HAVE_STRUCT_MSGHDR_MSG_CONTROL && HAVE_UNION_PKTINFO */
780 ret = sendmsg(sock, &msg, flags);
785 static void echo_udp(int sock)
787 struct torture_address saddr = {
788 .sa_socklen = sizeof(struct sockaddr_storage),
790 struct torture_address daddr = {
791 .sa_socklen = sizeof(struct sockaddr_storage),
797 bret = echo_udp_recv_from_to(sock,
808 bret = echo_udp_send_to_from(sock,
823 static void echo(int sock, struct echo_srv_opts *opts)
825 switch (opts->socktype) {
833 fprintf(stderr, "Unsupported protocol\n");
838 int main(int argc, char **argv)
842 struct echo_srv_opts opts;
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 },
855 opts.port = DFL_PORT;
856 opts.socktype = SOCK_STREAM;
858 opts.pidfile = PIDFILE;
861 while ((opt = getopt_long(argc, argv, "Dutp:b:",
862 long_options, &optindex)) != -1) {
866 opts.pidfile = optarg;
870 opts.port = atoi(optarg);
876 opts.socktype = SOCK_DGRAM;
879 opts.socktype = SOCK_STREAM;
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 " \
891 "The default port is 7, the default PIDfile is " \
892 "echo_srv.pid in the current directory\n",
900 ret = become_daemon();
902 fprintf(stderr, "Cannot become daemon: %s\n", strerror(ret));
907 ret = setup_srv(&opts, &sock);
909 fprintf(stderr, "Cannot setup server: %s\n", strerror(ret));
913 if (opts.daemon && opts.pidfile != NULL) {
914 ret = pidfile(opts.pidfile);
916 fprintf(stderr, "Cannot create pidfile %s: %s\n",
917 opts.pidfile, strerror(ret));
925 if (opts.daemon && opts.pidfile != NULL) {
926 unlink(opts.pidfile);