Exemplo n.º 1
0
Arquivo: io.c Projeto: aosm/distcc
/**
 * Write bytes to an fd.  Keep writing until we're all done or something goes
 * wrong.
 *
 * @returns 0 or exit code.
 **/
int dcc_writex(int fd, const void *buf, size_t len)
{
    ssize_t r;
    int ret;
	
    while (len > 0) {
        r = write(fd, buf, len);

        if (r == -1 && errno == EAGAIN) {
            if ((ret = dcc_select_for_write(fd, dcc_io_timeout)))
                return ret;
            else
                continue;
        } else if (r == -1 && errno == EINTR) {
            continue;
        } else if (r == -1) {
            rs_log_error("failed to write: %s", strerror(errno));
            return EXIT_IO_ERROR;
        } else if (r == 0) {
            rs_log_error("unexpected eof on fd%d", fd);
            return EXIT_TRUNCATED;
        } else {
            buf = &((char *) buf)[r];
            len -= r;
        }
    }

    return 0;
}
Exemplo n.º 2
0
/*
 * Transmit the body of a file using sendfile().
 *
 * Linux at the moment requires the input be page-based -- ie a disk file, and
 * only on particular filesystems.  If the sendfile() call fails in a way that
 * makes us think that regular IO might work, then we try that instead.  For
 * example, the /tmp filesystem may not support sendfile().
 */
int
dcc_pump_sendfile(int ofd, int ifd, size_t size)
{
    ssize_t sent;
    off_t offset = 0;
    int ret;

    while (size) {
        /* Handle possibility of partial transmission, e.g. if
         * sendfile() is interrupted by a signal.  size is decremented
         * as we go. */

        sent = sys_sendfile(ofd, ifd, &offset, size);
        if (sent == -1) {
            if ((errno == ENOSYS || errno == EINVAL) && offset == 0) {
                /* The offset==0 tests is because we may be part way through
                 * the file.  We can't just naively go back to read/write
                 * because sendfile() does not update the file pointer: we
                 * would need to lseek() first.  That case is not handled at
                 * the moment because it's unlikely that sendfile() would
                 * suddenly be unsupported while we're using it.  A failure
                 * halfway through probably indicates a genuine error.*/

                rs_log_info("decided to use read/write rather than sendfile");
                return dcc_pump_readwrite(ofd, ifd, size);
            } else if (errno == EAGAIN) {
                /* Sleep until we're able to write out more data. */
                if ((ret = dcc_select_for_write(ofd, dcc_io_timeout)) != 0)
                    return ret;
                rs_trace("select() returned, continuing to write");
            } else if (errno == EINTR) {
                rs_trace("sendfile() interrupted, continuing");
            } else {
                rs_log_error("sendfile failed: %s", strerror(errno));
                return EXIT_IO_ERROR;
            }
        } else if (sent == 0) {
            rs_log_error("sendfile returned 0? can't cope");
            return EXIT_IO_ERROR;
        } else if (sent != (ssize_t) size) {
            /* offset is automatically updated by sendfile. */
            size -= sent;
            rs_log_notice("sendfile: partial transmission of %ld bytes; retrying %ld @%ld",
                          (long) sent, (long) size, (long) offset);
        } else {
            /* normal case, everything was sent. */
            break;
        }
    }
    return 0;
}
Exemplo n.º 3
0
Arquivo: clinet.c Projeto: aosm/distcc
/*
 * Connect to a host given its binary address, with a timeout.
 * 
 * host and port are only here to aid printing debug messages.
 */
static int
dcc_connect_by_addr(struct sockaddr *sa, size_t salen,
                    int *p_fd)
{
    int fd;
    int ret;
    char *s;
    int failed;

    dcc_sockaddr_to_string(sa, salen, &s);

    rs_trace("started connecting to %s", s);

    if ((fd = socket(sa->sa_family, SOCK_STREAM, 0)) == -1) {
        rs_log_error("failed to create socket: %s", strerror(errno));
        ret = EXIT_CONNECT_FAILED;
        goto out_failed;
    }

    dcc_set_nonblocking(fd);

    /* start the nonblocking connect... */
    do
        failed = connect(fd, sa, salen);
    while (failed == -1 && errno == EINTR);

    if (failed == -1 && errno != EINPROGRESS) {
        rs_log(RS_LOG_ERR|RS_LOG_NONAME,
               "failed to connect to %s: %s", s, strerror(errno));
        ret = EXIT_CONNECT_FAILED;
        goto out_failed;
    }

    if ((ret = dcc_select_for_write(fd, dcc_connect_timeout))) {
        rs_log(RS_LOG_ERR|RS_LOG_NONAME,
               "timeout while connecting to %s", s);
        goto out_failed;
    }

    *p_fd = fd;
    free(s);
    return 0;
    
out_failed:
    free(s);
    return ret;
}
Exemplo n.º 4
0
/*
 * Connect to a host given its binary address, with a timeout.
 *
 * host and port are only here to aid printing debug messages.
 */
int dcc_connect_by_addr(struct sockaddr *sa, size_t salen,
                        int *p_fd)
{
    int fd;
    int ret;
    char *s;
    int failed;
    int connecterr;
    int tries = 3;

    dcc_sockaddr_to_string(sa, salen, &s);
    if (s == NULL) return EXIT_OUT_OF_MEMORY;

    rs_trace("started connecting to %s", s);

    if ((fd = socket(sa->sa_family, SOCK_STREAM, 0)) == -1) {
        rs_log_error("failed to create socket: %s", strerror(errno));
        ret = EXIT_CONNECT_FAILED;
        goto out_failed;
    }

    dcc_set_nonblocking(fd);

    /* start the nonblocking connect... */
    do
        failed = connect(fd, sa, salen);
    while (failed == -1 &&
           (errno == EINTR ||
            (errno == EAGAIN && tries-- && poll(NULL, 0, 500) == 0)));

   if (failed == -1 && errno != EINPROGRESS) {
       rs_log(RS_LOG_ERR|RS_LOG_NONAME,
              "failed to connect to %s: %s", s, strerror(errno));
       ret = EXIT_CONNECT_FAILED;
       goto out_failed;
   }

    do {
       socklen_t len;

       if ((ret = dcc_select_for_write(fd, dcc_connect_timeout))) {
           rs_log(RS_LOG_ERR|RS_LOG_NONAME,
                  "timeout while connecting to %s", s);
           goto out_failed;
       }

       connecterr = -1;
       len = sizeof(connecterr);
       if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (char *)&connecterr, &len) < 0) {
               rs_log_error("getsockopt SO_ERROR failed?!");
               ret = EXIT_CONNECT_FAILED;
               goto out_failed;
       }

       /* looping is unlikely, but I believe I needed this in dkftpbench */
       /* fixme: should reduce timeout on each time around this loop */
    } while (connecterr == EINPROGRESS);

    if (connecterr) {
       rs_log(RS_LOG_ERR|RS_LOG_NONAME,
                "nonblocking connect to %s failed: %s", s, strerror(connecterr));
       ret = EXIT_CONNECT_FAILED;
       goto out_failed;
    }

    *p_fd = fd;
    free(s);
    return 0;

out_failed:
    free(s);
    return ret;
}