Created
August 31, 2021 03:42
-
-
Save avegancafe/45b3e9481f4c12a574e88cd24d06fc03 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #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