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