Assignment
Systems Programming
PROGRAM DESCRIPTION:
In this assignment, you will write a complete C program to support a client/server and
pseudo-client/client model) using Linux sockets using the apollo server instead of the
standard Linux CSE machines (i.e., cse01 – cse06). The program will consist of a
server that will keep a running sum of the integral data being sent by two clients as
follows:
Server
o The server will receive integer values from up to two clients (in any order) and
add these values to its current total separate for each client, which the server
then returns back to the originating client so that the client is aware of its most
up-to-date total. Unlike Minor 6, the values sent in from the clients will be input
manually from the keyboard for each client. The server can have, at most, 2
clients connected at one time, though this functionality (i.e., a client being able to
send an integral value to the server and the server responding to this request)
should still continue even when only 1 client is connected.
o When the total sum for an individual client reaches a value between 1,024 and
49,151 (the range of ports registered for general use), the server will return this
value back to the client as usual, but the server will also send the message
“PORT” followed by this value to the other client, which will act as a trigger for
both clients that the client whose value exceeded the port threshold will then act
as a server for the other client to connect to. If only 1 client is connected at the time this threshold is reached, the server shall reset the individual client’s current total back to 0.
oThe server will provide important status updates of messages sent and received,
such as connection events, each client’s running total, and when the port
threshold has been reached.
oThe server will continue to “listen” for clients and run indefinitely until manually
terminated. A client may disconnect and later reconnect to the server. Up to 2 clients may connect and disconnect at any time, but the server should still be able to respond to connected clients while listening for new clients (if 1 or no clients are connected).
Clients (there are up to 2 clients)
o Once connected to the server, a user will manually enter integral values using
the keyboard for each client that will be sent to the server. The server, in
response to this integral value, will send the client a current individual total for
that client so that the client is aware of the most up-to-date total.
o Once the current individual total for a client reaches a value between 1,024 and
49,151 (the range of ports registered for general use), the “originating” client
whose total has reached this threshold will then itself start acting as the “server”
for the other client to connect to, using this total as the port number. The other
client will then (1) disconnect from the server, (2) connect to the originating client
(i.e., the new “client” server), (3) send its current total to the originating, and (4)
disconnect from the originating client. The remaining “active” client should still be
connected to the server and may continue sending its own integer values to the
server.
oEach client will provide important status updates of messages sent and received,
such as connection events, the client’s running total and when a client-client
connection is being established.
oA client may voluntarily “quit” sending integer values to the server when the user
manually enters a 0 for its integer value (whereupon the client will disconnect
from the server).
APOLLO SERVER:
The server and one client will be run on one of the VMs, while another client will be run on the other VM. Note that client 1 and client 2 will consist of the same code handling both cases. The configuration for each team will be similar to the following diagram, although IP addresses and ports will vary for each team:
The figure shows the client on the remote machine connecting to the client on the same
machine as the server, but it could be the other way around (i.e., the client on the same
machine as the server connecting to the client on the remote machine), depending on
which client exceeded the “port” threshold to trigger the new connection.
After connecting with VPN, each group will connect to the apollo server address,
[email protected], using their assigned group number and ports, which
will be port forwarded to their specific VM. Then, once on the respective machine, you
will invoke your programs for the server and clients in the following manner (using the
above diagram as reference):
SERVER: (on A01)
./server
For example, ./server 8001.
CLIENT 1: (on A01)
./client
For example, ./client A01 8001 192.168.122.117.
CLIENT 2: (on A17)
./client
For example, ./client A01 8001 192.168.122.101.
nov01Bcli.c
#include
#include
#include
#include
#include
#include
#include
#include
void error(const char *msg)
{
perror(msg);
exit(0);
}
int main(int argc, char *argv[])
{
int sockfd, portno, n;
struct sockaddr_in serv_addr;
struct hostent *server;
char buffer[256];
if (argc < 3)
{
fprintf(stderr,”usage %s hostname port\n”, argv[0]);
exit(0);
}
portno = atoi(argv[2]);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
{
error(“ERROR opening socket”);
}
server = gethostbyname(argv[1]);
if (server == NULL)
{
fprintf(stderr,”ERROR, no such host\n”);
exit(0);
}
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *)server->h_addr, (char *)&serv_addr.sin_addr.s_addr, server->h_length);
serv_addr.sin_port = htons(portno);
if (connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0)
{
error(“ERROR connecting”);
}
printf(“Please enter the message: “);
bzero(buffer,256);
fgets(buffer,255,stdin);
n = write(sockfd,buffer,strlen(buffer));
if (n < 0)
{
error(“ERROR writing to socket”);
}
bzero(buffer,256);
n = read(sockfd,buffer,255);
if (n < 0)
{
error(“ERROR reading from socket”);
}
printf(“%s\n”,buffer);
close(sockfd);
return 0;
}
nov01Bsvr.c
/* A simple server in the internet domain using TCP
The port number is passed as an argument */
#include
#include
#include
#include
#include
#include
#include
void error(const char *msg)
{
perror(msg);
exit(1);
}
int main(int argc, char *argv[])
{
int sockfd, newsockfd, portno;
socklen_t clilen;
char buffer[256];
struct sockaddr_in serv_addr, cli_addr;
int n;
if (argc < 2)
{
fprintf(stderr,”ERROR, no port provided\n”);
exit(1);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
{
error(“ERROR opening socket”);
}
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
{
error(“ERROR on binding”);
}
listen(sockfd,5);
clilen = sizeof(cli_addr);
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0)
{
error(“ERROR on accept”);
}
bzero(buffer,256);
n = read(newsockfd,buffer,255);
if (n < 0)
{
error(“ERROR reading from socket”);
}
printf(“Here is the message: %s\n”,buffer);
n = write(newsockfd,”I got your message”,18);
if (n < 0)
{
error(“ERROR writing to socket”);
}
close(newsockfd);
close(sockfd);
return 0;
}
nov03Acli.c
#include
#include
#include
#include
#include
#include /* inet(3) functions */
#define MAXLINE 4096
void dg_cli(FILE *fp, int sockfd, const struct sockaddr *pservaddr, socklen_t servlen);
int main(int argc, char **argv)
{
int sockfd;
struct sockaddr_in servaddr;
if (argc != 2)
{
printf(“usage : %s \n”, argv[0]);
exit(1);
}
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(9877);
inet_pton(AF_INET, argv[1], &servaddr.sin_addr);
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
dg_cli(stdin, sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr));
exit(0);
}
void dg_cli(FILE *fp, int sockfd, const struct sockaddr *pservaddr, socklen_t servlen)
{
int n;
char sendline[MAXLINE], recvline[MAXLINE+1];
while (fgets(sendline, MAXLINE, fp) != NULL)
{
sendto(sockfd, sendline, strlen(sendline), 0, pservaddr, servlen);
n = recvfrom(sockfd, recvline, MAXLINE, 0, NULL, NULL);
recvline[n] = ‘\0’; /* null terminate */
printf(“rcvd msg from server: “);
fputs(recvline, stdout);
}
}
nov03Asvr.c
#include
#include
#include
#include
#include /* inet(3) functions */
#define MAXLINE 4096
void dg_echo(int sockfd, struct sockaddr *pcliaddr, socklen_t clilen);
int main(int argc, char **argv)
{
int sockfd;
struct sockaddr_in servaddr,cliaddr;
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(9877);
bind(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr));
dg_echo(sockfd, (struct sockaddr *) &cliaddr, sizeof(cliaddr));
}
void dg_echo(int sockfd, struct sockaddr *pcliaddr, socklen_t clilen)
{
int n;
socklen_t len;
char mesg[MAXLINE];
for( ; ; )
{
len = clilen;
n = recvfrom(sockfd, mesg, MAXLINE, 0, pcliaddr, &len);
printf(“rcvd from client: %s\n”, mesg);
sendto(sockfd, mesg, n, 0, pcliaddr, len);
}
}
nov03Bcli.c
#include
#include
#include
#include
#include
#include
#include
#define SOCKETNAME “selectServerSocket”
int
main(void)
{
int s; /* This end of connection*/
int len; /* length of sockaddr */
int nread; /* return from read() */
int nready; /* # fd’s ready. */
int maxfd; /* fd’s 0 to maxfd-1 checked. */
char buf[1024];
fd_set fds; /* set of file descriptors to check. */
struct sockaddr_un name;
if( (s = socket(AF_UNIX, SOCK_STREAM, 0) ) < 0)
{
perror(“socket”);
exit(1);
}
/*Create the address of the server.*/
memset(&name, 0, sizeof(struct sockaddr_un));
name.sun_family = AF_UNIX;
strcpy(name.sun_path, SOCKETNAME);
len = sizeof(name.sun_family) + strlen(name.sun_path);
/*Connect to the server.*/
if (connect(s, (struct sockaddr *) &name, len) < 0)
{
perror(“connect”);
exit(1);
}
maxfd = s + 1;
while(1)
{
/* Set up polling. */
FD_ZERO(&fds);
FD_SET(s,&fds);
FD_SET(0,&fds);
/* Wait for some input. */
nready = select(maxfd, &fds, (fd_set *) 0, (fd_set *) 0,
(struct timeval *) 0);
/* If either device has some input,
read it and copy it to the other. */
if( FD_ISSET(s, &fds))
{
nread = recv(s, buf, sizeof(buf), 0);
/* If error or eof, terminate. */
if(nread < 1)
{
close(s);
exit(0);
}
write(1, buf, nread);
}
if( FD_ISSET(0, &fds))
{
nread = read(0, buf, sizeof(buf));
/* If error or eof, terminate. */
if(nread < 1){
close(s);
exit(0);
}
send( s, buf, nread, 0);
}
}
}
nov03Bsvr.c
/* This program sets up a socket to allow two clients to talk to each other */
#include
#include
#include
#include
#include
#include
#include
#define SOCKETNAME “selectServerSocket”
int
main(void)
{
char buf[1024]; /* Buffer for messages to others. */
int s; /* Listen socket */
int ns; /* Socket for first connection. */
int ns2; /* Socket for second connection. */
int len; /* len of sockaddr */
int maxfd; /* descriptors up to maxfd-1 polled*/
int nread; /* # chars on read()*/
int nready; /* # descriptors ready. */
struct sockaddr_un name;
fd_set fds; /* Set of file descriptors to poll*/
/* Remove any previous socket.*/
unlink(SOCKETNAME);
/* Create the socket. */
if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
{
perror(“socket”);
exit(1);
}
/* Create the address of the server.*/
memset(&name, 0, sizeof(struct sockaddr_un));
name.sun_family = AF_UNIX;
strcpy(name.sun_path, SOCKETNAME);
len = sizeof(name.sun_family) + strlen(name.sun_path);
/*Bind the socket to the address.*/
if (bind(s, (struct sockaddr *) &name, len) < 0)
{
perror(“bind”);
exit(1);
}
/* Listen for connections. */
if (listen(s, 5) < 0)
{
perror( “listen”);
exit(1);
}
/*Accept a connection.*/
if ((ns = accept(s, (struct sockaddr *) &name, &len)) < 0)
{
perror(“accept”);
exit(1);
}
/* Accept another connection. */
if ((ns2 = accept(s, (struct sockaddr *) &name, &len)) < 0)
{
perror(“accept”);
exit(1);
}
maxfd = (ns > ns2 ? ns : ns2) + 1;
while (1)
{
/* Set up polling using select. */
FD_ZERO(&fds);
FD_SET(ns,&fds);
FD_SET(ns2,&fds);
/* Wait for some input. */
nready = select(maxfd, &fds, (fd_set *) 0, (fd_set *) 0,
(struct timeval *) 0);
/* If either descriptor has some input,
read it and copy it to the other. */
if( FD_ISSET(ns, &fds))
{
nread = recv(ns, buf, sizeof(buf), 0);
/* If error or eof, terminate. */
if(nread < 1)
{
close(ns);
close(ns2);
exit(0);
}
send( ns2, buf, nread, 0);
}
if( FD_ISSET(ns2, &fds))
{
nread = recv(ns2, buf, sizeof(buf), 0);
/* If error or eof, terminate. */
if(nread < 1)
{
close(ns);
close(ns2);
exit(0);
}
send( ns, buf, nread, 0);
}
}
}
oct30Acli.c
#include
#include
#include
#include
#include
#include
#include
#define SOCK_PATH “my_socket”
int main(void)
{
int s, t, len;
struct sockaddr_un remote;
char str[100];
if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
{
perror(“socket”);
exit(1);
}
printf(“Trying to connect…\n”);
remote.sun_family = AF_UNIX;
strcpy(remote.sun_path, SOCK_PATH);
len = strlen(remote.sun_path) + sizeof(remote.sun_family);
if (connect(s, (struct sockaddr *)&remote, len) == -1)
{
perror(“connect”);
exit(1);
}
printf(“Connected.\n”);
while(printf(“> “), fgets(str, 100, stdin), !feof(stdin))
{
if (send(s, str, strlen(str), 0) == -1)
{
perror(“send”);
exit(1);
}
if ((t=recv(s, str, 100, 0)) > 0)
{
str[t] = ‘\0’;
printf(“echo> %s”, str);
}
else
{
if (t < 0)
{
perror(“recv”);
}
else
{
printf(“Server closed connection\n”);
}
exit(1);
}
}
close(s);
return 0;
}
oct30Asvr.c
#include
#include
#include
#include
#include
#include
#include
#define SOCK_PATH “my_socket”
int main(void)
{
int s, s2, t, len;
struct sockaddr_un local, remote;
char str[100];
if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
{
perror(“socket”);
exit(1);
}
local.sun_family = AF_UNIX;
strcpy(local.sun_path, SOCK_PATH);
unlink(local.sun_path); // remove existing socket
len = strlen(local.sun_path) + sizeof(local.sun_family);
if (bind(s, (struct sockaddr *)&local, len) == -1)
{
perror(“bind”);
exit(1);
}
if (listen(s, 5) == -1)
{
perror(“listen”);
exit(1);
}
for(;;)
{
int done, n;
printf(“Waiting for a connection…\n”);
t = sizeof(remote);
if ((s2 = accept(s, (struct sockaddr *)&remote, &t)) == -1)
{
perror(“accept”);
exit(1);
}
printf(“Connected.\n”);
done = 0;
do
{
n = recv(s2, str, 100, 0);
if (n > 0)
{
str[n] = ‘\0’;
printf(“Received : %s\n”, str);
}
else if (n <= 0)
{
if (n < 0) perror(“recv”);
done = 1;
}
if (!done)
{
if (send(s2, str, n, 0) < 0)
{
perror(“send”);
done = 1;
}
}
} while (!done);
close(s2);
}
close(s);
return 0;
}
Solution
cliMajor2.c
/*
* The client source code
* Once connected to the server, a user will manually enter intgral values using the keyborad for each client that will be sent to the server.
* The server, in response to this intgral value, will send the client a current individual total for that client so that client is aware of the most
* up-to-date total
* Format: ./client
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
// Function prototypes
int clientInit(int, char*, char*, int);
void listenerInit(int, int, int, int);
void remoteInit(int, char*, int, char*);
void error(const char*);
void signal_callback_handler(int signum);
int main(int argc, char *argv[])
{
// Checks if user provided necessary arguments
if (argc != 4)
{
fprintf(stderr, “Usage: ./client \n”);
exit(0);
}
// Register signal and signal handler
signal(SIGINT, signal_callback_handler);
// Declares variables
char* serverIP = argv[1];
char *remoteIP = argv[3];
int serverPort = atoi(argv[2]);
ssize_t n = 0;
// Listener variables
int listenerPort = 0;
int listenerSocket = 0;
int listenerSocketNew = 0;
// Remote variables
int remotePort = 0;
int remoteSocket = 0;
// Client variables
char buffer[256];
int serverSocket = socket(AF_INET, SOCK_STREAM, 0);
char clientID[2];
int currentTotal = 0;
remotePort = clientInit(serverSocket, clientID, serverIP, serverPort);
if (remotePort > 0)
{
// Disconnect to server socket
n = write(serverSocket, “-1”, 3);
if (n < 0)
{
error(“ERROR writing to socket”);
}
// Start new connection to new server
printf(“Start new connection to new server.\n”);
printf(“Enter current total values: “);
bzero(buffer, 256);
fgets(buffer, 255, stdin);
remoteInit(remoteSocket, remoteIP, remotePort, buffer);
printf(“Disconnect to new server and EXIT!\n”);
} else
{
while (1)
{
// Prompts user for enter integral value and stores it in a buffer
printf(“Enter integral values: “);
bzero(buffer, 256);
fgets(buffer, 255, stdin);
// Writes integral value to server
n = write(serverSocket, buffer, strlen(buffer));
if (n < 0)
{
error(“ERROR writing to socket”);
}
printf(“Sent to server: %s”, buffer);
// Reads server reply (should be total) and stores it in a buffer
bzero(buffer, 256);
n = read(serverSocket, buffer, 255);
if (n < 0)
{
error(“ERROR reading from socket”);
} else if (strncmp(buffer, “QUIT”, 6) == 0)
{
// Listens for QUIT confirmation from server then breaks from loop
break;
} else
{
// Prints total count from server
currentTotal = (int) strtoul(buffer, NULL, 0);
printf(” Current total: %d\n”, currentTotal);
if (currentTotal > 1024 && currentTotal < 49151)
{
listenerPort = currentTotal;
printf(“Start listen for new client connect to\n”);
listenerInit(listenerSocket, listenerPort, listenerSocketNew, serverSocket);
printf(“Exit client \n”);
close(listenerSocket);
close(listenerSocketNew);
break;
}
}
}
}
close(serverSocket);
close(listenerSocket);
close(listenerSocketNew);
close(remoteSocket);
printf(“Disconnected from server. %s\n”, clientID);
return EXIT_SUCCESS;
}
int clientInit(int serverSocket, char* clientID, char *serverIP, int serverPort)
{
printf(“SERVER IP: %s\n”, serverIP);
printf(“SERVER PORT: %i\n”, serverPort);
struct sockaddr_in serv_addr;
struct hostent* server = NULL;
ssize_t n = 0;
// Initializes socket
if (serverSocket < 0)
error(“ERROR opening socket”);
server = gethostbyname(serverIP);
if (server == NULL)
{
fprintf(stderr, “ERROR, no such host\n”);
exit(0);
}
bzero((char*) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy(server->h_addr, (char*) &serv_addr.sin_addr.s_addr, (size_t) server->h_length);
serv_addr.sin_port = htons(serverPort);
if (connect(serverSocket, (struct sockaddr*) &serv_addr, sizeof(serv_addr)) < 0)
{
error(“ERROR connecting to server”);
}
//TODO: Read message return. If return PORT or clientID
char buffer[256];
bzero(buffer, 256);
bzero(buffer, 256);
n = read(serverSocket, buffer, 255);
if (n < 0)
{
error(“ERROR reading from socket”);
} else if (strncmp(buffer, “PORT”, 4) == 0)
{
// Listens for PORT return from server
int newport = (int) strtoul(buffer + 5, NULL, 0);
printf(“Receive package: %s from server. New port: %d\n”, buffer, newport);
return newport; // Need close to current server. And create new for new server
} else
{
bzero(clientID, 2);
// Receives clientID from server
memcpy(clientID, buffer, 6);
printf(“CLIENT ID: %s\n\n”, clientID);
}
return 0;
}
void listenerInit(int listenerSocket, int listenerPort, int listenerSocketNew, int serverSocket)
{
// Declares variables
ssize_t n;
socklen_t clilen;
struct sockaddr_in serv_addr, cli_addr;
char buffer[256];
// Opens INET TCP socket
listenerSocket = socket(AF_INET, SOCK_STREAM, 0);
if (listenerSocket < 0)
{
error(“ERROR opening socket”);
}
// Initializes socket structure
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(listenerPort);
// Binds the host address using bind() function
if (bind(listenerSocket, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
{
error(“ERROR on binding”);
}
// Listens for clients and waits for incoming connections
listen(listenerSocket, 5);
clilen = sizeof(cli_addr);
listenerSocketNew = accept(listenerSocket, (struct sockaddr *) &cli_addr, &clilen);
if (listenerSocketNew < 0)
{
error(“ERROR on accept”);
}
printf(“Connection accepted: Remote client\n”);
printf(“Handler assigned: Remote client\n”);
bzero(buffer, 256);
n = read(listenerSocketNew, buffer, 255);
if (n < 0)
{
error(“ERROR writing to socket”);
}
int clientTotal = (int) strtoul(buffer, NULL, 0);
printf(“Received %u from remote client\n”, clientTotal);
close(listenerSocketNew);
printf(“Disconnected: Remote Client\n”);
}
void remoteInit(int remoteSocket, char* remoteIP, int remotePort, char* buffer)
{
struct sockaddr_in serv_addr;
struct hostent* server = NULL;
remoteSocket = socket(AF_INET, SOCK_STREAM, 0);
int currentTotal = (int) strtoul(buffer, NULL, 0);
ssize_t n;
// Initializes socket
if (remoteSocket < 0)
error(“ERROR opening socket”);
server = gethostbyname(remoteIP);
if (server == NULL)
{
fprintf(stderr, “ERROR, no such host\n”);
exit(0);
}
bzero((char*) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy(server->h_addr, (char*) &serv_addr.sin_addr.s_addr, (size_t) server->h_length);
serv_addr.sin_port = htons(remotePort);
if (connect(remoteSocket, (struct sockaddr*) &serv_addr, sizeof(serv_addr)) < 0)
{
//error(“ERROR connecting”);
fprintf(stderr, “Remote client is offline, data not sent\n”);
} else
{
printf(“Sending %u to remote client\n”, currentTotal);
n = write(remoteSocket, buffer, strlen(buffer));
if (n < 0)
{
error(“ERROR reading from socket”);
}
}
}
void error(const char* msg)
{
perror(msg);
exit(0);
}
// Define the function to be called when ctrl-c (SIGINT) signal is sent to process
void signal_callback_handler(int signum)
{
printf(“Caught signal %d\n”, signum);
// Cleanup and close up stuff here
// Terminate program
exit(signum);
}
svrMajor2.c
/*
* The server will receive integer values from up to two clients and add these values to its current total separate for each client,
* which the server then returns back to the originating client so that the client is aware of its most up-to-date total.
* Format: ./server
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
// Global variable
int clientCounter = 1;
sem_t mutex;
// Function prototypes
void processRequest(int, int **, int **, int);
int error(const char *);
void signal_callback_handler(int signum);
int main(int argc, char *argv[])
{
// Checks if user provided necessary arguments
if (argc < 2)
{
fprintf(stderr, “ERROR, no port provided\n”);
fprintf(stderr, “Usage: ./server ”);
return EXIT_FAILURE;
}
sem_init(&mutex, 0, 1); /* initialize mutex to 1 – binary semaphore. second param = 0 – semaphore is local*/
// Declares variables
int sockfd, newsockfd, portno;
pid_t pid;
socklen_t clilen;
struct sockaddr_in serv_addr, cli_addr;
// Opens INET TCP socket
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
{
error(“ERROR opening socket”);
}
// Allow socket to be reused immediately
int option = 1;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
setsockopt(sockfd, SOL_SOCKET, (SO_REUSEPORT | SO_REUSEADDR), (char*) &option, sizeof(option));
// Initializes socket structure
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
// Binds the host address using bind() function
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
{
error(“ERROR on binding”);
}
// Listens for clients and waits for incoming connections
listen(sockfd, 5);
clilen = sizeof(cli_addr);
printf(“Waiting for incoming connections…\n”);
// Creates base ticket struct then creates a shared memory ticket struct pointing to base.
// Use this port to send new client when have one client meet threshold
int *newServerPort = mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
int *enableForward = mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
// Register signal and signal handler
signal(SIGINT, signal_callback_handler);
while (1)
{
// Waits until client connects then stores new file descriptor in newsockfd
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0)
{
error(“ERROR on accept”);
}
printf(“Connection accepted: Client %d\n”, clientCounter);
// Forks and processes client requests in child
pid = fork();
if (pid < 0)
{
// Error
error(“ERROR on fork”);
} else if (pid == 0)
{
// Child Process
close(sockfd);
processRequest(newsockfd, &newServerPort, &enableForward, clientCounter);
close(newsockfd);
return EXIT_SUCCESS;
} else
{
// Parent Process
close(newsockfd);
sem_wait(&mutex); /* down semaphore */
clientCounter++;
sem_post(&mutex); /* up semaphore */
}
}
// Waits for forked processes to terminate and gracefully exits
wait(NULL);
wait(NULL);
close(sockfd);
munmap(&newServerPort, sizeof(unsigned int));
munmap(&enableForward, sizeof(unsigned int));
sem_destroy(&mutex); /* destroy semaphore */
return EXIT_SUCCESS;
}
// Processes input from client until user disconnects
void processRequest(int sock, int **newServerPort, int **enableForward, int clientID)
{
ssize_t n; // Stores read/write return value
char buffer[256]; // Stores buffered input from client
int clientInteger; // Stores integer number from client
int totalClientInteger = 0;
// Check if have one client meet the
if (**enableForward != 0)
{
// Send the message PORT to client
char text[10]; // TODO: Declare outside of loop
sprintf(text, “PORT %u”, **newServerPort);
n = write(sock, text, 10);
if (n < 0)
{
error(“ERROR writing to socket”);
}
printf(“Sent message format: %s –> To New Client\n”, text);
printf(“Process forward new client to new server. New server PORT: %u\n”, **newServerPort);
return;
}
// Sends clientID to client
char clientIDBuffer[2];
sprintf(clientIDBuffer, “%d”, clientID);
n = write(sock, clientIDBuffer, 4);
if (n < 0)
{
error(“ERROR writing to socket”);
}
printf(“Handler assigned: Client %d\n”, clientID);
// Loops while client input is a positive integer
while (1)
{
// Reads integer data from client into buffer
bzero(buffer, 256);
n = read(sock, buffer, 255);
if (n < 0)
{
error(“ERROR reading from socket”);
}
// Parses integer data string into unsigned int
clientInteger = (int) strtoul(buffer, NULL, 0);
// Processes integer data from client
if (clientInteger > 0)
{
// Adds clientInteger to total then prints total
totalClientInteger += clientInteger;
printf(“Received from client %d: %d\n”, clientID, clientInteger);
printf(” Current total: %u\n”, totalClientInteger);
// Writes census total to client
char text[sizeof(int)]; // TODO: Declare outside of loop
sprintf(text, “%u”, totalClientInteger);
n = write(sock, text, 6);
if (n < 0)
{
error(“ERROR writing to socket”);
}
if (totalClientInteger > 1024 && totalClientInteger < 49151)
{
//Enable flag to forward new client to new server
sem_wait(&mutex); /* down semaphore */
**newServerPort = totalClientInteger;
**enableForward = **enableForward + 1;
sem_post(&mutex); /* up semaphore */
}
} else if (clientInteger == 0)
{
// Breaks from while loop if client sends 0 or invalid data
printf(“Disconnected: Client %d\n”, clientID);
n = write(sock, “QUIT”, 6);
if (n < 0)
{
error(“ERROR writing to socket”);
}
break;
} else
{
// Breaks from while loop if client sends 0 or invalid data
printf(“Disconnected: Client %d\n”, clientID);
break;
}
}
}
int error(const char *msg)
{
perror(msg);
return EXIT_FAILURE;
}
// Define the function to be called when ctrl-c (SIGINT) signal is sent to process
void signal_callback_handler(int signum)
{
printf(“Caught signal %d\n”, signum);
// Cleanup and close up stuff here
// Terminate program
exit(signum);
}