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