diff -ruN ./0.4/config.h ./0.5/config.h --- ./0.4/config.h Fri May 10 14:38:39 2002 +++ ./0.5/config.h Mon May 13 20:29:56 2002 @@ -1,2 +1,2 @@ #define TCP_PORT 8080 -#define VERSION "0.3" +#define VERSION "0.5" diff -ruN ./0.4/connection.c ./0.5/connection.c --- ./0.4/connection.c Fri May 10 19:15:17 2002 +++ ./0.5/connection.c Wed May 15 17:58:28 2002 @@ -7,7 +7,106 @@ goto next_iteration; \ } while (0) -extern item_struct *items[MAX_SERVER_ID]; +#define BAIL_OUT_EXIT do { connection->reply_filename = NON_EXISTENT_FILENAME; \ + return; \ + } while (0) +#if 1 +#define DEBUG(x) (fprintf(stderr,x)) +#else +#define DEBUG(x) do { } while (0) +#endif + +/* functions for working with global structure */ + +extern item_struct *items[MAX_SERVER_ID+1]; + +extern item_struct *first_free[MAX_SERVER_ID+1]; + +extern int number_free[MAX_SERVER_ID+1]; + +/* adds new item to global items[] + * for description of data structures, see connection.h + * if we've run out of free nodes, allocate PTR_BLOCKSIZE + * make it a round-linked-list, and connect to the former + * round-linked-list + */ + +void add_new_item(int server_id, time_t curtime, char *identifier, + int first_visit_flag, char *ip_addr) +{ + int q; + item_struct *tmp_item=NULL, *swap=NULL, *prev=NULL, *first=NULL, *tmp=NULL; + + if (number_free[server_id] == 0){ + DEBUG("out of space, allocating new round-list\n"); + for(q = 0; qid = 0; + tmp->first_request = 0; + tmp->request_count = 0; + tmp->first_visit_flag = 0; + tmp->identifier = (char *)strdup("\0"); + tmp->ip_addr = (char *)strdup("\0"); + if (!q) { + first = tmp; + prev = tmp; + } + if(q) { + prev->next = tmp; + prev->next->prev = prev; + prev = tmp; + } + } + swap = items[server_id]->next; + items[server_id]->next = first; + prev->next = swap; + number_free[server_id] = PTR_BLOCKSIZE+1; + } + + tmp_item = first_free[server_id]; + tmp_item->id = server_id; + tmp_item->first_request = curtime; + tmp_item->last_request = curtime; + tmp_item->first_visit_flag = first_visit_flag; + tmp_item->identifier = (char *)strdup(identifier); + tmp_item->ip_addr = (char *)strdup(ip_addr); + number_free[server_id]--; + if(number_free[server_id]){ + while(first_free[server_id]->id) + first_free[server_id] = first_free[server_id]->next; + } + + +} + +/* search an entry in global items[]. item is identified by + * server_id, identifier, and ip addr + * if not found, return NULL + */ + +item_struct *get_item(int server_id, char *identifier, char *ip_addr) +{ + item_struct *tmp_item; + int found = 0; + + tmp_item = items[server_id]; + while(tmp_item != NULL && !found){ + if(!strcmp(identifier, tmp_item->identifier) && + !strcmp(ip_addr, tmp_item->ip_addr)) + found = 1; + else{ + tmp_item = tmp_item->next; + if (tmp_item == items[server_id]) + tmp_item = NULL; + + } + } + return tmp_item; +} + +/* count expration date of a session. simly adds + * SESSION_TIMEOUT to current time + */ int get_expiry_date(char *buffer) { @@ -21,6 +120,10 @@ return 0; } +/* make a substitution of %-coded characters in URL, according + * to RFC + */ + void decode_hexa_octets(char *s1, char *s2) { int i,a,q; @@ -43,9 +146,8 @@ } } - -connection_ptr -connection_new (void) +/* allocate new connection */ +connection_ptr connection_new (void) { int size; connection_ptr new_connection; @@ -59,8 +161,8 @@ return new_connection; } -void -connection_init (connection_ptr connection) +/* initialize connection structure */ +void connection_init (connection_ptr connection) { connection->request_text = NULL; @@ -77,9 +179,8 @@ } - -void -connection_free (connection_ptr connection) +/* called when connection closed */ +void connection_free (connection_ptr connection) { if (!connection) return; @@ -98,7 +199,7 @@ free (connection); } - +/* detects end of client's request */ int connection_have_a_request (connection_ptr connection) { if (!connection) return 0; @@ -110,7 +211,7 @@ (connection->request_text[connection->request_text_size-4] == '\r')); } - +/* tests valididy of currently examined cookie */ int is_valid_cookie(char *cookie) { int q=0; @@ -124,6 +225,8 @@ if (q >= 1 && q<= 5) return 1; else return 0; } + +/* calls RMD160 routine to compute hash from server_id & time */ char *get_identifier(int i_name, time_t time) { char hashcode[RMDsize]; @@ -149,8 +252,10 @@ return (char *)(strdup(ret)); } -void -connection_parse_request (connection_ptr connection) +/* main parsing routine - parse GET, Cookie: and fill in apropriate data + * structures (calling the above functions) + */ +void connection_parse_request (connection_ptr connection) { int i = 0; int li = 0; @@ -160,8 +265,9 @@ char c_server_id[MAX_SERVER_ID_LENGTH], tmp_S[MAX_STRING_ARG_LENGTH]; char tmp_N[9]; char decoded[1024]; - char *c, *line_ptr, *tmp_ptr; + char *c, *line_ptr, *tmp_ptr, S_cookie[1024]; long tmp_server_id,N=0; + int got_S_cookie, got_V_cookie; ASSERT (connection != NULL); ASSERT (connection->request_text != NULL); @@ -171,9 +277,14 @@ connection->request_text_size = strlen(decoded); got_valid_cookie = 0; + got_S_cookie = 0; + got_V_cookie = 0; connection->do_set_cookie = 0; connection->reply_filename = SEND_FILENAME; + strcpy(S_cookie, ""); + + while (i < connection->request_text_size) { @@ -245,10 +356,12 @@ connection->N = (int) N; connection->N_num = N_num; } - else if (strncmp (&connection->request_text[i], "Cookie: ", 8) == 0) { + else if (strncmp (&connection->request_text[i], "Cookie:", 7) == 0) { /* Take from "Cookie: " to the end */ - i += 8; + i += 7; + while(isspace(connection->request_text[i])) i++; li = 0; + got_S_cookie = 0; for (;((connection->request_text[i] != '\r') && (i < connection->request_text_size)) && (i<1024); i++, li++) { @@ -275,6 +388,7 @@ /* verify S[0-9]{1.5]=value */ if (is_valid_cookie(line_ptr)){ + DEBUG("got valid cookie\n"); got_valid_cookie = 1; tmp_ptr = line_ptr; tmp_ptr++; @@ -286,53 +400,31 @@ } tmp_N[q] = '\0'; N = strtol(tmp_N, NULL, 10); - if(*line_ptr == 'V' && N == connection->server_id){ + if(*line_ptr == 'V'){ if ( (tmp_ptr = strchr(line_ptr,'=')) ){ tmp_ptr++; while (isspace(*tmp_ptr)) tmp_ptr++; - if(!strcmp(tmp_ptr,"YES")){ - items[N]->first_visit_flag = 1; + if(!strcmp(tmp_ptr,"YES") + && N == connection->server_id){ + DEBUG("got V cookie\n"); + got_V_cookie = 1; } } } - else if (N != connection->server_id){ - BAIL_OUT; - } - if (*line_ptr == 'S' && N == connection->server_id) { + if (*line_ptr == 'S') { if ( (tmp_ptr = strchr(line_ptr,'=')) ){ tmp_ptr++; while(isspace(*tmp_ptr)) tmp_ptr++; - /* now there is string identifier in tmp_ptr */ - - if (!strcmp(tmp_ptr, items[N]->identifier)){ - if (!strcmp(items[N]->ip_addr, - connection->ip_addr)){ - if (time(NULL) - items[N]->last_request < - SESSION_TIMEOUT){ - items[N]->last_request = time(NULL); - if (items[N]->request_count++ < 0) - items[N]->request_count--; - } else { - fprintf(stderr,"session timed out\n"); - BAIL_OUT; - } - } - } else { - fprintf(stderr,"wrong cookie identifier. Got %s expected %s\n", tmp_ptr, items[N]->identifier); - BAIL_OUT; - } + got_S_cookie = 1; + strncpy(S_cookie, tmp_ptr, 1024); + DEBUG("got S cookie\n"); } } -/* else if (N != connection->server_id) - BAIL_OUT;*/ } /* is valid cookie */ line_ptr = c; + line_ptr ++; } - /* and the last one, not parsed inside while - */ -/* while (isspace(*line_ptr)) line_ptr++; - fprintf(stderr, "Cookie: -> %s <-\n", line_ptr);*/ } else { next_iteration: @@ -341,35 +433,54 @@ } } - if (!got_valid_cookie) { - N = connection->server_id; - if (items[N]->id == 0){ - - fprintf(stderr,"NO VALID COOKIE, CREATING SERVER_ID: %ld\n",N); + /* make action according to received cookies */ + N = connection->server_id; + if ( (got_V_cookie && !got_S_cookie) || (!got_V_cookie && !got_S_cookie) ){ + /* we need to create new item - only setting of first_visit_flag + * differs from case to case (we know from got_V_cookie) + */ + fprintf(stderr,"Received V cookie, no S cookie - creating new session, with first_visit_flag = 0\n"); + connection->do_set_cookie = 1; + connection->set_cookie = get_identifier( + connection->server_id, time(NULL)); + add_new_item(N, time(NULL), connection->set_cookie, got_V_cookie, + (char *)strdup(connection->ip_addr)); + } + else if (got_V_cookie && got_S_cookie){ + item_struct *tmp_item; + + /* just increment # visit counter & last_request time */ + DEBUG("got_S_cookie && got_V_cookie\n"); + tmp_item = get_item(N, S_cookie, connection->ip_addr); + if (!tmp_item){ + fprintf(stderr,"Got S cookie, but no data found. Acting as if received only V cookie.\n"); connection->do_set_cookie = 1; - connection->set_cookie = get_identifier(connection->server_id,time(NULL)); - items[N]->id = connection->server_id; - items[N]->first_request = time(NULL); - items[N]->last_request = items[N]->first_request; - items[N]->request_count = 1; - items[N]->identifier = connection->set_cookie; - items[N]->first_visit_flag = 0; - items[N]->ip_addr = (char *)strdup(connection->ip_addr); + connection->set_cookie = get_identifier( + connection->server_id, time(NULL)); + add_new_item(N, time(NULL), connection->set_cookie, got_V_cookie, + (char *)strdup(connection->ip_addr)); } - else { - fprintf(stderr,"NO VALID COOKIE, BUT SERVER EXISTS\n"); - connection->reply_filename = NON_EXISTENT_FILENAME; + else{ /* not neccesary ;) */ + DEBUG("adjusting item I got\n"); + tmp_item->last_request = time(NULL); + tmp_item->request_count++; + if (tmp_item->request_count < 0) tmp_item->request_count--; + connection->do_set_cookie = 1; + connection->set_cookie = (char *) strdup(tmp_item->identifier); } } - + else { + /* did got only S cookie - weird */ + DEBUG("got something weird\n"); + BAIL_OUT_EXIT; + } } - -static int __inline -connection_add_text (connection_ptr connection, char *text, int len) +/* do buffer operation over currently read text buffer */ +static int __inline connection_add_text (connection_ptr connection, char *text, int len) { ASSERT (connection != NULL); ASSERT (text != NULL); @@ -392,6 +503,7 @@ return 0; } +/* those are obvious... */ #define MAX_READ_BUFFER_SIZE 1024 char read_buffer[MAX_READ_BUFFER_SIZE]; @@ -448,10 +560,16 @@ if (connection->do_set_cookie){ get_expiry_date(&expiry_time[0]); - snprintf (write_buffer, MAX_WRITE_BUFFER_SIZE, "Set-cookie: S%d = %s; expires = %s; domain = %s; PATH = /\r\n\r\n", + /* S cookie */ + snprintf (write_buffer, MAX_WRITE_BUFFER_SIZE, "Set-cookie: S%d = %s; expires = %s; domain = %s; PATH = /foo\r\n", connection->server_id, connection->set_cookie, expiry_time, DOMAIN_NAME); write(socket, write_buffer, strlen(write_buffer)); + /* V cookie */ + snprintf (write_buffer, MAX_WRITE_BUFFER_SIZE, "Set-cookie: V%d = YES; expires = %s; domain = %s; PATH = /\r\n\r\n", + connection->server_id, expiry_time, DOMAIN_NAME); + write(socket, write_buffer, strlen(write_buffer)); + } } diff -ruN ./0.4/connection.h ./0.5/connection.h --- ./0.4/connection.h Fri May 10 18:19:03 2002 +++ ./0.5/connection.h Wed May 15 17:59:23 2002 @@ -1,3 +1,4 @@ + #ifndef __CONNECTION_H__ #define __CONNECTION_H__ @@ -17,12 +18,21 @@ #include "rmd160.h" #define MAX_REQUEST_PROCESSING_TIME 30 -#define MAX_SERVER_ID 16386 +/*#define MAX_SERVER_ID 16386*/ #define MAX_SERVER_ID 16 #define MAX_SERVER_ID_LENGTH 5 #define MAX_STRING_ARG_LENGTH 256 #define SESSION_TIMEOUT 30*60 #define DOMAIN_NAME "dummy.domain.cz" +#define PTR_BLOCKSIZE 32 + +/* item struct is a round-liked list, allocated PT_BLOCKSIZE + * nodes in advance. items[i] allocated in init_item_struct() + * is not to be deleted (delete function not yet implemented) + * there must always be at least one structure for each server_id + * (it shouldn't lower under PTR_BLOCKSIZE, respectively, which + * is delete function's care) + */ typedef struct _item_struct item_struct; @@ -35,9 +45,10 @@ int first_visit_flag; char *ip_addr; -}; - + item_struct *next; + item_struct *prev; +}; typedef struct _connection connection; diff -ruN ./0.4/main.c ./0.5/main.c --- ./0.4/main.c Fri May 10 19:04:23 2002 +++ ./0.5/main.c Mon May 13 20:42:41 2002 @@ -1,17 +1,36 @@ #include "jikos_cheetah.h" +/* the main linked list */ item_struct *items[MAX_SERVER_ID+1]; + +/* indicating first unused node in each linked list */ +item_struct *first_free[MAX_SERVER_ID+1]; + +/* # of free nodes in each linked list. needed to keep it + * not too much memory-consuming + */ +int number_free[MAX_SERVER_ID+1]; + sig_atomic_t terminate = 0; void free_item_struct() { int i; + item_struct *tmp, *tmp1; + for (i = 0; iidentifier) free(items[i]->identifier); if(items[i]->ip_addr) free(items[i]->ip_addr); - + tmp = items[i]->next; + while (tmp->next != items[i]){ + tmp1 = tmp->next; + if(tmp->identifier) free(tmp->identifier); + if(tmp->ip_addr) free(tmp->ip_addr); + free (tmp); + tmp = tmp1; + } free(items[i]); } @@ -19,8 +38,12 @@ void init_item_struct() { - int i; - /* FIXME: instead of for(), calling malloc() for enough big data is enough */ + int i, q; + item_struct *tmp, *first = NULL, *prev = NULL; /* to aviod compiler warnings */ + /* !! BEWARE !! when deleting item from rounded-list, be careful about + * deleting "first" item (items[i]). you can't delete it, it must be allocated + * all the time (first & next pointing to itself) + */ for (i = 0; iid = 0; @@ -30,6 +53,28 @@ items[i]->first_visit_flag = 0; items[i]->identifier = (char *)strdup("\0"); items[i]->ip_addr = (char *)strdup("\0"); + for(q = 0; qid = 0; + tmp->first_request = 0; + tmp->request_count = 0; + tmp->first_visit_flag = 0; + tmp->identifier = (char *)strdup("\0"); + tmp->ip_addr = (char *)strdup("\0"); + if (!q) { + first = tmp; + prev = tmp; + } + if(q) { + prev->next = tmp; + prev->next->prev = prev; + prev = tmp; + } + } + prev->next = items[i]; + items[i]->next = first; + first_free[i] = items[i]; + number_free[i] = PTR_BLOCKSIZE+1; } }