Browse Source

- 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 23 năm trước cách đây
mục cha
commit
5b532c7fdd
9 tập tin đã thay đổi với 882 bổ sung3 xóa
  1. 5 1
      Makefile.defs
  2. 4 0
      globals.h
  3. 4 2
      ip_addr.h
  4. 27 0
      main.c
  5. 124 0
      pass_fd.c
  6. 37 0
      pass_fd.h
  7. 71 0
      tcp_conn.h
  8. 357 0
      tcp_main.c
  9. 253 0
      tcp_read.c

+ 5 - 1
Makefile.defs

@@ -131,6 +131,9 @@ YACC := $(shell echo "$${YACC}")
 #  		if enabled, allows forking of the snmp agent just before child
 #  		forking (done at the top of main_loop). Needed if you want
 #  		to use the snmp module.
+# -DUSE_TCP
+#		compiles in tcp support (highly experimental for now, it will probably
+#		not work, use it only if you really now what you are doing)
 DEFS+= -DNAME='"$(NAME)"' -DVERSION='"$(RELEASE)"' -DARCH='"$(ARCH)"' \
 	 -DOS='"$(OS)"' -DCOMPILER='"$(CC_VER)"' -D__CPU_$(ARCH)\
 	 -DCFG_DIR='"$(cfg-target)"'\
@@ -140,6 +143,7 @@ DEFS+= -DNAME='"$(NAME)"' -DVERSION='"$(RELEASE)"' -DARCH='"$(ARCH)"' \
 	 -DDNS_IP_HACK \
 	 -DUSE_IPV6 \
 	 -DDBG_QM_MALLOC \
+	# -DUSE_TCP \
 	 #-DF_MALLOC \
 	 #-DNO_DEBUG \
 	 #-DNO_LOG
@@ -293,7 +297,7 @@ ifeq	($(ARCH), i386)
 		# if gcc 
 ifeq		($(CC_NAME), gcc)
 				#common stuff
-				CFLAGS=-O9 -funroll-loops  -Wcast-align $(PROFILE) \
+				CFLAGS=-g -O9 -funroll-loops  -Wcast-align $(PROFILE) \
 					-Wall   \
 			#if gcc 3.0
 ifeq			($(CC_SHORTVER), 3.0)

+ 4 - 0
globals.h

@@ -46,6 +46,7 @@
 extern char * cfg_file;
 extern char *stat_file;
 extern struct socket_info sock_info[]; /* all addresses we listen/send from*/
+extern struct socket_info tcp_info[]; /* all tcp sockets we listen on*/
 extern int sock_no; /* number of addresses/open sockets*/
 extern unsigned short port_no;
 /*
@@ -67,6 +68,9 @@ extern struct socket_info* sendipv6; /* same as above for ipv6 */
 
 extern unsigned int maxbuffer;
 extern int children_no;
+#ifdef USE_TCP
+extern int tcp_children_no;
+#endif
 extern int dont_fork;
 extern int check_via;
 extern int received_dns;

+ 4 - 2
ip_addr.h

@@ -40,7 +40,8 @@
 
 #include "dprint.h"
 
-
+#define SOCKET_TCP	1
+#define SOCKET_UDP	0
 
 struct ip_addr{
 	unsigned int af; /* address family: AF_INET6 or AF_INET */
@@ -80,6 +81,7 @@ struct socket_info{
 	int is_ip; /* 1 if name is an ip address, 0 if not  -- optimization*/
 	int is_lo; /* 1 if is a loopback, 0 if not */
 	union sockaddr_union su; 
+	int proto; /* tcp or udp*/
 };
 
 
@@ -136,7 +138,7 @@ void print_net(struct net* net);
 	[ diff. adress fams ]) */
 inline static int matchnet(struct ip_addr* ip, struct net* net)
 {
-	int r;
+	unsigned int r;
 	int ret;
 	
 	ret=-1;

+ 27 - 0
main.c

@@ -94,6 +94,9 @@ static char flags[]=
 #ifdef USE_IPV6
 ", USE_IPV6"
 #endif
+#ifdef USE_TCP
+", USE_TCP"
+#endif
 #ifdef NO_DEBUG
 ", NO_DEBUG"
 #endif
@@ -225,6 +228,9 @@ unsigned int maxbuffer = MAX_RECV_BUFFER_SIZE; /* maximum buffer size we do
 												  auto-probing procedure; may 
 												  be re-configured */
 int children_no = 0;			/* number of children processing requests */
+#ifdef USE_TCP
+int tcp_children_no = 0;
+#endif
 struct process_table *pt=0;		/*array with childrens pids, 0= main proc,
 									alloc'ed in shared mem if possible*/
 int sig_flag = 0;              /* last signal received */
@@ -266,6 +272,9 @@ struct ip_addr addresses[MAX_LISTEN]; /* our ips */
 int addresses_no=0;                   /* number of names/ips */
 #endif
 struct socket_info sock_info[MAX_LISTEN];/*all addresses we listen/send from*/
+#ifdef USE_TCP
+struct socket_info tcp_info[MAX_LISTEN];/*all tcp addresses we listen on*/
+#endif
 int sock_no=0; /* number of addresses/open sockets*/
 struct socket_info* bind_address=0; /* pointer to the crt. proc.
 									 listening address*/
@@ -616,6 +625,21 @@ int main_loop()
 			/* all procs should have access to all the sockets (for sending)
 			 * so we open all first*/
 		}
+#ifdef USE_TCP
+			/* start tcp master proc */
+		process_no++;
+		if ((pid=fork())<0){
+			LOG(L_CRIT, "main_loop: cannot fork tcp main process\n");
+			goto error;
+		}else if (pid==0){
+			/* child */
+			/* is_main=0; */
+			tcp_main();
+		}else{
+			pt[process_no].pid=pid;
+			strncpy(pt[process_no].desc, "tcp main process", MAX_PT_DESC );
+		}
+#endif
 		for(r=0; r<sock_no;r++){
 			for(i=0;i<children_no;i++){
 				process_no++;
@@ -1165,6 +1189,9 @@ try_again:
 
 	
 	if (children_no<=0) children_no=CHILD_NO;
+#ifdef USE_TCP
+	tcp_children_no=children_no;
+#endif
 #ifdef _OBSOLETED
 	else if (children_no >= MAX_PROCESSES ) {
 		fprintf(stderr, "ERROR: too many children processes configured;"

+ 124 - 0
pass_fd.c

@@ -0,0 +1,124 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2001-2003 Fhg Fokus
+ *
+ * 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
+ */
+
+#ifdef USE_TCP
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+/* remove this after replacing fprintf*/
+#include <stdio.h>
+
+
+/* at least 1 byte must be sent! */
+int send_fd(int unix_socket, void* data, int data_len, int fd)
+{
+	struct msghdr msg;
+	struct iovec iov[1];
+	struct cmsghdr* cmsg;
+	int ret;
+	union {
+		struct cmsghdr cm;
+		char control[CMSG_SPACE(sizeof(fd))];
+	}control_un;
+	
+	msg.msg_control=control_un.control;
+	msg.msg_controllen=sizeof(control_un.control);
+	
+	msg.msg_name=0;
+	msg.msg_namelen=0;
+	
+	iov[0].iov_base=data;
+	iov[0].iov_len=data_len;
+	msg.msg_iov=iov;
+	msg.msg_iovlen=1;
+	
+	cmsg=CMSG_FIRSTHDR(&msg);
+	cmsg->cmsg_level = SOL_SOCKET;
+	cmsg->cmsg_type = SCM_RIGHTS;
+	cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
+	*(int*)CMSG_DATA(cmsg)=fd;
+	msg.msg_flags=0;
+	
+	ret=sendmsg(unix_socket, &msg, 0);
+	
+	return ret;
+}
+
+
+
+int receive_fd(int unix_socket, void* data, int data_len, int* fd)
+{
+	struct msghdr msg;
+	struct iovec iov[1];
+	struct cmsghdr* cmsg;
+	int new_fd;
+	int ret;
+	union{
+		struct cmsghdr cm;
+		char control[CMSG_SPACE(sizeof(new_fd))];
+	}control_un;
+	
+	msg.msg_control=control_un.control;
+	msg.msg_controllen=sizeof(control_un.control);
+	
+	msg.msg_name=0;
+	msg.msg_namelen=0;
+	
+	iov[0].iov_base=data;
+	iov[0].iov_len=data_len;
+	msg.msg_iov=iov;
+	msg.msg_iovlen=1;
+	
+	ret=recvmsg(unix_socket, &msg, 0);
+	if (ret<=0) goto error;
+	
+	cmsg=CMSG_FIRSTHDR(&msg);
+	if ((cmsg!=0) && (cmsg->cmsg_len==CMSG_LEN(sizeof(new_fd)))){
+		if (cmsg->cmsg_type!= SCM_RIGHTS){
+			fprintf(stderr, " msg control type != SCM_RIGHTS\n");
+			ret=-1;
+			goto error;
+		}
+		if (cmsg->cmsg_level!= SOL_SOCKET){
+			fprintf(stderr, " msg level != SOL_SOCKET\n");
+			ret=-1;
+			goto error;
+		}
+		*fd=*((int*) CMSG_DATA(cmsg));
+	}else{
+		fprintf(stderr, " no descriptor passed, cmsg=%p, len=%d\n",
+				cmsg, cmsg->cmsg_len);
+		*fd=-1;
+		/* it's not really an error */
+	}
+	
+error:
+	return ret;
+}
+
+#endif

+ 37 - 0
pass_fd.h

@@ -0,0 +1,37 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2001-2003 Fhg Fokus
+ *
+ * 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
+ */
+
+#ifndef _pass_fd_h
+#define _pass_fd_h
+
+
+int send_fd(int unix_socket, void* data, int data_len, int fd);
+int receive_fd(int unix_socket, void* data, int data_len, int* fd);
+
+
+
+#endif

+ 71 - 0
tcp_conn.h

@@ -0,0 +1,71 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2001-2003 Fhg Fokus
+ *
+ * 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
+ */
+
+
+
+#ifndef _tcp_conn_h
+#define _tcp_conn_h
+
+
+
+#define TCP_BUF_SIZE 65535
+enum {TCP_REQ_INIT, TCP_REQ_OK, TCP_READ_ERROR, TCP_REQ_OVERRUN };
+enum {H_PARSING, H_LF, H_LFCR,  H_BODY };
+
+struct tcp_req{
+	struct tcp_req* next;
+	int fd;
+	/* sockaddr ? */
+	char buf[TCP_BUF_SIZE]; /* bytes read so far*/
+	char* pos; /* current position in buf */
+	char* parsed; /* last parsed position */
+	char* body; /* body position */
+	int error;
+	int state;
+};
+
+
+#define init_tcp_req( r, f) \
+	do{ \
+		memset( (r), 0, sizeof(struct tcp_req)); \
+		(r)->fd=(f); \
+		(r)->parsed=(r)->pos=(r)->buf; \
+		(r)->error=TCP_REQ_OK;\
+		(r)->state=H_PARSING; \
+	}while(0)
+
+
+
+
+
+
+
+
+
+#endif
+
+

+ 357 - 0
tcp_main.c

@@ -0,0 +1,357 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2001-2003 Fhg Fokus
+ *
+ * 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
+ */
+
+
+#ifdef USE_TCP
+
+#include <sys/select.h>
+
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <unistd.h>
+
+#include <errno.h>
+#include <string.h>
+
+
+
+#include "ip_addr.h"
+#include "pass_fd.h"
+#include "globals.h"
+#include "mem/mem.h"
+
+
+#define local_malloc pkg_malloc
+#define local_free   pkg_free
+
+#define MAX_TCP_CHILDREN 100
+
+struct tcp_child{
+	pid_t pid;
+	int s; /* unix socket for comm*/
+	int busy;
+	int n_reqs; /* number of requests serviced so far */
+};
+
+
+enum { CONN_OK, CONN_ERROR };
+
+struct tcp_connection{
+	int s; /*socket */
+	struct ip_addr ip;
+	union sockaddr_union su;
+	int refcnt;
+	struct tcp_connection* next;
+	struct tcp_connection* prev;
+};
+
+
+
+struct tcp_connection* conn_list=0;
+struct tcp_child tcp_children[MAX_TCP_CHILDREN];
+
+
+
+struct tcp_connection*  tcpconn_add(int sock, union sockaddr_union* su)
+{
+	struct tcp_connection *c;
+	
+
+	c=(struct tcp_connection*)local_malloc(sizeof(struct tcp_connection));
+	if (c==0){
+		LOG(L_ERR, "ERROR: tcpconn_add: mem. allocation failure\n");
+		goto error;
+	}
+	c->s=sock;
+	c->su=*su;
+	c->refcnt=0;
+	su2ip_addr(&c->ip, su);
+
+	/* add it at the begining of the list*/
+	c->next=conn_list;
+	c->prev=0;
+	if (conn_list) conn_list->prev=c;
+	conn_list=c;
+	return c;
+	
+error:
+	return 0;
+}
+
+
+
+void tcpconn_rm(struct tcp_connection* c)
+{
+	
+	if (conn_list==c) conn_list=c->next;
+	if (c->next) c->next->prev=c->prev;
+	if (c->prev) c->prev->next=c->next;
+	local_free(c);
+}
+
+
+
+int tcp_init_sock(struct socket_info* sock_info)
+{
+	union sockaddr_union* addr;
+	
+	addr=&sock_info->su;
+	sock_info->proto=SOCKET_TCP;
+	if (init_su(addr, &sock_info->address, htons(sock_info->port_no))<0){
+		LOG(L_ERR, "ERROR: tcp_init: could no init sockaddr_union\n");
+		goto error;
+	}
+	sock_info->socket=socket(AF2PF(addr->s.sa_family), SOCK_STREAM, 0);
+	if (sock_info->socket==-1){
+		LOG(L_ERR, "ERROR: tcp_init: socket: %s\n", strerror(errno));
+		goto error;
+	}
+	if (bind(sock_info->socket, &addr->s, sockaddru_len(*addr))==-1){
+		LOG(L_ERR, "ERROR: tcp_init: bind(%x, %p, %d) on %s: %s\n",
+				sock_info->socket, &addr->s, 
+				sockaddru_len(*addr),
+				sock_info->address_str.s,
+				strerror(errno));
+		goto error;
+	}
+	if (listen(sock_info->socket, 10)==-1){
+		LOG(L_ERR, "ERROR: tcp_init: listen(%x, %p, %d) on %s: %s\n",
+				sock_info->socket, &addr->s, 
+				sockaddru_len(*addr),
+				sock_info->address_str.s,
+				strerror(errno));
+		goto error;
+	}
+	
+	return 0;
+error:
+	if (sock_info->socket!=-1){
+		close(sock_info->socket);
+		sock_info->socket=-1;
+	}
+	return -1;
+}
+
+
+
+static int send2child(struct tcp_connection* tcpconn)
+{
+	int i;
+	
+	for (i=0; i<tcp_children_no; i++){
+		if (!tcp_children[i].busy){
+			tcp_children[i].busy=1;
+			tcp_children[i].n_reqs++;
+			tcpconn->refcnt++;
+			DBG("send2child: to child %d, %ld\n", i, (long)tcpconn);
+			send_fd(tcp_children[i].s, &tcpconn, sizeof(tcpconn), tcpconn->s);
+			return 0;
+		}
+	}
+	if (i==tcp_children_no){
+		return -1;
+	}
+	return 0; /* just to fix a warning*/
+}
+
+
+void tcp_main_loop()
+{
+	int r;
+	int n;
+	fd_set master_set;
+	fd_set sel_set;
+	int maxfd;
+	int new_sock;
+	union sockaddr_union su;
+	struct tcp_connection* tcpconn;
+	long response[2];
+	int state;
+	socklen_t su_len;
+
+	/*init */
+	maxfd=0;
+	FD_ZERO(&master_set);
+	/* set all the listen addresses */
+	for (r=0; r<sock_no; r++){
+		if ((tcp_info[r].proto==SOCKET_TCP) &&(tcp_info[r].socket!=-1)){
+			FD_SET(tcp_info[r].socket, &master_set);
+			if (tcp_info[r].socket>maxfd) maxfd=tcp_info[r].socket;
+		}
+	}
+	/* set all the unix sockets used for child comm */
+	for (r=0; r<tcp_children_no; r++){
+		if (tcp_children[r].s>=0){
+			FD_SET(tcp_children[r].s, &master_set);
+			if (tcp_children[r].s>maxfd) maxfd=tcp_children[r].s;
+		}
+	}
+	
+	
+	/* main loop*/
+	
+	while(1){
+		sel_set=master_set;
+		n=select(maxfd+1, &sel_set, 0 ,0 , 0);
+		if (n<0){
+			/* errors */
+		}
+		
+		for (r=0; r<sock_no && n; r++){
+			if ((tcp_info[r].proto==SOCKET_TCP) &&
+					(FD_ISSET(tcp_info[r].socket, &sel_set))){
+				/* got a connection on r */
+				su_len=sizeof(su);
+				new_sock=accept(tcp_info[r].socket, &(su.s), &su_len);
+				n--;
+				if (new_sock<0){
+					LOG(L_ERR,  "WARNING: tcp_main_loop: error while accepting"
+							" connection(%d): %s\n", errno, strerror(errno));
+					continue;
+				}
+				
+				/* add socket to list */
+				tcpconn=tcpconn_add(new_sock, &su);
+				DBG("tcp_main_loop: new connection: %p %d\n",
+						tcpconn, tcpconn->s);
+				/* pass it to a child */
+				if(send2child(tcpconn)<0){
+					LOG(L_ERR,"ERROR: tcp_main_loop: no children available\n");
+					close(tcpconn->s);
+					tcpconn_rm(tcpconn);
+				}
+			}
+		}
+		
+		/* check all the read fds (from the tcpconn list) */
+		
+		for(tcpconn=conn_list; tcpconn && n; tcpconn=tcpconn->next){
+			if ((tcpconn->refcnt==0)&&(FD_ISSET(tcpconn->s, &sel_set))){
+				/* new data available */
+				n--;
+				/* pass it to child, so remove it from select list */
+				DBG("tcp_main_loop: data available on %p %d\n",
+						tcpconn, tcpconn->s);
+				FD_CLR(tcpconn->s, &master_set);
+				if (send2child(tcpconn)<0){
+					LOG(L_ERR,"ERROR: tcp_main_loop: no children available\n");
+					close(tcpconn->s);
+					tcpconn_rm(tcpconn);
+				}
+			}
+		}
+		
+		/* check unix sockets & listen | destroy connections */
+		for (r=0; r<tcp_children_no && n; r++){
+			if (FD_ISSET(tcp_children[r].s, &sel_set)){
+				n--;
+				/* errno==EINTR !!! todo*/
+				read(tcp_children[r].s, response, sizeof(response));
+				DBG("tcp__main_loop: read response= %lx, %ld\n",
+						response[0], response[1]);
+				tcp_children[r].busy=0;
+				tcpconn=(struct tcp_connection*)response[0];
+				state=response[1];
+				if (tcpconn){
+					tcpconn->refcnt--;
+					if (state>=0){
+						/* listen on this too */
+						if (tcpconn->refcnt==0){
+							FD_SET(tcpconn->s, &master_set);
+							if (maxfd<tcpconn->s) maxfd=tcpconn->s;
+						}
+					}else{
+						/*error, we should destroy it */
+						if (tcpconn->refcnt==0){
+							DBG("tcp_main_loop: destroying connection\n");
+							close(tcpconn->s);
+							tcpconn_rm(tcpconn);
+						}else{
+							DBG("tcp_main_loop: delaying ...\n");
+						}
+					}
+				}else{
+					LOG(L_CRIT, "BUG: tcp_main_loop: null tcp conn pointer\n");
+				}
+			}
+		}
+	
+	}
+}
+
+
+
+/* starts the tcp processes */
+int tcp_main()
+{
+	int r;
+	int sockfd[2];
+	pid_t pid;
+	
+	
+	/* create the tcp sock_info structures */
+	/* copy the sockets*/
+	for (r=0; r<sock_no ; r++){
+		tcp_info[r]=sock_info[r];
+		tcp_init_sock(&tcp_info[r]);
+	}
+	
+	/* fork children & create the socket pairs*/
+	for(r=0; r<tcp_children_no; r++){
+		if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sockfd)<0){
+			LOG(L_ERR, "ERROR: tcp_main: socketpair failed: %s\n",
+					strerror(errno));
+			goto error;
+		}
+		
+		pid=fork();
+		if (pid<0){
+			LOG(L_ERR, "ERROR: tcp_main: fork failed: %s\n",
+					strerror(errno));
+			goto error;
+		}else if (pid>0){
+			/* parent */
+			close(sockfd[1]);
+			tcp_children[r].pid=pid;
+			tcp_children[r].s=sockfd[0];
+			tcp_children[r].busy=0;
+			tcp_children[r].n_reqs=0;
+		}else{
+			/* child */
+			close(sockfd[0]);
+			tcp_receive_loop(sockfd[1]);
+		}
+	}
+	
+	tcp_main_loop();
+error:
+	return -1;
+}
+
+#endif

+ 253 - 0
tcp_read.c

@@ -0,0 +1,253 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2001-2003 Fhg Fokus
+ *
+ * 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
+ */
+
+#ifdef USE_TCP
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+
+#include <sys/select.h>
+
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <unistd.h>
+
+
+#include "tcp_conn.h"
+#include "pass_fd.h"
+
+
+#define q_memchr memchr
+
+/* reads next available bytes
+ * return number of bytes read, 0 on EOF or -1 on error,
+ * sets also r->error */
+int tcp_read(struct tcp_req *r)
+{
+	int bytes_free, bytes_read;
+	
+	bytes_free=TCP_BUF_SIZE- (int)(r->pos - r->buf);
+	
+	if (bytes_free==0){
+		fprintf(stderr, "buffer overrun, dropping\n");
+		r->error=TCP_REQ_OVERRUN;
+		return -1;
+	}
+again:
+	bytes_read=read(r->fd, r->pos, bytes_free);
+
+	if(bytes_read==-1){
+		if (errno == EWOULDBLOCK || errno == EAGAIN){
+			return 0; /* nothing has been read */
+		}else if (errno == EINTR) goto again;
+		else{
+			fprintf(stderr, "error reading: %s\n", strerror(errno));
+			r->error=TCP_READ_ERROR;
+			return -1;
+		}
+	}
+	
+	r->pos+=bytes_read;
+	return bytes_read;
+}
+
+
+
+/* reads all headers (until double crlf),
+ * returns number of bytes read & sets r->state & r->body
+ * when either r->body!=0 or r->state==H_BODY =>
+ * all headers have been read. It should be called in a while loop.
+ * returns < 0 if error or 0 if EOF */
+int tcp_read_headers(struct tcp_req *r)
+{
+	int bytes;
+	char *p;
+	
+	bytes=tcp_read(r);
+	if (bytes<=0) return bytes;
+	p=r->parsed;
+	
+	while(p<r->pos && r->state!=H_BODY){
+		switch(r->state){
+			case H_PARSING:
+				/* find lf */
+				p=q_memchr(p, '\n', r->pos-r->parsed);
+				if (p){
+					p++;
+					r->state=H_LF;
+				}else{
+					p=r->pos;
+				}
+				break;
+				
+			case H_LF:
+				/* terminate on LF CR LF or LF LF */
+				if (*p=='\r'){
+					r->state=H_LFCR;
+				}else if (*p=='\n'){
+					/* found LF LF */
+					r->state=H_BODY;
+					r->body=p+1;
+				}else r->state=H_PARSING;
+				p++;
+				break;
+			
+			case H_LFCR:
+				if (*p=='\n'){
+					/* found LF CR LF */
+					r->state=H_BODY;
+					r->body=p+1;
+				}else r->state=H_PARSING;
+				p++;
+				break;
+				
+			default:
+				fprintf(stderr, "BUG: unexpected state %d\n", r->state);
+				abort();
+		}
+	}
+	
+	r->parsed=p;
+	return bytes;
+}
+
+
+
+
+void tcp_receive_loop(int unix_sock)
+{
+	struct tcp_req req;
+	int bytes;
+	long size;
+	int n;
+	long id;
+	int s;
+	long state;
+	long response[2];
+	
+	
+	
+	
+	/* listen on the unix socket for the fd */
+	for(;;){
+			n=receive_fd(unix_sock, &id, sizeof(id), &s);
+			if (n<0){
+				if (errno == EWOULDBLOCK || errno == EAGAIN || errno == EINTR){
+					continue;
+				}else{
+					fprintf(stderr, "ERROR: tcp_receive_loop: read_fd: %s\n",
+							strerror(errno));
+					abort(); /* big error*/
+				}
+			}
+			if (n==0){
+					fprintf(stderr, 
+							"WARNING: tcp_receive_loop: 0 bytes read\n");
+					continue;
+			}
+			fprintf(stderr, "received n=%d id=%ld, fd=%d\n", n, id, s);
+			if (s==-1) {
+					fprintf(stderr, "ERROR: tcp_receive_loop: read_fd:"
+									"no fd read\n");
+					state=-1;
+					goto end_req; /* ?*/
+			}
+		
+		init_tcp_req(&req, s);
+		
+		
+	again:
+		while(req.body==0){
+			bytes=tcp_read_headers(&req);
+			/* if timeout state=0; goto end__req; */
+			fprintf(stderr, "read= %d bytes, parsed=%d, state=%d, error=%d\n",
+					bytes, req.parsed-req.buf, req.state, req.error );
+			if (bytes==-1){
+				fprintf(stderr, "ERROR!\n");
+				state=-1;
+				goto end_req;
+			}
+			if (bytes==0){
+				fprintf(stderr, "EOF!\n");
+				state=-1;
+				goto end_req;
+			}
+
+		}
+		fprintf(stderr, "end of header part\n");
+		fprintf(stderr, "headers:\n%.*s.\n",req.body-req.buf, req.buf);
+
+		/* just debugging*/
+		state=0;
+		goto end_req;
+		/* parse headers ... */
+		
+		/* get body */
+		
+		/* copy request */
+
+		/* prepare for next request */
+		size=req.pos-req.body;
+		if (size) memmove(req.buf, req.body, size);
+		fprintf(stderr, "\npreparing for new request, kept %ld bytes\n", size);
+		req.pos=req.buf+size;
+		req.parsed=req.buf;
+		req.body=0;
+		req.error=TCP_REQ_OK;
+		req.state=H_PARSING;
+	
+		/* process last req. */
+		
+		goto again;
+		
+	end_req:
+			fprintf(stderr, "end req\n");
+		/* release req & signal the parent */
+		if (s!=-1) close(s);
+		/* errno==EINTR, EWOULDBLOCK a.s.o todo */
+		response[0]=id;
+		response[1]=state;
+		write(unix_sock, response, sizeof(response));
+		
+	
+	}
+}
+
+
+#if 0
+int main(int argv, char** argc )
+{
+	printf("starting tests\n");
+	tcp_receive_loop();
+}
+
+#endif
+
+#endif