/* 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 <netdb.h> */
|
#include <netdb.h>
|
#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");
|
}
|
}
|