From: bluhm Date: Tue, 11 Jul 2017 00:25:19 +0000 (+0000) Subject: Rewrite regress sendsrcaddr so that is uses UDP sockets on localhost, X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=7c4552f47293c6aede5d0485921e7e233b1b9b2d;p=openbsd Rewrite regress sendsrcaddr so that is uses UDP sockets on localhost, does not try to connect to google and avoids BPF programming. --- diff --git a/regress/sys/netinet/sendsrcaddr/Makefile b/regress/sys/netinet/sendsrcaddr/Makefile index f5a8cf5aa9b..600df5ed407 100644 --- a/regress/sys/netinet/sendsrcaddr/Makefile +++ b/regress/sys/netinet/sendsrcaddr/Makefile @@ -1,30 +1,65 @@ -# $OpenBSD: Makefile,v 1.1 2016/08/16 22:25:08 vgross Exp $ - -PROG = runtest -DESTADDR = www.google.com -TESTIFACE = vether12 -TESTNET != jot -r -s '.' 2 0 255 -RESV_ADDR = 10.${TESTNET}.1 -BIND_ADDR = 10.${TESTNET}.2 -CMSG_ADDR = 10.${TESTNET}.3 -NONE_ADDR = 10.${TESTNET}.4 - -run-regress-runtest: ${PROG} +# $OpenBSD: Makefile,v 1.2 2017/07/11 00:25:19 bluhm Exp $ + +PROG = runtest +CFLAGS = -Wall +DESTADDR = 127.0.0.1 +TESTIFACE = vether12 +TESTNET !!= jot -s '.' 2 0 255 +RESV_ADDR = 10.${TESTNET}.1 +BIND_ADDR = 10.${TESTNET}.2 +CMSG_ADDR = 10.${TESTNET}.3 +NONE_ADDR = 10.${TESTNET}.4 +CLEANFILES = stamp-* + +REGRESS_TARGETS = run-regress-1 \ + run-regress-2 \ + run-regress-3 \ + run-regress-4 \ + run-regress-5 \ + run-regress-6 \ + run-regress-7 \ + run-regress-8 \ + run-regress-9 \ + run-regress-cleanup + +stamp-setup: + -! ${SUDO} ifconfig ${TESTIFACE} destroy ${SUDO} ifconfig ${TESTIFACE} create ${SUDO} ifconfig ${TESTIFACE} inet ${RESV_ADDR}/24 up ${SUDO} ifconfig ${TESTIFACE} inet ${BIND_ADDR}/24 alias ${SUDO} ifconfig ${TESTIFACE} inet ${CMSG_ADDR}/24 alias - sleep 1 ${SUDO} ifconfig ${TESTIFACE} - ${.OBJDIR}/${PROG} 0 ${DESTADDR}=destination ${RESV_ADDR}=reserved_saddr ${BIND_ADDR}=bind_saddr - ${.OBJDIR}/${PROG} 0 ${DESTADDR}=destination ${RESV_ADDR}=reserved_saddr ${BIND_ADDR}=bind_saddr ${CMSG_ADDR}=cmsg_saddr,wire_saddr - ${.OBJDIR}/${PROG} 0 ${DESTADDR}=destination ${RESV_ADDR}=reserved_saddr ${BIND_ADDR}=bind_saddr ${BIND_ADDR}=cmsg_saddr,wire_saddr - ${.OBJDIR}/${PROG} 49 ${DESTADDR}=destination ${RESV_ADDR}=reserved_saddr ${BIND_ADDR}=bind_saddr ${NONE_ADDR}=cmsg_saddr - ${.OBJDIR}/${PROG} 48 ${DESTADDR}=destination ${RESV_ADDR}=reserved_saddr ${BIND_ADDR}=bind_saddr ${RESV_ADDR}=cmsg_saddr - ${.OBJDIR}/${PROG} 0 ${DESTADDR}=destination ${RESV_ADDR}=reserved_saddr 0.0.0.0=bind_saddr ${BIND_ADDR}=cmsg_saddr,wire_saddr - ${.OBJDIR}/${PROG} 0 ${DESTADDR}=destination ${RESV_ADDR}=reserved_saddr 0.0.0.0=bind_saddr ${RESV_ADDR}=cmsg_saddr,wire_saddr - ${.OBJDIR}/${PROG} 0 ${DESTADDR}=destination ${RESV_ADDR}=reserved_saddr ${BIND_ADDR}=bind_saddr 0.0.0.0=cmsg_saddr - ${.OBJDIR}/${PROG} 22 ${DESTADDR}=destination ${RESV_ADDR}=reserved_saddr ${BIND_ADDR}=bind_saddr ${CMSG_ADDR}=cmsg_saddr fuzz - ${SUDO} ifconfig ${TESTIFACE} destroy + date >$@ + +run-regress-1: ${PROG} stamp-setup + ./${PROG} -D ${DESTADDR} -R ${RESV_ADDR} -B ${BIND_ADDR} -W ${BIND_ADDR} + +run-regress-2: ${PROG} stamp-setup + ./${PROG} -D ${DESTADDR} -R ${RESV_ADDR} -B ${BIND_ADDR} -C ${CMSG_ADDR} -W ${CMSG_ADDR} + +run-regress-3: ${PROG} stamp-setup + ./${PROG} -D ${DESTADDR} -R ${RESV_ADDR} -B ${BIND_ADDR} -C ${BIND_ADDR} -W ${BIND_ADDR} + +run-regress-4: ${PROG} stamp-setup + ./${PROG} -D ${DESTADDR} -R ${RESV_ADDR} -B ${BIND_ADDR} -C ${NONE_ADDR} -E 49 + +run-regress-5: ${PROG} stamp-setup + ./${PROG} -D ${DESTADDR} -R ${RESV_ADDR} -B ${BIND_ADDR} -C ${RESV_ADDR} -E 48 + +run-regress-6: ${PROG} stamp-setup + ./${PROG} -D ${DESTADDR} -R ${RESV_ADDR} -B 0.0.0.0 -C ${BIND_ADDR} -W ${BIND_ADDR} + +run-regress-7: ${PROG} stamp-setup + ./${PROG} -D ${DESTADDR} -R ${RESV_ADDR} -B 0.0.0.0 -C ${RESV_ADDR} -W ${RESV_ADDR} + +run-regress-8: ${PROG} stamp-setup + ./${PROG} -D ${DESTADDR} -R ${RESV_ADDR} -B ${BIND_ADDR} -C 0.0.0.0 -W ${BIND_ADDR} + +run-regress-9: ${PROG} stamp-setup + ./${PROG} -D ${DESTADDR} -R ${RESV_ADDR} -B ${BIND_ADDR} -C ${CMSG_ADDR} -f -E 22 + +run-regress-cleanup: + rm -f stamp-setup + -${SUDO} ifconfig ${TESTIFACE} destroy .include diff --git a/regress/sys/netinet/sendsrcaddr/runtest.c b/regress/sys/netinet/sendsrcaddr/runtest.c index 8329d96227a..96667a50f7c 100644 --- a/regress/sys/netinet/sendsrcaddr/runtest.c +++ b/regress/sys/netinet/sendsrcaddr/runtest.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2016 Vincent Gross + * Copyright (c) 2017 Alexander Bluhm * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -14,320 +15,184 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include +#include + +#include +#include + #include #include -#include #include #include #include -#include #include #include #include #include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include - -#include - -#define PORTNUM "23000" #define PAYLOAD "payload" -char cmd_tmpl[] = "route get %s | awk '/interface:/ { printf($2) }'"; -#define CMD_TMPL_SZ sizeof(cmd_tmpl) - int fuzzit; -void check_packet_tx(int); +void __dead usage(const char *); +int udp_bind(struct sockaddr_in *); +int udp_send(int, struct sockaddr_in *, struct sockaddr_in *); +struct sockaddr_in * udp_recv(int s, struct sockaddr_in *); + +void __dead +usage(const char *msg) +{ + if (msg != NULL) + fprintf(stderr, "%s\n", msg); + fprintf(stderr, "runtest [-f] -D destination -B bind [-C cmesg] " + "[-E error] -R reserved -W wire\n"); + exit(1); +} int main(int argc, char *argv[]) { - int i; - char *argp, *addr, *flag; - - struct addrinfo hints; - struct addrinfo *inai; - - struct sockaddr_in *dst_sin = NULL; - struct sockaddr_in *reserved_sin = NULL; - struct sockaddr_in *bind_sin = NULL; - struct sockaddr_in *cmsg_sin = NULL; - struct sockaddr_in *wire_sin = NULL; - - int ch, rc, wstat, expected = -1; - int first_sock; - pid_t pid; - - const char *numerr; - char adrbuf[40]; - const char *adrp; - - char *dst_str = NULL; - char cmd[CMD_TMPL_SZ + INET_ADDRSTRLEN]; - FILE *outif_pipe; - char ifname_buf[IF_NAMESIZE]; - size_t ifname_len; - - int bpf_fd; - + int ch, error, errexpect, bind_sock, dest_sock, resv_sock; + char addr[16]; + const char *errstr; + struct addrinfo hints, *res; + struct sockaddr_in *bind_sin, *cmsg_sin, *dest_sin, *resv_sin, + *wire_sin, *from_sin; bzero(&hints, sizeof(hints)); hints.ai_family = AF_INET; hints.ai_socktype = SOCK_DGRAM; - expected = strtonum(argv[1], 0, 255, &numerr); - if (numerr != NULL) - errx(2, "strtonum(%s): %s", optarg, numerr); - - for (i = 2; i < argc; i++) { - argp = argv[i]; - if (strcmp("fuzz",argp) == 0) { + bind_sin = cmsg_sin = dest_sin = resv_sin = wire_sin = NULL; + errexpect = 0; + + while ((ch = getopt(argc, argv, "B:C:D:E:fR:W:")) != -1) { + switch (ch) { + case 'B': + error = getaddrinfo(optarg, NULL, &hints, &res); + if (error) + errx(1, "-B: %s", gai_strerror(error)); + bind_sin = (struct sockaddr_in *)res->ai_addr; + break; + case 'C': + error = getaddrinfo(optarg, NULL, &hints, &res); + if (error) + errx(1, "-C: %s", gai_strerror(error)); + cmsg_sin = (struct sockaddr_in *)res->ai_addr; + break; + case 'D': + error = getaddrinfo(optarg, NULL, &hints, &res); + if (error) + errx(1, "-D: %s", gai_strerror(error)); + dest_sin = (struct sockaddr_in *)res->ai_addr; + break; + case 'E': + errexpect = strtonum(optarg, 1, 255, &errstr); + if (errstr != NULL) + errx(1, "error number is %s: %s", + errstr, optarg); + break; + case 'f': fuzzit = 1; - continue; - } - addr = strsep(&argp, "="); - rc = getaddrinfo(addr, PORTNUM, &hints, &inai); - if (rc) - errx(2, "getaddrinfo(%s) = %d: %s", - argv[0], rc, gai_strerror(rc)); - if (argp == NULL) - errx(2, "arg must be of form =,"); - - for (; (flag = strsep(&argp,",")) != NULL;) { - if (strcmp("destination",flag) == 0 && dst_sin == NULL) { - dst_sin = (struct sockaddr_in *)inai->ai_addr; - /* get output interface */ - snprintf(cmd, sizeof(cmd), cmd_tmpl, addr); - outif_pipe = popen(cmd, "re"); - if (outif_pipe == NULL) - err(2, "popen(route get)"); - if (fgets(ifname_buf, IF_NAMESIZE, outif_pipe) == NULL) - err(2, "fgets()"); - pclose(outif_pipe); - if (strlen(ifname_buf) == 0) - err(2, "strlen(ifname_buf) == 0"); - } - if (strcmp("reserved_saddr",flag) == 0 && reserved_sin == NULL) - reserved_sin = (struct sockaddr_in *)inai->ai_addr; - if (strcmp("bind_saddr",flag) == 0 && bind_sin == NULL) - bind_sin = (struct sockaddr_in *)inai->ai_addr; - if (strcmp("cmsg_saddr",flag) == 0 && cmsg_sin == NULL) - cmsg_sin = (struct sockaddr_in *)inai->ai_addr; - if (strcmp("wire_saddr",flag) == 0 && wire_sin == NULL) - wire_sin = (struct sockaddr_in *)inai->ai_addr; + break; + case 'R': + error = getaddrinfo(optarg, NULL, &hints, &res); + if (error) + errx(1, "-R: %s", gai_strerror(error)); + resv_sin = (struct sockaddr_in *)res->ai_addr; + break; + case 'W': + error = getaddrinfo(optarg, NULL, &hints, &res); + if (error) + errx(1, "-W: %s", gai_strerror(error)); + wire_sin = (struct sockaddr_in *)res->ai_addr; + break; + default: + usage(NULL); } } + argc -= optind; + argv += optind; - if (reserved_sin == NULL) - errx(2, "reserved_sin == NULL"); + if (argc > 0) + usage("too many arguments"); if (bind_sin == NULL) - errx(2, "bind_sin == NULL"); + usage("no bind addr"); - if (dst_sin == NULL) - errx(2, "dst_sin == NULL"); + if (dest_sin == NULL) + usage("no destination addr"); - if (expected < 0) - errx(2, "need expected"); + if (resv_sin == NULL) + usage("no reserved addr"); + /* bind on address that cannot be used */ + resv_sock = udp_bind(resv_sin); - if (wire_sin != NULL) - bpf_fd = setup_bpf(ifname_buf, wire_sin, dst_sin); + /* bind socket that should receive the packet */ + dest_sock = udp_bind(dest_sin); - first_sock = udp_first(reserved_sin); + /* bind socket that is used to send the packet */ + bind_sin->sin_port = resv_sin->sin_port; + bind_sock = udp_bind(bind_sin); + error = udp_send(bind_sock, cmsg_sin, dest_sin); - pid = fork(); - if (pid == 0) { - return udp_override(dst_sin, bind_sin, cmsg_sin); + if (errexpect && !error) { + errno = errexpect; + err(2, "udp send succeeded, but expected error"); + } + if (!errexpect && error) { + errno = error; + err(2, "no error expected, but udp send failed"); + } + if (errexpect != error) { + errno = error; + err(2, "expected error %d, but udp send failed", errexpect); } - (void)wait(&wstat); - close(first_sock); - - if (!WIFEXITED(wstat)) - errx(2, "error setting up override"); - - if (WEXITSTATUS(wstat) != expected) - errx(2, "expected %d, got %d", expected, WEXITSTATUS(wstat)); - - if (wire_sin != NULL) - check_packet_tx(bpf_fd); - - return EXIT_SUCCESS; -} - - -struct bpf_insn outgoing_bpf_filter[] = { - /* ethertype = IP */ - BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 12), - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 0, 9), - - /* Make sure it's a UDP packet. */ - BPF_STMT(BPF_LD + BPF_B + BPF_ABS, 23), - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 7), - - /* Fragments are handled as errors */ - BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 20), - BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 5, 0), - - /* Make sure it's from the right address */ - BPF_STMT(BPF_LD + BPF_W + BPF_ABS, 26), - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0, 0, 3), /* Need to patch this */ - - /* Make sure it's to the right address */ - BPF_STMT(BPF_LD + BPF_W + BPF_ABS, 30), - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0, 0, 1), /* Need to patch this */ -#if 0 - /* Get the IP header length. */ - BPF_STMT(BPF_LDX + BPF_B + BPF_MSH, 14), - - /* Make sure it's to the right port. */ - BPF_STMT(BPF_LD + BPF_H + BPF_IND, 16), - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0, 0, 1), -#endif - /* If we passed all the tests, ask for the whole packet. */ - BPF_STMT(BPF_RET+BPF_K, (u_int)-1), - - /* Otherwise, drop it. */ - BPF_STMT(BPF_RET+BPF_K, 0), -}; - -int outgoing_bpf_filter_len = sizeof(outgoing_bpf_filter)/sizeof(struct bpf_insn); -int -setup_bpf(char *ifname, struct sockaddr_in *from, struct sockaddr_in *to) -{ - int fd; - struct ifreq ifr; - u_int flag; - struct bpf_version vers; - struct bpf_program prog; - - fd = open("/dev/bpf", O_RDWR | O_CLOEXEC); - if (fd == -1) - err(2, "open(/dev/bpf)"); - - if (ioctl(fd, BIOCVERSION, &vers) < 0) - err(2, "ioctl(BIOCVERSION)"); - - if (vers.bv_major != BPF_MAJOR_VERSION || - vers.bv_minor < BPF_MINOR_VERSION) - errx(2, "bpf version mismatch, expected %d.%d, got %d.%d", - BPF_MAJOR_VERSION, BPF_MINOR_VERSION, - vers.bv_major, vers.bv_minor); - - strlcpy(ifr.ifr_name, ifname, IFNAMSIZ); - if (ioctl(fd, BIOCSETIF, &ifr) < 0) - err(2, "ioctl(BIOCSETIF)"); - - flag = 1; - if (ioctl(fd, BIOCIMMEDIATE, &flag) < 0) - err(2, "ioctl(BIOCIMMEDIATE)"); - - flag = BPF_DIRECTION_IN; - if (ioctl(fd, BIOCSDIRFILT, &flag) < 0) - err(2, "ioctl(BIOCDIRFILT)"); - - outgoing_bpf_filter[7].k = ntohl(from->sin_addr.s_addr) ; - outgoing_bpf_filter[9].k = ntohl(to->sin_addr.s_addr) ; -#if 0 - outgoing_bpf_filter[12].k = (u_int32_t)ntohs(to->sin_port) ; -#endif - - prog.bf_len = outgoing_bpf_filter_len; - prog.bf_insns = outgoing_bpf_filter; - if (ioctl(fd, BIOCSETF, &prog) < 0) - err(2, "ioctl(BIOCSETF)"); - - return fd; -} + if (wire_sin != NULL) { + from_sin = udp_recv(dest_sock, dest_sin); + if (from_sin == NULL) + errx(2, "receive timeout"); + inet_ntop(from_sin->sin_family, &from_sin->sin_addr, + addr, sizeof(addr)); + if (from_sin->sin_addr.s_addr != wire_sin->sin_addr.s_addr) + errx(2, "receive addr %s", addr); + if (from_sin->sin_port != bind_sin->sin_port) + errx(2, "receive port %d", ntohs(from_sin->sin_port)); + } -void -check_packet_tx(int fd) -{ - u_int buf_max; - size_t len; - struct pollfd pfd; - int pollrc; - char *buf, *payload; - struct bpf_hdr *hdr; - struct ip *ip; - - if (ioctl(fd, BIOCGBLEN, &buf_max) < 0) - err(2, "ioctl(BIOCGBLEN)"); - - if (buf_max <= 0) - errx(2, "buf_max = %d <= 0", buf_max); - - buf = malloc(buf_max); - if (!buf) - err(2, "malloc(buf_max)"); - - pfd.fd = fd; - pfd.events = POLLIN; - pollrc = poll(&pfd, 1, 5000); - if (pollrc == -1) - err(2, "poll()"); - if (pollrc == 0) - errx(2, "poll() timeout"); - - len = read(fd, buf, buf_max); - if (len <= 0) - err(2, "read(/dev/bpf)"); - len = BPF_WORDALIGN(len); - - if (len < sizeof(hdr)) - errx(2, "short read, len < sizeof(bpf_hdr)"); - - hdr = (struct bpf_hdr *)buf; - if (hdr->bh_hdrlen + hdr->bh_caplen > len) - errx(2, "buffer too small for the whole capture"); - - /* XXX we could try again if enough space in the buffer */ - if (hdr->bh_caplen != hdr->bh_datalen) - errx(2, "partial capture"); - - ip = (struct ip *)(buf + hdr->bh_hdrlen + ETHER_HDR_LEN); - payload = ((char *)ip + ip->ip_hl*4 + 8); - - if (strcmp(PAYLOAD,payload) != 0) - errx(2, "payload corrupted"); - - return; + return 0; } int -udp_first(struct sockaddr_in *src) +udp_bind(struct sockaddr_in *src) { - int s_con; - - s_con = socket(src->sin_family, SOCK_DGRAM, 0); - if (s_con == -1) - err(2, "udp_bind: socket()"); - - if (bind(s_con, (struct sockaddr *)src, src->sin_len)) - err(2, "udp_bind: bind()"); - - return s_con; + int s, reuse, salen; + char addr[16]; + + inet_ntop(src->sin_family, &src->sin_addr, addr, sizeof(addr)); + + if ((s = socket(src->sin_family, SOCK_DGRAM, 0)) == -1) + err(1, "socket %s", addr); + reuse = ntohl(src->sin_addr.s_addr) == INADDR_ANY ? 1 : 0; + if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) + == -1) + err(1, "setsockopt %s", addr); + if (bind(s, (struct sockaddr *)src, src->sin_len) == -1) + err(1, "bind %s", addr); + /* fill out port */ + salen = sizeof(*src); + if (getsockname(s, (struct sockaddr *)src, &salen)) + err(1, "getsockname %s", addr); + + return s; } - int -udp_override(struct sockaddr_in *dst, struct sockaddr_in *src_bind, - struct sockaddr_in *src_sendmsg) +udp_send(int s, struct sockaddr_in *src, struct sockaddr_in *dst) { - int s, optval, error, saved_errno; - ssize_t send_rc; struct msghdr msg; struct iovec iov; struct cmsghdr *cmsg; @@ -339,34 +204,16 @@ udp_override(struct sockaddr_in *dst, struct sockaddr_in *src_bind, #define CMSGBUF_SP CMSGSP_SADDR + CMSGSP_HOPLIM + CMSGSP_BOGUS + 3 unsigned char cmsgbuf[CMSGBUF_SP]; - bzero(&msg, sizeof(msg)); - bzero(&cmsgbuf, sizeof(cmsgbuf)); - - s = socket(src_bind->sin_family, SOCK_DGRAM, 0); - if (s == -1) { - warn("udp_override: socket()"); - kill(getpid(), SIGTERM); - } - - optval = 1; - if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(int))) { - warn("udp_override: setsockopt(SO_REUSEADDR)"); - kill(getpid(), SIGTERM); - } - - if (bind(s, (struct sockaddr *)src_bind, src_bind->sin_len)) { - warn("udp_override: bind()"); - kill(getpid(), SIGTERM); - } - iov.iov_base = PAYLOAD; iov.iov_len = strlen(PAYLOAD) + 1; + bzero(&msg, sizeof(msg)); msg.msg_name = dst; msg.msg_namelen = dst->sin_len; msg.msg_iov = &iov; msg.msg_iovlen = 1; - if (src_sendmsg) { + if (src) { + bzero(&cmsgbuf, sizeof(cmsgbuf)); msg.msg_control = &cmsgbuf; msg.msg_controllen = CMSGSP_SADDR; cmsg = CMSG_FIRSTHDR(&msg); @@ -374,7 +221,7 @@ udp_override(struct sockaddr_in *dst, struct sockaddr_in *src_bind, cmsg->cmsg_level = IPPROTO_IP; cmsg->cmsg_type = IP_SENDSRCADDR; sendopt = (struct in_addr *)CMSG_DATA(cmsg); - memcpy(sendopt, &src_sendmsg->sin_addr, sizeof(*sendopt)); + memcpy(sendopt, &src->sin_addr, sizeof(*sendopt)); if (fuzzit) { msg.msg_controllen = CMSGBUF_SP; cmsg = CMSG_NXTHDR(&msg, cmsg); @@ -391,12 +238,43 @@ udp_override(struct sockaddr_in *dst, struct sockaddr_in *src_bind, } } - send_rc = sendmsg(s, &msg, 0); - saved_errno = errno; + if (sendmsg(s, &msg, 0) == -1) + return errno; - close(s); + return 0; +} - if (send_rc == iov.iov_len) - return 0; - return saved_errno; +struct sockaddr_in * +udp_recv(int s, struct sockaddr_in *dst) +{ + struct sockaddr_in *src; + struct pollfd pfd[1]; + char addr[16], buf[256]; + int nready, len, salen; + + inet_ntop(dst->sin_family, &dst->sin_addr, addr, sizeof(addr)); + + pfd[0].fd = s; + pfd[0].events = POLLIN; + nready = poll(pfd, 1, 2 * 1000); + if (nready == -1) + err(1, "poll"); + if (nready == 0) + return NULL; + if ((pfd[0].revents & POLLIN) == 0) + errx(1, "event %d %s", pfd[0].revents, addr); + + if ((src = malloc(sizeof(*src))) == NULL) + err(1, "malloc"); + salen = sizeof(*src); + if ((len = recvfrom(s, buf, sizeof(buf), 0, (struct sockaddr *)src, + &salen)) == -1) + err(1, "recvfrom %s", addr); + + if (len != strlen(PAYLOAD) + 1) + errx(1, "recvfrom %s len %d", addr, len); + if (strcmp(buf, PAYLOAD) != 0) + errx(1, "recvfrom %s payload", addr); + + return src; }