Browse code

- using separate unix sockets for tcp readers & for getting the write socket (to avoid the case when a reader process execs the script, wants to write on some tcp. con. and in the same time the main tcp process sends it another socket for reading -> the write will get the read socket & the read loop will get the write one)

Andrei Pelinescu-Onciul authored on 07/11/2003 00:43:26
Showing 4 changed files
... ...
@@ -43,7 +43,7 @@ export makefile_defs
43 43
 VERSION = 0
44 44
 PATCHLEVEL = 8
45 45
 SUBLEVEL =   12
46
-EXTRAVERSION = -testing-23
46
+EXTRAVERSION = -testing-24
47 47
 
48 48
 RELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
49 49
 OS = $(shell uname -s | sed -e s/SunOS/solaris/ | tr "[A-Z]" "[a-z]")
... ...
@@ -70,7 +70,7 @@ int recv_all(int socket, void* data, int data_len)
70 70
 }
71 71
 
72 72
 
73
-/* sends all data (takes care of signals)
73
+/* sends all data (takes care of signals) (assumes blocking fd)
74 74
  * returns number of bytes sent or < 0 for an error */
75 75
 int send_all(int socket, void* data, int data_len)
76 76
 {
... ...
@@ -70,6 +70,8 @@ enum tcp_conn_states { S_CONN_ERROR=-2, S_CONN_BAD=-1, S_CONN_OK=0,
70 70
 /* fd communication commands */
71 71
 enum conn_cmds { CONN_DESTROY=-3, CONN_ERROR=-2, CONN_EOF=-1, CONN_RELEASE, 
72 72
 					CONN_GET_FD, CONN_NEW };
73
+/* CONN_RELEASE, EOF, ERROR, DESTROY can be used by "reader" processes
74
+ * CONN_GET_FD, NEW, ERROR only by writers */
73 75
 
74 76
 struct tcp_req{
75 77
 	struct tcp_req* next;
... ...
@@ -44,6 +44,8 @@
44 44
  *  2003-07-09  tls_close called before closing the tcp connection (andrei)
45 45
  *  2003-11-04  always lock before manipulating refcnt; sendchild
46 46
  *              does not inc refcnt by itself anymore (andrei)
47
+ *  2003-11-07  different unix sockets are used for fd passing
48
+ *              to/from readers/writers (andrei)
47 49
  */
48 50
 
49 51
 
... ...
@@ -100,7 +102,7 @@
100 102
 struct tcp_child{
101 103
 	pid_t pid;
102 104
 	int proc_no; /* ser proc_no, for debugging */
103
-	int unix_sock; /* unix sock fd, copied from pt*/
105
+	int unix_sock; /* unix "read child" sock fd */
104 106
 	int busy;
105 107
 	int n_reqs; /* number of requests serviced so far */
106 108
 };
... ...
@@ -756,6 +758,34 @@ static inline void handle_new_connect(struct socket_info* si,
756 758
 }
757 759
 
758 760
 
761
+/* used internally by tcp_main_loop() */
762
+static void tcpconn_destroy(struct tcp_connection* tcpconn)
763
+{
764
+	int fd;
765
+
766
+	TCPCONN_LOCK; /*avoid races w/ tcp_send*/
767
+	tcpconn->refcnt--;
768
+	if (tcpconn->refcnt==0){ 
769
+		DBG("tcp_main_loop: destroying connection\n");
770
+		fd=tcpconn->s;
771
+#ifdef USE_TLS
772
+		/*FIXME: lock ->writelock ? */
773
+		if (tcpconn->type==PROTO_TLS)
774
+			tls_close(tcpconn, fd);
775
+#endif
776
+		_tcpconn_rm(tcpconn);
777
+		close(fd);
778
+	}else{
779
+		/* force timeout */
780
+		tcpconn->timeout=0;
781
+		tcpconn->state=S_CONN_BAD;
782
+		DBG("tcp_main_loop: delaying ...\n");
783
+		
784
+	}
785
+	TCPCONN_UNLOCK;
786
+}
787
+
788
+
759 789
 void tcp_main_loop()
760 790
 {
761 791
 	int r;
... ...
@@ -795,6 +825,14 @@ void tcp_main_loop()
795 825
 			if (pt[r].unix_sock>maxfd) maxfd=pt[r].unix_sock;
796 826
 		}
797 827
 	}
828
+	for (r=0; r<tcp_children_no; r++){
829
+		if (tcp_children[r].unix_sock>0){ /* we can't have 0, 
830
+											 we never close it!*/
831
+			FD_SET(tcp_children[r].unix_sock, &master_set);
832
+			if (tcp_children[r].unix_sock>maxfd)
833
+				maxfd=tcp_children[r].unix_sock;
834
+		}
835
+	}
798 836
 	
799 837
 	
800 838
 	/* main loop*/
... ...
@@ -849,94 +887,107 @@ void tcp_main_loop()
849 887
 			}
850 888
 		}
851 889
 		/* check unix sockets & listen | destroy connections */
852
-		/* start from 1, the "main" process does not transmit anything*/
853
-		for (r=1; r<process_no && n; r++){
854
-			if ( (pt[r].unix_sock>0) && FD_ISSET(pt[r].unix_sock, &sel_set)){
890
+		/* tcp_children readers first */
891
+		for (r=0; r<tcp_children_no && n; r++){
892
+			if ( (tcp_children[r].unix_sock>0) && 
893
+					FD_ISSET(tcp_children[r].unix_sock, &sel_set)){
855 894
 				/* (we can't have a fd==0, 0 is never closed )*/
856 895
 				n--;
857 896
 				/* read until sizeof(response)
858 897
 				 * (this is a SOCK_STREAM so read is not atomic */
859
-				bytes=recv_all(pt[r].unix_sock, response, sizeof(response));
898
+				bytes=recv_all(tcp_children[r].unix_sock, response,
899
+								sizeof(response));
860 900
 				if (bytes==0){
861 901
 					/* EOF -> bad, child has died */
862
-					LOG(L_CRIT, "BUG: tcp_main_loop: dead child %d\n", r);
902
+					LOG(L_CRIT, "BUG: tcp_main_loop: dead tcp child %d\n", r);
863 903
 					/* don't listen on it any more */
864
-					FD_CLR(pt[r].unix_sock, &master_set);
904
+					FD_CLR(tcp_children[r].unix_sock, &master_set);
865 905
 					/*exit(-1);*/
866 906
 					continue; /* skip this and try the next one */
867 907
 				}else if (bytes<0){
868
-					LOG(L_CRIT, "ERROR: tcp_main_loop: read from child:  %s\n",
869
-							strerror(errno));
908
+					LOG(L_CRIT, "ERROR: tcp_main_loop: read from tcp child %d "
909
+							"%s\n", r, strerror(errno));
870 910
 					/* try to ignore ? */
871 911
 					continue; /* skip this and try the next one */
872 912
 				}
873 913
 					
874
-				DBG("tcp_main_loop: read response= %lx, %ld from %d (%d)\n",
875
-						response[0], response[1], r, pt[r].pid);
914
+				DBG("tcp_main_loop: reader response= %lx, %ld from %d \n",
915
+						response[0], response[1], r);
876 916
 				cmd=response[1];
917
+				tcpconn=(struct tcp_connection*)response[0];
877 918
 				switch(cmd){
878 919
 					case CONN_RELEASE:
879
-						if (pt[r].idx>=0){
880
-							tcp_children[pt[r].idx].busy--;
881
-						}else{
882
-							LOG(L_CRIT, "BUG: tcp_main_loop: CONN_RELEASE\n");
883
-						}
884
-						tcpconn=(struct tcp_connection*)response[0];
920
+						tcp_children[r].busy--;
885 921
 						if (tcpconn){
886
-								if (tcpconn->state==S_CONN_BAD) 
887
-									goto tcpconn_destroy;
922
+								if (tcpconn->state==S_CONN_BAD){ 
923
+									tcpconn_destroy(tcpconn);
924
+									break;
925
+								}
888 926
 								FD_SET(tcpconn->s, &master_set);
889 927
 								if (maxfd<tcpconn->s) maxfd=tcpconn->s;
890 928
 								/* update the timeout*/
891 929
 								tcpconn->timeout=get_ticks()+TCP_CON_TIMEOUT;
892 930
 								tcpconn_put(tcpconn);
893
-								DBG("tcp_main_loop: %p refcnt= %d\n", 
894
-									tcpconn, tcpconn->refcnt);
931
+								DBG("tcp_main_loop: CONN_RELEASE  %p"
932
+										" refcnt= %d\n", 
933
+										tcpconn, tcpconn->refcnt);
895 934
 						}
896 935
 						break;
897 936
 					case CONN_ERROR:
898 937
 					case CONN_DESTROY:
899 938
 					case CONN_EOF:
900 939
 						/* WARNING: this will auto-dec. refcnt! */
901
-						if (pt[r].idx>=0){
902
-							tcp_children[pt[r].idx].busy--;
903
-						}else{
904
-							/* CON_ERROR is ok, since we can get it from
905
-							 * any process using tcp_send */
906
-							if (cmd!=CONN_ERROR)
907
-								LOG(L_CRIT, "BUG: tcp_main_loop:"
908
-											"CONN_EOF/DESTROY\n");
940
+						tcp_children[pt[r].idx].busy--;
941
+						if (tcpconn){
942
+							if (tcpconn->s!=-1)
943
+								FD_CLR(tcpconn->s, &master_set);
944
+							tcpconn_destroy(tcpconn);
909 945
 						}
910
-						tcpconn=(struct tcp_connection*)response[0];
946
+						break;
947
+					default:
948
+							LOG(L_CRIT, "BUG: tcp_main_loop:  unknown cmd %d"
949
+										" from tcp reader %d\n",
950
+									cmd, r);
951
+				}
952
+			}
953
+		}
954
+		/* check "send" unix sockets & listen | destroy connections */
955
+		/* start from 1, the "main" process does not transmit anything*/
956
+		for (r=1; r<process_no && n; r++){
957
+			if ( (pt[r].unix_sock>0) && FD_ISSET(pt[r].unix_sock, &sel_set)){
958
+				/* (we can't have a fd==0, 0 is never closed )*/
959
+				n--;
960
+				/* read until sizeof(response)
961
+				 * (this is a SOCK_STREAM so read is not atomic */
962
+				bytes=recv_all(pt[r].unix_sock, response, sizeof(response));
963
+				if (bytes==0){
964
+					/* EOF -> bad, child has died */
965
+					LOG(L_CRIT, "BUG: tcp_main_loop: dead child %d\n", r);
966
+					/* don't listen on it any more */
967
+					FD_CLR(pt[r].unix_sock, &master_set);
968
+					/*exit(-1);*/
969
+					continue; /* skip this and try the next one */
970
+				}else if (bytes<0){
971
+					LOG(L_CRIT, "ERROR: tcp_main_loop: read from child:  %s\n",
972
+							strerror(errno));
973
+					/* try to ignore ? */
974
+					continue; /* skip this and try the next one */
975
+				}
976
+					
977
+				DBG("tcp_main_loop: read response= %lx, %ld from %d (%d)\n",
978
+						response[0], response[1], r, pt[r].pid);
979
+				cmd=response[1];
980
+				tcpconn=(struct tcp_connection*)response[0];
981
+				switch(cmd){
982
+					case CONN_ERROR:
911 983
 						if (tcpconn){
912 984
 							if (tcpconn->s!=-1)
913 985
 								FD_CLR(tcpconn->s, &master_set);
914
-		tcpconn_destroy:
915
-							TCPCONN_LOCK; /*avoid races w/ tcp_send*/
916
-							tcpconn->refcnt--;
917
-							if (tcpconn->refcnt==0){ 
918
-								DBG("tcp_main_loop: destroying connection\n");
919
-								fd=tcpconn->s;
920
-#ifdef USE_TLS
921
-								/*FIXME: lock ->writelock ? */
922
-								if (tcpconn->type==PROTO_TLS)
923
-									tls_close(tcpconn, fd);
924
-#endif
925
-								_tcpconn_rm(tcpconn);
926
-								close(fd);
927
-							}else{
928
-								/* force timeout */
929
-								tcpconn->timeout=0;
930
-								tcpconn->state=S_CONN_BAD;
931
-								DBG("tcp_main_loop: delaying ...\n");
932
-								
933
-							}
934
-							TCPCONN_UNLOCK;
986
+							tcpconn_destroy(tcpconn);
935 987
 						}
936 988
 						break;
937 989
 					case CONN_GET_FD:
938 990
 						/* send the requested FD  */
939
-						tcpconn=(struct tcp_connection*)response[0];
940 991
 						/* WARNING: take care of setting refcnt properly to
941 992
 						 * avoid race condition */
942 993
 						if (tcpconn){
... ...
@@ -951,7 +1002,6 @@ void tcp_main_loop()
951 1002
 						break;
952 1003
 					case CONN_NEW:
953 1004
 						/* update the fd in the requested tcpconn*/
954
-						tcpconn=(struct tcp_connection*)response[0];
955 1005
 						/* WARNING: take care of setting refcnt properly to
956 1006
 						 * avoid race condition */
957 1007
 						if (tcpconn){
... ...
@@ -1087,6 +1137,7 @@ int tcp_init_children()
1087 1137
 {
1088 1138
 	int r;
1089 1139
 	int sockfd[2];
1140
+	int reader_fd[2]; /* for comm. with the tcp children read  */
1090 1141
 	pid_t pid;
1091 1142
 	
1092 1143
 	
... ...
@@ -1100,6 +1151,11 @@ int tcp_init_children()
1100 1151
 					strerror(errno));
1101 1152
 			goto error;
1102 1153
 		}
1154
+		if (socketpair(AF_UNIX, SOCK_STREAM, 0, reader_fd)<0){
1155
+			LOG(L_ERR, "ERROR: tcp_main: socketpair failed: %s\n",
1156
+					strerror(errno));
1157
+			goto error;
1158
+		}
1103 1159
 		
1104 1160
 		process_no++;
1105 1161
 		pid=fork();
... ...
@@ -1110,11 +1166,12 @@ int tcp_init_children()
1110 1166
 		}else if (pid>0){
1111 1167
 			/* parent */
1112 1168
 			close(sockfd[1]);
1169
+			close(reader_fd[1]);
1113 1170
 			tcp_children[r].pid=pid;
1114 1171
 			tcp_children[r].proc_no=process_no;
1115 1172
 			tcp_children[r].busy=0;
1116 1173
 			tcp_children[r].n_reqs=0;
1117
-			tcp_children[r].unix_sock=sockfd[0];
1174
+			tcp_children[r].unix_sock=reader_fd[0];
1118 1175
 			pt[process_no].pid=pid;
1119 1176
 			pt[process_no].unix_sock=sockfd[0];
1120 1177
 			pt[process_no].idx=r;
... ...
@@ -1130,7 +1187,7 @@ int tcp_init_children()
1130 1187
 				LOG(L_ERR, "init_children failed\n");
1131 1188
 				goto error;
1132 1189
 			}
1133
-			tcp_receive_loop(sockfd[1]);
1190
+			tcp_receive_loop(reader_fd[1]);
1134 1191
 		}
1135 1192
 	}
1136 1193
 	return 0;