Logo Search packages:      
Sourcecode: fair version File versions  Download package

fdcopy.c

/******************************************************************************

      fdcopy.c -- ringbuffer copying routines
      Copyright (C) 2004  Wessel Dankers <wsl@uvt.nl>

      This program is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published by
      the Free Software Foundation; either version 2 of the License, or
      (at your option) any later version.

      This program is distributed in the hope that it will be useful,
      but WITHOUT ANY WARRANTY; without even the implied warranty of
      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      GNU General Public License for more details.

      You should have received a copy of the GNU General Public License
      along with this program; if not, write to the Free Software
      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

      $Id: fdcopy.c 23144 2007-12-21 15:36:48Z wsl $
      $URL: https://infix.uvt.nl/its-id/trunk/sources/fair-0.5.1/src/fdcopy.c $

******************************************************************************/

#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <fcntl.h>

#include <avl.h>

#include "fair.h"
#include "chrono.h"
#include "error.h"
#include "fd.h"
#include "conf.h"

#include "fdcopy.h"

static int ptrcmp(byte *a, byte *b) {
      assert(a && b);
      return a - b;
}

static avl_tree_t fdcopys = {NULL, NULL, NULL, (avl_compare_t)ptrcmp, NULL};

unsigned int fdcopy_count(void) {
      return avl_count(&fdcopys);
}

static void fdcopy_write(fd_t *, fd_event_t);

static void fdcopy_read(fd_t *fd, fd_event_t evt) {
      fdcopy_t *fdc;
      size_t offset, fill, size;
      size_t end, len;
      struct iovec vec[2];
      ssize_t r;

      unless(fd) return;
      fdc = fd->rdata;

      unless(fdc) return;
      unless(fdc->func) return;
      unless(fdc->src) return;
      unless(fdc->dst) return;

      offset = fdc->offset;
      fill = fdc->fill;
      size = fdc->size;
      end = offset + fill;
      len = size - fill;

      assert(len >= 0);
      assert(size >= 0);
      assert(end <= size);

      if(!offset) {
            r = read(fd->fd, fdc->buf + end, len);
      } else if(end >= fdc->size) {
            r = read(fd->fd, fdc->buf + end - size, len);
      } else {
            vec[0].iov_base = fdc->buf + end;
            vec[0].iov_len = size - end;
            vec[1].iov_base = fdc->buf;
            vec[1].iov_len = offset;
            r = readv(fd->fd, vec, 2);
      }

      if(r > 0) {
            fdc->fill = fill += r;
            fd_write(fdc->dst, fdcopy_write, fdc);
            if(size - fill < conf_MinBurst)
                  fd_read(fdc->src, NULL, NULL);
      } else {
            if(fill)
                  fd_write(fdc->dst, fdcopy_write, fdc);
            else
                  fdc->dst = NULL;
            fd_read(fdc->src, NULL, NULL);
            fdc->src = NULL;
      }
      fdc->func(fdc, FDCOPY_EVENT_READ, r);
      if(fdc->dst)
            return;
      fdc->func(fdc, FDCOPY_EVENT_DONE, fill);
}

static void fdcopy_write(fd_t *fd, fd_event_t evt) {
      fdcopy_t *fdc;
      size_t offset, fill, size;
      struct iovec vec[2];
      ssize_t r;

      unless(fd) return;
      fdc = fd->wdata;

      unless(fdc) return;
      unless(fdc->func) return;
      unless(fdc->dst) return;

      offset = fdc->offset;
      fill = fdc->fill;
      size = fdc->size;

      if(offset + fill <= size) {
            r = write(fd->fd, fdc->buf + offset, fill);
      } else {
            vec[0].iov_base = fdc->buf + offset;
            vec[0].iov_len = size - offset;
            vec[1].iov_base = fdc->buf;
            vec[1].iov_len = fill - size + offset;
            r = writev(fd->fd, vec, 2);
      }

      if(r > 0) {
            fdc->fill = fill -= r;
            if(fill) {
                  offset += r;
                  if(offset > size)
                        offset -= size;
            } else {
                  offset = 0;
                  fd_write(fdc->dst, NULL, NULL);
            }
            fdc->offset = offset;
            if(fdc->src) {
                  if(size - fill >= conf_MinBurst)
                        fd_read(fdc->src, fdcopy_read, fdc);
            } else if(!fill) {
                  fd_write(fdc->dst, NULL, NULL);
                  fdc->dst = NULL;
            }
      } else {
            fd_write(fdc->dst, NULL, NULL);
            fdc->dst = NULL;
      }
      fdc->func(fdc, FDCOPY_EVENT_WRITE, r);
      if(fdc->dst)
            return;
      if(fdc->src) {
            fd_read(fdc->src, NULL, NULL);
            fdc->src = NULL;
      }
      fdc->func(fdc, FDCOPY_EVENT_DONE, fill);
}

fdcopy_t *fdcopy_new(fd_t *src, fd_t *dst, fdcopy_hook_t func, void *data) {
      fdcopy_t *r;
      unless(src) return errno = EINVAL, NULL;
      unless(dst) return errno = EINVAL, NULL;
      r = xalloc(sizeof *r + conf_MaxBurst);
      avl_init_node(&r->node, r);
      avl_insert_node(&fdcopys, &r->node);
      r->src = src;
      r->dst = dst;
      r->size = conf_MaxBurst;
      r->fill = r->offset = 0;
      r->func = func;
      r->data = data;
      fd_read(src, fdcopy_read, r);
      return r;
}

void fdcopy_delete(fdcopy_t *victim) {
      unless(victim) return;
      avl_unlink_node(&fdcopys, &victim->node);
      free(victim);
}

Generated by  Doxygen 1.6.0   Back to index