static void send_eof_and_close(Channel * channel, int err) { ChannelNP * c = channel2np(channel); assert(c->magic == CHANNEL_MAGIC); if (channel->state == ChannelStateDisconnected) return; ibuf_flush(&c->ibuf); if (c->ibuf.handling_msg == HandleMsgTriggered) { /* Cancel pending message handling */ cancel_event(handle_channel_msg, c, 0); c->ibuf.handling_msg = HandleMsgIdle; } write_stream(&c->chan.out, MARKER_EOS); write_errno(&c->chan.out, err); write_stream(&c->chan.out, MARKER_EOM); np_flush_with_flags(c, 0); #if ENABLE_OutputQueue if (output_queue_is_empty(&c->out_queue)) #endif nopoll_conn_shutdown(c->np_socket); c->chan.state = ChannelStateDisconnected; np_post_read(&c->ibuf, c->ibuf.buf, c->ibuf.buf_size); notify_channel_closed(channel); if (channel->disconnected) { channel->disconnected(channel); } else { trace(LOG_PROTOCOL, "channel %#lx disconnected", c); if (channel->protocol != NULL) protocol_release(channel->protocol); } channel->protocol = NULL; }
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 done_write_request(void * args) { ChannelPIPE * c = (ChannelPIPE *)((AsyncReqInfo *)args)->client_data; int size = 0; int error = 0; assert(args == &c->out_req); if (c->out_req.u.fio.rval < 0) error = c->out_req.error; else size = c->out_req.u.fio.rval; output_queue_done(&c->out_queue, error, size); if (output_queue_is_empty(&c->out_queue) && c->chan->state == ChannelStateDisconnected) close_output_pipe(c); pipe_unlock(c->chan); }
static void done_write_request(void * args) { ChannelTCP * c = (ChannelTCP *)((AsyncReqInfo *)args)->client_data; int size = 0; int error = 0; assert(args == &c->wr_req); assert(c->socket >= 0); if (c->wr_req.u.sio.rval < 0) error = c->wr_req.error; else if (c->wr_req.type == AsyncReqSend) size = c->wr_req.u.sio.rval; output_queue_done(&c->out_queue, error, size); if (error) c->out_errno = error; if (output_queue_is_empty(&c->out_queue) && c->chan.state == ChannelStateDisconnected) shutdown(c->socket, SHUT_WR); tcp_unlock(&c->chan); }
static void done_write_request(void * args) { ChannelNP * c = (ChannelNP *)((AsyncReqInfo *)args)->client_data; int size = 0; int error = 0; assert(args == &c->wr_req); assert(c->socket != NOPOLL_INVALID_SOCKET); loc_free(((AsyncReqInfo *)args)->u.user.data); if (c->wr_req.u.user.rval < 0) error = c->wr_req.error; size = c->wr_req.u.user.rval; output_queue_done(&c->out_queue, error, size); if (error) c->out_errno = error; if (output_queue_is_empty(&c->out_queue) && c->chan.state == ChannelStateDisconnected) nopoll_conn_shutdown(c->np_socket); np_unlock(&c->chan); trace(LOG_PROTOCOL, "done_write_request"); }
static void delete_channel(ChannelPIPE * c) { trace(LOG_PROTOCOL, "Deleting channel %#lx", c); assert(c->lock_cnt == 0); assert(c->out_flush_cnt == 0); assert(c->magic == CHANNEL_MAGIC); assert(c->read_pending == 0); assert(c->ibuf.handling_msg != HandleMsgTriggered); assert(output_queue_is_empty(&c->out_queue)); output_queue_clear(&c->out_queue); channel_clear_broadcast_group(&c->chan); close_input_pipe(c); list_remove(&c->chan.chanlink); if (list_is_empty(&channel_root) && list_is_empty(&channel_server_root)) shutdown_set_stopped(&channel_shutdown); c->magic = 0; loc_free(c->ibuf.buf); loc_free(c->chan.peer_name); loc_free(c); }