2929#include "we_util.h"
3030#include "we_metric.h"
3131
32+ #include <iphlpapi.h>
33+
34+ const char * TCP_STATE_STRINGS [] = {
35+ "ESTABLISHED" , "SYN_SENT" , "SYN_RECV" , "FIN_WAIT1" , "FIN_WAIT2" , "TIME_WAIT" ,
36+ "CLOSE" , "CLOSE_WAIT" , "LAST_ACK" , "LISTEN" , "CLOSING" , "DELETE_TCB" , "UNKNOWN"
37+ };
38+
39+ static inline int windows_state_to_index (int state )
40+ {
41+ switch (state ) {
42+ case MIB_TCP_STATE_ESTAB :
43+ return 0 ;
44+ case MIB_TCP_STATE_SYN_SENT :
45+ return 1 ;
46+ case MIB_TCP_STATE_SYN_RCVD :
47+ return 2 ;
48+ case MIB_TCP_STATE_FIN_WAIT1 :
49+ return 3 ;
50+ case MIB_TCP_STATE_FIN_WAIT2 :
51+ return 4 ;
52+ case MIB_TCP_STATE_TIME_WAIT :
53+ return 5 ;
54+ /* MIB_TCP_STATE_CLOSED is 1 */
55+ case MIB_TCP_STATE_CLOSE_WAIT :
56+ return 7 ;
57+ case MIB_TCP_STATE_LAST_ACK :
58+ return 8 ;
59+ case MIB_TCP_STATE_LISTEN :
60+ return 9 ;
61+ case MIB_TCP_STATE_CLOSING :
62+ return 10 ;
63+ case MIB_TCP_STATE_DELETE_TCB :
64+ return 11 ;
65+ default :
66+ return 12 ;
67+ }
68+ }
69+
70+ static int we_tcp_get_state_metrics (struct flb_we * ctx , const char * af_label )
71+ {
72+ PMIB_TCPTABLE2 tcp_table = NULL ;
73+ ULONG buffer_size = 0 ;
74+ DWORD result ;
75+ DWORD idx = 0 ;
76+ int state_index ;
77+ int i = 0 ;
78+ const char * state_label ;
79+ uint64_t timestamp = cfl_time_now ();
80+ int af_family = (strcmp (af_label , "ipv4" ) == 0 ) ? AF_INET : AF_INET6 ;
81+ unsigned int state_counts [13 ] = {0 };
82+ const char * labels [2 ];
83+
84+ result = GetExtendedTcpTable (NULL , & buffer_size , FALSE, af_family , TCP_TABLE_OWNER_PID_ALL , 0 );
85+ if (result != ERROR_INSUFFICIENT_BUFFER ) {
86+ flb_plg_error (ctx -> ins , "TCP state metrics: error getting buffer size: %lu" , result );
87+ return -1 ;
88+ }
89+
90+ tcp_table = (PMIB_TCPTABLE2 )flb_malloc (buffer_size );
91+ if (tcp_table == NULL ) {
92+ flb_plg_error (ctx -> ins , "TCP state metrics: could not allocate buffer" );
93+ return -1 ;
94+ }
95+
96+ result = GetExtendedTcpTable (tcp_table , & buffer_size , FALSE, af_family , TCP_TABLE_OWNER_PID_ALL , 0 );
97+ if (result != NO_ERROR ) {
98+ flb_plg_error (ctx -> ins , "TCP state metrics: error getting table: %lu" , result );
99+ flb_free (tcp_table );
100+ return -1 ;
101+ }
102+
103+ for (idx = 0 ; idx < tcp_table -> dwNumEntries ; idx ++ ) {
104+ state_index = windows_state_to_index (tcp_table -> table [idx ].dwState );
105+ state_counts [state_index ]++ ;
106+ }
107+
108+ flb_free (tcp_table );
109+
110+ for (i = 0 ; i < 13 ; i ++ ) {
111+ if (state_counts [i ] > 0 ) {
112+ state_label = TCP_STATE_STRINGS [i ];
113+ labels [0 ] = af_label ;
114+ labels [1 ] = state_label ;
115+ cmt_gauge_set (ctx -> wmi_tcp -> connections_state , timestamp ,
116+ (double )state_counts [i ], 2 , (char * * )labels );
117+ }
118+ }
119+
120+ return 0 ;
121+ }
122+
32123int we_wmi_tcp_init (struct flb_we * ctx )
33124{
34125 ctx -> wmi_tcp = flb_calloc (1 , sizeof (struct we_wmi_tcp_counters ));
@@ -40,12 +131,22 @@ int we_wmi_tcp_init(struct flb_we *ctx)
40131
41132 struct cmt_gauge * g ;
42133 struct cmt_counter * c ;
43- char * label = "af" ;
134+ char * wmi_label [] = {"af" };
135+ char * state_labels [] = {"af" , "state" };
136+
137+ g = cmt_gauge_create (ctx -> cmt , "windows" , "tcp" ,
138+ "connections_state" ,
139+ "Number of connections in a given state." ,
140+ 2 , state_labels );
141+ if (!g ) {
142+ return -1 ;
143+ }
144+ ctx -> wmi_tcp -> connections_state = g ;
44145
45146 c = cmt_counter_create (ctx -> cmt , "windows" , "tcp" ,
46147 "connection_failures_total" ,
47148 "Total number of connection failures." ,
48- 1 , & label );
149+ 1 , wmi_label );
49150 if (!c ) {
50151 return -1 ;
51152 }
@@ -54,7 +155,7 @@ int we_wmi_tcp_init(struct flb_we *ctx)
54155 g = cmt_gauge_create (ctx -> cmt , "windows" , "tcp" ,
55156 "connections_active" ,
56157 "Number of active TCP connections." ,
57- 1 , & label );
158+ 1 , wmi_label );
58159 if (!g ) {
59160 return -1 ;
60161 }
@@ -63,7 +164,7 @@ int we_wmi_tcp_init(struct flb_we *ctx)
63164 c = cmt_counter_create (ctx -> cmt , "windows" , "tcp" ,
64165 "connections_established_total" ,
65166 "Total number of TCP connections established." ,
66- 1 , & label );
167+ 1 , wmi_label );
67168 if (!c ) {
68169 return -1 ;
69170 }
@@ -72,7 +173,7 @@ int we_wmi_tcp_init(struct flb_we *ctx)
72173 c = cmt_counter_create (ctx -> cmt , "windows" , "tcp" ,
73174 "connections_passive_total" ,
74175 "Total number of passive TCP connections." ,
75- 1 , & label );
176+ 1 , wmi_label );
76177 if (!c ) {
77178 return -1 ;
78179 }
@@ -81,7 +182,7 @@ int we_wmi_tcp_init(struct flb_we *ctx)
81182 c = cmt_counter_create (ctx -> cmt , "windows" , "tcp" ,
82183 "connections_reset_total" ,
83184 "Total number of reset TCP connections." ,
84- 1 , & label );
185+ 1 , wmi_label );
85186 if (!c ) {
86187 return -1 ;
87188 }
@@ -90,7 +191,7 @@ int we_wmi_tcp_init(struct flb_we *ctx)
90191 g = cmt_gauge_create (ctx -> cmt , "windows" , "tcp" ,
91192 "segments_total" ,
92193 "Total TCP segments sent or received per second." ,
93- 1 , & label );
194+ 1 , wmi_label );
94195 if (!g ) {
95196 return -1 ;
96197 }
@@ -99,7 +200,7 @@ int we_wmi_tcp_init(struct flb_we *ctx)
99200 g = cmt_gauge_create (ctx -> cmt , "windows" , "tcp" ,
100201 "segments_total" ,
101202 "TCP segments received per second." ,
102- 1 , & label );
203+ 1 , wmi_label );
103204 if (!g ) {
104205 return -1 ;
105206 }
@@ -108,7 +209,7 @@ int we_wmi_tcp_init(struct flb_we *ctx)
108209 g = cmt_gauge_create (ctx -> cmt , "windows" , "tcp" ,
109210 "segments_retransmitted_total" ,
110211 "TCP segments retransmitted per second." ,
111- 1 , & label );
212+ 1 , wmi_label );
112213 if (!g ) {
113214 return -1 ;
114215 }
@@ -117,7 +218,7 @@ int we_wmi_tcp_init(struct flb_we *ctx)
117218 g = cmt_gauge_create (ctx -> cmt , "windows" , "tcp" ,
118219 "segments_sent_total" ,
119220 "TCP segments sent per second." ,
120- 1 , & label );
221+ 1 , wmi_label );
121222 if (!g ) {
122223 return -1 ;
123224 }
@@ -175,6 +276,10 @@ int we_wmi_tcp_update(struct flb_we *ctx)
175276 return -1 ;
176277 }
177278
279+ /* Collect the new state-based metrics first. This does not require WMI coinitialization. */
280+ we_tcp_get_state_metrics (ctx , ipv4_label );
281+ we_tcp_get_state_metrics (ctx , ipv6_label );
282+
178283 if (FAILED (we_wmi_coinitialize (ctx ))) {
179284 return -1 ;
180285 }
0 commit comments