Browse code

ratelimit: added helper functions for statistics on network load

Daniel-Constantin Mierla authored on 06/12/2016 09:35:45
Showing 3 changed files
... ...
@@ -42,6 +42,7 @@
42 42
 #include "../../data_lump_rpl.h"
43 43
 #include "../../counters.h"
44 44
 #include "../../rpc_lookup.h"
45
+#include "rl_statistics.h"
45 46
 
46 47
 
47 48
 MODULE_VERSION
... ...
@@ -324,7 +325,6 @@ static int get_cpuload(double * load)
324 325
 	static int first_time = 1;
325 326
 	FILE * f = fopen("/proc/stat", "r");
326 327
 	double vload;
327
-	int ncpu;
328 328
 	static int errormsg = 0;
329 329
 
330 330
 	if (! f) {
331 331
new file mode 100644
... ...
@@ -0,0 +1,496 @@
1
+/*
2
+ * Copyright (C) 2006 Voice Sistem SRL
3
+ *
4
+ * This file is part of Kamailio, a free SIP server.
5
+ *
6
+ * Kamailio is free software; you can redistribute it and/or modify
7
+ * it under the terms of the GNU General Public License as published by
8
+ * the Free Software Foundation; either version 2 of the License, or
9
+ * (at your option) any later version.
10
+ *
11
+ * Kamailio is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
+ * GNU General Public License for more details.
15
+ *
16
+ * You should have received a copy of the GNU General Public License
17
+ * along with this program; if not, write to the Free Software
18
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19
+ *
20
+ *
21
+ */
22
+
23
+/*!
24
+ * \file
25
+ * \brief Statistics support
26
+ * \author bogdan, andrei
27
+ * \author Jeffrey Magder - SOMA Networks
28
+ */
29
+
30
+
31
+#include <string.h>
32
+#include <stdio.h>
33
+#include <stdlib.h>
34
+
35
+#include "../../ut.h"
36
+#include "../../dprint.h"
37
+#include "../../socket_info.h"
38
+#include "rl_statistics.h"
39
+
40
+#ifdef STATISTICS
41
+
42
+
43
+/*! \brief
44
+ * Returns the statistic associated with 'numerical_code' and 'out_codes'.
45
+ * Specifically:
46
+ *
47
+ *  - if out_codes is nonzero, then the stat_var for the number of messages
48
+ *    _sent out_ with the 'numerical_code' will be returned if it exists.
49
+ *  - otherwise, the stat_var for the number of messages _received_ with the
50
+ *    'numerical_code' will be returned, if the stat exists.
51
+ */
52
+stat_var *get_stat_var_from_num_code(unsigned int numerical_code, int out_codes)
53
+{
54
+	static char msg_code[INT2STR_MAX_LEN+4];
55
+	str stat_name;
56
+
57
+	stat_name.s = int2bstr( (unsigned long)numerical_code, msg_code,
58
+		&stat_name.len);
59
+	stat_name.s[stat_name.len++] = '_';
60
+
61
+	if (out_codes) {
62
+		stat_name.s[stat_name.len++] = 'o';
63
+		stat_name.s[stat_name.len++] = 'u';
64
+		stat_name.s[stat_name.len++] = 't';
65
+	} else {
66
+		stat_name.s[stat_name.len++] = 'i';
67
+		stat_name.s[stat_name.len++] = 'n';
68
+	}
69
+
70
+	return get_stat(&stat_name);
71
+}
72
+
73
+
74
+#endif /*STATISTICS*/
75
+
76
+#define MAX_PROC_BUFFER 256
77
+
78
+/*!
79
+ * This function will retrieve a list of all ip addresses and ports that Kamailio
80
+ * is listening on, with respect to the transport protocol specified with
81
+ * 'protocol'.
82
+ *
83
+ * The first parameter, ipList, is a pointer to a pointer. It will be assigned a
84
+ * new block of memory holding the IP Addresses and ports being listened to with
85
+ * respect to 'protocol'.  The array maps a 2D array into a 1 dimensional space,
86
+ * and is layed out as follows:
87
+ *
88
+ * The first NUM_IP_OCTETS indices will be the IP address, and the next index
89
+ * the port.  So if NUM_IP_OCTETS is equal to 4 and there are two IP addresses
90
+ * found, then:
91
+ *
92
+ *  - ipList[0] will be the first octet of the first ip address
93
+ *  - ipList[3] will be the last octet of the first ip address.
94
+ *  - iplist[4] will be the port of the first ip address
95
+ *  -
96
+ *  - iplist[5] will be the first octet of the first ip address,
97
+ *  - and so on.
98
+ *
99
+ * The function will return the number of sockets which were found.  This can be
100
+ * used to index into ipList.
101
+ *
102
+ * \note This function assigns a block of memory equal to:
103
+ *
104
+ *            returnedValue * (NUM_IP_OCTETS + 1) * sizeof(int);
105
+ *
106
+ *       Therefore it is CRUCIAL that you free ipList when you are done with its
107
+ *       contents, to avoid a nasty memory leak.
108
+ */
109
+int get_socket_list_from_proto(int **ipList, int protocol) {
110
+	return get_socket_list_from_proto_and_family(ipList, protocol, AF_INET);
111
+}
112
+
113
+
114
+/*!
115
+ * This function will retrieve a list of all ip addresses and ports that Kamailio
116
+ * is listening on, with respect to the transport protocol specified with
117
+ * 'protocol'. This function supports both IPv4 and IPv6
118
+ *
119
+ * The first parameter, ipList, is a pointer to a pointer. It will be assigned a
120
+ * new block of memory holding the IP Addresses and ports being listened to with
121
+ * respect to 'protocol'.  The array maps a 2D array into a 1 dimensional space,
122
+ * and is layed out as follows:
123
+ *
124
+ * The first NUM_IP_OCTETS indices will be the IP address, and the next index
125
+ * the port.  So if NUM_IP_OCTETS is equal to 4 and there are two IP addresses
126
+ * found, then:
127
+ *
128
+ *  - ipList[0] will be the first octet of the first ip address
129
+ *  - ipList[3] will be the last octet of the first ip address.
130
+ *  - iplist[4] will be the port of the first ip address
131
+ *  -
132
+ *  - iplist[5] will be the first octet of the first ip address,
133
+ *  - and so on.
134
+ */
135
+int get_socket_list_from_proto_and_family(int **ipList, int protocol, int family) {
136
+
137
+	struct socket_info  *si;
138
+	struct socket_info** list;
139
+
140
+	int num_ip_octets   = family == AF_INET ? NUM_IP_OCTETS : NUM_IPV6_OCTETS;
141
+	int numberOfSockets = 0;
142
+	int currentRow      = 0;
143
+
144
+	/* I hate to use #ifdefs, but this is necessary because of the way
145
+	 * get_sock_info_list() is defined.  */
146
+#ifndef USE_TCP
147
+	if (protocol == PROTO_TCP)
148
+	{
149
+		return 0;
150
+	}
151
+#endif
152
+
153
+#ifndef USE_TLS
154
+	if (protocol == PROTO_TLS)
155
+	{
156
+		return 0;
157
+	}
158
+#endif
159
+#ifndef USE_SCTP
160
+	if (protocol == PROTO_SCTP)
161
+	{
162
+		return 0;
163
+	}
164
+#endif
165
+	/* We have no "interfaces" for websockets */
166
+	if (protocol == PROTO_WS || protocol == PROTO_WSS)
167
+		return 0;
168
+
169
+	/* Retrieve the list of sockets with respect to the given protocol. */
170
+	list=get_sock_info_list(protocol);
171
+
172
+	/* Find out how many sockets are in the list.  We need to know this so
173
+	 * we can malloc an array to assign to ipList. */
174
+	for(si=list?*list:0; si; si=si->next){
175
+		if (si->address.af == family) {
176
+			numberOfSockets++;
177
+		}
178
+	}
179
+
180
+	/* There are no open sockets with respect to the given protocol. */
181
+	if (numberOfSockets == 0)
182
+	{
183
+		return 0;
184
+	}
185
+
186
+	*ipList = pkg_malloc(numberOfSockets * (num_ip_octets + 1) * sizeof(int));
187
+
188
+	/* We couldn't allocate memory for the IP List.  So all we can do is
189
+	 * fail. */
190
+	if (*ipList == NULL) {
191
+		LM_ERR("no more pkg memory");
192
+		return 0;
193
+	}
194
+
195
+
196
+	/* We need to search the list again.  So find the front of the list. */
197
+	list=get_sock_info_list(protocol);
198
+
199
+	/* Extract out the IP Addresses and ports.  */
200
+	for(si=list?*list:0; si; si=si->next){
201
+		int i;
202
+
203
+		/* We currently only support IPV4. */
204
+		if (si->address.af != family) {
205
+			continue;
206
+		}
207
+
208
+		for (i = 0; i < num_ip_octets; i++) {
209
+			(*ipList)[currentRow*(num_ip_octets + 1) + i ] =
210
+				si->address.u.addr[i];
211
+		}
212
+		(*ipList)[currentRow*(num_ip_octets + 1) + i] =
213
+			si->port_no;
214
+
215
+		currentRow++;
216
+	}
217
+
218
+	return numberOfSockets;
219
+}
220
+
221
+/*!
222
+ * Takes a 'line' (from the proc file system), parses out the ipAddress,
223
+ * address, and stores the number of bytes waiting in 'rx_queue'
224
+ *
225
+ * Returns 1 on success, and 0 on a failed parse.
226
+ *
227
+ * Note: The format of ipAddress is as defined in the comments of
228
+ * get_socket_list_from_proto() in this file.
229
+ *
230
+ */
231
+static int parse_proc_net_line(char *line, int *ipAddress, int *rx_queue)
232
+{
233
+	int i;
234
+
235
+	int ipOctetExtractionMask = 0xFF;
236
+
237
+	char *currColonLocation;
238
+	char *nextNonNumericalChar;
239
+	char *currentLocationInLine = line;
240
+
241
+	int parsedInteger[4];
242
+
243
+	/* Example line from /proc/net/tcp or /proc/net/udp:
244
+	 *
245
+	 *	sl  local_address rem_address   st tx_queue rx_queue
246
+	 *	21: 5A0A0B0A:CAC7 1C016E0A:0016 01 00000000:00000000
247
+	 *
248
+	 * Algorithm:
249
+	 *
250
+	 * 	1) Find the location of the first  ':'
251
+	 * 	2) Parse out the IP Address into an integer
252
+	 * 	3) Find the location of the second ':'
253
+	 * 	4) Parse out the port number.
254
+	 * 	5) Find the location of the fourth ':'
255
+	 * 	6) Parse out the rx_queue.
256
+	 */
257
+
258
+	for (i = 0; i < 4; i++) {
259
+
260
+		currColonLocation = strchr(currentLocationInLine, ':');
261
+
262
+		/* We didn't find all the needed ':', so fail. */
263
+		if (currColonLocation == NULL) {
264
+			return 0;
265
+		}
266
+
267
+		/* Parse out the integer, keeping the location of the next
268
+		 * non-numerical character.  */
269
+		parsedInteger[i] =
270
+			(int) strtol(++currColonLocation, &nextNonNumericalChar,
271
+					16);
272
+
273
+		/* strtol()'s specifications specify that the second parameter
274
+		 * is set to the first parameter when a number couldn't be
275
+		 * parsed out.  This means the parse was unsuccesful.  */
276
+		if (nextNonNumericalChar == currColonLocation) {
277
+			return 0;
278
+		}
279
+
280
+		/* Reset the currentLocationInLine to the last non-numerical
281
+		 * character, so that next iteration of this loop, we can find
282
+		 * the next colon location. */
283
+		currentLocationInLine = nextNonNumericalChar;
284
+
285
+	}
286
+
287
+	/* Extract out the segments of the IP Address.  They are stored in
288
+	 * reverse network byte order. */
289
+	for (i = 0; i < NUM_IP_OCTETS; i++) {
290
+
291
+		ipAddress[i] =
292
+			parsedInteger[0] & (ipOctetExtractionMask << i*8);
293
+
294
+		ipAddress[i] >>= i*8;
295
+
296
+	}
297
+
298
+	ipAddress[NUM_IP_OCTETS] = parsedInteger[1];
299
+
300
+	*rx_queue = parsedInteger[3];
301
+
302
+	return 1;
303
+}
304
+
305
+
306
+/*!
307
+ * Returns 1 if ipOne was found in ipArray, and 0 otherwise.
308
+ *
309
+ * The format of ipOne and ipArray are described in the comments of
310
+ * get_socket_list_from_proto() in this file.
311
+ *
312
+ * */
313
+static int match_ip_and_port(int *ipOne, int *ipArray, int sizeOf_ipArray)
314
+{
315
+	int curIPAddrIdx;
316
+	int curOctetIdx;
317
+	int ipArrayIndex;
318
+
319
+	/* Loop over every IP Address */
320
+	for (curIPAddrIdx = 0; curIPAddrIdx < sizeOf_ipArray; curIPAddrIdx++) {
321
+
322
+		/* Check for octets that don't match.  If one is found, skip the
323
+		 * rest.  */
324
+		for (curOctetIdx = 0; curOctetIdx < NUM_IP_OCTETS + 1; curOctetIdx++) {
325
+
326
+			/* We've encoded a 2D array as a 1D array.  So find out
327
+			 * our position in the 1D array. */
328
+			ipArrayIndex =
329
+				curIPAddrIdx * (NUM_IP_OCTETS + 1) + curOctetIdx;
330
+
331
+			if (ipOne[curOctetIdx] != ipArray[ipArrayIndex]) {
332
+				break;
333
+			}
334
+		}
335
+
336
+		/* If the index from the inner loop is equal to NUM_IP_OCTETS
337
+		 * + 1, then that means that every octet (and the port with the
338
+		 * + 1) matched. */
339
+		if (curOctetIdx == NUM_IP_OCTETS + 1) {
340
+			return 1;
341
+		}
342
+
343
+	}
344
+
345
+	return 0;
346
+}
347
+
348
+
349
+/*!
350
+ * Returns the number of bytes waiting to be consumed on the network interfaces
351
+ * assigned the IP Addresses specified in interfaceList.  The check will be
352
+ * limited to the TCP or UDP transport exclusively.  Specifically:
353
+ *
354
+ * - If forTCP is non-zero, the check involves only the TCP transport.
355
+ * - if forTCP is zero, the check involves only the UDP transport.
356
+ *
357
+ * Note: This only works on linux systems supporting the /proc/net/[tcp|udp]
358
+ *       interface.  On other systems, zero will always be returned.
359
+ */
360
+static int get_used_waiting_queue(
361
+		int forTCP, int *interfaceList, int listSize)
362
+{
363
+	FILE *fp;
364
+	char *fileToOpen;
365
+
366
+	char lineBuffer[MAX_PROC_BUFFER];
367
+	int  ipAddress[NUM_IP_OCTETS+1];
368
+	int  rx_queue;
369
+
370
+	int  waitingQueueSize = 0;
371
+
372
+#ifndef __OS_linux
373
+	/* /proc/net/tcp and /proc/net/udp only exists on Linux systems, so don't bother with
374
+	   trying to open these files */
375
+	return 0;
376
+#endif
377
+
378
+	/* Set up the file we want to open. */
379
+	if (forTCP) {
380
+		fileToOpen = "/proc/net/tcp";
381
+	} else {
382
+		fileToOpen = "/proc/net/udp";
383
+	}
384
+
385
+	fp = fopen(fileToOpen, "r");
386
+
387
+	if (fp == NULL) {
388
+		LM_ERR("Could not open %s. kamailioMsgQueueDepth and its related"
389
+				" alarms will not be available.\n", fileToOpen);
390
+		return 0;
391
+	}
392
+
393
+	/* Read in every line of the file, parse out the ip address, port, and
394
+	 * rx_queue, and compare to our list of interfaces we are listening on.
395
+	 * Add up rx_queue for those lines which match our known interfaces. */
396
+	while (fgets(lineBuffer, MAX_PROC_BUFFER, fp)!=NULL) {
397
+
398
+		/* Parse out the ip address, port, and rx_queue. */
399
+		if(parse_proc_net_line(lineBuffer, ipAddress, &rx_queue)) {
400
+
401
+			/* Only add rx_queue if the line just parsed corresponds
402
+			 * to an interface we are listening on.  We do this
403
+			 * check because it is possible that this system has
404
+			 * other network interfaces that Kamailio has been told
405
+			 * to ignore. */
406
+			if (match_ip_and_port(ipAddress, interfaceList, listSize)) {
407
+				waitingQueueSize += rx_queue;
408
+			}
409
+		}
410
+	}
411
+
412
+	fclose(fp);
413
+
414
+	return waitingQueueSize;
415
+}
416
+
417
+/*!
418
+ * Returns the sum of the number of bytes waiting to be consumed on all network
419
+ * interfaces and transports that Kamailio is listening on.
420
+ *
421
+ * Note: This currently only works on systems supporting the /proc/net/[tcp|udp]
422
+ *       interface.  On other systems, zero will always be returned.  To change
423
+ *       this in the future, add an equivalent for get_used_waiting_queue().
424
+ */
425
+int get_total_bytes_waiting(void)
426
+{
427
+	int bytesWaiting = 0;
428
+
429
+	int *UDPList  = NULL;
430
+	int *TCPList  = NULL;
431
+	int *TLSList  = NULL;
432
+	int *UDP6List  = NULL;
433
+	int *TCP6List  = NULL;
434
+	int *TLS6List  = NULL;
435
+
436
+	int numUDPSockets  = 0;
437
+	int numTCPSockets  = 0;
438
+	int numTLSSockets  = 0;
439
+	int numUDP6Sockets  = 0;
440
+	int numTCP6Sockets  = 0;
441
+	int numTLS6Sockets  = 0;
442
+
443
+	/* Extract out the IP address address for UDP, TCP, and TLS, keeping
444
+	 * track of the number of IP addresses from each transport  */
445
+	numUDPSockets  = get_socket_list_from_proto(&UDPList,  PROTO_UDP);
446
+	numTCPSockets  = get_socket_list_from_proto(&TCPList,  PROTO_TCP);
447
+	numTLSSockets  = get_socket_list_from_proto(&TLSList,  PROTO_TLS);
448
+
449
+	numUDP6Sockets  = get_socket_list_from_proto_and_family(&UDP6List,  PROTO_UDP, AF_INET6);
450
+	numTCP6Sockets  = get_socket_list_from_proto_and_family(&TCP6List,  PROTO_TCP, AF_INET6);
451
+	numTLS6Sockets  = get_socket_list_from_proto_and_family(&TLS6List,  PROTO_TLS, AF_INET6);
452
+
453
+	/* Deliberately not looking at PROTO_WS or PROTO_WSS here as they are
454
+	   just upgraded TCP/TLS connections */
455
+
456
+	/* Find out the number of bytes waiting on our interface list over all
457
+	 * UDP and TCP transports. */
458
+	bytesWaiting  += get_used_waiting_queue(0, UDPList,  numUDPSockets);
459
+	bytesWaiting  += get_used_waiting_queue(1, TCPList,  numTCPSockets);
460
+	bytesWaiting  += get_used_waiting_queue(1, TLSList,  numTLSSockets);
461
+
462
+	bytesWaiting  += get_used_waiting_queue(0, UDP6List,  numUDP6Sockets);
463
+	bytesWaiting  += get_used_waiting_queue(1, TCP6List,  numTCP6Sockets);
464
+	bytesWaiting  += get_used_waiting_queue(1, TLS6List,  numTLS6Sockets);
465
+
466
+	/* get_socket_list_from_proto() allocated a chunk of memory, so we need
467
+	 * to free it. */
468
+	if (numUDPSockets > 0)
469
+	{
470
+		pkg_free(UDPList);
471
+	}
472
+	if (numUDP6Sockets > 0)
473
+	{
474
+		pkg_free(UDP6List);
475
+	}
476
+
477
+	if (numTCPSockets > 0)
478
+	{
479
+		pkg_free(TCPList);
480
+	}
481
+	if (numTCP6Sockets > 0)
482
+	{
483
+		pkg_free(TCP6List);
484
+	}
485
+
486
+	if (numTLSSockets > 0)
487
+	{
488
+		pkg_free(TLSList);
489
+	}
490
+	if (numTLS6Sockets > 0)
491
+	{
492
+		pkg_free(TLS6List);
493
+	}
494
+
495
+	return bytesWaiting;
496
+}
0 497
new file mode 100644
... ...
@@ -0,0 +1,109 @@
1
+/*
2
+ * Copyright (C) 2006 Voice Sistem SRL
3
+ *
4
+ * This file is part of Kamailio, a free SIP server.
5
+ *
6
+ * Kamailio is free software; you can redistribute it and/or modify
7
+ * it under the terms of the GNU General Public License as published by
8
+ * the Free Software Foundation; either version 2 of the License, or
9
+ * (at your option) any later version.
10
+ *
11
+ * Kamailio is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
+ * GNU General Public License for more details.
15
+ *
16
+ * You should have received a copy of the GNU General Public License
17
+ * along with this program; if not, write to the Free Software
18
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19
+ *
20
+ */
21
+
22
+/*!
23
+ * \file
24
+ * \brief Kamailio statistics handling
25
+ * \author bogdan
26
+ * \author Jeffrey Magder - SOMA Networks
27
+ */
28
+
29
+
30
+#ifndef _KSTATISTICS_H_
31
+#define _KSTATISTICS_H_
32
+
33
+#include "../../counters.h"
34
+
35
+
36
+#define NUM_IP_OCTETS 4
37
+#define NUM_IPV6_OCTETS 16
38
+
39
+
40
+#ifdef STATISTICS
41
+/*! \brief
42
+ * Returns the statistic associated with 'numerical_code' and 'is_a_reply'.
43
+ * Specifically:
44
+ *
45
+ *  - if in_codes is nonzero, then the stat_var for the number of messages
46
+ *    _received_ with the 'numerical_code' will be returned if it exists.
47
+ *  - otherwise, the stat_var for the number of messages _sent_ with the
48
+ *    'numerical_code' will be returned, if the stat exists.
49
+ */
50
+stat_var *get_stat_var_from_num_code(unsigned int numerical_code, int in_codes);
51
+
52
+#else
53
+	#define get_stat_var_from_num_code( _n_code, _in_code) NULL
54
+#endif
55
+
56
+
57
+
58
+/*!
59
+ * This function will retrieve a list of all ip addresses and ports that Kamailio
60
+ * is listening on, with respect to the transport protocol specified with
61
+ * 'protocol'. This function only returns IPv4 addresses.
62
+ *
63
+ * The first parameter, ipList, is a pointer to a pointer. It will be assigned a
64
+ * new block of memory holding the IP Addresses and ports being listened to with
65
+ * respect to 'protocol'.  The array maps a 2D array into a 1 dimensional space,
66
+ * and is layed out as follows:
67
+ *
68
+ * The first NUM_IP_OCTETS indices will be the IP address, and the next index
69
+ * the port.  So if NUM_IP_OCTETS is equal to 4 and there are two IP addresses
70
+ * found, then:
71
+ *
72
+ *  - ipList[0] will be the first octet of the first ip address
73
+ *  - ipList[3] will be the last octet of the first ip address.
74
+ *  - iplist[4] will be the port of the first ip address
75
+ *  -
76
+ *  - iplist[5] will be the first octet of the first ip address,
77
+ *  - and so on.
78
+ *
79
+ * The function will return the number of sockets which were found.  This can be
80
+ * used to index into ipList.
81
+ *
82
+ * \note This function assigns a block of memory equal to:
83
+ *
84
+ *            returnedValue * (NUM_IP_OCTETS + 1) * sizeof(int);
85
+ *
86
+ *       Therefore it is CRUCIAL that you free ipList when you are done with its
87
+ *       contents, to avoid a nasty memory leak.
88
+ */
89
+int get_socket_list_from_proto(int **ipList, int protocol);
90
+
91
+/*! \brief Function to get a list of all IP addresses and ports in a specific
92
+ * family, like AF_INET or AF_INET6
93
+ *
94
+ * For documentation see \ref get_socket_list_from_proto()
95
+ */
96
+int get_socket_list_from_proto_and_family(int **ipList, int protocol, int family);
97
+
98
+
99
+/*!
100
+ * Returns the sum of the number of bytes waiting to be consumed on all network
101
+ * interfaces and transports that Kamailio is listening on.
102
+ *
103
+ * Note: This currently only works on systems supporting the /proc/net/[tcp|udp]
104
+ *       interface.  On other systems, zero will always be returned.  Details of
105
+ *       why this is so can be found in network_stats.c
106
+ */
107
+int get_total_bytes_waiting(void);
108
+
109
+#endif