#include #include #include #include #include #include #include #include #include #include #include #define BUF 256 using std::cerr; using std::cout; using std::endl; void Usage(char *progname); bool LookupName(char *name, unsigned short port, struct sockaddr_storage *ret_addr, size_t *ret_addrlen); bool Connect(const struct sockaddr_storage &addr, const size_t &addrlen, int *ret_fd); int main(int argc, char **argv) { if (argc != 3) { Usage(argv[0]); } unsigned short port = 0; if (sscanf(argv[2], "%hu", &port) != 1) { Usage(argv[0]); } // Get an appropriate sockaddr structure. struct sockaddr_storage addr; size_t addrlen; if (!LookupName(argv[1], port, &addr, &addrlen)) { Usage(argv[0]); } // Connect to the remote host. int socket_fd; if (!Connect(addr, addrlen, &socket_fd)) { Usage(argv[0]); } // Read something from the remote host. // Will only read BUF-1 characters at most. char readbuf[BUF]; int res; while (1) { res = read(socket_fd, readbuf, BUF-1); if (res == 0) { cerr << "socket closed prematurely" << endl; close(socket_fd); return EXIT_FAILURE; } if (res == -1) { if (errno == EINTR) continue; cerr << "socket read failure: " << strerror(errno) << endl; close(socket_fd); return EXIT_FAILURE; } readbuf[res] = '\0'; cout << readbuf; break; } // Repeat what we got from the remote host back to them. while (1) { int wres = write(socket_fd, readbuf, res); if (wres == 0) { cerr << "socket closed prematurely" << endl; close(socket_fd); return EXIT_FAILURE; } if (wres == -1) { if (errno == EINTR) continue; cerr << "socket write failure: " << strerror(errno) << endl; close(socket_fd); return EXIT_FAILURE; } break; } // Clean up. close(socket_fd); return EXIT_SUCCESS; } void Usage(char *progname) { cerr << "usage: " << progname << " hostname port" << endl; exit(EXIT_FAILURE); } bool LookupName(char *name, unsigned short port, struct sockaddr_storage *ret_addr, size_t *ret_addrlen) { struct addrinfo hints, *results; int retval; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; // Do the lookup by invoking getaddrinfo(). if ((retval = getaddrinfo(name, nullptr, &hints, &results)) != 0) { cerr << "getaddrinfo failed: "; cerr << gai_strerror(retval) << endl; return false; } // Set the port in the first result. if (results->ai_family == AF_INET) { struct sockaddr_in *v4addr = reinterpret_cast(results->ai_addr); v4addr->sin_port = htons(port); } else if (results->ai_family == AF_INET6) { struct sockaddr_in6 *v6addr = reinterpret_cast(results->ai_addr); v6addr->sin6_port = htons(port); } else { cerr << "getaddrinfo failed to provide an IPv4 or IPv6 address"; cerr << endl; freeaddrinfo(results); return false; } // Return the first result. assert(results != nullptr); memcpy(ret_addr, results->ai_addr, results->ai_addrlen); *ret_addrlen = results->ai_addrlen; // Clean up. freeaddrinfo(results); return true; } bool Connect(const struct sockaddr_storage &addr, const size_t &addrlen, int *ret_fd) { // Create the socket. int socket_fd = socket(addr.ss_family, SOCK_STREAM, 0); if (socket_fd == -1) { cerr << "socket() failed: " << strerror(errno) << endl; return false; } // Connect the socket to the remote host. int res = connect(socket_fd, reinterpret_cast(&addr), addrlen); if (res == -1) { cerr << "connect() failed: " << strerror(errno) << endl; return false; } *ret_fd = socket_fd; return true; }