Browse code

- switched to much better tcp timers (performance increase especially with tesn of thousands of active tcp connections)

Andrei Pelinescu-Onciul authored on 27/11/2007 07:23:27
Showing 5 changed files
... ...
@@ -77,7 +77,7 @@ MAIN_NAME=ser
77 77
 VERSION = 2
78 78
 PATCHLEVEL = 1
79 79
 SUBLEVEL =  0
80
-EXTRAVERSION = -dev12
80
+EXTRAVERSION = -dev13
81 81
 
82 82
 SER_VER = $(shell expr $(VERSION) \* 1000000 + $(PATCHLEVEL) \* 1000 + \
83 83
 			$(SUBLEVEL) )
... ...
@@ -37,6 +37,9 @@
37 37
 #ifndef _local_timer_h
38 38
 #define _local_timer_h
39 39
 
40
+#include "timer_ticks.h"
41
+#include "timer_funcs.h"
42
+
40 43
 
41 44
 struct local_timer {
42 45
 	/* private timer information */
... ...
@@ -33,6 +33,7 @@
33 33
  *  2006-10-13  added tcp_req_states for STUN (vlada)
34 34
  *  2007-07-26  improved tcp connection hash function; increased aliases
35 35
  *               hash size (andrei)
36
+ *  2007-11-26  switched to local_timer (andrei)
36 37
  */
37 38
 
38 39
 
... ...
@@ -44,6 +45,7 @@
44 44
 #include "locking.h"
45 45
 #include "atomic_ops.h"
46 46
 #include "timer_ticks.h"
47
+#include "timer.h"
47 48
 
48 49
 /* maximum number of port aliases x search wildcard possibilities */
49 50
 #define TCP_CON_MAX_ALIASES (4*3) 
... ...
@@ -64,6 +66,7 @@
64 64
 /* tcp connection flags */
65 65
 #define F_CONN_NON_BLOCKING 1
66 66
 #define F_CONN_REMOVED      2 /* no longer  in "main" listen fd list */
67
+#define F_CONN_READER       4 /* handled by a tcp reader */
67 68
 
68 69
 
69 70
 enum tcp_req_errors {	TCP_REQ_INIT, TCP_REQ_OK, TCP_READ_ERROR,
... ...
@@ -132,6 +135,7 @@ struct tcp_connection{
132 132
 	int flags; /* connection related flags */
133 133
 	enum tcp_conn_states state; /* connection state */
134 134
 	void* extra_data; /* extra data associated to the connection, 0 for tcp*/
135
+	struct timer_ln timer;
135 136
 	unsigned int timeout;/* connection timeout, after this it will be removed*/
136 137
 	unsigned id_hash; /* hash index in the id_hash */
137 138
 	struct tcp_connection* id_next; /* next, prev in id hash table */
... ...
@@ -83,6 +83,7 @@
83 83
  *               connect/ new sockets (andrei)
84 84
  *  2007-11-22  always add the connection & clear the coresponding flags before
85 85
  *               io_watch_add-ing its fd - it's safer this way (andrei)
86
+ *  2007-11-26  improved tcp timers: switched to local_timer (andrei)
86 87
  */
87 88
 
88 89
 
... ...
@@ -130,6 +131,7 @@
130 130
 #include "tcp_init.h"
131 131
 #include "tsend.h"
132 132
 #include "timer_ticks.h"
133
+#include "local_timer.h"
133 134
 #ifdef CORE_TLS
134 135
 #include "tls/tls_server.h"
135 136
 #define tls_loaded() 1
... ...
@@ -167,8 +169,9 @@
167 167
 
168 168
 /* maximum accepted lifetime (maximum possible is  ~ MAXINT/2) */
169 169
 #define MAX_TCP_CON_LIFETIME	((1U<<(sizeof(ticks_t)*8-1))-1)
170
-/* minimum interval tcpconn_timeout() is allowed to run, in ticks */
171
-#define TCPCONN_TIMEOUT_MIN_RUN S_TO_TICKS(1)  /* once per s */
170
+/* minimum interval local_timer_run() is allowed to run, in ticks */
171
+#define TCPCONN_TIMEOUT_MIN_RUN 1  /* once per tick */
172
+#define TCPCONN_WAIT_TIMEOUT 1 /* 1 tick */
172 173
 
173 174
 enum fd_types { F_NONE, F_SOCKINFO /* a tcp_listen fd */,
174 175
 				F_TCPCONN, F_TCPCHILD, F_PROC };
... ...
@@ -213,8 +216,11 @@ static int tcp_proto_no=-1; /* tcp protocol number as returned by
213 213
 
214 214
 static io_wait_h io_h;
215 215
 
216
+static struct local_timer tcp_main_ltimer;
216 217
 
217 218
 
219
+static ticks_t tcpconn_main_timeout(ticks_t , struct timer_ln* , void* );
220
+
218 221
 inline static int _tcpconn_add_alias_unsafe(struct tcp_connection* c, int port,
219 222
 										struct ip_addr* l_ip, int l_port,
220 223
 										int flags);
... ...
@@ -531,6 +537,7 @@ struct tcp_connection* tcpconn_new(int sock, union sockaddr_union* su,
531 531
 	c->rcv.src_su=*su;
532 532
 	
533 533
 	atomic_set(&c->refcnt, 0);
534
+	timer_init(&c->timer, tcpconn_main_timeout, c, 0);
534 535
 	su2ip_addr(&c->rcv.src_ip, su);
535 536
 	c->rcv.src_port=su_getport(su);
536 537
 	c->rcv.bind_address=ba;
... ...
@@ -697,8 +704,7 @@ inline static struct tcp_connection*  tcpconn_add(struct tcp_connection *c)
697 697
 }
698 698
 
699 699
 
700
-/* unsafe tcpconn_rm version (nolocks) */
701
-void _tcpconn_rm(struct tcp_connection* c)
700
+static inline void _tcpconn_detach(struct tcp_connection *c)
702 701
 {
703 702
 	int r;
704 703
 	tcpconn_listrm(tcpconn_id_hash[c->id_hash], c, id_next, id_prev);
... ...
@@ -706,15 +712,30 @@ void _tcpconn_rm(struct tcp_connection* c)
706 706
 	for (r=0; r<c->aliases; r++)
707 707
 		tcpconn_listrm(tcpconn_aliases_hash[c->con_aliases[r].hash], 
708 708
 						&c->con_aliases[r], next, prev);
709
+}
710
+
711
+
712
+
713
+static inline void _tcpconn_free(struct tcp_connection* c)
714
+{
709 715
 	lock_destroy(&c->write_lock);
710 716
 #ifdef USE_TLS
711
-	if (c->type==PROTO_TLS) tls_tcpconn_clean(c);
717
+	if (unlikely(c->type==PROTO_TLS)) tls_tcpconn_clean(c);
712 718
 #endif
713 719
 	shm_free(c);
714 720
 }
715 721
 
716 722
 
717 723
 
724
+/* unsafe tcpconn_rm version (nolocks) */
725
+void _tcpconn_rm(struct tcp_connection* c)
726
+{
727
+	_tcpconn_detach(c);
728
+	_tcpconn_free(c);
729
+}
730
+
731
+
732
+
718 733
 void tcpconn_rm(struct tcp_connection* c)
719 734
 {
720 735
 	int r;
... ...
@@ -1207,9 +1228,17 @@ error:
1207 1207
 static void tcpconn_destroy(struct tcp_connection* tcpconn)
1208 1208
 {
1209 1209
 	int fd;
1210
+	ticks_t t;
1210 1211
 
1212
+	/* always try to remove the timer to protect against tcpconn_destroy
1213
+	 *  being called several times for the same connection 
1214
+	 *  (if the timer is already removed, nothing happens) */
1215
+	if (likely(!(tcpconn->flags & F_CONN_READER)))
1216
+		local_timer_del(&tcp_main_ltimer, &tcpconn->timer);
1211 1217
 	TCPCONN_LOCK; /*avoid races w/ tcp_send*/
1212
-	if (atomic_dec_and_test(&tcpconn->refcnt)){ 
1218
+	if (likely(atomic_dec_and_test(&tcpconn->refcnt))){ 
1219
+		_tcpconn_detach(tcpconn);
1220
+		TCPCONN_UNLOCK;
1213 1221
 		DBG("tcpconn_destroy: destroying connection %p, flags %04x\n",
1214 1222
 				tcpconn, tcpconn->flags);
1215 1223
 		fd=tcpconn->s;
... ...
@@ -1218,18 +1247,26 @@ static void tcpconn_destroy(struct tcp_connection* tcpconn)
1218 1218
 		if (tcpconn->type==PROTO_TLS)
1219 1219
 			tls_close(tcpconn, fd);
1220 1220
 #endif
1221
-		_tcpconn_rm(tcpconn);
1221
+		_tcpconn_free(tcpconn);
1222 1222
 		close(fd);
1223 1223
 		(*tcp_connections_no)--;
1224 1224
 	}else{
1225
+		TCPCONN_UNLOCK;
1225 1226
 		/* force timeout */
1226
-		tcpconn->timeout=get_ticks_raw();
1227
+		t=get_ticks_raw();
1228
+		tcpconn->timeout=t+TCPCONN_WAIT_TIMEOUT;
1227 1229
 		tcpconn->state=S_CONN_BAD;
1230
+		if (!(tcpconn->flags & F_CONN_READER)){
1231
+			/* re-activate the timer only if the connection is handled
1232
+			 * by tcp_main (and not by a tcp reader)*/
1233
+			tcpconn->timer.f=tcpconn_main_timeout;
1234
+			timer_reinit(&tcpconn->timer);
1235
+			local_timer_add(&tcp_main_ltimer, &tcpconn->timer, 
1236
+									TCPCONN_WAIT_TIMEOUT, t);
1237
+		}
1228 1238
 		DBG("tcpconn_destroy: delaying (%p, flags %04x) ...\n",
1229 1239
 				tcpconn, tcpconn->flags);
1230
-		
1231 1240
 	}
1232
-	TCPCONN_UNLOCK;
1233 1241
 }
1234 1242
 
1235 1243
 
... ...
@@ -1308,7 +1345,7 @@ inline static int send_fd_queue_add(	struct tcp_send_fd_q* q,
1308 1308
 		if (new_size< MAX_SEND_FD_QUEUE_SIZE/2){
1309 1309
 			new_size*=2;
1310 1310
 		}else new_size=MAX_SEND_FD_QUEUE_SIZE;
1311
-		if (q->crt>=&q->data[new_size]){
1311
+		if (unlikely(q->crt>=&q->data[new_size])){
1312 1312
 			LOG(L_ERR, "ERROR: send_fd_queue_add: queue full: %ld/%ld\n",
1313 1313
 					(long)(q->crt-&q->data[0]-1), new_size);
1314 1314
 			goto error;
... ...
@@ -1316,7 +1353,7 @@ inline static int send_fd_queue_add(	struct tcp_send_fd_q* q,
1316 1316
 		LOG(L_CRIT, "INFO: send_fd_queue: queue full: %ld, extending to %ld\n",
1317 1317
 				(long)(q->end-&q->data[0]), new_size);
1318 1318
 		tmp=pkg_realloc(q->data, new_size*sizeof(struct send_fd_info));
1319
-		if (tmp==0){
1319
+		if (unlikely(tmp==0)){
1320 1320
 			LOG(L_ERR, "ERROR: send_fd_queue_add: out of memory\n");
1321 1321
 			goto error;
1322 1322
 		}
... ...
@@ -1342,8 +1379,8 @@ inline static void send_fd_queue_run(struct tcp_send_fd_q* q)
1342 1342
 	struct send_fd_info* t;
1343 1343
 	
1344 1344
 	for (p=t=&q->data[0]; p<q->crt; p++){
1345
-		if (send_fd(p->unix_sock, &(p->tcp_conn),
1346
-					sizeof(struct tcp_connection*), p->tcp_conn->s)<=0){
1345
+		if (unlikely(send_fd(p->unix_sock, &(p->tcp_conn),
1346
+					sizeof(struct tcp_connection*), p->tcp_conn->s)<=0)){
1347 1347
 			if ( ((errno==EAGAIN)||(errno==EWOULDBLOCK)) && 
1348 1348
 							((s_ticks_t)(p->expire-get_ticks_raw())>0)){
1349 1349
 				/* leave in queue for a future try */
... ...
@@ -1384,8 +1421,9 @@ inline static int handle_tcp_child(struct tcp_child* tcp_c, int fd_i)
1384 1384
 	long response[2];
1385 1385
 	int cmd;
1386 1386
 	int bytes;
1387
+	ticks_t t;
1387 1388
 	
1388
-	if (tcp_c->unix_sock<=0){
1389
+	if (unlikely(tcp_c->unix_sock<=0)){
1389 1390
 		/* (we can't have a fd==0, 0 is never closed )*/
1390 1391
 		LOG(L_CRIT, "BUG: handle_tcp_child: fd %d for %d "
1391 1392
 				"(pid %d, ser no %d)\n", tcp_c->unix_sock,
... ...
@@ -1395,7 +1433,7 @@ inline static int handle_tcp_child(struct tcp_child* tcp_c, int fd_i)
1395 1395
 	/* read until sizeof(response)
1396 1396
 	 * (this is a SOCK_STREAM so read is not atomic) */
1397 1397
 	bytes=recv_all(tcp_c->unix_sock, response, sizeof(response), MSG_DONTWAIT);
1398
-	if (bytes<(int)sizeof(response)){
1398
+	if (unlikely(bytes<(int)sizeof(response))){
1399 1399
 		if (bytes==0){
1400 1400
 			/* EOF -> bad, child has died */
1401 1401
 			DBG("DBG: handle_tcp_child: dead tcp child %d (pid %d, no %d)"
... ...
@@ -1432,7 +1470,7 @@ inline static int handle_tcp_child(struct tcp_child* tcp_c, int fd_i)
1432 1432
 					response[0], response[1], (int)(tcp_c-&tcp_children[0]));
1433 1433
 	cmd=response[1];
1434 1434
 	tcpconn=(struct tcp_connection*)response[0];
1435
-	if (tcpconn==0){
1435
+	if (unlikely(tcpconn==0)){
1436 1436
 		/* should never happen */
1437 1437
 		LOG(L_CRIT, "BUG: handle_tcp_child: null tcpconn pointer received"
1438 1438
 				 " from tcp child %d (pid %d): %lx, %lx\n",
... ...
@@ -1443,16 +1481,28 @@ inline static int handle_tcp_child(struct tcp_child* tcp_c, int fd_i)
1443 1443
 	switch(cmd){
1444 1444
 		case CONN_RELEASE:
1445 1445
 			tcp_c->busy--;
1446
-			if (tcpconn->state==S_CONN_BAD){ 
1446
+			if (unlikely(tcpconn->state==S_CONN_BAD)){ 
1447 1447
 				tcpconn_destroy(tcpconn);
1448 1448
 				break;
1449 1449
 			}
1450 1450
 			/* update the timeout*/
1451
-			tcpconn->timeout=get_ticks_raw()+tcp_con_lifetime;
1451
+			t=get_ticks_raw();
1452
+			tcpconn->timeout=t+tcp_con_lifetime;
1452 1453
 			tcpconn_put(tcpconn);
1454
+			/* re-activate the timer */
1455
+			tcpconn->timer.f=tcpconn_main_timeout;
1456
+			timer_reinit(&tcpconn->timer);
1457
+			local_timer_add(&tcp_main_ltimer, &tcpconn->timer, 
1458
+								tcp_con_lifetime, t);
1453 1459
 			/* must be after the de-ref*/
1454
-			tcpconn->flags&=~F_CONN_REMOVED;
1455
-			io_watch_add(&io_h, tcpconn->s, F_TCPCONN, tcpconn);
1460
+			tcpconn->flags&=~(F_CONN_REMOVED|F_CONN_READER);
1461
+			if (unlikely(
1462
+					io_watch_add(&io_h, tcpconn->s, F_TCPCONN, tcpconn)<0)){
1463
+				LOG(L_CRIT, "ERROR: tcp_main: handle_tcp_child: failed to add"
1464
+						" new socket to the fd list\n");
1465
+				tcpconn->flags|=F_CONN_REMOVED;
1466
+				tcpconn_destroy(tcpconn); /* closes also the fd */
1467
+			}
1456 1468
 			DBG("handle_tcp_child: CONN_RELEASE  %p refcnt= %d\n", 
1457 1469
 							tcpconn, atomic_get(&tcpconn->refcnt));
1458 1470
 			break;
... ...
@@ -1501,9 +1551,10 @@ inline static int handle_ser_child(struct process_table* p, int fd_i)
1501 1501
 	int bytes;
1502 1502
 	int ret;
1503 1503
 	int fd;
1504
+	ticks_t t;
1504 1505
 	
1505 1506
 	ret=-1;
1506
-	if (p->unix_sock<=0){
1507
+	if (unlikely(p->unix_sock<=0)){
1507 1508
 		/* (we can't have a fd==0, 0 is never closed )*/
1508 1509
 		LOG(L_CRIT, "BUG: handle_ser_child: fd %d for %d "
1509 1510
 				"(pid %d)\n", p->unix_sock, (int)(p-&pt[0]), p->pid);
... ...
@@ -1514,7 +1565,7 @@ inline static int handle_ser_child(struct process_table* p, int fd_i)
1514 1514
 	 * (this is a SOCK_STREAM so read is not atomic) */
1515 1515
 	bytes=receive_fd(p->unix_sock, response, sizeof(response), &fd,
1516 1516
 						MSG_DONTWAIT);
1517
-	if (bytes<(int)sizeof(response)){
1517
+	if (unlikely(bytes<(int)sizeof(response))){
1518 1518
 		/* too few bytes read */
1519 1519
 		if (bytes==0){
1520 1520
 			/* EOF -> bad, child has died */
... ...
@@ -1551,7 +1602,7 @@ inline static int handle_ser_child(struct process_table* p, int fd_i)
1551 1551
 					response[0], response[1], fd, (int)(p-&pt[0]), p->pid);
1552 1552
 	cmd=response[1];
1553 1553
 	tcpconn=(struct tcp_connection*)response[0];
1554
-	if (tcpconn==0){
1554
+	if (unlikely(tcpconn==0)){
1555 1555
 		LOG(L_CRIT, "BUG: handle_ser_child: null tcpconn pointer received"
1556 1556
 				 " from child %d (pid %d): %lx, %lx\n",
1557 1557
 				 	(int)(p-&pt[0]), p->pid, response[0], response[1]) ;
... ...
@@ -1569,8 +1620,8 @@ inline static int handle_ser_child(struct process_table* p, int fd_i)
1569 1569
 			/* send the requested FD  */
1570 1570
 			/* WARNING: take care of setting refcnt properly to
1571 1571
 			 * avoid race condition */
1572
-			if (send_fd(p->unix_sock, &tcpconn, sizeof(tcpconn),
1573
-							tcpconn->s)<=0){
1572
+			if (unlikely(send_fd(p->unix_sock, &tcpconn, sizeof(tcpconn),
1573
+								tcpconn->s)<=0)){
1574 1574
 				LOG(L_ERR, "ERROR: handle_ser_child: send_fd failed\n");
1575 1575
 			}
1576 1576
 			break;
... ...
@@ -1578,7 +1629,7 @@ inline static int handle_ser_child(struct process_table* p, int fd_i)
1578 1578
 			/* update the fd in the requested tcpconn*/
1579 1579
 			/* WARNING: take care of setting refcnt properly to
1580 1580
 			 * avoid race condition */
1581
-			if (fd==-1){
1581
+			if (unlikely(fd==-1)){
1582 1582
 				LOG(L_CRIT, "BUG: handle_ser_child: CONN_NEW:"
1583 1583
 							" no fd received\n");
1584 1584
 				break;
... ...
@@ -1588,9 +1639,19 @@ inline static int handle_ser_child(struct process_table* p, int fd_i)
1588 1588
 			/* add tcpconn to the list*/
1589 1589
 			tcpconn_add(tcpconn);
1590 1590
 			/* update the timeout*/
1591
-			tcpconn->timeout=get_ticks_raw()+tcp_con_lifetime;
1591
+			t=get_ticks_raw();
1592
+			tcpconn->timeout=t+tcp_con_lifetime;
1593
+			/* activate the timer (already properly init. in tcpconn_new() */
1594
+			local_timer_add(&tcp_main_ltimer, &tcpconn->timer, 
1595
+								tcp_con_lifetime, t);
1592 1596
 			tcpconn->flags&=~F_CONN_REMOVED;
1593
-			io_watch_add(&io_h, tcpconn->s, F_TCPCONN, tcpconn);
1597
+			if (unlikely(
1598
+					io_watch_add(&io_h, tcpconn->s, F_TCPCONN, tcpconn)<0)){
1599
+				LOG(L_CRIT, "ERROR: tcp_main: handle_ser_child: failed to add"
1600
+						" new socket to the fd list\n");
1601
+				tcpconn->flags|=F_CONN_REMOVED;
1602
+				tcpconn_destroy(tcpconn); /* closes also the fd */
1603
+			}
1594 1604
 			break;
1595 1605
 		default:
1596 1606
 			LOG(L_CRIT, "BUG: handle_ser_child: unknown cmd %d\n", cmd);
... ...
@@ -1630,7 +1691,7 @@ inline static int send2child(struct tcp_connection* tcpconn)
1630 1630
 	
1631 1631
 	tcp_children[idx].busy++;
1632 1632
 	tcp_children[idx].n_reqs++;
1633
-	if (min_busy){
1633
+	if (unlikely(min_busy)){
1634 1634
 		DBG("WARNING: send2child: no free tcp receiver, "
1635 1635
 				" connection passed to the least busy one (%d)\n",
1636 1636
 				min_busy);
... ...
@@ -1649,8 +1710,8 @@ inline static int send2child(struct tcp_connection* tcpconn)
1649 1649
 		
1650 1650
 #ifdef SEND_FD_QUEUE
1651 1651
 	/* if queue full, try to queue the io */
1652
-	if (send_fd(tcp_children[idx].unix_sock, &tcpconn, sizeof(tcpconn),
1653
-			tcpconn->s)<=0){
1652
+	if (unlikely(send_fd(tcp_children[idx].unix_sock, &tcpconn,
1653
+							sizeof(tcpconn), tcpconn->s)<=0)){
1654 1654
 		if ((errno==EAGAIN)||(errno==EWOULDBLOCK)){
1655 1655
 			/* FIXME: remove after debugging */
1656 1656
 			 LOG(L_CRIT, "INFO: tcp child %d, socket %d: queue full,"
... ...
@@ -1668,8 +1729,8 @@ inline static int send2child(struct tcp_connection* tcpconn)
1668 1668
 		}
1669 1669
 	}
1670 1670
 #else
1671
-	if (send_fd(tcp_children[idx].unix_sock, &tcpconn, sizeof(tcpconn),
1672
-			tcpconn->s)<=0){
1671
+	if (unlikely(send_fd(tcp_children[idx].unix_sock, &tcpconn,
1672
+						sizeof(tcpconn), tcpconn->s)<=0)){
1673 1673
 		LOG(L_ERR, "ERROR: send2child: send_fd failed\n");
1674 1674
 		return -1;
1675 1675
 	}
... ...
@@ -1700,20 +1761,20 @@ static inline int handle_new_connect(struct socket_info* si)
1700 1700
 	/* got a connection on r */
1701 1701
 	su_len=sizeof(su);
1702 1702
 	new_sock=accept(si->socket, &(su.s), &su_len);
1703
-	if (new_sock==-1){
1703
+	if (unlikely(new_sock==-1)){
1704 1704
 		if ((errno==EAGAIN)||(errno==EWOULDBLOCK))
1705 1705
 			return 0;
1706 1706
 		LOG(L_ERR,  "WARNING: handle_new_connect: error while accepting"
1707 1707
 				" connection(%d): %s\n", errno, strerror(errno));
1708 1708
 		return -1;
1709 1709
 	}
1710
-	if (*tcp_connections_no>=tcp_max_connections){
1710
+	if (unlikely(*tcp_connections_no>=tcp_max_connections)){
1711 1711
 		LOG(L_ERR, "ERROR: maximum number of connections exceeded: %d/%d\n",
1712 1712
 					*tcp_connections_no, tcp_max_connections);
1713 1713
 		close(new_sock);
1714 1714
 		return 1; /* success, because the accept was succesfull */
1715 1715
 	}
1716
-	if (init_sock_opt_accept(new_sock)<0){
1716
+	if (unlikely(init_sock_opt_accept(new_sock)<0)){
1717 1717
 		LOG(L_ERR, "ERROR: handle_new_connect: init_sock_opt failed\n");
1718 1718
 		close(new_sock);
1719 1719
 		return 1; /* success, because the accept was succesfull */
... ...
@@ -1721,7 +1782,7 @@ static inline int handle_new_connect(struct socket_info* si)
1721 1721
 	(*tcp_connections_no)++;
1722 1722
 	
1723 1723
 	dst_su=&si->su;
1724
-	if (si->flags & SI_IS_ANY){
1724
+	if (unlikely(si->flags & SI_IS_ANY)){
1725 1725
 		/* INADDR_ANY => get local dst */
1726 1726
 		sock_name_len=sizeof(sock_name);
1727 1727
 		if (getsockname(new_sock, &sock_name.s, &sock_name_len)!=0){
... ...
@@ -1735,11 +1796,19 @@ static inline int handle_new_connect(struct socket_info* si)
1735 1735
 	}
1736 1736
 	/* add socket to list */
1737 1737
 	tcpconn=tcpconn_new(new_sock, &su, dst_su, si, si->proto, S_CONN_ACCEPT);
1738
-	if (tcpconn){
1738
+	if (likely(tcpconn)){
1739 1739
 #ifdef TCP_PASS_NEW_CONNECTION_ON_DATA
1740 1740
 		tcpconn_add(tcpconn);
1741
+		/* activate the timer */
1742
+		local_timer_add(&tcp_main_ltimer, &tcpconn->timer, 
1743
+								tcp_con_lifetime, get_ticks_raw());
1741 1744
 		tcpconn->flags&=~F_CONN_REMOVED;
1742
-		io_watch_add(&io_h, tcpconn->s, F_TCPCONN, tcpconn);
1745
+		if (unlikely(io_watch_add(&io_h, tcpconn->s, F_TCPCONN, tcpconn)<0)){
1746
+			LOG(L_CRIT, "ERROR: tcp_main: handle_new_connect: failed to add"
1747
+						" new socket to the fd list\n");
1748
+			tcpconn->flags|=F_CONN_REMOVED;
1749
+			tcpconn_destroy(tcpconn); /* closes also the fd */
1750
+		}
1743 1751
 #else
1744 1752
 		atomic_set(&tcpconn->refcnt, 1); /* safe, not yet available to the
1745 1753
 											outside world */
... ...
@@ -1747,7 +1816,8 @@ static inline int handle_new_connect(struct socket_info* si)
1747 1747
 		DBG("handle_new_connect: new connection: %p %d flags: %04x\n",
1748 1748
 			tcpconn, tcpconn->s, tcpconn->flags);
1749 1749
 		/* pass it to a child */
1750
-		if(send2child(tcpconn)<0){
1750
+		tcpconn->flags|=F_CONN_READER;
1751
+		if(unlikely(send2child(tcpconn)<0)){
1751 1752
 			LOG(L_ERR,"ERROR: handle_new_connect: no children "
1752 1753
 					"available\n");
1753 1754
 			tcpconn_destroy(tcpconn);
... ...
@@ -1793,12 +1863,14 @@ inline static int handle_tcpconn_ev(struct tcp_connection* tcpconn, int fd_i)
1793 1793
 		return -1;
1794 1794
 	}
1795 1795
 #endif
1796
-	/* pass it to child, so remove it from the io watch list */
1796
+	/* pass it to child, so remove it from the io watch list  and the local
1797
+	 *  timer */
1797 1798
 	DBG("handle_tcpconn_ev: data available on %p %d\n", tcpconn, tcpconn->s);
1798
-	if (io_watch_del(&io_h, tcpconn->s, fd_i, 0)==-1) goto error;
1799
-	tcpconn->flags|=F_CONN_REMOVED;
1799
+	if (unlikely(io_watch_del(&io_h, tcpconn->s, fd_i, 0)==-1)) goto error;
1800
+	tcpconn->flags|=F_CONN_REMOVED|F_CONN_READER;
1801
+	local_timer_del(&tcp_main_ltimer, &tcpconn->timer);
1800 1802
 	tcpconn_ref(tcpconn); /* refcnt ++ */
1801
-	if (send2child(tcpconn)<0){
1803
+	if (unlikely(send2child(tcpconn)<0)){
1802 1804
 		LOG(L_ERR,"ERROR: handle_tcpconn_ev: no children available\n");
1803 1805
 		tcpconn_destroy(tcpconn);
1804 1806
 	}
... ...
@@ -1855,40 +1927,91 @@ error:
1855 1855
 
1856 1856
 
1857 1857
 
1858
-/* very inefficient for now - FIXME
1859
- * keep in sync with tcpconn_destroy, the "delete" part should be
1858
+/* timer handler for tcpconnection handled by tcp_main */
1859
+static ticks_t tcpconn_main_timeout(ticks_t t, struct timer_ln* tl, void* data)
1860
+{
1861
+	struct tcp_connection *c;
1862
+	int fd;
1863
+	
1864
+	c=(struct tcp_connection*)data; 
1865
+	/* or (struct tcp...*)(tl-offset(c->timer)) */
1866
+	
1867
+	if (TICKS_LT(t, c->timeout)){
1868
+		/* timeout extended, exit */
1869
+		return (ticks_t)(c->timeout - t);
1870
+	}
1871
+	if (likely(atomic_get(&c->refcnt)==0)){
1872
+		TCPCONN_LOCK;
1873
+			/* check again to avoid races with tcp_send() */
1874
+			if (likely(atomic_get(&c->refcnt)==0)){
1875
+				/* delete */
1876
+				_tcpconn_detach(c);
1877
+				TCPCONN_UNLOCK; /* unlock as soon as possible */
1878
+				fd=c->s;
1879
+				if (likely(fd>0)){
1880
+					if (likely(!(c->flags & F_CONN_REMOVED))){
1881
+						io_watch_del(&io_h, fd, -1, IO_FD_CLOSING);
1882
+						c->flags|=F_CONN_REMOVED;
1883
+					}
1884
+#ifdef USE_TLS
1885
+					if (unlikely(c->type==PROTO_TLS ))
1886
+						tls_close(c, fd);
1887
+#endif /* USE_TLS */
1888
+					_tcpconn_free(c);
1889
+					close(fd);
1890
+				}
1891
+				(*tcp_connections_no)--; /* modified only in tcp_main
1892
+											 => no lock needed */
1893
+				return 0; /* don't prolong the timer anymore */
1894
+			}
1895
+		TCPCONN_UNLOCK;
1896
+	}
1897
+	/* if we are here we can't delete the connection, it's still referenced
1898
+	 *  => we just delay deleting it */
1899
+	return TCPCONN_WAIT_TIMEOUT;
1900
+}
1901
+
1902
+
1903
+
1904
+static inline void tcp_timer_run()
1905
+{
1906
+	ticks_t ticks;
1907
+	static ticks_t prev_ticks=0;
1908
+	
1909
+	ticks=get_ticks_raw();
1910
+	if (unlikely((ticks-prev_ticks)<TCPCONN_TIMEOUT_MIN_RUN)) return;
1911
+	prev_ticks=ticks;
1912
+	local_timer_run(&tcp_main_ltimer, ticks);
1913
+}
1914
+
1915
+
1916
+
1917
+/* keep in sync with tcpconn_destroy, the "delete" part should be
1860 1918
  * the same except for io_watch_del..
1861
- * Note: this function is called only from the tcp_main process with 1 
1862
- * exception: on shutdown it's called also by the main ser process via
1863
- * cleanup() => with the ser shutdown exception, it cannot execute in parallel
1919
+ * Note: this function is called only on shutdown by the main ser process via
1920
+ * cleanup(). However it's also safe to call it from the tcp_main process.
1921
+ * => with the ser shutdown exception, it cannot execute in parallel
1864 1922
  * with tcpconn_add() or tcpconn_destroy()*/
1865
-static inline void tcpconn_timeout(int force)
1923
+static inline void tcpconn_destroy_all()
1866 1924
 {
1867
-	static ticks_t prev_ticks=0;
1868 1925
 	struct tcp_connection *c, *next;
1869
-	ticks_t ticks;
1870 1926
 	unsigned h;
1871 1927
 	int fd;
1872 1928
 	
1873 1929
 	
1874
-	ticks=get_ticks_raw();
1875
-	if (((ticks-prev_ticks)<TCPCONN_TIMEOUT_MIN_RUN) && !force) return;
1876
-	prev_ticks=ticks;
1877
-	TCPCONN_LOCK; /* fixme: we can lock only on delete IMO */
1930
+	TCPCONN_LOCK; 
1878 1931
 	for(h=0; h<TCP_ID_HASH_SIZE; h++){
1879 1932
 		c=tcpconn_id_hash[h];
1880 1933
 		while(c){
1881 1934
 			next=c->id_next;
1882
-			if (force ||((atomic_get(&c->refcnt)==0) &&
1883
-						((s_ticks_t)(ticks-c->timeout)>=0))){
1884
-				if (!force)
1885
-					DBG("tcpconn_timeout: timeout for hash=%d - %p"
1886
-							" (%d > %d)\n", h, c, ticks, c->timeout);
1887
-				if (c->s>0 && is_tcp_main){
1935
+				if (is_tcp_main){
1888 1936
 					/* we cannot close or remove the fd if we are not in the
1889 1937
 					 * tcp main proc.*/
1938
+					if (!(c->flags & F_CONN_READER))
1939
+						local_timer_del(&tcp_main_ltimer, &c->timer);
1940
+					/* else still in some reader */
1890 1941
 					fd=c->s;
1891
-					if (!(c->flags & F_CONN_REMOVED)){
1942
+					if (fd>0 && !(c->flags & F_CONN_REMOVED)){
1892 1943
 						io_watch_del(&io_h, fd, -1, IO_FD_CLOSING);
1893 1944
 						c->flags|=F_CONN_REMOVED;
1894 1945
 					}
... ...
@@ -1896,7 +2019,7 @@ static inline void tcpconn_timeout(int force)
1896 1896
 					fd=-1;
1897 1897
 				}
1898 1898
 #ifdef USE_TLS
1899
-				if (c->type==PROTO_TLS)
1899
+				if (fd>0 && c->type==PROTO_TLS)
1900 1900
 					tls_close(c, fd);
1901 1901
 #endif
1902 1902
 				_tcpconn_rm(c);
... ...
@@ -1904,7 +2027,6 @@ static inline void tcpconn_timeout(int force)
1904 1904
 					close(fd);
1905 1905
 				}
1906 1906
 				(*tcp_connections_no)--;
1907
-			}
1908 1907
 			c=next;
1909 1908
 		}
1910 1909
 	}
... ...
@@ -1994,7 +2116,7 @@ void tcp_main_loop()
1994 1994
 				io_wait_loop_poll(&io_h, TCP_MAIN_SELECT_TIMEOUT, 0); 
1995 1995
 				send_fd_queue_run(&send2child_q); /* then new io */
1996 1996
 				/* remove old connections */
1997
-				tcpconn_timeout(0);
1997
+				tcp_timer_run();
1998 1998
 			}
1999 1999
 			break;
2000 2000
 #ifdef HAVE_SELECT
... ...
@@ -2002,7 +2124,7 @@ void tcp_main_loop()
2002 2002
 			while(1){
2003 2003
 				io_wait_loop_select(&io_h, TCP_MAIN_SELECT_TIMEOUT, 0);
2004 2004
 				send_fd_queue_run(&send2child_q); /* then new io */
2005
-				tcpconn_timeout(0);
2005
+				tcp_timer_run();
2006 2006
 			}
2007 2007
 			break;
2008 2008
 #endif
... ...
@@ -2011,7 +2133,7 @@ void tcp_main_loop()
2011 2011
 			while(1){
2012 2012
 				io_wait_loop_sigio_rt(&io_h, TCP_MAIN_SELECT_TIMEOUT);
2013 2013
 				send_fd_queue_run(&send2child_q); /* then new io */
2014
-				tcpconn_timeout(0);
2014
+				tcp_timer_run();
2015 2015
 			}
2016 2016
 			break;
2017 2017
 #endif
... ...
@@ -2020,14 +2142,14 @@ void tcp_main_loop()
2020 2020
 			while(1){
2021 2021
 				io_wait_loop_epoll(&io_h, TCP_MAIN_SELECT_TIMEOUT, 0);
2022 2022
 				send_fd_queue_run(&send2child_q); /* then new io */
2023
-				tcpconn_timeout(0);
2023
+				tcp_timer_run();
2024 2024
 			}
2025 2025
 			break;
2026 2026
 		case POLL_EPOLL_ET:
2027 2027
 			while(1){
2028 2028
 				io_wait_loop_epoll(&io_h, TCP_MAIN_SELECT_TIMEOUT, 1);
2029 2029
 				send_fd_queue_run(&send2child_q); /* then new io */
2030
-				tcpconn_timeout(0);
2030
+				tcp_timer_run();
2031 2031
 			}
2032 2032
 			break;
2033 2033
 #endif
... ...
@@ -2036,7 +2158,7 @@ void tcp_main_loop()
2036 2036
 			while(1){
2037 2037
 				io_wait_loop_kqueue(&io_h, TCP_MAIN_SELECT_TIMEOUT, 0);
2038 2038
 				send_fd_queue_run(&send2child_q); /* then new io */
2039
-				tcpconn_timeout(0);
2039
+				tcp_timer_run();
2040 2040
 			}
2041 2041
 			break;
2042 2042
 #endif
... ...
@@ -2045,7 +2167,7 @@ void tcp_main_loop()
2045 2045
 			while(1){
2046 2046
 				io_wait_loop_devpoll(&io_h, TCP_MAIN_SELECT_TIMEOUT, 0);
2047 2047
 				send_fd_queue_run(&send2child_q); /* then new io */
2048
-				tcpconn_timeout(0);
2048
+				tcp_timer_run();
2049 2049
 			}
2050 2050
 			break;
2051 2051
 #endif
... ...
@@ -2075,7 +2197,7 @@ void destroy_tcp()
2075 2075
 								   some process was terminated while holding 
2076 2076
 								   it; this will allow an almost gracious 
2077 2077
 								   shutdown */
2078
-			tcpconn_timeout(1); /* force close/expire for all active tcpconns*/
2078
+			tcpconn_destroy_all(); 
2079 2079
 			shm_free(tcpconn_id_hash);
2080 2080
 			tcpconn_id_hash=0;
2081 2081
 		}
... ...
@@ -2100,6 +2222,7 @@ void destroy_tcp()
2100 2100
 			pkg_free(tcp_children);
2101 2101
 			tcp_children=0;
2102 2102
 		}
2103
+		destroy_local_timer(&tcp_main_ltimer);
2103 2104
 }
2104 2105
 
2105 2106
 
... ...
@@ -2189,6 +2312,11 @@ int init_tcp()
2189 2189
 					poll_method_name(tcp_poll_method));
2190 2190
 	}
2191 2191
 	
2192
+	if (init_local_timer(&tcp_main_ltimer, get_ticks_raw())!=0){
2193
+		LOG(L_ERR, "ERROR: init_tcp: failed to init local timer\n");
2194
+		goto error;
2195
+	}
2196
+	
2192 2197
 	return 0;
2193 2198
 error:
2194 2199
 	/* clean-up */
... ...
@@ -37,6 +37,7 @@
37 37
  * 2006-02-03  use tsend_stream instead of send_all (andrei)
38 38
  * 2006-10-13  added STUN support - state machine for TCP (vlada)
39 39
  * 2007-02-20  fixed timeout calc. bug (andrei)
40
+ * 2007-11-26  improved tcp timers: switched to local_timer (andrei)
40 41
  */
41 42
 
42 43
 #ifdef USE_TCP
... ...
@@ -61,6 +62,7 @@
61 61
 #include "globals.h"
62 62
 #include "receive.h"
63 63
 #include "timer.h"
64
+#include "local_timer.h"
64 65
 #include "ut.h"
65 66
 #ifdef CORE_TLS
66 67
 #include "tls/tls_server.h"
... ...
@@ -80,6 +82,8 @@ int is_msg_complete(struct tcp_req* r);
80 80
 
81 81
 #endif /* USE_STUN */
82 82
 
83
+#define TCPCONN_TIMEOUT_MIN_RUN  1 /* run the timers each new tick */
84
+
83 85
 /* types used in io_wait* */
84 86
 enum fd_types { F_NONE, F_TCPMAIN, F_TCPCONN };
85 87
 
... ...
@@ -88,6 +92,8 @@ static struct tcp_connection* tcp_conn_lst=0;
88 88
 static io_wait_h io_w; /* io_wait handler*/
89 89
 static int tcpmain_sock=-1;
90 90
 
91
+static struct local_timer tcp_reader_ltimer;
92
+
91 93
 
92 94
 /* reads next available bytes
93 95
  * return number of bytes read, 0 on EOF or -1 on error,
... ...
@@ -675,146 +681,25 @@ void release_tcpconn(struct tcp_connection* c, long state, int unix_sock)
675 675
 }
676 676
 
677 677
 
678
-#ifdef DEBUG_TCP_RECEIVE
679
-/* old code known to work, kept arround for debuging */
680
-void tcp_receive_loop(int unix_sock)
678
+
679
+static ticks_t tcpconn_read_timeout(ticks_t t, struct timer_ln* tl, void* data)
681 680
 {
682
-	struct tcp_connection* list; /* list with connections in use */
683
-	struct tcp_connection* con;
684
-	struct tcp_connection* c_next;
685
-	int n;
686
-	int nfds;
687
-	int s;
688
-	long resp;
689
-	fd_set master_set;
690
-	fd_set sel_set;
691
-	int maxfd;
692
-	struct timeval timeout;
693
-	ticks_t ticks;
681
+	struct tcp_connection *c;
694 682
 	
683
+	c=(struct tcp_connection*)data; 
684
+	/* or (struct tcp...*)(tl-offset(c->timer)) */
695 685
 	
696
-	/* init */
697
-	list=con=0;
698
-	FD_ZERO(&master_set);
699
-	FD_SET(unix_sock, &master_set);
700
-	maxfd=unix_sock;
701
-	
702
-	/* listen on the unix socket for the fd */
703
-	for(;;){
704
-			timeout.tv_sec=TCP_CHILD_SELECT_TIMEOUT;
705
-			timeout.tv_usec=0;
706
-			sel_set=master_set;
707
-			nfds=select(maxfd+1, &sel_set, 0 , 0 , &timeout);
708
-#ifdef EXTRA_DEBUG
709
-			for (n=0; n<maxfd; n++){
710
-				if (FD_ISSET(n, &sel_set)) 
711
-					DBG("tcp receive: FD %d is set\n", n);
712
-			}
713
-#endif
714
-			if (nfds<0){
715
-				if (errno==EINTR) continue; /* just a signal */
716
-				/* errors */
717
-				LOG(L_ERR, "ERROR: tcp_receive_loop: select:(%d) %s\n", errno,
718
-					strerror(errno));
719
-				continue;
720
-			}
721
-			if (FD_ISSET(unix_sock, &sel_set)){
722
-				nfds--;
723
-				/* a new conn from "main" */
724
-				n=receive_fd(unix_sock, &con, sizeof(con), &s, 0);
725
-				if (n<0){
726
-					if (errno == EWOULDBLOCK || errno == EAGAIN ||
727
-							errno == EINTR){
728
-						goto skip;
729
-					}else{
730
-						LOG(L_CRIT,"BUG: tcp_receive_loop: read_fd: %s\n",
731
-							strerror(errno));
732
-						abort(); /* big error*/
733
-					}
734
-				}
735
-				DBG("received n=%d con=%p, fd=%d\n", n, con, s);
736
-				if (n==0){
737
-					LOG(L_ERR, "WARNING: tcp_receive_loop: 0 bytes read\n");
738
-					goto skip;
739
-				}
740
-				if (con==0){
741
-					LOG(L_CRIT, "BUG: tcp_receive_loop: null pointer\n");
742
-					goto skip;
743
-				}
744
-				con->fd=s;
745
-				if (s==-1) {
746
-					LOG(L_ERR, "ERROR: tcp_receive_loop: read_fd:"
747
-									"no fd read\n");
748
-					resp=CONN_ERROR;
749
-					con->state=S_CONN_BAD;
750
-					release_tcpconn(con, resp, unix_sock);
751
-					goto skip;
752
-				}
753
-				con->timeout=get_ticks_raw()+S_TO_TICKS(TCP_CHILD_TIMEOUT);
754
-				FD_SET(s, &master_set);
755
-				if (maxfd<s) maxfd=s;
756
-				if (con==list){
757
-					LOG(L_CRIT, "BUG: tcp_receive_loop: duplicate"
758
-							" connection received: %p, id %d, fd %d, refcnt %d"
759
-							" state %d (n=%d)\n", con, con->id, con->fd,
760
-							atomic_get(&con->refcnt), con->state, n);
761
-					resp=CONN_ERROR;
762
-					release_tcpconn(con, resp, unix_sock);
763
-					goto skip; /* try to recover */
764
-				}
765
-				tcpconn_listadd(list, con, c_next, c_prev);
766
-			}
767
-skip:
768
-			ticks=get_ticks_raw();
769
-			for (con=list; con ; con=c_next){
770
-				c_next=con->c_next; /* safe for removing*/
771
-#ifdef EXTRA_DEBUG
772
-				DBG("tcp receive: list fd=%d, id=%d, timeout=%d, refcnt=%d\n",
773
-						con->fd, con->id, con->timeout,
774
-						atomic_get(&con->refcnt));
775
-#endif
776
-				if (con->state<0){
777
-					/* S_CONN_BAD or S_CONN_ERROR, remove it */
778
-					resp=CONN_ERROR;
779
-					FD_CLR(con->fd, &master_set);
780
-					tcpconn_listrm(list, con, c_next, c_prev);
781
-					con->state=S_CONN_BAD;
782
-					release_tcpconn(con, resp, unix_sock);
783
-					continue;
784
-				}
785
-				if (nfds && FD_ISSET(con->fd, &sel_set)){
786
-#ifdef EXTRA_DEBUG
787
-					DBG("tcp receive: match, fd:isset\n");
788
-#endif
789
-					nfds--;
790
-					resp=tcp_read_req(con);
791
-					
792
-					if (resp<0){
793
-						FD_CLR(con->fd, &master_set);
794
-						tcpconn_listrm(list, con, c_next, c_prev);
795
-						con->state=S_CONN_BAD;
796
-						release_tcpconn(con, resp, unix_sock);
797
-					}else{
798
-						/* update timeout */
799
-						con->timeout=ticks+TCP_CHILD_TIMEOUT;
800
-					}
801
-				}else{
802
-					/* timeout */
803
-					if ((s_ticks_t)(ticks-con->timeout)>=0){
804
-						/* expired, return to "tcp main" */
805
-						DBG("tcp_receive_loop: %p expired (%d, %d)\n",
806
-								con, con->timeout, ticks);
807
-						resp=CONN_RELEASE;
808
-						FD_CLR(con->fd, &master_set);
809
-						tcpconn_listrm(list, con, c_next, c_prev);
810
-						release_tcpconn(con, resp, unix_sock);
811
-					}
812
-				}
813
-			}
814
-		
686
+	if (likely(!(c->state<0) && TICKS_LT(t, c->timeout))){
687
+		/* timeout extended, exit */
688
+		return (ticks_t)(c->timeout - t);
815 689
 	}
690
+	/* if conn->state is ERROR or BAD => force timeout too */
691
+	io_watch_del(&io_w, c->fd, -1, IO_FD_CLOSING);
692
+	tcpconn_listrm(tcp_conn_lst, c, c_next, c_prev);
693
+	release_tcpconn(c, (c->state<0)?CONN_ERROR:CONN_RELEASE, tcpmain_sock);
694
+	
695
+	return 0;
816 696
 }
817
-#else /* DEBUG_TCP_RECEIVE */
818 697
 
819 698
 
820 699
 
... ...
@@ -838,13 +723,14 @@ inline static int handle_io(struct fd_map* fm, int idx)
838 838
 	struct tcp_connection* con;
839 839
 	int s;
840 840
 	long resp;
841
+	ticks_t t;
841 842
 	
842 843
 	switch(fm->type){
843 844
 		case F_TCPMAIN:
844 845
 again:
845 846
 			ret=n=receive_fd(fm->fd, &con, sizeof(con), &s, 0);
846 847
 			DBG("received n=%d con=%p, fd=%d\n", n, con, s);
847
-			if (n<0){
848
+			if (unlikely(n<0)){
848 849
 				if (errno == EWOULDBLOCK || errno == EAGAIN){
849 850
 					ret=0;
850 851
 					break;
... ...
@@ -855,21 +741,21 @@ again:
855 855
 						abort(); /* big error*/
856 856
 				}
857 857
 			}
858
-			if (n==0){
858
+			if (unlikely(n==0)){
859 859
 				LOG(L_ERR, "WARNING: tcp_receive: handle_io: 0 bytes read\n");
860 860
 				goto error;
861 861
 			}
862
-			if (con==0){
862
+			if (unlikely(con==0)){
863 863
 					LOG(L_CRIT, "BUG: tcp_receive: handle_io null pointer\n");
864 864
 					goto error;
865 865
 			}
866 866
 			con->fd=s;
867
-			if (s==-1) {
867
+			if (unlikely(s==-1)) {
868 868
 				LOG(L_ERR, "ERROR: tcp_receive: handle_io: read_fd:"
869 869
 									"no fd read\n");
870 870
 				goto con_error;
871 871
 			}
872
-			if (con==tcp_conn_lst){
872
+			if (unlikely(con==tcp_conn_lst)){
873 873
 				LOG(L_CRIT, "BUG: tcp_receive: handle_io: duplicate"
874 874
 							" connection received: %p, id %d, fd %d, refcnt %d"
875 875
 							" state %d (n=%d)\n", con, con->id, con->fd,
... ...
@@ -882,21 +768,29 @@ again:
882 882
 			 * handle_io might decide to del. the new connection =>
883 883
 			 * must be in the list */
884 884
 			tcpconn_listadd(tcp_conn_lst, con, c_next, c_prev);
885
-			con->timeout=get_ticks_raw()+S_TO_TICKS(TCP_CHILD_TIMEOUT);
886
-			if (io_watch_add(&io_w, s, F_TCPCONN, con)<0){
885
+			t=get_ticks_raw();
886
+			con->timeout=t+S_TO_TICKS(TCP_CHILD_TIMEOUT);
887
+			/* re-activate the timer */
888
+			con->timer.f=tcpconn_read_timeout;
889
+			timer_reinit(&con->timer);
890
+			local_timer_add(&tcp_reader_ltimer, &con->timer,
891
+								S_TO_TICKS(TCP_CHILD_TIMEOUT), t);
892
+			if (unlikely(io_watch_add(&io_w, s, F_TCPCONN, con))<0){
887 893
 				LOG(L_CRIT, "ERROR: tcp_receive: handle_io: failed to add"
888 894
 						" new socket to the fd list\n");
889 895
 				tcpconn_listrm(tcp_conn_lst, con, c_next, c_prev);
896
+				local_timer_del(&tcp_reader_ltimer, &con->timer);
890 897
 				goto con_error;
891 898
 			}
892 899
 			break;
893 900
 		case F_TCPCONN:
894 901
 			con=(struct tcp_connection*)fm->data;
895 902
 			resp=tcp_read_req(con, &ret);
896
-			if (resp<0){
903
+			if (unlikely(resp<0)){
897 904
 				ret=-1; /* some error occured */
898 905
 				io_watch_del(&io_w, con->fd, idx, IO_FD_CLOSING);
899 906
 				tcpconn_listrm(tcp_conn_lst, con, c_next, c_prev);
907
+				local_timer_del(&tcp_reader_ltimer, &con->timer);
900 908
 				con->state=S_CONN_BAD;
901 909
 				release_tcpconn(con, resp, tcpmain_sock);
902 910
 			}else{
... ...
@@ -925,35 +819,15 @@ error:
925 925
 
926 926
 
927 927
 
928
-/* releases expired connections and cleans up bad ones (state<0) */
929
-static inline void tcp_receive_timeout()
928
+inline static void tcp_reader_timer_run()
930 929
 {
931
-	struct tcp_connection* con;
932
-	struct tcp_connection* next;
933 930
 	ticks_t ticks;
931
+	static ticks_t prev_ticks=0;
934 932
 	
935 933
 	ticks=get_ticks_raw();
936
-	for (con=tcp_conn_lst; con; con=next){
937
-		next=con->c_next; /* safe for removing */
938
-		if (con->state<0){   /* kill bad connections */ 
939
-			/* S_CONN_BAD or S_CONN_ERROR, remove it */
940
-			/* fd will be closed in release_tcpconn */
941
-			io_watch_del(&io_w, con->fd, -1, IO_FD_CLOSING);
942
-			tcpconn_listrm(tcp_conn_lst, con, c_next, c_prev);
943
-			con->state=S_CONN_BAD;
944
-			release_tcpconn(con, CONN_ERROR, tcpmain_sock);
945
-			continue;
946
-		}
947
-		if ((s_ticks_t)(ticks-con->timeout)>=0){
948
-			/* expired, return to "tcp main" */
949
-			DBG("tcp_receive_loop: %p expired (%d, %d)\n",
950
-					con, con->timeout, ticks);
951
-			/* fd will be closed in release_tcpconn */
952
-			io_watch_del(&io_w, con->fd, -1, IO_FD_CLOSING);
953
-			tcpconn_listrm(tcp_conn_lst, con, c_next, c_prev);
954
-			release_tcpconn(con, CONN_RELEASE, tcpmain_sock);
955
-		}
956
-	}
934
+	if (unlikely((ticks-prev_ticks)<TCPCONN_TIMEOUT_MIN_RUN)) return;
935
+	prev_ticks=ticks;
936
+	local_timer_run(&tcp_reader_ltimer, ticks);
957 937
 }
958 938
 
959 939
 
... ...
@@ -965,6 +839,8 @@ void tcp_receive_loop(int unix_sock)
965 965
 	tcpmain_sock=unix_sock; /* init com. socket */
966 966
 	if (init_io_wait(&io_w, get_max_open_fds(), tcp_poll_method)<0)
967 967
 		goto error;
968
+	if (init_local_timer(&tcp_reader_ltimer, get_ticks_raw())!=0)
969
+		goto error;
968 970
 	/* add the unix socket */
969 971
 	if (io_watch_add(&io_w, tcpmain_sock, F_TCPMAIN, 0)<0){
970 972
 		LOG(L_CRIT, "ERROR: tcp_receive_loop: init: failed to add socket "
... ...
@@ -976,14 +852,14 @@ void tcp_receive_loop(int unix_sock)
976 976
 		case POLL_POLL:
977 977
 				while(1){
978 978
 					io_wait_loop_poll(&io_w, TCP_CHILD_SELECT_TIMEOUT, 0);
979
-					tcp_receive_timeout();
979
+					tcp_reader_timer_run();
980 980
 				}
981 981
 				break;
982 982
 #ifdef HAVE_SELECT
983 983
 		case POLL_SELECT:
984 984
 			while(1){
985 985
 				io_wait_loop_select(&io_w, TCP_CHILD_SELECT_TIMEOUT, 0);
986
-				tcp_receive_timeout();
986
+				tcp_reader_timer_run();
987 987
 			}
988 988
 			break;
989 989
 #endif
... ...
@@ -991,7 +867,7 @@ void tcp_receive_loop(int unix_sock)
991 991
 		case POLL_SIGIO_RT:
992 992
 			while(1){
993 993
 				io_wait_loop_sigio_rt(&io_w, TCP_CHILD_SELECT_TIMEOUT);
994
-				tcp_receive_timeout();
994
+				tcp_reader_timer_run();
995 995
 			}
996 996
 			break;
997 997
 #endif
... ...
@@ -999,13 +875,13 @@ void tcp_receive_loop(int unix_sock)
999 999
 		case POLL_EPOLL_LT:
1000 1000
 			while(1){
1001 1001
 				io_wait_loop_epoll(&io_w, TCP_CHILD_SELECT_TIMEOUT, 0);
1002
-				tcp_receive_timeout();
1002
+				tcp_reader_timer_run();
1003 1003
 			}
1004 1004
 			break;
1005 1005
 		case POLL_EPOLL_ET:
1006 1006
 			while(1){
1007 1007
 				io_wait_loop_epoll(&io_w, TCP_CHILD_SELECT_TIMEOUT, 1);
1008
-				tcp_receive_timeout();
1008
+				tcp_reader_timer_run();
1009 1009
 			}
1010 1010
 			break;
1011 1011
 #endif
... ...
@@ -1013,7 +889,7 @@ void tcp_receive_loop(int unix_sock)
1013 1013
 		case POLL_KQUEUE:
1014 1014
 			while(1){
1015 1015
 				io_wait_loop_kqueue(&io_w, TCP_CHILD_SELECT_TIMEOUT, 0);
1016
-				tcp_receive_timeout();
1016
+				tcp_reader_timer_run();
1017 1017
 			}
1018 1018
 			break;
1019 1019
 #endif
... ...
@@ -1021,7 +897,7 @@ void tcp_receive_loop(int unix_sock)
1021 1021
 		case POLL_DEVPOLL:
1022 1022
 			while(1){
1023 1023
 				io_wait_loop_devpoll(&io_w, TCP_CHILD_SELECT_TIMEOUT, 0);
1024
-				tcp_receive_timeout();
1024
+				tcp_reader_timer_run();
1025 1025
 			}
1026 1026
 			break;
1027 1027
 #endif
... ...
@@ -1037,7 +913,7 @@ error:
1037 1037
 	exit(-1);
1038 1038
 }
1039 1039
 
1040
-#endif /* DEBUG_TCP_RECEIVE */
1040
+
1041 1041
 
1042 1042
 #ifdef USE_STUN
1043 1043
 int is_msg_complete(struct tcp_req* r)