/* * */ #include #include #include #include #include #include #include #include #include struct sd { int family; int type; int proto; struct sockaddr *sa; int sa_len; }; static int bind_socket(struct sd *sd) { struct sockaddr_in *sin; struct sockaddr_in6 *sin6; int error, s; s = socket(sd->family, sd->type, sd->proto); printf("socket(%d,%d,%d) -> %d | %s\n", sd->family, sd->type, sd->proto, s, strerror(errno)); for (int i = 0; i < 10; i++) { int port = htons(32768 + random() % 4096); error = 0; switch (sd->family) { case AF_INET: sin = (struct sockaddr_in *)sd->sa; memset(sin, 0, sizeof(struct sockaddr_in)); sin->sin_family = AF_INET; inet_pton(AF_INET, "127.0.0.1", &sin->sin_addr); sin->sin_port = htons(port); sd->sa_len = sizeof(struct sockaddr_in); break; case AF_INET6: sin6 = (struct sockaddr_in6 *)sd->sa; memset(sin6, 0, sizeof(struct sockaddr_in6)); sin6->sin6_family = AF_INET6; inet_pton(AF_INET6, "::1", &sin6->sin6_addr); sin6->sin6_port = htons(port); sd->sa_len = sizeof(struct sockaddr_in6); break; } error = bind(s, sd->sa, sd->sa_len); printf("bind(fd#%d) -> %d | %s\n", s, error, strerror(errno)); if (error != EADDRINUSE) break; } if (error != 0) { close(s); return (0); } return (s); } static void test_msg_peek_sd(int s, struct sd *sd) { int c = socket(sd->family, sd->type, sd->proto); int databuf_len = 1024; char *databuf = malloc(databuf_len); memset(databuf, 0xFF, databuf_len); char *rxbuf = malloc(databuf_len); memset(databuf, 0, databuf_len); int peek_len = 128; memset(databuf, 0xEE, peek_len); int len; len = sendto(c, databuf, databuf_len, 0, sd->sa, sd->sa_len); printf("sendto(fd#%d) -> %d\n", c, len); char sabuf[32]; struct iovec iov = { .iov_base = rxbuf, .iov_len = peek_len, }; struct msghdr msg = { .msg_name = sabuf, .msg_namelen = sizeof(sabuf), .msg_iov = &iov, .msg_iovlen = 1, }; errno = 0; len = recvmsg(s, &msg, MSG_PEEK); printf("recvmsg(fd#%d) -> %d | errno %s\n", s, len, strerror(errno)); assert(len == peek_len); assert(memcmp(rxbuf, databuf, len) == 0); iov.iov_len = databuf_len; len = recvmsg(s, &msg, 0); printf("recvmsg(fd#%d) -> %d | errno %s\n", s, len, strerror(errno)); assert(len == databuf_len); assert(memcmp(rxbuf, databuf, len) == 0); free(databuf); free(rxbuf); } static void test_msg_peek() { char sa_buffer[32]; struct sd sd = { .family = AF_INET, .type = SOCK_DGRAM, .proto = IPPROTO_UDP, .sa = (struct sockaddr *)sa_buffer, }; int s = bind_socket(&sd); test_msg_peek_sd(s, &sd); } int main() { test_msg_peek(); return (0); }