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