Mercurial > urweb
comparison src/c/http.c @ 2071:739172204214
Introduce recv timeout controlled by '-T' option in http.c
This should prevent a DDoS attack where attacker and keeps the connection open
but send no data.
author | Sergey Mironov <grrwlf@gmail.com> |
---|---|
date | Tue, 02 Sep 2014 17:42:10 +0000 |
parents | 382911d72e63 |
children | 1839df6ed755 |
comparison
equal
deleted
inserted
replaced
2070:382911d72e63 | 2071:739172204214 |
---|---|
114 body = strstr(buf, "\r\n\r\n"); | 114 body = strstr(buf, "\r\n\r\n"); |
115 if (body == NULL) { | 115 if (body == NULL) { |
116 r = recv(sock, back, buf_size - 1 - (back - buf), 0); | 116 r = recv(sock, back, buf_size - 1 - (back - buf), 0); |
117 | 117 |
118 if (r < 0) { | 118 if (r < 0) { |
119 qfprintf(stderr, "Recv failed while receiving header\n"); | 119 qfprintf(stderr, "Recv failed while receiving header, retcode %d errno %m\n", r); |
120 close(sock); | 120 close(sock); |
121 sock = 0; | 121 sock = 0; |
122 break; | 122 break; |
123 } | 123 } |
124 | 124 |
171 } | 171 } |
172 | 172 |
173 r = recv(sock, back, buf_size - 1 - (back - buf), 0); | 173 r = recv(sock, back, buf_size - 1 - (back - buf), 0); |
174 | 174 |
175 if (r < 0) { | 175 if (r < 0) { |
176 qfprintf(stderr, "Recv failed\n"); | 176 qfprintf(stderr, "Recv failed while receiving content, retcode %d errno %m\n", r); |
177 close(sock); | 177 close(sock); |
178 sock = 0; | 178 sock = 0; |
179 goto done; | 179 goto done; |
180 } | 180 } |
181 | 181 |
310 | 310 |
311 return NULL; | 311 return NULL; |
312 } | 312 } |
313 | 313 |
314 static void help(char *cmd) { | 314 static void help(char *cmd) { |
315 printf("Usage: %s [-p <port>] [-a <IP address>] [-t <thread count>] [-k] [-q]\nThe '-k' option turns on HTTP keepalive.\nThe '-q' option turns off some chatter on stdout.\n", cmd); | 315 printf("Usage: %s [-p <port>] [-a <IP address>] [-t <thread count>] [-k] [-q] [-T SEC]\nThe '-k' option turns on HTTP keepalive.\nThe '-q' option turns off some chatter on stdout.\nThe -T option sets socket recv timeout (0 disables timeout, default is 5 sec)", cmd); |
316 } | 316 } |
317 | 317 |
318 static void sigint(int signum) { | 318 static void sigint(int signum) { |
319 printf("Exiting....\n"); | 319 printf("Exiting....\n"); |
320 exit(0); | 320 exit(0); |
325 int sockfd; // listen on sock_fd | 325 int sockfd; // listen on sock_fd |
326 struct sockaddr_in my_addr; | 326 struct sockaddr_in my_addr; |
327 struct sockaddr_in their_addr; // connector's address information | 327 struct sockaddr_in their_addr; // connector's address information |
328 socklen_t sin_size; | 328 socklen_t sin_size; |
329 int yes = 1, uw_port = 8080, nthreads = 1, i, *names, opt; | 329 int yes = 1, uw_port = 8080, nthreads = 1, i, *names, opt; |
330 int recv_timeout_sec = 5; | |
330 | 331 |
331 signal(SIGINT, sigint); | 332 signal(SIGINT, sigint); |
332 signal(SIGPIPE, SIG_IGN); | 333 signal(SIGPIPE, SIG_IGN); |
333 | 334 |
334 my_addr.sin_addr.s_addr = INADDR_ANY; // auto-fill with my IP | 335 my_addr.sin_addr.s_addr = INADDR_ANY; // auto-fill with my IP |
335 memset(my_addr.sin_zero, '\0', sizeof my_addr.sin_zero); | 336 memset(my_addr.sin_zero, '\0', sizeof my_addr.sin_zero); |
336 | 337 |
337 while ((opt = getopt(argc, argv, "hp:a:t:kq")) != -1) { | 338 while ((opt = getopt(argc, argv, "hp:a:t:kqT:")) != -1) { |
338 switch (opt) { | 339 switch (opt) { |
339 case '?': | 340 case '?': |
340 fprintf(stderr, "Unknown command-line option\n"); | 341 fprintf(stderr, "Unknown command-line option\n"); |
341 help(argv[0]); | 342 help(argv[0]); |
342 return 1; | 343 return 1; |
373 | 374 |
374 case 'k': | 375 case 'k': |
375 keepalive = 1; | 376 keepalive = 1; |
376 break; | 377 break; |
377 | 378 |
379 case 'T': | |
380 recv_timeout_sec = atoi(optarg); | |
381 if (recv_timeout_sec < 0) { | |
382 fprintf(stderr, "Invalid recv timeout\n"); | |
383 help(argv[0]); | |
384 return 1; | |
385 } | |
386 break; | |
387 | |
378 case 'q': | 388 case 'q': |
379 quiet = 1; | 389 quiet = 1; |
380 break; | 390 break; |
381 | 391 |
382 default: | 392 default: |
451 if (keepalive) { | 461 if (keepalive) { |
452 int flag = 1; | 462 int flag = 1; |
453 setsockopt(new_fd, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int)); | 463 setsockopt(new_fd, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int)); |
454 } | 464 } |
455 | 465 |
466 if(recv_timeout_sec>0) { | |
467 int ret; | |
468 struct timeval tv; | |
469 memset(&tv, 0, sizeof(struct timeval)); | |
470 tv.tv_sec = recv_timeout_sec; | |
471 ret = setsockopt(new_fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(struct timeval)); | |
472 if(ret != 0) { | |
473 qfprintf(stderr, "Timeout setting failed, errcode %d errno '%m'\n", ret); | |
474 } | |
475 } | |
476 | |
456 uw_enqueue(new_fd); | 477 uw_enqueue(new_fd); |
457 } | 478 } |
458 } | 479 } |
459 } | 480 } |
460 | 481 |