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 45
 #include "locking.h"
45 46
 #include "atomic_ops.h"
46 47
 #include "timer_ticks.h"
48
+#include "timer.h"
47 49
 
48 50
 /* maximum number of port aliases x search wildcard possibilities */
49 51
 #define TCP_CON_MAX_ALIASES (4*3) 
... ...
@@ -64,6 +66,7 @@
64 66
 /* tcp connection flags */
65 67
 #define F_CONN_NON_BLOCKING 1
66 68
 #define F_CONN_REMOVED      2 /* no longer  in "main" listen fd list */
69
+#define F_CONN_READER       4 /* handled by a tcp reader */
67 70
 
68 71
 
69 72
 enum tcp_req_errors {	TCP_REQ_INIT, TCP_REQ_OK, TCP_READ_ERROR,
... ...
@@ -132,6 +135,7 @@ struct tcp_connection{
132 135
 	int flags; /* connection related flags */
133 136
 	enum tcp_conn_states state; /* connection state */
134 137
 	void* extra_data; /* extra data associated to the connection, 0 for tcp*/
138
+	struct timer_ln timer;
135 139
 	unsigned int timeout;/* connection timeout, after this it will be removed*/
136 140
 	unsigned id_hash; /* hash index in the id_hash */
137 141
 	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 131
 #include "tcp_init.h"
131 132
 #include "tsend.h"
132 133
 #include "timer_ticks.h"
134
+#include "local_timer.h"
133 135
 #ifdef CORE_TLS
134 136
 #include "tls/tls_server.h"
135 137
 #define tls_loaded() 1
... ...
@@ -167,8 +169,9 @@
167 169
 
168 170
 /* maximum accepted lifetime (maximum possible is  ~ MAXINT/2) */
169 171
 #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 */
172
+/* minimum interval local_timer_run() is allowed to run, in ticks */
173
+#define TCPCONN_TIMEOUT_MIN_RUN 1  /* once per tick */
174
+#define TCPCONN_WAIT_TIMEOUT 1 /* 1 tick */
172 175
 
173 176
 enum fd_types { F_NONE, F_SOCKINFO /* a tcp_listen fd */,
174 177
 				F_TCPCONN, F_TCPCHILD, F_PROC };
... ...
@@ -213,8 +216,11 @@ static int tcp_proto_no=-1; /* tcp protocol number as returned by
213 216
 
214 217
 static io_wait_h io_h;
215 218
 
219
+static struct local_timer tcp_main_ltimer;
216 220
 
217 221
 
222
+static ticks_t tcpconn_main_timeout(ticks_t , struct timer_ln* , void* );
223
+
218 224
 inline static int _tcpconn_add_alias_unsafe(struct tcp_connection* c, int port,
219 225
 										struct ip_addr* l_ip, int l_port,
220 226
 										int flags);
... ...
@@ -531,6 +537,7 @@ struct tcp_connection* tcpconn_new(int sock, union sockaddr_union* su,
531 537
 	c->rcv.src_su=*su;
532 538
 	
533 539
 	atomic_set(&c->refcnt, 0);
540
+	timer_init(&c->timer, tcpconn_main_timeout, c, 0);
534 541
 	su2ip_addr(&c->rcv.src_ip, su);
535 542
 	c->rcv.src_port=su_getport(su);
536 543
 	c->rcv.bind_address=ba;
... ...
@@ -697,8 +704,7 @@ inline static struct tcp_connection*  tcpconn_add(struct tcp_connection *c)
697 704
 }
698 705
 
699 706
 
700
-/* unsafe tcpconn_rm version (nolocks) */
701
-void _tcpconn_rm(struct tcp_connection* c)
707
+static inline void _tcpconn_detach(struct tcp_connection *c)
702 708
 {
703 709
 	int r;
704 710
 	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 712
 	for (r=0; r<c->aliases; r++)
707 713
 		tcpconn_listrm(tcpconn_aliases_hash[c->con_aliases[r].hash], 
708 714
 						&c->con_aliases[r], next, prev);
715
+}
716
+
717
+
718
+
719
+static inline void _tcpconn_free(struct tcp_connection* c)
720
+{
709 721
 	lock_destroy(&c->write_lock);
710 722
 #ifdef USE_TLS
711
-	if (c->type==PROTO_TLS) tls_tcpconn_clean(c);
723
+	if (unlikely(c->type==PROTO_TLS)) tls_tcpconn_clean(c);
712 724
 #endif
713 725
 	shm_free(c);
714 726
 }
715 727
 
716 728
 
717 729
 
730
+/* unsafe tcpconn_rm version (nolocks) */
731
+void _tcpconn_rm(struct tcp_connection* c)
732
+{
733
+	_tcpconn_detach(c);
734
+	_tcpconn_free(c);
735
+}
736
+
737
+
738
+
718 739
 void tcpconn_rm(struct tcp_connection* c)
719 740
 {
720 741
 	int r;
... ...
@@ -1207,9 +1228,17 @@ error:
1207 1228
 static void tcpconn_destroy(struct tcp_connection* tcpconn)
1208 1229
 {
1209 1230
 	int fd;
1231
+	ticks_t t;
1210 1232
 
1233
+	/* always try to remove the timer to protect against tcpconn_destroy
1234
+	 *  being called several times for the same connection 
1235
+	 *  (if the timer is already removed, nothing happens) */
1236
+	if (likely(!(tcpconn->flags & F_CONN_READER)))
1237
+		local_timer_del(&tcp_main_ltimer, &tcpconn->timer);
1211 1238
 	TCPCONN_LOCK; /*avoid races w/ tcp_send*/
1212
-	if (atomic_dec_and_test(&tcpconn->refcnt)){ 
1239
+	if (likely(atomic_dec_and_test(&tcpconn->refcnt))){ 
1240
+		_tcpconn_detach(tcpconn);
1241
+		TCPCONN_UNLOCK;
1213 1242
 		DBG("tcpconn_destroy: destroying connection %p, flags %04x\n",
1214 1243
 				tcpconn, tcpconn->flags);
1215 1244
 		fd=tcpconn->s;
... ...
@@ -1218,18 +1247,26 @@ static void tcpconn_destroy(struct tcp_connection* tcpconn)
1218 1247
 		if (tcpconn->type==PROTO_TLS)
1219 1248
 			tls_close(tcpconn, fd);
1220 1249
 #endif
1221
-		_tcpconn_rm(tcpconn);
1250
+		_tcpconn_free(tcpconn);
1222 1251
 		close(fd);
1223 1252
 		(*tcp_connections_no)--;
1224 1253
 	}else{
1254
+		TCPCONN_UNLOCK;
1225 1255
 		/* force timeout */
1226
-		tcpconn->timeout=get_ticks_raw();
1256
+		t=get_ticks_raw();
1257
+		tcpconn->timeout=t+TCPCONN_WAIT_TIMEOUT;
1227 1258
 		tcpconn->state=S_CONN_BAD;
1259
+		if (!(tcpconn->flags & F_CONN_READER)){
1260
+			/* re-activate the timer only if the connection is handled
1261
+			 * by tcp_main (and not by a tcp reader)*/
1262
+			tcpconn->timer.f=tcpconn_main_timeout;
1263
+			timer_reinit(&tcpconn->timer);
1264
+			local_timer_add(&tcp_main_ltimer, &tcpconn->timer, 
1265
+									TCPCONN_WAIT_TIMEOUT, t);
1266
+		}
1228 1267
 		DBG("tcpconn_destroy: delaying (%p, flags %04x) ...\n",
1229 1268
 				tcpconn, tcpconn->flags);
1230
-		
1231 1269
 	}
1232
-	TCPCONN_UNLOCK;
1233 1270
 }
1234 1271
 
1235 1272
 
... ...
@@ -1308,7 +1345,7 @@ inline static int send_fd_queue_add(	struct tcp_send_fd_q* q,
1308 1345
 		if (new_size< MAX_SEND_FD_QUEUE_SIZE/2){
1309 1346
 			new_size*=2;
1310 1347
 		}else new_size=MAX_SEND_FD_QUEUE_SIZE;
1311
-		if (q->crt>=&q->data[new_size]){
1348
+		if (unlikely(q->crt>=&q->data[new_size])){
1312 1349
 			LOG(L_ERR, "ERROR: send_fd_queue_add: queue full: %ld/%ld\n",
1313 1350
 					(long)(q->crt-&q->data[0]-1), new_size);
1314 1351
 			goto error;
... ...
@@ -1316,7 +1353,7 @@ inline static int send_fd_queue_add(	struct tcp_send_fd_q* q,
1316 1353
 		LOG(L_CRIT, "INFO: send_fd_queue: queue full: %ld, extending to %ld\n",
1317 1354
 				(long)(q->end-&q->data[0]), new_size);
1318 1355
 		tmp=pkg_realloc(q->data, new_size*sizeof(struct send_fd_info));
1319
-		if (tmp==0){
1356
+		if (unlikely(tmp==0)){
1320 1357
 			LOG(L_ERR, "ERROR: send_fd_queue_add: out of memory\n");
1321 1358
 			goto error;
1322 1359
 		}
... ...
@@ -1342,8 +1379,8 @@ inline static void send_fd_queue_run(struct tcp_send_fd_q* q)
1342 1379
 	struct send_fd_info* t;
1343 1380
 	
1344 1381
 	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){
1382
+		if (unlikely(send_fd(p->unix_sock, &(p->tcp_conn),
1383
+					sizeof(struct tcp_connection*), p->tcp_conn->s)<=0)){
1347 1384
 			if ( ((errno==EAGAIN)||(errno==EWOULDBLOCK)) && 
1348 1385
 							((s_ticks_t)(p->expire-get_ticks_raw())>0)){
1349 1386
 				/* 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 1421
 	long response[2];
1385 1422
 	int cmd;
1386 1423
 	int bytes;
1424
+	ticks_t t;
1387 1425
 	
1388
-	if (tcp_c->unix_sock<=0){
1426
+	if (unlikely(tcp_c->unix_sock<=0)){
1389 1427
 		/* (we can't have a fd==0, 0 is never closed )*/
1390 1428
 		LOG(L_CRIT, "BUG: handle_tcp_child: fd %d for %d "
1391 1429
 				"(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 1433
 	/* read until sizeof(response)
1396 1434
 	 * (this is a SOCK_STREAM so read is not atomic) */
1397 1435
 	bytes=recv_all(tcp_c->unix_sock, response, sizeof(response), MSG_DONTWAIT);
1398
-	if (bytes<(int)sizeof(response)){
1436
+	if (unlikely(bytes<(int)sizeof(response))){
1399 1437
 		if (bytes==0){
1400 1438
 			/* EOF -> bad, child has died */
1401 1439
 			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 1470
 					response[0], response[1], (int)(tcp_c-&tcp_children[0]));
1433 1471
 	cmd=response[1];
1434 1472
 	tcpconn=(struct tcp_connection*)response[0];
1435
-	if (tcpconn==0){
1473
+	if (unlikely(tcpconn==0)){
1436 1474
 		/* should never happen */
1437 1475
 		LOG(L_CRIT, "BUG: handle_tcp_child: null tcpconn pointer received"
1438 1476
 				 " 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 1481
 	switch(cmd){
1444 1482
 		case CONN_RELEASE:
1445 1483
 			tcp_c->busy--;
1446
-			if (tcpconn->state==S_CONN_BAD){ 
1484
+			if (unlikely(tcpconn->state==S_CONN_BAD)){ 
1447 1485
 				tcpconn_destroy(tcpconn);
1448 1486
 				break;
1449 1487
 			}
1450 1488
 			/* update the timeout*/
1451
-			tcpconn->timeout=get_ticks_raw()+tcp_con_lifetime;
1489
+			t=get_ticks_raw();
1490
+			tcpconn->timeout=t+tcp_con_lifetime;
1452 1491
 			tcpconn_put(tcpconn);
1492
+			/* re-activate the timer */
1493
+			tcpconn->timer.f=tcpconn_main_timeout;
1494
+			timer_reinit(&tcpconn->timer);
1495
+			local_timer_add(&tcp_main_ltimer, &tcpconn->timer, 
1496
+								tcp_con_lifetime, t);
1453 1497
 			/* must be after the de-ref*/
1454
-			tcpconn->flags&=~F_CONN_REMOVED;
1455
-			io_watch_add(&io_h, tcpconn->s, F_TCPCONN, tcpconn);
1498
+			tcpconn->flags&=~(F_CONN_REMOVED|F_CONN_READER);
1499
+			if (unlikely(
1500
+					io_watch_add(&io_h, tcpconn->s, F_TCPCONN, tcpconn)<0)){
1501
+				LOG(L_CRIT, "ERROR: tcp_main: handle_tcp_child: failed to add"
1502
+						" new socket to the fd list\n");
1503
+				tcpconn->flags|=F_CONN_REMOVED;
1504
+				tcpconn_destroy(tcpconn); /* closes also the fd */
1505
+			}
1456 1506
 			DBG("handle_tcp_child: CONN_RELEASE  %p refcnt= %d\n", 
1457 1507
 							tcpconn, atomic_get(&tcpconn->refcnt));
1458 1508
 			break;
... ...
@@ -1501,9 +1551,10 @@ inline static int handle_ser_child(struct process_table* p, int fd_i)
1501 1551
 	int bytes;
1502 1552
 	int ret;
1503 1553
 	int fd;
1554
+	ticks_t t;
1504 1555
 	
1505 1556
 	ret=-1;
1506
-	if (p->unix_sock<=0){
1557
+	if (unlikely(p->unix_sock<=0)){
1507 1558
 		/* (we can't have a fd==0, 0 is never closed )*/
1508 1559
 		LOG(L_CRIT, "BUG: handle_ser_child: fd %d for %d "
1509 1560
 				"(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 1565
 	 * (this is a SOCK_STREAM so read is not atomic) */
1515 1566
 	bytes=receive_fd(p->unix_sock, response, sizeof(response), &fd,
1516 1567
 						MSG_DONTWAIT);
1517
-	if (bytes<(int)sizeof(response)){
1568
+	if (unlikely(bytes<(int)sizeof(response))){
1518 1569
 		/* too few bytes read */
1519 1570
 		if (bytes==0){
1520 1571
 			/* EOF -> bad, child has died */
... ...
@@ -1551,7 +1602,7 @@ inline static int handle_ser_child(struct process_table* p, int fd_i)
1551 1602
 					response[0], response[1], fd, (int)(p-&pt[0]), p->pid);
1552 1603
 	cmd=response[1];
1553 1604
 	tcpconn=(struct tcp_connection*)response[0];
1554
-	if (tcpconn==0){
1605
+	if (unlikely(tcpconn==0)){
1555 1606
 		LOG(L_CRIT, "BUG: handle_ser_child: null tcpconn pointer received"
1556 1607
 				 " from child %d (pid %d): %lx, %lx\n",
1557 1608
 				 	(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 1620
 			/* send the requested FD  */
1570 1621
 			/* WARNING: take care of setting refcnt properly to
1571 1622
 			 * avoid race condition */
1572
-			if (send_fd(p->unix_sock, &tcpconn, sizeof(tcpconn),
1573
-							tcpconn->s)<=0){
1623
+			if (unlikely(send_fd(p->unix_sock, &tcpconn, sizeof(tcpconn),
1624
+								tcpconn->s)<=0)){
1574 1625
 				LOG(L_ERR, "ERROR: handle_ser_child: send_fd failed\n");
1575 1626
 			}
1576 1627
 			break;
... ...
@@ -1578,7 +1629,7 @@ inline static int handle_ser_child(struct process_table* p, int fd_i)
1578 1629
 			/* update the fd in the requested tcpconn*/
1579 1630
 			/* WARNING: take care of setting refcnt properly to
1580 1631
 			 * avoid race condition */
1581
-			if (fd==-1){
1632
+			if (unlikely(fd==-1)){
1582 1633
 				LOG(L_CRIT, "BUG: handle_ser_child: CONN_NEW:"
1583 1634
 							" no fd received\n");
1584 1635
 				break;
... ...
@@ -1588,9 +1639,19 @@ inline static int handle_ser_child(struct process_table* p, int fd_i)
1588 1639
 			/* add tcpconn to the list*/
1589 1640
 			tcpconn_add(tcpconn);
1590 1641
 			/* update the timeout*/
1591
-			tcpconn->timeout=get_ticks_raw()+tcp_con_lifetime;
1642
+			t=get_ticks_raw();
1643
+			tcpconn->timeout=t+tcp_con_lifetime;
1644
+			/* activate the timer (already properly init. in tcpconn_new() */
1645
+			local_timer_add(&tcp_main_ltimer, &tcpconn->timer, 
1646
+								tcp_con_lifetime, t);
1592 1647
 			tcpconn->flags&=~F_CONN_REMOVED;
1593
-			io_watch_add(&io_h, tcpconn->s, F_TCPCONN, tcpconn);
1648
+			if (unlikely(
1649
+					io_watch_add(&io_h, tcpconn->s, F_TCPCONN, tcpconn)<0)){
1650
+				LOG(L_CRIT, "ERROR: tcp_main: handle_ser_child: failed to add"
1651
+						" new socket to the fd list\n");
1652
+				tcpconn->flags|=F_CONN_REMOVED;
1653
+				tcpconn_destroy(tcpconn); /* closes also the fd */
1654
+			}
1594 1655
 			break;
1595 1656
 		default:
1596 1657
 			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 1691
 	
1631 1692
 	tcp_children[idx].busy++;
1632 1693
 	tcp_children[idx].n_reqs++;
1633
-	if (min_busy){
1694
+	if (unlikely(min_busy)){
1634 1695
 		DBG("WARNING: send2child: no free tcp receiver, "
1635 1696
 				" connection passed to the least busy one (%d)\n",
1636 1697
 				min_busy);
... ...
@@ -1649,8 +1710,8 @@ inline static int send2child(struct tcp_connection* tcpconn)
1649 1710
 		
1650 1711
 #ifdef SEND_FD_QUEUE
1651 1712
 	/* if queue full, try to queue the io */
1652
-	if (send_fd(tcp_children[idx].unix_sock, &tcpconn, sizeof(tcpconn),
1653
-			tcpconn->s)<=0){
1713
+	if (unlikely(send_fd(tcp_children[idx].unix_sock, &tcpconn,
1714
+							sizeof(tcpconn), tcpconn->s)<=0)){
1654 1715
 		if ((errno==EAGAIN)||(errno==EWOULDBLOCK)){
1655 1716
 			/* FIXME: remove after debugging */
1656 1717
 			 LOG(L_CRIT, "INFO: tcp child %d, socket %d: queue full,"
... ...
@@ -1668,8 +1729,8 @@ inline static int send2child(struct tcp_connection* tcpconn)
1668 1729
 		}
1669 1730
 	}
1670 1731
 #else
1671
-	if (send_fd(tcp_children[idx].unix_sock, &tcpconn, sizeof(tcpconn),
1672
-			tcpconn->s)<=0){
1732
+	if (unlikely(send_fd(tcp_children[idx].unix_sock, &tcpconn,
1733
+						sizeof(tcpconn), tcpconn->s)<=0)){
1673 1734
 		LOG(L_ERR, "ERROR: send2child: send_fd failed\n");
1674 1735
 		return -1;
1675 1736
 	}
... ...
@@ -1700,20 +1761,20 @@ static inline int handle_new_connect(struct socket_info* si)
1700 1761
 	/* got a connection on r */
1701 1762
 	su_len=sizeof(su);
1702 1763
 	new_sock=accept(si->socket, &(su.s), &su_len);
1703
-	if (new_sock==-1){
1764
+	if (unlikely(new_sock==-1)){
1704 1765
 		if ((errno==EAGAIN)||(errno==EWOULDBLOCK))
1705 1766
 			return 0;
1706 1767
 		LOG(L_ERR,  "WARNING: handle_new_connect: error while accepting"
1707 1768
 				" connection(%d): %s\n", errno, strerror(errno));
1708 1769
 		return -1;
1709 1770
 	}
1710
-	if (*tcp_connections_no>=tcp_max_connections){
1771
+	if (unlikely(*tcp_connections_no>=tcp_max_connections)){
1711 1772
 		LOG(L_ERR, "ERROR: maximum number of connections exceeded: %d/%d\n",
1712 1773
 					*tcp_connections_no, tcp_max_connections);
1713 1774
 		close(new_sock);
1714 1775
 		return 1; /* success, because the accept was succesfull */
1715 1776
 	}
1716
-	if (init_sock_opt_accept(new_sock)<0){
1777
+	if (unlikely(init_sock_opt_accept(new_sock)<0)){
1717 1778
 		LOG(L_ERR, "ERROR: handle_new_connect: init_sock_opt failed\n");
1718 1779
 		close(new_sock);
1719 1780
 		return 1; /* success, because the accept was succesfull */
... ...
@@ -1721,7 +1782,7 @@ static inline int handle_new_connect(struct socket_info* si)
1721 1782
 	(*tcp_connections_no)++;
1722 1783
 	
1723 1784
 	dst_su=&si->su;
1724
-	if (si->flags & SI_IS_ANY){
1785
+	if (unlikely(si->flags & SI_IS_ANY)){
1725 1786
 		/* INADDR_ANY => get local dst */
1726 1787
 		sock_name_len=sizeof(sock_name);
1727 1788
 		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 1796
 	}
1736 1797
 	/* add socket to list */
1737 1798
 	tcpconn=tcpconn_new(new_sock, &su, dst_su, si, si->proto, S_CONN_ACCEPT);
1738
-	if (tcpconn){
1799
+	if (likely(tcpconn)){
1739 1800
 #ifdef TCP_PASS_NEW_CONNECTION_ON_DATA
1740 1801
 		tcpconn_add(tcpconn);
1802
+		/* activate the timer */
1803
+		local_timer_add(&tcp_main_ltimer, &tcpconn->timer, 
1804
+								tcp_con_lifetime, get_ticks_raw());
1741 1805
 		tcpconn->flags&=~F_CONN_REMOVED;
1742
-		io_watch_add(&io_h, tcpconn->s, F_TCPCONN, tcpconn);
1806
+		if (unlikely(io_watch_add(&io_h, tcpconn->s, F_TCPCONN, tcpconn)<0)){
1807
+			LOG(L_CRIT, "ERROR: tcp_main: handle_new_connect: failed to add"
1808
+						" new socket to the fd list\n");
1809
+			tcpconn->flags|=F_CONN_REMOVED;
1810
+			tcpconn_destroy(tcpconn); /* closes also the fd */
1811
+		}
1743 1812
 #else
1744 1813
 		atomic_set(&tcpconn->refcnt, 1); /* safe, not yet available to the
1745 1814
 											outside world */
... ...
@@ -1747,7 +1816,8 @@ static inline int handle_new_connect(struct socket_info* si)
1747 1816
 		DBG("handle_new_connect: new connection: %p %d flags: %04x\n",
1748 1817
 			tcpconn, tcpconn->s, tcpconn->flags);
1749 1818
 		/* pass it to a child */
1750
-		if(send2child(tcpconn)<0){
1819
+		tcpconn->flags|=F_CONN_READER;
1820
+		if(unlikely(send2child(tcpconn)<0)){
1751 1821
 			LOG(L_ERR,"ERROR: handle_new_connect: no children "
1752 1822
 					"available\n");
1753 1823
 			tcpconn_destroy(tcpconn);
... ...
@@ -1793,12 +1863,14 @@ inline static int handle_tcpconn_ev(struct tcp_connection* tcpconn, int fd_i)
1793 1863
 		return -1;
1794 1864
 	}
1795 1865
 #endif
1796
-	/* pass it to child, so remove it from the io watch list */
1866
+	/* pass it to child, so remove it from the io watch list  and the local
1867
+	 *  timer */
1797 1868
 	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;
1869
+	if (unlikely(io_watch_del(&io_h, tcpconn->s, fd_i, 0)==-1)) goto error;
1870
+	tcpconn->flags|=F_CONN_REMOVED|F_CONN_READER;
1871
+	local_timer_del(&tcp_main_ltimer, &tcpconn->timer);
1800 1872
 	tcpconn_ref(tcpconn); /* refcnt ++ */
1801
-	if (send2child(tcpconn)<0){
1873
+	if (unlikely(send2child(tcpconn)<0)){
1802 1874
 		LOG(L_ERR,"ERROR: handle_tcpconn_ev: no children available\n");
1803 1875
 		tcpconn_destroy(tcpconn);
1804 1876
 	}
... ...
@@ -1855,40 +1927,91 @@ error:
1855 1927
 
1856 1928
 
1857 1929
 
1858
-/* very inefficient for now - FIXME
1859
- * keep in sync with tcpconn_destroy, the "delete" part should be
1930
+/* timer handler for tcpconnection handled by tcp_main */
1931
+static ticks_t tcpconn_main_timeout(ticks_t t, struct timer_ln* tl, void* data)
1932
+{
1933
+	struct tcp_connection *c;
1934
+	int fd;
1935
+	
1936
+	c=(struct tcp_connection*)data; 
1937
+	/* or (struct tcp...*)(tl-offset(c->timer)) */
1938
+	
1939
+	if (TICKS_LT(t, c->timeout)){
1940
+		/* timeout extended, exit */
1941
+		return (ticks_t)(c->timeout - t);
1942
+	}
1943
+	if (likely(atomic_get(&c->refcnt)==0)){
1944
+		TCPCONN_LOCK;
1945
+			/* check again to avoid races with tcp_send() */
1946
+			if (likely(atomic_get(&c->refcnt)==0)){
1947
+				/* delete */
1948
+				_tcpconn_detach(c);
1949
+				TCPCONN_UNLOCK; /* unlock as soon as possible */
1950
+				fd=c->s;
1951
+				if (likely(fd>0)){
1952
+					if (likely(!(c->flags & F_CONN_REMOVED))){
1953
+						io_watch_del(&io_h, fd, -1, IO_FD_CLOSING);
1954
+						c->flags|=F_CONN_REMOVED;
1955
+					}
1956
+#ifdef USE_TLS
1957
+					if (unlikely(c->type==PROTO_TLS ))
1958
+						tls_close(c, fd);
1959
+#endif /* USE_TLS */
1960
+					_tcpconn_free(c);
1961
+					close(fd);
1962
+				}
1963
+				(*tcp_connections_no)--; /* modified only in tcp_main
1964
+											 => no lock needed */
1965
+				return 0; /* don't prolong the timer anymore */
1966
+			}
1967
+		TCPCONN_UNLOCK;
1968
+	}
1969
+	/* if we are here we can't delete the connection, it's still referenced
1970
+	 *  => we just delay deleting it */
1971
+	return TCPCONN_WAIT_TIMEOUT;
1972
+}
1973
+
1974
+
1975
+
1976
+static inline void tcp_timer_run()
1977
+{
1978
+	ticks_t ticks;
1979
+	static ticks_t prev_ticks=0;
1980
+	
1981
+	ticks=get_ticks_raw();
1982
+	if (unlikely((ticks-prev_ticks)<TCPCONN_TIMEOUT_MIN_RUN)) return;
1983
+	prev_ticks=ticks;
1984
+	local_timer_run(&tcp_main_ltimer, ticks);
1985
+}
1986
+
1987
+
1988
+
1989
+/* keep in sync with tcpconn_destroy, the "delete" part should be
1860 1990
  * 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
1991
+ * Note: this function is called only on shutdown by the main ser process via
1992
+ * cleanup(). However it's also safe to call it from the tcp_main process.
1993
+ * => with the ser shutdown exception, it cannot execute in parallel
1864 1994
  * with tcpconn_add() or tcpconn_destroy()*/
1865
-static inline void tcpconn_timeout(int force)
1995
+static inline void tcpconn_destroy_all()
1866 1996
 {
1867
-	static ticks_t prev_ticks=0;
1868 1997
 	struct tcp_connection *c, *next;
1869
-	ticks_t ticks;
1870 1998
 	unsigned h;
1871 1999
 	int fd;
1872 2000
 	
1873 2001
 	
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 */
2002
+	TCPCONN_LOCK; 
1878 2003
 	for(h=0; h<TCP_ID_HASH_SIZE; h++){
1879 2004
 		c=tcpconn_id_hash[h];
1880 2005
 		while(c){
1881 2006
 			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){
2007
+				if (is_tcp_main){
1888 2008
 					/* we cannot close or remove the fd if we are not in the
1889 2009
 					 * tcp main proc.*/
2010
+					if (!(c->flags & F_CONN_READER))
2011
+						local_timer_del(&tcp_main_ltimer, &c->timer);
2012
+					/* else still in some reader */
1890 2013
 					fd=c->s;
1891
-					if (!(c->flags & F_CONN_REMOVED)){
2014
+					if (fd>0 && !(c->flags & F_CONN_REMOVED)){
1892 2015
 						io_watch_del(&io_h, fd, -1, IO_FD_CLOSING);
1893 2016
 						c->flags|=F_CONN_REMOVED;
1894 2017
 					}
... ...
@@ -1896,7 +2019,7 @@ static inline void tcpconn_timeout(int force)
1896 2019
 					fd=-1;
1897 2020
 				}
1898 2021
 #ifdef USE_TLS
1899
-				if (c->type==PROTO_TLS)
2022
+				if (fd>0 && c->type==PROTO_TLS)
1900 2023
 					tls_close(c, fd);
1901 2024
 #endif
1902 2025
 				_tcpconn_rm(c);
... ...
@@ -1904,7 +2027,6 @@ static inline void tcpconn_timeout(int force)
1904 2027
 					close(fd);
1905 2028
 				}
1906 2029
 				(*tcp_connections_no)--;
1907
-			}
1908 2030
 			c=next;
1909 2031
 		}
1910 2032
 	}
... ...
@@ -1994,7 +2116,7 @@ void tcp_main_loop()
1994 2116
 				io_wait_loop_poll(&io_h, TCP_MAIN_SELECT_TIMEOUT, 0); 
1995 2117
 				send_fd_queue_run(&send2child_q); /* then new io */
1996 2118
 				/* remove old connections */
1997
-				tcpconn_timeout(0);
2119
+				tcp_timer_run();
1998 2120
 			}
1999 2121
 			break;
2000 2122
 #ifdef HAVE_SELECT
... ...
@@ -2002,7 +2124,7 @@ void tcp_main_loop()
2002 2124
 			while(1){
2003 2125
 				io_wait_loop_select(&io_h, TCP_MAIN_SELECT_TIMEOUT, 0);
2004 2126
 				send_fd_queue_run(&send2child_q); /* then new io */
2005
-				tcpconn_timeout(0);
2127
+				tcp_timer_run();
2006 2128
 			}
2007 2129
 			break;
2008 2130
 #endif
... ...
@@ -2011,7 +2133,7 @@ void tcp_main_loop()
2011 2133
 			while(1){
2012 2134
 				io_wait_loop_sigio_rt(&io_h, TCP_MAIN_SELECT_TIMEOUT);
2013 2135
 				send_fd_queue_run(&send2child_q); /* then new io */
2014
-				tcpconn_timeout(0);
2136
+				tcp_timer_run();
2015 2137
 			}
2016 2138
 			break;
2017 2139
 #endif
... ...
@@ -2020,14 +2142,14 @@ void tcp_main_loop()
2020 2142
 			while(1){
2021 2143
 				io_wait_loop_epoll(&io_h, TCP_MAIN_SELECT_TIMEOUT, 0);
2022 2144
 				send_fd_queue_run(&send2child_q); /* then new io */
2023
-				tcpconn_timeout(0);
2145
+				tcp_timer_run();
2024 2146
 			}
2025 2147
 			break;
2026 2148
 		case POLL_EPOLL_ET:
2027 2149
 			while(1){
2028 2150
 				io_wait_loop_epoll(&io_h, TCP_MAIN_SELECT_TIMEOUT, 1);
2029 2151
 				send_fd_queue_run(&send2child_q); /* then new io */
2030
-				tcpconn_timeout(0);
2152
+				tcp_timer_run();
2031 2153
 			}
2032 2154
 			break;
2033 2155
 #endif
... ...
@@ -2036,7 +2158,7 @@ void tcp_main_loop()
2036 2158
 			while(1){
2037 2159
 				io_wait_loop_kqueue(&io_h, TCP_MAIN_SELECT_TIMEOUT, 0);
2038 2160
 				send_fd_queue_run(&send2child_q); /* then new io */
2039
-				tcpconn_timeout(0);
2161
+				tcp_timer_run();
2040 2162
 			}
2041 2163
 			break;
2042 2164
 #endif
... ...
@@ -2045,7 +2167,7 @@ void tcp_main_loop()
2045 2167
 			while(1){
2046 2168
 				io_wait_loop_devpoll(&io_h, TCP_MAIN_SELECT_TIMEOUT, 0);
2047 2169
 				send_fd_queue_run(&send2child_q); /* then new io */
2048
-				tcpconn_timeout(0);
2170
+				tcp_timer_run();
2049 2171
 			}
2050 2172
 			break;
2051 2173
 #endif
... ...
@@ -2075,7 +2197,7 @@ void destroy_tcp()
2075 2197
 								   some process was terminated while holding 
2076 2198
 								   it; this will allow an almost gracious 
2077 2199
 								   shutdown */
2078
-			tcpconn_timeout(1); /* force close/expire for all active tcpconns*/
2200
+			tcpconn_destroy_all(); 
2079 2201
 			shm_free(tcpconn_id_hash);
2080 2202
 			tcpconn_id_hash=0;
2081 2203
 		}
... ...
@@ -2100,6 +2222,7 @@ void destroy_tcp()
2100 2222
 			pkg_free(tcp_children);
2101 2223
 			tcp_children=0;
2102 2224
 		}
2225
+		destroy_local_timer(&tcp_main_ltimer);
2103 2226
 }
2104 2227
 
2105 2228
 
... ...
@@ -2189,6 +2312,11 @@ int init_tcp()
2189 2312
 					poll_method_name(tcp_poll_method));
2190 2313
 	}
2191 2314
 	
2315
+	if (init_local_timer(&tcp_main_ltimer, get_ticks_raw())!=0){
2316
+		LOG(L_ERR, "ERROR: init_tcp: failed to init local timer\n");
2317
+		goto error;
2318
+	}
2319
+	
2192 2320
 	return 0;
2193 2321
 error:
2194 2322
 	/* 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 62
 #include "globals.h"
62 63
 #include "receive.h"
63 64
 #include "timer.h"
65
+#include "local_timer.h"
64 66
 #include "ut.h"
65 67
 #ifdef CORE_TLS
66 68
 #include "tls/tls_server.h"
... ...
@@ -80,6 +82,8 @@ int is_msg_complete(struct tcp_req* r);
80 82
 
81 83
 #endif /* USE_STUN */
82 84
 
85
+#define TCPCONN_TIMEOUT_MIN_RUN  1 /* run the timers each new tick */
86
+
83 87
 /* types used in io_wait* */
84 88
 enum fd_types { F_NONE, F_TCPMAIN, F_TCPCONN };
85 89
 
... ...
@@ -88,6 +92,8 @@ static struct tcp_connection* tcp_conn_lst=0;
88 92
 static io_wait_h io_w; /* io_wait handler*/
89 93
 static int tcpmain_sock=-1;
90 94
 
95
+static struct local_timer tcp_reader_ltimer;
96
+
91 97
 
92 98
 /* reads next available bytes
93 99
  * 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 681
 }
676 682
 
677 683
 
678
-#ifdef DEBUG_TCP_RECEIVE
679
-/* old code known to work, kept arround for debuging */
680
-void tcp_receive_loop(int unix_sock)
684
+
685
+static ticks_t tcpconn_read_timeout(ticks_t t, struct timer_ln* tl, void* data)
681 686
 {
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;
687
+	struct tcp_connection *c;
694 688
 	
689
+	c=(struct tcp_connection*)data; 
690
+	/* or (struct tcp...*)(tl-offset(c->timer)) */
695 691
 	
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
-		
692
+	if (likely(!(c->state<0) && TICKS_LT(t, c->timeout))){
693
+		/* timeout extended, exit */
694
+		return (ticks_t)(c->timeout - t);
815 695
 	}
696
+	/* if conn->state is ERROR or BAD => force timeout too */
697
+	io_watch_del(&io_w, c->fd, -1, IO_FD_CLOSING);
698
+	tcpconn_listrm(tcp_conn_lst, c, c_next, c_prev);
699
+	release_tcpconn(c, (c->state<0)?CONN_ERROR:CONN_RELEASE, tcpmain_sock);
700
+	
701
+	return 0;
816 702
 }
817
-#else /* DEBUG_TCP_RECEIVE */
818 703
 
819 704
 
820 705
 
... ...
@@ -838,13 +723,14 @@ inline static int handle_io(struct fd_map* fm, int idx)
838 723
 	struct tcp_connection* con;
839 724
 	int s;
840 725
 	long resp;
726
+	ticks_t t;
841 727
 	
842 728
 	switch(fm->type){
843 729
 		case F_TCPMAIN:
844 730
 again:
845 731
 			ret=n=receive_fd(fm->fd, &con, sizeof(con), &s, 0);
846 732
 			DBG("received n=%d con=%p, fd=%d\n", n, con, s);
847
-			if (n<0){
733
+			if (unlikely(n<0)){
848 734
 				if (errno == EWOULDBLOCK || errno == EAGAIN){
849 735
 					ret=0;
850 736
 					break;
... ...
@@ -855,21 +741,21 @@ again:
855 741
 						abort(); /* big error*/
856 742
 				}
857 743
 			}
858
-			if (n==0){
744
+			if (unlikely(n==0)){
859 745
 				LOG(L_ERR, "WARNING: tcp_receive: handle_io: 0 bytes read\n");
860 746
 				goto error;
861 747
 			}
862
-			if (con==0){
748
+			if (unlikely(con==0)){
863 749
 					LOG(L_CRIT, "BUG: tcp_receive: handle_io null pointer\n");
864 750
 					goto error;
865 751
 			}
866 752
 			con->fd=s;
867
-			if (s==-1) {
753
+			if (unlikely(s==-1)) {
868 754
 				LOG(L_ERR, "ERROR: tcp_receive: handle_io: read_fd:"
869 755
 									"no fd read\n");
870 756
 				goto con_error;
871 757
 			}
872
-			if (con==tcp_conn_lst){
758
+			if (unlikely(con==tcp_conn_lst)){
873 759
 				LOG(L_CRIT, "BUG: tcp_receive: handle_io: duplicate"
874 760
 							" connection received: %p, id %d, fd %d, refcnt %d"
875 761
 							" state %d (n=%d)\n", con, con->id, con->fd,
... ...
@@ -882,21 +768,29 @@ again:
882 768
 			 * handle_io might decide to del. the new connection =>
883 769
 			 * must be in the list */
884 770
 			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){
771
+			t=get_ticks_raw();
772
+			con->timeout=t+S_TO_TICKS(TCP_CHILD_TIMEOUT);
773
+			/* re-activate the timer */
774
+			con->timer.f=tcpconn_read_timeout;
775
+			timer_reinit(&con->timer);
776
+			local_timer_add(&tcp_reader_ltimer, &con->timer,
777
+								S_TO_TICKS(TCP_CHILD_TIMEOUT), t);
778
+			if (unlikely(io_watch_add(&io_w, s, F_TCPCONN, con))<0){
887 779
 				LOG(L_CRIT, "ERROR: tcp_receive: handle_io: failed to add"
888 780
 						" new socket to the fd list\n");
889 781
 				tcpconn_listrm(tcp_conn_lst, con, c_next, c_prev);
782
+				local_timer_del(&tcp_reader_ltimer, &con->timer);
890 783
 				goto con_error;
891 784
 			}
892 785
 			break;
893 786
 		case F_TCPCONN:
894 787
 			con=(struct tcp_connection*)fm->data;
895 788
 			resp=tcp_read_req(con, &ret);
896
-			if (resp<0){
789
+			if (unlikely(resp<0)){
897 790
 				ret=-1; /* some error occured */
898 791
 				io_watch_del(&io_w, con->fd, idx, IO_FD_CLOSING);
899 792
 				tcpconn_listrm(tcp_conn_lst, con, c_next, c_prev);
793
+				local_timer_del(&tcp_reader_ltimer, &con->timer);
900 794
 				con->state=S_CONN_BAD;
901 795
 				release_tcpconn(con, resp, tcpmain_sock);
902 796
 			}else{
... ...
@@ -925,35 +819,15 @@ error:
925 819
 
926 820
 
927 821
 
928
-/* releases expired connections and cleans up bad ones (state<0) */
929
-static inline void tcp_receive_timeout()
822
+inline static void tcp_reader_timer_run()
930 823
 {
931
-	struct tcp_connection* con;
932
-	struct tcp_connection* next;
933 824
 	ticks_t ticks;
825
+	static ticks_t prev_ticks=0;
934 826
 	
935 827
 	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
-	}
828
+	if (unlikely((ticks-prev_ticks)<TCPCONN_TIMEOUT_MIN_RUN)) return;
829
+	prev_ticks=ticks;
830
+	local_timer_run(&tcp_reader_ltimer, ticks);
957 831
 }
958 832
 
959 833
 
... ...
@@ -965,6 +839,8 @@ void tcp_receive_loop(int unix_sock)
965 839
 	tcpmain_sock=unix_sock; /* init com. socket */
966 840
 	if (init_io_wait(&io_w, get_max_open_fds(), tcp_poll_method)<0)
967 841
 		goto error;
842
+	if (init_local_timer(&tcp_reader_ltimer, get_ticks_raw())!=0)
843
+		goto error;
968 844
 	/* add the unix socket */
969 845
 	if (io_watch_add(&io_w, tcpmain_sock, F_TCPMAIN, 0)<0){
970 846
 		LOG(L_CRIT, "ERROR: tcp_receive_loop: init: failed to add socket "
... ...
@@ -976,14 +852,14 @@ void tcp_receive_loop(int unix_sock)
976 852
 		case POLL_POLL:
977 853
 				while(1){
978 854
 					io_wait_loop_poll(&io_w, TCP_CHILD_SELECT_TIMEOUT, 0);
979
-					tcp_receive_timeout();
855
+					tcp_reader_timer_run();
980 856
 				}
981 857
 				break;
982 858
 #ifdef HAVE_SELECT
983 859
 		case POLL_SELECT:
984 860
 			while(1){
985 861
 				io_wait_loop_select(&io_w, TCP_CHILD_SELECT_TIMEOUT, 0);
986
-				tcp_receive_timeout();
862
+				tcp_reader_timer_run();
987 863
 			}
988 864
 			break;
989 865
 #endif
... ...
@@ -991,7 +867,7 @@ void tcp_receive_loop(int unix_sock)
991 867
 		case POLL_SIGIO_RT:
992 868
 			while(1){
993 869
 				io_wait_loop_sigio_rt(&io_w, TCP_CHILD_SELECT_TIMEOUT);
994
-				tcp_receive_timeout();
870
+				tcp_reader_timer_run();
995 871
 			}
996 872
 			break;
997 873
 #endif
... ...
@@ -999,13 +875,13 @@ void tcp_receive_loop(int unix_sock)
999 875
 		case POLL_EPOLL_LT:
1000 876
 			while(1){
1001 877
 				io_wait_loop_epoll(&io_w, TCP_CHILD_SELECT_TIMEOUT, 0);
1002
-				tcp_receive_timeout();
878
+				tcp_reader_timer_run();
1003 879
 			}
1004 880
 			break;
1005 881
 		case POLL_EPOLL_ET:
1006 882
 			while(1){
1007 883
 				io_wait_loop_epoll(&io_w, TCP_CHILD_SELECT_TIMEOUT, 1);
1008
-				tcp_receive_timeout();
884
+				tcp_reader_timer_run();
1009 885
 			}
1010 886
 			break;
1011 887
 #endif
... ...
@@ -1013,7 +889,7 @@ void tcp_receive_loop(int unix_sock)
1013 889
 		case POLL_KQUEUE:
1014 890
 			while(1){
1015 891
 				io_wait_loop_kqueue(&io_w, TCP_CHILD_SELECT_TIMEOUT, 0);
1016
-				tcp_receive_timeout();
892
+				tcp_reader_timer_run();
1017 893
 			}
1018 894
 			break;
1019 895
 #endif
... ...
@@ -1021,7 +897,7 @@ void tcp_receive_loop(int unix_sock)
1021 897
 		case POLL_DEVPOLL:
1022 898
 			while(1){
1023 899
 				io_wait_loop_devpoll(&io_w, TCP_CHILD_SELECT_TIMEOUT, 0);
1024
-				tcp_receive_timeout();
900
+				tcp_reader_timer_run();
1025 901
 			}
1026 902
 			break;
1027 903
 #endif
... ...
@@ -1037,7 +913,7 @@ error:
1037 913
 	exit(-1);
1038 914
 }
1039 915
 
1040
-#endif /* DEBUG_TCP_RECEIVE */
916
+
1041 917
 
1042 918
 #ifdef USE_STUN
1043 919
 int is_msg_complete(struct tcp_req* r)