↑ 1 #include <string.h>
↑ 2 #include <stdlib.h>
↑ 3 #include <errno.h>
↑ 4 #include <stdio.h>
↑ 5 #include <sys/sendfile.h>
↑ 6 #include <sys/uio.h>
↑ 7 #include "rh_bitset.h"
↑ 8 #include "rh_chunk.h"
↑ 9
↑ 10 static int rh_chunk_write_iovec (rh_chunk_t *chunk, int fd,
↑ 11 struct rh_chunk_entry *entry);
↑ 12
↑ 13 static int rh_chunk_write_file (rh_chunk_t *chunk, int fd,
↑ 14 struct rh_chunk_entry *entry);
↑ 15
↑ 16 static void rh_chunk_destroy_iovec (rh_chunk_t *chunk,
↑ 17 struct rh_chunk_entry *entry);
↑ 18
↑ 19 int rh_chunk_done (rh_chunk_t *chunk)
↑ 20 {
↑ 21 return (NULL == TAILQ_FIRST(&chunk->list));
↑ 22 }
↑ 23
↑ 24 void rh_chunk_init (rh_chunk_t *chunk)
↑ 25 {
↑ 26 memset (chunk, 0, sizeof(*chunk));
↑ 27
↑ 28 TAILQ_INIT(&chunk->list);
↑ 29 }
↑ 30
↑ 31 void rh_chunk_destroy (rh_chunk_t *chunk)
↑ 32 {
↑ 33 for (;;) {
↑ 34 struct rh_chunk_entry *entry;
↑ 35 struct rh_chunk_entry_file *file;
↑ 36
↑ 37 entry = TAILQ_FIRST(&chunk->list);
↑ 38 if (NULL == entry)
↑ 39 break;
↑ 40
↑ 41 switch (entry->type) {
↑ 42 case RH_CHUNK_ENTRY_IOVEC:
↑ 43 rh_chunk_destroy_iovec (chunk, entry);
↑ 44 break;
↑ 45
↑ 46 case RH_CHUNK_ENTRY_FILE:
↑ 47 file = entry->data.file;
↑ 48
↑ 49 TAILQ_REMOVE(&chunk->list, entry, list);
↑ 50
↑ 51 if (file->cb && file->cb_arg)
↑ 52 file->cb(file->cb_arg);
↑ 53
↑ 54 free (file);
↑ 55 free (entry);
↑ 56
↑ 57 break;
↑ 58
↑ 59 default:
↑ 60
↑ 61 TAILQ_REMOVE(&chunk->list, entry, list);
↑ 62 free (entry);
↑ 63
↑ 64 break;
↑ 65 }
↑ 66 }
↑ 67 }
↑ 68
↑ 69 void rh_chunk_reset (rh_chunk_t *chunk)
↑ 70 {
↑ 71 rh_chunk_destroy (chunk);
↑ 72 rh_chunk_init (chunk);
↑ 73 }
↑ 74
↑ 75 ssize_t rh_chunk_write (rh_chunk_t *chunk, int fd)
↑ 76 {
↑ 77 size_t bytes;
↑ 78
↑ 79 bytes = chunk->size_out;
↑ 80
↑ 81 for (;;) {
↑ 82 struct rh_chunk_entry *entry;
↑ 83
↑ 84 entry = TAILQ_FIRST(&chunk->list);
↑ 85 if (NULL == entry)
↑ 86 break;
↑ 87
↑ 88 switch (entry->type) {
↑ 89 case RH_CHUNK_ENTRY_UNKNOWN:
↑ 90 break;
↑ 91
↑ 92 case RH_CHUNK_ENTRY_IOVEC:
↑ 93 if (0 != rh_chunk_write_iovec (chunk, fd, entry))
↑ 94 return -1;
↑ 95
↑ 96 break;
↑ 97 case RH_CHUNK_ENTRY_FILE:
↑ 98 if (0 != rh_chunk_write_file (chunk, fd, entry))
↑ 99 return -1;
↑100 break;
↑101 }
↑102
↑103 }
↑104
↑105 return (chunk->size_out - bytes);
↑106 }
↑107
↑108 int rh_chunk_append_uint (struct rh_chunk *chunk, size_t len)
↑109 {
↑110 char *len_str, *ptr;
↑111 int len_nstr;
↑112
↑113 len_str = malloc(32);
↑114 if (NULL == len_str)
↑115 return -1;
↑116
↑117 ptr = len_str + 31;
↑118 if (0 == len) {
↑119 *ptr-- = '0';
↑120 } else {
↑121 for (; len; len/=10)
↑122 *ptr-- = '0' + (len % 10);
↑123 }
↑124
↑125 len_nstr = (len_str + 31) - ptr;
↑126
↑127 if (-1 == rh_chunk_append_buffer (chunk,
↑128 ptr+1, len_nstr, free, len_str)) {
↑129 free (len_str);
↑130 return -1;
↑131 }
↑132
↑133 return 0;
↑134 }
↑135
↑136 int rh_chunk_append_buffer (rh_chunk_t *chunk,
↑137 void *src, size_t nsrc,
↑138 void (*cb)(void *), void *cb_arg)
↑139 {
↑140 struct rh_chunk_entry *entry;
↑141 struct rh_chunk_entry_iovec *iovec;
↑142
↑143 entry = TAILQ_LAST(&chunk->list, rh_chunk_list);
↑144
↑145 if ( NULL != entry &&
↑146 entry->type == RH_CHUNK_ENTRY_IOVEC &&
↑147 entry->data.iovec->used < RH_CHUNK_IOVEC_SZ)
↑148 {
↑149 iovec = entry->data.iovec;
↑150 } else {
↑151 entry = malloc (sizeof(*entry));
↑152 if (NULL == entry)
↑153 return -1;
↑154
↑155 iovec = malloc (sizeof(*iovec));
↑156 if (NULL == iovec) {
↑157 free (entry);
↑158 return -1;
↑159 }
↑160
↑161 entry->type = RH_CHUNK_ENTRY_IOVEC;
↑162 entry->data.iovec = iovec;
↑163 iovec->used = 0;
↑164 iovec->offset = 0;
↑165 iovec->size = 0;
↑166
↑167 TAILQ_INSERT_TAIL(&chunk->list, entry, list);
↑168 }
↑169
↑170 iovec->vec[iovec->used].iov_base = src;
↑171 iovec->vec[iovec->used].iov_len = nsrc;
↑172
↑173 iovec->cb[iovec->used] = cb;
↑174 iovec->cb_arg[iovec->used] = cb_arg;
↑175
↑176 ++iovec->used;
↑177
↑178 iovec->size += nsrc;
↑179
↑180 chunk->size_in += nsrc;
↑181
↑182 return 0;
↑183 }
↑184
↑185 static void rh_chunk_destroy_iovec (rh_chunk_t *chunk,
↑186 struct rh_chunk_entry *entry)
↑187 {
↑188 struct rh_chunk_entry_iovec *iovec;
↑189 unsigned short i;
↑190
↑191 TAILQ_REMOVE(&chunk->list, entry, list);
↑192
↑193 iovec = entry->data.iovec;
↑194
↑195 for (i=iovec->offset; i<iovec->used; ++i) {
↑196 if ( NULL == iovec->cb[i] ||
↑197 NULL == iovec->cb_arg[i])
↑198 {
↑199 continue;
↑200 }
↑201
↑202 iovec->cb[i] (iovec->cb_arg[i]);
↑203 iovec->cb[i] = NULL;
↑204
↑205 }
↑206 iovec->used = 0;
↑207
↑208 free (iovec);
↑209 free (entry);
↑210
↑211 }
↑212
↑213 static int rh_chunk_write_iovec (rh_chunk_t *chunk, int fd,
↑214 struct rh_chunk_entry *entry)
↑215 {
↑216 struct rh_chunk_entry_iovec *iovec;
↑217 ssize_t wrote;
↑218 size_t wrote_recalc;
↑219 unsigned short i;
↑220
↑221 iovec = entry->data.iovec;
↑222
↑223 wrote = writev (fd, &iovec->vec[iovec->offset],
↑224 iovec->used - iovec->offset);
↑225
↑226 if (wrote < 1)
↑227 return -1;
↑228
↑229 iovec->size -= wrote;
↑230 chunk->size_out += wrote;
↑231 wrote_recalc = wrote;
↑232
↑233 for (i=iovec->offset; i<iovec->used; ++i) {
↑234 iovec->offset = i;
↑235
↑236 if (wrote_recalc >= iovec->vec[i].iov_len) {
↑237 wrote_recalc -= iovec->vec[i].iov_len;
↑238
↑239 if ( NULL != iovec->cb[i] &&
↑240 NULL != iovec->cb_arg[i])
↑241 {
↑242 iovec->cb[i] (iovec->cb_arg[i]);
↑243 iovec->cb[i] = NULL;
↑244 }
↑245
↑246 continue;
↑247 }
↑248
↑249 iovec->vec[i].iov_len -= wrote_recalc;
↑250 iovec->vec[i].iov_base = ((char*)iovec->vec[i].iov_base) + wrote_recalc;
↑251 return -1;
↑252 }
↑253
↑254 TAILQ_REMOVE(&chunk->list, entry, list);
↑255 free (iovec);
↑256 free (entry);
↑257
↑258 return 0;
↑259 }
↑260
↑261 /*
↑262 *
↑263 *
↑264 *
↑265 *
↑266 *
↑267 *
↑268 * file
↑269 *
↑270 *
↑271 *
↑272 *
↑273 *
↑274 *
↑275 *
↑276 *
↑277 */
↑278
↑279 int rh_chunk_append_file (rh_chunk_t *chunk,
↑280 int fd, off_t offset, size_t size,
↑281 void (*cb)(void *), void *cb_arg)
↑282 {
↑283 struct rh_chunk_entry *entry;
↑284 struct rh_chunk_entry_file *file;
↑285
↑286 entry = malloc (sizeof(*entry));
↑287 if (NULL == entry)
↑288 return -1;
↑289
↑290 file = malloc (sizeof(*file));
↑291 if (NULL == file) {
↑292 free (entry);
↑293 return -1;
↑294 }
↑295
↑296 entry->type = RH_CHUNK_ENTRY_FILE;
↑297 entry->data.file = file;
↑298
↑299 file->fd = fd;
↑300 file->offset = offset;
↑301 file->size = size;
↑302 file->cb = cb;
↑303 file->cb_arg = cb_arg;
↑304
↑305 chunk->size_in += size;
↑306
↑307 TAILQ_INSERT_TAIL(&chunk->list, entry, list);
↑308
↑309 return 0;
↑310 }
↑311
↑312 static int rh_chunk_write_file (rh_chunk_t *chunk, int fd,
↑313 struct rh_chunk_entry *entry)
↑314 {
↑315 struct rh_chunk_entry_file *file = entry->data.file;
↑316
↑317 while (file->size) {
↑318 ssize_t bytes;
↑319 #if 0
↑320 printf ("sendfile: fd(%d) off(%llu) size(%zu)\n",
↑321 file->fd,
↑322 file->offset, file->size);
↑323 #endif
↑324
↑325 bytes = sendfile (fd, file->fd, &(file->offset), file->size);
↑326
↑327 #if 0
↑328 printf (" %zd bytes\n", bytes);
↑329 #endif
↑330
↑331 if (bytes < 1)
↑332 return -1;
↑333
↑334 chunk->size_out += bytes;
↑335
↑336 if (file->size > bytes) {
↑337 file->size -= bytes;
↑338 } else {
↑339 file->size = 0;
↑340 }
↑341 }
↑342
↑343 TAILQ_REMOVE(&chunk->list, entry, list);
↑344
↑345 if (file->cb && file->cb_arg)
↑346 file->cb(file->cb_arg);
↑347
↑348 free (file);
↑349 free (entry);
↑350
↑351 return 0;
↑352 }
syntax highlighted by Code2HTML, v. 0.9.1