Esempio n. 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;
}
Esempio n. 2
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;
        }
Esempio n. 3
0
static void tcp_flush_event(void * x) {
    ChannelTCP * c = (ChannelTCP *)x;
    assert(c->magic == CHANNEL_MAGIC);
    if (--c->out_flush_cnt == 0) {
        int congestion_level = c->chan.congestion_level;
        if (congestion_level > 0) usleep(congestion_level * 2500);
        tcp_flush_with_flags(c, 0);
        tcp_unlock(&c->chan);
    }
}
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);
    }
}
static void tcp_flush_stream(OutputStream * out) {
    tcp_flush_with_flags(out, 0);
}