Browse code

- increased ROUTE_MAX_REC_LEV to 100 - added new route commad: send_tcp(address, port) - tcp global vars (added new members to pt a.s.o) - tcp_send(buf, len, server, 0) will try to find an existing open tcp connection to "server"; if none found a new one will be opened (ser will also start listening on it for sip messages) - first udp to tcp & tcp to tcp send (not forward, I still have to solve some tricky via stuff)

Andrei Pelinescu-Onciul authored on 11/12/2002 21:30:44
Showing 16 changed files
... ...
@@ -43,6 +43,9 @@
43 43
 #include "mem/mem.h"
44 44
 #include "globals.h"
45 45
 #include "dset.h"
46
+#ifdef USE_TCP
47
+#include "tcp_server.h"
48
+#endif
46 49
 
47 50
 #include <sys/types.h>
48 51
 #include <sys/socket.h>
... ...
@@ -133,6 +136,7 @@ int do_action(struct action* a, struct sip_msg* msg)
133 136
 			}
134 137
 			break;
135 138
 		case SEND_T:
139
+		case SEND_TCP_T:
136 140
 			if ((a->p1_type!= PROXY_ST)|(a->p2_type!=NUMBER_ST)){
137 141
 				LOG(L_CRIT, "BUG: do_action: bad send() types %d, %d\n",
138 142
 						a->p1_type, a->p2_type);
... ...
@@ -161,12 +165,21 @@ int do_action(struct action* a, struct sip_msg* msg)
161 165
 			if (ret==0){
162 166
 				p->tx++;
163 167
 				p->tx_bytes+=msg->len;
164
-				send_sock=get_send_socket(to);
165
-				if (send_sock!=0){
166
-					ret=udp_send(send_sock, msg->orig, msg->len, to);
167
-				}else{
168
-					ret=-1;
168
+				if (a->type==SEND_T){
169
+					/*udp*/
170
+					send_sock=get_send_socket(to);
171
+					if (send_sock!=0){
172
+						ret=udp_send(send_sock, msg->orig, msg->len, to);
173
+					}else{
174
+						ret=-1;
175
+					}
169 176
 				}
177
+#ifdef USE_TCP
178
+					else{
179
+					/*tcp*/
180
+					ret=tcp_send(msg->orig, msg->len, to, 0);
181
+				}
182
+#endif
170 183
 			}
171 184
 			free(to);
172 185
 			if (ret<0){
... ...
@@ -41,8 +41,10 @@
41 41
 
42 42
 /* action keywords */
43 43
 FORWARD	forward
44
+FORWARD_TCP	forward_tcp
44 45
 DROP	"drop"|"break"
45 46
 SEND	send
47
+SEND_TCP	send_tcp
46 48
 LOG		log
47 49
 ERROR	error
48 50
 ROUTE	route
... ...
@@ -152,8 +154,10 @@ EAT_ABLE	[\ \t\b\r]
152 154
 <INITIAL>{EAT_ABLE}	{ count(); }
153 155
 
154 156
 <INITIAL>{FORWARD}	{count(); yylval.strval=yytext; return FORWARD; }
157
+<INITIAL>{FORWARD_TCP}	{count(); yylval.strval=yytext; return FORWARD_TCP; }
155 158
 <INITIAL>{DROP}	{ count(); yylval.strval=yytext; return DROP; }
156 159
 <INITIAL>{SEND}	{ count(); yylval.strval=yytext; return SEND; }
160
+<INITIAL>{SEND_TCP}	{ count(); yylval.strval=yytext; return SEND_TCP; }
157 161
 <INITIAL>{LOG}	{ count(); yylval.strval=yytext; return LOG_TOK; }
158 162
 <INITIAL>{ERROR}	{ count(); yylval.strval=yytext; return ERROR; }
159 163
 <INITIAL>{SETFLAG}	{ count(); yylval.strval=yytext; return SETFLAG; }
... ...
@@ -63,7 +63,9 @@ struct id_list* lst_tmp;
63 63
 
64 64
 /* keywords */
65 65
 %token FORWARD
66
+%token FORWARD_TCP
66 67
 %token SEND
68
+%token SEND_TCP
67 69
 %token DROP
68 70
 %token LOG_TOK
69 71
 %token ERROR
... ...
@@ -720,6 +722,45 @@ cmd:		FORWARD LPAREN host RPAREN	{ $$=mk_action(	FORWARD_T,
720 722
 		| SEND error { $$=0; yyerror("missing '(' or ')' ?"); }
721 723
 		| SEND LPAREN error RPAREN { $$=0; yyerror("bad send"
722 724
 													"argument"); }
725
+		| SEND_TCP LPAREN host RPAREN	{ $$=mk_action(	SEND_TCP_T,
726
+													STRING_ST,
727
+													NUMBER_ST,
728
+													$3,
729
+													0);
730
+									}
731
+		| SEND_TCP LPAREN STRING RPAREN { $$=mk_action(	SEND_TCP_T,
732
+													STRING_ST,
733
+													NUMBER_ST,
734
+													$3,
735
+													0);
736
+									}
737
+		| SEND_TCP LPAREN ip RPAREN		{ $$=mk_action(	SEND_TCP_T,
738
+													IP_ST,
739
+													NUMBER_ST,
740
+													(void*)$3,
741
+													0);
742
+									}
743
+		| SEND_TCP LPAREN host COMMA NUMBER RPAREN	{ $$=mk_action(	SEND_TCP_T,
744
+																STRING_ST,
745
+																NUMBER_ST,
746
+																$3,
747
+																(void*)$5);
748
+												}
749
+		| SEND_TCP LPAREN STRING COMMA NUMBER RPAREN {$$=mk_action(	SEND_TCP_T,
750
+																STRING_ST,
751
+																NUMBER_ST,
752
+																$3,
753
+																(void*)$5);
754
+												}
755
+		| SEND_TCP LPAREN ip COMMA NUMBER RPAREN { $$=mk_action(	SEND_TCP_T,
756
+																IP_ST,
757
+																NUMBER_ST,
758
+																(void*)$3,
759
+																(void*)$5);
760
+											   }
761
+		| SEND_TCP error { $$=0; yyerror("missing '(' or ')' ?"); }
762
+		| SEND_TCP LPAREN error RPAREN { $$=0; yyerror("bad send_tcp"
763
+													"argument"); }
723 764
 		| DROP LPAREN RPAREN	{$$=mk_action(DROP_T,0, 0, 0, 0); }
724 765
 		| DROP					{$$=mk_action(DROP_T,0, 0, 0, 0); }
725 766
 		| LOG_TOK LPAREN STRING RPAREN	{$$=mk_action(	LOG_T, NUMBER_ST, 
... ...
@@ -50,7 +50,7 @@
50 50
 #define DEFAULT_RT 0 /* default routing table */
51 51
 
52 52
 #define MAX_REC_LEV 100 /* maximum number of recursive calls */
53
-#define ROUTE_MAX_REC_LEV 10 /* maximum number of recursive calls
53
+#define ROUTE_MAX_REC_LEV 100 /* maximum number of recursive calls
54 54
 							   for route()*/
55 55
 
56 56
 #define MAX_URI_SIZE 1024	/* used when rewriting URIs */
... ...
@@ -458,6 +458,9 @@ int open_fifo_server()
458 458
 {
459 459
 	char *t;
460 460
 	struct stat filestat;
461
+#ifdef USE_TCP
462
+	int sockfd[2];
463
+#endif
461 464
 
462 465
 	if (fifo==NULL) {
463 466
 		DBG("TM: open_uac_fifo: no fifo will be opened\n");
... ...
@@ -502,6 +505,13 @@ int open_fifo_server()
502 505
 		return -1;
503 506
 	}
504 507
 	memcpy(up_since_ctime,t,strlen(t)+1);
508
+#ifdef USE_TCP
509
+	if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sockfd)<0){
510
+			LOG(L_ERR, "ERROR: open_fifo_server: socketpair failed: %s\n",
511
+				strerror(errno));
512
+			return -1;
513
+	}
514
+#endif
505 515
 	process_no++;
506 516
 	fifo_pid=fork();
507 517
 	if (fifo_pid<0) {
... ...
@@ -514,6 +524,10 @@ int open_fifo_server()
514 524
 		/* call per-child module initialization too -- some
515 525
 		   FIFO commands may need it
516 526
 		*/
527
+#ifdef USE_TCP
528
+		close(sockfd[0]);
529
+		unix_tcp_sock=sockfd[1];
530
+#endif
517 531
 		if (init_child(process_no) < 0 ) {
518 532
 			LOG(L_ERR, "ERROR: open_uac_fifo: init_child failed\n");
519 533
 			return -1;
... ...
@@ -539,6 +553,11 @@ int open_fifo_server()
539 553
 	/* dad process */
540 554
 	pt[process_no].pid=fifo_pid;
541 555
 	strncpy(pt[process_no].desc, "fifo server", MAX_PT_DESC );
556
+#ifdef USE_TCP
557
+	close(sockfd[1]);
558
+	pt[process_no].unix_sock=sockfd[0];
559
+	pt[process_no].idx=-1; /* this is not "tcp" process*/
560
+#endif
542 561
 	/* make sure the read fifo will not close */
543 562
 	fifo_write=open(fifo, O_WRONLY, 0);
544 563
 	if (fifo_write<0) {
... ...
@@ -66,6 +66,10 @@ extern struct socket_info* sendipv4; /* ipv4 socket to use when msg.
66 66
 										comes from ipv6*/
67 67
 extern struct socket_info* sendipv6; /* same as above for ipv6 */
68 68
 
69
+#ifdef USE_TCP
70
+extern int unix_tcp_sock; /* socket used for communication with tcp main*/
71
+#endif
72
+
69 73
 extern unsigned int maxbuffer;
70 74
 extern int children_no;
71 75
 #ifdef USE_TCP
... ...
@@ -157,6 +157,7 @@ inline static int matchnet(struct ip_addr* ip, struct net* net)
157 157
 
158 158
 
159 159
 
160
+
160 161
 /* inits an ip_addr pointer from a sockaddr structure*/
161 162
 static inline void sockaddr2ip_addr(struct ip_addr* ip, struct sockaddr* sa)
162 163
 {
... ...
@@ -181,6 +182,50 @@ static inline void sockaddr2ip_addr(struct ip_addr* ip, struct sockaddr* sa)
181 182
 
182 183
 
183 184
 
185
+/* compare 2 ip_addrs (both args are pointers)*/
186
+#define ip_addr_cmp(ip1, ip2) \
187
+	(((ip1)->af==(ip2)->af)&& \
188
+	 	(memcmp((ip1)->u.addr, (ip2)->u.addr, (ip1)->len)==0))
189
+
190
+
191
+
192
+/* compare 2 sockaddr_unions */
193
+static inline int su_cmp(union sockaddr_union* s1, union sockaddr_union* s2)
194
+{
195
+	if (s1->s.sa_family!=s2->s.sa_family) return 0;
196
+	switch(s1->s.sa_family){
197
+		case AF_INET:
198
+			return (s1->sin.sin_port==s2->sin.sin_port)&&
199
+					(memcmp(&s1->sin.sin_addr, &s2->sin.sin_addr, 4)==0);
200
+		case AF_INET6:
201
+			return (s1->sin6.sin6_port==s2->sin6.sin6_port)&&
202
+					(memcmp(&s1->sin6.sin6_addr, &s2->sin6.sin6_addr, 16)==0);
203
+		default:
204
+			LOG(L_CRIT,"su_cmp: BUG: unknown address family %d\n",
205
+						s1->s.sa_family);
206
+			return 0;
207
+	}
208
+}
209
+
210
+
211
+
212
+/* gets the port number */
213
+static inline short su_getport(union sockaddr_union* su)
214
+{
215
+	switch(su->s.sa_family){
216
+		case AF_INET:
217
+			return su->sin.sin_port;
218
+		case AF_INET6:
219
+			return su->sin6.sin6_port;
220
+		default:
221
+			LOG(L_CRIT,"su_get_port: BUG: unknown address family %d\n",
222
+						su->s.sa_family);
223
+			return 0;
224
+	}
225
+}
226
+
227
+
228
+
184 229
 /* inits an ip_addr pointer from a sockaddr_union ip address */
185 230
 static inline void su2ip_addr(struct ip_addr* ip, union sockaddr_union* su)
186 231
 {
... ...
@@ -528,6 +528,9 @@ int main_loop()
528 528
 {
529 529
 	int r, i;
530 530
 	pid_t pid;
531
+#ifdef USE_TCP
532
+	int sockfd[2];
533
+#endif
531 534
 #ifdef WITH_SNMP_MOD
532 535
 	int (*snmp_start)();
533 536
 
... ...
@@ -632,31 +635,25 @@ int main_loop()
632 635
 			/* all procs should have access to all the sockets (for sending)
633 636
 			 * so we open all first*/
634 637
 		}
635
-#ifdef USE_TCP
636
-			/* start tcp receivers */
637
-		if (tcp_init_children()<0) goto error;
638
-			/* start tcp master proc */
639
-		process_no++;
640
-		if ((pid=fork())<0){
641
-			LOG(L_CRIT, "main_loop: cannot fork tcp main process\n");
642
-			goto error;
643
-		}else if (pid==0){
644
-			/* child */
645
-			/* is_main=0; */
646
-			tcp_main_loop();
647
-		}else{
648
-			pt[process_no].pid=pid;
649
-			strncpy(pt[process_no].desc, "tcp main process", MAX_PT_DESC );
650
-		}
651
-#endif
652 638
 		for(r=0; r<sock_no;r++){
653 639
 			for(i=0;i<children_no;i++){
654 640
 				process_no++;
641
+#ifdef USE_TCP
642
+		 		if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sockfd)<0){
643
+					LOG(L_ERR, "ERROR: main_loop: socketpair failed: %s\n",
644
+						strerror(errno));
645
+					goto error;
646
+				}
647
+#endif
655 648
 				if ((pid=fork())<0){
656 649
 					LOG(L_CRIT,  "main_loop: Cannot fork\n");
657 650
 					goto error;
658 651
 				}else if (pid==0){
659 652
 					     /* child */
653
+#ifdef USE_TCP
654
+					close(sockfd[0]);
655
+					unix_tcp_sock=sockfd[1];
656
+#endif
660 657
 					bind_address=&sock_info[r]; /* shortcut */
661 658
 					bind_idx=r;
662 659
 					if (init_child(i) < 0) {
... ...
@@ -672,6 +669,11 @@ int main_loop()
672 669
 						snprintf(pt[process_no].desc, MAX_PT_DESC,
673 670
 							"receiver child=%d sock=%d @ %s:%s", i, r, 	
674 671
 							sock_info[r].name.s, sock_info[r].port_no_str.s );
672
+#ifdef USE_TCP
673
+						close(sockfd[1]);
674
+						pt[process_no].unix_sock=sockfd[0];
675
+						pt[process_no].idx=-1; /* this is not "tcp" process*/
676
+#endif
675 677
 				}
676 678
 			}
677 679
 			/*parent*/
... ...
@@ -682,6 +684,7 @@ int main_loop()
682 684
 	/*this is the main process*/
683 685
 	bind_address=&sock_info[0]; /* main proc -> it shoudln't send anything, */
684 686
 	bind_idx=0;					/* if it does it will use the first address */
687
+	
685 688
 	/* if configured to do so, start a server for accepting FIFO commands */
686 689
 	if (open_fifo_server()<0) {
687 690
 		LOG(L_ERR, "opening fifo server failed\n");
... ...
@@ -693,6 +696,13 @@ int main_loop()
693 696
 	if (timer_list)
694 697
 #endif
695 698
 	{
699
+#ifdef USE_TCP
700
+ 		if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sockfd)<0){
701
+			LOG(L_ERR, "ERROR: main_loop: socketpair failed: %s\n",
702
+				strerror(errno));
703
+			goto error;
704
+		}
705
+#endif
696 706
 		/* fork again for the attendant process*/
697 707
 		process_no++;
698 708
 		if ((pid=fork())<0){
... ...
@@ -701,6 +711,10 @@ int main_loop()
701 711
 		}else if (pid==0){
702 712
 			/* child */
703 713
 			/* is_main=0; */
714
+#ifdef USE_TCP
715
+			close(sockfd[0]);
716
+			unix_tcp_sock=sockfd[1];
717
+#endif
704 718
 			for(;;){
705 719
 				/* debug:  instead of doing something usefull */
706 720
 				/* (placeholder for timers, etc.) */
... ...
@@ -711,12 +725,41 @@ int main_loop()
711 725
 		}else{
712 726
 			pt[process_no].pid=pid;
713 727
 			strncpy(pt[process_no].desc, "timer", MAX_PT_DESC );
728
+#ifdef USE_TCP
729
+						close(sockfd[1]);
730
+						pt[process_no].unix_sock=sockfd[0];
731
+						pt[process_no].idx=-1; /* this is not a "tcp" process*/
732
+#endif
714 733
 		}
715 734
 	}
716
-
735
+#ifdef USE_TCP
736
+			/* start tcp receivers */
737
+		if (tcp_init_children()<0) goto error;
738
+			/* start tcp master proc */
739
+		process_no++;
740
+		if ((pid=fork())<0){
741
+			LOG(L_CRIT, "main_loop: cannot fork tcp main process\n");
742
+			goto error;
743
+		}else if (pid==0){
744
+			/* child */
745
+			/* is_main=0; */
746
+			tcp_main_loop();
747
+		}else{
748
+			pt[process_no].pid=pid;
749
+			strncpy(pt[process_no].desc, "tcp main process", MAX_PT_DESC );
750
+			pt[process_no].unix_sock=-1;
751
+			pt[process_no].idx=-1; /* this is not a "tcp" process*/
752
+			unix_tcp_sock=-1;
753
+		}
754
+#endif
717 755
 	/* main */
718 756
 	pt[0].pid=getpid();
719 757
 	strncpy(pt[0].desc, "attendant", MAX_PT_DESC );
758
+#ifdef USE_TCP
759
+	pt[process_no].unix_sock=-1;
760
+	pt[process_no].idx=-1; /* this is not a "tcp" process*/
761
+	unix_tcp_sock=-1;
762
+#endif
720 763
 	/*DEBUG- remove it*/
721 764
 #ifdef DEBUG
722 765
 	printf("\n% 3d processes, % 3d children * % 3d listening addresses + main"
... ...
@@ -1177,7 +1220,14 @@ try_again:
1177 1220
 		LOG(L_CRIT, "could not initialize timer, exiting...\n");
1178 1221
 		goto error;
1179 1222
 	}
1180
-
1223
+#ifdef USE_TCP
1224
+	/*init tcp*/
1225
+	if (init_tcp()<0){
1226
+		LOG(L_CRIT, "could not initialize tcp, exiting...\n");
1227
+		goto error;
1228
+	}
1229
+#endif
1230
+	
1181 1231
 	/* register a diagnostic FIFO command */
1182 1232
 	if (register_core_fifo()<0) {
1183 1233
 		LOG(L_CRIT, "unable to register core FIFO commands\n");
... ...
@@ -43,6 +43,10 @@
43 43
 
44 44
 struct process_table {
45 45
 	int pid;
46
+#ifdef USE_TCP
47
+	int unix_sock; /* unix socket on which tcp main listens */
48
+	int idx; /* tcp child index, -1 for other processes */
49
+#endif
46 50
 	char desc[MAX_PT_DESC];
47 51
 };
48 52
 
... ...
@@ -145,7 +145,9 @@ static int fix_actions(struct action* a)
145 145
 	for(t=a; t!=0; t=t->next){
146 146
 		switch(t->type){
147 147
 			case FORWARD_T:
148
+			case FORWARD_TCP_T:
148 149
 			case SEND_T:
150
+			case SEND_TCP_T:
149 151
 					switch(t->p1_type){
150 152
 						case IP_ST: 
151 153
 							tmp=strdup(ip_addr2a(
... ...
@@ -232,9 +232,15 @@ void print_action(struct action* a)
232 232
 			case FORWARD_T:
233 233
 					DBG("forward(");
234 234
 					break;
235
+			case FORWARD_TCP_T:
236
+					DBG("forward_tcp(");
237
+					break;
235 238
 			case SEND_T:
236 239
 					DBG("send(");
237 240
 					break;
241
+			case SEND_TCP_T:
242
+					DBG("send_tcp(");
243
+					break;
238 244
 			case DROP_T:
239 245
 					DBG("drop(");
240 246
 					break;
... ...
@@ -54,7 +54,9 @@ enum { FORWARD_T=1, SEND_T, DROP_T, LOG_T, ERROR_T, ROUTE_T, EXEC_T,
54 54
 		SETFLAG_T, RESETFLAG_T, ISFLAGSET_T ,
55 55
 		LEN_GT_T, PREFIX_T, STRIP_T,
56 56
 		APPEND_BRANCH_T,
57
-		REVERT_URI_T };
57
+		REVERT_URI_T,
58
+		FORWARD_TCP_T,
59
+		SEND_TCP_T};
58 60
 enum { NOSUBTYPE=0, STRING_ST, NET_ST, NUMBER_ST, IP_ST, RE_ST, PROXY_ST,
59 61
 		EXPR_ST, ACTIONS_ST, CMDF_ST, MODFIXUP_ST, URIHOST_ST, URIPORT_ST,
60 62
 		MYSELF_ST };
... ...
@@ -50,6 +50,10 @@ enum {	H_SKIP, H_LF, H_LFCR,  H_BODY, H_STARTWS,
50 50
 		H_CONT_LEN_BODY, H_CONT_LEN_BODY_PARSE 
51 51
 	};
52 52
 
53
+/* fd communication commands */
54
+enum { CONN_DESTROY=-3, CONN_ERROR=-2, CONN_EOF=-1, CONN_RELEASE, CONN_GET_FD,
55
+	   CONN_NEW };
56
+
53 57
 struct tcp_req{
54 58
 	struct tcp_req* next;
55 59
 	/* sockaddr ? */
... ...
@@ -71,7 +75,10 @@ struct tcp_req{
71 75
 struct tcp_connection{
72 76
 	int s; /*socket, used by "tcp main" */
73 77
 	int fd; /* used only by "children" */
78
+	int id; /* id (unique!) used to retrieve a specific connection when
79
+	           reply-ing*/
74 80
 	struct ip_addr ip; /* peer ip */
81
+	int port; /* peer port */
75 82
 	int sock_idx; /* receiving socket index in the tcp_info array */
76 83
 	union sockaddr_union su;
77 84
 	struct tcp_req req; /* request data */
... ...
@@ -116,7 +123,10 @@ struct tcp_connection{
116 123
 	}while(0)
117 124
 
118 125
 
119
-
126
+#define TCPCONN_LOCK LOG(L_CRIT, "LOCK not implemented yet: %s : %d: %s\n", \
127
+							__FILE__, __LINE__, __FUNCTION__);
128
+#define TCPCONN_UNLOCK LOG(L_CRIT, "UNLOCK not implemented yet: %s: %d: %s\n",\
129
+							__FILE__, __LINE__, __FUNCTION__);
120 130
 
121 131
 
122 132
 
... ...
@@ -54,6 +54,7 @@
54 54
 #include "mem/mem.h"
55 55
 #include "mem/shm_mem.h"
56 56
 #include "timer.h"
57
+#include "tcp_server.h"
57 58
 
58 59
 
59 60
 
... ...
@@ -64,23 +65,23 @@
64 65
 
65 66
 struct tcp_child{
66 67
 	pid_t pid;
67
-	int s; /* unix socket for comm*/
68
+	int unix_sock; /* unix sock fd, copied from pt*/
68 69
 	int busy;
69 70
 	int n_reqs; /* number of requests serviced so far */
70 71
 };
71 72
 
72 73
 
73
-enum { CONN_OK, CONN_ERROR };
74 74
 
75
-
76
-
77
-
78
-struct tcp_connection* conn_list=0;
75
+struct tcp_connection** conn_list=0;
79 76
 struct tcp_child tcp_children[MAX_TCP_CHILDREN];
77
+static int connection_id=1; /*  unique for each connection, used for 
78
+								quickly finding the corresponding connection
79
+								for a reply */
80
+int unix_tcp_sock;
80 81
 
81 82
 
82 83
 
83
-struct tcp_connection*  tcpconn_add(int sock, union sockaddr_union* su, int i)
84
+struct tcp_connection* tcpconn_new(int sock, union sockaddr_union* su, int i)
84 85
 {
85 86
 	struct tcp_connection *c;
86 87
 	
... ...
@@ -91,15 +92,15 @@ struct tcp_connection*  tcpconn_add(int sock, union sockaddr_union* su, int i)
91 92
 		goto error;
92 93
 	}
93 94
 	c->s=sock;
95
+	c->fd=sock;
94 96
 	c->su=*su;
95 97
 	c->sock_idx=i;
96 98
 	c->refcnt=0;
97 99
 	su2ip_addr(&c->ip, su);
100
+	c->port=su_getport(su);
98 101
 	init_tcp_req(&c->req);
99 102
 	c->timeout=get_ticks()+TCP_CON_TIMEOUT;
100
-
101
-	/* add it at the begining of the list*/
102
-	tcpconn_listadd(conn_list, c, next, prev);
103
+	c->id=connection_id++;
103 104
 	return c;
104 105
 	
105 106
 error:
... ...
@@ -108,27 +109,158 @@ error:
108 109
 
109 110
 
110 111
 
112
+struct tcp_connection* tcpconn_connect(union sockaddr_union* server)
113
+{
114
+	int s;
115
+
116
+	s=socket(AF2PF(server->s.sa_family), SOCK_STREAM, 0);
117
+	if (s<0){
118
+		LOG(L_ERR, "ERROR: tcpconn_connect: socket: (%d) %s\n",
119
+				errno, strerror(errno));
120
+		goto error;
121
+	}
122
+	if (connect(s, &server->s, sockaddru_len(*server))<0){
123
+		LOG(L_ERR, "ERROR: tcpconn_connect: connect: (%d) %s\n",
124
+				errno, strerror(errno));
125
+		goto error;
126
+	}
127
+	return tcpconn_new(s, server, 0); /*FIXME: set sock idx! */
128
+error:
129
+	return 0;
130
+}
131
+
132
+
133
+
134
+struct tcp_connection*  tcpconn_add(struct tcp_connection *c)
135
+{
136
+	TCPCONN_LOCK;
137
+	/* add it at the begining of the list*/
138
+	if (c) tcpconn_listadd(*conn_list, c, next, prev);
139
+	TCPCONN_UNLOCK;
140
+	return c;
141
+}
142
+
143
+
144
+
111 145
 void tcpconn_rm(struct tcp_connection* c)
112 146
 {
113
-	tcpconn_listrm(conn_list, c, next, prev);
147
+	TCPCONN_LOCK;
148
+	tcpconn_listrm(*conn_list, c, next, prev);
149
+	TCPCONN_UNLOCK;
114 150
 	shm_free(c);
115 151
 }
116 152
 
117 153
 
154
+/* finds a connection, if id=0 uses the ip addr & port */
155
+struct tcp_connection* tcpconn_find(int id, struct ip_addr* ip, int port)
156
+{
157
+
158
+	struct tcp_connection *c;
159
+	
160
+	DBG("tcpconn_find: %d ",id ); print_ip(ip); DBG(" %d\n", port);
161
+	for (c=*conn_list; c; c=c->next){
162
+		DBG("c=%p, c->id=%d, ip=",c, c->id);
163
+		print_ip(&c->ip);
164
+		DBG(" port=%d\n", c->port);
165
+		if (id){
166
+			if (id==c->id) return c;
167
+		}else if ((port==c->port)&&(ip_addr_cmp(ip, &c->ip))) return c;
168
+	}
169
+	return 0;
170
+}
171
+
172
+
173
+
174
+struct tcp_connection* tcpconn_get(int id, struct ip_addr* ip, int port)
175
+{
176
+	struct tcp_connection* c;
177
+	TCPCONN_LOCK;
178
+	c=tcpconn_find(id, ip, port);
179
+	if (c) c->refcnt++;
180
+	TCPCONN_UNLOCK;
181
+	return c;
182
+}
183
+
184
+
185
+
186
+void tcpconn_put(struct tcp_connection* c)
187
+{
188
+	c->refcnt--; /* FIXME: atomic_dec */
189
+}
190
+
191
+
192
+
193
+/* finds a tcpconn & sends on it */
194
+int tcp_send(char* buf, unsigned len, union sockaddr_union* to, int id)
195
+{
196
+	struct tcp_connection *c;
197
+	struct ip_addr ip;
198
+	int port;
199
+	long response[2];
200
+	int n;
201
+	
202
+	su2ip_addr(&ip, to);
203
+	port=su_getport(to);
204
+	
205
+	c=tcpconn_get(id, &ip, port); /* lock ;inc refcnt; unlock */
206
+	if (id){
207
+		if (c==0) {
208
+		LOG(L_ERR, "ERROR: tcp_send: id %d not found, dropping\n",
209
+					id);
210
+			return -1;
211
+		}
212
+	}else{
213
+		if (c==0){
214
+			DBG("tcp_send: no open tcp connection found, opening new one\n");
215
+			/* create tcp connection */
216
+			if ((c=tcpconn_connect(to))==0){
217
+				LOG(L_ERR, "ERROR: tcp_send: connect failed\n");
218
+				return 0;
219
+			}
220
+			c->refcnt++;
221
+			
222
+			/* send the new tcpconn to "tcp main" */
223
+			response[0]=(long)c;
224
+			response[1]=CONN_NEW;
225
+			n=write(unix_tcp_sock, response, sizeof(response));
226
+			n=send_fd(unix_tcp_sock, &c, sizeof(c), c->s);
227
+		}else{
228
+			DBG("tcp_send: tcp connection found, acquiring fd\n");
229
+			/* get the fd */
230
+			response[0]=(long)c;
231
+			response[1]=CONN_GET_FD;
232
+			n=write(unix_tcp_sock, response, sizeof(response));
233
+			n=receive_fd(unix_tcp_sock, &c, sizeof(c), &c->fd);
234
+		}
235
+	
236
+	}
237
+	DBG("tcp_send: sending...\n");
238
+	n=write(c->fd, buf, len);
239
+	close(c->fd);
240
+	tcpconn_put(c); /* release c (lock; dec refcnt; unlock) */
241
+	return n;
242
+}
243
+
244
+
245
+
118 246
 /* very ineficient for now, use hashtable some day - FIXME*/
119
-void tcpconn_timeout()
247
+void tcpconn_timeout(fd_set* set)
120 248
 {
121 249
 	struct tcp_connection *c, *next;
122 250
 	int ticks;;
123 251
 	
124 252
 	
125 253
 	ticks=get_ticks();
126
-	c=conn_list;
254
+	c=*conn_list;
127 255
 	while(c){
128 256
 		next=c->next;
129 257
 		if ((c->refcnt==0) && (ticks>c->timeout)) {
130 258
 			DBG("tcpconn_timeout: timeout for %p (%d > %d)\n",
131 259
 					c, ticks, c->timeout);
260
+			if (c->s>0) {
261
+				FD_CLR(c->s, set);
262
+				close(c->s);
263
+			}
132 264
 			tcpconn_rm(c);
133 265
 		}
134 266
 		c=next;
... ...
@@ -209,7 +341,8 @@ static int send2child(struct tcp_connection* tcpconn)
209 341
 				min_busy);
210 342
 	}
211 343
 	DBG("send2child: to child %d, %ld\n", idx, (long)tcpconn);
212
-	send_fd(tcp_children[idx].s, &tcpconn, sizeof(tcpconn), tcpconn->s);
344
+	send_fd(tcp_children[idx].unix_sock, &tcpconn, sizeof(tcpconn),
345
+			tcpconn->s);
213 346
 	
214 347
 	return 0; /* just to fix a warning*/
215 348
 }
... ...
@@ -226,7 +359,7 @@ void tcp_main_loop()
226 359
 	union sockaddr_union su;
227 360
 	struct tcp_connection* tcpconn;
228 361
 	long response[2];
229
-	int state;
362
+	int cmd;
230 363
 	int bytes;
231 364
 	socklen_t su_len;
232 365
 	struct timeval timeout;
... ...
@@ -242,10 +375,10 @@ void tcp_main_loop()
242 375
 		}
243 376
 	}
244 377
 	/* set all the unix sockets used for child comm */
245
-	for (r=0; r<tcp_children_no; r++){
246
-		if (tcp_children[r].s>=0){
247
-			FD_SET(tcp_children[r].s, &master_set);
248
-			if (tcp_children[r].s>maxfd) maxfd=tcp_children[r].s;
378
+	for (r=0; r<process_no; r++){
379
+		if (pt[r].unix_sock>=0){
380
+			FD_SET(pt[r].unix_sock, &master_set);
381
+			if (pt[r].unix_sock>maxfd) maxfd=pt[r].unix_sock;
249 382
 		}
250 383
 	}
251 384
 	
... ...
@@ -262,6 +395,7 @@ void tcp_main_loop()
262 395
 			/* errors */
263 396
 			LOG(L_ERR, "ERROR: tcp_main_loop: select:(%d) %s\n", errno,
264 397
 					strerror(errno));
398
+			n=0;
265 399
 		}
266 400
 		
267 401
 		for (r=0; r<sock_no && n; r++){
... ...
@@ -278,21 +412,25 @@ void tcp_main_loop()
278 412
 				}
279 413
 				
280 414
 				/* add socket to list */
281
-				tcpconn=tcpconn_add(new_sock, &su, r);
282
-				DBG("tcp_main_loop: new connection: %p %d\n",
415
+				tcpconn=tcpconn_new(new_sock, &su, r);
416
+				if (tcpconn){
417
+					tcpconn_add(tcpconn);
418
+					DBG("tcp_main_loop: new connection: %p %d\n",
283 419
 						tcpconn, tcpconn->s);
284
-				/* pass it to a child */
285
-				if(send2child(tcpconn)<0){
286
-					LOG(L_ERR,"ERROR: tcp_main_loop: no children available\n");
287
-					close(tcpconn->s);
288
-					tcpconn_rm(tcpconn);
420
+					/* pass it to a child */
421
+					if(send2child(tcpconn)<0){
422
+						LOG(L_ERR,"ERROR: tcp_main_loop: no children "
423
+								"available\n");
424
+						close(tcpconn->s);
425
+						tcpconn_rm(tcpconn);
426
+					}
289 427
 				}
290 428
 			}
291 429
 		}
292 430
 		
293 431
 		/* check all the read fds (from the tcpconn list) */
294 432
 		
295
-		for(tcpconn=conn_list; tcpconn && n; tcpconn=tcpconn->next){
433
+		for(tcpconn=*conn_list; tcpconn && n; tcpconn=tcpconn->next){
296 434
 			if ((tcpconn->refcnt==0)&&(FD_ISSET(tcpconn->s, &sel_set))){
297 435
 				/* new data available */
298 436
 				n--;
... ...
@@ -309,17 +447,18 @@ void tcp_main_loop()
309 447
 		}
310 448
 		
311 449
 		/* check unix sockets & listen | destroy connections */
312
-		for (r=0; r<tcp_children_no && n; r++){
313
-			if (FD_ISSET(tcp_children[r].s, &sel_set)){
450
+		/* start from 1, the "main" process does not transmit anything*/
451
+		for (r=1; r<process_no && n; r++){
452
+			if ( (pt[r].unix_sock>=0) && FD_ISSET(pt[r].unix_sock, &sel_set)){
314 453
 				n--;
315 454
 				/* errno==EINTR !!! TODO*/
316 455
 read_again:
317
-				bytes=read(tcp_children[r].s, response, sizeof(response));
456
+				bytes=read(pt[r].unix_sock, response, sizeof(response));
318 457
 				if (bytes==0){
319 458
 					/* EOF -> bad, child has died */
320 459
 					LOG(L_CRIT, "BUG: tcp_main_loop: dead child %d\n", r);
321
-					/* terminating everybody */
322
-					FD_CLR(tcp_children[r].s, &master_set);
460
+					/* don't listen on it any more */
461
+					FD_CLR(pt[r].unix_sock, &master_set);
323 462
 					/*exit(-1)*/;
324 463
 				}else if (bytes<0){
325 464
 					if (errno==EINTR) goto read_again;
... ...
@@ -330,45 +469,108 @@ read_again:
330 469
 					}
331 470
 				}
332 471
 					
333
-				DBG("tcp__main_loop: read response= %lx, %ld\n",
334
-						response[0], response[1]);
335
-				tcp_children[r].busy=0;
336
-				tcpconn=(struct tcp_connection*)response[0];
337
-				state=response[1];
338
-				if (tcpconn){
339
-					tcpconn->refcnt--;
340
-					if (state>=0){
341
-						/* listen on this too */
342
-						if (tcpconn->refcnt==0){
472
+				DBG("tcp_main_loop: read response= %lx, %ld from %d (%d)\n",
473
+						response[0], response[1], r, pt[r].pid);
474
+				cmd=response[1];
475
+				switch(cmd){
476
+					case CONN_RELEASE:
477
+						if (pt[r].idx>=0){
478
+							tcp_children[pt[r].idx].busy--;
479
+						}else{
480
+							LOG(L_CRIT, "BUG: tcp_main_loop: CONN_RELEASE\n");
481
+						}
482
+						tcpconn=(struct tcp_connection*)response[0];
483
+						if (tcpconn){
484
+							tcpconn->refcnt--;
485
+							DBG("tcp_main_loop: %p refcnt= %d\n", 
486
+									tcpconn, tcpconn->refcnt);
487
+								FD_SET(tcpconn->s, &master_set);
488
+								if (maxfd<tcpconn->s) maxfd=tcpconn->s;
489
+								/* update the timeout*/
490
+								tcpconn->timeout=get_ticks()+TCP_CON_TIMEOUT;
491
+						}
492
+						break;
493
+					case CONN_ERROR:
494
+					case CONN_DESTROY:
495
+					case CONN_EOF:
496
+						if (pt[r].idx>=0){
497
+							tcp_children[pt[r].idx].busy--;
498
+						}else{
499
+							LOG(L_CRIT, "BUG: tcp_main_loop: CONN_RELEASE\n");
500
+						}
501
+						tcpconn=(struct tcp_connection*)response[0];
502
+						if (tcpconn){
503
+							tcpconn->refcnt--;
504
+							if (tcpconn->refcnt==0){
505
+								DBG("tcp_main_loop: destroying connection\n");
506
+								close(tcpconn->s);
507
+								tcpconn_rm(tcpconn);
508
+							}else{
509
+								DBG("tcp_main_loop: delaying ...\n");
510
+							}
511
+						}
512
+						break;
513
+					case CONN_GET_FD:
514
+						/* send the requested FD  */
515
+						tcpconn=(struct tcp_connection*)response[0];
516
+						/* WARNING: take care of setting refcnt properly to
517
+						 * avoid race condition */
518
+						if (tcpconn){
519
+							send_fd(pt[r].unix_sock, &tcpconn,
520
+									sizeof(tcpconn), tcpconn->s);
521
+						}else{
522
+							LOG(L_CRIT, "BUG: tcp_main_loop: null pointer\n");
523
+						}
524
+						break;
525
+					case CONN_NEW:
526
+						/* update the fd in the requested tcpconn*/
527
+						tcpconn=(struct tcp_connection*)response[0];
528
+						/* WARNING: take care of setting refcnt properly to
529
+						 * avoid race condition */
530
+						if (tcpconn){
531
+							receive_fd(pt[r].unix_sock, &tcpconn,
532
+										sizeof(tcpconn), &tcpconn->s);
533
+							/* add tcpconn to the list*/
534
+							tcpconn_add(tcpconn);
343 535
 							FD_SET(tcpconn->s, &master_set);
344 536
 							if (maxfd<tcpconn->s) maxfd=tcpconn->s;
345 537
 							/* update the timeout*/
346 538
 							tcpconn->timeout=get_ticks()+TCP_CON_TIMEOUT;
347
-						}
348
-					}else{
349
-						/*error, we should destroy it */
350
-						if (tcpconn->refcnt==0){
351
-							DBG("tcp_main_loop: destroying connection\n");
352
-							close(tcpconn->s);
353
-							tcpconn_rm(tcpconn);
354 539
 						}else{
355
-							DBG("tcp_main_loop: delaying ...\n");
540
+							LOG(L_CRIT, "BUG: tcp_main_loop: null pointer\n");
356 541
 						}
357
-					}
358
-				}else{
359
-					LOG(L_CRIT, "BUG: tcp_main_loop: null tcp conn pointer\n");
542
+						break;
543
+					default:
544
+							LOG(L_CRIT, "BUG: tcp_main_loop: unknown cmd %d\n",
545
+									cmd);
360 546
 				}
361 547
 			}
362 548
 		}
363 549
 		
364 550
 		/* remove old connections */
365
-		tcpconn_timeout();
551
+		tcpconn_timeout(&master_set);
366 552
 	
367 553
 	}
368 554
 }
369 555
 
370 556
 
371 557
 
558
+int init_tcp()
559
+{
560
+	/* allocate list head*/
561
+	conn_list=shm_malloc(sizeof(struct tcp_connection*));
562
+	if (conn_list==0){
563
+		LOG(L_CRIT, "ERROR: tcp_init: memory allocation failure\n");
564
+		goto error;
565
+	}
566
+	*conn_list=0;
567
+	return 0;
568
+error:
569
+		return -1;
570
+}
571
+
572
+
573
+
372 574
 /* starts the tcp processes */
373 575
 int tcp_init_children()
374 576
 {
... ...
@@ -402,14 +604,17 @@ int tcp_init_children()
402 604
 			/* parent */
403 605
 			close(sockfd[1]);
404 606
 			tcp_children[r].pid=pid;
405
-			tcp_children[r].s=sockfd[0];
406 607
 			tcp_children[r].busy=0;
407 608
 			tcp_children[r].n_reqs=0;
609
+			tcp_children[r].unix_sock=sockfd[0];
408 610
 			pt[process_no].pid=pid;
611
+			pt[process_no].unix_sock=sockfd[0];
612
+			pt[process_no].idx=r;
409 613
 			strncpy(pt[process_no].desc, "tcp receiver", MAX_PT_DESC);
410 614
 		}else{
411 615
 			/* child */
412 616
 			close(sockfd[0]);
617
+			unix_tcp_sock=sockfd[1];
413 618
 			tcp_receive_loop(sockfd[1]);
414 619
 		}
415 620
 	}
... ...
@@ -315,12 +315,12 @@ skip:
315 315
 int tcp_read_req(struct tcp_connection* con)
316 316
 {
317 317
 	int bytes;
318
-	int state;
318
+	int resp;
319 319
 	long size;
320 320
 	struct tcp_req* req;
321 321
 	int s;
322 322
 		
323
-		state=0;
323
+		resp=CONN_RELEASE;
324 324
 		s=con->fd;
325 325
 		req=&con->req;
326 326
 		if(req->complete==0 && req->error==TCP_REQ_OK){
... ...
@@ -330,12 +330,12 @@ int tcp_read_req(struct tcp_connection* con)
330 330
 					bytes, req->parsed-req->buf, req->state, req->error );
331 331
 			if (bytes==-1){
332 332
 				LOG(L_ERR, "ERROR: tcp_read_req: error reading \n");
333
-				state=-1;
333
+				resp=CONN_ERROR;
334 334
 				goto end_req;
335 335
 			}
336 336
 			if (bytes==0){
337 337
 				DBG( "tcp_read_req: EOF\n");
338
-				state=-1;
338
+				resp=CONN_EOF;
339 339
 				goto end_req;
340 340
 			}
341 341
 		
... ...
@@ -343,7 +343,7 @@ int tcp_read_req(struct tcp_connection* con)
343 343
 		if (req->error!=TCP_REQ_OK){
344 344
 			LOG(L_ERR,"ERROR: tcp_read_req: bad request, state=%d, error=%d\n",
345 345
 					req->state, req->error);
346
-			state=-1;
346
+			resp=CONN_ERROR;
347 347
 			goto end_req;
348 348
 		}
349 349
 		if (req->complete){
... ...
@@ -357,16 +357,19 @@ int tcp_read_req(struct tcp_connection* con)
357 357
 				req->error=TCP_REQ_BAD_LEN;
358 358
 				LOG(L_ERR, "ERROR: tcp_read_req: content length not present or"
359 359
 						" unparsable\n");
360
-				state=-1;
360
+				resp=CONN_ERROR;
361 361
 				goto end_req;
362 362
 			}
363 363
 			/* if we are here everything is nice and ok*/
364
-			state=0;
364
+			resp=CONN_RELEASE;
365 365
 			/* just for debugging use sendipv4 as receiving socket */
366 366
 			DBG("calling receive_msg(%p, %d, )\n",
367 367
 					req->buf, (int)(req->parsed-req->buf));
368 368
 			bind_address=sendipv4; /*&tcp_info[con->sock_idx];*/
369
-			receive_msg(req->buf, req->parsed-req->buf, &con->su);
369
+			if (receive_msg(req->buf, req->parsed-req->buf, &con->su)<0){
370
+				resp=CONN_ERROR;
371
+				goto end_req;
372
+			}
370 373
 			
371 374
 			/* prepare for next request */
372 375
 			size=req->pos-req->body;
... ...
@@ -385,7 +388,7 @@ int tcp_read_req(struct tcp_connection* con)
385 388
 		
386 389
 		
387 390
 	end_req:
388
-		return state;
391
+		return resp;
389 392
 }
390 393
 
391 394
 
... ...
@@ -413,7 +416,7 @@ void tcp_receive_loop(int unix_sock)
413 416
 	int n;
414 417
 	int nfds;
415 418
 	int s;
416
-	long state;
419
+	long resp;
417 420
 	fd_set master_set;
418 421
 	fd_set sel_set;
419 422
 	int maxfd;
... ...
@@ -463,13 +466,13 @@ void tcp_receive_loop(int unix_sock)
463 466
 				if (s==-1) {
464 467
 					LOG(L_ERR, "ERROR: tcp_receive_loop: read_fd:"
465 468
 									"no fd read\n");
466
-					state=-1;
467
-					release_tcpconn(con, state, unix_sock);
469
+					resp=CONN_ERROR;
470
+					release_tcpconn(con, resp, unix_sock);
468 471
 				}
469 472
 				if (con==0){
470 473
 					LOG(L_ERR, "ERROR: tcp_receive_loop: null pointer\n");
471
-					state=-1;
472
-					release_tcpconn(con, state, unix_sock);
474
+					resp=CONN_ERROR;
475
+					release_tcpconn(con, resp, unix_sock);
473 476
 				}
474 477
 				con->timeout=get_ticks()+TCP_CHILD_TIMEOUT;
475 478
 				FD_SET(s, &master_set);
... ...
@@ -481,11 +484,11 @@ void tcp_receive_loop(int unix_sock)
481 484
 				c_next=con->c_next; /* safe for removing*/
482 485
 				if (nfds && FD_ISSET(con->fd, &sel_set)){
483 486
 					nfds--;
484
-					state=tcp_read_req(con);
485
-					if (state==-1){
487
+					resp=tcp_read_req(con);
488
+					if (resp<0){
486 489
 						FD_CLR(con->fd, &master_set);
487 490
 						tcpconn_listrm(list, con, c_next, c_prev);
488
-						release_tcpconn(con, state, unix_sock);
491
+						release_tcpconn(con, resp, unix_sock);
489 492
 					}else{
490 493
 						/* update timeout */
491 494
 						con->timeout=ticks+TCP_CHILD_TIMEOUT;
... ...
@@ -496,10 +499,10 @@ void tcp_receive_loop(int unix_sock)
496 499
 						/* expired, return to "tcp main" */
497 500
 						DBG("tcp_receive_loop: %p expired (%d, %d)\n",
498 501
 								con, con->timeout, ticks);
499
-						state=0;
502
+						resp=CONN_RELEASE;
500 503
 						FD_CLR(con->fd, &master_set);
501 504
 						tcpconn_listrm(list, con, c_next, c_prev);
502
-						release_tcpconn(con, state, unix_sock);
505
+						release_tcpconn(con, resp, unix_sock);
503 506
 					}
504 507
 				}
505 508
 			}
506 509
new file mode 100644
... ...
@@ -0,0 +1,46 @@
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
+#ifndef tcp_server_h
30
+#define tcp_server_h
31
+
32
+
33
+
34
+
35
+/* "public" functions*/
36
+
37
+struct tcp_connection* tcpconn_get(int id, struct ip_addr* ip, int port);
38
+void tcpconn_put(struct tcp_connection* c);
39
+int tcp_send(char* buf, unsigned len, union sockaddr_union* to, int id);
40
+
41
+
42
+
43
+
44
+
45
+
46
+#endif