... | ... |
@@ -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; |