~ubuntu-branches/ubuntu/natty/lighttpd/natty

« back to all changes in this revision

Viewing changes to src/network_freebsd_sendfile.c

  • Committer: Bazaar Package Importer
  • Author(s): Soren Hansen
  • Date: 2006-12-08 14:40:42 UTC
  • mto: (6.1.1 lenny)
  • mto: This revision was merged to the branch mainline in revision 14.
  • Revision ID: james.westby@ubuntu.com-20061208144042-ehr7h8c6xmijqipw
Tags: upstream-1.4.13
ImportĀ upstreamĀ versionĀ 1.4.13

Show diffs side-by-side

added added

removed removed

Lines of Context:
26
26
 
27
27
#ifndef UIO_MAXIOV
28
28
# ifdef __FreeBSD__
29
 
/* FreeBSD 4.7, 4.9 defined it in sys/uio.h only if _KERNEL is specified */ 
 
29
/* FreeBSD 4.7, 4.9 defined it in sys/uio.h only if _KERNEL is specified */
30
30
#  define UIO_MAXIOV 1024
31
31
# endif
32
32
#endif
34
34
int network_write_chunkqueue_freebsdsendfile(server *srv, connection *con, int fd, chunkqueue *cq) {
35
35
        chunk *c;
36
36
        size_t chunks_written = 0;
37
 
        
 
37
 
38
38
        for(c = cq->first; c; c = c->next, chunks_written++) {
39
39
                int chunk_finished = 0;
40
 
                
 
40
 
41
41
                switch(c->type) {
42
42
                case MEM_CHUNK: {
43
43
                        char * offset;
44
44
                        size_t toSend;
45
45
                        ssize_t r;
46
 
                        
 
46
 
47
47
                        size_t num_chunks, i;
48
48
                        struct iovec chunks[UIO_MAXIOV];
49
49
                        chunk *tc;
50
50
                        size_t num_bytes = 0;
51
 
                        
 
51
 
52
52
                        /* we can't send more then SSIZE_MAX bytes in one chunk */
53
 
                        
54
 
                        /* build writev list 
55
 
                         * 
 
53
 
 
54
                        /* build writev list
 
55
                         *
56
56
                         * 1. limit: num_chunks < UIO_MAXIOV
57
57
                         * 2. limit: num_bytes < SSIZE_MAX
58
58
                         */
59
59
                        for(num_chunks = 0, tc = c; tc && tc->type == MEM_CHUNK && num_chunks < UIO_MAXIOV; num_chunks++, tc = tc->next);
60
 
                        
 
60
 
61
61
                        for(tc = c, i = 0; i < num_chunks; tc = tc->next, i++) {
62
62
                                if (tc->mem->used == 0) {
63
63
                                        chunks[i].iov_base = tc->mem->ptr;
65
65
                                } else {
66
66
                                        offset = tc->mem->ptr + tc->offset;
67
67
                                        toSend = tc->mem->used - 1 - tc->offset;
68
 
                                        
 
68
 
69
69
                                        chunks[i].iov_base = offset;
70
 
                                        
 
70
 
71
71
                                        /* protect the return value of writev() */
72
72
                                        if (toSend > SSIZE_MAX ||
73
73
                                            num_bytes + toSend > SSIZE_MAX) {
74
74
                                                chunks[i].iov_len = SSIZE_MAX - num_bytes;
75
 
                                                
 
75
 
76
76
                                                num_chunks = i + 1;
77
77
                                                break;
78
78
                                        } else {
79
79
                                                chunks[i].iov_len = toSend;
80
80
                                        }
81
 
                                 
 
81
 
82
82
                                        num_bytes += toSend;
83
83
                                }
84
84
                        }
85
 
                        
 
85
 
86
86
                        if ((r = writev(fd, chunks, num_chunks)) < 0) {
87
87
                                switch (errno) {
88
88
                                case EAGAIN:
94
94
                                case ECONNRESET:
95
95
                                        return -2;
96
96
                                default:
97
 
                                        log_error_write(srv, __FILE__, __LINE__, "ssd", 
 
97
                                        log_error_write(srv, __FILE__, __LINE__, "ssd",
98
98
                                                        "writev failed:", strerror(errno), fd);
99
 
                                        
 
99
 
100
100
                                        return -1;
101
101
                                }
102
102
 
103
103
                                r = 0;
104
104
                        }
105
 
                        
 
105
 
106
106
                        /* check which chunks have been written */
107
107
                        cq->bytes_out += r;
108
 
                        
 
108
 
109
109
                        for(i = 0, tc = c; i < num_chunks; i++, tc = tc->next) {
110
110
                                if (r >= (ssize_t)chunks[i].iov_len) {
111
111
                                        /* written */
112
112
                                        r -= chunks[i].iov_len;
113
113
                                        tc->offset += chunks[i].iov_len;
114
 
                                        
 
114
 
115
115
                                        if (chunk_finished) {
116
116
                                                /* skip the chunks from further touches */
117
117
                                                chunks_written++;
122
122
                                        }
123
123
                                } else {
124
124
                                        /* partially written */
125
 
                                        
 
125
 
126
126
                                        tc->offset += r;
127
127
                                        chunk_finished = 0;
128
 
                                        
 
128
 
129
129
                                        break;
130
130
                                }
131
131
                        }
132
 
                        
 
132
 
133
133
                        break;
134
134
                }
135
135
                case FILE_CHUNK: {
137
137
                        size_t toSend;
138
138
                        stat_cache_entry *sce = NULL;
139
139
                        int ifd;
140
 
                        
 
140
 
141
141
                        if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
142
142
                                log_error_write(srv, __FILE__, __LINE__, "sb",
143
143
                                                strerror(errno), c->file.name);
144
144
                                return -1;
145
145
                        }
146
 
                        
 
146
 
147
147
                        offset = c->file.start + c->offset;
148
148
                        /* limit the toSend to 2^31-1 bytes in a chunk */
149
 
                        toSend = c->file.length - c->offset > ((1 << 30) - 1) ? 
 
149
                        toSend = c->file.length - c->offset > ((1 << 30) - 1) ?
150
150
                                ((1 << 30) - 1) : c->file.length - c->offset;
151
 
                                
 
151
 
152
152
                        if (offset > sce->st.st_size) {
153
153
                                log_error_write(srv, __FILE__, __LINE__, "sb", "file was shrinked:", c->file.name);
154
 
                                
 
154
 
155
155
                                return -1;
156
156
                        }
157
 
                        
 
157
 
158
158
                        if (-1 == (ifd = open(c->file.name->ptr, O_RDONLY))) {
159
159
                                log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
160
 
                                
 
160
 
161
161
                                return -1;
162
162
                        }
163
 
                        
 
163
 
164
164
                        r = 0;
165
 
                        
 
165
 
166
166
                        /* FreeBSD sendfile() */
167
167
                        if (-1 == sendfile(ifd, fd, offset, toSend, NULL, &r, 0)) {
168
168
                                switch(errno) {
178
178
                                }
179
179
                        }
180
180
                        close(ifd);
181
 
                        
 
181
 
182
182
                        c->offset += r;
183
183
                        cq->bytes_out += r;
184
 
                        
 
184
 
185
185
                        if (c->offset == c->file.length) {
186
186
                                chunk_finished = 1;
187
187
                        }
188
 
                        
 
188
 
189
189
                        break;
190
190
                }
191
191
                default:
192
 
                        
 
192
 
193
193
                        log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
194
 
                        
 
194
 
195
195
                        return -1;
196
196
                }
197
 
                
 
197
 
198
198
                if (!chunk_finished) {
199
199
                        /* not finished yet */
200
 
                        
 
200
 
201
201
                        break;
202
202
                }
203
203
        }