diff --git a/server.c b/server.c index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..bb186091c380a4e59c2479a297f24c53de574cfa 100644 --- a/server.c +++ b/server.c @@ -0,0 +1,320 @@ +/* Hanbin Li 789786 +login id: hanbinl1 +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include <string.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <sys/wait.h> +#include <signal.h> +#include <pthread.h> + + +#define BACKLOG 10 // how many pending connections queue will hold +#define MAXDATASIZE 1000 + +//Global variables used only for setiing the command line root from the user. +char demoRpath[100]; +char *rootPath; + + + +//********************************************************************* +//---------------------------read request line Method------------------ +#if 1 +// Function to read each line of the GET reuqest +int http_readline(int sock, char *buf, int maxlen) +{ + int n = 0; + char *p = buf; + while (n < maxlen - 1) { + char c; + int rc = read(sock, &c, 1);// Reading from a socket and copying it to a integer + + if (rc == 1) { + /* Stop at \n and strip away \r and \n. */ + if (c == '\n') { + *p = 0; /* null-terminated */ + return n; + } else if (c != '\r') { + *p++ = c; + n++; + } + + } else if (rc == 0) { + return -1; + /* EOF */ + } else if (errno == EINTR) { + continue; + /* retry */ + } else { + return -1; + /* error */ + } + } + return -1; /* buffer too small */ +} +#endif +/*=========================== Readline- End ===========================*/ + + + + +//********************************************************************* +//---------------------------httpRequest Method------------------------ +void* httpRequest(void* data) +{ + int th,r,b=0,fileOK=0; + char *req,tmp_var[50],doc_root[100],demoRpath[100]; + char buf[MAXDATASIZE], *filePath,*ftype,*type; + + char statusLine[100]="HTTP/1.0"; + char contentTypeLine[100]="Content-type: "; + char entityBody[100]="<html>"; + FILE *fp; + + /* + + variable description + ------------------------------------------------------------------- + int r -----> Used to save the readline return value. + int b -----> Used in iteration in while loop. + char *req -----> Used to save the returned buffer line. + char tmp_var[] -----> Used to check empty space and empty space. + char doc_root -----> Used to save the root location taken from the user. + char demoRpath[] -----> Used to commandline arugument passed for root address + char buf[] -----> Used to save the GET request from client. + char *filePath -----> Used to save the file path requested in root folder. + char *ftype -----> Used to save the file file. + char *type -----> Used to return MIME type. + + */ + + + th=*((int *)data); + int a=0; + + r=http_readline(th,buf,sizeof(buf));// + + if(r>0) { + req=buf; + } else { + perror("[ERROR:] Failed to read.\n"); + exit(1); + } + + // Condition runs till it encounters an empty space + while(req[b]!=' ') { + tmp_var[b]=req[b++]; + } + + //copying the command line entered root location to rootPath to make it rootlocation + strcpy(demoRpath,rootPath); + + if((strcmp(tmp_var,"GET"))==0)// Comparing the temporary array to check the string + { + strcpy(doc_root,demoRpath); + fprintf(stderr,"\nDocument Root\n\n\t"); + puts(doc_root); + + + // Extract the file name + char *filePath, *fl1, *fl2; + fl1 = strpbrk(req,"/"); + fl2 = strtok(fl1," "); + filePath = strpbrk(fl2, "/"); + + + + /* + tmp_ptr1=strpbrk(req,"/"); // Breaks the line and processes the string which has "/". + tmp_ptr2=strtok(tmp_ptr1," "); // Removes blankspces if any + filePath=strpbrk(tmp_ptr2,"/");// Copying the file loaction that the client want to access and break at / and copy after that + strcpy(tmp_ptr3,tmp_ptr2);//coping tmp_ptr2 value to tmp_ptr3 + */ + // When GET request sends "/" we map to "/index.html" + if (strcmp(filePath,"/")==0){ + strcpy(filePath,strcat(doc_root,"/index.html")); + } else { + strcpy(filePath, strcat(doc_root,filePath)); + printf("\nRequest File path\n\n\t"); + puts(filePath); + + } + + + //Open the requested file. + + fp=fopen(filePath,"r"); + + printf("\nRequested File status\n\n\t"); + + if(fp!=NULL){ + fileOK=1; + printf("Requested file exist in the server.\n"); + } else { + printf("Requested file does exist in the server.\n"); + } + + + + if (fileOK==1) { + //fclose (fp); + int z ='.'; + + ftype=strrchr(filePath,z); + printf("\nRequested file is of type:\t"); + puts(ftype); + + // MIME recognition + if((strcmp(ftype,".html"))==0){ + type="text/html"; + } else if (strcmp(ftype, ".jpg") == 0) { + type= "image/jpeg"; + } else if (strcmp(ftype, ".css") == 0) { + type = "text/css"; + } else if (strcmp(ftype, ".js") == 0) { + type = "text/js"; + } else { + type= "application/octet-stream"; + } + + + + //send status line and the content type line + strcpy(statusLine,strcat(statusLine,"200 OK")); + strcpy(statusLine,strcat(statusLine,"\r\n")); + strcpy(contentTypeLine,strcat(contentTypeLine,type)); + strcpy(contentTypeLine,strcat(contentTypeLine,"\r\n")); + } else { + strcpy(statusLine,strcat(statusLine,"404 Not Found")); + strcpy(statusLine,strcat(statusLine,"\r\n")); + //send a blank line to indicate the end of the header lines + strcpy(contentTypeLine,strcat(contentTypeLine,"NONE")); + strcpy(contentTypeLine,strcat(contentTypeLine,"\r\n")); + //send the entity body + strcpy(entityBody,strcat(entityBody,"<HEAD><TITLE>404 Not Found</TITLE></HEAD>")); + strcpy(entityBody,strcat(entityBody,"<BODY>Not Found</BODY></html>")); + strcpy(entityBody,strcat(entityBody,"\r\n")); + } + + //send the header. + if ((send(th, statusLine, strlen(statusLine), 0) == -1) || + (send(th, statusLine, strlen(statusLine),0) == -1) || + (send(th,"\r\n", strlen("\r\n"), 0) == -1)) { + + perror("Failed to send bytes to client"); + } + + if (fileOK) { + wchar_t read_char[1]; + while((read_char[0]=fgetc(fp))!=EOF) { + if(send(th,read_char,sizeof(char),0) == -1){ + perror("Failed to send bytes to client"); + } + } + } else { + if (send(th, entityBody, 100, 0) == -1){ + perror("Failed to send bytes to client"); + } + } + + close(th); // Close the connection. + pthread_exit(NULL); //Existing from the threads. + + } else { + printf("Warning message\n"); + } + +} + + + + + + + +//**************************************************************************************************************** +//Main Method------------------------------------------------------------------ +int main (int argc, char **argv) +{ + int sockfd, new_fd, portno; // listen on sock_fd, new connection on new_fd + struct sockaddr_in serv_addr, cli_addr; + socklen_t clilen; + pthread_t p_thread[3000]; + pthread_attr_t attr_t;// Attritube to thread + pthread_attr_init(&attr_t);// Initilizing the attribute + pthread_attr_setdetachstate(&attr_t, PTHREAD_CREATE_DETACHED); //Creating the tread in detach state + + int thr_id,i=0; + + + // check command line + if (argc != 3) + { + fprintf(stderr,"ERROR, usage: server [port number] [path]\n"); + exit(1); + } + + + //Create the parent socket. + sockfd = socket(AF_INET, SOCK_STREAM, 0); + + if (sockfd < 0) + { + perror("ERROR opening socket"); + exit(1); + } + + bzero((char *) &serv_addr, sizeof(serv_addr)); + portno = atoi(argv[1]); + rootPath = argv[2]; + + //Build the server's Inernet address. + // bzero((char *) &serv_addr, sizeof(serv_addr)); + serv_addr.sin_family = AF_INET; // host byte order + serv_addr.sin_port = htons(portno); // short, network byte order + serv_addr.sin_addr.s_addr = INADDR_ANY; // automatically fill with my IP + + + + // Bind address to the socket */ + if (bind(sockfd, (struct sockaddr *) &serv_addr, + sizeof(serv_addr)) < 0) + { + perror("ERROR on binding"); + exit(1); + } + + //Make this socket ready to accept connection requests. + if (listen(sockfd, BACKLOG) == -1) { + perror("listen"); + exit(1); + } + + + clilen = sizeof(cli_addr); + + while(1) + { // main accept() loop + new_fd = accept( sockfd, (struct sockaddr *) &cli_addr, &clilen); + if (new_fd < 0) + { + perror("ERROR on accept"); + exit(1); + } + + //Creates threads. + thr_id = pthread_create(&p_thread[i++],&attr_t,httpRequest,(void*)&new_fd); + pthread_attr_destroy(&attr_t); + } + + + return 0; +}