]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - contrib/serf/buckets/iovec_buckets.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / contrib / serf / buckets / iovec_buckets.c
1 /* Copyright 2011 Justin Erenkrantz and Greg Stein
2  *
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15
16 #include <apr_pools.h>
17
18 #include "serf.h"
19 #include "serf_bucket_util.h"
20
21
22 typedef struct {
23     struct iovec *vecs;
24
25     /* Total number of buffer stored in the vecs var. */
26     int vecs_len;
27     /* Points to the first unread buffer. */
28     int current_vec;
29     /* First buffer offset. */
30     int offset;
31 } iovec_context_t;
32
33 serf_bucket_t *serf_bucket_iovec_create(
34     struct iovec vecs[],
35     int len,
36     serf_bucket_alloc_t *allocator)
37 {
38     iovec_context_t *ctx;
39     int i;
40
41     ctx = serf_bucket_mem_alloc(allocator, sizeof(*ctx));
42     ctx->vecs = serf_bucket_mem_alloc(allocator, len * sizeof(struct iovec));
43     ctx->vecs_len = len;
44     ctx->current_vec = 0;
45     ctx->offset = 0;
46
47     /* copy all buffers to our iovec. */
48     for (i = 0; i < len; i++) {
49         ctx->vecs[i].iov_base = vecs[i].iov_base;
50         ctx->vecs[i].iov_len = vecs[i].iov_len;
51     }
52
53     return serf_bucket_create(&serf_bucket_type_iovec, allocator, ctx);
54 }
55
56 static apr_status_t serf_iovec_readline(serf_bucket_t *bucket,
57                                          int acceptable, int *found,
58                                          const char **data, apr_size_t *len)
59 {
60     return APR_ENOTIMPL;
61 }
62
63 static apr_status_t serf_iovec_read_iovec(serf_bucket_t *bucket,
64                                           apr_size_t requested,
65                                           int vecs_size,
66                                           struct iovec *vecs,
67                                           int *vecs_used)
68 {
69     iovec_context_t *ctx = bucket->data;
70
71     *vecs_used = 0;
72
73     /* copy the requested amount of buffers to the provided iovec. */
74     for (; ctx->current_vec < ctx->vecs_len; ctx->current_vec++) {
75         struct iovec vec = ctx->vecs[ctx->current_vec];
76         apr_size_t remaining;
77
78         if (requested != SERF_READ_ALL_AVAIL && requested <= 0)
79             break;
80         if (*vecs_used >= vecs_size)
81             break;
82
83         vecs[*vecs_used].iov_base = (char*)vec.iov_base + ctx->offset;
84         remaining = vec.iov_len - ctx->offset;
85
86         /* Less bytes requested than remaining in the current buffer. */
87         if (requested != SERF_READ_ALL_AVAIL && requested < remaining) {
88             vecs[*vecs_used].iov_len = requested;
89             ctx->offset += requested;
90             requested = 0;
91             (*vecs_used)++;
92             break;
93         } else {
94             /* Copy the complete buffer. */
95             vecs[*vecs_used].iov_len = remaining;
96             ctx->offset = 0;
97             if (requested != SERF_READ_ALL_AVAIL)
98                 requested -= remaining;
99             (*vecs_used)++;
100         }
101     }
102
103     if (ctx->current_vec == ctx->vecs_len && !ctx->offset)
104         return APR_EOF;
105
106     return APR_SUCCESS;
107 }
108
109 static apr_status_t serf_iovec_read(serf_bucket_t *bucket,
110                                     apr_size_t requested,
111                                     const char **data, apr_size_t *len)
112 {
113     struct iovec vec[1];
114     apr_status_t status;
115     int vecs_used;
116
117     status = serf_iovec_read_iovec(bucket, requested, 1, vec, &vecs_used);
118
119     if (vecs_used) {
120         *data = vec[0].iov_base;
121         *len = vec[0].iov_len;
122     } else {
123         *len = 0;
124     }
125
126     return status;
127 }
128
129 static apr_status_t serf_iovec_peek(serf_bucket_t *bucket,
130                                     const char **data,
131                                     apr_size_t *len)
132 {
133     iovec_context_t *ctx = bucket->data;
134
135     if (ctx->current_vec >= ctx->vecs_len) {
136         *len = 0;
137         return APR_EOF;
138     }
139
140     /* Return the first unread buffer, don't bother combining all
141        remaining data. */
142     *data = ctx->vecs[ctx->current_vec].iov_base;
143     *len = ctx->vecs[ctx->current_vec].iov_len;
144
145     if (ctx->current_vec + 1 == ctx->vecs_len)
146         return APR_EOF;
147
148     return APR_SUCCESS;
149 }
150
151 static void serf_iovec_destroy(serf_bucket_t *bucket)
152 {
153     iovec_context_t *ctx = bucket->data;
154
155     serf_bucket_mem_free(bucket->allocator, ctx->vecs);
156     serf_default_destroy_and_data(bucket);
157 }
158
159
160 const serf_bucket_type_t serf_bucket_type_iovec = {
161     "IOVEC",
162     serf_iovec_read,
163     serf_iovec_readline,
164     serf_iovec_read_iovec,
165     serf_default_read_for_sendfile,
166     serf_default_read_bucket,
167     serf_iovec_peek,
168     serf_iovec_destroy,
169 };