Skip to content

Commit 61e16cc

Browse files
committed
Review error handling in I/O wrappers
Some of these were subtly broken. Make them hopefully less broken(?)
1 parent 6be4831 commit 61e16cc

File tree

1 file changed

+83
-83
lines changed

1 file changed

+83
-83
lines changed

src/lib/lwan-io-wrappers.c

+83-83
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,10 @@
3131

3232
static const int MAX_FAILED_TRIES = 5;
3333

34-
ssize_t
35-
lwan_writev_fd(struct lwan_request *request, int fd, struct iovec *iov, int iov_count)
34+
ssize_t lwan_writev_fd(struct lwan_request *request,
35+
int fd,
36+
struct iovec *iov,
37+
int iov_count)
3638
{
3739
ssize_t total_written = 0;
3840
int curr_iov = 0;
@@ -44,7 +46,8 @@ lwan_writev_fd(struct lwan_request *request, int fd, struct iovec *iov, int iov_
4446

4547
if (remaining_len == 1) {
4648
const struct iovec *vec = &iov[curr_iov];
47-
return lwan_send_fd(request, fd, vec->iov_base, vec->iov_len, flags);
49+
return lwan_send_fd(request, fd, vec->iov_base, vec->iov_len,
50+
flags);
4851
}
4952

5053
struct msghdr hdr = {
@@ -60,35 +63,36 @@ lwan_writev_fd(struct lwan_request *request, int fd, struct iovec *iov, int iov_
6063
switch (errno) {
6164
case EAGAIN:
6265
case EINTR:
63-
goto try_again;
66+
break;
6467
default:
6568
return -errno;
6669
}
67-
}
70+
} else {
71+
total_written += written;
6872

69-
total_written += written;
70-
71-
while (curr_iov < iov_count &&
72-
written >= (ssize_t)iov[curr_iov].iov_len) {
73-
written -= (ssize_t)iov[curr_iov].iov_len;
74-
curr_iov++;
75-
}
73+
while (curr_iov < iov_count &&
74+
written >= (ssize_t)iov[curr_iov].iov_len) {
75+
written -= (ssize_t)iov[curr_iov].iov_len;
76+
curr_iov++;
77+
}
7678

77-
if (curr_iov == iov_count)
78-
return total_written;
79+
iov[curr_iov].iov_base = (char *)iov[curr_iov].iov_base + written;
80+
iov[curr_iov].iov_len -= (size_t)written;
7981

80-
iov[curr_iov].iov_base = (char *)iov[curr_iov].iov_base + written;
81-
iov[curr_iov].iov_len -= (size_t)written;
82+
if (curr_iov == iov_count && iov[curr_iov].iov_len == 0)
83+
return total_written;
84+
}
8285

83-
try_again:
8486
lwan_request_await_read(request, fd);
8587
}
8688

8789
return -ETIMEDOUT;
8890
}
8991

90-
ssize_t
91-
lwan_readv_fd(struct lwan_request *request, int fd, struct iovec *iov, int iov_count)
92+
ssize_t lwan_readv_fd(struct lwan_request *request,
93+
int fd,
94+
struct iovec *iov,
95+
int iov_count)
9296
{
9397
ssize_t total_bytes_read = 0;
9498
int curr_iov = 0;
@@ -102,27 +106,27 @@ lwan_readv_fd(struct lwan_request *request, int fd, struct iovec *iov, int iov_c
102106
switch (errno) {
103107
case EAGAIN:
104108
case EINTR:
105-
goto try_again;
109+
break;
106110
default:
107111
return -errno;
108112
}
109-
}
113+
} else {
114+
total_bytes_read += bytes_read;
110115

111-
total_bytes_read += bytes_read;
112-
113-
while (curr_iov < iov_count &&
114-
bytes_read >= (ssize_t)iov[curr_iov].iov_len) {
115-
bytes_read -= (ssize_t)iov[curr_iov].iov_len;
116-
curr_iov++;
117-
}
116+
while (curr_iov < iov_count &&
117+
bytes_read >= (ssize_t)iov[curr_iov].iov_len) {
118+
bytes_read -= (ssize_t)iov[curr_iov].iov_len;
119+
curr_iov++;
120+
}
118121

119-
if (curr_iov == iov_count)
120-
return total_bytes_read;
122+
iov[curr_iov].iov_base =
123+
(char *)iov[curr_iov].iov_base + bytes_read;
124+
iov[curr_iov].iov_len -= (size_t)bytes_read;
121125

122-
iov[curr_iov].iov_base = (char *)iov[curr_iov].iov_base + bytes_read;
123-
iov[curr_iov].iov_len -= (size_t)bytes_read;
126+
if (curr_iov == iov_count && iov[curr_iov].iov_len == 0)
127+
return total_bytes_read;
128+
}
124129

125-
try_again:
126130
lwan_request_await_read(request, fd);
127131
}
128132

@@ -135,32 +139,30 @@ ssize_t lwan_send_fd(struct lwan_request *request,
135139
size_t count,
136140
int flags)
137141
{
138-
ssize_t total_sent = 0;
142+
size_t to_send = count;
139143

140144
if (request->conn->flags & CONN_CORK)
141145
flags |= MSG_MORE;
142146

143147
for (int tries = MAX_FAILED_TRIES; tries;) {
144-
ssize_t written = send(fd, buf, count, flags);
148+
ssize_t written = send(fd, buf, to_send, flags);
145149
if (UNLIKELY(written < 0)) {
146150
tries--;
147151

148152
switch (errno) {
149153
case EAGAIN:
150154
case EINTR:
151-
goto try_again;
155+
break;
152156
default:
153157
return -errno;
154158
}
155-
}
156-
157-
total_sent += written;
158-
if ((size_t)total_sent == count)
159-
return total_sent;
160-
if ((size_t)total_sent < count)
159+
} else {
160+
to_send -= (size_t)written;
161+
if (!to_send)
162+
return count;
161163
buf = (char *)buf + written;
164+
}
162165

163-
try_again:
164166
lwan_request_await_write(request, fd);
165167
}
166168

@@ -170,32 +172,29 @@ ssize_t lwan_send_fd(struct lwan_request *request,
170172
ssize_t
171173
lwan_recv_fd(struct lwan_request *request, int fd, void *buf, size_t count, int flags)
172174
{
173-
ssize_t total_recv = 0;
175+
size_t to_recv = count;
174176

175177
for (int tries = MAX_FAILED_TRIES; tries;) {
176-
ssize_t recvd = recv(fd, buf, count, flags);
178+
ssize_t recvd = recv(fd, buf, to_recv, flags);
177179
if (UNLIKELY(recvd < 0)) {
178180
tries--;
179181

180182
switch (errno) {
183+
case EINTR:
181184
case EAGAIN:
182185
if (flags & MSG_DONTWAIT)
183-
return total_recv;
184-
/* Fallthrough */
185-
case EINTR:
186-
goto try_again;
186+
return count - to_recv;
187+
break;
187188
default:
188189
return -errno;
189190
}
190-
}
191-
192-
total_recv += recvd;
193-
if ((size_t)total_recv == count)
194-
return total_recv;
195-
if ((size_t)total_recv < count)
191+
} else {
192+
to_recv -= (size_t)recvd;
193+
if (!to_recv)
194+
return count;
196195
buf = (char *)buf + recvd;
196+
}
197197

198-
try_again:
199198
lwan_request_await_read(request, fd);
200199
}
201200

@@ -220,8 +219,7 @@ int lwan_sendfile_fd(struct lwan_request *request,
220219
* sent using MSG_MORE. Subsequent chunks are sized 2^21 bytes. (Do
221220
* this regardless of this connection being TLS or not for simplicity.)
222221
*
223-
* [1]
224-
* https://www.kernel.org/doc/html/v5.12/networking/tls.html#sending-tls-application-data
222+
* [1] https://www.kernel.org/doc/html/v5.12/networking/tls.html#sending-tls-application-data
225223
* [2] https://github.com/lpereira/lwan/issues/334
226224
*/
227225
size_t chunk_size = LWAN_MIN(count, (1ul << 21) - header_len);
@@ -236,24 +234,23 @@ int lwan_sendfile_fd(struct lwan_request *request,
236234

237235
while (true) {
238236
ssize_t written = sendfile(out_fd, in_fd, &offset, chunk_size);
239-
if (written < 0) {
237+
if (UNLIKELY(written < 0)) {
240238
switch (errno) {
241239
case EAGAIN:
242240
case EINTR:
243-
goto try_again;
241+
break;
244242
default:
245243
return -errno;
246244
}
247-
}
248-
249-
to_be_written -= (size_t)written;
250-
if (!to_be_written)
251-
return 0;
245+
} else {
246+
to_be_written -= (size_t)written;
247+
if (!to_be_written)
248+
return 0;
252249

253-
chunk_size = LWAN_MIN(to_be_written, 1ul << 21);
254-
lwan_readahead_queue(in_fd, offset, chunk_size);
250+
chunk_size = LWAN_MIN(to_be_written, 1ul << 21);
251+
lwan_readahead_queue(in_fd, offset, chunk_size);
252+
}
255253

256-
try_again:
257254
lwan_request_await_write(request, out_fd);
258255
}
259256
}
@@ -292,39 +289,41 @@ int lwan_sendfile(struct lwan_request *request,
292289
case EAGAIN:
293290
case EBUSY:
294291
case EINTR:
295-
goto try_again;
292+
break;
296293
default:
297294
return -errno;
298295
}
296+
} else {
297+
count -= (size_t)sbytes;
298+
if (!count)
299+
return 0;
299300
}
300301

301-
count -= (size_t)sbytes;
302-
if (!count)
303-
return 0;
304-
305-
try_again:
306302
lwan_request_await_write(request, out_fd);
307303
}
308304
}
309305
#else
310306
static ssize_t try_pread_file(struct lwan_request *request,
311-
int fd,
312-
void *buffer,
313-
size_t len,
314-
off_t offset)
307+
int fd,
308+
void *buffer,
309+
size_t len,
310+
off_t offset)
315311
{
316312
size_t total_read = 0;
317313

318314
for (int tries = MAX_FAILED_TRIES; tries;) {
319315
ssize_t r = pread(fd, buffer, len, offset);
320316

317+
if (r == 0) {
318+
return total_read;
319+
}
321320
if (UNLIKELY(r < 0)) {
322321
tries--;
323322

324323
switch (errno) {
325324
case EAGAIN:
326325
case EINTR:
327-
/* fd is a file, re-read -- but give other coros some time, too */
326+
/* fd is a file, re-read -- but give other coros some time */
328327
coro_yield(request->conn->coro, CONN_CORO_YIELD);
329328
continue;
330329
default:
@@ -333,9 +332,9 @@ static ssize_t try_pread_file(struct lwan_request *request,
333332
}
334333

335334
total_read += (size_t)r;
336-
337-
if (r == 0 || total_read == len)
335+
if (total_read == len) {
338336
return total_read;
337+
}
339338

340339
offset += r;
341340
}
@@ -362,11 +361,12 @@ int lwan_sendfile_fd(struct lwan_request *request,
362361
while (count) {
363362
r = try_pread_file(request, in_fd, buffer,
364363
LWAN_MIN(count, sizeof(buffer)), offset);
365-
if (UNLIKELY(r < 0))
364+
if (UNLIKELY(r <= 0))
366365
return (int)r;
367366

368367
size_t bytes_read = (size_t)r;
369-
r = lwan_send_fd(request, out_fd, buffer, bytes_read, 0);
368+
r = lwan_send_fd(request, out_fd, buffer, bytes_read,
369+
bytes_read < sizeof(buffer) ? 0 : MSG_MORE);
370370
if (UNLIKELY(r < 0))
371371
return (int)r;
372372

0 commit comments

Comments
 (0)