... | ... |
@@ -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) |