Skip to content

Instantly share code, notes, and snippets.

@avegancafe
Created August 31, 2021 03:42
Show Gist options
  • Select an option

  • Save avegancafe/45b3e9481f4c12a574e88cd24d06fc03 to your computer and use it in GitHub Desktop.

Select an option

Save avegancafe/45b3e9481f4c12a574e88cd24d06fc03 to your computer and use it in GitHub Desktop.
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netdb.h>
#include<signal.h>
#include<fcntl.h>
#define CONNMAX 1000
#define BYTES 1024
char *ROOT;
int listenfd, clients[CONNMAX];
void error (char *);
void startServer (char *);
void respond (int);
int main (int argc, char* argv[]) {
struct sockaddr_in clientaddr;
socklen_t addrlen;
char c;
//Default Values PATH = current directory and PORT=5953
char PORT[6];
ROOT = getenv("PWD");
strcpy (PORT,"5953"); // Kyle
int slot = 0;
//Parsing the command line arguments
while ( (c = getopt (argc, argv, "p:r:")) != -1 ) {
switch (c) {
case 'r':
ROOT = malloc (strlen(optarg));
strcpy (ROOT,optarg);
break;
case 'p':
strcpy (PORT,optarg);
break;
case '?':
fprintf (stderr,"Wrong arguments given!!!\n");
exit (1);
default:
exit (1);
}
}
printf ("Server started at port no. %s%s%s with root directory as %s%s%s\n","\033[92m",PORT,"\033[0m","\033[92m",ROOT,"\033[0m");
// Setting all elements to -1: signifies there is no client connected
int i;
for (i = 0; i < CONNMAX; i++) {
clients[i] = -1;
}
startServer (PORT);
// ACCEPT connections
while (1) {
addrlen = sizeof (clientaddr);
clients[slot] = accept (listenfd, (struct sockaddr *) &clientaddr, &addrlen);
if (clients[slot] < 0) {
error ("accept() error");
} else {
if (fork() == 0) {
respond (slot);
exit(0);
}
}
while (clients[slot] != -1) {
slot = (slot + 1) % CONNMAX;
}
}
return 0;
}
//start server
void startServer (char *port) {
struct addrinfo hints, *res, *p;
// getaddrinfo for host
memset (&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
if ( getaddrinfo( NULL, port, &hints, &res) != 0 ) {
perror ("getaddrinfo() error");
exit (1);
}
// socket and bind
for (p = res; p!=NULL; p=p->ai_next) {
listenfd = socket (p->ai_family, p->ai_socktype, 0);
if (listenfd == -1) {
continue;
}
if ( bind(listenfd, p->ai_addr, p->ai_addrlen) == 0 ) {
break;
}
}
if (p == NULL ) {
perror ("socket() or bind()");
exit (1);
}
freeaddrinfo (res);
// listen for incoming connections
if ( listen (listenfd, 1000000) != 0 ) {
perror ("listen() error");
exit (1);
}
}
const char *get_filename_ext(const char *filename) {
const char *dot = strrchr (filename, '.');
if ( !dot || dot == filename ) {
return "";
}
return dot + 1;
}
//client connection
void respond(int n) {
char mesg[99999], *reqline[3], data_to_send[BYTES], path[99999];
int rcvd, fd, bytes_read, stat_status;
struct stat statbuf;
int flag = 0;
memset ( (void*)mesg, (int)'\0', 99999 );
rcvd = recv (clients[n], mesg, 99999, 0);
if (rcvd < 0) { // receive error
fprintf(stderr,("recv() error\n"));
} else if (rcvd == 0) { // receive socket closed
fprintf(stderr,"Client disconnected upexpectedly.\n");
} else { // message received
reqline[0] = strtok (mesg, " \t\n");
if ( strncmp(reqline[0], "GET\0", 4) == 0 ) {
reqline[1] = strtok (NULL, " \t");
reqline[2] = strtok (NULL, " \t\n");
if ( strncmp( reqline[2], "HTTP/1.0", 8) != 0 && strncmp ( reqline[2], "HTTP/1.1", 8) != 0 ) {
write(clients[n], "HTTP/1.0 400 Bad Request\n", 25);
} else {
printf ("Requesting: %s\n", reqline[1]);
strcpy (path, ROOT);
strcpy (&path[strlen(ROOT)], reqline[1]);
// Stat dat file
stat_status = lstat (path, &statbuf);
int inPipe[2];
int outPipe[2];
char* filename = strtok (reqline[1], "?");
if ( strcmp(filename, "/new_histogram") == 0 ) { // endpoint for making a new histogram
send (clients[n], "HTTP/1.0 200 OK", 15, 0);
char* lsArgs[4];
int pid;
int status;
const char* ext = get_filename_ext (path);
printf ("Histogram requested\n");
pipe (inPipe);
pipe (outPipe);
char cmd[9999] = "/usr/local/bin/perl my_histogram.pl ";
char* query = strtok (NULL, "&");
while (query != NULL) {
strcpy (&cmd[strlen(cmd)], query);
strcpy (&cmd[strlen(cmd)], " ");
query = strtok (NULL, "&");
}
pid = fork();
if (pid == 0) {
dup2 (inPipe[0], fileno(stdin));
dup2 (outPipe[1], fileno(stdout));
send (clients[n], "\n", 1, 0);
system (cmd);
return;
}
waitpid (pid, &status, 0);
flag = 1;
} else if (stat_status != -1) { // this is a file that exists
send (clients[n], "HTTP/1.0 200 OK", 15, 0);
printf ("HTTP/1.0 200 OK\n");
char* lsArgs[4];
int pid;
int status;
const char* ext = get_filename_ext(path);
switch (statbuf.st_mode & S_IFMT) { // check if directory or file
case S_IFDIR: // directory
write (clients[n], "\n", 1);
pipe (inPipe);
pipe (outPipe);
pid = fork();
if (pid == 0) {
dup2 (inPipe[0], fileno(stdin));
dup2 (outPipe[1], fileno(stdout));
lsArgs[0] = "ls";
lsArgs[1] = "-l";
lsArgs[2] = path;
lsArgs[3] = NULL;
execvp (lsArgs[0], lsArgs);
}
waitpid (pid, &status, 0);
flag = 1;
break;
case S_IFREG: // regular file
if (statbuf.st_mode & 0111) { // Execute script and send back response
pipe (inPipe);
pipe (outPipe);
pid = fork();
if (pid == 0) {
dup2 (inPipe[0], fileno(stdin));
dup2 (outPipe[1], fileno(stdout));
system (path);
return;
}
waitpid (pid, &status, 0);
flag = 1;
} else { // Send back the file
write (clients[n], "\n", 1);
fd = open (path, O_RDONLY);
}
break;
}
} else { // file is not found
send (clients[n], "HTTP/1.0 404 Not Found\nContent-Type: text/html\n\n", 48, 0);
printf ("HTTP/1.0 404 Not Found\n");
char* errFile;
strcpy ( errFile, ROOT );
strcpy ( &errFile[strlen(ROOT)], "/404.html" );
fd = open (errFile, O_RDONLY);
} // endif
if (flag) {
fd = outPipe[0];
}
close (inPipe[0]);
close (outPipe[1]);
write (clients[n], "\n", 1);
while ( (bytes_read=read(fd, data_to_send, BYTES)) > 0 ) {
write (clients[n], data_to_send, bytes_read);
}
}
}
} // endif
//Closing SOCKET
shutdown (clients[n], SHUT_RDWR); //All further send and recieve operations are DISABLED...
close (clients[n]);
clients[n]=-1;
} // endof [respond]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment