/* tcp_utilities.c Adapted in C from Douglas Comer's "Internetworking with TCP/IP" by Jeff Ondich and Lauren Jantz, 1995 Rewritten in C++, Jeff Ondich, 2000 Re-rewritten in C, Jeff Ondich, 2000 These are utility functions that are intended to make very simple TCP-based client/server programs relatively easy to write. The functions here are used by the example client (hello_client.c) and servers (hello_server.c and hello_concurrent.c). */ #include #include #include #include #include #include #include #include "tcp_utilities.h" // Tries to make a TCP connection to the given host and port. Returns the socket descriptor // corresponding to the connection or -1 on failure. The host_name can be either a domain // name (e.g., www.moose.com) or dotted-decimal IPv4 address (e.g., 123.123.123.123). int make_connection(const char *host_name, int port) { // Ask the OS for a socket to use in connecting to the remote host. int socket_descriptor = socket(PF_INET, SOCK_STREAM, 0); if (socket_descriptor < 0) { return -1; } // Initialize the remote address. This variable will // eventually hold the address of the remote host. struct sockaddr_in remote_address; bzero( (char *)(&remote_address), sizeof(remote_address) ); remote_address.sin_family = AF_INET; remote_address.sin_port = htons((u_short)port); // Get the destination IP address using the host name. // The resulting address is stored in remote_address.sin_addr. struct hostent *host_info = gethostbyname(host_name); if (host_info) { bcopy(host_info->h_addr, (char *)(&remote_address.sin_addr), host_info->h_length); } else { // host_name didn't work out as a domain name, so now // we'll try it as a dotted-decimal IP address. remote_address.sin_addr.s_addr = inet_addr(host_name); if (remote_address.sin_addr.s_addr == INADDR_NONE) { return -1; } } // Connect the socket to destination address/port. if (connect(socket_descriptor, (struct sockaddr *)&remote_address, sizeof(remote_address) ) < 0) { return -1; } // The connection is good. Return the socket. return socket_descriptor; } // Allocates and initializes a socket that will act as the local endpoint of // incoming TCP connections. The bind() and listen() calls, if successful, // lay claim to the given port so that this process will receive requests for // connection to the port. int prepare_to_accept_connections(int port) { // Allocate a socket int socket_descriptor = socket(PF_INET, SOCK_STREAM, 0); if (socket_descriptor < 0) { fprintf(stderr, "Can't create socket: %s\n", strerror(errno)); exit(1); } // Initialize the socket and bind it to the desired port. struct sockaddr_in address; bzero((char *)(&address), sizeof(address)); address.sin_family = AF_INET; address.sin_addr.s_addr = INADDR_ANY; address.sin_port = (u_short)htons(port); if (bind(socket_descriptor, (struct sockaddr *)(&address), sizeof(address) ) < 0) { fprintf(stderr, "Can't bind to port %d: %s\n", port, strerror(errno)); exit(1); } // Lay claim to the port. if (listen(socket_descriptor, DEFAULT_QUEUE_LENGTH) < 0) { fprintf(stderr, "Can't listen on port %d: %s\n", port, strerror(errno)); exit(1); } // The socket is ready. Caller may call accept(). return socket_descriptor; } // Reads the specified number of bytes from the specified socket. // Returns the number of bytes that have been stored in the destination // buffer (which may be different from bytes_to_read if the socket // is closed). Returns a negative number if an error occurs. // // buffer must point to allocated memory large enough to hold byte_to_read bytes. // // Note that the read() system call, when applied to a network // connection, returns not when it has as many bytes as requested, // but simply when there are any bytes to return at all. That way, // a well designed program could process whatever bytes it has // received while waiting for more. The point of read_from_socket is // to simplify the case when you want to wait until all your bytes // have arrived. int read_from_socket(int socket_descriptor, char *buffer, int bytes_to_read) { char *destination = buffer; int bytes_to_go = bytes_to_read; while (bytes_to_go > 0) { int n = read(socket_descriptor, destination, bytes_to_go); if (n < 0) { return n; // error: caller should handle it } if (n == 0) { // EOF; that is, the connection was closed on the other end return bytes_to_read - bytes_to_go; } bytes_to_go = bytes_to_go - n; destination = destination + n; } return bytes_to_read - bytes_to_go; } // Retrieves the domain name of the machine on the other end of the TCP // connection specified by socket_descriptor. If no name is found, name // is assigned an empty string. void get_peer_host_name(int socket_descriptor, char *name, int name_buffer_size) { name[0] = '\0'; struct sockaddr_in peer; socklen_t peer_size = sizeof(peer); if (!getpeername(socket_descriptor, (struct sockaddr *)&peer, &peer_size)) { int in_address_size = sizeof(struct in_addr); struct hostent *host_info; host_info = gethostbyaddr((char *)(&peer.sin_addr), in_address_size, AF_INET); if (host_info) { strncpy(name, host_info->h_name, name_buffer_size); } else { strncpy(name, inet_ntoa(peer.sin_addr), name_buffer_size); } name[name_buffer_size - 1] = '\0'; } }