Browse Source

- fixed some tcp connections accounting bugs
- tcp info available via fifo/rpc

Andrei Pelinescu-Onciul 19 years ago
parent
commit
d95154053d
3 changed files with 138 additions and 11 deletions
  1. 31 0
      core_cmd.c
  2. 48 0
      tcp_info.h
  3. 59 11
      tcp_main.c

+ 31 - 0
core_cmd.c

@@ -36,6 +36,7 @@
 #include "globals.h"
 #include "pt.h"
 #include "ut.h"
+#include "tcp_info.h"
 #include "core_cmd.h"
 
 
@@ -252,6 +253,35 @@ static const char* core_shmmem_doc[] = {
 };
 
 
+static const char* core_tcpinfo_doc[] = {
+	"Returns tcp related info.",    /* Documentation string */
+	0                               /* Method signature(s) */
+};
+
+static void core_tcpinfo(rpc_t* rpc, void* c)
+{
+	void *handle;
+#ifdef USE_TCP
+	struct tcp_gen_info ti;
+	
+	if (!tcp_disable){
+		tcp_get_info(&ti);
+		rpc->add(c, "{", &handle);
+		rpc->struct_add(handle, "ddddd",
+			"readers", ti.tcp_readers,
+			"max_connections", ti.tcp_max_connections,
+			"opened_connections", ti.tcp_connections_no,
+			"inactive_connections", ti.tcp_inactive_connections,
+			"total_requests", ti.tcp_total_requests
+		);
+	}else{
+		rpc->fault(c, 500, "tcp support disabled");
+	}
+#else
+	rpc->fault(c, 500, "tcp support not compiled");
+#endif
+}
+
 /*
  * RPC Methods exported by this module
  */
@@ -267,6 +297,7 @@ rpc_export_t core_rpc_methods[] = {
 	{"core.arg",               core_arg,               core_arg_doc,               RET_ARRAY},
 	{"core.kill",              core_kill,              core_kill_doc,              0        },
 	{"core.shmmem",            core_shmmem,            core_shmmem_doc,            0	},
+	{"core.tcp_info",          core_tcpinfo,           core_tcpinfo_doc,          0	},
 	{0, 0, 0, 0}
 };
 

+ 48 - 0
tcp_info.h

@@ -0,0 +1,48 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2006 iptelorg GmbH
+ *
+ * This file is part of ser, a free SIP server.
+ *
+ * ser is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * For a license to use the ser software under conditions
+ * other than those described here, or to purchase support for this
+ * software, please contact iptel.org by e-mail at the following addresses:
+ *    [email protected]
+ *
+ * ser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+/*
+ * tcp various information
+ */
+
+#ifndef _tcp_info_h
+#define _tcp_info_h
+
+struct tcp_gen_info{
+	int tcp_readers;
+	int tcp_max_connections;
+	int tcp_connections_no; /* crt. number */
+	int tcp_inactive_connections;
+	unsigned int tcp_total_requests;
+};
+
+
+
+
+void tcp_get_info(struct tcp_gen_info* ti);
+
+
+#endif

+ 59 - 11
tcp_main.c

@@ -66,6 +66,8 @@
  *  2006-02-03  timers are run only once per s (andrei)
  *              tcp children fds can be non-blocking; send fds are queued on
  *              EAGAIN; lots of bug fixes (andrei)
+ *  2006-02-06  better tcp_max_connections checks, tcp_connections_no moved to
+ *              shm (andrei)
  */
 
 
@@ -116,6 +118,7 @@
 #ifdef USE_TLS
 #include "tls/tls_server.h"
 #endif 
+#include "tcp_info.h"
 
 #define local_malloc pkg_malloc
 #define local_free   pkg_free
@@ -163,7 +166,7 @@ enum poll_types tcp_poll_method=0; /* by default choose the best method */
 int tcp_max_connections=DEFAULT_TCP_MAX_CONNECTIONS;
 int tcp_max_fd_no=0;
 
-static int tcp_connections_no=0; /* current open connections */
+static int* tcp_connections_no=0; /* current open connections */
 
 /* connection hash table (after ip&port) , includes also aliases */
 struct tcp_conn_alias** tcpconn_aliases_hash=0;
@@ -447,7 +450,6 @@ struct tcp_connection* tcpconn_new(int sock, union sockaddr_union* su,
 	}
 	c->flags|=F_CONN_REMOVED;
 	
-	tcp_connections_no++;
 	return c;
 	
 error:
@@ -466,6 +468,14 @@ struct tcp_connection* tcpconn_connect(union sockaddr_union* server, int type)
 	struct tcp_connection* con;
 	struct ip_addr ip;
 
+	s=-1;
+	
+	if (*tcp_connections_no >= tcp_max_connections){
+		LOG(L_ERR, "ERROR: tcpconn_connect: maximum number of connections"
+					" exceeded (%d/%d)\n",
+					*tcp_connections_no, tcp_max_connections);
+		goto error;
+	}
 	s=socket(AF2PF(server->s.sa_family), SOCK_STREAM, 0);
 	if (s==-1){
 		LOG(L_ERR, "ERROR: tcpconn_connect: socket: (%d) %s\n",
@@ -970,7 +980,7 @@ static void tcpconn_destroy(struct tcp_connection* tcpconn)
 #endif
 		_tcpconn_rm(tcpconn);
 		close(fd);
-		tcp_connections_no--;
+		(*tcp_connections_no)--;
 	}else{
 		/* force timeout */
 		tcpconn->timeout=0;
@@ -1060,11 +1070,11 @@ inline static int send_fd_queue_add(	struct tcp_send_fd_q* q,
 		}else new_size=MAX_SEND_FD_QUEUE_SIZE;
 		if (q->crt>=&q->data[new_size]){
 			LOG(L_ERR, "ERROR: send_fd_queue_add: queue full: %ld/%ld\n",
-					q->crt-&q->data[0]-1, new_size);
+					(long)(q->crt-&q->data[0]-1), new_size);
 			goto error;
 		}
 		LOG(L_CRIT, "INFO: send_fd_queue: queue full: %ld, extending to %ld\n",
-				q->end-&q->data[0], new_size);
+				(long)(q->end-&q->data[0]), new_size);
 		tmp=pkg_realloc(q->data, new_size*sizeof(struct send_fd_info));
 		if (tmp==0){
 			LOG(L_ERR, "ERROR: send_fd_queue_add: out of memory\n");
@@ -1104,7 +1114,7 @@ inline static void send_fd_queue_run(struct tcp_send_fd_q* q)
 				LOG(L_ERR, "ERROR: run_send_fd_queue: send_fd failed"
 						   " on socket %d , queue entry %ld, retries %d,"
 						   " connection %p, tcp socket %d, errno=%d (%s) \n",
-						   p->unix_sock, p-&q->data[0], p->retries,
+						   p->unix_sock, (long)(p-&q->data[0]), p->retries,
 						   p->tcp_conn, p->tcp_conn->s, errno,
 						   strerror(errno));
 				tcpconn_destroy(p->tcp_conn);
@@ -1333,6 +1343,7 @@ inline static int handle_ser_child(struct process_table* p, int fd_i)
 							" no fd received\n");
 				break;
 			}
+			(*tcp_connections_no)++;
 			tcpconn->s=fd;
 			/* add tcpconn to the list*/
 			tcpconn_add(tcpconn);
@@ -1453,12 +1464,13 @@ static inline int handle_new_connect(struct socket_info* si)
 				" connection(%d): %s\n", errno, strerror(errno));
 		return -1;
 	}
-	if (tcp_connections_no>=tcp_max_connections){
+	if (*tcp_connections_no>=tcp_max_connections){
 		LOG(L_ERR, "ERROR: maximum number of connections exceeded: %d/%d\n",
-					tcp_connections_no, tcp_max_connections);
+					*tcp_connections_no, tcp_max_connections);
 		close(new_sock);
 		return 1; /* success, because the accept was succesfull */
 	}
+	(*tcp_connections_no)++;
 	if (init_sock_opt(new_sock)<0){
 		LOG(L_ERR, "ERROR: handle_new_connect: init_sock_opt failed\n");
 		close(new_sock);
@@ -1633,7 +1645,7 @@ static inline void tcpconn_timeout(int force)
 					}
 					close(fd);
 				}
-				tcp_connections_no--;
+				(*tcp_connections_no)--;
 			}
 			c=next;
 		}
@@ -1803,6 +1815,10 @@ void destroy_tcp()
 			shm_free(tcpconn_id_hash);
 			tcpconn_id_hash=0;
 		}
+		if (tcp_connections_no){
+			shm_free(tcp_connections_no);
+			tcp_connections_no=0;
+		}
 		if (connection_id){
 			shm_free(connection_id);
 			connection_id=0;
@@ -1841,7 +1857,13 @@ int init_tcp()
 		goto error;
 	}
 	/* init globals */
-	connection_id=(int*)shm_malloc(sizeof(int));
+	tcp_connections_no=shm_malloc(sizeof(int));
+	if (tcp_connections_no==0){
+		LOG(L_CRIT, "ERROR: init_tcp: could not alloc globals\n");
+		goto error;
+	}
+	*tcp_connections_no=0;
+	connection_id=shm_malloc(sizeof(int));
 	if (connection_id==0){
 		LOG(L_CRIT, "ERROR: init_tcp: could not alloc globals\n");
 		goto error;
@@ -1938,7 +1960,10 @@ int tcp_init_children()
 #endif
 	
 	tcp_max_fd_no=process_count*2 +r-1 /* timer */ +3; /* stdin/out/err*/
-	tcp_max_fd_no+=tcp_max_connections;
+	/* max connections can be temporarily exceeded with process_count
+	 * - tcp_main (tcpconn_connect called simultaneously in all all the 
+	 *  processes) */
+	tcp_max_fd_no+=tcp_max_connections+process_count-1 /* tcp main */;
 	
 	/* alloc the children array */
 	tcp_children=pkg_malloc(sizeof(struct tcp_child)*tcp_children_no);
@@ -2012,4 +2037,27 @@ error:
 	return -1;
 }
 
+
+
+void tcp_get_info(struct tcp_gen_info *ti)
+{
+	int r;
+	int active_connections;
+	unsigned int total_reqs;
+	
+	
+	ti->tcp_readers=tcp_children_no;
+	ti->tcp_max_connections=tcp_max_connections;
+	ti->tcp_connections_no=*tcp_connections_no;
+	
+	active_connections=0;
+	total_reqs=0;
+	for (r=0; r<tcp_children_no; r++){
+		active_connections*=tcp_children[r].busy;
+		total_reqs+=tcp_children[r].n_reqs;
+	}
+	ti->tcp_inactive_connections=*tcp_connections_no-active_connections;
+	ti->tcp_total_requests=total_reqs;
+}
+
 #endif