/* * Echo server, to start needs the port number * not threaded or anything like that * */ #include #include #include #include #include #include #include #include #include #include extern int h_errno; /* Number of connections to allow */ #define LIST_MAX 1024 /* Maximum number of characters in a message + 1 */ #define MAXLINE 1024 /* functions to print error messages */ void socket_error(); void setsockopt_error(); void bind_error(); void listen_error(); void accept_error(); void gethostbyaddr_error(); void recv_error(); void send_error(); void close_error(); int main(int argc, char **argv) { int listenfd, connfd, optval = 1; char *port = argv[1]; struct addrinfo hints; // hints will be used to tell socket struct addrinfo *hostaddress = NULL; //has all the host addresses, but we only // first one. /* Set up our buffer to accept a message from client */ char buf[MAXLINE]; /* To be used when sending and receiving messages */ size_t n, numread, nleft, nwritten, numBrecv, numBsent; char c; char *bufptr; socklen_t clientlen; int error; /* Check for correct number of arguments */ if (argc != 2) { fprintf(stderr, "usage: %s \n", argv[0]); exit(0); } /* Port we will accept connections on */ port = atoi(argv[1]); /* find out the server's IP address and port */ memset(&hints, 0, sizeof(hints)); hints.ai_flags = AI_ADDRCONFIG | AI_V4MAPPED | AI_PASSIVE; hints.ai_family = AF_INET6; hints.ai_socktype = SOCK_STREAM; error = getaddrinfo(NULL, port, &hints, &hostaddress); //get host info if (error !=0) { freeaddrinfo(hostaddress); // error, free struct meme fprintf (stderr, "port %s: %s\n", port gai_strerror(error)); return -2; } /* Creates the socket descriptor take advantage that AF_* and PF_* are identical */ printf("Server Creating socket..."); if ((listenfd = socket(hostaddress->ai_family, hostaddress->ai_socktype, hostaddress->ai_protocol))) < 0) { socket_error(); return (-1); } printf("Have socket id %s: %s\n", listenfd); /* Configure our socket SOL_SOCKET to set socket level options SO_REUSEADDR to support reuse of local address optval enables or disables the option */ printf("Setting socket options..."); if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (const void *)&optval, sizeof(int)) < 0) { setsockopt_error(); return(-1); } printf("Binding socket to file descriptor..."); /*listenfd will be endpoint for all requests to this port */ /* Associate the server socket with our listenfd file descriptor */ if (bind(listenfd, hostaddress->ai_addr, hostaddress->ai_addrlen) < 0) { bind_error(); return (-1); } printf("Done with bind\n"); printf("Enabling listening on socket..."); /* Set listenfd to be able to listen for requests from clients */ if (listen(listenfd, LIST_MAX) < 0) { listen_error(); return (-1); } printf("Done\n"); /* believe we can release hostaddress struct */ freeaddrinfo(hostaddress); while (1) { /* Accept a connection request from a client */ printf("Waiting for a client...\n"); clientlen = sizeof(clientaddr); if ((connfd = accept(listenfd, (struct sockaddr *)&clientaddr, &clientlen)) < 0) { accept_error(); } printf("Client found\n"); } /* Convert socket address to numbers and dots notation of IP address */ haddrp = inet_ntoa(clientaddr.sin_addr); /* Print connection info */ printf("server connected to %s (%s)\n", hp->h_name, haddrp); printf("Done with setup\n"); while (1) { /* Prepare to receive a message from the client */ printf("Reading message from client...\n"); numBrecv = recv(connfd, buf, MAXLINE, 0); if (numBrecv < 0) { recv_error(); } /* echo message back to server */ numBsent = send(connfd, buf, numBrecv, 0); if (numBsent <0) { send_error(); } else if (numBsent != numBrevc) { send_error(); } // more data? numBrecv = recv(connfd, buf, MAXLINE, 0); if (numBrecv < 0) { recv_error(); } } /* Close the connection to client */ printf("Closing connection with client..."); if (close(connfd) < 0) { close_error(); } printf("Really Done\n"); } exit(); } 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; } } 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 recv_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 send_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; } }