/* * Sockets lab Client, * execute: echoclient dnsname port */ #include #include #include #include #include #include #include #include #include extern int h_errno; /* Maximum number of characters in a message + 1 */ #define MAXLINE 1024 /* functions to print error messages */ /* over kill */ void socket_error(); void connect_error(); void setsockopt_error(); void bind_error(); void listen_error(); void accept_error(); void gethostbyaddr_error(); void read_error(); void write_error(); void close_error(); void * dnsaccess(char *, char *); int main(int argc, char **argv) { int clientsocket; // client fd returned by socket function struct addrinfo *hostaddress; // from dnsaccess char *port = argv[2]; // port number char *server = argv[1]; // server dns name char thebuffer[256]; // buffer to hold characters int count; // count of characters struct sockaddr_in *address; //needed to hold returned address, which we will print char addrbuf[INET_ADDRSTRLEN]; //man inet_ntopfor details /* Check for correct number of arguments */ if (argc != 3) { fprintf(stderr, "usage: echoclient servername port %s \n", argv[0]); exit(0); } /* get the address of server */ hostaddress = dnsaccess(server, port); // pass pointers to server name, port // returned value points to hostaddress // struct /* We take advantage of the fact that AF_* and PF_* are identical */ /* get a socket with specified criteria as returned via hostaddress */ clientsocket = socket(hostaddress->ai_family, hostaddress->ai_socktype, hostaddress->ai_protocol); if (clientsocket < 0) // if socket error bail. { socket_error(); exit(0); } /* do not care about anything else, except address info for socket * getname is new way to do this, but old way works. * print it out for fun * */ address = (struct sockaddr_in *) hostaddress->ai_addr; /* have the address, convert to network format */ inet_ntop(address->sin_family, &address->sin_addr, addrbuf, sizeof(addrbuf)); printf("I am the client\n"); printf("The address: %s\n", addrbuf); printf("The socket: %i\n", clientsocket); /* have a socket, now create a connection to server ip address, port */ if (connect(clientsocket, hostaddress->ai_addr, hostaddress->ai_addrlen) < 0) { connect_error(); exit(0); } /* believe we can now giveup hostaddress */ freeaddrinfo(hostaddress); printf("About to read data \n"); /* write to the server whatever is typed on the console * then print out what the server returns */ while (fgets(thebuffer, sizeof(thebuffer)-1, stdin) != NULL) { printf("the string: \n"); fputs(thebuffer, stdout); /* NOT SURE WHY I COMMENTED OUT NEXT LINES, NEED TO TEST */ /* // get out for now, until server runs // using send over write send(clientsocket, thebuffer, strlen(thebuffer)); // write to server // using recv over read count = recv(clientsocket, thebuffer, sizeof(thebuffer) -1); //read what server sends if (count >= 0) // have data, add end of string { thebuffer[count] = '\0'; fputs(thebuffer, stdout); //print out what the server sent } */ } /* All Done */ close(clientsocket); exit(0); } void accept_error() { switch (errno) { case EAGAIN: printf("The socket is marked non-blocking and no connections are present to be accepted."); break; case EBADF: printf("The descriptor is invalid"); break; case ECONNABORTED: printf("A connection has been aborted."); break; case EINTR: printf("The system call was interrupted by a signal that was caught before a valid connection arrived."); break; case EINVAL: printf("Socket is not listening for connections, or addrlen is invalid (e.g., is negative)."); break; case EMFILE: printf("The per-process limit of open file descriptors has been reached."); break; case ENFILE: printf("The system limit on the total number of open files has been reached."); break; case ENOTSOCK: printf("The descriptor references a file, not a socket."); break; case EFAULT: printf("The addr argument is not in a writable part of the user address space."); break; case ENOBUFS: printf(" Not enough free memory. This often means that the memory allocation is limited by the socket \ buffer limits, not by the system memory."); break; case EPROTO: printf("Protocol error"); break; case EPERM: printf("Firewall rules forbid connection"); break; default: printf("Unknown error"); break; } } void close_error() { switch (errno) { case EBADF: printf("fd isn't a valid open file descriptor"); break; case EINTR: printf("The close call was interrupted by a signal"); break; case EIO: printf("An I/O error occurred."); break; default: printf("Unknown error"); break; } } void gethostbyaddr_error() { switch(h_errno) { case HOST_NOT_FOUND: printf("The specified host is unknown."); break; case NO_ADDRESS: printf("The requested name is valid but does not have an IP address."); break; case NO_RECOVERY: printf("A non-recoverable name server error occurred."); break; case TRY_AGAIN: printf("A temporary error occurred on an authoritative name server. Try again later."); break; default: printf("Unknown error"); break; } } /*if there is an error getting a socket, errno has the error * number * man sockets to check on the error. */ void socket_error() { switch(errno) { case EACCES: printf("Permission to create a socket of the specified type and/or protocol is denied."); break; case EAFNOSUPPORT: printf("The implementation does not support the specified address family."); break; case EINVAL: printf("Unknown protocol, or protocol family not available."); break; case EMFILE: printf("Process file table overflow."); break; case ENOBUFS: printf("The system limit on the total number of open files has been reached."); break; case ENOMEM: printf("Insufficient memory is available. The socket cannot be created until sufficient resources are freed."); break; case EPROTONOSUPPORT: printf("The protocol type or the specified protocol is not supported within this domain."); break; default: printf("Unknown error"); break; } } void connect_error() { switch(errno) { case EACCES: printf("Permission to create a socket of the specified type and/or protocol is denied."); break; case EPERM: printf("The user tried to connect to a broadcast address without having the socket \ broadcast flag enabled or the connection request failed because of a local fire‐ \ wall rule."); break; case EADDRINUSE: printf("Local address is already in use."); break; case EAFNOSUPPORT: printf("The passed address didn’t have the correct address family in its sa_family field."); break; case EAGAIN: printf("No more free local ports or insufficient entries in the routing cache. For \ PF_INET see the net.ipv4.ip_local_port_range sysctl in ip(7) on how to increase \ the number of local ports."); break; case EALREADY: printf("The socket is non-blocking and a previous connection attempt has not yet been completed."); break; case EBADF: printf("The file descriptor is not a valid index in the descriptor table."); break; case ECONNREFUSED: printf("No one listening on the remote address."); break; case EFAULT: printf("The socket structure address is outside the user’s address space."); break; case EINPROGRESS: printf("The socket is non-blocking and the connection cannot be completed immediately."); break; case EINTR: printf("The system call was interrupted by a signal that was caught."); break; case EISCONN: printf("The socket is already connected."); break; case ENETUNREACH: printf("Network is unreachable."); break; case ENOTSOCK: printf("The file descriptor is not associated with a socket."); break; case ETIMEDOUT: printf("Timeout while attempting connection. The server may be too busy to accept new \ connections. Note that for IP sockets the timeout may be very long when syncook‐ \ ies are enabled on the server."); break; default: printf("Unknown error"); break; } } void setsockopt_error() { switch(errno) { case EBADF: printf("THe argument s is not a valid descriptor"); break; case EFAULT: printf("The address pointed to by optval is not in a valid part of the process \ address space. For getsockopt(), this error may also be returned if optlen \ is not in a valid part of the process address space"); break; case EINVAL: printf("optlen invalid in setsockopt()"); break; case ENOPROTOOPT: printf("THe option is unkown at the level indicated"); break; case ENOTSOCK: printf("The argument s is a file, not a socket"); break; default: printf("Unknown error"); break; } } void bind_error() { switch(errno) { case EACCES: printf("The address is protected, and the user is not the superuser."); break; case EADDRINUSE: printf("Another socket is already listening on the same port"); break; case EBADF: printf("The argument sockfd is not a valid descriptor."); break; case EINVAL: printf("The socket is already bound to an address."); break; case ENOTSOCK: printf("The argument sockfd is not a socket."); break; case EADDRNOTAVAIL: printf("A non-existent interface was requested or the requested address was not local."); break; case EFAULT: printf("my_addr points outside the user’s accessible address space."); break; case ELOOP: printf("Too many symbolic links were encountered in resolving my_addr."); break; case ENAMETOOLONG: printf("my_addr is too long"); break; case ENOENT: printf("The file does not exist"); break; case ENOMEM: printf("Insufficient kernel memory was available."); break; case ENOTDIR: printf("A component of the path prefix is not a directory."); break; case EROFS: printf("The socket inode would reside on a read-only file system."); break; default: printf("Unknown error"); break; } } void listen_error() { switch(errno) { case EADDRINUSE: printf("Another socket is already listening on the same port"); break; case EBADF: printf("The argument sockfd is not a valid descriptor."); break; case ENOTSOCK: printf("The argument sockfd is not a socket."); break; case EOPNOTSUPP: printf("The socket is not of a type that supports the listen() operation."); break; default: printf("Unknown error"); break; } } void read_error() { switch(errno) { case EAGAIN: printf("Non-blocking I/O has been selected using O_NONBLOCK and no data was immediately available for reading."); break; case EBADF: printf("fd is not a valid file descriptor or is not open for reading."); break; case EFAULT: printf("buf is outside your accessible address space."); break; case EINTR: printf("The call was interrupted by a signal before any data was read."); break; case EINVAL: printf("fd is attached to an object which is unsuitable for reading; or the file was opened \ with the O_DIRECT flag, and either the address specified in buf, the value specified in \ count, or the current file offset is not suitably aligned."); break; case EIO: printf("I/O error. This will happen for example when the process is in a background process group, tries to read from \ its controlling tty, and either it is ignoring or blocking SIGTTIN or its process group is orphaned. It may \ also occur when there is a low-level I/O error while reading from a disk or tape."); break; case EISDIR: printf("fd refers to a directory."); break; default: printf("Unknown error"); break; } } void write_error() { switch (errno) { case EAGAIN: printf("Non-blocking I/O has been selected using O_NONBLOCK and the write would block."); break; case EBADF: printf("fd is not a valid file descriptor or is not open for writing."); break; case EFAULT: printf("buf is outside your accessible address space."); break; case EFBIG: printf("An attempt was made to write a file that exceeds the implementation-defined maximum file size or \ the process’ file size limit, or to write at a position past the maximum allowed offset."); break; case EINTR: printf("The call was interrupted by a signal before any data was written."); break; case EINVAL: printf("fd is attached to an object which is unsuitable for writing; or the file was opened with the \ O_DIRECT flag, and either the address specified in buf, the value specified in count, or the \ current file offset is not suitably aligned."); break; case EIO: printf("A low-level I/O error occurred while modifying the inode."); break; case ENOSPC: printf("The device containing the file referred to by fd has no room for the data."); break; case EPIPE: printf("fd is connected to a pipe or socket whose reading end is closed. When this happens the writing\ process will also receive a SIGPIPE signal. (Thus, the write return value is seen only if the\ program catches, blocks or ignores this signal.)"); break; default: printf("Unknown error"); break; } } /* function to do DNS access * uses the new struct and new commands * to handle IPv6 and to be thread safe */ void * dnsaccess(char *name, char *port) //name is domain name, port is the port { struct addrinfo hints; // man getaddrinfo for details struct addrinfo *firsthost; struct sockaddr_in *address; //needed to hold return address, which we will print char addrbuf[INET_ADDRSTRLEN]; //man inet_ntopfor details int error; /* 0 memory so that debugging does not find trash */ memset(&hints, 0, sizeof(hints)); /* set the flags in the hits addrinfo struct */ /* tells getaddrinfo, what info about host is wanted */ hints.ai_flags = AI_CANONNAME; // want canonical name hints.ai_family = AF_UNSPEC; // any protocol family hints.ai_socktype = SOCK_STREAM; // TCP socket /* do the call to get dns info for the host */ error = getaddrinfo(name, port, &hints, &firsthost); /* if call failed, error and die */ if (error) { errx(1, "getaddrinfo error"); } /* have the dns info, start by printing first name, * which is the canonical name */ printf("Canonical hostname: %s\n", firsthost->ai_canonname); /* do not care about anything else, except address info for socket * print it out for fun * */ address = (struct sockaddr_in *) firsthost->ai_addr; /* have the address, convert to network format */ inet_ntop(address->sin_family, &address->sin_addr, addrbuf, sizeof(addrbuf)); printf("The address: %s\n", addrbuf); /*we are done */ printf("That's All Folks, from dnsaccess \n"); /* return address of the host, so can be used in socket creation */ return (firsthost); }