Browse code

- first tcp 2 udp packet sent

Andrei Pelinescu-Onciul authored on 04/12/2002 18:47:52
Showing 4 changed files
... ...
@@ -143,7 +143,7 @@ DEFS+= -DNAME='"$(NAME)"' -DVERSION='"$(RELEASE)"' -DARCH='"$(ARCH)"' \
143 143
 	 -DDNS_IP_HACK \
144 144
 	 -DUSE_IPV6 \
145 145
 	 -DDBG_QM_MALLOC \
146
-	# -DUSE_TCP \
146
+	 #-DUSE_TCP \
147 147
 	 #-DF_MALLOC \
148 148
 	 #-DNO_DEBUG \
149 149
 	 #-DNO_LOG
... ...
@@ -33,8 +33,14 @@
33 33
 
34 34
 
35 35
 #define TCP_BUF_SIZE 65535
36
-enum {TCP_REQ_INIT, TCP_REQ_OK, TCP_READ_ERROR, TCP_REQ_OVERRUN };
37
-enum {H_PARSING, H_LF, H_LFCR,  H_BODY };
36
+enum {	TCP_REQ_INIT, TCP_REQ_OK, TCP_READ_ERROR, TCP_REQ_OVERRUN, 
37
+	 	TCP_REQ_BAD_LEN };
38
+enum {	H_SKIP, H_LF, H_LFCR,  H_BODY, H_STARTWS,
39
+		H_CONT_LEN1, H_CONT_LEN2, H_CONT_LEN3, H_CONT_LEN4, H_CONT_LEN5,
40
+		H_CONT_LEN6, H_CONT_LEN7, H_CONT_LEN8, H_CONT_LEN9, H_CONT_LEN10,
41
+		H_CONT_LEN11, H_CONT_LEN12, H_CONT_LEN13, H_L_COLON, 
42
+		H_CONT_LEN_BODY, H_CONT_LEN_BODY_PARSE 
43
+	};
38 44
 
39 45
 struct tcp_req{
40 46
 	struct tcp_req* next;
... ...
@@ -44,6 +50,10 @@ struct tcp_req{
44 44
 	char* pos; /* current position in buf */
45 45
 	char* parsed; /* last parsed position */
46 46
 	char* body; /* body position */
47
+	int content_len;
48
+	int has_content_len; /* 1 if content_length was parsed ok*/
49
+	int complete; /* 1 if one req has been fully read, 0 otherwise*/
50
+	int bytes_to_go; /* how many bytes we have still to read from the body*/
47 51
 	int error;
48 52
 	int state;
49 53
 };
... ...
@@ -55,7 +65,7 @@ struct tcp_req{
55 55
 		(r)->fd=(f); \
56 56
 		(r)->parsed=(r)->pos=(r)->buf; \
57 57
 		(r)->error=TCP_REQ_OK;\
58
-		(r)->state=H_PARSING; \
58
+		(r)->state=H_STARTWS; \
59 59
 	}while(0)
60 60
 
61 61
 
... ...
@@ -193,6 +193,7 @@ void tcp_main_loop()
193 193
 	struct tcp_connection* tcpconn;
194 194
 	long response[2];
195 195
 	int state;
196
+	int bytes;
196 197
 	socklen_t su_len;
197 198
 
198 199
 	/*init */
... ...
@@ -271,8 +272,23 @@ void tcp_main_loop()
271 271
 		for (r=0; r<tcp_children_no && n; r++){
272 272
 			if (FD_ISSET(tcp_children[r].s, &sel_set)){
273 273
 				n--;
274
-				/* errno==EINTR !!! todo*/
275
-				read(tcp_children[r].s, response, sizeof(response));
274
+				/* errno==EINTR !!! TODO*/
275
+read_again:
276
+				bytes=read(tcp_children[r].s, response, sizeof(response));
277
+				if (bytes==0){
278
+					/* EOF -> bad, chidl has died */
279
+					LOG(L_CRIT, "BUG: tcp_main_loop: dead child %d\n", r);
280
+					/* terminating everybody */
281
+					exit(-1);
282
+				}else if (bytes<0){
283
+					if (errno==EINTR) goto read_again;
284
+					else{
285
+						LOG(L_CRIT, "ERROR: tcp_main_loop: read from child: "
286
+								" %s\n", strerror(errno));
287
+						/* try to continue ? */
288
+					}
289
+				}
290
+					
276 291
 				DBG("tcp__main_loop: read response= %lx, %ld\n",
277 292
 						response[0], response[1]);
278 293
 				tcp_children[r].busy=0;
... ...
@@ -40,8 +40,11 @@
40 40
 #include <unistd.h>
41 41
 
42 42
 
43
+#include "dprint.h"
43 44
 #include "tcp_conn.h"
44 45
 #include "pass_fd.h"
46
+#include "globals.h"
47
+#include "receive.h"
45 48
 
46 49
 
47 50
 #define q_memchr memchr
... ...
@@ -80,24 +83,76 @@ again:
80 80
 
81 81
 
82 82
 
83
-/* reads all headers (until double crlf),
83
+/* reads all headers (until double crlf), & parses the content-length header
84
+ * (WARNING: highly ineficient, tries to reuse receive_msg but will parse
85
+ *  all the header names twice [once here & once in receive_msg]; a more
86
+ *  speed eficient version will result in either major code duplication or
87
+ *  major changes to the receive code - TODO)
84 88
  * returns number of bytes read & sets r->state & r->body
85 89
  * when either r->body!=0 or r->state==H_BODY =>
86 90
  * all headers have been read. It should be called in a while loop.
87 91
  * returns < 0 if error or 0 if EOF */
88 92
 int tcp_read_headers(struct tcp_req *r)
89 93
 {
90
-	int bytes;
94
+	int bytes, remaining;
91 95
 	char *p;
92 96
 	
97
+	#define crlf_default_skip_case \
98
+					case '\n': \
99
+						r->state=H_LF; \
100
+						break; \
101
+					default: \
102
+						r->state=H_SKIP
103
+	
104
+	#define content_len_beg_case \
105
+					case ' ': \
106
+					case '\t': \
107
+						if (!r->has_content_len) r->state=H_STARTWS; \
108
+						else r->state=H_SKIP; \
109
+							/* not interested if we already found one */ \
110
+						break; \
111
+					case 'C': \
112
+					case 'c': \
113
+						if(!r->has_content_len) r->state=H_CONT_LEN1; \
114
+						else r->state=H_SKIP; \
115
+						break 
116
+						
117
+	#define change_state(upper, lower, newstate)\
118
+					switch(*p){ \
119
+						case upper: \
120
+						case lower: \
121
+							r->state=(newstate); break; \
122
+						crlf_default_skip_case; \
123
+					}
124
+	
125
+	#define change_state_case(state0, upper, lower, newstate)\
126
+					case state0: \
127
+							  change_state(upper, lower, newstate); \
128
+							  p++; \
129
+							  break
130
+
131
+
132
+	
93 133
 	bytes=tcp_read(r);
94 134
 	if (bytes<=0) return bytes;
95 135
 	p=r->parsed;
96 136
 	
97
-	while(p<r->pos && r->state!=H_BODY){
137
+	while(p<r->pos && r->error==TCP_REQ_OK){
98 138
 		switch(r->state){
99
-			case H_PARSING:
100
-				/* find lf */
139
+			case H_BODY: /* read the body*/
140
+				remaining=r->pos-p;
141
+				if (remaining>r->bytes_to_go) remaining=r->bytes_to_go;
142
+				r->bytes_to_go-=remaining;
143
+				p+=remaining;
144
+				if (r->bytes_to_go==0){
145
+					r->complete=1;
146
+					goto skip;
147
+				}
148
+				break;
149
+				
150
+			case H_SKIP:
151
+				/* find lf, we are in this state if we are not interested
152
+				 * in anything till end of line*/
101 153
 				p=q_memchr(p, '\n', r->pos-r->parsed);
102 154
 				if (p){
103 155
 					p++;
... ...
@@ -109,31 +164,146 @@ int tcp_read_headers(struct tcp_req *r)
109 109
 				
110 110
 			case H_LF:
111 111
 				/* terminate on LF CR LF or LF LF */
112
-				if (*p=='\r'){
113
-					r->state=H_LFCR;
114
-				}else if (*p=='\n'){
115
-					/* found LF LF */
116
-					r->state=H_BODY;
117
-					r->body=p+1;
118
-				}else r->state=H_PARSING;
112
+				switch (*p){
113
+					case '\r':
114
+						r->state=H_LFCR;
115
+						break;
116
+					case '\n':
117
+						/* found LF LF */
118
+						r->state=H_BODY;
119
+						if (r->has_content_len){
120
+							r->body=p+1;
121
+							r->bytes_to_go=r->content_len;
122
+							if (r->bytes_to_go==0){
123
+								r->complete=1;
124
+								goto skip;
125
+							}
126
+						}else{
127
+							r->error=TCP_REQ_BAD_LEN;
128
+						}
129
+						break;
130
+					content_len_beg_case;
131
+					default: 
132
+						r->state=H_SKIP;
133
+				}
119 134
 				p++;
120 135
 				break;
121
-			
122 136
 			case H_LFCR:
123 137
 				if (*p=='\n'){
124 138
 					/* found LF CR LF */
125 139
 					r->state=H_BODY;
126
-					r->body=p+1;
127
-				}else r->state=H_PARSING;
140
+					if (r->has_content_len){
141
+						r->body=p+1;
142
+						r->bytes_to_go=r->content_len;
143
+						if (r->bytes_to_go==0){
144
+							r->complete=1;
145
+							goto skip;
146
+						}
147
+					}else{
148
+						r->error=TCP_REQ_BAD_LEN;
149
+					}
150
+				}else r->state=H_SKIP;
128 151
 				p++;
129 152
 				break;
130 153
 				
154
+			case H_STARTWS:
155
+				switch (*p){
156
+					content_len_beg_case;
157
+					crlf_default_skip_case;
158
+				}
159
+				p++;
160
+				break;
161
+			
162
+			change_state_case(H_CONT_LEN1,  'O', 'o', H_CONT_LEN2);
163
+			change_state_case(H_CONT_LEN2,  'N', 'n', H_CONT_LEN3);
164
+			change_state_case(H_CONT_LEN3,  'T', 't', H_CONT_LEN4);
165
+			change_state_case(H_CONT_LEN4,  'E', 'e', H_CONT_LEN5);
166
+			change_state_case(H_CONT_LEN5,  'N', 'n', H_CONT_LEN6);
167
+			change_state_case(H_CONT_LEN6,  'T', 't', H_CONT_LEN7);
168
+			change_state_case(H_CONT_LEN7,  '-', '_', H_CONT_LEN8);
169
+			change_state_case(H_CONT_LEN8,  'L', 'l', H_CONT_LEN9);
170
+			change_state_case(H_CONT_LEN9,  'E', 'e', H_CONT_LEN10);
171
+			change_state_case(H_CONT_LEN10, 'N', 'n', H_CONT_LEN11);
172
+			change_state_case(H_CONT_LEN11, 'G', 'g', H_CONT_LEN12);
173
+			change_state_case(H_CONT_LEN12, 'T', 't', H_CONT_LEN13);
174
+			change_state_case(H_CONT_LEN13, 'H', 'h', H_L_COLON);
175
+			
176
+			case H_L_COLON:
177
+				switch(*p){
178
+					case ' ':
179
+					case '\t':
180
+						break; /* skip space */
181
+					case ':':
182
+						r->state=H_CONT_LEN_BODY;
183
+						break;
184
+					crlf_default_skip_case;
185
+				};
186
+				p++;
187
+				break;
188
+			
189
+			case  H_CONT_LEN_BODY:
190
+				switch(*p){
191
+					case ' ':
192
+					case '\t':
193
+						break; /* eat space */
194
+					case '0':
195
+					case '1':
196
+					case '2':
197
+					case '3':
198
+					case '4':
199
+					case '5':
200
+					case '6':
201
+					case '7':
202
+					case '8':
203
+					case '9':
204
+						r->state=H_CONT_LEN_BODY_PARSE;
205
+						r->content_len=(*p-'0');
206
+						break;
207
+					/*FIXME: content lenght on different lines ! */
208
+					crlf_default_skip_case;
209
+				}
210
+				p++;
211
+				break;
212
+				
213
+			case H_CONT_LEN_BODY_PARSE:
214
+				switch(*p){
215
+					case '0':
216
+					case '1':
217
+					case '2':
218
+					case '3':
219
+					case '4':
220
+					case '5':
221
+					case '6':
222
+					case '7':
223
+					case '8':
224
+						r->content_len=r->content_len*10+(*p-'0');
225
+						break;
226
+					case '\r':
227
+					case ' ':
228
+					case '\t': /* FIXME: check if line contains only WS */
229
+						r->state=H_SKIP;
230
+						r->has_content_len=1;
231
+						break;
232
+					case '\n':
233
+						/* end of line, parse succesfull */
234
+						r->state=H_LF;
235
+						r->has_content_len=1;
236
+						break;
237
+					default:
238
+						LOG(L_ERR, "ERROR: tcp_read_headers: bad "
239
+								"Content-Length header value, unexpected "
240
+								"char %c in state %d\n", *p, r->state);
241
+						r->state=H_SKIP; /* try to find another?*/
242
+				}
243
+				p++;
244
+				break;
245
+			
131 246
 			default:
132 247
 				fprintf(stderr, "BUG: unexpected state %d\n", r->state);
133 248
 				abort();
134 249
 		}
135 250
 	}
136
-	
251
+skip:
137 252
 	r->parsed=p;
138 253
 	return bytes;
139 254
 }
... ...
@@ -184,7 +354,7 @@ void tcp_receive_loop(int unix_sock)
184 184
 		
185 185
 		
186 186
 	again:
187
-		while(req.body==0){
187
+		while(req.complete==0 && req.error==TCP_REQ_OK){
188 188
 			bytes=tcp_read_headers(&req);
189 189
 			/* if timeout state=0; goto end__req; */
190 190
 			fprintf(stderr, "read= %d bytes, parsed=%d, state=%d, error=%d\n",
... ...
@@ -201,17 +371,31 @@ void tcp_receive_loop(int unix_sock)
201 201
 			}
202 202
 
203 203
 		}
204
+		if (req.error!=TCP_REQ_OK){
205
+			fprintf(stderr, "bad request, state=%d, error=%d\n",
206
+					req.state, req.error);
207
+			state=-1;
208
+			goto end_req;
209
+		}
204 210
 		fprintf(stderr, "end of header part\n");
205 211
 		fprintf(stderr, "headers:\n%.*s.\n",req.body-req.buf, req.buf);
212
+		if (req.has_content_len){
213
+			fprintf(stderr, "content-length= %d\n", req.content_len);
214
+			fprintf(stderr, "body:\n%.*s\n", req.content_len, req.body);
215
+		}else{
216
+			req.error=TCP_REQ_BAD_LEN;
217
+			fprintf(stderr, "content length not present or unparsable\n");
218
+			state=-1;
219
+			goto end_req;
220
+		}
206 221
 
207
-		/* just debugging*/
222
+		/* if we are here everything is nice and ok*/
208 223
 		state=0;
209
-		goto end_req;
210
-		/* parse headers ... */
211
-		
212
-		/* get body */
213
-		
214
-		/* copy request */
224
+		/* just for debugging use sendipv4 as receiving socket */
225
+		DBG("calling receive_msg(%p, %d, %p)\n",
226
+				req.buf, (int)(req.parsed-req.buf), &sendipv4->su);
227
+		bind_address=sendipv4;
228
+		receive_msg(req.buf, req.parsed-req.buf, &sendipv4->su);
215 229
 
216 230
 		/* prepare for next request */
217 231
 		size=req.pos-req.body;
... ...
@@ -221,7 +405,9 @@ void tcp_receive_loop(int unix_sock)
221 221
 		req.parsed=req.buf;
222 222
 		req.body=0;
223 223
 		req.error=TCP_REQ_OK;
224
-		req.state=H_PARSING;
224
+		req.state=H_STARTWS;
225
+		req.complete=req.content_len=req.has_content_len=0;
226
+		req.bytes_to_go=0;
225 227
 	
226 228
 		/* process last req. */
227 229