blob: cece0a2092eeeb51f624c7cdb4043ddf6015a25f [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/*
Willy Tarreaud7971282006-07-29 18:36:34 +020044 * this function is called on a read event from a stream socket.
Willy Tarreaubaaee002006-06-26 02:48:02 +020045 * It returns 0.
46 */
Willy Tarreaud7971282006-07-29 18:36:34 +020047int stream_sock_read(int fd) {
Willy Tarreau54469402006-07-29 16:59:06 +020048 struct buffer *b = fdtab[fd].cb[DIR_RD].b;
Willy Tarreaubaaee002006-06-26 02:48:02 +020049 int ret, max;
50
51#ifdef DEBUG_FULL
Willy Tarreaud7971282006-07-29 18:36:34 +020052 fprintf(stderr,"stream_sock_read : fd=%d, owner=%p\n", fd, fdtab[fd].owner);
Willy Tarreaubaaee002006-06-26 02:48:02 +020053#endif
54
55 if (fdtab[fd].state != FD_STERROR) {
56#ifdef FILL_BUFFERS
57 while (1)
58#else
59 do
60#endif
61 {
62 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
63 b->r = b->w = b->h = b->lr = b->data;
64 max = b->rlim - b->data;
65 }
66 else if (b->r > b->w) {
67 max = b->rlim - b->r;
68 }
69 else {
70 max = b->w - b->r;
71 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
72 * since it means that the rewrite protection has been removed. This
73 * implies that the if statement can be removed.
74 */
75 if (max > b->rlim - b->data)
76 max = b->rlim - b->data;
77 }
78
79 if (max == 0) { /* not anymore room to store data */
80 FD_CLR(fd, StaticReadEvent);
81 break;
82 }
83
84#ifndef MSG_NOSIGNAL
85 {
86 int skerr;
87 socklen_t lskerr = sizeof(skerr);
88
89 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
90 if (skerr)
91 ret = -1;
92 else
93 ret = recv(fd, b->r, max, 0);
94 }
95#else
96 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
97#endif
98 if (ret > 0) {
99 b->r += ret;
100 b->l += ret;
Willy Tarreau0f9f5052006-07-29 17:39:25 +0200101 b->flags |= BF_PARTIAL_READ;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200102
103 if (b->r == b->data + BUFSIZE) {
104 b->r = b->data; /* wrap around the buffer */
105 }
106
107 b->total += ret;
108 /* we hope to read more data or to get a close on next round */
109 continue;
110 }
111 else if (ret == 0) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +0200112 b->flags |= BF_READ_NULL;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200113 break;
114 }
115 else if (errno == EAGAIN) {/* ignore EAGAIN */
116 break;
117 }
118 else {
Willy Tarreau0f9f5052006-07-29 17:39:25 +0200119 b->flags |= BF_READ_ERROR;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200120 fdtab[fd].state = FD_STERROR;
121 break;
122 }
123 } /* while(1) */
124#ifndef FILL_BUFFERS
125 while (0);
126#endif
127 }
128 else {
Willy Tarreau0f9f5052006-07-29 17:39:25 +0200129 b->flags |= BF_READ_ERROR;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200130 fdtab[fd].state = FD_STERROR;
131 }
132
Willy Tarreau0f9f5052006-07-29 17:39:25 +0200133 if (b->flags & BF_READ_STATUS) {
Willy Tarreaud7971282006-07-29 18:36:34 +0200134 if (b->rto && FD_ISSET(fd, StaticReadEvent))
135 tv_delayfrom(&b->rex, &now, b->rto);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200136 else
Willy Tarreaud7971282006-07-29 18:36:34 +0200137 tv_eternity(&b->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200138
Willy Tarreaud7971282006-07-29 18:36:34 +0200139 task_wakeup(&rq, fdtab[fd].owner);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200140 }
141
142 return 0;
143}
144
145
146/*
Willy Tarreauf8306d52006-07-29 19:01:31 +0200147 * this function is called on a write event from a stream socket.
Willy Tarreaubaaee002006-06-26 02:48:02 +0200148 * It returns 0.
149 */
Willy Tarreauf8306d52006-07-29 19:01:31 +0200150int stream_sock_write(int fd) {
Willy Tarreau54469402006-07-29 16:59:06 +0200151 struct buffer *b = fdtab[fd].cb[DIR_WR].b;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200152 int ret, max;
153
154#ifdef DEBUG_FULL
Willy Tarreauf8306d52006-07-29 19:01:31 +0200155 fprintf(stderr,"stream_sock_write : fd=%d, owner=%p\n", fd, fdtab[fd].owner);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200156#endif
157
158 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
159 b->r = b->w = b->h = b->lr = b->data;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200160 max = 0;
161 }
162 else if (b->r > b->w) {
163 max = b->r - b->w;
164 }
165 else
166 max = b->data + BUFSIZE - b->w;
167
168 if (fdtab[fd].state != FD_STERROR) {
169 if (max == 0) {
Willy Tarreauf8306d52006-07-29 19:01:31 +0200170 /* may be we have received a connection acknowledgement in TCP mode without data */
171 if (fdtab[fd].state == FD_STCONN) {
172 int skerr;
173 socklen_t lskerr = sizeof(skerr);
174 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
175 if (skerr) {
176 b->flags |= BF_WRITE_ERROR;
177 fdtab[fd].state = FD_STERROR;
178 task_wakeup(&rq, fdtab[fd].owner);
179 tv_eternity(&b->wex);
180 FD_CLR(fd, StaticWriteEvent);
181 return 0;
182 }
183 }
184
Willy Tarreau0f9f5052006-07-29 17:39:25 +0200185 b->flags |= BF_WRITE_NULL;
Willy Tarreauf8306d52006-07-29 19:01:31 +0200186 task_wakeup(&rq, fdtab[fd].owner);
187 fdtab[fd].state = FD_STREADY;
Willy Tarreaud7971282006-07-29 18:36:34 +0200188 tv_eternity(&b->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200189 FD_CLR(fd, StaticWriteEvent);
190 return 0;
191 }
192
193#ifndef MSG_NOSIGNAL
194 {
195 int skerr;
196 socklen_t lskerr = sizeof(skerr);
197
198 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
199 if (skerr)
200 ret = -1;
201 else
202 ret = send(fd, b->w, max, MSG_DONTWAIT);
203 }
204#else
205 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
206#endif
207
208 if (ret > 0) {
209 b->l -= ret;
210 b->w += ret;
211
Willy Tarreau0f9f5052006-07-29 17:39:25 +0200212 b->flags |= BF_PARTIAL_WRITE;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200213
214 if (b->w == b->data + BUFSIZE) {
215 b->w = b->data; /* wrap around the buffer */
216 }
217 }
218 else if (ret == 0) {
Willy Tarreauf8306d52006-07-29 19:01:31 +0200219 /* nothing written, just pretend we were never called */
Willy Tarreau0f9f5052006-07-29 17:39:25 +0200220 // b->flags |= BF_WRITE_NULL;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200221 return 0;
222 }
223 else if (errno == EAGAIN) /* ignore EAGAIN */
224 return 0;
225 else {
Willy Tarreau0f9f5052006-07-29 17:39:25 +0200226 b->flags |= BF_WRITE_ERROR;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200227 fdtab[fd].state = FD_STERROR;
228 }
229 }
230 else {
Willy Tarreau0f9f5052006-07-29 17:39:25 +0200231 b->flags |= BF_WRITE_ERROR;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200232 fdtab[fd].state = FD_STERROR;
233 }
234
Willy Tarreaud7971282006-07-29 18:36:34 +0200235 if (b->wto) {
236 tv_delayfrom(&b->wex, &now, b->wto);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200237 /* FIXME: to prevent the client from expiring read timeouts during writes,
238 * we refresh it. A solution would be to merge read+write timeouts into a
239 * unique one, although that needs some study particularly on full-duplex
240 * TCP connections. */
Willy Tarreaud7971282006-07-29 18:36:34 +0200241 b->rex = b->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200242 }
243 else
Willy Tarreaud7971282006-07-29 18:36:34 +0200244 tv_eternity(&b->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200245
Willy Tarreauf8306d52006-07-29 19:01:31 +0200246 task_wakeup(&rq, fdtab[fd].owner);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200247 return 0;
248}
249
Willy Tarreaubaaee002006-06-26 02:48:02 +0200250
251
252/*
253 * Local variables:
254 * c-indent-level: 8
255 * c-basic-offset: 8
256 * End:
257 */