Code:
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/epoll.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <netdb.h>
#include <strings.h>
#include <string.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <signal.h>
#define TRUE 1
#define FALSE 0
#define EPOLL_QUEUE_LEN 10
#define BUFLEN 1024
#define SERVER_PORT 7000
//Globals
int fd_server;
struct clientStuff
{
int sockfd;
struct sockaddr_in client;
};
// Function prototypes
static void SystemFatal (const char* message);
static void* ClearSocket (void* arg);
void close_fd (int);
int main (int argc, char* argv[])
{
int i, arg, visits;
int num_fds, fd_new, epoll_fd;
static struct epoll_event events[EPOLL_QUEUE_LEN], event;
int port = SERVER_PORT;
struct sockaddr_in addr, remote_addr;
socklen_t addr_size = sizeof(struct sockaddr_in);
struct sigaction act;
FILE *fp;
visits = 0;
// set up the signal handler to close the server socket when CTRL-c is received
act.sa_handler = close_fd;
act.sa_flags = 0;
if ((sigemptyset (&act.sa_mask) == -1 || sigaction (SIGINT, &act, NULL) == -1))
{
perror ("Failed to set SIGINT handler");
exit (EXIT_FAILURE);
}
// Create the listening socket
fd_server = socket (AF_INET, SOCK_STREAM, 0);
if (fd_server == -1)
SystemFatal("socket");
// set SO_REUSEADDR so port can be resused imemediately after exit, i.e., after CTRL-c
arg = 1;
if (setsockopt (fd_server, SOL_SOCKET, SO_REUSEADDR, &arg, sizeof(arg)) == -1)
SystemFatal("setsockopt");
// Make the server listening socket non-blocking
if (fcntl (fd_server, F_SETFL, O_NONBLOCK | fcntl (fd_server, F_GETFL, 0)) == -1)
SystemFatal("fcntl");
// Bind to the specified listening port
memset (&addr, 0, sizeof (struct sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(port);
if (bind (fd_server, (struct sockaddr*) &addr, sizeof(addr)) == -1)
SystemFatal("bind");
// Listen for fd_news; SOMAXCONN is 128 by default
if (listen (fd_server, SOMAXCONN) == -1)
SystemFatal("listen");
// Create the epoll file descriptor
epoll_fd = epoll_create(EPOLL_QUEUE_LEN);
if (epoll_fd == -1)
SystemFatal("epoll_create");
// Add the server socket to the epoll event loop
event.events = EPOLLIN | EPOLLERR | EPOLLHUP | EPOLLET;
event.data.fd = fd_server;
if (epoll_ctl (epoll_fd, EPOLL_CTL_ADD, fd_server, &event) == -1)
SystemFatal("epoll_ctl");
// Execute the epoll event loop
while (TRUE)
{
// signal( SIGABRT, function);
//struct epoll_event events[256];
num_fds = epoll_wait (epoll_fd, events, EPOLL_QUEUE_LEN, -1);
if (num_fds < 0)
SystemFatal ("Error in epoll_wait!");
for (i = 0; i < num_fds; i++)
{
// Case 1: Error condition
if (events[i].events & (EPOLLHUP | EPOLLERR))
{
fputs("epoll: EPOLLERR", stderr);
close(events[i].data.fd);
continue;
}
assert (events[i].events & EPOLLIN);
// Case 2: Server is receiving a connection request
if (events[i].data.fd == fd_server)
{
struct clientStuff c1;
fd_new = accept (fd_server, (struct sockaddr*) &remote_addr, &addr_size);
printf(">> Initializing remote address: %s\n", inet_ntoa(remote_addr.sin_addr));
visits++;
fp=fopen("server-output.txt", "a"); /* Open file */
fprintf(fp, "Connections-to-date,%u\n",visits);
fprintf(fp, "%s,connect\n",inet_ntoa(remote_addr.sin_addr));
fclose(fp);
printf("Connections to date: %u \n",visits);
c1.sockfd = fd_new;
printf("sockfd: %u\n",c1.sockfd);
c1.client = remote_addr;
if (fd_new == -1)
{
if (errno != EAGAIN && errno != EWOULDBLOCK)
{
perror("accept");
}
continue;
}
// Make the fd_new non-blocking
if (fcntl (fd_new, F_SETFL, O_NONBLOCK | fcntl(fd_new, F_GETFL, 0)) == -1)
SystemFatal("fcntl");
// Add the new socket descriptor to the epoll loop
event.data.fd = fd_new;
if (epoll_ctl (epoll_fd, EPOLL_CTL_ADD, fd_new, &event) == -1)
SystemFatal ("epoll_ctl");
continue;
}
// Case 3: One of the sockets has read data
if (!ClearSocket(events[i].data.fd))
{
// epoll will remove the fd from its set
// automatically when the fd is closed
close (events[i].data.fd);
}
}
}
close(fd_server);
exit (EXIT_SUCCESS);
}
static void* ClearSocket (void* arg)
{
struct clientStuff *ptr;
struct sockaddr_in client_addr;
int bytes_to_read, sockfd;
char *bp, buf[BUFLEN];
ssize_t n;
FILE *fp;
//ptr = (struct clientStuff *)arg;
sockfd = (int) arg;
//printf("sockfd: %u",ptr->sockfd);
// client_addr = ptr->client;
bp = buf;
bytes_to_read = BUFLEN -1;
while(1) {
n = read(sockfd, bp, bytes_to_read);
bp += n;
bytes_to_read -= n;
if (bytes_to_read <= 0)
{
/* File I/O Preparations */
fp=fopen("server-output.txt", "a");
fprintf(fp,"%s,Recv,%s\n",inet_ntoa(client_addr.sin_addr), buf);
printf("%s,Recv,%s\n", inet_ntoa(client_addr.sin_addr), buf);
}
if((write(sockfd, "DATA-ACK", strlen("DATA-ACK"))) == -1) {
fprintf(fp, "%s,Disconnect\n",inet_ntoa(client_addr.sin_addr));
fclose(fp);
printf("Error on read\n");
close(sockfd);
return 1;
}
fprintf(fp, "%s,Sent,DATA-ACK\n",inet_ntoa(client_addr.sin_addr));
fclose(fp);
sleep(9);
}
return 1;
}
// Prints the error stored in errno and aborts the program.
static void SystemFatal(const char* message)
{
perror (message);
exit (EXIT_FAILURE);
}
// close fd
void close_fd (int signo)
{
close(fd_server);
exit (EXIT_SUCCESS);
}