示例#1
0
static void tcp_write_stream(OutputStream * out, int byte) {
    ChannelTCP * c = channel2tcp(out2channel(out));
    assert(c->magic == CHANNEL_MAGIC);
    if (!c->chan.out.supports_zero_copy || c->chan.out.cur >= c->chan.out.end - 32 || byte < 0) {
        if (c->out_bin_block != NULL) tcp_bin_block_end(c);
        if (c->chan.out.cur == c->chan.out.end) tcp_flush_with_flags(c, MSG_MORE);
        if (byte < 0 || byte == ESC) {
            char esc = 0;
            *c->chan.out.cur++ = ESC;
            if (byte == ESC) esc = 0;
            else if (byte == MARKER_EOM) esc = 1;
            else if (byte == MARKER_EOS) esc = 2;
            else assert(0);
            if (c->chan.out.cur == c->chan.out.end) tcp_flush_with_flags(c, MSG_MORE);
            *c->chan.out.cur++ = esc;
            if (byte == MARKER_EOM && c->out_flush_cnt < 4) {
                if (c->out_flush_cnt++ == 0) tcp_lock(&c->chan);
                post_event(tcp_flush_event, c);
            }
            return;
        }
    }
    else if (c->out_bin_block == NULL) {
        tcp_bin_block_start(c);
    }
    *c->chan.out.cur++ = (char)byte;
}
static int tcp_is_closed(Channel * channel) {
    ChannelTCP * c = channel2tcp(channel);
    assert(is_dispatch_thread());
    assert(c->magic == CHANNEL_MAGIC);
    assert(c->lock_cnt > 0);
    return c->socket < 0;
}
示例#3
0
static int tcp_is_closed(Channel * channel) {
    ChannelTCP * c = channel2tcp(channel);
    assert(is_dispatch_thread());
    assert(c->magic == CHANNEL_MAGIC);
    assert(c->lock_cnt > 0);
    return c->chan.state == ChannelStateDisconnected;
}
static void tcp_flush_with_flags(OutputStream * out, int flags) {
    int cnt = 0;
    ChannelTCP * c = channel2tcp(out2channel(out));
    assert(is_dispatch_thread());
    assert(c->magic == CHANNEL_MAGIC);
    assert(c->obuf_inp <= BUF_SIZE);
    if (c->obuf_inp == 0) return;
    if (c->socket < 0 || c->out_errno) {
        c->obuf_inp = 0;
        return;
    }
    while (cnt < c->obuf_inp) {
        int wr = 0;
        if (c->ssl) {
#if ENABLE_SSL
            wr = SSL_write(c->ssl, c->obuf + cnt, c->obuf_inp - cnt);
            if (wr <= 0) {
                int err = SSL_get_error(c->ssl, wr);
                if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) {
                    struct timeval tv;
                    fd_set readfds;
                    fd_set writefds;
                    fd_set errorfds;
                    FD_ZERO(&readfds);
                    FD_ZERO(&writefds);
                    FD_ZERO(&errorfds);
                    if (err == SSL_ERROR_WANT_READ) FD_SET(c->socket, &readfds);
                    if (err == SSL_ERROR_WANT_WRITE) FD_SET(c->socket, &writefds);
                    FD_SET(c->socket, &errorfds);
                    tv.tv_sec = 10L;
                    tv.tv_usec = 0;
                    if (select(c->socket + 1, &readfds, &writefds, &errorfds, &tv) >= 0) continue;
                }
                trace(LOG_PROTOCOL, "Can't SSL_write() on channel %#lx: %s", c,
                    ERR_error_string(ERR_get_error(), NULL));
                c->out_errno = EIO;
                c->obuf_inp = 0;
                return;
            }
#else
            assert(0);
#endif
        }
        else {
            wr = send(c->socket, c->obuf + cnt, c->obuf_inp - cnt, flags);
            if (wr < 0) {
                int err = errno;
                trace(LOG_PROTOCOL, "Can't send() on channel %#lx: %d %s", c, err, errno_to_str(err));
                c->out_errno = err;
                c->obuf_inp = 0;
                return;
            }
        }
        cnt += wr;
    }
    assert(cnt == c->obuf_inp);
    c->obuf_inp = 0;
}
static void tcp_unlock(Channel * channel) {
    ChannelTCP * c = channel2tcp(channel);
    assert(is_dispatch_thread());
    assert(c->magic == CHANNEL_MAGIC);
    assert(c->lock_cnt > 0);
    c->lock_cnt--;
    if (c->lock_cnt == 0 && !c->read_pending) {
        delete_channel(c);
    }
}
示例#6
0
static ssize_t tcp_splice_block_stream(OutputStream * out, int fd, size_t size, int64_t * offset) {
    assert(is_dispatch_thread());
    if (size == 0) return 0;
#if ENABLE_Splice
    {
        ChannelTCP * c = channel2tcp(out2channel(out));
        if (!c->ssl && out->supports_zero_copy) {
            ssize_t rd = splice(fd, offset, c->pipefd[1], NULL, size, SPLICE_F_MOVE);
            if (rd > 0) {
                /* Send the binary data escape seq */
                size_t n = rd;
                if (c->out_bin_block != NULL) tcp_bin_block_end(c);
                if (c->chan.out.cur >= c->chan.out.end - 8) tcp_flush_with_flags(c, MSG_MORE);
                *c->chan.out.cur++ = ESC;
                *c->chan.out.cur++ = 3;
                for (;;) {
                    if (n <= 0x7fu) {
                        *c->chan.out.cur++ = (char)n;
                        break;
                    }
                    *c->chan.out.cur++ = (n & 0x7fu) | 0x80u;
                    n = n >> 7;
                }
                /* We need to flush the buffer then send our data */
                tcp_flush_with_flags(c, MSG_MORE);

#if ENABLE_OutputQueue
                while (!output_queue_is_empty(&c->out_queue)) {
                    cancel_event(done_write_request, &c->wr_req, 1);
                    done_write_request(&c->wr_req);
                }
#endif

                if (c->chan.state == ChannelStateDisconnected) return rd;
                if (c->out_errno) return rd;

                n = rd;
                while (n > 0) {
                    ssize_t wr = splice(c->pipefd[0], NULL, c->socket, NULL, n, SPLICE_F_MORE);

                    if (wr < 0) {
                        c->out_errno = errno;
                        trace(LOG_PROTOCOL, "Error in socket splice: %s", errno_to_str(errno));
                        break;
                    }
                    n -= wr;
                }
            }
            return rd;
        }
static void tcp_write_block_stream(OutputStream * out, const char * bytes, size_t size) {
    size_t cnt = 0;
    ChannelTCP * c = channel2tcp(out2channel(out));

#if ENABLE_ZeroCopy
    if (!c->ssl && out->supports_zero_copy && size > 32) {
        /* Send the binary data escape seq */
        size_t n = size;
        if (c->obuf_inp >= BUF_SIZE - 8) tcp_flush_with_flags(out, MSG_MORE);
        c->obuf[c->obuf_inp++] = ESC;
        c->obuf[c->obuf_inp++] = 3;
        for (;;) {
            if (n <= 0x7fu) {
                c->obuf[c->obuf_inp++] = (char)n;
                break;
            }
            c->obuf[c->obuf_inp++] = (n & 0x7fu) | 0x80u;
            n = n >> 7;
        }
        /* We need to flush the buffer then send our data */
        tcp_flush_with_flags(out, MSG_MORE);

        if (c->socket < 0) return;
        if (c->out_errno) return;

        while (cnt < size) {
            int wr = send(c->socket, bytes + cnt, size - cnt, MSG_MORE);
            if (wr < 0) {
                int err = errno;
                trace(LOG_PROTOCOL, "Can't send() on channel %#lx: %d %s", c, err, errno_to_str(err));
                c->out_errno = err;
                return;
            }
            cnt += wr;
        }
        return;
    }
static void tcp_write_stream(OutputStream * out, int byte) {
    ChannelTCP * c = channel2tcp(out2channel(out));
    assert(is_dispatch_thread());
    assert(c->magic == CHANNEL_MAGIC);
    if (c->socket < 0) return;
    if (c->out_errno) return;
    if (c->obuf_inp == BUF_SIZE) tcp_flush_with_flags(out, MSG_MORE);
    c->obuf[c->obuf_inp++] = (char)(byte < 0 ? ESC : byte);
    if (byte < 0 || byte == ESC) {
        char esc = 0;
        if (byte == ESC) esc = 0;
        else if (byte == MARKER_EOM) esc = 1;
        else if (byte == MARKER_EOS) esc = 2;
        else assert(0);
        if (c->socket < 0) return;
        if (c->out_errno) return;
        if (c->obuf_inp == BUF_SIZE) tcp_flush_with_flags(out, MSG_MORE);
        c->obuf[c->obuf_inp++] = esc;
    }
    if (byte == MARKER_EOM) {
        int congestion_level = out2channel(out)->congestion_level;
        if (congestion_level > 0) usleep(congestion_level * 2500);
    }
}
示例#9
0
static void tcp_lock(Channel * channel) {
    ChannelTCP * c = channel2tcp(channel);
    assert(is_dispatch_thread());
    assert(c->magic == CHANNEL_MAGIC);
    c->lock_cnt++;
}