Browse code

- tcp timeout preliminary stuff (not yet enabled)

Andrei Pelinescu-Onciul authored on 28/11/2003 18:11:03
Showing 2 changed files
... ...
@@ -46,6 +46,9 @@
46 46
 #define TCP_BUF_SIZE 65535
47 47
 #define TCP_CON_TIMEOUT 120 /* in  seconds */
48 48
 #define TCP_CON_SEND_TIMEOUT 120 /* timeout after a send */
49
+#define TCP_SEND_TIMEOUT 10 /* if a send doesn't complete in 10s, timeout */
50
+#define TCP_CONNECT_TIMEOUT 10 /* if a connect doesn't complete in this time,
51
+                                  timeout */
49 52
 #define TCP_CHILD_TIMEOUT 5 /* after 5 seconds, the child "returns" 
50 53
 							 the connection to the tcp master process */
51 54
 #define TCP_MAIN_SELECT_TIMEOUT 5 /* how often "tcp main" checks for timeout*/
... ...
@@ -50,6 +50,9 @@
50 50
  *              to/from readers/writers (andrei)
51 51
  *  2003-11-17  handle_new_connect & tcp_connect will close the 
52 52
  *              new socket if tcpconn_new return 0 (e.g. out of mem) (andrei)
53
+ *  2003-11-28  tcp_blocking_write & tcp_blocking_connect added (andrei)
54
+ *   TODO: switch to non-blocking tcp sockets, replace send & connect
55
+ *         with tcp_blocking_*
53 56
  */
54 57
 
55 58
 
... ...
@@ -480,6 +483,139 @@ void tcpconn_put(struct tcp_connection* c)
480 483
 }
481 484
 
482 485
 
486
+static int tcp_blocking_connect(int fd, const struct sockaddr *servaddr,
487
+								socklen_t addrlen)
488
+{
489
+	int n;
490
+	fd_set sel_set;
491
+	struct timeval timeout;
492
+	int ticks;
493
+	int err;
494
+	int err_len;
495
+	
496
+again:
497
+	n=connect(fd, servaddr, addrlen);
498
+	if (n==-1){
499
+		if (errno==EINTR) goto again;
500
+		if (errno!=EINPROGRESS && errno!=EALREADY){
501
+			LOG(L_ERR, "ERROR: tcp_blocking_connect: (%d) %s\n",
502
+					errno, strerror(errno));
503
+			goto error;
504
+		}
505
+	}else goto end;
506
+	
507
+	while(1){
508
+		FD_ZERO(&sel_set);
509
+		FD_SET(fd, &sel_set);
510
+		timeout.tv_sec=TCP_CONNECT_TIMEOUT;
511
+		timeout.tv_usec=0;
512
+		ticks=get_ticks();
513
+		n=select(fd+1, 0, &sel_set, 0, &timeout);
514
+		if (n<0){
515
+			if (errno==EINTR) continue;
516
+			LOG(L_ERR, "ERROR: tcp_blocking_connect: select failed: (%d) %s\n",
517
+					errno, strerror(errno));
518
+			goto error;
519
+		}else if (n==0){
520
+			/* timeout */
521
+			if (get_ticks()-ticks>=TCP_CONNECT_TIMEOUT){
522
+				LOG(L_ERR, "ERROR: tcp_blocking_connect: send timeout\n");
523
+				goto error;
524
+			}
525
+			continue;
526
+		}
527
+		if (FD_ISSET(fd, &sel_set)){
528
+			err_len=sizeof(err);
529
+			getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &err_len);
530
+			if (err==0) goto end;
531
+			if (err!=EINPROGRESS && err!=EALREADY){
532
+				LOG(L_ERR, "ERROR: tcp_blocking_connect: SO_ERROR (%d) %s\n",
533
+						err, strerror(err));
534
+				goto error;
535
+			}
536
+		}
537
+	}
538
+error:
539
+	return -1;
540
+end:
541
+	return 0;
542
+}
543
+
544
+
545
+
546
+/* blocking write even on non-blocking sockets 
547
+ * if TCP_TIMEOUT will return with error */
548
+static int tcp_blocking_write(struct tcp_connection* c, int fd, char* buf,
549
+								unsigned int len)
550
+{
551
+	int n;
552
+	fd_set sel_set;
553
+	struct timeval timeout;
554
+	int ticks;
555
+	int initial_len;
556
+	
557
+	initial_len=len;
558
+again:
559
+	/* try first without select */
560
+	if (c->state==S_CONN_CONNECT){
561
+		/* connect not finished,  try again ? */
562
+		LOG(L_CRIT, "BUG: tcp_blocking_write: connect not implemented yet\n");
563
+		goto error;
564
+	}
565
+	n=send(fd, buf, len,
566
+#ifdef HAVE_MSG_NOSIGNAL
567
+			MSG_NOSIGNAL
568
+#else
569
+			0
570
+#endif
571
+		);
572
+	if (n<0){
573
+		if (errno==EINTR)	goto again;
574
+		else if (errno!=EAGAIN && errno!=EWOULDBLOCK){
575
+			LOG(L_ERR, "tcp_blocking_write: failed to send: (%d) %s\n",
576
+					errno, strerror(errno));
577
+			goto error;
578
+		}
579
+	}else if (n<len){
580
+		/* partial write */
581
+		buf+=n;
582
+		len-=n;
583
+	}else{
584
+		/* success: full write */
585
+		goto end;
586
+	}
587
+	while(1){
588
+		FD_ZERO(&sel_set);
589
+		FD_SET(fd, &sel_set);
590
+		timeout.tv_sec=TCP_SEND_TIMEOUT;
591
+		timeout.tv_usec=0;
592
+		ticks=get_ticks();
593
+		n=select(fd+1, 0, &sel_set, 0, &timeout);
594
+		if (n<0){
595
+			if (errno==EINTR) continue; /* signal, ignore */
596
+			LOG(L_ERR, "ERROR: tcp_blocking_write: select failed: "
597
+					" (%d) %s\n", errno, strerror(errno));
598
+			goto error;
599
+		}else if (n==0){
600
+			/* timeout */
601
+			if (get_ticks()-ticks>=TCP_SEND_TIMEOUT){
602
+				LOG(L_ERR, "ERROR: tcp_blocking_write: send timeout\n");
603
+				goto error;
604
+			}
605
+			continue;
606
+		}
607
+		if (FD_ISSET(fd, &sel_set)){
608
+			/* we can write again */
609
+			goto again;
610
+		}
611
+	}
612
+error:
613
+		return -1;
614
+end:
615
+		return initial_len;
616
+}
617
+
618
+
483 619
 
484 620
 /* finds a tcpconn & sends on it */
485 621
 int tcp_send(int type, char* buf, unsigned len, union sockaddr_union* to,