6 #include <sys/socket.h>
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>
29 #define PIDFILE "echo_srv.pid"
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"
40 #define BUFSIZE 0x20000 /* 128K */
44 #define discard_const(ptr) ((void *)((uintptr_t)(ptr)))
47 #ifndef discard_const_p
48 #define discard_const_p(type, ptr) ((type *)discard_const(ptr))
52 #define ZERO_STRUCT(x) memset((char *)&(x), 0, sizeof(x))
55 struct torture_address {
59 struct sockaddr_in in;
61 struct sockaddr_in6 in6;
63 struct sockaddr_storage ss;
67 struct echo_srv_opts {
75 #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
77 #if defined(IP_PKTINFO) || defined(IP_RECVDSTADDR) || defined(IPV6_PKTINFO)
79 #ifdef HAVE_STRUCT_IN6_PKTINFO
80 struct in6_pktinfo pkt6;
82 #ifdef HAVE_STRUCT_IN_PKTINFO
83 struct in_pktinfo pkt4;
84 #elif defined(IP_RECVDSTADDR)
90 #define HAVE_UNION_PKTINFO 1
91 #endif /* IP_PKTINFO || IP_RECVDSTADDR || IPV6_PKTINFO */
93 static const char *echo_server_address(int family)
97 const char *ip4 = getenv("TORTURE_SERVER_ADDRESS_IPV4");
99 if (ip4 != NULL && ip4[0] != '\0') {
103 return ECHO_SRV_IPV4;
107 const char *ip6 = getenv("TORTURE_SERVER_ADDRESS_IPV6");
109 if (ip6 != NULL && ip6[0] != '\0') {
113 return ECHO_SRV_IPV6;
122 #endif /* HAVE_STRUCT_MSGHDR_MSG_CONTROL */
124 static void _assert_return_code(int rc,
126 const char * const file,
130 fprintf(stderr, "Fatal error: %s\n", strerror(err));
131 fprintf(stderr, "%s:%d", file, line);
136 #define assert_return_code(rc, err) \
137 _assert_return_code(rc, err, __FILE__, __LINE__)
140 static int pidfile(const char *path)
144 char pid_str[32] = { 0 };
148 fd = open(path, O_RDONLY, 0644);
153 } else if (err != ENOENT) {
157 fd = open(path, O_CREAT | O_WRONLY | O_EXCL, 0644);
163 snprintf(pid_str, sizeof(pid_str) -1, "%u\n", (unsigned int) getpid());
164 len = strlen(pid_str);
166 nwritten = write(fd, pid_str, len);
168 if (nwritten != (ssize_t)len) {
175 static int become_daemon(void)
182 if (getppid() == 1) {
187 if (child_pid == -1) {
191 } else if (child_pid > 0) {
195 /* If a working directory was defined, go there */
207 for (i = 0; i < 3; i++) {
210 fd = open("/dev/null", O_RDWR, 0);
212 fd = open("/dev/null", O_WRONLY, 0);
216 perror("Can't open /dev/null");
220 perror("Didn't get correct fd");
230 static void set_sock_pktinfo(int sock, int family)
243 option = IP_RECVDSTADDR;
246 #endif /* IP_PKTINFO */
249 #ifdef IPV6_RECVPKTINFO
251 proto = IPPROTO_IPV6;
252 option = IPV6_RECVPKTINFO;
254 #endif /* IPV6_RECVPKTINFO */
255 #endif /* HAVE_IPV6 */
260 rc = setsockopt(sock, proto, option, &sockopt, sizeof(sockopt));
261 assert_return_code(rc, errno);
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)
268 struct addrinfo hints;
269 struct addrinfo *res, *ri;
274 memset(&hints, 0, sizeof(hints));
275 hints.ai_family = AF_UNSPEC;
276 hints.ai_socktype = opts->socktype;
277 hints.ai_flags = AI_PASSIVE;
279 snprintf(svc, sizeof(svc), "%d", opts->port);
281 ret = getaddrinfo(opts->bind, svc, &hints, &res);
286 for (ri = res; ri != NULL; ri = ri->ai_next) {
287 sock = socket(ri->ai_family, ri->ai_socktype,
296 if (ri->ai_socktype == SOCK_DGRAM) {
297 set_sock_pktinfo(sock, ri->ai_family);
300 ret = bind(sock, ri->ai_addr, ri->ai_addrlen);
310 fprintf(stderr, "Could not bind\n");
314 if (opts->socktype == SOCK_STREAM) {
315 ret = listen(sock, BACKLOG);
324 struct tcp_info info;
325 socklen_t optlen = sizeof(info);
328 ret = getsockopt(sock, IPPROTO_TCP, TCP_INFO, &info, &optlen);
331 perror("TCP_INFO failed");
335 #ifdef HAVE_NETINET_TCP_FSM_H
336 /* This is FreeBSD */
337 # define __TCP_LISTEN TCPS_LISTEN
340 # define __TCP_LISTEN TCP_LISTEN
342 if (info.tcpi_state != __TCP_LISTEN) {
343 errno = ret = ERANGE;
344 perror("not __TCP_LISTEN => ERANGE...");
349 #endif /* TCP_INFO */
356 static int socket_dup(int s)
358 struct torture_address cli_addr1 = {
359 .sa_socklen = sizeof(struct sockaddr_storage),
361 struct torture_address srv_addr1 = {
362 .sa_socklen = sizeof(struct sockaddr_storage),
365 struct torture_address cli_addr2 = {
366 .sa_socklen = sizeof(struct sockaddr_storage),
368 struct torture_address srv_addr2 = {
369 .sa_socklen = sizeof(struct sockaddr_storage),
372 struct torture_address cli_addr3 = {
373 .sa_socklen = sizeof(struct sockaddr_storage),
375 struct torture_address srv_addr3 = {
376 .sa_socklen = sizeof(struct sockaddr_storage),
382 rc = getsockname(s, &srv_addr1.sa.s, &srv_addr1.sa_socklen);
384 perror("getsockname");
388 rc = getpeername(s, &cli_addr1.sa.s, &cli_addr1.sa_socklen);
390 perror("getpeername");
394 if (cli_addr1.sa.ss.ss_family != srv_addr1.sa.ss.ss_family) {
395 perror("client/server family mismatch");
407 rc = getsockname(s2, &srv_addr2.sa.s, &srv_addr2.sa_socklen);
409 perror("getsockname");
414 rc = getpeername(s2, &cli_addr2.sa.s, &cli_addr2.sa_socklen);
416 perror("getpeername");
421 if (cli_addr1.sa_socklen != cli_addr2.sa_socklen ||
422 srv_addr1.sa_socklen != srv_addr2.sa_socklen) {
423 perror("length mismatch");
428 switch(cli_addr1.sa.ss.ss_family) {
430 rc = memcmp(&cli_addr1.sa.in, &cli_addr2.sa.in, sizeof(struct sockaddr_in));
432 perror("client mismatch");
435 rc = memcmp(&srv_addr1.sa.in, &srv_addr2.sa.in, sizeof(struct sockaddr_in));
437 perror("server mismatch");
443 rc = memcmp(&cli_addr1.sa.in6, &cli_addr2.sa.in6, sizeof(struct sockaddr_in6));
445 perror("client mismatch");
448 rc = memcmp(&srv_addr1.sa.in6, &srv_addr2.sa.in6, sizeof(struct sockaddr_in6));
450 perror("server mismatch");
456 perror("family mismatch");
469 rc = getsockname(s, &srv_addr3.sa.s, &srv_addr3.sa_socklen);
471 perror("getsockname");
476 rc = getpeername(s, &cli_addr3.sa.s, &cli_addr3.sa_socklen);
478 perror("getpeername");
483 if (cli_addr2.sa_socklen != cli_addr3.sa_socklen ||
484 srv_addr2.sa_socklen != srv_addr3.sa_socklen) {
485 perror("length mismatch");
490 switch(cli_addr2.sa.ss.ss_family) {
492 rc = memcmp(&cli_addr1.sa.in, &cli_addr2.sa.in, sizeof(struct sockaddr_in));
494 perror("client mismatch");
497 rc = memcmp(&srv_addr1.sa.in, &srv_addr2.sa.in, sizeof(struct sockaddr_in));
499 perror("server mismatch");
505 rc = memcmp(&cli_addr1.sa.in6, &cli_addr2.sa.in6, sizeof(struct sockaddr_in6));
507 perror("client mismatch");
510 rc = memcmp(&srv_addr1.sa.in6, &srv_addr2.sa.in6, sizeof(struct sockaddr_in6));
512 perror("server mismatch");
518 perror("family mismatch");
526 static void echo_tcp(int sock)
528 struct torture_address addr = {
529 .sa_socklen = sizeof(struct sockaddr_storage),
535 int client_sock = -1;
540 waitpid(-1, NULL, WNOHANG);
541 s = accept(sock, &addr.sa.s, &addr.sa_socklen);
542 if (s == -1 && errno == ECONNABORTED) {
553 } else if (pid == 0) {
555 client_sock = socket_dup(s);
556 if (client_sock == -1) {
557 perror("socket_dup");
562 bret = recv(client_sock, buf, BUFSIZE, 0);
566 } else if (bret == 0) {
570 bret = send(client_sock, buf, bret, 0);
583 if (client_sock != -1) {
588 static ssize_t echo_udp_recv_from_to(int sock,
589 void *buf, size_t buflen, int flags,
590 struct torture_address *from,
591 struct torture_address *to)
597 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL) && defined(HAVE_UNION_PKTINFO)
598 size_t cmlen = CMSG_LEN(sizeof(union pktinfo));
600 #endif /* HAVE_STRUCT_MSGHDR_MSG_CONTROL */
603 riov.iov_len = buflen;
607 rmsg.msg_name = &from->sa.s;
608 rmsg.msg_namelen = from->sa_socklen;
610 rmsg.msg_iov = &riov;
613 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL) && defined(HAVE_UNION_PKTINFO)
614 memset(cmsg, 0, cmlen);
616 rmsg.msg_control = cmsg;
617 rmsg.msg_controllen = cmlen;
620 ret = recvmsg(sock, &rmsg, flags);
624 from->sa_socklen = rmsg.msg_namelen;
626 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL) && defined(HAVE_UNION_PKTINFO)
627 if (rmsg.msg_controllen > 0) {
628 struct cmsghdr *cmsgptr;
630 cmsgptr = CMSG_FIRSTHDR(&rmsg);
631 while (cmsgptr != NULL) {
634 #if defined(IP_PKTINFO) && defined(HAVE_STRUCT_IN_PKTINFO)
635 if (cmsgptr->cmsg_level == IPPROTO_IP &&
636 cmsgptr->cmsg_type == IP_PKTINFO) {
637 char ip[INET_ADDRSTRLEN] = { 0 };
638 struct in_pktinfo *pkt;
639 void *cmsg_cast_ptr = CMSG_DATA(cmsgptr);
641 pkt = (struct in_pktinfo *)cmsg_cast_ptr;
643 to->sa.in.sin_family = AF_INET;
644 to->sa.in.sin_addr = pkt->ipi_addr;
645 to->sa_socklen = sizeof(struct sockaddr_in);
647 p = inet_ntop(AF_INET, &to->sa.in.sin_addr, ip, sizeof(ip));
649 fprintf(stderr, "Failed to convert IP address");
653 if (strcmp(ip, echo_server_address(AF_INET)) != 0) {
654 fprintf(stderr, "Wrong IP received");
658 #endif /* IP_PKTINFO */
659 #ifdef IP_RECVDSTADDR
660 if (cmsgptr->cmsg_level == IPPROTO_IP &&
661 cmsgptr->cmsg_type == IP_RECVDSTADDR) {
662 char ip[INET_ADDRSTRLEN] = { 0 };
663 struct in_addr *addr;
664 void *cmsg_cast_ptr = CMSG_DATA(cmsgptr);
666 addr = (struct in_addr *)cmsg_cast_ptr;
668 to->sa.in.sin_family = AF_INET;
669 to->sa.in.sin_addr = *addr;
670 to->sa_socklen = sizeof(struct sockaddr_in);
672 p = inet_ntop(AF_INET, &to->sa.in.sin_addr, ip, sizeof(ip));
674 fprintf(stderr, "Failed to convert IP address");
678 if (strcmp(ip, echo_server_address(AF_INET)) != 0) {
679 fprintf(stderr, "Wrong IP received");
683 #endif /* IP_RECVDSTADDR */
684 #if defined(IPV6_PKTINFO) && defined(HAVE_STRUCT_IN6_PKTINFO)
685 if (cmsgptr->cmsg_level == IPPROTO_IPV6 &&
686 cmsgptr->cmsg_type == IPV6_PKTINFO) {
687 char ip[INET6_ADDRSTRLEN] = { 0 };
688 struct in6_pktinfo *pkt6;
689 void *cmsg_cast_ptr = CMSG_DATA(cmsgptr);
691 pkt6 = (struct in6_pktinfo *)cmsg_cast_ptr;
693 to->sa.in6.sin6_family = AF_INET6;
694 to->sa.in6.sin6_addr = pkt6->ipi6_addr;
696 p = inet_ntop(AF_INET6, &to->sa.in6.sin6_addr, ip, sizeof(ip));
698 fprintf(stderr, "Failed to convert IP address");
702 if (strcmp(ip, echo_server_address(AF_INET6)) != 0) {
703 fprintf(stderr, "Wrong IP received");
707 #endif /* IPV6_PKTINFO */
708 cmsgptr = CMSG_NXTHDR(&rmsg, cmsgptr);
711 fprintf(stderr, "Failed to receive pktinfo");
714 #endif /* HAVE_STRUCT_MSGHDR_MSG_CONTROL && HAVE_UNION_PKTINFO */
719 static ssize_t echo_udp_send_to_from(int sock,
720 void *buf, size_t buflen, int flags,
721 struct sockaddr *to, socklen_t tolen,
722 struct sockaddr *from, socklen_t fromlen)
728 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL) && defined(HAVE_UNION_PKTINFO)
729 size_t clen = CMSG_SPACE(sizeof(union pktinfo));
731 struct cmsghdr *cmsgptr;
733 (void)from; /* unused */
734 (void)fromlen; /* unused */
735 #endif /* HAVE_STRUCT_MSGHDR_MSG_CONTROL && HAVE_UNION_PKTINFO */
738 iov.iov_len = buflen;
743 msg.msg_namelen = tolen;
748 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL) && defined(HAVE_UNION_PKTINFO)
749 memset(cbuf, 0, clen);
751 msg.msg_control = cbuf;
752 msg.msg_controllen = clen;
754 cmsgptr = CMSG_FIRSTHDR(&msg);
755 msg.msg_controllen = 0;
757 switch (from->sa_family) {
758 #if defined(IP_PKTINFO) || defined(IP_SENDSRCADDR)
760 void *cmsg_cast_ptr = CMSG_DATA(cmsgptr);
762 struct in_pktinfo *p = (struct in_pktinfo *)cmsg_cast_ptr;
763 #elif defined(IP_SENDSRCADDR)
764 struct in_addr *p = (struct in_addr *)cmsg_cast_ptr;
766 const struct sockaddr_in *from4 =
767 (const struct sockaddr_in *)(const void *)from;
769 if (fromlen != sizeof(struct sockaddr_in)) {
773 cmsgptr->cmsg_level = IPPROTO_IP;
775 cmsgptr->cmsg_type = IP_PKTINFO;
776 p->ipi_spec_dst = from4->sin_addr;
777 #elif defined(IP_SENDSRCADDR)
778 cmsgptr->cmsg_type = IP_SENDSRCADDR;
779 *p = from4->sin_addr;
781 cmsgptr->cmsg_len = CMSG_LEN(sizeof(*p));
783 msg.msg_controllen = CMSG_SPACE(sizeof(*p));
787 #endif /* IP_PKTINFO || IP_SENDSRCADDR */
790 void *cast_ptr = CMSG_DATA(cmsgptr);
791 struct in6_pktinfo *p = (struct in6_pktinfo *)cast_ptr;
792 const struct sockaddr_in6 *from6 =
793 (const struct sockaddr_in6 *)(const void *)from;
795 if (fromlen != sizeof(struct sockaddr_in6)) {
799 cmsgptr->cmsg_level = IPPROTO_IPV6;
800 cmsgptr->cmsg_type = IPV6_PKTINFO;
801 cmsgptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
803 p->ipi6_addr = from6->sin6_addr;
805 msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
809 #endif /* IPV6_PKTINFO */
813 #endif /* HAVE_STRUCT_MSGHDR_MSG_CONTROL && HAVE_UNION_PKTINFO */
815 ret = sendmsg(sock, &msg, flags);
820 static void echo_udp(int sock)
822 struct torture_address saddr = {
823 .sa_socklen = sizeof(struct sockaddr_storage),
825 struct torture_address daddr = {
826 .sa_socklen = sizeof(struct sockaddr_storage),
832 bret = echo_udp_recv_from_to(sock,
843 bret = echo_udp_send_to_from(sock,
858 static void echo(int sock, struct echo_srv_opts *opts)
860 switch (opts->socktype) {
868 fprintf(stderr, "Unsupported protocol\n");
873 int main(int argc, char **argv)
877 struct echo_srv_opts opts;
880 static struct option long_options[] = {
881 { discard_const_p(char, "tcp"), no_argument, 0, 't' },
882 { discard_const_p(char, "udp"), no_argument, 0, 'u' },
883 { discard_const_p(char, "bind-addr"), required_argument, 0, 'b' },
884 { discard_const_p(char, "port"), required_argument, 0, 'p' },
885 { discard_const_p(char, "daemon"), no_argument, 0, 'D' },
886 { discard_const_p(char, "pid"), required_argument, 0, 0 },
890 opts.port = DFL_PORT;
891 opts.socktype = SOCK_STREAM;
893 opts.pidfile = PIDFILE;
896 while ((opt = getopt_long(argc, argv, "Dutp:b:",
897 long_options, &optindex)) != -1) {
901 opts.pidfile = optarg;
905 opts.port = atoi(optarg);
911 opts.socktype = SOCK_DGRAM;
914 opts.socktype = SOCK_STREAM;
920 fprintf(stderr, "Usage: %s [-p port] [-u] [-t] [-b bind_addr] " \
921 "[-D] [--pid pidfile]\n"
922 "-t makes the server listen on TCP\n"
923 "-u makes the server listen on UDP\n"
924 "-D tells the server to become a daemon and " \
926 "The default port is 7, the default PIDfile is " \
927 "echo_srv.pid in the current directory\n",
935 ret = become_daemon();
937 fprintf(stderr, "Cannot become daemon: %s\n", strerror(ret));
942 ret = setup_srv(&opts, &sock);
944 fprintf(stderr, "Cannot setup server: %s\n", strerror(ret));
948 if (opts.daemon && opts.pidfile != NULL) {
949 ret = pidfile(opts.pidfile);
951 fprintf(stderr, "Cannot create pidfile %s: %s\n",
952 opts.pidfile, strerror(ret));
962 if (opts.daemon && opts.pidfile != NULL) {
963 unlink(opts.pidfile);