forked from mongrel2/mongrel2
/
bsd_specific.c
127 lines (106 loc) · 3.9 KB
/
bsd_specific.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
/**
*
* Copyright (c) 2010, Zed A. Shaw and Mongrel2 Project Contributors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of the Mongrel2 Project, Zed A. Shaw, nor the names
* of its contributors may be used to endorse or promote products
* derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stddef.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <task/task.h>
#include <dbg.h>
#if defined(__APPLE__) || defined(__FreeBSD__)
/**
* BSD version of sendfile, which is OSX and FreeBSD mostly.
*/
int bsd_sendfile(int out_fd, int in_fd, off_t *offset, size_t count) {
off_t my_count = count;
int rc;
// We have to do this loop nastiness, because mac os x fails with resource
// temporarily unavailable (per bug e8eddb51a8)
do {
fdwait(out_fd, 'w');
#if defined(__APPLE__)
rc = sendfile(in_fd, out_fd, *offset, &my_count, NULL, 0);
#elif defined(__FreeBSD__)
rc = sendfile(in_fd, out_fd, *offset, count, NULL, &my_count, 0);
#endif
*offset += my_count;
} while(rc != 0 && errno == 35);
check(rc == 0, "OS X sendfile wrapper failed");
return my_count;
error:
return -1;
}
#else
extern int fdrecv(int fd, void *buf, int n);
extern int fdsend(int fd, void *buf, int n);
#define BSD_SENDFILE_BUF_SIZE 16384
#include <unistd.h>
/** For the BSDs without sendfile like open and net.**/
int bsd_sendfile(int out_fd, int in_fd, off_t *offset, size_t count) {
char buf[BSD_SENDFILE_BUF_SIZE];
int ret = -1;
off_t orig_offset = 0;
int cur = 0;
int rem = count;
int sent = 0;
size_t tot = 0;
check(rem > 0, "Possible integer overflow in count.");
if (offset != NULL) {
orig_offset = lseek(in_fd, 0, SEEK_CUR);
check(orig_offset >= 0, "lseek failure when determining current position");
check(lseek(in_fd, *offset, SEEK_SET) >= 0, "lseek failure when setting new position");
}
for (tot = 0, rem = count, cur = rem; cur != 0 && tot < count; tot += cur, rem -= cur) {
if (rem >= BSD_SENDFILE_BUF_SIZE) {
cur = BSD_SENDFILE_BUF_SIZE;
} else {
cur = rem;
}
cur = fdread(in_fd, buf, cur);
check(cur >= 0, "Internal sendfile emulation failed: fdread: %i", cur);
if (cur != 0) {
sent = fdwrite(out_fd, buf, cur);
check(sent == cur, "Internal sendfile emulation failed: fdread: %i, fdwrite: %i", cur, sent);
}
}
ret = tot;
error:
if (offset != NULL) {
if (ret != -1) {
*offset += tot;
}
lseek(in_fd, orig_offset, SEEK_SET);
}
return ret;
}
#endif