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 @@
0
+/* 
1
+ * $Id$
2
+ * 
3
+ * Copyright (C) 2009 iptelorg GmbH
4
+ *
5
+ * Permission to use, copy, modify, and distribute this software for any
6
+ * purpose with or without fee is hereby granted, provided that the above
7
+ * copyright notice and this permission notice appear in all copies.
8
+ *
9
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
+ */
17
+/*
18
+ * tcp_ev.h - tcp events
19
+ */
20
+/*
21
+ * History:
22
+ * --------
23
+ *  2009-04-09  initial version (andrei)
24
+*/
25
+
26
+#ifndef __tcp_ev_h
27
+#define __tcp_ev_h
28
+
29
+#include <errno.h>
30
+#include <string.h>
31
+
32
+#include "ip_addr.h"
33
+
34
+
35
+/** a connect attempt got a RST from the peer
36
+ * Note: the RST might be for the connect() itself (SYN), for the first
37
+ *  send() attempt on the connection (unlikely) or received immediately after
38
+ * the connect() succeeded (unlikely, the remote host would have a very small
39
+ *  window after accepting a connection to send a RST before it receives
40
+ * any data).
41
+ *
42
+ * @param err - if 0 it should be ignored (no corresp. libc error), if non-0
43
+ *                it will contain the errno.
44
+ * @param lip   - pointer to an ip_addr containing the local ip
45
+ *                   or 0 if dynamic (WARNING can be 0).
46
+ * @param lport - pointer to an ip_addr containing the local port or 0
47
+ *                   if unknown/dynamic.
48
+ * @param dst   - pointer to a sockaddr_union containing the destination.
49
+ * @param proto - protocol used
50
+ */
51
+#define TCP_EV_CONNECT_RST(err, lip, lport, dst, proto) \
52
+	LOG(L_ERR, "connect %s failed (RST) %s\n", \
53
+			su2a(dst, sizeof(*(dst))), (err)?strerror(err):"")
54
+
55
+/** a connect failed because the remote host/network is unreachable. */
56
+#define TCP_EV_CONNECT_UNREACHABLE(err, lip, lport, dst, proto) \
57
+	LOG(L_ERR, "connect %s failed (unreachable) %s\n", \
58
+			su2a(dst, sizeof(*(dst))), (err)?strerror(err):"")
59
+
60
+/** a connect attempt did timeout. */
61
+#define TCP_EV_CONNECT_TIMEOUT(err, lip, lport, dst, proto) \
62
+	LOG(L_ERR, "connect %s failed (timeout) %s\n", \
63
+			su2a(dst, sizeof(*(dst))), (err)?strerror(err):"")
64
+
65
+/** a connect attempt failed because the local ports are exhausted. */
66
+#define TCP_EV_CONNECT_NO_MORE_PORTS(err, lip, lport, dst, proto) \
67
+	LOG(L_ERR, "connect %s failed (no more ports) %s\n", \
68
+			su2a(dst, sizeof(*(dst))), (err)?strerror(err):"")
69
+
70
+/** a connect attempt failed for some unknown reason.  */
71
+#define TCP_EV_CONNECT_ERR(err, lip, lport, dst, proto) \
72
+	LOG(L_ERR, "connect %s failed %s\n", \
73
+			su2a(dst, sizeof(*(dst))), (err)?strerror(err):"")
74
+
75
+
76
+/** send failed due to timeout.
77
+ * @param err   - if 0 it should be ignored (no corresp. libc error), if non-0
78
+ *                it will contain the errno.
79
+ * @param rcv   - pointer to rcv_info structure
80
+ * 
81
+ */
82
+#define TCP_EV_SEND_TIMEOUT(err, rcv)
83
+
84
+/** send failed due to buffering capacity being exceeded.
85
+  * (only in async mode) */
86
+#define TCP_EV_SENDQ_FULL(err, rcv)
87
+
88
+/** established connection closed for being idle too long. */
89
+#define TCP_EV_IDLE_CONN_CLOSED(err, rcv)
90
+
91
+
92
+
93
+
94
+#endif /*__tcp_ev_h*/
95
+
96
+/* 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 155
 #include "sr_module.h"
156 156
 #include "tcp_server.h"
157 157
 #include "tcp_init.h"
158
+#include "tcp_stats.h"
159
+#include "tcp_ev.h"
158 160
 #include "tsend.h"
159 161
 #include "timer_ticks.h"
160 162
 #include "local_timer.h"
... ...
@@ -503,19 +506,45 @@ again:
503 503
 			else goto error_timeout;
504 504
 		}
505 505
 		if (errno!=EINPROGRESS && errno!=EALREADY){
506
+			switch(errno){
507
+				case ENETUNREACH:
508
+				case EHOSTUNREACH:
506 509
 #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:
510
+					if (cfg_get(core, core_cfg, use_dst_blacklist))
511
+						dst_blacklist_su(BLST_ERR_CONNECT, type,
512
+									 (union sockaddr_union*)servaddr, 0);
513
+#endif /* USE_DST_BLACKLIST */
514
+					TCP_EV_CONNECT_UNREACHABLE(errno, 0, 0,
515
+									(union sockaddr_union*)servaddr, type);
516
+					break;
517
+				case ETIMEDOUT:
518
+#ifdef USE_DST_BLACKLIST
519
+					if (cfg_get(core, core_cfg, use_dst_blacklist))
514 520
 						dst_blacklist_su(BLST_ERR_CONNECT, type,
515 521
 										 (union sockaddr_union*)servaddr, 0);
516
-						break;
517
-				}
518 522
 #endif /* USE_DST_BLACKLIST */
523
+					TCP_EV_CONNECT_TIMEOUT(errno, 0, 0,
524
+									(union sockaddr_union*)servaddr, type);
525
+					break;
526
+				case ECONNREFUSED:
527
+				case ECONNRESET:
528
+#ifdef USE_DST_BLACKLIST
529
+					if (cfg_get(core, core_cfg, use_dst_blacklist))
530
+						dst_blacklist_su(BLST_ERR_CONNECT, type,
531
+										 (union sockaddr_union*)servaddr, 0);
532
+#endif /* USE_DST_BLACKLIST */
533
+					TCP_EV_CONNECT_RST(errno, 0, 0,
534
+									(union sockaddr_union*)servaddr, type);
535
+					break;
536
+				case EAGAIN: /* not posix, but supported on linux and bsd */
537
+					TCP_EV_CONNECT_NO_MORE_PORTS(errno, 0, 0,
538
+									(union sockaddr_union*)servaddr, type);
539
+					break;
540
+				default:
541
+					TCP_EV_CONNECT_ERR(errno, 0, 0,
542
+										(union sockaddr_union*)servaddr, type);
543
+			}
544
+			TCP_STATS_CONNECT_FAILED();
519 545
 			LOG(L_ERR, "ERROR: tcp_blocking_connect %s: (%d) %s\n",
520 546
 					su2a((union sockaddr_union*)servaddr, addrlen),
521 547
 					errno, strerror(errno));
... ...
@@ -584,6 +613,8 @@ error_timeout:
584 584
 		dst_blacklist_su(BLST_ERR_CONNECT, type,
585 585
 							(union sockaddr_union*)servaddr, 0);
586 586
 #endif /* USE_DST_BLACKLIST */
587
+	TCP_EV_CONNECT_TIMEOUT(0, 0, 0, (union sockaddr_union*)servaddr, type);
588
+	TCP_STATS_CONNECT_FAILED();
587 589
 	LOG(L_ERR, "ERROR: tcp_blocking_connect %s: timeout %d s elapsed "
588 590
 				"from %d s\n", su2a((union sockaddr_union*)servaddr, addrlen),
589 591
 				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 630
 					size, q->queued, *tcp_total_wq,
631 631
 					TICKS_TO_S(t-q->wr_timeout-
632 632
 						cfg_get(tcp, tcp_cfg, send_timeout)));
633
+		if (q->first && TICKS_LT(q->wr_timeout, t)){
634
+			if (unlikely(c->state==S_CONN_CONNECT)){
633 635
 #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
-		}
636
+				if (likely(cfg_get(core, core_cfg, use_dst_blacklist))){
637
+					DBG("blacklisting, state=%d\n", c->state);
638
+					dst_blacklist_su( BLST_ERR_CONNECT, c->rcv.proto,
639
+										&c->rcv.src_su, 0);
640
+				}
641
+#endif /* USE_DST_BLACKLIST */
642
+				TCP_EV_CONNECT_TIMEOUT(0, TCP_LADDR(c), TCP_LPORT(c),
643
+											TCP_PSU(c), TCP_PROTO(c));
644
+				TCP_STATS_CONNECT_FAILED();
645
+			}else{
646
+#ifdef USE_DST_BLACKLIST
647
+				if (likely(cfg_get(core, core_cfg, use_dst_blacklist))){
648
+					DBG("blacklisting, state=%d\n", c->state);
649
+					dst_blacklist_su( BLST_ERR_SEND, c->rcv.proto,
650
+										&c->rcv.src_su, 0);
651
+				}
641 652
 #endif /* USE_DST_BLACKLIST */
653
+				TCP_EV_SEND_TIMEOUT(0, &c->rcv);
654
+				TCP_STATS_SEND_TIMEOUT();
655
+			}
656
+		}else{
657
+			/* if it's not a timeout => queue full */
658
+			TCP_EV_SENDQ_FULL(0, &c->rcv);
659
+			TCP_STATS_SENDQ_FULL();
660
+		}
642 661
 		goto error;
643 662
 	}
644 663
 	
... ...
@@ -808,20 +858,55 @@ inline static int wbufq_run(int fd, struct tcp_connection* c, int* empty)
808 808
 			if (n<0){
809 809
 				/* EINTR is handled inside _tcpconn_write_nb */
810 810
 				if (!(errno==EAGAIN || errno==EWOULDBLOCK)){
811
-#ifdef USE_DST_BLACKLIST
812
-					if (cfg_get(core, core_cfg, use_dst_blacklist))
811
+					if (unlikely(c->state==S_CONN_CONNECT)){
813 812
 						switch(errno){
814 813
 							case ENETUNREACH:
814
+							case EHOSTUNREACH: /* not posix for send() */
815
+#ifdef USE_DST_BLACKLIST
816
+								if (cfg_get(core, core_cfg, use_dst_blacklist))
817
+									dst_blacklist_su(BLST_ERR_CONNECT,
818
+															c->rcv.proto,
819
+															&c->rcv.src_su, 0);
820
+#endif /* USE_DST_BLACKLIST */
821
+								TCP_EV_CONNECT_UNREACHABLE(errno, TCP_LADDR(c),
822
+													TCP_LPORT(c), TCP_PSU(c),
823
+													TCP_PROTO(c));
824
+								break;
825
+							case ECONNREFUSED:
815 826
 							case ECONNRESET:
816
-							/*case EHOSTUNREACH: -- not posix */
817
-								dst_blacklist_su((c->state==S_CONN_CONNECT)?
818
-														BLST_ERR_CONNECT:
819
-														BLST_ERR_SEND,
827
+#ifdef USE_DST_BLACKLIST
828
+								if (cfg_get(core, core_cfg, use_dst_blacklist))
829
+									dst_blacklist_su(BLST_ERR_CONNECT,
830
+															c->rcv.proto,
831
+															&c->rcv.src_su, 0);
832
+#endif /* USE_DST_BLACKLIST */
833
+								TCP_EV_CONNECT_RST(0, TCP_LADDR(c),
834
+													TCP_LPORT(c), TCP_PSU(c),
835
+													TCP_PROTO(c));
836
+								break;
837
+							default:
838
+								TCP_EV_CONNECT_ERR(errno, TCP_LADDR(c),
839
+													TCP_LPORT(c), TCP_PSU(c),
840
+													TCP_PROTO(c));
841
+						}
842
+						TCP_STATS_CONNECT_FAILED();
843
+					}else{
844
+						switch(errno){
845
+							case ECONNREFUSED:
846
+							case ECONNRESET:
847
+								TCP_STATS_CON_RESET();
848
+								/* no break */
849
+							case ENETUNREACH:
850
+							case EHOSTUNREACH: /* not posix for send() */
851
+#ifdef USE_DST_BLACKLIST
852
+								if (cfg_get(core, core_cfg, use_dst_blacklist))
853
+									dst_blacklist_su(BLST_ERR_SEND,
820 854
 														c->rcv.proto,
821 855
 														&c->rcv.src_su, 0);
856
+#endif /* USE_DST_BLACKLIST */
822 857
 								break;
823 858
 						}
824
-#endif /* USE_DST_BLACKLIST */
859
+					}
825 860
 					ret=-1;
826 861
 					LOG(L_ERR, "ERROR: wbuf_runq: %s [%d]\n",
827 862
 						strerror(errno), errno);
... ...
@@ -839,8 +924,10 @@ inline static int wbufq_run(int fd, struct tcp_connection* c, int* empty)
839 839
 	lock_release(&c->write_lock);
840 840
 	if (likely(ret>0)){
841 841
 		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))
842
+		if (unlikely(c->state==S_CONN_CONNECT || c->state==S_CONN_ACCEPT)){
843
+			TCP_STATS_ESTABLISHED(c->state);
843 844
 			c->state=S_CONN_OK;
845
+		}
844 846
 	}
845 847
 	return ret;
846 848
 }
... ...
@@ -1032,19 +1119,37 @@ again:
1032 1032
 				*state=S_CONN_CONNECT;
1033 1033
 			else if (errno==EINTR) goto again;
1034 1034
 			else if (errno!=EALREADY){
1035
+				switch(errno){
1036
+					case ENETUNREACH:
1037
+					case EHOSTUNREACH:
1035 1038
 #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
-				}
1039
+						if (cfg_get(core, core_cfg, use_dst_blacklist))
1040
+							dst_blacklist_su(BLST_ERR_CONNECT, type, server,0);
1041
+#endif /* USE_DST_BLACKLIST */
1042
+						TCP_EV_CONNECT_UNREACHABLE(errno, 0, 0, server, type);
1043
+						break;
1044
+					case ETIMEDOUT:
1045
+#ifdef USE_DST_BLACKLIST
1046
+						if (cfg_get(core, core_cfg, use_dst_blacklist))
1047
+							dst_blacklist_su(BLST_ERR_CONNECT, type, server,0);
1047 1048
 #endif /* USE_DST_BLACKLIST */
1049
+						TCP_EV_CONNECT_TIMEOUT(errno, 0, 0, server, type);
1050
+						break;
1051
+					case ECONNREFUSED:
1052
+					case ECONNRESET:
1053
+#ifdef USE_DST_BLACKLIST
1054
+						if (cfg_get(core, core_cfg, use_dst_blacklist))
1055
+							dst_blacklist_su(BLST_ERR_CONNECT, type, server,0);
1056
+#endif /* USE_DST_BLACKLIST */
1057
+						TCP_EV_CONNECT_RST(errno, 0, 0, server, type);
1058
+						break;
1059
+					case EAGAIN:/* not posix, but supported on linux and bsd */
1060
+						TCP_EV_CONNECT_NO_MORE_PORTS(errno, 0, 0, server,type);
1061
+						break;
1062
+					default:
1063
+						TCP_EV_CONNECT_ERR(errno, 0, 0, server, type);
1064
+				}
1065
+				TCP_STATS_CONNECT_FAILED();
1048 1066
 				LOG(L_ERR, "ERROR: tcp_do_connect: connect %s: (%d) %s\n",
1049 1067
 							su2a(server, sizeof(*server)),
1050 1068
 							errno, strerror(errno));
... ...
@@ -1744,9 +1849,11 @@ no_id:
1744 1744
 						DBG("tcp_send: pending write on new connection %p "
1745 1745
 								" (%d/%d bytes written)\n", c, n, len);
1746 1746
 						if (n<0) n=0;
1747
-						else 
1747
+						else{
1748
+							TCP_STATS_ESTABLISHED(S_CONN_CONNECT);
1748 1749
 							c->state=S_CONN_OK; /* partial write => connect()
1749 1750
 													ended */
1751
+						}
1750 1752
 						/* add to the write queue */
1751 1753
 						lock_get(&c->write_lock);
1752 1754
 							if (unlikely(_wbufq_insert(c, buf+n, len-n)<0)){
... ...
@@ -1774,19 +1881,33 @@ no_id:
1774 1774
 						n=len;
1775 1775
 						goto end;
1776 1776
 					}
1777
+					/* if first write failed it's most likely a
1778
+					   connect error */
1779
+					switch(errno){
1780
+						case ENETUNREACH:
1781
+						case EHOSTUNREACH:  /* not posix for send() */
1777 1782
 #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 */
1783
+							if (cfg_get(core, core_cfg, use_dst_blacklist))
1785 1784
 								dst_blacklist_add( BLST_ERR_CONNECT, dst, 0);
1786
-								break;
1787
-						}
1788 1785
 #endif /* USE_DST_BLACKLIST */
1786
+							TCP_EV_CONNECT_UNREACHABLE(errno, TCP_LADDR(c),
1787
+									TCP_LPORT(c), TCP_PSU(c), TCP_PROTO(c));
1788
+							break;
1789
+						case ECONNREFUSED:
1790
+						case ECONNRESET:
1791
+#ifdef USE_DST_BLACKLIST
1792
+							if (cfg_get(core, core_cfg, use_dst_blacklist))
1793
+								dst_blacklist_add( BLST_ERR_CONNECT, dst, 0);
1794
+#endif /* USE_DST_BLACKLIST */
1795
+							TCP_EV_CONNECT_RST(errno, TCP_LADDR(c),
1796
+									TCP_LPORT(c), TCP_PSU(c), TCP_PROTO(c));
1797
+							break;
1798
+						default:
1799
+							TCP_EV_CONNECT_ERR(errno, TCP_LADDR(c),
1800
+									TCP_LPORT(c), TCP_PSU(c), TCP_PROTO(c));
1801
+					}
1789 1802
 					/* error: destroy it directly */
1803
+					TCP_STATS_CONNECT_FAILED();
1790 1804
 					LOG(L_ERR, "ERROR: tcp_send %s: connect & send "
1791 1805
 										" for %p failed:" " %s (%d)\n",
1792 1806
 										su2a(&dst->to, sizeof(dst->to)),
... ...
@@ -1794,6 +1915,7 @@ no_id:
1794 1794
 					goto conn_wait_error;
1795 1795
 				}
1796 1796
 				LOG(L_INFO, "tcp_send: quick connect for %p\n", c);
1797
+				TCP_STATS_ESTABLISHED(S_CONN_CONNECT);
1797 1798
 				c->state=S_CONN_OK;
1798 1799
 				/* send to tcp_main */
1799 1800
 				response[0]=(long)c;
... ...
@@ -1814,6 +1936,8 @@ no_id:
1814 1814
 								su2a(&dst->to, sizeof(dst->to)));
1815 1815
 				return -1;
1816 1816
 			}
1817
+			if (likely(c->state==S_CONN_OK))
1818
+				TCP_STATS_ESTABLISHED(S_CONN_CONNECT);
1817 1819
 			atomic_set(&c->refcnt, 2); /* ref. from here and it will also
1818 1820
 			                              be added in the tcp_main hash */
1819 1821
 			fd=c->s;
... ...
@@ -1965,8 +2089,10 @@ send_it:
1965 1965
 			enable_write_watch=_wbufq_empty(c);
1966 1966
 			if (n<0) n=0;
1967 1967
 			else if (unlikely(c->state==S_CONN_CONNECT ||
1968
-						c->state==S_CONN_ACCEPT))
1968
+						c->state==S_CONN_ACCEPT)){
1969
+				TCP_STATS_ESTABLISHED(c->state);
1969 1970
 				c->state=S_CONN_OK; /* something was written */
1971
+			}
1970 1972
 			if (unlikely(_wbufq_add(c, buf+n, len-n)<0)){
1971 1973
 				lock_release(&c->write_lock);
1972 1974
 				n=-1;
... ...
@@ -1989,20 +2115,49 @@ send_it:
1989 1989
 			lock_release(&c->write_lock);
1990 1990
 		}
1991 1991
 #endif /* TCP_ASYNC */
1992
-#ifdef USE_DST_BLACKLIST
1993
-		if (cfg_get(core, core_cfg, use_dst_blacklist))
1992
+		if (unlikely(c->state==S_CONN_CONNECT)){
1994 1993
 			switch(errno){
1995 1994
 				case ENETUNREACH:
1995
+				case EHOSTUNREACH: /* not posix for send() */
1996
+#ifdef USE_DST_BLACKLIST
1997
+					if (cfg_get(core, core_cfg, use_dst_blacklist))
1998
+						dst_blacklist_su(BLST_ERR_CONNECT, c->rcv.proto,
1999
+											&c->rcv.src_su, 0);
2000
+#endif /* USE_DST_BLACKLIST */
2001
+					TCP_EV_CONNECT_UNREACHABLE(errno, TCP_LADDR(c),
2002
+									TCP_LPORT(c), TCP_PSU(c), TCP_PROTO(c));
2003
+					break;
2004
+				case ECONNREFUSED:
2005
+				case ECONNRESET:
2006
+#ifdef USE_DST_BLACKLIST
2007
+					if (cfg_get(core, core_cfg, use_dst_blacklist))
2008
+						dst_blacklist_su(BLST_ERR_CONNECT, c->rcv.proto,
2009
+											&c->rcv.src_su, 0);
2010
+#endif /* USE_DST_BLACKLIST */
2011
+					TCP_EV_CONNECT_RST(errno, TCP_LADDR(c), TCP_LPORT(c),
2012
+										TCP_PSU(c), TCP_PROTO(c));
2013
+					break;
2014
+				default:
2015
+					TCP_EV_CONNECT_ERR(errno, TCP_LADDR(c), TCP_LPORT(c),
2016
+										TCP_PSU(c), TCP_PROTO(c));
2017
+				}
2018
+			TCP_STATS_CONNECT_FAILED();
2019
+		}else{
2020
+			switch(errno){
2021
+				case ECONNREFUSED:
1996 2022
 				case ECONNRESET:
2023
+					TCP_STATS_CON_RESET();
2024
+					/* no break */
2025
+				case ENETUNREACH:
1997 2026
 				/*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);
2027
+#ifdef USE_DST_BLACKLIST
2028
+					if (cfg_get(core, core_cfg, use_dst_blacklist))
2029
+						dst_blacklist_su(BLST_ERR_SEND, c->rcv.proto,
2030
+												&c->rcv.src_su, 0);
2031
+#endif /* USE_DST_BLACKLIST */
2003 2032
 					break;
2004 2033
 			}
2005
-#endif /* USE_DST_BLACKLIST */
2034
+		}
2006 2035
 		LOG(L_ERR, "ERROR: tcp_send: failed to send on %p (%s:%d->%s): %s (%d)"
2007 2036
 					"\n", c, ip_addr2a(&c->rcv.dst_ip), c->rcv.dst_port,
2008 2037
 					su2a(&c->rcv.src_su, sizeof(c->rcv.src_su)),
... ...
@@ -2042,8 +2197,10 @@ error:
2042 2042
 	lock_release(&c->write_lock);
2043 2043
 #endif /* TCP_ASYNC */
2044 2044
 	/* 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))
2045
+	if (unlikely(c->state==S_CONN_CONNECT || c->state==S_CONN_ACCEPT)){
2046
+			TCP_STATS_ESTABLISHED(c->state);
2046 2047
 			c->state=S_CONN_OK;
2048
+	}
2047 2049
 end:
2048 2050
 #ifdef TCP_FD_CACHE
2049 2051
 	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 2682
 							"refcnt= %d\n", tcpconn,
2683 2683
 							atomic_get(&tcpconn->refcnt));
2684 2684
 					/* timeout */
2685
+					if (unlikely(tcpconn->state==S_CONN_CONNECT)){
2685 2686
 #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,
2687
+						if (cfg_get(core, core_cfg, use_dst_blacklist))
2688
+							dst_blacklist_su( BLST_ERR_CONNECT,
2689
+													tcpconn->rcv.proto,
2690
+													&tcpconn->rcv.src_su, 0);
2691
+#endif /* USE_DST_BLACKLIST */
2692
+						TCP_EV_CONNECT_TIMEOUT(0, TCP_LADDR(tcpconn),
2693
+										TCP_LPORT(tcpconn), TCP_PSU(tcpconn),
2694
+										TCP_PROTO(tcpconn));
2695
+						TCP_STATS_CONNECT_FAILED();
2696
+					}else{
2697
+#ifdef USE_DST_BLACKLIST
2698
+						if (cfg_get(core, core_cfg, use_dst_blacklist))
2699
+							dst_blacklist_su( BLST_ERR_SEND,
2690 2700
 													tcpconn->rcv.proto,
2691 2701
 													&tcpconn->rcv.src_su, 0);
2692 2702
 #endif /* USE_DST_BLACKLIST */
2703
+						TCP_EV_SEND_TIMEOUT(0, &tcpconn->rcv);
2704
+						TCP_STATS_SEND_TIMEOUT();
2705
+					}
2693 2706
 					if (unlikely(tcpconn->flags & F_CONN_WRITE_W)){
2694 2707
 						io_watch_del(&io_h, tcpconn->s, -1, IO_FD_CLOSING);
2695 2708
 						tcpconn->flags&=~F_CONN_WRITE_W;
... ...
@@ -3182,6 +3352,7 @@ static inline int handle_new_connect(struct socket_info* si)
3182 3182
 					*tcp_connections_no,
3183 3183
 					cfg_get(tcp, tcp_cfg, max_connections));
3184 3184
 		close(new_sock);
3185
+		TCP_STATS_LOCAL_REJECT();
3185 3186
 		return 1; /* success, because the accept was succesfull */
3186 3187
 	}
3187 3188
 	if (unlikely(init_sock_opt_accept(new_sock)<0)){
... ...
@@ -3190,6 +3361,7 @@ static inline int handle_new_connect(struct socket_info* si)
3190 3190
 		return 1; /* success, because the accept was succesfull */
3191 3191
 	}
3192 3192
 	(*tcp_connections_no)++;
3193
+	TCP_STATS_ESTABLISHED(S_CONN_ACCEPT);
3193 3194
 	
3194 3195
 	dst_su=&si->su;
3195 3196
 	if (unlikely(si->flags & SI_IS_ANY)){
... ...
@@ -3323,6 +3495,16 @@ inline static int handle_tcpconn_ev(struct tcp_connection* tcpconn, short ev,
3323 3323
 				LOG(L_CRIT, "BUG: tcpconn_ev: unhashed connection %p\n",
3324 3324
 							tcpconn);
3325 3325
 			}
3326
+			if (unlikely(ev & POLLERR)){
3327
+				if (unlikely(tcpconn->state=S_CONN_CONNECT)){
3328
+					TCP_EV_CONNECT_ERR(0, TCP_LADDR(tcpconn),
3329
+										TCP_LPORT(tcpconn), TCP_PSU(tcpconn),
3330
+										TCP_PROTO(tcpconn));
3331
+					TCP_STATS_CONNECT_FAILED();
3332
+				}else{
3333
+					TCP_STATS_CON_RESET(); /* FIXME: it could != RST */
3334
+				}
3335
+			}
3326 3336
 			tcpconn_put_destroy(tcpconn);
3327 3337
 			goto error;
3328 3338
 		}
... ...
@@ -3485,15 +3667,27 @@ static ticks_t tcpconn_main_timeout(ticks_t t, struct timer_ln* tl, void* data)
3485 3485
 		else
3486 3486
 			return (ticks_t)(c->timeout - t);
3487 3487
 	}
3488
-#ifdef USE_DST_BLACKLIST
3489 3488
 	/* 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);
3489
+	if (tcp_async && _wbufq_non_empty(c) && TICKS_GE(t, c->wbuf_q.wr_timeout)){
3490
+		if (unlikely(c->state==S_CONN_CONNECT)){
3491
+#ifdef USE_DST_BLACKLIST
3492
+			if (cfg_get(core, core_cfg, use_dst_blacklist))
3493
+				dst_blacklist_su(BLST_ERR_CONNECT, c->rcv.proto,
3494
+									&c->rcv.src_su, 0);
3495
+#endif /* USE_DST_BLACKLIST */
3496
+			TCP_EV_CONNECT_TIMEOUT(0, TCP_LADDR(c), TCP_LPORT(c), TCP_PSU(c),
3497
+									TCP_PROTO(c));
3498
+			TCP_STATS_CONNECT_FAILED();
3499
+		}else{
3500
+#ifdef USE_DST_BLACKLIST
3501
+			if (cfg_get(core, core_cfg, use_dst_blacklist))
3502
+				dst_blacklist_su(BLST_ERR_SEND, c->rcv.proto,
3503
+									&c->rcv.src_su, 0);
3496 3504
 #endif /* USE_DST_BLACKLIST */
3505
+			TCP_EV_SEND_TIMEOUT(0, &c->rcv);
3506
+			TCP_STATS_SEND_TIMEOUT();
3507
+		}
3508
+	}
3497 3509
 #else /* ! TCP_ASYNC */
3498 3510
 	if (TICKS_LT(t, c->timeout)){
3499 3511
 		/* timeout extended, exit */
... ...
@@ -3520,6 +3714,8 @@ static ticks_t tcpconn_main_timeout(ticks_t t, struct timer_ln* tl, void* data)
3520 3520
 			c->flags&=~(F_CONN_READ_W|F_CONN_WRITE_W);
3521 3521
 		}
3522 3522
 	}
3523
+	TCP_EV_IDLE_CONN_CLOSED(0, &c->rcv);
3524
+	TCP_STATS_CON_TIMEOUT();
3523 3525
 	tcpconn_put_destroy(c);
3524 3526
 	return 0;
3525 3527
 }
... ...
@@ -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 61
 
62 62
 #include "dprint.h"
63 63
 #include "tcp_conn.h"
64
+#include "tcp_stats.h"
65
+#include "tcp_ev.h"
64 66
 #include "pass_fd.h"
65 67
 #include "globals.h"
66 68
 #include "receive.h"
... ...
@@ -146,19 +149,47 @@ again:
146 146
 				bytes_read=0; /* nothing has been read */
147 147
 			}else if (errno == EINTR) goto again;
148 148
 			else{
149
-#ifdef USE_DST_BLACKLIST
150
-				if (cfg_get(core, core_cfg, use_dst_blacklist))
149
+				if (unlikely(c->state=S_CONN_CONNECT)){
151 150
 					switch(errno){
152 151
 						case ECONNRESET:
152
+#ifdef USE_DST_BLACKLIST
153
+							if (cfg_get(core, core_cfg, use_dst_blacklist))
154
+								dst_blacklist_su(BLST_ERR_CONNECT,
155
+														c->rcv.proto,
156
+														&c->rcv.src_su, 0);
157
+#endif /* USE_DST_BLACKLIST */
158
+							TCP_EV_CONNECT_RST(errno, TCP_LADDR(c),
159
+									TCP_LPORT(c), TCP_PSU(c), TCP_PROTO(c));
160
+							break;
153 161
 						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);
162
+#ifdef USE_DST_BLACKLIST
163
+							if (cfg_get(core, core_cfg, use_dst_blacklist))
164
+								dst_blacklist_su(BLST_ERR_CONNECT,
165
+														c->rcv.proto,
166
+														&c->rcv.src_su, 0);
167
+#endif /* USE_DST_BLACKLIST */
168
+							TCP_EV_CONNECT_TIMEOUT(errno, TCP_LADDR(c),
169
+									TCP_LPORT(c), TCP_PSU(c), TCP_PROTO(c));
159 170
 							break;
171
+						default:
172
+							TCP_EV_CONNECT_ERR(errno, TCP_LADDR(c),
173
+									TCP_LPORT(c), TCP_PSU(c), TCP_PROTO(c));
160 174
 					}
175
+					TCP_STATS_CONNECT_FAILED();
176
+				}else{
177
+						switch(errno){
178
+							case ECONNRESET:
179
+								TCP_STATS_CON_RESET();
180
+							case ETIMEDOUT:
181
+#ifdef USE_DST_BLACKLIST
182
+								if (cfg_get(core, core_cfg, use_dst_blacklist))
183
+									dst_blacklist_su(BLST_ERR_SEND,
184
+														c->rcv.proto,
185
+														&c->rcv.src_su, 0);
161 186
 #endif /* USE_DST_BLACKLIST */
187
+								break;
188
+						}
189
+				}
162 190
 				LOG(L_ERR, "ERROR: tcp_read: error reading: %s (%d)\n",
163 191
 							strerror(errno), errno);
164 192
 				r->error=TCP_READ_ERROR;
... ...
@@ -170,14 +201,18 @@ again:
170 170
 			*flags|=RD_CONN_EOF;
171 171
 			DBG("tcp_read: EOF on %p, FD %d\n", c, fd);
172 172
 		}else{
173
-			if (unlikely(c->state==S_CONN_CONNECT || c->state==S_CONN_ACCEPT))
173
+			if (unlikely(c->state==S_CONN_CONNECT || c->state==S_CONN_ACCEPT)){
174
+				TCP_STATS_ESTABLISHED(c->state);
174 175
 				c->state=S_CONN_OK;
176
+			}
175 177
 		}
176 178
 		/* short read */
177 179
 		*flags|=RD_CONN_SHORT_READ;
178 180
 	}else{ /* else normal full read */
179
-		if (unlikely(c->state==S_CONN_CONNECT || c->state==S_CONN_ACCEPT))
181
+		if (unlikely(c->state==S_CONN_CONNECT || c->state==S_CONN_ACCEPT)){
182
+			TCP_STATS_ESTABLISHED(c->state);
180 183
 			c->state=S_CONN_OK;
184
+		}
181 185
 	}
182 186
 #ifdef EXTRA_DEBUG
183 187
 	DBG("tcp_read: read %d bytes:\n%.*s\n", bytes_read, bytes_read, r->pos);
184 188
new file mode 100644
... ...
@@ -0,0 +1,72 @@
0
+/* 
1
+ * $Id$
2
+ * 
3
+ * Copyright (C) 2009 iptelorg GmbH
4
+ *
5
+ * Permission to use, copy, modify, and distribute this software for any
6
+ * purpose with or without fee is hereby granted, provided that the above
7
+ * copyright notice and this permission notice appear in all copies.
8
+ *
9
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
+ */
17
+/*
18
+ * tcp_stats.h - tcp statistics macros
19
+ */
20
+/*
21
+ * History:
22
+ * --------
23
+ *  2009-04-08  initial version (andrei)
24
+*/
25
+
26
+#ifndef __tcp_stats_h
27
+#define __tcp_stats_h
28
+
29
+/** called each time a new tcp connection is established.
30
+ *  @param state - S_CONN_ACCEPT if it was the result of an accept()
31
+ *               - S_CONN_CONNECT if it was the result of a connect()
32
+ * Note: in general it will be called when the first packet was received or
33
+ *   sent on the new connection and not immediately after accept() or 
34
+ *   connect()
35
+ */
36
+#define TCP_STATS_ESTABLISHED(state)
37
+
38
+/** called each time a new outgoing connection fails.  */
39
+#define TCP_STATS_CONNECT_FAILED()
40
+
41
+/** called each time a new incoming connection is rejected.
42
+ * (accept() denied due to maximum number of TCP connections being exceeded)
43
+ */
44
+#define TCP_STATS_LOCAL_REJECT()
45
+
46
+
47
+/** called each time a connection lifetime expires.
48
+  * (the connection is closed for being idle for too long)
49
+  */
50
+#define TCP_STATS_CON_TIMEOUT()
51
+
52
+
53
+/** called each time a TCP RST is received on an established connection.  */
54
+#define TCP_STATS_CON_RESET()
55
+
56
+/** called each time a send operation fails due to a timeout.
57
+  * FIXME: it works only in async mode (in sync. mode a send might timeout
58
+  *  but the stats won't be increased).
59
+  */
60
+#define TCP_STATS_SEND_TIMEOUT()
61
+
62
+/** called each time a send fails due to the buffering capacity being exceeded.
63
+  * (used only in tcp async mode)
64
+  */
65
+#define TCP_STATS_SENDQ_FULL()
66
+
67
+
68
+
69
+#endif /*__tcp_stats_h*/
70
+
71
+/* vi: set ts=4 sw=4 tw=79:ai:cindent: */