#include #include #include #include #include #include #include #include size_t hash(const char* word) { size_t x; for (x=0; *word; ++word) x = (x + (x << 5)) ^ *word; return x; } #define HASHTABSIZE 65536 struct node { char* word,* ip,* port,* timestamp; struct node* next; }* hashtab[HASHTABSIZE]; void* allocassert(void* x) { if (!x) { #ifdef oldandslow fprintf(stderr,"out of memory!\n"); exit(1); #else die(1,"out of memory"); #endif } return x; } struct node** lookup(char* word) { struct node** x; for (x=&hashtab[hash(word)%HASHTABSIZE]; *x; x=&(*x)->next) if (!strcmp(word,(*x)->word)) break; return x; } char printfbuf[16*1024]; static int cmp3(const char* a, const char* b) { #if defined(__i386__) || defined(__x86_64__) return a[0]==b[0] && a[1]==b[1] && a[2]==b[2]; #else return ((*(uint32_t*)a ^ *(uint32_t*)b) & 0xffffff) == 0; #endif } static int cmp4(const char* a, const char* b) { #if defined(__i386__) || defined(__x86_64__) return *(uint32_t*)a == *(uint32_t*)b; #else return cmp3(a,b) && a[3]==b[3]; #endif } #ifndef oldandslow static unsigned char inbuf[16*1024]; static size_t ib_first,ib_last; static int mygetc() { if (ib_first>=ib_last) { ib_first=0; ib_last=read(0,inbuf,sizeof inbuf); if (ib_last==(size_t)-1) return -1; if (ib_last==0) return -2; } return inbuf[ib_first++]; } static size_t myfgets(char* buf,size_t bufsize) { static int eof; int i; size_t j; if (eof) return 0; for (j=0; j1) { int tslen; #endif /* find out what kind of time stamp there is */ tslen=0; if (line[0]=='@') { /* multilog timestamp */ char* x=strchr(line,' '); if (x) { tslen=x-line; if (tslen!=25) tslen=0; } } else if (isdigit(line[0])) { char* x=strchr(line,' '); if (x && x==line+10) { x=strchr(x+1,' '); if (x && x==line+29) tslen=29; } } if (tslen) { dat=line+tslen+1; line[tslen]=0; timestamp=line; } else { dat=line; timestamp=""; } /* element two is the unique key */ { char* fields[21]; char* x=dat; int i; /* early-out skip the field splitting if we are not interested in * the line anyway */ if (*x != 'a' && *x != 'c' && *x != 'G' && *x != 'P' && *x != 'H') continue; /* split into fields */ for (i=0; i<20; ++i) { char* y=strchr(x,' '); if (!y) break; *y=0; fields[i]=x; x=y+1; } fields[i]=x; ++i; if (!strcmp(fields[0],"accept")) { struct node** N; struct node* x; if (i<2) continue; N=lookup(fields[1]); if (!(x=*N)) { *N=malloc(sizeof(**N)); (*N)->next=0; x=*N; } else { free(x->word); #ifdef oldandslow free(x->ip); free(x->port); free(x->timestamp); #endif } #ifndef oldandslow /* reduce allocations */ x->word=allocassert(malloc((fields[4]-fields[1])+(fields[0]-line))); memcpy(x->word,fields[1],fields[4]-fields[1]); x->ip=x->word+(fields[2]-fields[1]); x->port=x->ip+(fields[3]-fields[2]); x->timestamp=x->port+(fields[4]-fields[3]); memcpy(x->timestamp,line,fields[0]-line); #else x->word=allocassert(strdup(fields[1])); x->ip=allocassert(strdup(fields[2])); x->port=allocassert(strdup(fields[3])); x->timestamp=allocassert(strdup(line)); #endif } else if (!strncmp(fields[0],"close/",6)) { struct node** N; N=lookup(fields[1]); if (*N) { struct node* y=(*N)->next; struct node* x=*N; free(x->word); #ifdef oldandslow free(x->ip); free(x->port); free(x->timestamp); #endif free(x); *N=y; } } else if (cmp3(fields[0],"GET") || cmp4(fields[0],"POST") || cmp4(fields[0],"HEAD")) { if (i>6) { /* otherwise it's a format violation and we ignore the line */ struct node** N; N=lookup(fields[1]); #ifdef oldandslow printf("%s %s %s http%s://%s%s %s %s %s\n", timestamp,fields[0],*N?(*N)->ip:"::", strstr(fields[0],"SSL")?"s":"",fields[6],fields[2],fields[3],fields[4],fields[5]); #else buffer_putm(buffer_1,timestamp," ",fields[0]," ",*N?(*N)->ip:"::"," http", strstr(fields[0],"SSL")?"s":"","://",fields[6],fields[2]," ", fields[3]," ",fields[4]," ",fields[5],"\n"); #endif } } } } #ifndef oldandslow buffer_flush(buffer_1); #endif return 0; }