iovec_buckets.c revision 302408
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 22typedef 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 33serf_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 56static 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 63static 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 109static 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 129static 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 151static 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 160const 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}; 170