1 #include <unistd.h>
2 #include <stdlib.h>
3 #include <stdio.h>
4 #include <string.h>
5 #include <ctype.h>
6 #include <stdint.h>
7 #include <buffer.h>
8 #include <errmsg.h>
9 
hash(const char * word)10 size_t hash(const char* word) {
11   size_t x;
12   for (x=0; *word; ++word)
13     x = (x + (x << 5)) ^ *word;
14   return x;
15 }
16 
17 #define HASHTABSIZE 65536
18 
19 struct node {
20   char* word,* ip,* port,* timestamp;
21   struct node* next;
22 }* hashtab[HASHTABSIZE];
23 
allocassert(void * x)24 void* allocassert(void* x) {
25   if (!x) {
26 #ifdef oldandslow
27     fprintf(stderr,"out of memory!\n");
28     exit(1);
29 #else
30     die(1,"out of memory");
31 #endif
32   }
33   return x;
34 }
35 
lookup(char * word)36 struct node** lookup(char* word) {
37   struct node** x;
38   for (x=&hashtab[hash(word)%HASHTABSIZE]; *x; x=&(*x)->next)
39     if (!strcmp(word,(*x)->word))
40       break;
41   return x;
42 }
43 
44 char printfbuf[16*1024];
45 
cmp3(const char * a,const char * b)46 static int cmp3(const char* a, const char* b) {
47 #if defined(__i386__) || defined(__x86_64__)
48   return a[0]==b[0] && a[1]==b[1] && a[2]==b[2];
49 #else
50   return ((*(uint32_t*)a ^ *(uint32_t*)b) & 0xffffff) == 0;
51 #endif
52 }
53 
cmp4(const char * a,const char * b)54 static int cmp4(const char* a, const char* b) {
55 #if defined(__i386__) || defined(__x86_64__)
56   return *(uint32_t*)a == *(uint32_t*)b;
57 #else
58   return cmp3(a,b) && a[3]==b[3];
59 #endif
60 }
61 
62 #ifndef oldandslow
63 static unsigned char inbuf[16*1024];
64 static size_t ib_first,ib_last;
65 
mygetc()66 static int mygetc() {
67   if (ib_first>=ib_last) {
68     ib_first=0;
69     ib_last=read(0,inbuf,sizeof inbuf);
70     if (ib_last==(size_t)-1) return -1;
71     if (ib_last==0) return -2;
72   }
73   return inbuf[ib_first++];
74 }
75 
myfgets(char * buf,size_t bufsize)76 static size_t myfgets(char* buf,size_t bufsize) {
77   static int eof;
78   int i;
79   size_t j;
80   if (eof) return 0;
81   for (j=0; j<bufsize-1; ++j) {
82     i=mygetc();
83     if (i==-2) { eof=1; return j; }
84     if (i==-1) return -1;
85     if (i=='\n') break;
86     buf[j]=i;
87   }
88   buf[j]=0;
89   return j;
90 }
91 #endif
92 
main()93 int main() {
94   char line[8192];
95   char* dat;
96   char* timestamp;
97 #ifdef oldandslow
98   setvbuf(stdout,printfbuf,_IOFBF,sizeof printfbuf);
99   while (fgets(line,sizeof(line),stdin)) {
100     int tslen;
101     /* chomp */
102     {
103       int i;
104       for (i=0; i<sizeof(line) && line[i]; ++i)
105 	if (line[i]=='\n') break;
106       line[i]=0;
107     }
108 #else
109   buffer_init(buffer_1,write,1,printfbuf,sizeof printfbuf);
110   while (myfgets(line,sizeof(line))+1>1) {
111     int tslen;
112 #endif
113     /* find out what kind of time stamp there is */
114     tslen=0;
115     if (line[0]=='@') {
116       /* multilog timestamp */
117       char* x=strchr(line,' ');
118       if (x) {
119 	tslen=x-line;
120 	if (tslen!=25) tslen=0;
121       }
122     } else if (isdigit(line[0])) {
123       char* x=strchr(line,' ');
124       if (x && x==line+10) {
125 	x=strchr(x+1,' ');
126 	if (x && x==line+29) tslen=29;
127       }
128     }
129     if (tslen) {
130       dat=line+tslen+1;
131       line[tslen]=0;
132       timestamp=line;
133     } else {
134       dat=line;
135       timestamp="";
136     }
137     /* element two is the unique key */
138     {
139       char* fields[21];
140       char* x=dat;
141       int i;
142 
143       /* early-out skip the field splitting if we are not interested in
144        * the line anyway */
145       if (*x != 'a' && *x != 'c' && *x != 'G' && *x != 'P' && *x != 'H')
146 	continue;
147 
148       /* split into fields */
149       for (i=0; i<20; ++i) {
150 	char* y=strchr(x,' ');
151 	if (!y) break;
152 	*y=0;
153 	fields[i]=x;
154 	x=y+1;
155       }
156       fields[i]=x; ++i;
157       if (!strcmp(fields[0],"accept")) {
158 	struct node** N;
159 	struct node* x;
160 	if (i<2) continue;
161 	N=lookup(fields[1]);
162 	if (!(x=*N)) {
163 	  *N=malloc(sizeof(**N));
164 	  (*N)->next=0;
165 	  x=*N;
166 	} else {
167 	  free(x->word);
168 #ifdef oldandslow
169 	  free(x->ip);
170 	  free(x->port);
171 	  free(x->timestamp);
172 #endif
173 	}
174 #ifndef oldandslow
175 	/* reduce allocations */
176 	x->word=allocassert(malloc((fields[4]-fields[1])+(fields[0]-line)));
177 	memcpy(x->word,fields[1],fields[4]-fields[1]);
178 	x->ip=x->word+(fields[2]-fields[1]);
179 	x->port=x->ip+(fields[3]-fields[2]);
180 	x->timestamp=x->port+(fields[4]-fields[3]);
181 	memcpy(x->timestamp,line,fields[0]-line);
182 #else
183 	x->word=allocassert(strdup(fields[1]));
184 	x->ip=allocassert(strdup(fields[2]));
185 	x->port=allocassert(strdup(fields[3]));
186 	x->timestamp=allocassert(strdup(line));
187 #endif
188       } else if (!strncmp(fields[0],"close/",6)) {
189 	struct node** N;
190 	N=lookup(fields[1]);
191 	if (*N) {
192 	  struct node* y=(*N)->next;
193 	  struct node* x=*N;
194 	  free(x->word);
195 #ifdef oldandslow
196 	  free(x->ip);
197 	  free(x->port);
198 	  free(x->timestamp);
199 #endif
200 	  free(x);
201 	  *N=y;
202 	}
203       } else if (cmp3(fields[0],"GET") || cmp4(fields[0],"POST") || cmp4(fields[0],"HEAD")) {
204 	if (i>6) {	/* otherwise it's a format violation and we ignore the line */
205 	  struct node** N;
206 	  N=lookup(fields[1]);
207 #ifdef oldandslow
208 	  printf("%s %s %s http%s://%s%s %s %s %s\n",
209 		 timestamp,fields[0],*N?(*N)->ip:"::",
210 		 strstr(fields[0],"SSL")?"s":"",fields[6],fields[2],fields[3],fields[4],fields[5]);
211 #else
212 	  buffer_putm(buffer_1,timestamp," ",fields[0]," ",*N?(*N)->ip:"::"," http",
213 		      strstr(fields[0],"SSL")?"s":"","://",fields[6],fields[2]," ",
214 		      fields[3]," ",fields[4]," ",fields[5],"\n");
215 #endif
216 	}
217       }
218     }
219   }
220 #ifndef oldandslow
221   buffer_flush(buffer_1);
222 #endif
223   return 0;
224 }
225