#include #include #include #include #include #include #include int open_listenfd(const char *port); // in csapp.h int accept(int socket, struct sockaddr *restrict addr, socklen_t *restrict addr_len); // in sys/socket.h // Opening a server socket int server(const char* port) { int clientfd = -1, listenfd = -1; listenfd = open_listenfd(port); // "Open the bar" if (listenfd < 0) { return -1; // Real error handling not shown } socklen_t clientlen; struct sockaddr_storage clientaddr; // Enough space for any address while ((clientfd = accept(listenfd, &clientaddr, &clientlen)) > 0) { // pointers can also be both NULL // Talk with the client using clientfd, a connected TCP socket, using read/write // You could spawn a separate thread close(clientfd); // Remember to say goodbye } close(listenfd); // Stop taking new clients. return 0; } int open_clientfd(const char *hostname, const char *port); // in csapp.h int client(const char* hostname, const char* port) { int clientfd = open_clientfd(hostname, port); if (clientfd < 0) { // Handle errors (-2 get address info error, -1 the socket itself failed) return -1; // Real error handling not shown } // talk to the server using clientfd, a now connected socket close(clientfd); // Say goodbye return 0; } /* open_listenfd - Open and return a listening socket on port. This * function is reentrant and protocol-independent. * * On error, returns: * -2 for getaddrinfo error * -1 with errno set for other errors. */ int open_listenfd(const char *port) { struct addrinfo hints = {0}, *listp, *p; int listenfd = -1, rc, optval = 1; hints.ai_socktype = SOCK_STREAM; // Accept connections hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; // … on any local IP address hints.ai_flags |= AI_NUMERICSERV; // if the port number is already a number // Get a list of potential server addresses if (( rc = getaddrinfo(NULL, port, &hints, &listp)) != 0){ fprintf(stderr, "getaddrinfo failed (port %s): %s\n", port, gai_strerror(rc)); return -2; } for (p = listp; p; p = p->ai_next){ // Walk the list for one that we can bind to listenfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol); // Create a socket fd if (listenfd < 0) { continue; // Socket failed, try the next } /* Eliminates "Address already in use" error from bind */ setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (const void *)&optval, sizeof(int)); // Bind the descriptor to the address if (bind(listenfd, p->ai_addr, p->ai_addrlen) == 0) { break; // Success } // not success, close and try next if (close(listenfd) < 0) { // Close failed, that's very wrong fprintf(stderr, "open_listenfd close failed: %s\n", strerror(errno)); return -1; } } freeaddrinfo(listp); // Clean up if (!p) { return -1; // No address worked } // Make it a listening socket ready to accept connection requests if (listen(listenfd, LISTENQ) < 0) { // Error close(listenfd); return -1; } return listenfd; // Call accept on listenfd to serve your clients their cidre } /* open_clientfd - Open connection to server at and * return a socket descriptor ready for reading and writing. This * function is reentrant and protocol-independent. * * On error, returns: * -2 for getaddrinfo error * -1 with errno set for other errors. */ #define LISTENQ 1024 /* Second argument to listen() */ int open_clientfd(const char *hostname, const char *port) { int clientfd = -1, rc; struct addrinfo hints = {0}, *listp, *p; hints.ai_socktype = SOCK_STREAM; // Open a connection hints.ai_flags = AI_NUMERICSERV; // ... using a numeric port arg. hints.ai_flags |= AI_ADDRCONFIG; // Recommended for connections // Get a list of potential server addresses if ((rc = getaddrinfo(hostname, port, &hints, &listp)) != 0) { fprintf(stderr, "getaddrinfo failed (%s:%s): %s\n", hostname, port, gai_strerror(rc)); return -2; } // Walk the list for one that we can successfully connect to for (p = listp; p; p = p->ai_next) { // Create a socket fd clientfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol); if (clientfd < 0){ continue; // Socket failed, try the next one } // Connect to the server if (connect(clientfd, p->ai_addr, p->ai_addrlen) != -1) { break; // Success } // Connect failed, try another if (close(clientfd) < 0) { fprintf(stderr, "open_clientfd: close failed: %s\n", strerror(errno)); return -1; } } freeaddrinfo(listp); // Clean up if (!p) { // All connects failed return -1; } return clientfd; // The last connect succeeded - we can ask for cidre and get it ! }