blob: d8a99bff03ab5b883e657e44d0e2beeb95ce0938 [file] [log] [blame]
Willy Tarreaubaaee002006-06-26 02:48:02 +02001/*
2 * Functions operating on SOCK_STREAM and buffers.
3 *
4 * Copyright 2000-2006 Willy Tarreau <w@1wt.eu>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 *
11 */
12
13#include <errno.h>
14#include <fcntl.h>
15#include <stdio.h>
16#include <stdlib.h>
17
18#include <sys/socket.h>
19#include <sys/stat.h>
20#include <sys/types.h>
21
Willy Tarreau2dd0d472006-06-29 17:53:05 +020022#include <common/compat.h>
23#include <common/time.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020024
25#include <types/backend.h>
26#include <types/buffers.h>
27#include <types/global.h>
28#include <types/httperr.h>
29#include <types/polling.h>
30#include <types/proxy.h>
31#include <types/server.h>
32#include <types/session.h>
33
34#include <proto/client.h>
35#include <proto/fd.h>
36#include <proto/log.h>
37#include <proto/proto_http.h>
38#include <proto/stream_sock.h>
39#include <proto/task.h>
40
41
42/*
43 * this function is called on a read event from a client socket.
44 * It returns 0.
45 */
46int event_cli_read(int fd) {
47 struct task *t = fdtab[fd].owner;
48 struct session *s = t->context;
49 struct buffer *b = s->req;
50 int ret, max;
51
52#ifdef DEBUG_FULL
53 fprintf(stderr,"event_cli_read : fd=%d, s=%p\n", fd, s);
54#endif
55
56 if (fdtab[fd].state != FD_STERROR) {
57#ifdef FILL_BUFFERS
58 while (1)
59#else
60 do
61#endif
62 {
63 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
64 b->r = b->w = b->h = b->lr = b->data;
65 max = b->rlim - b->data;
66 }
67 else if (b->r > b->w) {
68 max = b->rlim - b->r;
69 }
70 else {
71 max = b->w - b->r;
72 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
73 * since it means that the rewrite protection has been removed. This
74 * implies that the if statement can be removed.
75 */
76 if (max > b->rlim - b->data)
77 max = b->rlim - b->data;
78 }
79
80 if (max == 0) { /* not anymore room to store data */
81 FD_CLR(fd, StaticReadEvent);
82 break;
83 }
84
85#ifndef MSG_NOSIGNAL
86 {
87 int skerr;
88 socklen_t lskerr = sizeof(skerr);
89
90 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
91 if (skerr)
92 ret = -1;
93 else
94 ret = recv(fd, b->r, max, 0);
95 }
96#else
97 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
98#endif
99 if (ret > 0) {
100 b->r += ret;
101 b->l += ret;
102 s->res_cr = RES_DATA;
103
104 if (b->r == b->data + BUFSIZE) {
105 b->r = b->data; /* wrap around the buffer */
106 }
107
108 b->total += ret;
109 /* we hope to read more data or to get a close on next round */
110 continue;
111 }
112 else if (ret == 0) {
113 s->res_cr = RES_NULL;
114 break;
115 }
116 else if (errno == EAGAIN) {/* ignore EAGAIN */
117 break;
118 }
119 else {
120 s->res_cr = RES_ERROR;
121 fdtab[fd].state = FD_STERROR;
122 break;
123 }
124 } /* while(1) */
125#ifndef FILL_BUFFERS
126 while (0);
127#endif
128 }
129 else {
130 s->res_cr = RES_ERROR;
131 fdtab[fd].state = FD_STERROR;
132 }
133
134 if (s->res_cr != RES_SILENT) {
135 if (s->proxy->clitimeout && FD_ISSET(fd, StaticReadEvent))
136 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
137 else
138 tv_eternity(&s->crexpire);
139
140 task_wakeup(&rq, t);
141 }
142
143 return 0;
144}
145
146
147/*
148 * this function is called on a write event from a client socket.
149 * It returns 0.
150 */
151int event_cli_write(int fd) {
152 struct task *t = fdtab[fd].owner;
153 struct session *s = t->context;
154 struct buffer *b = s->rep;
155 int ret, max;
156
157#ifdef DEBUG_FULL
158 fprintf(stderr,"event_cli_write : fd=%d, s=%p\n", fd, s);
159#endif
160
161 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
162 b->r = b->w = b->h = b->lr = b->data;
163 // max = BUFSIZE; BUG !!!!
164 max = 0;
165 }
166 else if (b->r > b->w) {
167 max = b->r - b->w;
168 }
169 else
170 max = b->data + BUFSIZE - b->w;
171
172 if (fdtab[fd].state != FD_STERROR) {
173 if (max == 0) {
174 s->res_cw = RES_NULL;
175 task_wakeup(&rq, t);
176 tv_eternity(&s->cwexpire);
177 FD_CLR(fd, StaticWriteEvent);
178 return 0;
179 }
180
181#ifndef MSG_NOSIGNAL
182 {
183 int skerr;
184 socklen_t lskerr = sizeof(skerr);
185
186 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
187 if (skerr)
188 ret = -1;
189 else
190 ret = send(fd, b->w, max, MSG_DONTWAIT);
191 }
192#else
193 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
194#endif
195
196 if (ret > 0) {
197 b->l -= ret;
198 b->w += ret;
199
200 s->res_cw = RES_DATA;
201
202 if (b->w == b->data + BUFSIZE) {
203 b->w = b->data; /* wrap around the buffer */
204 }
205 }
206 else if (ret == 0) {
207 /* nothing written, just make as if we were never called */
208 // s->res_cw = RES_NULL;
209 return 0;
210 }
211 else if (errno == EAGAIN) /* ignore EAGAIN */
212 return 0;
213 else {
214 s->res_cw = RES_ERROR;
215 fdtab[fd].state = FD_STERROR;
216 }
217 }
218 else {
219 s->res_cw = RES_ERROR;
220 fdtab[fd].state = FD_STERROR;
221 }
222
223 if (s->proxy->clitimeout) {
224 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
225 /* FIXME: to prevent the client from expiring read timeouts during writes,
226 * we refresh it. A solution would be to merge read+write timeouts into a
227 * unique one, although that needs some study particularly on full-duplex
228 * TCP connections. */
229 s->crexpire = s->cwexpire;
230 }
231 else
232 tv_eternity(&s->cwexpire);
233
234 task_wakeup(&rq, t);
235 return 0;
236}
237
238
239/*
240 * this function is called on a read event from a server socket.
241 * It returns 0.
242 */
243int event_srv_read(int fd) {
244 struct task *t = fdtab[fd].owner;
245 struct session *s = t->context;
246 struct buffer *b = s->rep;
247 int ret, max;
248
249#ifdef DEBUG_FULL
250 fprintf(stderr,"event_srv_read : fd=%d, s=%p\n", fd, s);
251#endif
252
253 if (fdtab[fd].state != FD_STERROR) {
254#ifdef FILL_BUFFERS
255 while (1)
256#else
257 do
258#endif
259 {
260 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
261 b->r = b->w = b->h = b->lr = b->data;
262 max = b->rlim - b->data;
263 }
264 else if (b->r > b->w) {
265 max = b->rlim - b->r;
266 }
267 else {
268 max = b->w - b->r;
269 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
270 * since it means that the rewrite protection has been removed. This
271 * implies that the if statement can be removed.
272 */
273 if (max > b->rlim - b->data)
274 max = b->rlim - b->data;
275 }
276
277 if (max == 0) { /* not anymore room to store data */
278 FD_CLR(fd, StaticReadEvent);
279 break;
280 }
281
282#ifndef MSG_NOSIGNAL
283 {
284 int skerr;
285 socklen_t lskerr = sizeof(skerr);
286
287 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
288 if (skerr)
289 ret = -1;
290 else
291 ret = recv(fd, b->r, max, 0);
292 }
293#else
294 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
295#endif
296 if (ret > 0) {
297 b->r += ret;
298 b->l += ret;
299 s->res_sr = RES_DATA;
300
301 if (b->r == b->data + BUFSIZE) {
302 b->r = b->data; /* wrap around the buffer */
303 }
304
305 b->total += ret;
306 /* we hope to read more data or to get a close on next round */
307 continue;
308 }
309 else if (ret == 0) {
310 s->res_sr = RES_NULL;
311 break;
312 }
313 else if (errno == EAGAIN) {/* ignore EAGAIN */
314 break;
315 }
316 else {
317 s->res_sr = RES_ERROR;
318 fdtab[fd].state = FD_STERROR;
319 break;
320 }
321 } /* while(1) */
322#ifndef FILL_BUFFERS
323 while (0);
324#endif
325 }
326 else {
327 s->res_sr = RES_ERROR;
328 fdtab[fd].state = FD_STERROR;
329 }
330
331 if (s->res_sr != RES_SILENT) {
332 if (s->proxy->srvtimeout && FD_ISSET(fd, StaticReadEvent))
333 tv_delayfrom(&s->srexpire, &now, s->proxy->srvtimeout);
334 else
335 tv_eternity(&s->srexpire);
336
337 task_wakeup(&rq, t);
338 }
339
340 return 0;
341}
342
343
344/*
345 * this function is called on a write event from a server socket.
346 * It returns 0.
347 */
348int event_srv_write(int fd) {
349 struct task *t = fdtab[fd].owner;
350 struct session *s = t->context;
351 struct buffer *b = s->req;
352 int ret, max;
353
354#ifdef DEBUG_FULL
355 fprintf(stderr,"event_srv_write : fd=%d, s=%p\n", fd, s);
356#endif
357
358 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
359 b->r = b->w = b->h = b->lr = b->data;
360 // max = BUFSIZE; BUG !!!!
361 max = 0;
362 }
363 else if (b->r > b->w) {
364 max = b->r - b->w;
365 }
366 else
367 max = b->data + BUFSIZE - b->w;
368
369 if (fdtab[fd].state != FD_STERROR) {
370 if (max == 0) {
371 /* may be we have received a connection acknowledgement in TCP mode without data */
372 if (s->srv_state == SV_STCONN) {
373 int skerr;
374 socklen_t lskerr = sizeof(skerr);
375 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
376 if (skerr) {
377 s->res_sw = RES_ERROR;
378 fdtab[fd].state = FD_STERROR;
379 task_wakeup(&rq, t);
380 tv_eternity(&s->swexpire);
381 FD_CLR(fd, StaticWriteEvent);
382 return 0;
383 }
384 }
385
386 s->res_sw = RES_NULL;
387 task_wakeup(&rq, t);
388 fdtab[fd].state = FD_STREADY;
389 tv_eternity(&s->swexpire);
390 FD_CLR(fd, StaticWriteEvent);
391 return 0;
392 }
393
394#ifndef MSG_NOSIGNAL
395 {
396 int skerr;
397 socklen_t lskerr = sizeof(skerr);
398 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
399 if (skerr)
400 ret = -1;
401 else
402 ret = send(fd, b->w, max, MSG_DONTWAIT);
403 }
404#else
405 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
406#endif
407 fdtab[fd].state = FD_STREADY;
408 if (ret > 0) {
409 b->l -= ret;
410 b->w += ret;
411
412 s->res_sw = RES_DATA;
413
414 if (b->w == b->data + BUFSIZE) {
415 b->w = b->data; /* wrap around the buffer */
416 }
417 }
418 else if (ret == 0) {
419 /* nothing written, just make as if we were never called */
420 // s->res_sw = RES_NULL;
421 return 0;
422 }
423 else if (errno == EAGAIN) /* ignore EAGAIN */
424 return 0;
425 else {
426 s->res_sw = RES_ERROR;
427 fdtab[fd].state = FD_STERROR;
428 }
429 }
430 else {
431 s->res_sw = RES_ERROR;
432 fdtab[fd].state = FD_STERROR;
433 }
434
435 /* We don't want to re-arm read/write timeouts if we're trying to connect,
436 * otherwise it could loop indefinitely !
437 */
438 if (s->srv_state != SV_STCONN) {
439 if (s->proxy->srvtimeout) {
440 tv_delayfrom(&s->swexpire, &now, s->proxy->srvtimeout);
441 /* FIXME: to prevent the server from expiring read timeouts during writes,
442 * we refresh it. A solution would be to merge read+write+connect timeouts
443 * into a unique one since we don't mind expiring on read or write, and none
444 * of them is enabled while waiting for connect(), although that needs some
445 * study particularly on full-duplex TCP connections. */
446 s->srexpire = s->swexpire;
447 }
448 else
449 tv_eternity(&s->swexpire);
450 }
451
452 task_wakeup(&rq, t);
453 return 0;
454}
455
456
457/*
458 * Local variables:
459 * c-indent-level: 8
460 * c-basic-offset: 8
461 * End:
462 */