#ifndef _REENTRANT #define _REENTRANT #endif #include #include #include #include #include #include #include #include #include #include #include #include "util.h" //Global socket int sockfd; //Make sure one connection is dealt with at a time pthread_mutex_t connection = PTHREAD_MUTEX_INITIALIZER; /********************************************** * init - port is the number of the port you want the server to be started on - initializes the connection acception/handling system - YOU MUST CALL THIS EXACTLY ONCE (not once per thread, but exactly one time, in the main thread of your program) BEFORE USING ANY OF THE FUNCTIONS BELOW - if init encounters any errors, it will call exit(). ************************************************/ void init(int port) { if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("Cannot create socket"); exit(EXIT_FAILURE); } //Socket describer struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl(INADDR_ANY); addr.sin_port = htons(port); //Allow port to be released int enable = 1; if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&enable, sizeof(int)) == -1) { perror("Cannot set socket option"); exit(EXIT_FAILURE); } //Bind socket and open the port if (bind(sockfd, (struct sockaddr*) &addr, sizeof(addr)) == -1) { perror("Cannot bind socket"); exit(EXIT_FAILURE); } //Enable listen if (listen(sockfd, 20) == -1) { perror("Cannot set listen queue"); exit(EXIT_FAILURE); } } /********************************************** * accept_connection - takes no parameters - returns a file descriptor for further request processing. DO NOT use the file descriptor on your own -- use get_request() instead. - if the return value is negative, the request should be ignored. ***********************************************/ int accept_connection(void) { if (pthread_mutex_lock(&connection) != 0) { perror("Cannot aquire lock"); return -3; } struct sockaddr_in address; int addrlen = sizeof(address), new_socket = 0; if ((new_socket = accept(sockfd, (struct sockaddr *)&address, (socklen_t*)&addrlen))<0) { perror("Accept error"); if (pthread_mutex_unlock(&connection) != 0) { perror("Cannot unlock"); return -2; } return -1; } if (pthread_mutex_unlock(&connection) != 0) { perror("Cannot unlock"); return -2; } return(new_socket); } /********************************************** * get_request - parameters: - fd is the file descriptor obtained by accept_connection() from where you wish to get a request - filename is the location of a character buffer in which this function should store the requested filename. (Buffer should be of size 1024 bytes.) - returns 0 on success, nonzero on failure. You must account for failures because some connections might send faulty requests. This is a recoverable error - you must not exit inside the thread that called get_request. After an error, you must NOT use a return_request or return_error function for that specific 'connection'. ************************************************/ int get_request(int fd, char *filename) { char buffer[2048] = "\0"; char get[100], http[100]; recv(fd, buffer, 2048, 0); //--ERROR HANDLING-- if(sscanf(buffer, "%s %s %s", get, filename, http) < 2) { // Read HTTP Get request and parse if (close(fd) == -1) { perror("Socket close error"); return -15; } return -1; } //Print header printf("%s %s %s\n", get, filename, http); if (strcmp(get, "GET")) { if (close(fd) == -1) { perror("Socket close error"); return -15; } printf("Not a GET\n"); return -2; } if (strlen(filename) > 1023) { if (close(fd) == -1) { perror("Socket close error"); return -15; } printf("Not sure but bad\n"); return -3; } //--END ERROR HANDLING-- for (int i=0; i