diff options
-rw-r--r-- | opentracker.c | 477 |
1 files changed, 236 insertions, 241 deletions
diff --git a/opentracker.c b/opentracker.c index d2df803..4a421cc 100644 --- a/opentracker.c +++ b/opentracker.c | |||
@@ -36,272 +36,267 @@ struct http_data { | |||
36 | 36 | ||
37 | int header_complete(struct http_data* r) | 37 | int header_complete(struct http_data* r) |
38 | { | 38 | { |
39 | long i; | 39 | long i; |
40 | 40 | ||
41 | long l = array_bytes(&r->r); | 41 | long l = array_bytes(&r->r); |
42 | const char* c = array_start(&r->r); | 42 | const char* c = array_start(&r->r); |
43 | 43 | ||
44 | for (i=0; i+1<l; ++i) | 44 | for (i=0; i+1<l; ++i) |
45 | { | 45 | { |
46 | if (c[i]=='\n' && c[i+1]=='\n') | 46 | if (c[i]=='\n' && c[i+1]=='\n') |
47 | return i+2; | 47 | return i+2; |
48 | 48 | ||
49 | if (i+3<l && c[i]=='\r' && c[i+1]=='\n' && c[i+2]=='\r' && c[i+3]=='\n') | 49 | if (i+3<l && c[i]=='\r' && c[i+1]=='\n' && c[i+2]=='\r' && c[i+3]=='\n') |
50 | return i+4; | 50 | return i+4; |
51 | } | 51 | } |
52 | return 0; | 52 | return 0; |
53 | } | 53 | } |
54 | 54 | ||
55 | void httperror(struct http_data* r,const char* title,const char* message) | 55 | void httperror(struct http_data* r,const char* title,const char* message) |
56 | { | 56 | { |
57 | char* c; | 57 | char* c; |
58 | c=r->hdrbuf=(char*)malloc(strlen(message)+strlen(title)+200); | 58 | c=r->hdrbuf=(char*)malloc(strlen(message)+strlen(title)+200); |
59 | 59 | ||
60 | if (!c) | 60 | if (!c) |
61 | { | 61 | { |
62 | r->hdrbuf="HTTP/1.0 500 internal error\r\nContent-Type: text/plain\r\nConnection: close\r\n\r\nout of memory\n"; | 62 | r->hdrbuf="HTTP/1.0 500 internal error\r\nContent-Type: text/plain\r\nConnection: close\r\n\r\nout of memory\n"; |
63 | r->hlen=strlen(r->hdrbuf); | 63 | r->hlen=strlen(r->hdrbuf); |
64 | } | 64 | } |
65 | else | 65 | else |
66 | { | 66 | { |
67 | c+=fmt_str(c,"HTTP/1.0 "); | 67 | c+=fmt_str(c,"HTTP/1.0 "); |
68 | c+=fmt_str(c,title); | 68 | c+=fmt_str(c,title); |
69 | c+=fmt_str(c,"\r\nContent-Type: text/html\r\nConnection: close\r\nContent-Length: "); | 69 | c+=fmt_str(c,"\r\nContent-Type: text/html\r\nConnection: close\r\nContent-Length: "); |
70 | c+=fmt_ulong(c,strlen(message)+strlen(title)+16-4); | 70 | c+=fmt_ulong(c,strlen(message)+strlen(title)+16-4); |
71 | c+=fmt_str(c,"\r\n\r\n<title>"); | 71 | c+=fmt_str(c,"\r\n\r\n<title>"); |
72 | c+=fmt_str(c,title+4); | 72 | c+=fmt_str(c,title+4); |
73 | c+=fmt_str(c,"</title>\n"); | 73 | c+=fmt_str(c,"</title>\n"); |
74 | r->hlen=c - r->hdrbuf; | 74 | r->hlen=c - r->hdrbuf; |
75 | } | 75 | } |
76 | iob_addbuf(&r->iob,r->hdrbuf,r->hlen); | 76 | iob_addbuf(&r->iob,r->hdrbuf,r->hlen); |
77 | } | 77 | } |
78 | 78 | ||
79 | // bestimmten http parameter auslesen und adresse zurueckgeben | 79 | // bestimmten http parameter auslesen und adresse zurueckgeben |
80 | 80 | ||
81 | const char* http_header(struct http_data* r,const char* h) | 81 | const char* http_header(struct http_data* r,const char* h) |
82 | { | 82 | { |
83 | long i; | 83 | long i; |
84 | 84 | ||
85 | long l = array_bytes(&r->r); | 85 | long l = array_bytes(&r->r); |
86 | long sl = strlen(h); | 86 | long sl = strlen(h); |
87 | const char* c = array_start(&r->r); | 87 | const char* c = array_start(&r->r); |
88 | 88 | ||
89 | for (i=0; i+sl+2<l; ++i) | 89 | for (i=0; i+sl+2<l; ++i) |
90 | { | 90 | { |
91 | if (c[i]=='\n' && case_equalb(c+i+1,sl,h) && c[i+sl+1]==':') | 91 | if (c[i]=='\n' && case_equalb(c+i+1,sl,h) && c[i+sl+1]==':') |
92 | { | 92 | { |
93 | c+=i+sl+1; | 93 | c+=i+sl+1; |
94 | if (*c==' ' || *c=='\t') ++c; | 94 | if (*c==' ' || *c=='\t') ++c; |
95 | return c; | 95 | return c; |
96 | } | 96 | } |
97 | return 0; | 97 | return 0; |
98 | } | 98 | } |
99 | } | 99 | } |
100 | 100 | ||
101 | void httpresponse(struct http_data* h,int64 s) | 101 | void httpresponse(struct http_data* h,int64 s) |
102 | { | 102 | { |
103 | char* c; | 103 | char* c; |
104 | array_cat0(&h->r); | 104 | array_cat0(&h->r); |
105 | 105 | ||
106 | c = array_start(&h->r); | 106 | c = array_start(&h->r); |
107 | 107 | ||
108 | if (byte_diff(c,4,"GET ")) | 108 | if (byte_diff(c,4,"GET ")) |
109 | { | 109 | { |
110 | e400: | 110 | e400: |
111 | httperror(h,"400 Invalid Request","This server only understands GET."); | 111 | httperror(h,"400 Invalid Request","This server only understands GET."); |
112 | } | 112 | } |
113 | else | 113 | else |
114 | { | 114 | { |
115 | char *d; | 115 | char *d; |
116 | int64 fd; | 116 | int64 fd; |
117 | struct stat s; | 117 | struct stat s; |
118 | 118 | ||
119 | // expect 'GET /uri?nnbjhg HTTP/1.*' | 119 | // expect 'GET /uri?nnbjhg HTTP/1.*' |
120 | c+=4; | 120 | c+=4; |
121 | 121 | ||
122 | for (d=c; *d!=' '&&*d!='\t'&&*d!='\n'&&*d!='\r'; ++d) ; | 122 | for (d=c; *d!=' '&&*d!='\t'&&*d!='\n'&&*d!='\r'; ++d) ; |
123 | 123 | ||
124 | if (*d!=' ') goto e400; | 124 | if (*d!=' ') goto e400; |
125 | *d=0; | 125 | *d=0; |
126 | if (c[0]!='/') goto e404; | 126 | if (c[0]!='/') goto e404; |
127 | while (c[1]=='/') ++c; | 127 | while (c[1]=='/') ++c; |
128 | 128 | ||
129 | if (!byte_diff(c,9,"announce?")) | 129 | data = c; |
130 | { | 130 | switch( scan_urlencoded_query( &c, data, SCAN_PATH ) ) { |
131 | // info_hash, left, port, numwant, compact | 131 | case 6: /* scrape ? */ |
132 | struct ot_peer peer; | 132 | if (!byte_diff(c,6,"scrape")) |
133 | goto 404; | ||
134 | break; | ||
135 | case 9: | ||
136 | if( !byte_diff(c,8,"announce")) | ||
137 | goto 404; | ||
138 | else { | ||
139 | // info_hash, left, port, numwant, compact | ||
140 | struct ot_peer peer; | ||
133 | ot_hash hash; | 141 | ot_hash hash; |
134 | byte_copy( peer.ip, h->ip, 4); | 142 | byte_copy( peer.ip, h->ip, 4); |
135 | peer.port = 6881; | 143 | peer.port = 6881; |
136 | 144 | ||
137 | c+=9; | 145 | while( NOCHAMSCANNEN ) { |
138 | while( *c!=' ' ) { | 146 | data = c; |
139 | if(!byte_diff(c,10,"info_hash=")) | 147 | switch( scan_urlencoded_query( &c, data, SCAN_SEARCHPATH_PARAM ) ) { |
140 | { | 148 | case -1: /* error */ |
141 | size_t destlen = 20; | 149 | httperror(h,"404 Not Found","No such file or directory."); |
142 | // String is expected to be URL encoded, so expect | 150 | goto e404; |
143 | // (%[0-9A-F][0-9A-F]){20} | 151 | case 4: |
144 | 152 | if(!byte_diff(c,4,"port")) | |
145 | int s = scan_urlencoded( c+10, hash, &destlen); | 153 | /* scan int */ |
146 | if( c[s+10] != '&' ) | 154 | else if(!byte_diff(c,4,"left")) |
147 | goto e_parse; | 155 | /* scan int */ |
148 | 156 | break; | |
149 | } | 157 | case 7: |
150 | else if(!byte_diff(c,8,"numwant=")) | 158 | if(!byte_diff(c,7,"numwant")) |
151 | { | 159 | /* scan int */ |
152 | 160 | else if(!byte_diff(c,7,"compact")) | |
153 | } | 161 | /* scan flag */ |
154 | else if(!byte_diff(c,8,"compact=")) | 162 | break; |
155 | { | 163 | case 9: /* info_hash */ |
156 | 164 | if(!byte_diff(c,9,"info_hash")) | |
157 | } | 165 | /* scan 20 bytes */ |
158 | else if(!byte_diff(c,5,"port=")) | 166 | break; |
159 | { | 167 | } |
160 | 168 | } | |
161 | } | 169 | break; |
162 | else if(!byte_diff(c,5,"left=")) | 170 | default: /* neither scrape nor announce */ |
163 | { | 171 | httperror(h,"404 Not Found","No such file or directory."); |
164 | 172 | goto e404; | |
165 | } | 173 | } |
166 | 174 | ||
167 | while( *++c!=' ' && *c!='&'); | 175 | c=h->hdrbuf=(char*)malloc(500); |
168 | } | 176 | c+=fmt_str(c,"HTTP/1.1 Coming Up\r\nContent-Type: text/plain"); |
169 | } | 177 | c+=fmt_str(c,"\r\nContent-Length: "); |
170 | else if (!byte_diff(c,7,"scrape?")) | 178 | /* ANSWER SIZE*/ |
171 | { | 179 | c+=fmt_ulonglong(c,s.st_size); |
172 | 180 | c+=fmt_str(c,"\r\nLast-Modified: "); | |
173 | } | 181 | /* MODIFY DATE */ |
174 | else | 182 | c+=fmt_httpdate(c,s.st_mtime); |
175 | { | 183 | c+=fmt_str(c,"\r\nConnection: close\r\n\r\n"); |
176 | httperror(h,"404 Not Found","No such file or directory."); | 184 | iob_addbuf(&h->iob,h->hdrbuf,c - h->hdrbuf); |
177 | goto e404; | 185 | iob_addbuf(&h->iob,tracker_answer, tzracker_answer_size); |
178 | } | 186 | } |
179 | |||
180 | c=h->hdrbuf=(char*)malloc(500); | ||
181 | c+=fmt_str(c,"HTTP/1.1 Coming Up\r\nContent-Type: text/plain"); | ||
182 | c+=fmt_str(c,"\r\nContent-Length: "); | ||
183 | /* ANSWER SIZE*/ | ||
184 | c+=fmt_ulonglong(c,s.st_size); | ||
185 | c+=fmt_str(c,"\r\nLast-Modified: "); | ||
186 | /* MODIFY DATE */ | ||
187 | c+=fmt_httpdate(c,s.st_mtime); | ||
188 | c+=fmt_str(c,"\r\nConnection: close\r\n\r\n"); | ||
189 | iob_addbuf(&h->iob,h->hdrbuf,c - h->hdrbuf); | ||
190 | iob_addbuf(&h->iob,tracker_answer, tzracker_answer_size); | ||
191 | } | ||
192 | e404: | 187 | e404: |
193 | io_dontwantread(s); | 188 | io_dontwantread(s); |
194 | io_wantwrite(s); | 189 | io_wantwrite(s); |
195 | } | 190 | } |
196 | 191 | ||
197 | int main() | 192 | int main() |
198 | { | 193 | { |
199 | int s=socket_tcp6(); | 194 | int s=socket_tcp6(); |
200 | uint32 scope_id; | 195 | uint32 scope_id; |
201 | char ip[16]; | 196 | char ip[16]; |
202 | uint16 port; | 197 | uint16 port; |
203 | 198 | ||
204 | if (socket_bind6_reuse(s,V6any,8000,0)==-1) | 199 | if (socket_bind6_reuse(s,V6any,8000,0)==-1) |
205 | panic("socket_bind6_reuse"); | 200 | panic("socket_bind6_reuse"); |
206 | 201 | ||
207 | if (socket_listen(s,16)==-1) | 202 | if (socket_listen(s,16)==-1) |
208 | panic("socket_listen"); | 203 | panic("socket_listen"); |
209 | 204 | ||
210 | if (!io_fd(s)) | 205 | if (!io_fd(s)) |
211 | panic("io_fd"); | 206 | panic("io_fd"); |
212 | 207 | ||
213 | io_wantread(s); | 208 | io_wantread(s); |
214 | 209 | ||
215 | for (;;) | 210 | for (;;) |
216 | { | 211 | { |
217 | int64 i; | 212 | int64 i; |
218 | io_wait(); | 213 | io_wait(); |
219 | 214 | ||
220 | while ((i=io_canread())!=-1) | 215 | while ((i=io_canread())!=-1) |
221 | { | 216 | { |
222 | if (i==s) // ist es der serversocket? | 217 | if (i==s) // ist es der serversocket? |
223 | { | 218 | { |
224 | int n; | 219 | int n; |
225 | while ((n=socket_accept6(s,ip,&port,&scope_id))!=-1) | 220 | while ((n=socket_accept6(s,ip,&port,&scope_id))!=-1) |
226 | { | 221 | { |
227 | if (io_fd(n)) | 222 | if (io_fd(n)) |
228 | { | 223 | { |
229 | struct http_data* h=(struct http_data*)malloc(sizeof(struct http_data)); | 224 | struct http_data* h=(struct http_data*)malloc(sizeof(struct http_data)); |
230 | io_wantread(n); | 225 | io_wantread(n); |
231 | 226 | ||
232 | if (h) | 227 | if (h) |
233 | { | 228 | { |
234 | byte_zero(h,sizeof(struct http_data)); | 229 | byte_zero(h,sizeof(struct http_data)); |
235 | byte_copy(h->ip,ip,sizeof(ip)); | 230 | byte_copy(h->ip,ip,sizeof(ip)); |
236 | io_setcookie(n,h); | 231 | io_setcookie(n,h); |
237 | } else | 232 | } else |
238 | io_close(n); | 233 | io_close(n); |
239 | } else | 234 | } else |
240 | io_close(n); | 235 | io_close(n); |
241 | buffer_putnlflush(buffer_2); | 236 | buffer_putnlflush(buffer_2); |
242 | } | 237 | } |
243 | if (errno==EAGAIN) | 238 | if (errno==EAGAIN) |
244 | io_eagain(s); | 239 | io_eagain(s); |
245 | else | 240 | else |
246 | carp("socket_accept6"); | 241 | carp("socket_accept6"); |
247 | } | 242 | } |
248 | else | 243 | else |
249 | { | 244 | { |
250 | char buf[8192]; | 245 | char buf[8192]; |
251 | struct http_data* h=io_getcookie(i); | 246 | struct http_data* h=io_getcookie(i); |
252 | 247 | ||
253 | int l=io_tryread(i,buf,sizeof buf); | 248 | int l=io_tryread(i,buf,sizeof buf); |
254 | if (l<=0) | 249 | if (l<=0) |
255 | { | 250 | { |
256 | if (h) | 251 | if (h) |
257 | { | 252 | { |
258 | array_reset(&h->r); | 253 | array_reset(&h->r); |
259 | iob_reset(&h->iob); | 254 | iob_reset(&h->iob); |
260 | free(h->hdrbuf); h->hdrbuf=0; | 255 | free(h->hdrbuf); h->hdrbuf=0; |
261 | } | 256 | } |
262 | io_close(i); | 257 | io_close(i); |
263 | } | 258 | } |
264 | else | 259 | else |
265 | { | 260 | { |
266 | array_catb(&h->r,buf,l); | 261 | array_catb(&h->r,buf,l); |
267 | 262 | ||
268 | if (array_failed(&h->r)) | 263 | if (array_failed(&h->r)) |
269 | { | 264 | { |
270 | httperror(h,"500 Server Error","request too long."); | 265 | httperror(h,"500 Server Error","request too long."); |
271 | emerge: | 266 | emerge: |
272 | io_dontwantread(i); | 267 | io_dontwantread(i); |
273 | io_wantwrite(i); | 268 | io_wantwrite(i); |
274 | } | 269 | } |
275 | else if (array_bytes(&h->r)>8192) | 270 | else if (array_bytes(&h->r)>8192) |
276 | { | 271 | { |
277 | httperror(h,"500 request too long","You sent too much headers"); | 272 | httperror(h,"500 request too long","You sent too much headers"); |
278 | goto emerge; | 273 | goto emerge; |
279 | } | 274 | } |
280 | else if ((l=header_complete(h))) | 275 | else if ((l=header_complete(h))) |
281 | { | 276 | { |
282 | httpresponse(h,i); | 277 | httpresponse(h,i); |
283 | } | 278 | } |
284 | } | 279 | } |
285 | } | 280 | } |
286 | } | 281 | } |
287 | 282 | ||
288 | while ((i=io_canwrite())!=-1) | 283 | while ((i=io_canwrite())!=-1) |
289 | { | 284 | { |
290 | struct http_data* h=io_getcookie(i); | 285 | struct http_data* h=io_getcookie(i); |
291 | 286 | ||
292 | int64 r=iob_send(i,&h->iob); | 287 | int64 r=iob_send(i,&h->iob); |
293 | 288 | ||
294 | if (r==-1) | 289 | if (r==-1) |
295 | io_eagain(i); | 290 | io_eagain(i); |
296 | else | 291 | else |
297 | if (r<=0) | 292 | if (r<=0) |
298 | { | 293 | { |
299 | array_trunc(&h->r); | 294 | array_trunc(&h->r); |
300 | iob_reset(&h->iob); | 295 | iob_reset(&h->iob); |
301 | free(h->hdrbuf); h->hdrbuf=0; | 296 | free(h->hdrbuf); h->hdrbuf=0; |
302 | io_close(i); | 297 | io_close(i); |
303 | } | 298 | } |
304 | } | 299 | } |
305 | } | 300 | } |
306 | return 0; | 301 | return 0; |
307 | } | 302 | } |