int dettach_childs_queue(struct childs_queue *q){ ci_proc_mutex_lock(&(q->queue_mtx)); //Not really needed ......... if(ci_shared_mem_detach(&(q->shmid),q->childs)==0 ){ log_server(NULL,"can't dettach shared memory!"); return 0; } q->childs=NULL; ci_proc_mutex_unlock(&(q->queue_mtx)); return 1; }
int create_childs_queue(struct childs_queue *q, int size){ int ret,i; if((q->childs=ci_shared_mem_create(&(q->shmid),sizeof(child_shared_data_t)*size))==NULL){ log_server(NULL,"can't get shared memory!"); return 0; } q->size=size; for(i=0;i<q->size;i++){ q->childs[i].pid=0; } if((ret=ci_proc_mutex_init(&(q->queue_mtx)))==0){ log_server(NULL,"can't create childs queue semaphore!"); return 0; } return 1; }
int attach_childs_queue(struct childs_queue *q){ child_shared_data_t *c; ci_proc_mutex_lock(&(q->queue_mtx)); //Not really needed ......... if((c=(child_shared_data_t *)ci_shared_mem_attach(&(q->shmid)))==NULL){ log_server(NULL,"can't attach shared memory!"); return 0; } q->childs=c; ci_proc_mutex_unlock(&(q->queue_mtx)); return 1; }
void signal_handler(int signum) { //Verify signal received if (signum == SIGINT) { printf("%s\n", "Server site shutdown in emergency by admin\n"); sprintf(log_c, "Server site shutdown in emergency by admin.\n"); log_server(log_c); //This effectively kill main server processus exit(0); } if(signum==SIGUSR1) { printf("%s\n", "Signal SIGUSR1 is detected, all all connection information will be displayed: \n"); displaylog(); printf("%s\n", "Log END..... \n"); } }
static void sigpipe_handler(int sig){ debug_printf(1,"SIGPIPE signal received.\n"); log_server(NULL,"%s","SIGPIPE signal received.\n"); }
int start_server() { #ifdef MULTICHILD int child_indx, i; HANDLE child_handle; ci_thread_t mon_thread; int childs, freeservers, used, maxrequests; ci_proc_mutex_init(&accept_mutex); ci_thread_mutex_init(&control_process_mtx); if (!create_childs_queue(&childs_queue, MAX_CHILDS)) { log_server(NULL, "Can't init shared memory.Fatal error, exiting!\n"); ci_debug_printf(1, "Can't init shared memory.Fatal error, exiting!\n"); exit(0); } for (i = 0; i < START_CHILDS + 2; i++) { child_handle = start_child(LISTEN_SOCKET); } /*Start died childs monitor thread*/ /* ci_thread_create(&mon_thread, (void *(*)(void *))wait_achild_to_die, (void *)NULL); */ while (1) { if (check_for_died_child(5000)) continue; // Sleep(5000); childs_queue_stats(&childs_queue, &childs, &freeservers, &used, &maxrequests); ci_debug_printf(1, "Server stats: \n\t Childs:%d\n\t Free servers:%d\n\tUsed servers:%d\n\tRequests served:%d\n", childs, freeservers, used, maxrequests); if ((freeservers <= MIN_FREE_SERVERS && childs < MAX_CHILDS) || childs < START_CHILDS) { ci_debug_printf(1, "Going to start a child .....\n"); child_handle = start_child(LISTEN_SOCKET); } else if (freeservers >= MAX_FREE_SERVERS && childs > START_CHILDS) { ci_thread_mutex_lock(&control_process_mtx); if ((child_indx = find_an_idle_child(&childs_queue)) < 0) continue; childs_queue.childs[child_indx].to_be_killed = GRACEFULLY; tell_child_to_die(childs_queue.childs[child_indx].pipe); ci_thread_mutex_unlock(&control_process_mtx); ci_debug_printf(1, "Going to stop child %d .....\n", childs_queue.childs[child_indx].pid); } } /* for(i=0;i<START_CHILDS;i++){ pid=wait(&status); ci_debug_printf(1,"The child %d died with status %d\n",pid,status); } */ #else child_data = (child_shared_data_t *) malloc(sizeof(child_shared_data_t)); child_data->pid = 0; child_data->freeservers = START_SERVERS; child_data->usedservers = 0; child_data->requests = 0; child_data->connections = 0; child_data->to_be_killed = 0; child_data->idle = 1; child_main(LISTEN_SOCKET); #endif return 1; }
int main(int argc, char* argv[]) { // Variable declarations int i, port, sd_current, addrlen, handlingMethod, fifo, setval, max_fd; struct sockaddr_in sin, pin; configuration config; char error[1024]; pthread_t handler; pthread_attr_t att; pid_t pid; fd_set rfds; // Set execution to true execute = true; // Clear file creation mask. umask(0); // Set default handling method to thread handlingMethod = _THREAD; // Get size of pin .. addrlen = sizeof(pin); // Signal handlers signal(SIGPIPE, SIG_IGN); signal(SIGINT, sig_handle_int); signal(SIGABRT, sig_handle_int); // Set default config setDefaultConfig(&config); // Set root dir to current running directory path_init(&config); rootDir(argv[0]); // Parse config file if (parseConfig(&config) == -1) { exit(-1); } // Check arguments if(argc > 1) { for(i = 1; i < argc; i++) { switch(argv[i][1]) { // Help case 'h': printHelp(); return 3; break; // Port case 'p': i++; if(i >= argc) { printHelp(); return 3; } if(argv[i][0] != '-') { if((port = atoi(argv[i])) != 0 && port < 65536) { config.listenPort = port; printf("Port number: %d\n", port); } else { printHelp(); return 3; } } else { printHelp(); return 3; } break; // Deamonize case 'd': // Start daemon if set printf("Starting daemon...\n"); daemonfunc(); break; // Log file case 'l': i++; if(i >= argc) { printHelp(); return 3; } if(argv[i][0] != '-') { strncpy(config.accLogPath, argv[i], sizeof(config.accLogPath)); } else { printHelp(); return 3; } break; // Mode of operation case 's': i++; if(i >= argc) { printHelp(); return 3; } if(strncmp(argv[i], "thread", 6) == 0) handlingMethod = _THREAD; else if(strncmp(argv[i], "fork", 4) == 0) handlingMethod = _FORK; else { printHelp(); return 3; } break; case 'c': i++; if(i >= argc) { printHelp(); return 3; } if(argv[i][0] != '-') { strncpy(config.configPath, argv[i], sizeof(config.configPath)); } else { printHelp(); return 3; } break; } } } // Init logfunctions if (log_init(&config) == -1) { exit(-1); } // Create fifo if prefork is set if (handlingMethod == _FORK) { // Create the named fifo pipe mkfifo(config.fifoPath, 0666); // Try opening the pipe if((fifo = open(config.fifoPath, O_RDWR)) == -1) { sprintf(error, "Unable to open FIFO-pipe, %s", strerror(errno)); log_server(LOG_CRIT, error); execute = false; // Terminate } } // Check super user if (getuid() != 0) { perror("You have to be root to run this program"); exit(-1); } // Set root directory to document root chdir(config.basedir); if (chroot(config.basedir) == -1) { sprintf(error, "Unable to change root directory, %s", strerror(errno)); log_server(LOG_ERR, error); execute = false; // Terminate } // Drop root privileges if (setgid(getgid()) == -1) { sprintf(error, "Unable to change user, %s", strerror(errno)); log_server(LOG_ERR, error); execute = false; // Terminate } if (setuid(getuid()) == -1) { sprintf(error, "Unable to change user, %s", strerror(errno)); log_server(LOG_ERR, error); execute = false; // Terminate } // Create listening socket // Domain -> AF_INET = IPV4 // Type -> SOCK_STREAM = TCP if((sd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { sprintf(error, "Unable to open socket, %s", strerror(errno)); log_server(LOG_ERR, error); execute = false; // Terminate } // Zeroize sin memset(&sin, 0, sizeof(sin)); // Set domain sin.sin_family = AF_INET; // Set any in address sin.sin_addr.s_addr = INADDR_ANY; // Set port, hton converts byteorder sin.sin_port = htons(config.listenPort); // Try binding the socket if(bind(sd, (struct sockaddr*) &sin, sizeof(sin)) == -1) { sprintf(error, "Unable to bind socket, %s", strerror(errno)); log_server(LOG_ERR, error); execute = false; // Terminate } // Start to listen for requests if(listen(sd, config.backlog) == -1) { sprintf(error, "Too loud unable to listen, %s", strerror(errno)); log_server(LOG_ERR, error); execute = false; // Terminate } // Init thread lock pthread_mutex_init(&thread_lock, NULL); // If handling method is set to thread if(handlingMethod == _THREAD) { // Init thread attr pthread_attr_init(&att); // Set threads to detached state pthread_attr_setdetachstate(&att, PTHREAD_CREATE_DETACHED); // Set system scope pthread_attr_setscope(&att, PTHREAD_SCOPE_SYSTEM); // Set RoundRobin scheduling pthread_attr_setschedpolicy(&att, SCHED_RR); // Not supported in LINUX pthreads // Start accepting requests while(execute) { // Accept a request from queue, blocking if ((sd_current = accept(sd, (struct sockaddr*) &pin, (socklen_t*) &addrlen)) == -1) { if (execute) { sprintf(error, "Unable to accept request, %s", strerror(errno)); log_server(LOG_ERR, error); } close(sd_current); execute = false; // Terminate } else { // Shit happens, if server is out of memory just skip the request _rqhd_args *args = malloc(sizeof(_rqhd_args)); if (args == NULL) { sprintf(error, "Unable to allocate memory, %s", strerror(errno)); log_server(LOG_CRIT, error); close(sd_current); } else { // Set arguments args->sd = sd_current; args->pin = pin; args->config = &config; } // Create thread if(pthread_create(&handler, &att, requestHandle, args) != 0) { sprintf(error, "Unable to start thread, %s", strerror(errno)); log_server(LOG_CRIT, error); close(sd_current); execute = false; // Terminate } } } // Destroy attributes pthread_attr_destroy(&att); } // Else if handling method is set to fork else if(handlingMethod == _FORK) { max_fd = sd; if (fifo > sd) max_fd = fifo; // Start accepting requests while(execute) { FD_ZERO(&rfds); FD_SET(sd, &rfds); FD_SET(fifo, &rfds); // Accept request or handle child setval = select(max_fd + 1, &rfds, NULL, NULL, NULL); if (FD_ISSET(sd, &rfds)) { // Accept a request from queue if ((sd_current = accept(sd, (struct sockaddr*) &pin, (socklen_t*) &addrlen)) == -1) { if (execute) { sprintf(error, "Unable to accept request, %s", strerror(errno)); log_server(LOG_ERR, error); } close(sd_current); execute = false; // Terminate } else { // Fork if((pid = fork()) == 0) { // CHILD ---------------------------------------------------- // Shit happens, if server is out of memory just skip the request _rqhd_args *args = malloc(sizeof(_rqhd_args)); if (args == NULL) { sprintf(error, "Unable to allocate memory, %s", strerror(errno)); log_server(LOG_CRIT, error); close(sd_current); } else { // Set arguments args->sd = sd_current; args->pin = pin; args->config = &config; // Call request handler requestHandle(args); } // Tell parent I'm done pid_t id = getpid(); if (write(fifo, &id, sizeof(pid_t)) == -1) { sprintf(error, "Unable to send pid, %s", strerror(errno)); log_server(LOG_ERR, error); } // Done execute = false; } else if(pid > 0) { // PARENT --------------------------------------------------- // Parent don't handle dirty work close(sd_current); } else { sprintf(error, "Unable to fork, %s", strerror(errno)); log_server(LOG_CRIT, error); close(sd_current); execute = false; // Terminate } } } else if (FD_ISSET(fifo, &rfds)) { // Get child pid from fifo and wait for it pid_t child; if (read(fifo, &child, sizeof(pid_t)) == -1) { sprintf(error, "Unable to read pid, %s", strerror(errno)); log_server(LOG_ERR, error); } waitpid(child, NULL, 0); } else if (setval == -1){ // Error sprintf(error, "Select failed or was interrupted, %s", strerror(errno)); log_server(LOG_ERR, error); execute = false; // Terminate } } // Close fifo close(fifo); } // Else not a valid handling method else { sprintf(error, "Invalid handling method is set"); log_server(LOG_ERR, error); } // Clean up pthread_mutex_destroy(&thread_lock); close(sd); log_destroy(); if (pid != 0) printf("Cleanup complete, no one will know I was here.\n"); return 0; }
/* Send Header (Private) * * Sends a header with the information from the rqhd header struct * * @sd int, socket id * @rqhd struct, see header file for information * @return int, -1 if error */ int sendHeader(int sd, const _rqhd_header *head) { char buffert[4096]; char tmp[256]; char date[64]; time_t t = time(NULL); memset(tmp, '\0', sizeof(tmp)); memset(date, '\0', sizeof(date)); memset(buffert, '\0', sizeof(buffert)); // Header start // Status if (head->protocol != NULL && head->status != NULL){ // Build string snprintf(tmp, sizeof(tmp), "%s %s\r\n", head->protocol, head->status); strcat(buffert, tmp); } else { log_server(LOG_INFO, "Status header was not sent! Was this intentional?"); } // Server if (head->server != NULL) { // Build string snprintf(tmp, sizeof(tmp), "Server: %s\r\n", head->server); strcat(buffert, tmp); } else { log_server(LOG_INFO, "Server header was not sent! Was this intentional?"); } // Content-Length if (head->size != 0) { // Build string snprintf(tmp, sizeof(tmp), "Content-Length: %d\r\n", head->size); strcat(buffert, tmp); } else { log_server(LOG_INFO, "Content-Length header was not sent! Was this intentional?"); } // Content-Type if (head->type != NULL) { // Build string snprintf(tmp, sizeof(tmp), "Content-Type: %s\r\n", head->type); strcat(buffert, tmp); } else { log_server(LOG_INFO, "Content-Type header was not sent! Was this intentional?"); } // Cache-Control if (head->cache != NULL) { // Build string snprintf(tmp, sizeof(tmp), "Cache-Control: %s\r\n", head->cache); strcat(buffert, tmp); } else { log_server(LOG_INFO, "Cache-Control header was not sent! Was this intentional?"); } // Last-Modified if (head->cache != NULL) { // Build string snprintf(tmp, sizeof(tmp), "Last-Modified: %s\r\n", head->modified); strcat(buffert, tmp); } else { log_server(LOG_INFO, "Last-Modified header was not sent! Was this intentional?"); } // Date // Get date strftime(date, sizeof(date), "%a, %d %b %Y %T %z", localtime(&t)); // Build string snprintf(tmp, sizeof(tmp), "Date: %s\r\n", date); strcat(buffert, tmp); // End of header strcat(buffert, "\r\n"); if(sendLine(sd, buffert) == -1) return -1; return 0; }
void *requestHandle(void *context) { // Get the arguments char buffert[PATH_MAX] = {0}, reqBuf[BUF_REQ] = {0}, date[64] = {0}, error[1024] = {0}, *req_line = NULL, *req_token = NULL; _rqhd_header head; _rqhd_req req; _rqhd_args *args = (_rqhd_args*) context; struct sockaddr_in pin = args->pin; struct stat stat_buf = {0}; int sd = args->sd; FILE *reqFile = NULL; // Init variables head.protocol[0] = '\0'; head.status[0] = '\0'; head.server[0] = '\0'; head.type[0] = '\0'; head.cache[0] = '\0'; head.modified[0] = '\0'; head.size = 0; req.method[0] = '\0'; req.uri[0] = '\0'; req.protocol[0] = '\0'; req.error = false; // Recieve the data, thank you if (recv(sd, reqBuf, sizeof(reqBuf), 0) == -1) { snprintf(error, sizeof(error), "Unable to recieve request, %s", strerror(errno)); log_server(LOG_ERR, error); // Cleanup close(sd); free(args); return NULL; } // PARSE REQUEST ------------------------------------- // First line is the actual request req_line = strtok(reqBuf, "\r\n"); // Check if GET or HEAD is set req_token = strtok(req_line, " "); if (req_token != NULL) { if (strncmp(req_token, "GET", 3) == 0 || strncmp(req_token, "HEAD", 4) == 0) { strncpy(req.method, req_token, BUF_VAL); // Get uri req_token = strtok(NULL, " "); if (req_token != NULL) { strncpy(req.uri, req_token, BUF_VAL); /* Dosent matter // Get Protocol req_token = strtok(NULL, " "); if (req_token != NULL) { // Don't bother with the protocol strncpy(req.protocol, req_token, BUF_VAL); } else { // If no protocol set 400 Bad Request strncpy(head.status, "400 Bad Request", sizeof(head.status)); req.error = true; strncpy(req.path, "/errpg/400.html", sizeof(req.path)); }*/ strncpy(req.protocol, "HTTP/1.0", BUF_VAL); } else { // If no uri set 400 Bad Request strncpy(head.status, "400 Bad Request", sizeof(head.status)); req.error = true; strncpy(req.path, "/errpg/400.html", sizeof(req.path)); } } else { // If invalid method set 501 Not Implemented strncpy(head.status, "501 Not Implemented", sizeof(head.status)); req.error = true; strncpy(req.path, "/errpg/501.html", sizeof(req.path)); } } else { // If no method set 400 Bad Request strncpy(head.status, "400 Bad Request", sizeof(head.status)); req.error = true; strncpy(req.path, "/errpg/400.html", sizeof(req.path)); } // If '/' was only character in uri set index if (strncmp(req.uri, "/", 1) == 0) { strncpy(req.path, "/index.html", sizeof(req.path)); } // Else set the requested path unless the request is bad else if(!req.error) { strncpy(req.path, req.uri, sizeof(req.path)); } // Check if file exists with realpath if (realpath(req.path, buffert) == NULL) { // If file does not exists snprintf(error, sizeof(error), "%s was not found, sending error page instead", req.path); log_server(LOG_INFO, error); strncpy(head.status, "404 Not Found", sizeof(head.status)); req.error = true; // Load error page instead strncpy(req.path, "/errpg/404.html", sizeof(req.path)); realpath(req.path, buffert); } // If file exists and there was no error set status to 200 else if(!req.error) { strncpy(head.status, "200 OK", sizeof(head.status)); } // Open the file if ((reqFile = fopen(buffert, "r")) == NULL) { // If we can't open the file send 500 req.error = true; strncpy(head.status, "500 Internal Server Error", sizeof(head.status)); strncpy(head.protocol, "HEAD", sizeof(head.protocol)); } // Get the file size if (reqFile != NULL) { fstat(fileno(reqFile), &stat_buf); } // HEADER ------------------------------------- // Server name strncpy(head.server, _SERVER_NAME" "_SERVER_VERSION, sizeof(head.server)); // Protocol strncpy(head.protocol, "HTTP/"_SERVER_HTTP_VER, sizeof(head.protocol)); // Type if (strncmp(getExt(req.uri), ".png", 4) == 0) { strncpy(head.type, "image/png", sizeof(head.type)); } else if (strncmp(getExt(req.uri), ".jpg", 4) == 0) { strncpy(head.type, "image/jpg", sizeof(head.type)); } else if (strncmp(getExt(req.uri), ".gif", 4) == 0) { strncpy(head.type, "image/gif", sizeof(head.type)); } else if (strncmp(getExt(req.uri), ".css", 4) == 0) { strncpy(head.type, "text/css", sizeof(head.type)); } else if (strncmp(getExt(req.uri), ".js", 3) == 0) { strncpy(head.type, "application/javascript", sizeof(head.type)); } else if (strncmp(getExt(req.uri), ".html", 5) == 0) { strncpy(head.type, "text/html", sizeof(head.type)); } // Size head.size = (int)stat_buf.st_size; // Cache strncpy(head.cache, "public", sizeof(head.cache)); // Last-Modified strftime(date, sizeof(date), "%a, %d %b %Y %T %z", localtime(&stat_buf.st_ctime)); strncpy(head.modified, date, sizeof(head.modified)); // Send header if (sendHeader(sd, &head) == -1) { snprintf(error, sizeof(error), "Unable to send header, %s. Aborting", strerror(errno)); log_server(LOG_WARNING, error); DIE_CON }
int start_TCP_socket(int port) { int result = 0; int pid; int socket_fd; struct sockaddr_in server_address; socklen_t client_addr_len; int buff_size = 255; //Open socket here socket_fd = socket(AF_INET, SOCK_STREAM, 0); if (socket_fd < 0) { printf("Error in creating socket"); log_server("Error in creating socket"); } else { //Declare socket address //First, clear structure memset((char *)&server_address, 0, sizeof(server_address)); //Assign value to server address server_address.sin_family = AF_INET; server_address.sin_port = htons(port); server_address.sin_addr.s_addr = htonl(INADDR_ANY); // socket binding if (bind(socket_fd, (struct sockaddr *)&server_address, sizeof(server_address)) >= 0) { //Create a struct to store peer address: struct sockaddr_in peer_addr; memset((char *)&peer_addr, 0, sizeof(peer_addr)); socklen_t peer_addr_len = sizeof(peer_addr); listen(socket_fd, 5); //Allocate space for the buffer server is about to receive struct tcpquery * buffer = malloc(sizeof(struct tcpquery)); struct tcpquery * buffer2 = malloc(sizeof(struct tcpquery)); while (breaking_signal) { //Accept connection int new_sock = accept(socket_fd, (struct sockaddr *) &peer_addr, &peer_addr_len ); sprintf(ip, "Client IP %s", inet_ntoa(peer_addr.sin_addr)); sprintf(log_c, "New connection accpeted from IP %s\n", ip); log_server(log_c); if (new_sock == -1) { exit(1); } pid = fork(); if (pid < 0) { perror("Erro creating new process\n"); sprintf(log_c, "Erro creating new process\n"); log_server(log_c); } else if (pid == 0) { for (;;) { //Receiving connection request from client.This is an username send for verification int n = recv(new_sock, buffer, sizeof(*buffer), 0 ); if (n < 0) { perror("Data receiving from socket failed. Exit.\n"); sprintf(log_c, "%s :Data receiving from socket failed. Exit.\n", ip); log_server(log_c); exit(1); } else if (n == 0) { printf("Connection closed\n"); sprintf(log_c, "%s :Connection closed\n", ip); log_server(log_c); break; } struct tcpquery incoming = deserialization_tcp(buffer); //Free allocated buffer received //free(buffer); if (verify_tcp_packet(&incoming) == 1) { int password = getpassword(incoming.command); if (password != 0) { if (randomtokenhandling(new_sock) < 0) { perror("Socket writing error.\n"); sprintf(log_c, "%s :Socket writing error.\n", ip); log_server(log_c); exit(1); } int n = recv(new_sock, buffer2, sizeof(*buffer2), 0); if (n < 0) { perror("Data receiving from socket failed. Exit.\n"); sprintf(log_c, "%s :Data receiving from socket failed. Exit.\n", ip); log_server(log_c); exit(1); } else if (n == 0) { printf("Connection closed\n"); sprintf(log_c, "%s :Connection closed\n", ip); log_server(log_c); break; } if (generateH2value(new_sock, password, R)) { if (H_value_compare(buffer2) == 1) { printf("Authentication completed. Success...\n"); sprintf(log_c, "%s :Authentication completed. Success...\n", ip); log_server(log_c); auth_client(new_sock, 1); breaking_signal = 0; result = 1; start_UDP(H2, port); break; } else { printf("Authentication Failed\n"); sprintf(log_c, "%s :Authentication failed\n",ip); log_server(log_c); auth_client(new_sock, 0); //break; } } else { printf("Cannot generate authetication token\n"); sprintf(log_c, "%s :Cannot generate authetication token\n", ip); log_server(log_c); break; } } else { //User not found. Reject connection. printf("User not found. Rejected...\n"); sprintf(log_c, "%s :User not found. Rejected...\n", ip); log_server(log_c); rejectconnection(new_sock); break; } } else { printf("Packet received did not follow defined protocol. Rejected. \n"); sprintf(log_c, "%s :Packet received did not follow defined protocol. Rejected.\n", ip); log_server(log_c); break; } } //Child process suicides here exit(0); } close(new_sock); } close(socket_fd); free(buffer); free(buffer2); } } return result; }