/* * Three cases to handle: * - buf has data, iocache doesn't. * - iocache has data, buf doesn't. * - both buf and iocache has data. */ int iocache_sendto(iocache *ioc, int fd, char *buf, unsigned int len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen) { int sent; errno = 0; if (!ioc) return -1; if (!ioc->ioc_buflen && !len) return 0; if (ioc->ioc_buf && iocache_available(ioc)) { if (buf && len) { /* copy buf and len to iocache buffer to use just one write */ if (iocache_capacity(ioc) < len) { if (iocache_grow(ioc, iocache_size(ioc)) < 0) return -1; } if (iocache_add(ioc, buf, len) < 0) return -1; } buf = ioc->ioc_buf; len = iocache_available(ioc); } sent = sendto(fd, buf, len, flags, dest_addr, addrlen); if (sent < 1) return -errno; if (iocache_available(ioc)) iocache_use_size(ioc, sent); return sent; }
/* * Fetch one event from the node's iocache. If the cache is * exhausted, we handle partial events and iocache resets and * return NULL */ merlin_event *node_get_event(merlin_node *node) { merlin_event *pkt; iocache *ioc = node->ioc; pkt = (merlin_event *)(iocache_use_size(ioc, HDR_SIZE)); /* * buffer is empty */ if (pkt == NULL) { return NULL; } /* * If buffer is smaller than expected, put the header back * and wait for more data */ if (pkt->hdr.len > iocache_available(ioc)) { ldebug("IOC: packet is longer (%i) than remaining data (%lu) from %s - will read more and try again", pkt->hdr.len, iocache_available(ioc), node->name); if (iocache_unuse_size(ioc, HDR_SIZE) < 0) lerr("IOC: Failed to unuse %d bytes from iocache. Next packet from %s will be invalid\n", HDR_SIZE, node->name); return NULL; } if (pkt->hdr.sig.id != MERLIN_SIGNATURE) { lerr("Invalid signature on packet from '%s'. Disconnecting node", node->name); node_disconnect(node, "Invalid signature"); return NULL; } node->stats.events.read++; iocache_use_size(ioc, pkt->hdr.len); return pkt; }
static int print_input(int sd, int events, void *wp_) { int ret, pkt = 0; simple_worker *wp = (simple_worker *)wp_; struct kvvec kvv = KVVEC_INITIALIZER; char *buf; unsigned long tot_bytes = 0, size; /* * if some command filled the buffer, we grow it and read some * more until we hit the limit * @todo Define a limit :p */ size = iocache_size(wp->ioc); if (!iocache_capacity(wp->ioc)) { if (iocache_size(wp->ioc) < MAX_IOCACHE_SIZE) { /* double the size */ iocache_grow(wp->ioc, iocache_size(wp->ioc)); printf("Growing iocache for worker %d. sizes old/new %lu/%lu\n", wp->pid, size, iocache_size(wp->ioc)); } else { printf("iocache_size() for worker %d is already at max\n", wp->pid); } } ret = iocache_read(wp->ioc, sd); if (!ret) { printf("Worker with pid %d seems to have crashed. Exiting\n", wp->pid); exit(1); } if (ret < 0) { printf("iocache_read() from worker %d returned %d: %m\n", wp->pid, ret); return 0; } printf("read %d bytes from worker with pid %d::\n", ret, wp->pid); while ((buf = worker_ioc2msg(wp->ioc, &size, 0))) { int i, ret; tot_bytes += size; ret = worker_buf2kvvec_prealloc(&kvv, buf, (unsigned int)size, KVVEC_ASSIGN); if (!ret < 0) { printf("main: Failed to parse buffer of size %lu to key/value vector\n", size); continue; } for (i = 0; i < kvv.kv_pairs; i++) { struct key_value *kv = &kvv.kv[i]; if (!i && memcmp(kv->key, buf, kv->key_len)) { printf("### kv[0]->key doesn't match buf. error in kvvec?\n"); } printf("main: %2d.%02d: %s=%s\n", pkt, i, kv->key, kv->value); } pkt++; } printf("iocache: available: %lu; size: %lu; capacity: %lu\n", iocache_available(wp->ioc), iocache_size(wp->ioc), iocache_capacity(wp->ioc)); printf("Got %d packets in %ld bytes (ret: %d)\n", pkt, tot_bytes, ret); return 0; }
char *iocache_use_size(iocache *ioc, unsigned long size) { char *ret; if (!ioc || !ioc->ioc_buf) return NULL; if (ioc->ioc_bufsize < size || iocache_available(ioc) < size) return NULL; ret = ioc->ioc_buf + ioc->ioc_offset; ioc->ioc_offset += size; return ret; }
char *iocache_use_delim(iocache *ioc, const char *delim, size_t delim_len, unsigned long *size) { char *ptr = NULL; char *buf; unsigned long remains; if (!ioc || !ioc->ioc_buf || !ioc->ioc_bufsize || !ioc->ioc_buflen) return NULL; *size = 0; if (ioc->ioc_offset >= ioc->ioc_buflen) { iocache_move_data(ioc); return NULL; } buf = &ioc->ioc_buf[ioc->ioc_offset]; remains = iocache_available(ioc); while (remains >= delim_len) { unsigned long jump; ptr = memchr(buf, *delim, remains - (delim_len - 1)); if (!ptr) { return NULL; } if (delim_len == 1 || !memcmp(ptr, delim, delim_len)) { unsigned long ioc_start; ioc_start = (unsigned long)ioc->ioc_buf + ioc->ioc_offset; *size = (unsigned long)ptr - ioc_start; /* make sure we use up all of the delimiter as well */ return iocache_use_size(ioc, delim_len + *size); } jump = 1 + (unsigned long)ptr - (unsigned long)buf; remains -= jump; buf += jump; } return NULL; }