/* is_seqnum_sv.c A simple Internet stream socket server. Our service is to provide unique sequence numbers to clients. Usage: is_seqnum_sv [init-seq-num] (default = 0) See also is_seqnum_cl.c. */ #define _BSD_SOURCE /* To get definitions of NI_MAXHOST and NI_MAXSERV from */ #include #include "is_seqnum.h" #define BACKLOG 50 int main(int argc, char *argv[]) { char line[1024]; /* Length of requested sequence */ struct sockaddr_storage claddr; int lfd, cfd, optval; socklen_t addrlen; struct addrinfo hints; struct addrinfo *result, *rp; #define ADDRSTRLEN (NI_MAXHOST + NI_MAXSERV + 10) char addrStr[ADDRSTRLEN]; char host[NI_MAXHOST]; char service[NI_MAXSERV]; if (argc > 1 && strcmp(argv[1], "--help") == 0) printf("%s [init-seq-num]\n", argv[0]); /* Ignore the SIGPIPE signal, so that we find out about broken connection errors via a failure from write(). */ if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) err_exit(errno, "signal"); /* Call getaddrinfo() to obtain a list of addresses that we can try binding to */ memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_canonname = NULL; hints.ai_addr = NULL; hints.ai_next = NULL; hints.ai_socktype = SOCK_STREAM; hints.ai_family = AF_UNSPEC; /* Allows IPv4 or IPv6 */ hints.ai_flags = AI_PASSIVE | AI_NUMERICSERV; /* Wildcard IP address; service name is numeric */ if (getaddrinfo(NULL, PORT_NUM, &hints, &result) != 0) err_exit(errno, "getaddrinfo"); /* Walk through returned list until we find an address structure that can be used to successfully create and bind a socket */ optval = 1; for (rp = result; rp != NULL; rp = rp->ai_next) { lfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); if (lfd == -1) continue; /* On error, try next address */ if (setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) == -1) err_exit(errno, "setsockopt"); if (bind(lfd, rp->ai_addr, rp->ai_addrlen) == 0) break; /* Success */ /* bind() failed: close this socket and try next address */ close(lfd); } if (rp == NULL) err_exit(errno, "Could not bind socket to any address"); if (listen(lfd, BACKLOG) == -1) err_exit(errno, "listen"); freeaddrinfo(result); for (;;) { /* Handle clients iteratively */ /* Accept a client connection, obtaining client's address */ addrlen = sizeof(struct sockaddr_storage); cfd = accept(lfd, (struct sockaddr *) &claddr, &addrlen); if (cfd == -1) { err_msg(errno, "accept"); continue; } if (getnameinfo((struct sockaddr *) &claddr, addrlen, host, NI_MAXHOST, service, NI_MAXSERV, 0) == 0) snprintf(addrStr, ADDRSTRLEN, "(%s, %s)", host, service); else snprintf(addrStr, ADDRSTRLEN, "(?UNKNOWN?)"); printf("Connection from %s\n", addrStr); /* Read client request, send sequence number back */ if (readLine(cfd, line, 1024) <= 0) { close(cfd); continue; /* Failed read; skip request */ } if (write(cfd, line, strlen(line)) != strlen(line)) fprintf(stderr, "Error on write"); if (close(cfd) == -1) err_msg(errno, "close"); } }