Browse code

- preliminary tcp support (it doesn't work, it's just for debugging, as long as you compile w/o -DUSE_TCP you should be safe) Note: sip + tcp really sucks

Andrei Pelinescu-Onciul authored on 29/11/2002 21:12:24
Showing 9 changed files
... ...
@@ -131,6 +131,9 @@ YACC := $(shell echo "$${YACC}")
131 131
 #  		if enabled, allows forking of the snmp agent just before child
132 132
 #  		forking (done at the top of main_loop). Needed if you want
133 133
 #  		to use the snmp module.
134
+# -DUSE_TCP
135
+#		compiles in tcp support (highly experimental for now, it will probably
136
+#		not work, use it only if you really now what you are doing)
134 137
 DEFS+= -DNAME='"$(NAME)"' -DVERSION='"$(RELEASE)"' -DARCH='"$(ARCH)"' \
135 138
 	 -DOS='"$(OS)"' -DCOMPILER='"$(CC_VER)"' -D__CPU_$(ARCH)\
136 139
 	 -DCFG_DIR='"$(cfg-target)"'\
... ...
@@ -140,6 +143,7 @@ DEFS+= -DNAME='"$(NAME)"' -DVERSION='"$(RELEASE)"' -DARCH='"$(ARCH)"' \
140 140
 	 -DDNS_IP_HACK \
141 141
 	 -DUSE_IPV6 \
142 142
 	 -DDBG_QM_MALLOC \
143
+	# -DUSE_TCP \
143 144
 	 #-DF_MALLOC \
144 145
 	 #-DNO_DEBUG \
145 146
 	 #-DNO_LOG
... ...
@@ -293,7 +297,7 @@ ifeq	($(ARCH), i386)
293 293
 		# if gcc 
294 294
 ifeq		($(CC_NAME), gcc)
295 295
 				#common stuff
296
-				CFLAGS=-O9 -funroll-loops  -Wcast-align $(PROFILE) \
296
+				CFLAGS=-g -O9 -funroll-loops  -Wcast-align $(PROFILE) \
297 297
 					-Wall   \
298 298
 			#if gcc 3.0
299 299
 ifeq			($(CC_SHORTVER), 3.0)
... ...
@@ -46,6 +46,7 @@
46 46
 extern char * cfg_file;
47 47
 extern char *stat_file;
48 48
 extern struct socket_info sock_info[]; /* all addresses we listen/send from*/
49
+extern struct socket_info tcp_info[]; /* all tcp sockets we listen on*/
49 50
 extern int sock_no; /* number of addresses/open sockets*/
50 51
 extern unsigned short port_no;
51 52
 /*
... ...
@@ -67,6 +68,9 @@ extern struct socket_info* sendipv6; /* same as above for ipv6 */
67 67
 
68 68
 extern unsigned int maxbuffer;
69 69
 extern int children_no;
70
+#ifdef USE_TCP
71
+extern int tcp_children_no;
72
+#endif
70 73
 extern int dont_fork;
71 74
 extern int check_via;
72 75
 extern int received_dns;
... ...
@@ -40,7 +40,8 @@
40 40
 
41 41
 #include "dprint.h"
42 42
 
43
-
43
+#define SOCKET_TCP	1
44
+#define SOCKET_UDP	0
44 45
 
45 46
 struct ip_addr{
46 47
 	unsigned int af; /* address family: AF_INET6 or AF_INET */
... ...
@@ -80,6 +81,7 @@ struct socket_info{
80 80
 	int is_ip; /* 1 if name is an ip address, 0 if not  -- optimization*/
81 81
 	int is_lo; /* 1 if is a loopback, 0 if not */
82 82
 	union sockaddr_union su; 
83
+	int proto; /* tcp or udp*/
83 84
 };
84 85
 
85 86
 
... ...
@@ -136,7 +138,7 @@ void print_net(struct net* net);
136 136
 	[ diff. adress fams ]) */
137 137
 inline static int matchnet(struct ip_addr* ip, struct net* net)
138 138
 {
139
-	int r;
139
+	unsigned int r;
140 140
 	int ret;
141 141
 	
142 142
 	ret=-1;
... ...
@@ -94,6 +94,9 @@ static char flags[]=
94 94
 #ifdef USE_IPV6
95 95
 ", USE_IPV6"
96 96
 #endif
97
+#ifdef USE_TCP
98
+", USE_TCP"
99
+#endif
97 100
 #ifdef NO_DEBUG
98 101
 ", NO_DEBUG"
99 102
 #endif
... ...
@@ -225,6 +228,9 @@ unsigned int maxbuffer = MAX_RECV_BUFFER_SIZE; /* maximum buffer size we do
225 225
 												  auto-probing procedure; may 
226 226
 												  be re-configured */
227 227
 int children_no = 0;			/* number of children processing requests */
228
+#ifdef USE_TCP
229
+int tcp_children_no = 0;
230
+#endif
228 231
 struct process_table *pt=0;		/*array with childrens pids, 0= main proc,
229 232
 									alloc'ed in shared mem if possible*/
230 233
 int sig_flag = 0;              /* last signal received */
... ...
@@ -266,6 +272,9 @@ struct ip_addr addresses[MAX_LISTEN]; /* our ips */
266 266
 int addresses_no=0;                   /* number of names/ips */
267 267
 #endif
268 268
 struct socket_info sock_info[MAX_LISTEN];/*all addresses we listen/send from*/
269
+#ifdef USE_TCP
270
+struct socket_info tcp_info[MAX_LISTEN];/*all tcp addresses we listen on*/
271
+#endif
269 272
 int sock_no=0; /* number of addresses/open sockets*/
270 273
 struct socket_info* bind_address=0; /* pointer to the crt. proc.
271 274
 									 listening address*/
... ...
@@ -616,6 +625,21 @@ int main_loop()
616 616
 			/* all procs should have access to all the sockets (for sending)
617 617
 			 * so we open all first*/
618 618
 		}
619
+#ifdef USE_TCP
620
+			/* start tcp master proc */
621
+		process_no++;
622
+		if ((pid=fork())<0){
623
+			LOG(L_CRIT, "main_loop: cannot fork tcp main process\n");
624
+			goto error;
625
+		}else if (pid==0){
626
+			/* child */
627
+			/* is_main=0; */
628
+			tcp_main();
629
+		}else{
630
+			pt[process_no].pid=pid;
631
+			strncpy(pt[process_no].desc, "tcp main process", MAX_PT_DESC );
632
+		}
633
+#endif
619 634
 		for(r=0; r<sock_no;r++){
620 635
 			for(i=0;i<children_no;i++){
621 636
 				process_no++;
... ...
@@ -1165,6 +1189,9 @@ try_again:
1165 1165
 
1166 1166
 	
1167 1167
 	if (children_no<=0) children_no=CHILD_NO;
1168
+#ifdef USE_TCP
1169
+	tcp_children_no=children_no;
1170
+#endif
1168 1171
 #ifdef _OBSOLETED
1169 1172
 	else if (children_no >= MAX_PROCESSES ) {
1170 1173
 		fprintf(stderr, "ERROR: too many children processes configured;"
1171 1174
new file mode 100644
... ...
@@ -0,0 +1,124 @@
0
+/*
1
+ * $Id$
2
+ *
3
+ * Copyright (C) 2001-2003 Fhg Fokus
4
+ *
5
+ * This file is part of ser, a free SIP server.
6
+ *
7
+ * ser is free software; you can redistribute it and/or modify
8
+ * it under the terms of the GNU General Public License as published by
9
+ * the Free Software Foundation; either version 2 of the License, or
10
+ * (at your option) any later version
11
+ *
12
+ * For a license to use the ser software under conditions
13
+ * other than those described here, or to purchase support for this
14
+ * software, please contact iptel.org by e-mail at the following addresses:
15
+ *    info@iptel.org
16
+ *
17
+ * ser is distributed in the hope that it will be useful,
18
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
+ * GNU General Public License for more details.
21
+ *
22
+ * You should have received a copy of the GNU General Public License
23
+ * along with this program; if not, write to the Free Software
24
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25
+ */
26
+
27
+#ifdef USE_TCP
28
+
29
+#include <sys/types.h>
30
+#include <sys/socket.h>
31
+
32
+/* remove this after replacing fprintf*/
33
+#include <stdio.h>
34
+
35
+
36
+/* at least 1 byte must be sent! */
37
+int send_fd(int unix_socket, void* data, int data_len, int fd)
38
+{
39
+	struct msghdr msg;
40
+	struct iovec iov[1];
41
+	struct cmsghdr* cmsg;
42
+	int ret;
43
+	union {
44
+		struct cmsghdr cm;
45
+		char control[CMSG_SPACE(sizeof(fd))];
46
+	}control_un;
47
+	
48
+	msg.msg_control=control_un.control;
49
+	msg.msg_controllen=sizeof(control_un.control);
50
+	
51
+	msg.msg_name=0;
52
+	msg.msg_namelen=0;
53
+	
54
+	iov[0].iov_base=data;
55
+	iov[0].iov_len=data_len;
56
+	msg.msg_iov=iov;
57
+	msg.msg_iovlen=1;
58
+	
59
+	cmsg=CMSG_FIRSTHDR(&msg);
60
+	cmsg->cmsg_level = SOL_SOCKET;
61
+	cmsg->cmsg_type = SCM_RIGHTS;
62
+	cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
63
+	*(int*)CMSG_DATA(cmsg)=fd;
64
+	msg.msg_flags=0;
65
+	
66
+	ret=sendmsg(unix_socket, &msg, 0);
67
+	
68
+	return ret;
69
+}
70
+
71
+
72
+
73
+int receive_fd(int unix_socket, void* data, int data_len, int* fd)
74
+{
75
+	struct msghdr msg;
76
+	struct iovec iov[1];
77
+	struct cmsghdr* cmsg;
78
+	int new_fd;
79
+	int ret;
80
+	union{
81
+		struct cmsghdr cm;
82
+		char control[CMSG_SPACE(sizeof(new_fd))];
83
+	}control_un;
84
+	
85
+	msg.msg_control=control_un.control;
86
+	msg.msg_controllen=sizeof(control_un.control);
87
+	
88
+	msg.msg_name=0;
89
+	msg.msg_namelen=0;
90
+	
91
+	iov[0].iov_base=data;
92
+	iov[0].iov_len=data_len;
93
+	msg.msg_iov=iov;
94
+	msg.msg_iovlen=1;
95
+	
96
+	ret=recvmsg(unix_socket, &msg, 0);
97
+	if (ret<=0) goto error;
98
+	
99
+	cmsg=CMSG_FIRSTHDR(&msg);
100
+	if ((cmsg!=0) && (cmsg->cmsg_len==CMSG_LEN(sizeof(new_fd)))){
101
+		if (cmsg->cmsg_type!= SCM_RIGHTS){
102
+			fprintf(stderr, " msg control type != SCM_RIGHTS\n");
103
+			ret=-1;
104
+			goto error;
105
+		}
106
+		if (cmsg->cmsg_level!= SOL_SOCKET){
107
+			fprintf(stderr, " msg level != SOL_SOCKET\n");
108
+			ret=-1;
109
+			goto error;
110
+		}
111
+		*fd=*((int*) CMSG_DATA(cmsg));
112
+	}else{
113
+		fprintf(stderr, " no descriptor passed, cmsg=%p, len=%d\n",
114
+				cmsg, cmsg->cmsg_len);
115
+		*fd=-1;
116
+		/* it's not really an error */
117
+	}
118
+	
119
+error:
120
+	return ret;
121
+}
122
+
123
+#endif
0 124
new file mode 100644
... ...
@@ -0,0 +1,37 @@
0
+/*
1
+ * $Id$
2
+ *
3
+ * Copyright (C) 2001-2003 Fhg Fokus
4
+ *
5
+ * This file is part of ser, a free SIP server.
6
+ *
7
+ * ser is free software; you can redistribute it and/or modify
8
+ * it under the terms of the GNU General Public License as published by
9
+ * the Free Software Foundation; either version 2 of the License, or
10
+ * (at your option) any later version
11
+ *
12
+ * For a license to use the ser software under conditions
13
+ * other than those described here, or to purchase support for this
14
+ * software, please contact iptel.org by e-mail at the following addresses:
15
+ *    info@iptel.org
16
+ *
17
+ * ser is distributed in the hope that it will be useful,
18
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
+ * GNU General Public License for more details.
21
+ *
22
+ * You should have received a copy of the GNU General Public License
23
+ * along with this program; if not, write to the Free Software
24
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25
+ */
26
+
27
+#ifndef _pass_fd_h
28
+#define _pass_fd_h
29
+
30
+
31
+int send_fd(int unix_socket, void* data, int data_len, int fd);
32
+int receive_fd(int unix_socket, void* data, int data_len, int* fd);
33
+
34
+
35
+
36
+#endif
0 37
new file mode 100644
... ...
@@ -0,0 +1,71 @@
0
+/*
1
+ * $Id$
2
+ *
3
+ * Copyright (C) 2001-2003 Fhg Fokus
4
+ *
5
+ * This file is part of ser, a free SIP server.
6
+ *
7
+ * ser is free software; you can redistribute it and/or modify
8
+ * it under the terms of the GNU General Public License as published by
9
+ * the Free Software Foundation; either version 2 of the License, or
10
+ * (at your option) any later version
11
+ *
12
+ * For a license to use the ser software under conditions
13
+ * other than those described here, or to purchase support for this
14
+ * software, please contact iptel.org by e-mail at the following addresses:
15
+ *    info@iptel.org
16
+ *
17
+ * ser is distributed in the hope that it will be useful,
18
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
+ * GNU General Public License for more details.
21
+ *
22
+ * You should have received a copy of the GNU General Public License
23
+ * along with this program; if not, write to the Free Software
24
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25
+ */
26
+
27
+
28
+
29
+#ifndef _tcp_conn_h
30
+#define _tcp_conn_h
31
+
32
+
33
+
34
+#define TCP_BUF_SIZE 65535
35
+enum {TCP_REQ_INIT, TCP_REQ_OK, TCP_READ_ERROR, TCP_REQ_OVERRUN };
36
+enum {H_PARSING, H_LF, H_LFCR,  H_BODY };
37
+
38
+struct tcp_req{
39
+	struct tcp_req* next;
40
+	int fd;
41
+	/* sockaddr ? */
42
+	char buf[TCP_BUF_SIZE]; /* bytes read so far*/
43
+	char* pos; /* current position in buf */
44
+	char* parsed; /* last parsed position */
45
+	char* body; /* body position */
46
+	int error;
47
+	int state;
48
+};
49
+
50
+
51
+#define init_tcp_req( r, f) \
52
+	do{ \
53
+		memset( (r), 0, sizeof(struct tcp_req)); \
54
+		(r)->fd=(f); \
55
+		(r)->parsed=(r)->pos=(r)->buf; \
56
+		(r)->error=TCP_REQ_OK;\
57
+		(r)->state=H_PARSING; \
58
+	}while(0)
59
+
60
+
61
+
62
+
63
+
64
+
65
+
66
+
67
+
68
+#endif
69
+
70
+
0 71
new file mode 100644
... ...
@@ -0,0 +1,357 @@
0
+/*
1
+ * $Id$
2
+ *
3
+ * Copyright (C) 2001-2003 Fhg Fokus
4
+ *
5
+ * This file is part of ser, a free SIP server.
6
+ *
7
+ * ser is free software; you can redistribute it and/or modify
8
+ * it under the terms of the GNU General Public License as published by
9
+ * the Free Software Foundation; either version 2 of the License, or
10
+ * (at your option) any later version
11
+ *
12
+ * For a license to use the ser software under conditions
13
+ * other than those described here, or to purchase support for this
14
+ * software, please contact iptel.org by e-mail at the following addresses:
15
+ *    info@iptel.org
16
+ *
17
+ * ser is distributed in the hope that it will be useful,
18
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
+ * GNU General Public License for more details.
21
+ *
22
+ * You should have received a copy of the GNU General Public License
23
+ * along with this program; if not, write to the Free Software
24
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25
+ */
26
+
27
+
28
+#ifdef USE_TCP
29
+
30
+#include <sys/select.h>
31
+
32
+#include <sys/time.h>
33
+#include <sys/types.h>
34
+#include <sys/socket.h>
35
+
36
+#include <unistd.h>
37
+
38
+#include <errno.h>
39
+#include <string.h>
40
+
41
+
42
+
43
+#include "ip_addr.h"
44
+#include "pass_fd.h"
45
+#include "globals.h"
46
+#include "mem/mem.h"
47
+
48
+
49
+#define local_malloc pkg_malloc
50
+#define local_free   pkg_free
51
+
52
+#define MAX_TCP_CHILDREN 100
53
+
54
+struct tcp_child{
55
+	pid_t pid;
56
+	int s; /* unix socket for comm*/
57
+	int busy;
58
+	int n_reqs; /* number of requests serviced so far */
59
+};
60
+
61
+
62
+enum { CONN_OK, CONN_ERROR };
63
+
64
+struct tcp_connection{
65
+	int s; /*socket */
66
+	struct ip_addr ip;
67
+	union sockaddr_union su;
68
+	int refcnt;
69
+	struct tcp_connection* next;
70
+	struct tcp_connection* prev;
71
+};
72
+
73
+
74
+
75
+struct tcp_connection* conn_list=0;
76
+struct tcp_child tcp_children[MAX_TCP_CHILDREN];
77
+
78
+
79
+
80
+struct tcp_connection*  tcpconn_add(int sock, union sockaddr_union* su)
81
+{
82
+	struct tcp_connection *c;
83
+	
84
+
85
+	c=(struct tcp_connection*)local_malloc(sizeof(struct tcp_connection));
86
+	if (c==0){
87
+		LOG(L_ERR, "ERROR: tcpconn_add: mem. allocation failure\n");
88
+		goto error;
89
+	}
90
+	c->s=sock;
91
+	c->su=*su;
92
+	c->refcnt=0;
93
+	su2ip_addr(&c->ip, su);
94
+
95
+	/* add it at the begining of the list*/
96
+	c->next=conn_list;
97
+	c->prev=0;
98
+	if (conn_list) conn_list->prev=c;
99
+	conn_list=c;
100
+	return c;
101
+	
102
+error:
103
+	return 0;
104
+}
105
+
106
+
107
+
108
+void tcpconn_rm(struct tcp_connection* c)
109
+{
110
+	
111
+	if (conn_list==c) conn_list=c->next;
112
+	if (c->next) c->next->prev=c->prev;
113
+	if (c->prev) c->prev->next=c->next;
114
+	local_free(c);
115
+}
116
+
117
+
118
+
119
+int tcp_init_sock(struct socket_info* sock_info)
120
+{
121
+	union sockaddr_union* addr;
122
+	
123
+	addr=&sock_info->su;
124
+	sock_info->proto=SOCKET_TCP;
125
+	if (init_su(addr, &sock_info->address, htons(sock_info->port_no))<0){
126
+		LOG(L_ERR, "ERROR: tcp_init: could no init sockaddr_union\n");
127
+		goto error;
128
+	}
129
+	sock_info->socket=socket(AF2PF(addr->s.sa_family), SOCK_STREAM, 0);
130
+	if (sock_info->socket==-1){
131
+		LOG(L_ERR, "ERROR: tcp_init: socket: %s\n", strerror(errno));
132
+		goto error;
133
+	}
134
+	if (bind(sock_info->socket, &addr->s, sockaddru_len(*addr))==-1){
135
+		LOG(L_ERR, "ERROR: tcp_init: bind(%x, %p, %d) on %s: %s\n",
136
+				sock_info->socket, &addr->s, 
137
+				sockaddru_len(*addr),
138
+				sock_info->address_str.s,
139
+				strerror(errno));
140
+		goto error;
141
+	}
142
+	if (listen(sock_info->socket, 10)==-1){
143
+		LOG(L_ERR, "ERROR: tcp_init: listen(%x, %p, %d) on %s: %s\n",
144
+				sock_info->socket, &addr->s, 
145
+				sockaddru_len(*addr),
146
+				sock_info->address_str.s,
147
+				strerror(errno));
148
+		goto error;
149
+	}
150
+	
151
+	return 0;
152
+error:
153
+	if (sock_info->socket!=-1){
154
+		close(sock_info->socket);
155
+		sock_info->socket=-1;
156
+	}
157
+	return -1;
158
+}
159
+
160
+
161
+
162
+static int send2child(struct tcp_connection* tcpconn)
163
+{
164
+	int i;
165
+	
166
+	for (i=0; i<tcp_children_no; i++){
167
+		if (!tcp_children[i].busy){
168
+			tcp_children[i].busy=1;
169
+			tcp_children[i].n_reqs++;
170
+			tcpconn->refcnt++;
171
+			DBG("send2child: to child %d, %ld\n", i, (long)tcpconn);
172
+			send_fd(tcp_children[i].s, &tcpconn, sizeof(tcpconn), tcpconn->s);
173
+			return 0;
174
+		}
175
+	}
176
+	if (i==tcp_children_no){
177
+		return -1;
178
+	}
179
+	return 0; /* just to fix a warning*/
180
+}
181
+
182
+
183
+void tcp_main_loop()
184
+{
185
+	int r;
186
+	int n;
187
+	fd_set master_set;
188
+	fd_set sel_set;
189
+	int maxfd;
190
+	int new_sock;
191
+	union sockaddr_union su;
192
+	struct tcp_connection* tcpconn;
193
+	long response[2];
194
+	int state;
195
+	socklen_t su_len;
196
+
197
+	/*init */
198
+	maxfd=0;
199
+	FD_ZERO(&master_set);
200
+	/* set all the listen addresses */
201
+	for (r=0; r<sock_no; r++){
202
+		if ((tcp_info[r].proto==SOCKET_TCP) &&(tcp_info[r].socket!=-1)){
203
+			FD_SET(tcp_info[r].socket, &master_set);
204
+			if (tcp_info[r].socket>maxfd) maxfd=tcp_info[r].socket;
205
+		}
206
+	}
207
+	/* set all the unix sockets used for child comm */
208
+	for (r=0; r<tcp_children_no; r++){
209
+		if (tcp_children[r].s>=0){
210
+			FD_SET(tcp_children[r].s, &master_set);
211
+			if (tcp_children[r].s>maxfd) maxfd=tcp_children[r].s;
212
+		}
213
+	}
214
+	
215
+	
216
+	/* main loop*/
217
+	
218
+	while(1){
219
+		sel_set=master_set;
220
+		n=select(maxfd+1, &sel_set, 0 ,0 , 0);
221
+		if (n<0){
222
+			/* errors */
223
+		}
224
+		
225
+		for (r=0; r<sock_no && n; r++){
226
+			if ((tcp_info[r].proto==SOCKET_TCP) &&
227
+					(FD_ISSET(tcp_info[r].socket, &sel_set))){
228
+				/* got a connection on r */
229
+				su_len=sizeof(su);
230
+				new_sock=accept(tcp_info[r].socket, &(su.s), &su_len);
231
+				n--;
232
+				if (new_sock<0){
233
+					LOG(L_ERR,  "WARNING: tcp_main_loop: error while accepting"
234
+							" connection(%d): %s\n", errno, strerror(errno));
235
+					continue;
236
+				}
237
+				
238
+				/* add socket to list */
239
+				tcpconn=tcpconn_add(new_sock, &su);
240
+				DBG("tcp_main_loop: new connection: %p %d\n",
241
+						tcpconn, tcpconn->s);
242
+				/* pass it to a child */
243
+				if(send2child(tcpconn)<0){
244
+					LOG(L_ERR,"ERROR: tcp_main_loop: no children available\n");
245
+					close(tcpconn->s);
246
+					tcpconn_rm(tcpconn);
247
+				}
248
+			}
249
+		}
250
+		
251
+		/* check all the read fds (from the tcpconn list) */
252
+		
253
+		for(tcpconn=conn_list; tcpconn && n; tcpconn=tcpconn->next){
254
+			if ((tcpconn->refcnt==0)&&(FD_ISSET(tcpconn->s, &sel_set))){
255
+				/* new data available */
256
+				n--;
257
+				/* pass it to child, so remove it from select list */
258
+				DBG("tcp_main_loop: data available on %p %d\n",
259
+						tcpconn, tcpconn->s);
260
+				FD_CLR(tcpconn->s, &master_set);
261
+				if (send2child(tcpconn)<0){
262
+					LOG(L_ERR,"ERROR: tcp_main_loop: no children available\n");
263
+					close(tcpconn->s);
264
+					tcpconn_rm(tcpconn);
265
+				}
266
+			}
267
+		}
268
+		
269
+		/* check unix sockets & listen | destroy connections */
270
+		for (r=0; r<tcp_children_no && n; r++){
271
+			if (FD_ISSET(tcp_children[r].s, &sel_set)){
272
+				n--;
273
+				/* errno==EINTR !!! todo*/
274
+				read(tcp_children[r].s, response, sizeof(response));
275
+				DBG("tcp__main_loop: read response= %lx, %ld\n",
276
+						response[0], response[1]);
277
+				tcp_children[r].busy=0;
278
+				tcpconn=(struct tcp_connection*)response[0];
279
+				state=response[1];
280
+				if (tcpconn){
281
+					tcpconn->refcnt--;
282
+					if (state>=0){
283
+						/* listen on this too */
284
+						if (tcpconn->refcnt==0){
285
+							FD_SET(tcpconn->s, &master_set);
286
+							if (maxfd<tcpconn->s) maxfd=tcpconn->s;
287
+						}
288
+					}else{
289
+						/*error, we should destroy it */
290
+						if (tcpconn->refcnt==0){
291
+							DBG("tcp_main_loop: destroying connection\n");
292
+							close(tcpconn->s);
293
+							tcpconn_rm(tcpconn);
294
+						}else{
295
+							DBG("tcp_main_loop: delaying ...\n");
296
+						}
297
+					}
298
+				}else{
299
+					LOG(L_CRIT, "BUG: tcp_main_loop: null tcp conn pointer\n");
300
+				}
301
+			}
302
+		}
303
+	
304
+	}
305
+}
306
+
307
+
308
+
309
+/* starts the tcp processes */
310
+int tcp_main()
311
+{
312
+	int r;
313
+	int sockfd[2];
314
+	pid_t pid;
315
+	
316
+	
317
+	/* create the tcp sock_info structures */
318
+	/* copy the sockets*/
319
+	for (r=0; r<sock_no ; r++){
320
+		tcp_info[r]=sock_info[r];
321
+		tcp_init_sock(&tcp_info[r]);
322
+	}
323
+	
324
+	/* fork children & create the socket pairs*/
325
+	for(r=0; r<tcp_children_no; r++){
326
+		if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sockfd)<0){
327
+			LOG(L_ERR, "ERROR: tcp_main: socketpair failed: %s\n",
328
+					strerror(errno));
329
+			goto error;
330
+		}
331
+		
332
+		pid=fork();
333
+		if (pid<0){
334
+			LOG(L_ERR, "ERROR: tcp_main: fork failed: %s\n",
335
+					strerror(errno));
336
+			goto error;
337
+		}else if (pid>0){
338
+			/* parent */
339
+			close(sockfd[1]);
340
+			tcp_children[r].pid=pid;
341
+			tcp_children[r].s=sockfd[0];
342
+			tcp_children[r].busy=0;
343
+			tcp_children[r].n_reqs=0;
344
+		}else{
345
+			/* child */
346
+			close(sockfd[0]);
347
+			tcp_receive_loop(sockfd[1]);
348
+		}
349
+	}
350
+	
351
+	tcp_main_loop();
352
+error:
353
+	return -1;
354
+}
355
+
356
+#endif
0 357
new file mode 100644
... ...
@@ -0,0 +1,253 @@
0
+/*
1
+ * $Id$
2
+ *
3
+ * Copyright (C) 2001-2003 Fhg Fokus
4
+ *
5
+ * This file is part of ser, a free SIP server.
6
+ *
7
+ * ser is free software; you can redistribute it and/or modify
8
+ * it under the terms of the GNU General Public License as published by
9
+ * the Free Software Foundation; either version 2 of the License, or
10
+ * (at your option) any later version
11
+ *
12
+ * For a license to use the ser software under conditions
13
+ * other than those described here, or to purchase support for this
14
+ * software, please contact iptel.org by e-mail at the following addresses:
15
+ *    info@iptel.org
16
+ *
17
+ * ser is distributed in the hope that it will be useful,
18
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
+ * GNU General Public License for more details.
21
+ *
22
+ * You should have received a copy of the GNU General Public License
23
+ * along with this program; if not, write to the Free Software
24
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25
+ */
26
+
27
+#ifdef USE_TCP
28
+
29
+#include <stdio.h>
30
+#include <errno.h>
31
+#include <string.h>
32
+
33
+#include <sys/select.h>
34
+
35
+#include <sys/time.h>
36
+#include <sys/types.h>
37
+#include <sys/socket.h>
38
+
39
+#include <unistd.h>
40
+
41
+
42
+#include "tcp_conn.h"
43
+#include "pass_fd.h"
44
+
45
+
46
+#define q_memchr memchr
47
+
48
+/* reads next available bytes
49
+ * return number of bytes read, 0 on EOF or -1 on error,
50
+ * sets also r->error */
51
+int tcp_read(struct tcp_req *r)
52
+{
53
+	int bytes_free, bytes_read;
54
+	
55
+	bytes_free=TCP_BUF_SIZE- (int)(r->pos - r->buf);
56
+	
57
+	if (bytes_free==0){
58
+		fprintf(stderr, "buffer overrun, dropping\n");
59
+		r->error=TCP_REQ_OVERRUN;
60
+		return -1;
61
+	}
62
+again:
63
+	bytes_read=read(r->fd, r->pos, bytes_free);
64
+
65
+	if(bytes_read==-1){
66
+		if (errno == EWOULDBLOCK || errno == EAGAIN){
67
+			return 0; /* nothing has been read */
68
+		}else if (errno == EINTR) goto again;
69
+		else{
70
+			fprintf(stderr, "error reading: %s\n", strerror(errno));
71
+			r->error=TCP_READ_ERROR;
72
+			return -1;
73
+		}
74
+	}
75
+	
76
+	r->pos+=bytes_read;
77
+	return bytes_read;
78
+}
79
+
80
+
81
+
82
+/* reads all headers (until double crlf),
83
+ * returns number of bytes read & sets r->state & r->body
84
+ * when either r->body!=0 or r->state==H_BODY =>
85
+ * all headers have been read. It should be called in a while loop.
86
+ * returns < 0 if error or 0 if EOF */
87
+int tcp_read_headers(struct tcp_req *r)
88
+{
89
+	int bytes;
90
+	char *p;
91
+	
92
+	bytes=tcp_read(r);
93
+	if (bytes<=0) return bytes;
94
+	p=r->parsed;
95
+	
96
+	while(p<r->pos && r->state!=H_BODY){
97
+		switch(r->state){
98
+			case H_PARSING:
99
+				/* find lf */
100
+				p=q_memchr(p, '\n', r->pos-r->parsed);
101
+				if (p){
102
+					p++;
103
+					r->state=H_LF;
104
+				}else{
105
+					p=r->pos;
106
+				}
107
+				break;
108
+				
109
+			case H_LF:
110
+				/* terminate on LF CR LF or LF LF */
111
+				if (*p=='\r'){
112
+					r->state=H_LFCR;
113
+				}else if (*p=='\n'){
114
+					/* found LF LF */
115
+					r->state=H_BODY;
116
+					r->body=p+1;
117
+				}else r->state=H_PARSING;
118
+				p++;
119
+				break;
120
+			
121
+			case H_LFCR:
122
+				if (*p=='\n'){
123
+					/* found LF CR LF */
124
+					r->state=H_BODY;
125
+					r->body=p+1;
126
+				}else r->state=H_PARSING;
127
+				p++;
128
+				break;
129
+				
130
+			default:
131
+				fprintf(stderr, "BUG: unexpected state %d\n", r->state);
132
+				abort();
133
+		}
134
+	}
135
+	
136
+	r->parsed=p;
137
+	return bytes;
138
+}
139
+
140
+
141
+
142
+
143
+void tcp_receive_loop(int unix_sock)
144
+{
145
+	struct tcp_req req;
146
+	int bytes;
147
+	long size;
148
+	int n;
149
+	long id;
150
+	int s;
151
+	long state;
152
+	long response[2];
153
+	
154
+	
155
+	
156
+	
157
+	/* listen on the unix socket for the fd */
158
+	for(;;){
159
+			n=receive_fd(unix_sock, &id, sizeof(id), &s);
160
+			if (n<0){
161
+				if (errno == EWOULDBLOCK || errno == EAGAIN || errno == EINTR){
162
+					continue;
163
+				}else{
164
+					fprintf(stderr, "ERROR: tcp_receive_loop: read_fd: %s\n",
165
+							strerror(errno));
166
+					abort(); /* big error*/
167
+				}
168
+			}
169
+			if (n==0){
170
+					fprintf(stderr, 
171
+							"WARNING: tcp_receive_loop: 0 bytes read\n");
172
+					continue;
173
+			}
174
+			fprintf(stderr, "received n=%d id=%ld, fd=%d\n", n, id, s);
175
+			if (s==-1) {
176
+					fprintf(stderr, "ERROR: tcp_receive_loop: read_fd:"
177
+									"no fd read\n");
178
+					state=-1;
179
+					goto end_req; /* ?*/
180
+			}
181
+		
182
+		init_tcp_req(&req, s);
183
+		
184
+		
185
+	again:
186
+		while(req.body==0){
187
+			bytes=tcp_read_headers(&req);
188
+			/* if timeout state=0; goto end__req; */
189
+			fprintf(stderr, "read= %d bytes, parsed=%d, state=%d, error=%d\n",
190
+					bytes, req.parsed-req.buf, req.state, req.error );
191
+			if (bytes==-1){
192
+				fprintf(stderr, "ERROR!\n");
193
+				state=-1;
194
+				goto end_req;
195
+			}
196
+			if (bytes==0){
197
+				fprintf(stderr, "EOF!\n");
198
+				state=-1;
199
+				goto end_req;
200
+			}
201
+
202
+		}
203
+		fprintf(stderr, "end of header part\n");
204
+		fprintf(stderr, "headers:\n%.*s.\n",req.body-req.buf, req.buf);
205
+
206
+		/* just debugging*/
207
+		state=0;
208
+		goto end_req;
209
+		/* parse headers ... */
210
+		
211
+		/* get body */
212
+		
213
+		/* copy request */
214
+
215
+		/* prepare for next request */
216
+		size=req.pos-req.body;
217
+		if (size) memmove(req.buf, req.body, size);
218
+		fprintf(stderr, "\npreparing for new request, kept %ld bytes\n", size);
219
+		req.pos=req.buf+size;
220
+		req.parsed=req.buf;
221
+		req.body=0;
222
+		req.error=TCP_REQ_OK;
223
+		req.state=H_PARSING;
224
+	
225
+		/* process last req. */
226
+		
227
+		goto again;
228
+		
229
+	end_req:
230
+			fprintf(stderr, "end req\n");
231
+		/* release req & signal the parent */
232
+		if (s!=-1) close(s);
233
+		/* errno==EINTR, EWOULDBLOCK a.s.o todo */
234
+		response[0]=id;
235
+		response[1]=state;
236
+		write(unix_sock, response, sizeof(response));
237
+		
238
+	
239
+	}
240
+}
241
+
242
+
243
+#if 0
244
+int main(int argv, char** argc )
245
+{
246
+	printf("starting tests\n");
247
+	tcp_receive_loop();
248
+}
249
+
250
+#endif
251
+
252
+#endif