#include #include #include #include #include #include #include #include #include #include #define ERRNO_EXIT \ fprintf(stderr, "errno=%d (%s)\n", errno, strerror(errno)); \ exit(EXIT_FAILURE) int main(int argc, const char *argv[]) { struct sockaddr_in6 src_addr; struct sockaddr_in6 dst_addr; struct sockaddr_in6 addr; socklen_t addr_len; int tclass; int tcp_port; int udp_port; int listener_port; char port_str[200]; char addr_str[200]; int rc; struct pollfd fds; int tcp_listener_s; int tcp_conn_s; int acc_s; int udp_s; if (argc < 6) { fprintf(stderr, "Usage: ./ipv6_class_client src_ipv6 dst_ipv6 " "tclass udp_port tcp_port\n"); exit(EXIT_FAILURE); } memset(&src_addr, 0, sizeof(src_addr)); memset(&dst_addr, 0, sizeof(dst_addr)); src_addr.sin6_family = AF_INET6; dst_addr.sin6_family = AF_INET6; if (inet_pton(AF_INET6, argv[1], &src_addr.sin6_addr) < 1) { fprintf(stderr, "Failed to convert '%s' to source IPv6 address\n", argv[1]); ERRNO_EXIT; } if (inet_pton(AF_INET6, argv[2], &dst_addr.sin6_addr) < 1) { fprintf(stderr, "Failed to convert '%s' to destination IPv6 " "address\n", argv[2]); ERRNO_EXIT; } tclass = atoi(argv[3]); udp_port = atoi(argv[4]); tcp_port = atoi(argv[5]); udp_s = socket(AF_INET6, SOCK_DGRAM, 0); if (udp_s < 0) { fprintf(stderr, "Failed to create UDP socket\n"); ERRNO_EXIT; } tcp_listener_s = socket(AF_INET6, SOCK_STREAM, 0); if (tcp_listener_s < 0) { fprintf(stderr, "Failed to create TCP listener socket\n"); ERRNO_EXIT; } tcp_conn_s = socket(AF_INET6, SOCK_STREAM, 0); if (tcp_conn_s < 0) { fprintf(stderr, "Failed to create TCP socket\n"); ERRNO_EXIT; } if (setsockopt(udp_s, SOL_IPV6, IPV6_TCLASS, &tclass, sizeof(tclass)) < 0) { fprintf(stderr, "setsockopt(IPV6_TCLASS) failed for UDP socket\n"); ERRNO_EXIT; } if (setsockopt(tcp_listener_s, SOL_IPV6, IPV6_TCLASS, &tclass, sizeof(tclass)) < 0) { fprintf(stderr, "setsockopt(IPV6_TCLASS) failed for TCP listener " "socket\n"); ERRNO_EXIT; } if (setsockopt(tcp_conn_s, SOL_IPV6, IPV6_TCLASS, &tclass, sizeof(tclass)) < 0) { fprintf(stderr, "setsockopt(IPV6_TCLASS) failed for TCP socket\n"); ERRNO_EXIT; } if (bind(udp_s, (struct sockaddr *)&src_addr, sizeof(src_addr)) < 0) { fprintf(stderr, "Failed to bind UDP socket\n"); ERRNO_EXIT; } if (bind(tcp_listener_s, (struct sockaddr *)&src_addr, sizeof(src_addr)) < 0) { fprintf(stderr, "Failed to bind TCP listener socket\n"); ERRNO_EXIT; } if (bind(tcp_conn_s, (struct sockaddr *)&src_addr, sizeof(src_addr)) < 0) { fprintf(stderr, "Failed to bind TCP socket\n"); ERRNO_EXIT; } addr_len = sizeof(addr); if (getsockname(tcp_listener_s, (struct sockaddr *)&addr, &addr_len) < 0) { fprintf(stderr, "getsockname() failed for TCP listener socket\n"); ERRNO_EXIT; } listener_port = ntohs(addr.sin6_port); if (listen(tcp_listener_s, 1) < 0) { fprintf(stderr, "listen() failed for TCP listener socket\n"); ERRNO_EXIT; } dst_addr.sin6_port = htons(udp_port); if (connect(udp_s, (struct sockaddr *)&dst_addr, sizeof(dst_addr)) < 0) { fprintf(stderr, "Connecting UDP socket to %s failed with errno " "%d (%s)\n", argv[2], errno, strerror(errno)); } else { printf("Connecting UDP socket to %s succeeded\n", argv[2]); } snprintf(port_str, sizeof(port_str), "%d", listener_port); rc = sendto(udp_s, port_str, strlen(port_str) + 1, 0, (struct sockaddr *)&dst_addr, sizeof(dst_addr)); if (rc < 0) { fprintf(stderr, "Sending from UDP socket to %s failed with errno " "%d (%s)\n", argv[2], errno, strerror(errno)); } else { printf("Sending from UDP socket to %s succeeded\n", argv[2]); } memset(&fds, 0, sizeof(fds)); fds.fd = tcp_listener_s; fds.events = POLLIN; rc = poll(&fds, 1, 1000); if (rc == 0) { fprintf(stderr, "TCP listener did not become readable within " "1 second\n"); } else if (fds.revents != POLLIN) { fprintf(stderr, "Unexpected events 0x%x for TCP listener\n", fds.revents); } else { addr_len = sizeof(addr); acc_s = accept(tcp_listener_s, (struct sockaddr *)&addr, &addr_len); if (acc_s < 0) { fprintf(stderr, "accept() failed with errno %d (%s)\n", errno, strerror(errno)); } else { if (inet_ntop(AF_INET6, &addr.sin6_addr, addr_str, sizeof(addr_str)) == NULL) { fprintf(stderr, "Failed to convert source address " "of accepted connection to string\n"); } else { printf("TCP connection was accepted successfully " "from %s\n", addr_str); } close(acc_s); } } if (fcntl(tcp_conn_s, F_SETFL, O_NONBLOCK) < 0) { fprintf(stderr, "Failed to make TCP socket non-blocking\n"); ERRNO_EXIT; } dst_addr.sin6_port = htons(tcp_port); rc = connect(tcp_conn_s, (struct sockaddr *)&dst_addr, sizeof(dst_addr)); if (rc < 0 && errno != EINPROGRESS) { fprintf(stderr, "Nonblocking connect() failed with " "unexpected errno\n"); ERRNO_EXIT; } sleep(1); rc = connect(tcp_conn_s, (struct sockaddr *)&dst_addr, sizeof(dst_addr)); if (rc < 0 && errno != EISCONN) { fprintf(stderr, "Active TCP connection was not established in " "1 second\n"); } else { printf("Active TCP connection was successfully established\n"); } close(tcp_conn_s); close(tcp_listener_s); close(udp_s); return 0; }