diff --git a/src/network.c b/src/network.c index 2e400aa..2df05b0 100644 --- a/src/network.c +++ b/src/network.c @@ -12,30 +12,68 @@ int get_random_num(int range_start, int range_end) { // create a random number i return range_start + (rand() % (range_end - range_start + 1)); } -int check_port_available(unsigned short port) { // test a port is available or not - struct sockaddr_in server_addr; - memset(&server_addr, 0, sizeof(server_addr)); // struct init - server_addr.sin_family = AF_INET; // set as IP communication - server_addr.sin_addr.s_addr = htonl(INADDR_ANY); // allow any connection - server_addr.sin_port = htons(port); // set telnet port - int server_sockfd = socket(AF_INET, SOCK_STREAM, 0); // socket created - if (server_sockfd < 0) { // create failed - return 0; +int check_port_available(unsigned int port, int is_udp, int is_ipv6) { // test a port is available or not + int ipv4_tcp_sock, ipv4_udp_sock; + int ipv6_tcp_sock, ipv6_udp_sock; + struct sockaddr_in ipv4_tcp_addr, ipv4_udp_addr; + struct sockaddr_in6 ipv6_tcp_addr, ipv6_udp_addr; + + ipv4_tcp_sock = socket(AF_INET, SOCK_STREAM, 0); + bzero(&ipv4_tcp_addr, sizeof(ipv4_tcp_addr)); + ipv4_tcp_addr.sin_family = AF_INET; + ipv4_tcp_addr.sin_port = htons(port); + ipv4_tcp_addr.sin_addr.s_addr = INADDR_ANY; + if (bind(ipv4_tcp_sock, (struct sockaddr*)&ipv4_tcp_addr, sizeof(ipv4_tcp_addr)) < 0) { + return 0; // false + } + close(ipv4_tcp_sock); + + if (is_udp) { // udp check + ipv4_udp_sock = socket(AF_INET, SOCK_DGRAM, 0); + bzero(&ipv4_udp_addr, sizeof(ipv4_udp_addr)); + ipv4_udp_addr.sin_family = AF_INET; + ipv4_udp_addr.sin_port = htons(port); + ipv4_udp_addr.sin_addr.s_addr = INADDR_ANY; + if (bind(ipv4_udp_sock, (struct sockaddr*)&ipv4_udp_addr, sizeof(ipv4_udp_addr)) < 0) { + return 0; // false + } + close(ipv4_udp_sock); + } + + if (!is_ipv6) { // ipv6 ignore + return 1; // true } - if (bind(server_sockfd, (struct sockaddr*)&server_addr, sizeof(struct sockaddr)) < 0) { // bind failed - return 0; + + ipv6_tcp_sock = socket(AF_INET6, SOCK_STREAM, 0); + bzero(&ipv6_tcp_addr, sizeof(ipv6_tcp_addr)); + ipv6_tcp_addr.sin6_family = AF_INET6; + ipv6_tcp_addr.sin6_port = htons(port); + ipv6_tcp_addr.sin6_addr = in6addr_any; + if (bind(ipv6_tcp_sock, (struct sockaddr*)&ipv6_tcp_addr, sizeof(ipv6_tcp_addr)) < 0) { + return 0; // false } - if (close(server_sockfd) != 0) { // close failed - return 0; + close(ipv6_tcp_sock); + + if (is_udp) { // udp check + ipv6_udp_sock = socket(AF_INET6, SOCK_DGRAM, 0); + bzero(&ipv6_udp_addr, sizeof(ipv6_udp_addr)); + ipv6_udp_addr.sin6_family = AF_INET6; + ipv6_udp_addr.sin6_port = htons(port); + ipv6_udp_addr.sin6_addr = in6addr_any; + if (bind(ipv6_udp_sock, (struct sockaddr*)&ipv6_udp_addr, sizeof(ipv6_udp_addr)) < 0) { + return 0; // false + } + close(ipv6_udp_sock); } - return 1; // port available + + return 1; // true } int get_available_port(unsigned short range_start, unsigned short range_end) { // get a available port unsigned short port; for (;;) { // wait until a available port in range port = get_random_num(range_start, range_end); // get a random port in range - if (check_port_available(port)) { // port available + if (check_port_available(port, 1, 1)) { // port available return (int)port; } }