Browse code

tcp: internal macro-hooks for stats & events

- added macros for tcp statistics (for now empty, keeping
more statistics will only involve redefining them):

TCP_STATS_ESTABLISHED(state) - new connection established
TCP_STATS_CONNECT_FAILED() - new outgoing connection failed
TCP_STATS_LOCAL_REJECT() - new incoming connection rejected
(max. no exceeded)
TCP_STATS_CON_TIMEOUT() - connection closed for being idle too
long
TCP_STATS_SEND_TIMEOUT() - send fails due to a timeout
TCP_STATS_SENDQ_FULL() - send fails because of the buffering
capacity being exceed (async mode
only)

- added macros for various tcp events (for now some of them are
used for logging):

TCP_EV_CONNECT_RST(...) - connect attempt received RST
TCP_EV_CONNECT_UNREACHABLE(...)
TCP_EV_CONNECT_TIMEOUT(...)
TCP_EV_CONNECT_NO_MORE_PORTS(...)
TCP_EV_CONNECT_ERR(...) - other connect error
TCP_EV_SEND_TIMEOUT(...)
TCP_EV_SENDQ_FULL(...)
TCP_EV_IDLE_CONN_CLOSED(...)

Andrei Pelinescu-Onciul authored on 09/04/2009 19:10:56
Showing 4 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,97 @@
1
+/* 
2
+ * $Id$
3
+ * 
4
+ * Copyright (C) 2009 iptelorg GmbH
5
+ *
6
+ * Permission to use, copy, modify, and distribute this software for any
7
+ * purpose with or without fee is hereby granted, provided that the above
8
+ * copyright notice and this permission notice appear in all copies.
9
+ *
10
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
+ */
18
+/*
19
+ * tcp_ev.h - tcp events
20
+ */
21
+/*
22
+ * History:
23
+ * --------
24
+ *  2009-04-09  initial version (andrei)
25
+*/
26
+
27
+#ifndef __tcp_ev_h
28
+#define __tcp_ev_h
29
+
30
+#include <errno.h>
31
+#include <string.h>
32
+
33
+#include "ip_addr.h"
34
+
35
+
36
+/** a connect attempt got a RST from the peer
37
+ * Note: the RST might be for the connect() itself (SYN), for the first
38
+ *  send() attempt on the connection (unlikely) or received immediately after
39
+ * the connect() succeeded (unlikely, the remote host would have a very small
40
+ *  window after accepting a connection to send a RST before it receives
41
+ * any data).
42
+ *
43
+ * @param err - if 0 it should be ignored (no corresp. libc error), if non-0
44
+ *                it will contain the errno.
45
+ * @param lip   - pointer to an ip_addr containing the local ip
46
+ *                   or 0 if dynamic (WARNING can be 0).
47
+ * @param lport - pointer to an ip_addr containing the local port or 0
48
+ *                   if unknown/dynamic.
49
+ * @param dst   - pointer to a sockaddr_union containing the destination.
50
+ * @param proto - protocol used
51
+ */
52
+#define TCP_EV_CONNECT_RST(err, lip, lport, dst, proto) \
53
+	LOG(L_ERR, "connect %s failed (RST) %s\n", \
54
+			su2a(dst, sizeof(*(dst))), (err)?strerror(err):"")
55
+
56
+/** a connect failed because the remote host/network is unreachable. */
57
+#define TCP_EV_CONNECT_UNREACHABLE(err, lip, lport, dst, proto) \
58
+	LOG(L_ERR, "connect %s failed (unreachable) %s\n", \
59
+			su2a(dst, sizeof(*(dst))), (err)?strerror(err):"")
60
+
61
+/** a connect attempt did timeout. */
62
+#define TCP_EV_CONNECT_TIMEOUT(err, lip, lport, dst, proto) \
63
+	LOG(L_ERR, "connect %s failed (timeout) %s\n", \
64
+			su2a(dst, sizeof(*(dst))), (err)?strerror(err):"")
65
+
66
+/** a connect attempt failed because the local ports are exhausted. */
67
+#define TCP_EV_CONNECT_NO_MORE_PORTS(err, lip, lport, dst, proto) \
68
+	LOG(L_ERR, "connect %s failed (no more ports) %s\n", \
69
+			su2a(dst, sizeof(*(dst))), (err)?strerror(err):"")
70
+
71
+/** a connect attempt failed for some unknown reason.  */
72
+#define TCP_EV_CONNECT_ERR(err, lip, lport, dst, proto) \
73
+	LOG(L_ERR, "connect %s failed %s\n", \
74
+			su2a(dst, sizeof(*(dst))), (err)?strerror(err):"")
75
+
76
+
77
+/** send failed due to timeout.
78
+ * @param err   - if 0 it should be ignored (no corresp. libc error), if non-0
79
+ *                it will contain the errno.
80
+ * @param rcv   - pointer to rcv_info structure
81
+ * 
82
+ */
83
+#define TCP_EV_SEND_TIMEOUT(err, rcv)
84
+
85
+/** send failed due to buffering capacity being exceeded.
86
+  * (only in async mode) */
87
+#define TCP_EV_SENDQ_FULL(err, rcv)
88
+
89
+/** established connection closed for being idle too long. */
90
+#define TCP_EV_IDLE_CONN_CLOSED(err, rcv)
91
+
92
+
93
+
94
+
95
+#endif /*__tcp_ev_h*/
96
+
97
+/* vi: set ts=4 sw=4 tw=79:ai:cindent: */
... ...
@@ -100,6 +100,7 @@
100 100
  *  2009-02-26  direct blacklist support (andrei)
101 101
  *  2009-03-20  s/wq_timeout/send_timeout ; send_timeout is now in ticks
102 102
  *              (andrei)
103
+ * 2009-04-09  tcp ev and tcp stats macros added (andrei)
103 104
  */
104 105
 
105 106
 
... ...
@@ -155,6 +156,8 @@
155 156
 #include "sr_module.h"
156 157
 #include "tcp_server.h"
157 158
 #include "tcp_init.h"
159
+#include "tcp_stats.h"
160
+#include "tcp_ev.h"
158 161
 #include "tsend.h"
159 162
 #include "timer_ticks.h"
160 163
 #include "local_timer.h"
... ...
@@ -503,19 +506,45 @@ again:
503 506
 			else goto error_timeout;
504 507
 		}
505 508
 		if (errno!=EINPROGRESS && errno!=EALREADY){
509
+			switch(errno){
510
+				case ENETUNREACH:
511
+				case EHOSTUNREACH:
506 512
 #ifdef USE_DST_BLACKLIST
507
-			if (cfg_get(core, core_cfg, use_dst_blacklist))
508
-				switch(errno){
509
-					case ECONNREFUSED:
510
-					case ENETUNREACH:
511
-					case ETIMEDOUT:
512
-					case ECONNRESET:
513
-					case EHOSTUNREACH:
513
+					if (cfg_get(core, core_cfg, use_dst_blacklist))
514
+						dst_blacklist_su(BLST_ERR_CONNECT, type,
515
+									 (union sockaddr_union*)servaddr, 0);
516
+#endif /* USE_DST_BLACKLIST */
517
+					TCP_EV_CONNECT_UNREACHABLE(errno, 0, 0,
518
+									(union sockaddr_union*)servaddr, type);
519
+					break;
520
+				case ETIMEDOUT:
521
+#ifdef USE_DST_BLACKLIST
522
+					if (cfg_get(core, core_cfg, use_dst_blacklist))
514 523
 						dst_blacklist_su(BLST_ERR_CONNECT, type,
515 524
 										 (union sockaddr_union*)servaddr, 0);
516
-						break;
517
-				}
518 525
 #endif /* USE_DST_BLACKLIST */
526
+					TCP_EV_CONNECT_TIMEOUT(errno, 0, 0,
527
+									(union sockaddr_union*)servaddr, type);
528
+					break;
529
+				case ECONNREFUSED:
530
+				case ECONNRESET:
531
+#ifdef USE_DST_BLACKLIST
532
+					if (cfg_get(core, core_cfg, use_dst_blacklist))
533
+						dst_blacklist_su(BLST_ERR_CONNECT, type,
534
+										 (union sockaddr_union*)servaddr, 0);
535
+#endif /* USE_DST_BLACKLIST */
536
+					TCP_EV_CONNECT_RST(errno, 0, 0,
537
+									(union sockaddr_union*)servaddr, type);
538
+					break;
539
+				case EAGAIN: /* not posix, but supported on linux and bsd */
540
+					TCP_EV_CONNECT_NO_MORE_PORTS(errno, 0, 0,
541
+									(union sockaddr_union*)servaddr, type);
542
+					break;
543
+				default:
544
+					TCP_EV_CONNECT_ERR(errno, 0, 0,
545
+										(union sockaddr_union*)servaddr, type);
546
+			}
547
+			TCP_STATS_CONNECT_FAILED();
519 548
 			LOG(L_ERR, "ERROR: tcp_blocking_connect %s: (%d) %s\n",
520 549
 					su2a((union sockaddr_union*)servaddr, addrlen),
521 550
 					errno, strerror(errno));
... ...
@@ -584,6 +613,8 @@ error_timeout:
584 613
 		dst_blacklist_su(BLST_ERR_CONNECT, type,
585 614
 							(union sockaddr_union*)servaddr, 0);
586 615
 #endif /* USE_DST_BLACKLIST */
616
+	TCP_EV_CONNECT_TIMEOUT(0, 0, 0, (union sockaddr_union*)servaddr, type);
617
+	TCP_STATS_CONNECT_FAILED();
587 618
 	LOG(L_ERR, "ERROR: tcp_blocking_connect %s: timeout %d s elapsed "
588 619
 				"from %d s\n", su2a((union sockaddr_union*)servaddr, addrlen),
589 620
 				elapsed, cfg_get(tcp, tcp_cfg, connect_timeout_s));
... ...
@@ -630,15 +661,34 @@ inline static int _wbufq_add(struct  tcp_connection* c, char* data,
630 661
 					size, q->queued, *tcp_total_wq,
631 662
 					TICKS_TO_S(t-q->wr_timeout-
632 663
 						cfg_get(tcp, tcp_cfg, send_timeout)));
664
+		if (q->first && TICKS_LT(q->wr_timeout, t)){
665
+			if (unlikely(c->state==S_CONN_CONNECT)){
633 666
 #ifdef USE_DST_BLACKLIST
634
-		if (q->first && TICKS_LT(q->wr_timeout, t) &&
635
-				cfg_get(core, core_cfg, use_dst_blacklist)){
636
-			ERR("blacklisting, state=%d\n", c->state);
637
-			dst_blacklist_su((c->state==S_CONN_CONNECT)?  BLST_ERR_CONNECT:
638
-									BLST_ERR_SEND,
639
-								c->rcv.proto, &c->rcv.src_su, 0);
640
-		}
667
+				if (likely(cfg_get(core, core_cfg, use_dst_blacklist))){
668
+					DBG("blacklisting, state=%d\n", c->state);
669
+					dst_blacklist_su( BLST_ERR_CONNECT, c->rcv.proto,
670
+										&c->rcv.src_su, 0);
671
+				}
672
+#endif /* USE_DST_BLACKLIST */
673
+				TCP_EV_CONNECT_TIMEOUT(0, TCP_LADDR(c), TCP_LPORT(c),
674
+											TCP_PSU(c), TCP_PROTO(c));
675
+				TCP_STATS_CONNECT_FAILED();
676
+			}else{
677
+#ifdef USE_DST_BLACKLIST
678
+				if (likely(cfg_get(core, core_cfg, use_dst_blacklist))){
679
+					DBG("blacklisting, state=%d\n", c->state);
680
+					dst_blacklist_su( BLST_ERR_SEND, c->rcv.proto,
681
+										&c->rcv.src_su, 0);
682
+				}
641 683
 #endif /* USE_DST_BLACKLIST */
684
+				TCP_EV_SEND_TIMEOUT(0, &c->rcv);
685
+				TCP_STATS_SEND_TIMEOUT();
686
+			}
687
+		}else{
688
+			/* if it's not a timeout => queue full */
689
+			TCP_EV_SENDQ_FULL(0, &c->rcv);
690
+			TCP_STATS_SENDQ_FULL();
691
+		}
642 692
 		goto error;
643 693
 	}
644 694
 	
... ...
@@ -808,20 +858,55 @@ inline static int wbufq_run(int fd, struct tcp_connection* c, int* empty)
808 858
 			if (n<0){
809 859
 				/* EINTR is handled inside _tcpconn_write_nb */
810 860
 				if (!(errno==EAGAIN || errno==EWOULDBLOCK)){
811
-#ifdef USE_DST_BLACKLIST
812
-					if (cfg_get(core, core_cfg, use_dst_blacklist))
861
+					if (unlikely(c->state==S_CONN_CONNECT)){
813 862
 						switch(errno){
814 863
 							case ENETUNREACH:
864
+							case EHOSTUNREACH: /* not posix for send() */
865
+#ifdef USE_DST_BLACKLIST
866
+								if (cfg_get(core, core_cfg, use_dst_blacklist))
867
+									dst_blacklist_su(BLST_ERR_CONNECT,
868
+															c->rcv.proto,
869
+															&c->rcv.src_su, 0);
870
+#endif /* USE_DST_BLACKLIST */
871
+								TCP_EV_CONNECT_UNREACHABLE(errno, TCP_LADDR(c),
872
+													TCP_LPORT(c), TCP_PSU(c),
873
+													TCP_PROTO(c));
874
+								break;
875
+							case ECONNREFUSED:
815 876
 							case ECONNRESET:
816
-							/*case EHOSTUNREACH: -- not posix */
817
-								dst_blacklist_su((c->state==S_CONN_CONNECT)?
818
-														BLST_ERR_CONNECT:
819
-														BLST_ERR_SEND,
877
+#ifdef USE_DST_BLACKLIST
878
+								if (cfg_get(core, core_cfg, use_dst_blacklist))
879
+									dst_blacklist_su(BLST_ERR_CONNECT,
880
+															c->rcv.proto,
881
+															&c->rcv.src_su, 0);
882
+#endif /* USE_DST_BLACKLIST */
883
+								TCP_EV_CONNECT_RST(0, TCP_LADDR(c),
884
+													TCP_LPORT(c), TCP_PSU(c),
885
+													TCP_PROTO(c));
886
+								break;
887
+							default:
888
+								TCP_EV_CONNECT_ERR(errno, TCP_LADDR(c),
889
+													TCP_LPORT(c), TCP_PSU(c),
890
+													TCP_PROTO(c));
891
+						}
892
+						TCP_STATS_CONNECT_FAILED();
893
+					}else{
894
+						switch(errno){
895
+							case ECONNREFUSED:
896
+							case ECONNRESET:
897
+								TCP_STATS_CON_RESET();
898
+								/* no break */
899
+							case ENETUNREACH:
900
+							case EHOSTUNREACH: /* not posix for send() */
901
+#ifdef USE_DST_BLACKLIST
902
+								if (cfg_get(core, core_cfg, use_dst_blacklist))
903
+									dst_blacklist_su(BLST_ERR_SEND,
820 904
 														c->rcv.proto,
821 905
 														&c->rcv.src_su, 0);
906
+#endif /* USE_DST_BLACKLIST */
822 907
 								break;
823 908
 						}
824
-#endif /* USE_DST_BLACKLIST */
909
+					}
825 910
 					ret=-1;
826 911
 					LOG(L_ERR, "ERROR: wbuf_runq: %s [%d]\n",
827 912
 						strerror(errno), errno);
... ...
@@ -839,8 +924,10 @@ inline static int wbufq_run(int fd, struct tcp_connection* c, int* empty)
839 924
 	lock_release(&c->write_lock);
840 925
 	if (likely(ret>0)){
841 926
 		q->wr_timeout=get_ticks_raw()+cfg_get(tcp, tcp_cfg, send_timeout);
842
-		if (unlikely(c->state==S_CONN_CONNECT || c->state==S_CONN_ACCEPT))
927
+		if (unlikely(c->state==S_CONN_CONNECT || c->state==S_CONN_ACCEPT)){
928
+			TCP_STATS_ESTABLISHED(c->state);
843 929
 			c->state=S_CONN_OK;
930
+		}
844 931
 	}
845 932
 	return ret;
846 933
 }
... ...
@@ -1032,19 +1119,37 @@ again:
1032 1119
 				*state=S_CONN_CONNECT;
1033 1120
 			else if (errno==EINTR) goto again;
1034 1121
 			else if (errno!=EALREADY){
1122
+				switch(errno){
1123
+					case ENETUNREACH:
1124
+					case EHOSTUNREACH:
1035 1125
 #ifdef USE_DST_BLACKLIST
1036
-				if (cfg_get(core, core_cfg, use_dst_blacklist))
1037
-					switch(errno){
1038
-						case ECONNREFUSED:
1039
-						case ENETUNREACH:
1040
-						case ETIMEDOUT:
1041
-						case ECONNRESET:
1042
-						case EHOSTUNREACH:
1043
-							dst_blacklist_su(BLST_ERR_CONNECT, type, server,
1044
-												0);
1045
-							break;
1046
-				}
1126
+						if (cfg_get(core, core_cfg, use_dst_blacklist))
1127
+							dst_blacklist_su(BLST_ERR_CONNECT, type, server,0);
1128
+#endif /* USE_DST_BLACKLIST */
1129
+						TCP_EV_CONNECT_UNREACHABLE(errno, 0, 0, server, type);
1130
+						break;
1131
+					case ETIMEDOUT:
1132
+#ifdef USE_DST_BLACKLIST
1133
+						if (cfg_get(core, core_cfg, use_dst_blacklist))
1134
+							dst_blacklist_su(BLST_ERR_CONNECT, type, server,0);
1047 1135
 #endif /* USE_DST_BLACKLIST */
1136
+						TCP_EV_CONNECT_TIMEOUT(errno, 0, 0, server, type);
1137
+						break;
1138
+					case ECONNREFUSED:
1139
+					case ECONNRESET:
1140
+#ifdef USE_DST_BLACKLIST
1141
+						if (cfg_get(core, core_cfg, use_dst_blacklist))
1142
+							dst_blacklist_su(BLST_ERR_CONNECT, type, server,0);
1143
+#endif /* USE_DST_BLACKLIST */
1144
+						TCP_EV_CONNECT_RST(errno, 0, 0, server, type);
1145
+						break;
1146
+					case EAGAIN:/* not posix, but supported on linux and bsd */
1147
+						TCP_EV_CONNECT_NO_MORE_PORTS(errno, 0, 0, server,type);
1148
+						break;
1149
+					default:
1150
+						TCP_EV_CONNECT_ERR(errno, 0, 0, server, type);
1151
+				}
1152
+				TCP_STATS_CONNECT_FAILED();
1048 1153
 				LOG(L_ERR, "ERROR: tcp_do_connect: connect %s: (%d) %s\n",
1049 1154
 							su2a(server, sizeof(*server)),
1050 1155
 							errno, strerror(errno));
... ...
@@ -1744,9 +1849,11 @@ no_id:
1744 1849
 						DBG("tcp_send: pending write on new connection %p "
1745 1850
 								" (%d/%d bytes written)\n", c, n, len);
1746 1851
 						if (n<0) n=0;
1747
-						else 
1852
+						else{
1853
+							TCP_STATS_ESTABLISHED(S_CONN_CONNECT);
1748 1854
 							c->state=S_CONN_OK; /* partial write => connect()
1749 1855
 													ended */
1856
+						}
1750 1857
 						/* add to the write queue */
1751 1858
 						lock_get(&c->write_lock);
1752 1859
 							if (unlikely(_wbufq_insert(c, buf+n, len-n)<0)){
... ...
@@ -1774,19 +1881,33 @@ no_id:
1774 1881
 						n=len;
1775 1882
 						goto end;
1776 1883
 					}
1884
+					/* if first write failed it's most likely a
1885
+					   connect error */
1886
+					switch(errno){
1887
+						case ENETUNREACH:
1888
+						case EHOSTUNREACH:  /* not posix for send() */
1777 1889
 #ifdef USE_DST_BLACKLIST
1778
-					if (cfg_get(core, core_cfg, use_dst_blacklist))
1779
-						switch(errno){
1780
-							case ENETUNREACH:
1781
-							case ECONNRESET:
1782
-							/*case EHOSTUNREACH: -- not posix */
1783
-								/* if first write failed it's most likely a
1784
-								   connect error */
1890
+							if (cfg_get(core, core_cfg, use_dst_blacklist))
1785 1891
 								dst_blacklist_add( BLST_ERR_CONNECT, dst, 0);
1786
-								break;
1787
-						}
1788 1892
 #endif /* USE_DST_BLACKLIST */
1893
+							TCP_EV_CONNECT_UNREACHABLE(errno, TCP_LADDR(c),
1894
+									TCP_LPORT(c), TCP_PSU(c), TCP_PROTO(c));
1895
+							break;
1896
+						case ECONNREFUSED:
1897
+						case ECONNRESET:
1898
+#ifdef USE_DST_BLACKLIST
1899
+							if (cfg_get(core, core_cfg, use_dst_blacklist))
1900
+								dst_blacklist_add( BLST_ERR_CONNECT, dst, 0);
1901
+#endif /* USE_DST_BLACKLIST */
1902
+							TCP_EV_CONNECT_RST(errno, TCP_LADDR(c),
1903
+									TCP_LPORT(c), TCP_PSU(c), TCP_PROTO(c));
1904
+							break;
1905
+						default:
1906
+							TCP_EV_CONNECT_ERR(errno, TCP_LADDR(c),
1907
+									TCP_LPORT(c), TCP_PSU(c), TCP_PROTO(c));
1908
+					}
1789 1909
 					/* error: destroy it directly */
1910
+					TCP_STATS_CONNECT_FAILED();
1790 1911
 					LOG(L_ERR, "ERROR: tcp_send %s: connect & send "
1791 1912
 										" for %p failed:" " %s (%d)\n",
1792 1913
 										su2a(&dst->to, sizeof(dst->to)),
... ...
@@ -1794,6 +1915,7 @@ no_id:
1794 1915
 					goto conn_wait_error;
1795 1916
 				}
1796 1917
 				LOG(L_INFO, "tcp_send: quick connect for %p\n", c);
1918
+				TCP_STATS_ESTABLISHED(S_CONN_CONNECT);
1797 1919
 				c->state=S_CONN_OK;
1798 1920
 				/* send to tcp_main */
1799 1921
 				response[0]=(long)c;
... ...
@@ -1814,6 +1936,8 @@ no_id:
1814 1936
 								su2a(&dst->to, sizeof(dst->to)));
1815 1937
 				return -1;
1816 1938
 			}
1939
+			if (likely(c->state==S_CONN_OK))
1940
+				TCP_STATS_ESTABLISHED(S_CONN_CONNECT);
1817 1941
 			atomic_set(&c->refcnt, 2); /* ref. from here and it will also
1818 1942
 			                              be added in the tcp_main hash */
1819 1943
 			fd=c->s;
... ...
@@ -1965,8 +2089,10 @@ send_it:
1965 2089
 			enable_write_watch=_wbufq_empty(c);
1966 2090
 			if (n<0) n=0;
1967 2091
 			else if (unlikely(c->state==S_CONN_CONNECT ||
1968
-						c->state==S_CONN_ACCEPT))
2092
+						c->state==S_CONN_ACCEPT)){
2093
+				TCP_STATS_ESTABLISHED(c->state);
1969 2094
 				c->state=S_CONN_OK; /* something was written */
2095
+			}
1970 2096
 			if (unlikely(_wbufq_add(c, buf+n, len-n)<0)){
1971 2097
 				lock_release(&c->write_lock);
1972 2098
 				n=-1;
... ...
@@ -1989,20 +2115,49 @@ send_it:
1989 2115
 			lock_release(&c->write_lock);
1990 2116
 		}
1991 2117
 #endif /* TCP_ASYNC */
1992
-#ifdef USE_DST_BLACKLIST
1993
-		if (cfg_get(core, core_cfg, use_dst_blacklist))
2118
+		if (unlikely(c->state==S_CONN_CONNECT)){
1994 2119
 			switch(errno){
1995 2120
 				case ENETUNREACH:
2121
+				case EHOSTUNREACH: /* not posix for send() */
2122
+#ifdef USE_DST_BLACKLIST
2123
+					if (cfg_get(core, core_cfg, use_dst_blacklist))
2124
+						dst_blacklist_su(BLST_ERR_CONNECT, c->rcv.proto,
2125
+											&c->rcv.src_su, 0);
2126
+#endif /* USE_DST_BLACKLIST */
2127
+					TCP_EV_CONNECT_UNREACHABLE(errno, TCP_LADDR(c),
2128
+									TCP_LPORT(c), TCP_PSU(c), TCP_PROTO(c));
2129
+					break;
2130
+				case ECONNREFUSED:
2131
+				case ECONNRESET:
2132
+#ifdef USE_DST_BLACKLIST
2133
+					if (cfg_get(core, core_cfg, use_dst_blacklist))
2134
+						dst_blacklist_su(BLST_ERR_CONNECT, c->rcv.proto,
2135
+											&c->rcv.src_su, 0);
2136
+#endif /* USE_DST_BLACKLIST */
2137
+					TCP_EV_CONNECT_RST(errno, TCP_LADDR(c), TCP_LPORT(c),
2138
+										TCP_PSU(c), TCP_PROTO(c));
2139
+					break;
2140
+				default:
2141
+					TCP_EV_CONNECT_ERR(errno, TCP_LADDR(c), TCP_LPORT(c),
2142
+										TCP_PSU(c), TCP_PROTO(c));
2143
+				}
2144
+			TCP_STATS_CONNECT_FAILED();
2145
+		}else{
2146
+			switch(errno){
2147
+				case ECONNREFUSED:
1996 2148
 				case ECONNRESET:
2149
+					TCP_STATS_CON_RESET();
2150
+					/* no break */
2151
+				case ENETUNREACH:
1997 2152
 				/*case EHOSTUNREACH: -- not posix */
1998
-					dst_blacklist_su((c->state==S_CONN_CONNECT)?
1999
-											BLST_ERR_CONNECT:
2000
-											BLST_ERR_SEND,
2001
-										c->rcv.proto,
2002
-										&c->rcv.src_su, 0);
2153
+#ifdef USE_DST_BLACKLIST
2154
+					if (cfg_get(core, core_cfg, use_dst_blacklist))
2155
+						dst_blacklist_su(BLST_ERR_SEND, c->rcv.proto,
2156
+												&c->rcv.src_su, 0);
2157
+#endif /* USE_DST_BLACKLIST */
2003 2158
 					break;
2004 2159
 			}
2005
-#endif /* USE_DST_BLACKLIST */
2160
+		}
2006 2161
 		LOG(L_ERR, "ERROR: tcp_send: failed to send on %p (%s:%d->%s): %s (%d)"
2007 2162
 					"\n", c, ip_addr2a(&c->rcv.dst_ip), c->rcv.dst_port,
2008 2163
 					su2a(&c->rcv.src_su, sizeof(c->rcv.src_su)),
... ...
@@ -2042,8 +2197,10 @@ error:
2042 2197
 	lock_release(&c->write_lock);
2043 2198
 #endif /* TCP_ASYNC */
2044 2199
 	/* in non-async mode here we're either in S_CONN_OK or S_CONN_ACCEPT*/
2045
-	if (unlikely(c->state==S_CONN_CONNECT || c->state==S_CONN_ACCEPT))
2200
+	if (unlikely(c->state==S_CONN_CONNECT || c->state==S_CONN_ACCEPT)){
2201
+			TCP_STATS_ESTABLISHED(c->state);
2046 2202
 			c->state=S_CONN_OK;
2203
+	}
2047 2204
 end:
2048 2205
 #ifdef TCP_FD_CACHE
2049 2206
 	if (unlikely((fd_cache_e==0) && use_fd_cache)){
... ...
@@ -2682,14 +2839,27 @@ inline static int handle_tcp_child(struct tcp_child* tcp_c, int fd_i)
2682 2839
 							"refcnt= %d\n", tcpconn,
2683 2840
 							atomic_get(&tcpconn->refcnt));
2684 2841
 					/* timeout */
2842
+					if (unlikely(tcpconn->state==S_CONN_CONNECT)){
2685 2843
 #ifdef USE_DST_BLACKLIST
2686
-					if (cfg_get(core, core_cfg, use_dst_blacklist))
2687
-						dst_blacklist_su((tcpconn->state==S_CONN_CONNECT)?
2688
-													BLST_ERR_CONNECT:
2689
-													BLST_ERR_SEND,
2844
+						if (cfg_get(core, core_cfg, use_dst_blacklist))
2845
+							dst_blacklist_su( BLST_ERR_CONNECT,
2846
+													tcpconn->rcv.proto,
2847
+													&tcpconn->rcv.src_su, 0);
2848
+#endif /* USE_DST_BLACKLIST */
2849
+						TCP_EV_CONNECT_TIMEOUT(0, TCP_LADDR(tcpconn),
2850
+										TCP_LPORT(tcpconn), TCP_PSU(tcpconn),
2851
+										TCP_PROTO(tcpconn));
2852
+						TCP_STATS_CONNECT_FAILED();
2853
+					}else{
2854
+#ifdef USE_DST_BLACKLIST
2855
+						if (cfg_get(core, core_cfg, use_dst_blacklist))
2856
+							dst_blacklist_su( BLST_ERR_SEND,
2690 2857
 													tcpconn->rcv.proto,
2691 2858
 													&tcpconn->rcv.src_su, 0);
2692 2859
 #endif /* USE_DST_BLACKLIST */
2860
+						TCP_EV_SEND_TIMEOUT(0, &tcpconn->rcv);
2861
+						TCP_STATS_SEND_TIMEOUT();
2862
+					}
2693 2863
 					if (unlikely(tcpconn->flags & F_CONN_WRITE_W)){
2694 2864
 						io_watch_del(&io_h, tcpconn->s, -1, IO_FD_CLOSING);
2695 2865
 						tcpconn->flags&=~F_CONN_WRITE_W;
... ...
@@ -3182,6 +3352,7 @@ static inline int handle_new_connect(struct socket_info* si)
3182 3352
 					*tcp_connections_no,
3183 3353
 					cfg_get(tcp, tcp_cfg, max_connections));
3184 3354
 		close(new_sock);
3355
+		TCP_STATS_LOCAL_REJECT();
3185 3356
 		return 1; /* success, because the accept was succesfull */
3186 3357
 	}
3187 3358
 	if (unlikely(init_sock_opt_accept(new_sock)<0)){
... ...
@@ -3190,6 +3361,7 @@ static inline int handle_new_connect(struct socket_info* si)
3190 3361
 		return 1; /* success, because the accept was succesfull */
3191 3362
 	}
3192 3363
 	(*tcp_connections_no)++;
3364
+	TCP_STATS_ESTABLISHED(S_CONN_ACCEPT);
3193 3365
 	
3194 3366
 	dst_su=&si->su;
3195 3367
 	if (unlikely(si->flags & SI_IS_ANY)){
... ...
@@ -3323,6 +3495,16 @@ inline static int handle_tcpconn_ev(struct tcp_connection* tcpconn, short ev,
3323 3495
 				LOG(L_CRIT, "BUG: tcpconn_ev: unhashed connection %p\n",
3324 3496
 							tcpconn);
3325 3497
 			}
3498
+			if (unlikely(ev & POLLERR)){
3499
+				if (unlikely(tcpconn->state=S_CONN_CONNECT)){
3500
+					TCP_EV_CONNECT_ERR(0, TCP_LADDR(tcpconn),
3501
+										TCP_LPORT(tcpconn), TCP_PSU(tcpconn),
3502
+										TCP_PROTO(tcpconn));
3503
+					TCP_STATS_CONNECT_FAILED();
3504
+				}else{
3505
+					TCP_STATS_CON_RESET(); /* FIXME: it could != RST */
3506
+				}
3507
+			}
3326 3508
 			tcpconn_put_destroy(tcpconn);
3327 3509
 			goto error;
3328 3510
 		}
... ...
@@ -3485,15 +3667,27 @@ static ticks_t tcpconn_main_timeout(ticks_t t, struct timer_ln* tl, void* data)
3485 3667
 		else
3486 3668
 			return (ticks_t)(c->timeout - t);
3487 3669
 	}
3488
-#ifdef USE_DST_BLACKLIST
3489 3670
 	/* if time out due to write, add it to the blacklist */
3490
-	if (tcp_async && _wbufq_non_empty(c) &&
3491
-			TICKS_GE(t, c->wbuf_q.wr_timeout) &&
3492
-			cfg_get(core, core_cfg, use_dst_blacklist))
3493
-		dst_blacklist_su((c->state==S_CONN_CONNECT)?  BLST_ERR_CONNECT:
3494
-										BLST_ERR_SEND,
3495
-								c->rcv.proto, &c->rcv.src_su, 0);
3671
+	if (tcp_async && _wbufq_non_empty(c) && TICKS_GE(t, c->wbuf_q.wr_timeout)){
3672
+		if (unlikely(c->state==S_CONN_CONNECT)){
3673
+#ifdef USE_DST_BLACKLIST
3674
+			if (cfg_get(core, core_cfg, use_dst_blacklist))
3675
+				dst_blacklist_su(BLST_ERR_CONNECT, c->rcv.proto,
3676
+									&c->rcv.src_su, 0);
3677
+#endif /* USE_DST_BLACKLIST */
3678
+			TCP_EV_CONNECT_TIMEOUT(0, TCP_LADDR(c), TCP_LPORT(c), TCP_PSU(c),
3679
+									TCP_PROTO(c));
3680
+			TCP_STATS_CONNECT_FAILED();
3681
+		}else{
3682
+#ifdef USE_DST_BLACKLIST
3683
+			if (cfg_get(core, core_cfg, use_dst_blacklist))
3684
+				dst_blacklist_su(BLST_ERR_SEND, c->rcv.proto,
3685
+									&c->rcv.src_su, 0);
3496 3686
 #endif /* USE_DST_BLACKLIST */
3687
+			TCP_EV_SEND_TIMEOUT(0, &c->rcv);
3688
+			TCP_STATS_SEND_TIMEOUT();
3689
+		}
3690
+	}
3497 3691
 #else /* ! TCP_ASYNC */
3498 3692
 	if (TICKS_LT(t, c->timeout)){
3499 3693
 		/* timeout extended, exit */
... ...
@@ -3520,6 +3714,8 @@ static ticks_t tcpconn_main_timeout(ticks_t t, struct timer_ln* tl, void* data)
3520 3714
 			c->flags&=~(F_CONN_READ_W|F_CONN_WRITE_W);
3521 3715
 		}
3522 3716
 	}
3717
+	TCP_EV_IDLE_CONN_CLOSED(0, &c->rcv);
3718
+	TCP_STATS_CON_TIMEOUT();
3523 3719
 	tcpconn_put_destroy(c);
3524 3720
 	return 0;
3525 3721
 }
... ...
@@ -41,6 +41,7 @@
41 41
  * 2008-02-04  optimizations: handle POLLRDHUP (if supported), detect short
42 42
  *              reads (sock. buffer empty) (andrei)
43 43
  * 2009-02-26  direct blacklist support (andrei)
44
+ * 2009-04-09  tcp ev and tcp stats macros added (andrei)
44 45
  */
45 46
 
46 47
 #ifdef USE_TCP
... ...
@@ -61,6 +62,8 @@
61 62
 
62 63
 #include "dprint.h"
63 64
 #include "tcp_conn.h"
65
+#include "tcp_stats.h"
66
+#include "tcp_ev.h"
64 67
 #include "pass_fd.h"
65 68
 #include "globals.h"
66 69
 #include "receive.h"
... ...
@@ -146,19 +149,47 @@ again:
146 149
 				bytes_read=0; /* nothing has been read */
147 150
 			}else if (errno == EINTR) goto again;
148 151
 			else{
149
-#ifdef USE_DST_BLACKLIST
150
-				if (cfg_get(core, core_cfg, use_dst_blacklist))
152
+				if (unlikely(c->state=S_CONN_CONNECT)){
151 153
 					switch(errno){
152 154
 						case ECONNRESET:
155
+#ifdef USE_DST_BLACKLIST
156
+							if (cfg_get(core, core_cfg, use_dst_blacklist))
157
+								dst_blacklist_su(BLST_ERR_CONNECT,
158
+														c->rcv.proto,
159
+														&c->rcv.src_su, 0);
160
+#endif /* USE_DST_BLACKLIST */
161
+							TCP_EV_CONNECT_RST(errno, TCP_LADDR(c),
162
+									TCP_LPORT(c), TCP_PSU(c), TCP_PROTO(c));
163
+							break;
153 164
 						case ETIMEDOUT:
154
-							dst_blacklist_su((c->state==S_CONN_CONNECT)?
155
-													BLST_ERR_CONNECT:
156
-													BLST_ERR_SEND,
157
-													c->rcv.proto,
158
-													&c->rcv.src_su, 0);
165
+#ifdef USE_DST_BLACKLIST
166
+							if (cfg_get(core, core_cfg, use_dst_blacklist))
167
+								dst_blacklist_su(BLST_ERR_CONNECT,
168
+														c->rcv.proto,
169
+														&c->rcv.src_su, 0);
170
+#endif /* USE_DST_BLACKLIST */
171
+							TCP_EV_CONNECT_TIMEOUT(errno, TCP_LADDR(c),
172
+									TCP_LPORT(c), TCP_PSU(c), TCP_PROTO(c));
159 173
 							break;
174
+						default:
175
+							TCP_EV_CONNECT_ERR(errno, TCP_LADDR(c),
176
+									TCP_LPORT(c), TCP_PSU(c), TCP_PROTO(c));
160 177
 					}
178
+					TCP_STATS_CONNECT_FAILED();
179
+				}else{
180
+						switch(errno){
181
+							case ECONNRESET:
182
+								TCP_STATS_CON_RESET();
183
+							case ETIMEDOUT:
184
+#ifdef USE_DST_BLACKLIST
185
+								if (cfg_get(core, core_cfg, use_dst_blacklist))
186
+									dst_blacklist_su(BLST_ERR_SEND,
187
+														c->rcv.proto,
188
+														&c->rcv.src_su, 0);
161 189
 #endif /* USE_DST_BLACKLIST */
190
+								break;
191
+						}
192
+				}
162 193
 				LOG(L_ERR, "ERROR: tcp_read: error reading: %s (%d)\n",
163 194
 							strerror(errno), errno);
164 195
 				r->error=TCP_READ_ERROR;
... ...
@@ -170,14 +201,18 @@ again:
170 201
 			*flags|=RD_CONN_EOF;
171 202
 			DBG("tcp_read: EOF on %p, FD %d\n", c, fd);
172 203
 		}else{
173
-			if (unlikely(c->state==S_CONN_CONNECT || c->state==S_CONN_ACCEPT))
204
+			if (unlikely(c->state==S_CONN_CONNECT || c->state==S_CONN_ACCEPT)){
205
+				TCP_STATS_ESTABLISHED(c->state);
174 206
 				c->state=S_CONN_OK;
207
+			}
175 208
 		}
176 209
 		/* short read */
177 210
 		*flags|=RD_CONN_SHORT_READ;
178 211
 	}else{ /* else normal full read */
179
-		if (unlikely(c->state==S_CONN_CONNECT || c->state==S_CONN_ACCEPT))
212
+		if (unlikely(c->state==S_CONN_CONNECT || c->state==S_CONN_ACCEPT)){
213
+			TCP_STATS_ESTABLISHED(c->state);
180 214
 			c->state=S_CONN_OK;
215
+		}
181 216
 	}
182 217
 #ifdef EXTRA_DEBUG
183 218
 	DBG("tcp_read: read %d bytes:\n%.*s\n", bytes_read, bytes_read, r->pos);
184 219
new file mode 100644
... ...
@@ -0,0 +1,72 @@
1
+/* 
2
+ * $Id$
3
+ * 
4
+ * Copyright (C) 2009 iptelorg GmbH
5
+ *
6
+ * Permission to use, copy, modify, and distribute this software for any
7
+ * purpose with or without fee is hereby granted, provided that the above
8
+ * copyright notice and this permission notice appear in all copies.
9
+ *
10
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
+ */
18
+/*
19
+ * tcp_stats.h - tcp statistics macros
20
+ */
21
+/*
22
+ * History:
23
+ * --------
24
+ *  2009-04-08  initial version (andrei)
25
+*/
26
+
27
+#ifndef __tcp_stats_h
28
+#define __tcp_stats_h
29
+
30
+/** called each time a new tcp connection is established.
31
+ *  @param state - S_CONN_ACCEPT if it was the result of an accept()
32
+ *               - S_CONN_CONNECT if it was the result of a connect()
33
+ * Note: in general it will be called when the first packet was received or
34
+ *   sent on the new connection and not immediately after accept() or 
35
+ *   connect()
36
+ */
37
+#define TCP_STATS_ESTABLISHED(state)
38
+
39
+/** called each time a new outgoing connection fails.  */
40
+#define TCP_STATS_CONNECT_FAILED()
41
+
42
+/** called each time a new incoming connection is rejected.
43
+ * (accept() denied due to maximum number of TCP connections being exceeded)
44
+ */
45
+#define TCP_STATS_LOCAL_REJECT()
46
+
47
+
48
+/** called each time a connection lifetime expires.
49
+  * (the connection is closed for being idle for too long)
50
+  */
51
+#define TCP_STATS_CON_TIMEOUT()
52
+
53
+
54
+/** called each time a TCP RST is received on an established connection.  */
55
+#define TCP_STATS_CON_RESET()
56
+
57
+/** called each time a send operation fails due to a timeout.
58
+  * FIXME: it works only in async mode (in sync. mode a send might timeout
59
+  *  but the stats won't be increased).
60
+  */
61
+#define TCP_STATS_SEND_TIMEOUT()
62
+
63
+/** called each time a send fails due to the buffering capacity being exceeded.
64
+  * (used only in tcp async mode)
65
+  */
66
+#define TCP_STATS_SENDQ_FULL()
67
+
68
+
69
+
70
+#endif /*__tcp_stats_h*/
71
+
72
+/* vi: set ts=4 sw=4 tw=79:ai:cindent: */