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 133
 			}
134 134
 			break;
135 135
 		case SEND_T:
136
+		case SEND_TCP_T:
136 137
 			if ((a->p1_type!= PROXY_ST)|(a->p2_type!=NUMBER_ST)){
137 138
 				LOG(L_CRIT, "BUG: do_action: bad send() types %d, %d\n",
138 139
 						a->p1_type, a->p2_type);
... ...
@@ -161,12 +165,21 @@ int do_action(struct action* a, struct sip_msg* msg)
161 161
 			if (ret==0){
162 162
 				p->tx++;
163 163
 				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;
164
+				if (a->type==SEND_T){
165
+					/*udp*/
166
+					send_sock=get_send_socket(to);
167
+					if (send_sock!=0){
168
+						ret=udp_send(send_sock, msg->orig, msg->len, to);
169
+					}else{
170
+						ret=-1;
171
+					}
169 172
 				}
173
+#ifdef USE_TCP
174
+					else{
175
+					/*tcp*/
176
+					ret=tcp_send(msg->orig, msg->len, to, 0);
177
+				}
178
+#endif
170 179
 			}
171 180
 			free(to);
172 181
 			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 152
 <INITIAL>{EAT_ABLE}	{ count(); }
153 153
 
154 154
 <INITIAL>{FORWARD}	{count(); yylval.strval=yytext; return FORWARD; }
155
+<INITIAL>{FORWARD_TCP}	{count(); yylval.strval=yytext; return FORWARD_TCP; }
155 156
 <INITIAL>{DROP}	{ count(); yylval.strval=yytext; return DROP; }
156 157
 <INITIAL>{SEND}	{ count(); yylval.strval=yytext; return SEND; }
158
+<INITIAL>{SEND_TCP}	{ count(); yylval.strval=yytext; return SEND_TCP; }
157 159
 <INITIAL>{LOG}	{ count(); yylval.strval=yytext; return LOG_TOK; }
158 160
 <INITIAL>{ERROR}	{ count(); yylval.strval=yytext; return ERROR; }
159 161
 <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 720
 		| SEND error { $$=0; yyerror("missing '(' or ')' ?"); }
721 721
 		| SEND LPAREN error RPAREN { $$=0; yyerror("bad send"
722 722
 													"argument"); }
723
+		| SEND_TCP LPAREN host RPAREN	{ $$=mk_action(	SEND_TCP_T,
724
+													STRING_ST,
725
+													NUMBER_ST,
726
+													$3,
727
+													0);
728
+									}
729
+		| SEND_TCP LPAREN STRING RPAREN { $$=mk_action(	SEND_TCP_T,
730
+													STRING_ST,
731
+													NUMBER_ST,
732
+													$3,
733
+													0);
734
+									}
735
+		| SEND_TCP LPAREN ip RPAREN		{ $$=mk_action(	SEND_TCP_T,
736
+													IP_ST,
737
+													NUMBER_ST,
738
+													(void*)$3,
739
+													0);
740
+									}
741
+		| SEND_TCP LPAREN host COMMA NUMBER RPAREN	{ $$=mk_action(	SEND_TCP_T,
742
+																STRING_ST,
743
+																NUMBER_ST,
744
+																$3,
745
+																(void*)$5);
746
+												}
747
+		| SEND_TCP LPAREN STRING COMMA NUMBER RPAREN {$$=mk_action(	SEND_TCP_T,
748
+																STRING_ST,
749
+																NUMBER_ST,
750
+																$3,
751
+																(void*)$5);
752
+												}
753
+		| SEND_TCP LPAREN ip COMMA NUMBER RPAREN { $$=mk_action(	SEND_TCP_T,
754
+																IP_ST,
755
+																NUMBER_ST,
756
+																(void*)$3,
757
+																(void*)$5);
758
+											   }
759
+		| SEND_TCP error { $$=0; yyerror("missing '(' or ')' ?"); }
760
+		| SEND_TCP LPAREN error RPAREN { $$=0; yyerror("bad send_tcp"
761
+													"argument"); }
723 762
 		| DROP LPAREN RPAREN	{$$=mk_action(DROP_T,0, 0, 0, 0); }
724 763
 		| DROP					{$$=mk_action(DROP_T,0, 0, 0, 0); }
725 764
 		| 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 502
 		return -1;
503 503
 	}
504 504
 	memcpy(up_since_ctime,t,strlen(t)+1);
505
+#ifdef USE_TCP
506
+	if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sockfd)<0){
507
+			LOG(L_ERR, "ERROR: open_fifo_server: socketpair failed: %s\n",
508
+				strerror(errno));
509
+			return -1;
510
+	}
511
+#endif
505 512
 	process_no++;
506 513
 	fifo_pid=fork();
507 514
 	if (fifo_pid<0) {
... ...
@@ -514,6 +524,10 @@ int open_fifo_server()
514 514
 		/* call per-child module initialization too -- some
515 515
 		   FIFO commands may need it
516 516
 		*/
517
+#ifdef USE_TCP
518
+		close(sockfd[0]);
519
+		unix_tcp_sock=sockfd[1];
520
+#endif
517 521
 		if (init_child(process_no) < 0 ) {
518 522
 			LOG(L_ERR, "ERROR: open_uac_fifo: init_child failed\n");
519 523
 			return -1;
... ...
@@ -539,6 +553,11 @@ int open_fifo_server()
539 539
 	/* dad process */
540 540
 	pt[process_no].pid=fifo_pid;
541 541
 	strncpy(pt[process_no].desc, "fifo server", MAX_PT_DESC );
542
+#ifdef USE_TCP
543
+	close(sockfd[1]);
544
+	pt[process_no].unix_sock=sockfd[0];
545
+	pt[process_no].idx=-1; /* this is not "tcp" process*/
546
+#endif
542 547
 	/* make sure the read fifo will not close */
543 548
 	fifo_write=open(fifo, O_WRONLY, 0);
544 549
 	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 181
 
182 182
 
183 183
 
184
+/* compare 2 ip_addrs (both args are pointers)*/
185
+#define ip_addr_cmp(ip1, ip2) \
186
+	(((ip1)->af==(ip2)->af)&& \
187
+	 	(memcmp((ip1)->u.addr, (ip2)->u.addr, (ip1)->len)==0))
188
+
189
+
190
+
191
+/* compare 2 sockaddr_unions */
192
+static inline int su_cmp(union sockaddr_union* s1, union sockaddr_union* s2)
193
+{
194
+	if (s1->s.sa_family!=s2->s.sa_family) return 0;
195
+	switch(s1->s.sa_family){
196
+		case AF_INET:
197
+			return (s1->sin.sin_port==s2->sin.sin_port)&&
198
+					(memcmp(&s1->sin.sin_addr, &s2->sin.sin_addr, 4)==0);
199
+		case AF_INET6:
200
+			return (s1->sin6.sin6_port==s2->sin6.sin6_port)&&
201
+					(memcmp(&s1->sin6.sin6_addr, &s2->sin6.sin6_addr, 16)==0);
202
+		default:
203
+			LOG(L_CRIT,"su_cmp: BUG: unknown address family %d\n",
204
+						s1->s.sa_family);
205
+			return 0;
206
+	}
207
+}
208
+
209
+
210
+
211
+/* gets the port number */
212
+static inline short su_getport(union sockaddr_union* su)
213
+{
214
+	switch(su->s.sa_family){
215
+		case AF_INET:
216
+			return su->sin.sin_port;
217
+		case AF_INET6:
218
+			return su->sin6.sin6_port;
219
+		default:
220
+			LOG(L_CRIT,"su_get_port: BUG: unknown address family %d\n",
221
+						su->s.sa_family);
222
+			return 0;
223
+	}
224
+}
225
+
226
+
227
+
184 228
 /* inits an ip_addr pointer from a sockaddr_union ip address */
185 229
 static inline void su2ip_addr(struct ip_addr* ip, union sockaddr_union* su)
186 230
 {
... ...
@@ -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 632
 			/* all procs should have access to all the sockets (for sending)
633 633
 			 * so we open all first*/
634 634
 		}
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 635
 		for(r=0; r<sock_no;r++){
653 636
 			for(i=0;i<children_no;i++){
654 637
 				process_no++;
638
+#ifdef USE_TCP
639
+		 		if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sockfd)<0){
640
+					LOG(L_ERR, "ERROR: main_loop: socketpair failed: %s\n",
641
+						strerror(errno));
642
+					goto error;
643
+				}
644
+#endif
655 645
 				if ((pid=fork())<0){
656 646
 					LOG(L_CRIT,  "main_loop: Cannot fork\n");
657 647
 					goto error;
658 648
 				}else if (pid==0){
659 649
 					     /* child */
650
+#ifdef USE_TCP
651
+					close(sockfd[0]);
652
+					unix_tcp_sock=sockfd[1];
653
+#endif
660 654
 					bind_address=&sock_info[r]; /* shortcut */
661 655
 					bind_idx=r;
662 656
 					if (init_child(i) < 0) {
... ...
@@ -672,6 +669,11 @@ int main_loop()
672 672
 						snprintf(pt[process_no].desc, MAX_PT_DESC,
673 673
 							"receiver child=%d sock=%d @ %s:%s", i, r, 	
674 674
 							sock_info[r].name.s, sock_info[r].port_no_str.s );
675
+#ifdef USE_TCP
676
+						close(sockfd[1]);
677
+						pt[process_no].unix_sock=sockfd[0];
678
+						pt[process_no].idx=-1; /* this is not "tcp" process*/
679
+#endif
675 680
 				}
676 681
 			}
677 682
 			/*parent*/
... ...
@@ -682,6 +684,7 @@ int main_loop()
682 682
 	/*this is the main process*/
683 683
 	bind_address=&sock_info[0]; /* main proc -> it shoudln't send anything, */
684 684
 	bind_idx=0;					/* if it does it will use the first address */
685
+	
685 686
 	/* if configured to do so, start a server for accepting FIFO commands */
686 687
 	if (open_fifo_server()<0) {
687 688
 		LOG(L_ERR, "opening fifo server failed\n");
... ...
@@ -693,6 +696,13 @@ int main_loop()
693 693
 	if (timer_list)
694 694
 #endif
695 695
 	{
696
+#ifdef USE_TCP
697
+ 		if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sockfd)<0){
698
+			LOG(L_ERR, "ERROR: main_loop: socketpair failed: %s\n",
699
+				strerror(errno));
700
+			goto error;
701
+		}
702
+#endif
696 703
 		/* fork again for the attendant process*/
697 704
 		process_no++;
698 705
 		if ((pid=fork())<0){
... ...
@@ -701,6 +711,10 @@ int main_loop()
701 701
 		}else if (pid==0){
702 702
 			/* child */
703 703
 			/* is_main=0; */
704
+#ifdef USE_TCP
705
+			close(sockfd[0]);
706
+			unix_tcp_sock=sockfd[1];
707
+#endif
704 708
 			for(;;){
705 709
 				/* debug:  instead of doing something usefull */
706 710
 				/* (placeholder for timers, etc.) */
... ...
@@ -711,12 +725,41 @@ int main_loop()
711 711
 		}else{
712 712
 			pt[process_no].pid=pid;
713 713
 			strncpy(pt[process_no].desc, "timer", MAX_PT_DESC );
714
+#ifdef USE_TCP
715
+						close(sockfd[1]);
716
+						pt[process_no].unix_sock=sockfd[0];
717
+						pt[process_no].idx=-1; /* this is not a "tcp" process*/
718
+#endif
714 719
 		}
715 720
 	}
716
-
721
+#ifdef USE_TCP
722
+			/* start tcp receivers */
723
+		if (tcp_init_children()<0) goto error;
724
+			/* start tcp master proc */
725
+		process_no++;
726
+		if ((pid=fork())<0){
727
+			LOG(L_CRIT, "main_loop: cannot fork tcp main process\n");
728
+			goto error;
729
+		}else if (pid==0){
730
+			/* child */
731
+			/* is_main=0; */
732
+			tcp_main_loop();
733
+		}else{
734
+			pt[process_no].pid=pid;
735
+			strncpy(pt[process_no].desc, "tcp main process", MAX_PT_DESC );
736
+			pt[process_no].unix_sock=-1;
737
+			pt[process_no].idx=-1; /* this is not a "tcp" process*/
738
+			unix_tcp_sock=-1;
739
+		}
740
+#endif
717 741
 	/* main */
718 742
 	pt[0].pid=getpid();
719 743
 	strncpy(pt[0].desc, "attendant", MAX_PT_DESC );
744
+#ifdef USE_TCP
745
+	pt[process_no].unix_sock=-1;
746
+	pt[process_no].idx=-1; /* this is not a "tcp" process*/
747
+	unix_tcp_sock=-1;
748
+#endif
720 749
 	/*DEBUG- remove it*/
721 750
 #ifdef DEBUG
722 751
 	printf("\n% 3d processes, % 3d children * % 3d listening addresses + main"
... ...
@@ -1177,7 +1220,14 @@ try_again:
1177 1177
 		LOG(L_CRIT, "could not initialize timer, exiting...\n");
1178 1178
 		goto error;
1179 1179
 	}
1180
-
1180
+#ifdef USE_TCP
1181
+	/*init tcp*/
1182
+	if (init_tcp()<0){
1183
+		LOG(L_CRIT, "could not initialize tcp, exiting...\n");
1184
+		goto error;
1185
+	}
1186
+#endif
1187
+	
1181 1188
 	/* register a diagnostic FIFO command */
1182 1189
 	if (register_core_fifo()<0) {
1183 1190
 		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 71
 struct tcp_connection{
72 72
 	int s; /*socket, used by "tcp main" */
73 73
 	int fd; /* used only by "children" */
74
+	int id; /* id (unique!) used to retrieve a specific connection when
75
+	           reply-ing*/
74 76
 	struct ip_addr ip; /* peer ip */
77
+	int port; /* peer port */
75 78
 	int sock_idx; /* receiving socket index in the tcp_info array */
76 79
 	union sockaddr_union su;
77 80
 	struct tcp_req req; /* request data */
... ...
@@ -116,7 +123,10 @@ struct tcp_connection{
116 116
 	}while(0)
117 117
 
118 118
 
119
-
119
+#define TCPCONN_LOCK LOG(L_CRIT, "LOCK not implemented yet: %s : %d: %s\n", \
120
+							__FILE__, __LINE__, __FUNCTION__);
121
+#define TCPCONN_UNLOCK LOG(L_CRIT, "UNLOCK not implemented yet: %s: %d: %s\n",\
122
+							__FILE__, __LINE__, __FUNCTION__);
120 123
 
121 124
 
122 125
 
... ...
@@ -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 64
 
65 65
 struct tcp_child{
66 66
 	pid_t pid;
67
-	int s; /* unix socket for comm*/
67
+	int unix_sock; /* unix sock fd, copied from pt*/
68 68
 	int busy;
69 69
 	int n_reqs; /* number of requests serviced so far */
70 70
 };
71 71
 
72 72
 
73
-enum { CONN_OK, CONN_ERROR };
74 73
 
75
-
76
-
77
-
78
-struct tcp_connection* conn_list=0;
74
+struct tcp_connection** conn_list=0;
79 75
 struct tcp_child tcp_children[MAX_TCP_CHILDREN];
76
+static int connection_id=1; /*  unique for each connection, used for 
77
+								quickly finding the corresponding connection
78
+								for a reply */
79
+int unix_tcp_sock;
80 80
 
81 81
 
82 82
 
83
-struct tcp_connection*  tcpconn_add(int sock, union sockaddr_union* su, int i)
83
+struct tcp_connection* tcpconn_new(int sock, union sockaddr_union* su, int i)
84 84
 {
85 85
 	struct tcp_connection *c;
86 86
 	
... ...
@@ -91,15 +92,15 @@ struct tcp_connection*  tcpconn_add(int sock, union sockaddr_union* su, int i)
91 91
 		goto error;
92 92
 	}
93 93
 	c->s=sock;
94
+	c->fd=sock;
94 95
 	c->su=*su;
95 96
 	c->sock_idx=i;
96 97
 	c->refcnt=0;
97 98
 	su2ip_addr(&c->ip, su);
99
+	c->port=su_getport(su);
98 100
 	init_tcp_req(&c->req);
99 101
 	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);
102
+	c->id=connection_id++;
103 103
 	return c;
104 104
 	
105 105
 error:
... ...
@@ -108,27 +109,158 @@ error:
108 108
 
109 109
 
110 110
 
111
+struct tcp_connection* tcpconn_connect(union sockaddr_union* server)
112
+{
113
+	int s;
114
+
115
+	s=socket(AF2PF(server->s.sa_family), SOCK_STREAM, 0);
116
+	if (s<0){
117
+		LOG(L_ERR, "ERROR: tcpconn_connect: socket: (%d) %s\n",
118
+				errno, strerror(errno));
119
+		goto error;
120
+	}
121
+	if (connect(s, &server->s, sockaddru_len(*server))<0){
122
+		LOG(L_ERR, "ERROR: tcpconn_connect: connect: (%d) %s\n",
123
+				errno, strerror(errno));
124
+		goto error;
125
+	}
126
+	return tcpconn_new(s, server, 0); /*FIXME: set sock idx! */
127
+error:
128
+	return 0;
129
+}
130
+
131
+
132
+
133
+struct tcp_connection*  tcpconn_add(struct tcp_connection *c)
134
+{
135
+	TCPCONN_LOCK;
136
+	/* add it at the begining of the list*/
137
+	if (c) tcpconn_listadd(*conn_list, c, next, prev);
138
+	TCPCONN_UNLOCK;
139
+	return c;
140
+}
141
+
142
+
143
+
111 144
 void tcpconn_rm(struct tcp_connection* c)
112 145
 {
113
-	tcpconn_listrm(conn_list, c, next, prev);
146
+	TCPCONN_LOCK;
147
+	tcpconn_listrm(*conn_list, c, next, prev);
148
+	TCPCONN_UNLOCK;
114 149
 	shm_free(c);
115 150
 }
116 151
 
117 152
 
153
+/* finds a connection, if id=0 uses the ip addr & port */
154
+struct tcp_connection* tcpconn_find(int id, struct ip_addr* ip, int port)
155
+{
156
+
157
+	struct tcp_connection *c;
158
+	
159
+	DBG("tcpconn_find: %d ",id ); print_ip(ip); DBG(" %d\n", port);
160
+	for (c=*conn_list; c; c=c->next){
161
+		DBG("c=%p, c->id=%d, ip=",c, c->id);
162
+		print_ip(&c->ip);
163
+		DBG(" port=%d\n", c->port);
164
+		if (id){
165
+			if (id==c->id) return c;
166
+		}else if ((port==c->port)&&(ip_addr_cmp(ip, &c->ip))) return c;
167
+	}
168
+	return 0;
169
+}
170
+
171
+
172
+
173
+struct tcp_connection* tcpconn_get(int id, struct ip_addr* ip, int port)
174
+{
175
+	struct tcp_connection* c;
176
+	TCPCONN_LOCK;
177
+	c=tcpconn_find(id, ip, port);
178
+	if (c) c->refcnt++;
179
+	TCPCONN_UNLOCK;
180
+	return c;
181
+}
182
+
183
+
184
+
185
+void tcpconn_put(struct tcp_connection* c)
186
+{
187
+	c->refcnt--; /* FIXME: atomic_dec */
188
+}
189
+
190
+
191
+
192
+/* finds a tcpconn & sends on it */
193
+int tcp_send(char* buf, unsigned len, union sockaddr_union* to, int id)
194
+{
195
+	struct tcp_connection *c;
196
+	struct ip_addr ip;
197
+	int port;
198
+	long response[2];
199
+	int n;
200
+	
201
+	su2ip_addr(&ip, to);
202
+	port=su_getport(to);
203
+	
204
+	c=tcpconn_get(id, &ip, port); /* lock ;inc refcnt; unlock */
205
+	if (id){
206
+		if (c==0) {
207
+		LOG(L_ERR, "ERROR: tcp_send: id %d not found, dropping\n",
208
+					id);
209
+			return -1;
210
+		}
211
+	}else{
212
+		if (c==0){
213
+			DBG("tcp_send: no open tcp connection found, opening new one\n");
214
+			/* create tcp connection */
215
+			if ((c=tcpconn_connect(to))==0){
216
+				LOG(L_ERR, "ERROR: tcp_send: connect failed\n");
217
+				return 0;
218
+			}
219
+			c->refcnt++;
220
+			
221
+			/* send the new tcpconn to "tcp main" */
222
+			response[0]=(long)c;
223
+			response[1]=CONN_NEW;
224
+			n=write(unix_tcp_sock, response, sizeof(response));
225
+			n=send_fd(unix_tcp_sock, &c, sizeof(c), c->s);
226
+		}else{
227
+			DBG("tcp_send: tcp connection found, acquiring fd\n");
228
+			/* get the fd */
229
+			response[0]=(long)c;
230
+			response[1]=CONN_GET_FD;
231
+			n=write(unix_tcp_sock, response, sizeof(response));
232
+			n=receive_fd(unix_tcp_sock, &c, sizeof(c), &c->fd);
233
+		}
234
+	
235
+	}
236
+	DBG("tcp_send: sending...\n");
237
+	n=write(c->fd, buf, len);
238
+	close(c->fd);
239
+	tcpconn_put(c); /* release c (lock; dec refcnt; unlock) */
240
+	return n;
241
+}
242
+
243
+
244
+
118 245
 /* very ineficient for now, use hashtable some day - FIXME*/
119
-void tcpconn_timeout()
246
+void tcpconn_timeout(fd_set* set)
120 247
 {
121 248
 	struct tcp_connection *c, *next;
122 249
 	int ticks;;
123 250
 	
124 251
 	
125 252
 	ticks=get_ticks();
126
-	c=conn_list;
253
+	c=*conn_list;
127 254
 	while(c){
128 255
 		next=c->next;
129 256
 		if ((c->refcnt==0) && (ticks>c->timeout)) {
130 257
 			DBG("tcpconn_timeout: timeout for %p (%d > %d)\n",
131 258
 					c, ticks, c->timeout);
259
+			if (c->s>0) {
260
+				FD_CLR(c->s, set);
261
+				close(c->s);
262
+			}
132 263
 			tcpconn_rm(c);
133 264
 		}
134 265
 		c=next;
... ...
@@ -209,7 +341,8 @@ static int send2child(struct tcp_connection* tcpconn)
209 209
 				min_busy);
210 210
 	}
211 211
 	DBG("send2child: to child %d, %ld\n", idx, (long)tcpconn);
212
-	send_fd(tcp_children[idx].s, &tcpconn, sizeof(tcpconn), tcpconn->s);
212
+	send_fd(tcp_children[idx].unix_sock, &tcpconn, sizeof(tcpconn),
213
+			tcpconn->s);
213 214
 	
214 215
 	return 0; /* just to fix a warning*/
215 216
 }
... ...
@@ -226,7 +359,7 @@ void tcp_main_loop()
226 226
 	union sockaddr_union su;
227 227
 	struct tcp_connection* tcpconn;
228 228
 	long response[2];
229
-	int state;
229
+	int cmd;
230 230
 	int bytes;
231 231
 	socklen_t su_len;
232 232
 	struct timeval timeout;
... ...
@@ -242,10 +375,10 @@ void tcp_main_loop()
242 242
 		}
243 243
 	}
244 244
 	/* 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;
245
+	for (r=0; r<process_no; r++){
246
+		if (pt[r].unix_sock>=0){
247
+			FD_SET(pt[r].unix_sock, &master_set);
248
+			if (pt[r].unix_sock>maxfd) maxfd=pt[r].unix_sock;
249 249
 		}
250 250
 	}
251 251
 	
... ...
@@ -262,6 +395,7 @@ void tcp_main_loop()
262 262
 			/* errors */
263 263
 			LOG(L_ERR, "ERROR: tcp_main_loop: select:(%d) %s\n", errno,
264 264
 					strerror(errno));
265
+			n=0;
265 266
 		}
266 267
 		
267 268
 		for (r=0; r<sock_no && n; r++){
... ...
@@ -278,21 +412,25 @@ void tcp_main_loop()
278 278
 				}
279 279
 				
280 280
 				/* add socket to list */
281
-				tcpconn=tcpconn_add(new_sock, &su, r);
282
-				DBG("tcp_main_loop: new connection: %p %d\n",
281
+				tcpconn=tcpconn_new(new_sock, &su, r);
282
+				if (tcpconn){
283
+					tcpconn_add(tcpconn);
284
+					DBG("tcp_main_loop: new connection: %p %d\n",
283 285
 						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);
286
+					/* pass it to a child */
287
+					if(send2child(tcpconn)<0){
288
+						LOG(L_ERR,"ERROR: tcp_main_loop: no children "
289
+								"available\n");
290
+						close(tcpconn->s);
291
+						tcpconn_rm(tcpconn);
292
+					}
289 293
 				}
290 294
 			}
291 295
 		}
292 296
 		
293 297
 		/* check all the read fds (from the tcpconn list) */
294 298
 		
295
-		for(tcpconn=conn_list; tcpconn && n; tcpconn=tcpconn->next){
299
+		for(tcpconn=*conn_list; tcpconn && n; tcpconn=tcpconn->next){
296 300
 			if ((tcpconn->refcnt==0)&&(FD_ISSET(tcpconn->s, &sel_set))){
297 301
 				/* new data available */
298 302
 				n--;
... ...
@@ -309,17 +447,18 @@ void tcp_main_loop()
309 309
 		}
310 310
 		
311 311
 		/* 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)){
312
+		/* start from 1, the "main" process does not transmit anything*/
313
+		for (r=1; r<process_no && n; r++){
314
+			if ( (pt[r].unix_sock>=0) && FD_ISSET(pt[r].unix_sock, &sel_set)){
314 315
 				n--;
315 316
 				/* errno==EINTR !!! TODO*/
316 317
 read_again:
317
-				bytes=read(tcp_children[r].s, response, sizeof(response));
318
+				bytes=read(pt[r].unix_sock, response, sizeof(response));
318 319
 				if (bytes==0){
319 320
 					/* EOF -> bad, child has died */
320 321
 					LOG(L_CRIT, "BUG: tcp_main_loop: dead child %d\n", r);
321
-					/* terminating everybody */
322
-					FD_CLR(tcp_children[r].s, &master_set);
322
+					/* don't listen on it any more */
323
+					FD_CLR(pt[r].unix_sock, &master_set);
323 324
 					/*exit(-1)*/;
324 325
 				}else if (bytes<0){
325 326
 					if (errno==EINTR) goto read_again;
... ...
@@ -330,45 +469,108 @@ read_again:
330 330
 					}
331 331
 				}
332 332
 					
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){
333
+				DBG("tcp_main_loop: read response= %lx, %ld from %d (%d)\n",
334
+						response[0], response[1], r, pt[r].pid);
335
+				cmd=response[1];
336
+				switch(cmd){
337
+					case CONN_RELEASE:
338
+						if (pt[r].idx>=0){
339
+							tcp_children[pt[r].idx].busy--;
340
+						}else{
341
+							LOG(L_CRIT, "BUG: tcp_main_loop: CONN_RELEASE\n");
342
+						}
343
+						tcpconn=(struct tcp_connection*)response[0];
344
+						if (tcpconn){
345
+							tcpconn->refcnt--;
346
+							DBG("tcp_main_loop: %p refcnt= %d\n", 
347
+									tcpconn, tcpconn->refcnt);
348
+								FD_SET(tcpconn->s, &master_set);
349
+								if (maxfd<tcpconn->s) maxfd=tcpconn->s;
350
+								/* update the timeout*/
351
+								tcpconn->timeout=get_ticks()+TCP_CON_TIMEOUT;
352
+						}
353
+						break;
354
+					case CONN_ERROR:
355
+					case CONN_DESTROY:
356
+					case CONN_EOF:
357
+						if (pt[r].idx>=0){
358
+							tcp_children[pt[r].idx].busy--;
359
+						}else{
360
+							LOG(L_CRIT, "BUG: tcp_main_loop: CONN_RELEASE\n");
361
+						}
362
+						tcpconn=(struct tcp_connection*)response[0];
363
+						if (tcpconn){
364
+							tcpconn->refcnt--;
365
+							if (tcpconn->refcnt==0){
366
+								DBG("tcp_main_loop: destroying connection\n");
367
+								close(tcpconn->s);
368
+								tcpconn_rm(tcpconn);
369
+							}else{
370
+								DBG("tcp_main_loop: delaying ...\n");
371
+							}
372
+						}
373
+						break;
374
+					case CONN_GET_FD:
375
+						/* send the requested FD  */
376
+						tcpconn=(struct tcp_connection*)response[0];
377
+						/* WARNING: take care of setting refcnt properly to
378
+						 * avoid race condition */
379
+						if (tcpconn){
380
+							send_fd(pt[r].unix_sock, &tcpconn,
381
+									sizeof(tcpconn), tcpconn->s);
382
+						}else{
383
+							LOG(L_CRIT, "BUG: tcp_main_loop: null pointer\n");
384
+						}
385
+						break;
386
+					case CONN_NEW:
387
+						/* update the fd in the requested tcpconn*/
388
+						tcpconn=(struct tcp_connection*)response[0];
389
+						/* WARNING: take care of setting refcnt properly to
390
+						 * avoid race condition */
391
+						if (tcpconn){
392
+							receive_fd(pt[r].unix_sock, &tcpconn,
393
+										sizeof(tcpconn), &tcpconn->s);
394
+							/* add tcpconn to the list*/
395
+							tcpconn_add(tcpconn);
343 396
 							FD_SET(tcpconn->s, &master_set);
344 397
 							if (maxfd<tcpconn->s) maxfd=tcpconn->s;
345 398
 							/* update the timeout*/
346 399
 							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 400
 						}else{
355
-							DBG("tcp_main_loop: delaying ...\n");
401
+							LOG(L_CRIT, "BUG: tcp_main_loop: null pointer\n");
356 402
 						}
357
-					}
358
-				}else{
359
-					LOG(L_CRIT, "BUG: tcp_main_loop: null tcp conn pointer\n");
403
+						break;
404
+					default:
405
+							LOG(L_CRIT, "BUG: tcp_main_loop: unknown cmd %d\n",
406
+									cmd);
360 407
 				}
361 408
 			}
362 409
 		}
363 410
 		
364 411
 		/* remove old connections */
365
-		tcpconn_timeout();
412
+		tcpconn_timeout(&master_set);
366 413
 	
367 414
 	}
368 415
 }
369 416
 
370 417
 
371 418
 
419
+int init_tcp()
420
+{
421
+	/* allocate list head*/
422
+	conn_list=shm_malloc(sizeof(struct tcp_connection*));
423
+	if (conn_list==0){
424
+		LOG(L_CRIT, "ERROR: tcp_init: memory allocation failure\n");
425
+		goto error;
426
+	}
427
+	*conn_list=0;
428
+	return 0;
429
+error:
430
+		return -1;
431
+}
432
+
433
+
434
+
372 435
 /* starts the tcp processes */
373 436
 int tcp_init_children()
374 437
 {
... ...
@@ -402,14 +604,17 @@ int tcp_init_children()
402 402
 			/* parent */
403 403
 			close(sockfd[1]);
404 404
 			tcp_children[r].pid=pid;
405
-			tcp_children[r].s=sockfd[0];
406 405
 			tcp_children[r].busy=0;
407 406
 			tcp_children[r].n_reqs=0;
407
+			tcp_children[r].unix_sock=sockfd[0];
408 408
 			pt[process_no].pid=pid;
409
+			pt[process_no].unix_sock=sockfd[0];
410
+			pt[process_no].idx=r;
409 411
 			strncpy(pt[process_no].desc, "tcp receiver", MAX_PT_DESC);
410 412
 		}else{
411 413
 			/* child */
412 414
 			close(sockfd[0]);
415
+			unix_tcp_sock=sockfd[1];
413 416
 			tcp_receive_loop(sockfd[1]);
414 417
 		}
415 418
 	}
... ...
@@ -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 385
 		
386 386
 		
387 387
 	end_req:
388
-		return state;
388
+		return resp;
389 389
 }
390 390
 
391 391
 
... ...
@@ -413,7 +416,7 @@ void tcp_receive_loop(int unix_sock)
413 413
 	int n;
414 414
 	int nfds;
415 415
 	int s;
416
-	long state;
416
+	long resp;
417 417
 	fd_set master_set;
418 418
 	fd_set sel_set;
419 419
 	int maxfd;
... ...
@@ -463,13 +466,13 @@ void tcp_receive_loop(int unix_sock)
463 463
 				if (s==-1) {
464 464
 					LOG(L_ERR, "ERROR: tcp_receive_loop: read_fd:"
465 465
 									"no fd read\n");
466
-					state=-1;
467
-					release_tcpconn(con, state, unix_sock);
466
+					resp=CONN_ERROR;
467
+					release_tcpconn(con, resp, unix_sock);
468 468
 				}
469 469
 				if (con==0){
470 470
 					LOG(L_ERR, "ERROR: tcp_receive_loop: null pointer\n");
471
-					state=-1;
472
-					release_tcpconn(con, state, unix_sock);
471
+					resp=CONN_ERROR;
472
+					release_tcpconn(con, resp, unix_sock);
473 473
 				}
474 474
 				con->timeout=get_ticks()+TCP_CHILD_TIMEOUT;
475 475
 				FD_SET(s, &master_set);
... ...
@@ -481,11 +484,11 @@ void tcp_receive_loop(int unix_sock)
481 481
 				c_next=con->c_next; /* safe for removing*/
482 482
 				if (nfds && FD_ISSET(con->fd, &sel_set)){
483 483
 					nfds--;
484
-					state=tcp_read_req(con);
485
-					if (state==-1){
484
+					resp=tcp_read_req(con);
485
+					if (resp<0){
486 486
 						FD_CLR(con->fd, &master_set);
487 487
 						tcpconn_listrm(list, con, c_next, c_prev);
488
-						release_tcpconn(con, state, unix_sock);
488
+						release_tcpconn(con, resp, unix_sock);
489 489
 					}else{
490 490
 						/* update timeout */
491 491
 						con->timeout=ticks+TCP_CHILD_TIMEOUT;
... ...
@@ -496,10 +499,10 @@ void tcp_receive_loop(int unix_sock)
496 496
 						/* expired, return to "tcp main" */
497 497
 						DBG("tcp_receive_loop: %p expired (%d, %d)\n",
498 498
 								con, con->timeout, ticks);
499
-						state=0;
499
+						resp=CONN_RELEASE;
500 500
 						FD_CLR(con->fd, &master_set);
501 501
 						tcpconn_listrm(list, con, c_next, c_prev);
502
-						release_tcpconn(con, state, unix_sock);
502
+						release_tcpconn(con, resp, unix_sock);
503 503
 					}
504 504
 				}
505 505
 			}
506 506
new file mode 100644
... ...
@@ -0,0 +1,46 @@
0
+/*
1
+ * $Id$
2
+ *
3
+ * Copyright (C) 2001-2003 Fhg Fokus
4
+ *
5
+ * This file is part of ser, a free SIP server.
6
+ *
7
+ * ser is free software; you can redistribute it and/or modify
8
+ * it under the terms of the GNU General Public License as published by
9
+ * the Free Software Foundation; either version 2 of the License, or
10
+ * (at your option) any later version
11
+ *
12
+ * For a license to use the ser software under conditions
13
+ * other than those described here, or to purchase support for this
14
+ * software, please contact iptel.org by e-mail at the following addresses:
15
+ *    info@iptel.org
16
+ *
17
+ * ser is distributed in the hope that it will be useful,
18
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
+ * GNU General Public License for more details.
21
+ *
22
+ * You should have received a copy of the GNU General Public License 
23
+ * along with this program; if not, write to the Free Software 
24
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25
+ */
26
+
27
+
28
+#ifndef tcp_server_h
29
+#define tcp_server_h
30
+
31
+
32
+
33
+
34
+/* "public" functions*/
35
+
36
+struct tcp_connection* tcpconn_get(int id, struct ip_addr* ip, int port);
37
+void tcpconn_put(struct tcp_connection* c);
38
+int tcp_send(char* buf, unsigned len, union sockaddr_union* to, int id);
39
+
40
+
41
+
42
+
43
+
44
+
45
+#endif