#include #include #include #include #include #include #include #include #include #include #include void Usage(char *progname); void PrintOut(int fd, struct sockaddr *addr, size_t addrlen); int main(int argc, char **argv) { // Expect the port number as a command line argument. if (argc != 2) { Usage(argv[0]); } // Populate the "hints" addrinfo structure for getaddrinfo(). // ("man addrinfo") struct addrinfo hints; memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_INET6; // IPv6 (also handles IPv4 clients) hints.ai_socktype = SOCK_STREAM; // stream hints.ai_flags = AI_PASSIVE; // use wildcard "in6addr_any" address hints.ai_flags |= AI_V4MAPPED; // use v4-mapped v6 if no v6 found hints.ai_protocol = IPPROTO_TCP; // tcp protocol hints.ai_canonname = nullptr; hints.ai_addr = nullptr; hints.ai_next = nullptr; // Use argv[1] as the string representation of our portnumber to // pass in to getaddrinfo(). getaddrinfo() returns a list of // address structures via the output parameter "result". struct addrinfo *result; int res = getaddrinfo(nullptr, argv[1], &hints, &result); // Did addrinfo() fail? if (res != 0) { std::cerr << "getaddrinfo() failed: "; std::cerr << gai_strerror(res) << std::endl; return EXIT_FAILURE; } // Loop through the returned address structures until we are able // to create a socket and bind to one. The address structures are // linked in a list through the "ai_next" field of result. int listen_fd = -1; for (struct addrinfo *rp = result; rp != nullptr; rp = rp->ai_next) { listen_fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); if (listen_fd == -1) { // Creating this socket failed. So, loop to the next returned // result and try again. std::cerr << "socket() failed: " << strerror(errno) << std::endl; listen_fd = 0; continue; } // Configure the socket; we're setting a socket "option." In // particular, we set "SO_REUSEADDR", which tells the TCP stack // so make the port we bind to available again as soon as we // exit, rather than waiting for a few tens of seconds to recycle it. int optval = 1; setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); // Try binding the socket to the address and port number returned // by getaddrinfo(). if (bind(listen_fd, rp->ai_addr, rp->ai_addrlen) == 0) { // Bind worked! Print out the information about what // we bound to. PrintOut(listen_fd, rp->ai_addr, rp->ai_addrlen); break; } // The bind failed. Close the socket, then loop back around and // try the next address/port returned by getaddrinfo(). close(listen_fd); listen_fd = -1; } // Free the structure returned by getaddrinfo(). freeaddrinfo(result); // Did we succeed in binding to any addresses? if (listen_fd == -1) { // No. Quit with failure. std::cerr << "Couldn't bind to any addresses." << std::endl; return EXIT_FAILURE; } // Success. Tell the OS that we want this to be a listening socket. if (listen(listen_fd, SOMAXCONN) != 0) { std::cerr << "Failed to mark socket as listening: "; std::cerr << strerror(errno) << std::endl; close(listen_fd); return EXIT_FAILURE; } // Sleep for 20 seconds, then close house. sleep(20); close(listen_fd); return EXIT_SUCCESS; } void Usage(char *progname) { std::cerr << "usage: " << progname << " port" << std::endl; exit(EXIT_FAILURE); } void PrintOut(int fd, struct sockaddr *addr, size_t addrlen) { std::cout << "Socket [" << fd << "] is bound to:" << std::endl; if (addr->sa_family == AF_INET) { // Print out the IPV4 address and port char astring[INET_ADDRSTRLEN]; struct sockaddr_in *in4 = reinterpret_cast(addr); inet_ntop(AF_INET, &(in4->sin_addr), astring, INET_ADDRSTRLEN); std::cout << " IPv4 address " << astring; std::cout << " and port " << ntohs(in4->sin_port) << std::endl; } else if (addr->sa_family == AF_INET6) { // Print out the IPV6 address and port char astring[INET6_ADDRSTRLEN]; struct sockaddr_in6 *in6 = reinterpret_cast(addr); inet_ntop(AF_INET6, &(in6->sin6_addr), astring, INET6_ADDRSTRLEN); std::cout << " IPv6 address " << astring; std::cout << " and port " << ntohs(in6->sin6_port) << std::endl; } else { std::cout << " ???? address and port ????" << std::endl; } }