Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <ctype.h>
- #include <string.h>
- #include <pthread.h>
- #include <signal.h>
- #include <arpa/inet.h>
- #include <netinet/tcp.h>
- #include <netinet/in.h>
- #include <sys/time.h>
- #include <sys/stat.h>
- #include <sys/wait.h>
- #include <sys/socket.h>
- #include <sys/types.h>
- #define ISspace(x) isspace((int)(x))
- #define SERVER_PORT 8080
- #define SERVER_STRING "Server: wi2me server\r\n"
- #define MAX_LINE_SIZE 1024
- #define MAX_KEY_SIZE 20
- #define MAX_VALUE_SIZE 20
- #define MAX_DIR_SIZE 200
- #define HTTP_METHOD_GET 1
- #define HTTP_METHOD_POST 2
- #define HTTP_BAD_REQUEST -1
- #define HTTP_METHOD_NOT_IMPLEMENTED -2
- #define ERR_SOCKET -3
- struct client_log{
- char dir[MAX_DIR_SIZE];
- char tcp[MAX_DIR_SIZE];
- char info[MAX_DIR_SIZE];
- FILE* s_file;
- pthread_mutex_t file_mutex;
- };
- struct client_list{
- pthread_t pid;
- int sock;
- struct client_log* c_log;
- struct client_list* next;
- struct client_list* prev;
- };
- void* accept_request(void *);
- void client_bad_request(int);
- void client_unimplemented(int);
- void client_get(int, char*, struct client_log*);
- void client_post(int);
- void cat(int, FILE *);
- void error_die(const char *);
- int get_line(int, char *, int);
- void headers(int);
- void not_found(int);
- int startup(u_short *);
- void server_stop(int);
- void remove_from_list(struct client_list*);
- void unimplemented(int);
- struct client_list *first;
- pthread_mutex_t mutex_list = PTHREAD_MUTEX_INITIALIZER;
- /********************************************************************
- * Split a "key=value" string into key and value
- ********************************************************************/
- void split(char* s, char* key, char* value){
- int i=0, j=0;
- while((s[i] != '=') && (s[i] != '\0') && (i < MAX_KEY_SIZE - 1)){
- key[i]=s[i];
- i++;
- }
- key[i]='\0';
- if(s[i] != '\0'){
- i++;
- do{
- value[j] = s[i];
- i++; j++;
- }while((s[i] != '\0') && (j < MAX_VALUE_SIZE));
- }else value[0]='\0';
- }
- /**********************************************************************/
- /* Kill the server and all its instance when catching SIGINT */
- /**********************************************************************/
- void server_stop(int sig){
- printf("receive signal %i, shutting down the server\n",sig);
- /* while(first != NULL){
- struct client_list* next;
- next = first->next;
- remove_from_list(first);
- first=next;
- }
- */
- close(first->sock);
- exit(0);
- }
- /**********************************************************************/
- /* print list */
- /**********************************************************************/
- void print_list(){
- printf ("first : %i - ", first->sock);
- struct client_list* current = first->prev;
- while(current != first){
- if(current == NULL){printf("problem !"); break; }
- printf ("%i - ", current->sock);
- current = current->prev;
- }
- printf("\n");
- return;
- }
- /**********************************************************************/
- /* Write TCP Connecshun information */
- /**********************************************************************/
- void write_tcp_info(int socket, FILE* file, pthread_mutex_t *mutex){
- if(file == NULL) return;
- struct timeval t_val;
- struct tcp_info tcp_info;
- gettimeofday(&t_val, NULL);
- int tcp_info_length = sizeof(tcp_info);
- if ( getsockopt( socket, SOL_TCP, TCP_INFO, (void *)&tcp_info, (socklen_t *)&tcp_info_length ) == 0 ) {
- pthread_mutex_lock(mutex);
- fprintf(file,"%u.%u %u %u %u %u %u %u %u %u %u %u %u %u\n",
- (unsigned int)t_val.tv_sec,
- (unsigned int)t_val.tv_usec,
- tcp_info.tcpi_last_data_sent,
- tcp_info.tcpi_last_data_recv,
- tcp_info.tcpi_snd_cwnd,
- tcp_info.tcpi_snd_ssthresh,
- tcp_info.tcpi_rcv_ssthresh,
- tcp_info.tcpi_rtt,
- tcp_info.tcpi_rttvar,
- tcp_info.tcpi_unacked,
- tcp_info.tcpi_sacked,
- tcp_info.tcpi_lost,
- tcp_info.tcpi_retrans,
- tcp_info.tcpi_fackets
- );
- pthread_mutex_unlock(mutex);
- }
- }
- /**********************************************************************/
- /* Initialize the log for the current client */
- /**********************************************************************/
- struct client_log* initialize_log(int socket){
- char c_path[MAX_DIR_SIZE];
- char d_path[MAX_DIR_SIZE];
- char i_path[MAX_DIR_SIZE];
- char t_path[MAX_DIR_SIZE];
- char ipstr[INET6_ADDRSTRLEN];
- struct sockaddr_storage peer;
- struct client_log* c_log;
- FILE *tcp_watch, *info;
- struct timeval t_val;
- socklen_t len;
- int port;
- // Write information about the connecshun
- gettimeofday(&t_val, NULL);
- if(getcwd(c_path,MAX_DIR_SIZE) == NULL) return NULL;
- sprintf(d_path,"%s/%u.%02u", c_path, (unsigned int)t_val.tv_sec, (unsigned int)t_val.tv_usec);
- if( mkdir(d_path,S_IRWXU) != 0 ) return NULL;
- sprintf(i_path, "%s/info", d_path);
- info=fopen(i_path,"a+");
- if(info == NULL) return NULL;
- len = sizeof(peer);
- getpeername(socket, (struct sockaddr*)&peer, &len);
- if (peer.ss_family == AF_INET) { // IPv4
- struct sockaddr_in *s = (struct sockaddr_in *)&peer;
- port = ntohs(s->sin_port);
- inet_ntop(AF_INET, &s->sin_addr, ipstr, sizeof ipstr);
- } else { //IPv6
- struct sockaddr_in6 *s = (struct sockaddr_in6 *)&peer;
- port = ntohs(s->sin6_port);
- inet_ntop(AF_INET6, &s->sin6_addr, ipstr, sizeof ipstr);
- }
- fprintf(info, "timestamp : %u.%u\nhost : %s\nport source : %i\n\n", (unsigned int)t_val.tv_sec, (unsigned int)t_val.tv_usec, ipstr, port);
- fclose(info);
- // create tcp file for monitoring TCP connecshun
- sprintf(t_path, "%s/tcp", d_path);
- tcp_watch=fopen(t_path,"a+");
- if(tcp_watch == NULL) return NULL;
- // create the structure
- c_log = malloc(sizeof(struct client_log));
- strncpy(c_log->dir, d_path, strlen(d_path));
- strncpy(c_log->tcp, t_path, strlen(t_path));
- strncpy(c_log->info, i_path, strlen(i_path));
- c_log->s_file = tcp_watch;
- pthread_mutex_init(&(c_log->file_mutex), NULL);
- fprintf(tcp_watch, "sec.msec last_data_sent last_data_recv snd_cwnd snd_ssthresh rtt rttvar unacked sacked lost retrans fackets\n");
- write_tcp_info(socket, tcp_watch, &(c_log->file_mutex));
- return c_log;
- }
- /*******************************************************************/
- /* Add the client to the double linked list */
- /*******************************************************************/
- void add_client(int sock, struct client_log* c_log){
- pthread_mutex_lock(&mutex_list);
- struct client_list* current = malloc(sizeof(struct client_list));
- current->sock = sock;
- current->c_log = c_log;
- current->next = first;
- current->prev = first->prev;
- first->prev->next = current;
- first->prev = current;
- pthread_mutex_unlock(&mutex_list);
- }
- /*******************************************************************/
- /* Remove the client from the double linked list */
- /*******************************************************************/
- void remove_from_list(struct client_list* current){
- if(current == NULL) return;
- pthread_mutex_lock(&mutex_list);
- close(current->sock);
- if(current->c_log != NULL){
- fclose(current->c_log->s_file);
- free(current->c_log);
- }
- if(current->prev != NULL) current->prev->next = current->next;
- if(current->next != NULL) current->next->prev = current->prev;
- free(current);
- pthread_mutex_unlock(&mutex_list);
- }
- /*******************************************************************
- * get the method used by the client
- * if method is GET, feed "query" with the query string. query
- * should be properly allocated. it will not be fed more than
- * query_size bytes. returns HTTP_METHOD_GET.
- * if method is POST, returns HTTP_METHOD_POST.
- * if method is unknown, returns HTTP_METHOD_UNIMPLEMENTED.
- * throws the error if so
- *******************************************************************/
- int retrieve_method(int sock_client, char* query, int query_size){
- char buf[MAX_LINE_SIZE];
- char method[10];
- char *url = malloc(sizeof(char)*MAX_LINE_SIZE);
- char *url_ = url;
- int numchars;
- query[0] = '\0';
- numchars = get_line(sock_client, buf, sizeof(buf));
- //printf("%s\n",buf);
- if(numchars < 0) return numchars;
- unsigned int i = 0; unsigned int j = 0;
- while (!ISspace(buf[j]) && (i < sizeof(method) - 1) && (j < numchars))
- {
- method[i] = buf[j];
- i++; j++;
- }
- method[i] = '\0';
- //printf("%s\n",method);
- if( strcasecmp(method, "POST") == 0 ) return HTTP_METHOD_POST;
- if( strcasecmp(method, "GET") != 0 ) return HTTP_METHOD_NOT_IMPLEMENTED;
- //the method is GET, feed the query string
- i = 0;
- while (ISspace(buf[j]) && (j < numchars)) j++;
- while (!ISspace(buf[j]) && (i < MAX_LINE_SIZE - 1) && (j < numchars))
- {
- url_[i] = buf[j];
- i++; j++;
- }
- url_[i] = '\0';
- while ((*url_ != '?') && (*url_ != '\0')) url_++;
- if (*url_ == '?') url_++;
- strncpy(query, url_, query_size);
- query[query_size - 1] = '\0';
- free(url);
- return HTTP_METHOD_GET;
- }
- /**********************************************************************/
- /* Inform the client that a request it has made has a problem.
- * Parameters: client socket */
- /**********************************************************************/
- void client_bad_request(int client)
- {
- char buf[1024];
- sprintf(buf, "HTTP/1.0 400 BAD REQUEST\r\n");
- send(client, buf, sizeof(buf), 0);
- sprintf(buf, "Content-type: text/html\r\n");
- send(client, buf, sizeof(buf), 0);
- sprintf(buf, "\r\n");
- send(client, buf, sizeof(buf), 0);
- sprintf(buf, "<P>i couldn't understand your request Dudez !");
- send(client, buf, sizeof(buf), 0);
- sprintf(buf, "<P>check your bro !");
- send(client, buf, sizeof(buf), 0);
- }
- /**********************************************************************/
- /* Inform the client that the requested web method has not been
- * implemented.
- * Parameter: the client socket */
- /**********************************************************************/
- void client_unimplemented(int client)
- {
- char buf[1024];
- sprintf(buf, "HTTP/1.0 501 Method Not Implemented\r\n");
- send(client, buf, strlen(buf), 0);
- sprintf(buf, SERVER_STRING);
- send(client, buf, strlen(buf), 0);
- sprintf(buf, "Content-Type: text/html\r\n");
- send(client, buf, strlen(buf), 0);
- sprintf(buf, "\r\n");
- send(client, buf, strlen(buf), 0);
- sprintf(buf, "<HTML><HEAD><TITLE>Method Not Implemented\r\n");
- send(client, buf, strlen(buf), 0);
- sprintf(buf, "</TITLE></HEAD>\r\n");
- send(client, buf, strlen(buf), 0);
- sprintf(buf, "<BODY><P>HTTP request method not supported.\r\n");
- send(client, buf, strlen(buf), 0);
- sprintf(buf, "</BODY></HTML>\r\n");
- send(client, buf, strlen(buf), 0);
- }
- /**********************************************************************/
- /* Handle the GET method, basically, it just sends out a stream of @
- * Parameter: the client socket and the query string */
- /**********************************************************************/
- void client_get(int sock_client, char* query_string, struct client_log* c_log){
- char *query = malloc(sizeof(char)*(strlen(query_string)+1));
- char *token = NULL;
- char *id=NULL; char *mac=NULL; char *ssid=NULL;
- unsigned int size=0;
- strncpy(query, query_string, strlen(query_string));
- token = strtok(query, "&");
- while (token){
- char *key = malloc(sizeof(char)*MAX_KEY_SIZE);
- char *value = malloc(sizeof(char)*MAX_VALUE_SIZE);
- split(token, key, value);
- if (strcmp(key,"id") == 0) id = value;
- else if(strcmp(key,"mac") == 0) mac = value;
- else if(strcmp(key,"ssid") == 0) ssid = value;
- else if(strcmp(key,"size") == 0) size = atoi(value);
- else{ free(key); free(value); }
- free(key);
- token=strtok(NULL, "&");
- }
- free(query);
- //printf("%s - %s - %s - %u\n",id, mac, ssid, size);
- if((id == NULL) || (mac == NULL) || (ssid == NULL) || (size == 0)) goto bad_argument;
- printf("%s\n",c_log->info);
- FILE* info = fopen(c_log->info,"a+");
- if(info == NULL) goto log_error;
- fprintf(info,"access point bssid : %s\naccess point ssid : %s\nstation id : %s\ndata size : %u\n",mac, ssid, id, size);
- fclose(info);
- headers(sock_client);
- unsigned int k = 0;
- for(k = 0; k < size; k=k+100){
- if(send(sock_client, "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n", 100, 0) < 0)
- break;
- write_tcp_info(sock_client, c_log->s_file, &(c_log->file_mutex));
- }
- bad_argument:
- log_error:
- if(id != NULL) free(id);
- if(mac != NULL) free(mac);
- if(ssid != NULL) free(ssid);
- return;
- }
- /**********************************************************************/
- /* Handle the POST method, it just receive some data that it doesn't store
- * Parameter: the client socket and the query string */
- /**********************************************************************/
- void client_post(int sock_client){
- sock_client++;
- }
- void block_signal(){
- sigset_t set;
- sigemptyset(&set);
- sigaddset(&set, SIGHUP);
- sigaddset(&set, SIGINT);
- sigaddset(&set, SIGUSR1);
- sigaddset(&set, SIGUSR2);
- sigaddset(&set, SIGALRM);
- sigprocmask(SIG_BLOCK, &set, NULL);
- }
- /**********************************************************************/
- /* A request has caused a call to accept() on the server port to
- * return. Process the request appropriately.
- * Parameters: the socket connected to the client */
- /**********************************************************************/
- void* accept_request(void* p_client)
- {
- //block_signal();
- int client = *(int*)(p_client);
- char* query = malloc(sizeof(char)*MAX_LINE_SIZE);
- unsigned int port;
- char ipstr[INET6_ADDRSTRLEN];
- struct sockaddr_storage peer;
- socklen_t len = sizeof peer;
- getpeername(client, (struct sockaddr*)&peer, &len);
- if (peer.ss_family == AF_INET) { // IPv4
- struct sockaddr_in *s = (struct sockaddr_in *)&peer;
- port = ntohs(s->sin_port);
- inet_ntop(AF_INET, &s->sin_addr, ipstr, sizeof ipstr);
- } else { //IPv6
- struct sockaddr_in6 *s = (struct sockaddr_in6 *)&peer;
- port = ntohs(s->sin6_port);
- inet_ntop(AF_INET6, &s->sin6_addr, ipstr, sizeof ipstr);
- }
- printf("%s connecté depuis le port %u\n", ipstr, port);
- //print_list();
- struct client_log* c_log = initialize_log(client);
- if(c_log == NULL) goto no_log;
- add_client(client, c_log);
- switch(retrieve_method(client, query, MAX_LINE_SIZE)){
- case HTTP_BAD_REQUEST:
- client_bad_request(client);
- break;
- case ERR_SOCKET:
- break;
- case HTTP_METHOD_NOT_IMPLEMENTED:
- client_unimplemented(client);
- break;
- case HTTP_METHOD_GET:
- client_get(client, query, c_log);
- break;
- case HTTP_METHOD_POST:
- client_post(client);
- break;
- }
- no_log:
- free(query);
- struct client_list* current = first;
- pthread_mutex_lock(&mutex_list);
- while((current != NULL) && (current->sock != client)) current=current->next;
- pthread_mutex_unlock(&mutex_list);
- if(current != NULL) remove_from_list(current);
- //print_list();
- int retval = 0;
- pthread_exit(&retval);
- }
- /**********************************************************************/
- /* Print out an error message with perror() (for system errors; based
- * on value of errno, which indicates system call errors) and exit the
- * program indicating an error. */
- /**********************************************************************/
- void error_die(const char *sc)
- {
- perror(sc);
- exit(1);
- }
- /**********************************************************************/
- /* Get a line from a socket, whether the line ends in a newline,
- * carriage return, or a CRLF combination. Terminates the string read
- * with a null character. If no newline indicator is found before the
- * end of the buffer, the string is terminated with a null.
- * Parameters: the socket descriptor
- * the buffer to save the data in
- * the size of the buffer
- * Returns: the number of bytes stored
- * ERR_SOCKET if error on the socket
- * HTTP_BAD_REQUEST if line did not terminate with a CRLF */
- /**********************************************************************/
- int get_line(int sock, char *buf, int size)
- {
- int i = 0, n;
- char c = '\0';
- //int crlf=0;
- while ((i < size - 1) && (c != '\n'))
- {
- n = recv(sock, &c, 1, 0);
- //printf("%02x\n",c);
- /*
- if(n <= 0) return ERR_SOCKET;
- switch(crlf){
- case 0: if(c == '\r') crlf=1;
- break;
- case 1: if(c == '\n') crlf=2;
- break;
- }
- */
- buf[i] = c;
- i++;
- }
- buf[i] = '\0';
- //if(crlf != 2) return HTTP_BAD_REQUEST;
- //else return i;
- return i;
- }
- /**********************************************************************/
- /* Return the informational HTTP headers about a file. */
- /* Parameters: the socket to print the headers on
- * the name of the file */
- /**********************************************************************/
- void headers(int client)
- {
- char buf[1024];
- strcpy(buf, "HTTP/1.0 200 OK\r\n");
- send(client, buf, strlen(buf), 0);
- strcpy(buf, SERVER_STRING);
- send(client, buf, strlen(buf), 0);
- sprintf(buf, "Content-Type: text/html\r\n");
- send(client, buf, strlen(buf), 0);
- strcpy(buf, "\r\n");
- send(client, buf, strlen(buf), 0);
- }
- /**********************************************************************/
- /* This function starts the process of listening for web connections
- * on a specified port. If the port is 0, then dynamically allocate a
- * port and modify the original port variable to reflect the actual
- * port.
- * Parameters: pointer to variable containing the port to connect on
- * Returns: the socket */
- /**********************************************************************/
- int startup(u_short *port)
- {
- int httpd = 0;
- struct sockaddr_in name;
- httpd = socket(PF_INET, SOCK_STREAM, 0);
- if (httpd == -1)
- error_die("socket");
- memset(&name, 0, sizeof(name));
- name.sin_family = AF_INET;
- name.sin_port = htons(*port);
- name.sin_addr.s_addr = htonl(INADDR_ANY);
- if (bind(httpd, (struct sockaddr *)&name, sizeof(name)) < 0)
- error_die("bind");
- if (*port == 0) /* if dynamically allocating a port */
- {
- unsigned int namelen = sizeof(name);
- if (getsockname(httpd, (struct sockaddr *)&name, &namelen) == -1)
- error_die("getsockname");
- *port = ntohs(name.sin_port);
- }
- if (listen(httpd, 10) < 0)
- error_die("listen");
- return(httpd);
- }
- /**********************************************************************/
- int main(void)
- {
- //create core file for crash
- first = malloc(sizeof(struct client_list));
- first->sock = -1;
- first->pid = 0;
- first->c_log = NULL;
- first->next = first;
- first->prev = first;
- signal(SIGINT, server_stop);
- u_short port = SERVER_PORT;
- struct sockaddr_in client_name;
- unsigned int client_name_len = sizeof(client_name);
- first->sock = startup(&port);
- printf("httpd running on port %d\n", port);
- pthread_t newthread;
- while (1)
- {
- int client_sock = accept(first->sock,
- (struct sockaddr *)&client_name,
- &client_name_len);
- if (client_sock == -1)
- error_die("accept");
- if (pthread_create(&newthread , NULL, accept_request, &client_sock) != 0)
- perror("pthread_create");
- }
- server_stop(0);
- return(0);
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement