static void broker_server_client_ready(uv_poll_t *poll, int status, int events) { (void) status; Client *client = poll->data; Server *server = client->server; if (events & UV_READABLE) { server->data_ready(client, poll->loop->data); if (client->sock->socket_ctx.fd == -1) { // The callback closed the connection dslink_socket_free(client->sock); dslink_free(client); client = NULL; uv_close((uv_handle_t *) poll, broker_free_handle); } } if (client && (events & UV_WRITABLE)) { RemoteDSLink *link = client->sock_data; if (link) { link->ws->write_enabled = 1; wslay_event_send(link->ws); } } }
void h2o_websocket_proceed(h2o_websocket_conn_t *conn) { int handled; /* run the loop until getting to a point where no more progress can be achieved */ do { handled = 0; if (!h2o_socket_is_writing(conn->sock) && wslay_event_want_write(conn->ws_ctx)) { if (wslay_event_send(conn->ws_ctx) != 0) { goto Close; } handled = 1; } if (conn->sock->input->size != 0 && wslay_event_want_read(conn->ws_ctx)) { if (wslay_event_recv(conn->ws_ctx) != 0) { goto Close; } handled = 1; } } while (handled); if (wslay_event_want_read(conn->ws_ctx)) { h2o_socket_read_start(conn->sock, on_recv); } else if (h2o_socket_is_writing(conn->sock) || wslay_event_want_write(conn->ws_ctx)) { h2o_socket_read_stop(conn->sock); } else { /* nothing is going on... close the socket */ goto Close; } return; Close: on_close(conn); }
int dslink_ws_send(wslay_event_context_ptr ctx, const char *data) { struct wslay_event_msg msg; msg.msg = (const uint8_t *) data; msg.msg_length = strlen(data); msg.opcode = WSLAY_TEXT_FRAME; wslay_event_queue_msg(ctx, &msg); wslay_event_send(ctx); log_debug("Message sent: %s\n", data); return 0; }
void WebSocket::write(const Message& msg) { const String& data = msg.message(); wslay_event_msg wmsg = { static_cast<uint8_t>(msg.opcode()), reinterpret_cast<const uint8_t*>(data.constData()), static_cast<size_t>(data.size()) }; wslay_event_queue_msg(mCtx, &wmsg); wslay_event_send(mCtx); }
HIDDEN void ws_output(struct transaction_t *txn) { struct ws_context *ctx = (struct ws_context *) txn->ws_ctx; wslay_event_context_ptr ev = ctx->event; int want_write = wslay_event_want_write(ev); syslog(LOG_DEBUG, "ws_output() eof: %d, want write: %d", txn->conn->pin->eof, want_write); if (want_write) { /* Send queued frame(s) */ int r = wslay_event_send(ev); if (r) { syslog(LOG_ERR, "wslay_event_send: %s", wslay_strerror(r)); txn->flags.conn = CONN_CLOSE; } } }
static mrb_value mrb_wslay_event_send(mrb_state *mrb, mrb_value self) { mrb_wslay_user_data *data = (mrb_wslay_user_data *) DATA_PTR(self); mrb_assert(data); int err = wslay_event_send(data->ctx); if (err == WSLAY_ERR_NOMEM) { mrb_sys_fail(mrb, "wslay_event_send"); } else if (err == WSLAY_ERR_CALLBACK_FAILURE) { mrb_exc_raise(mrb, mrb_obj_value(mrb->exc)); } else if (err != 0) { return MRB_WSLAY_ERROR(mrb_fixnum_value(err)); } return self; }
void h2o_websocket_proceed(h2o_websocket_conn_t *conn) { int handled; /* run the loop until getting to a point where no more progress can be achieved */ do { handled = 0; if (!h2o_socket_is_writing(conn->sock) && wslay_event_want_write(conn->ws_ctx)) { if (wslay_event_send(conn->ws_ctx) != 0) { goto Close; } /* avoid infinite loop when user want send more bufers count than ours in on_msg_callback() */ if (conn->_write_buf.cnt < sizeof(conn->_write_buf.bufs) / sizeof(conn->_write_buf.bufs[0])) { handled = 1; } } if (conn->sock->input->size != 0 && wslay_event_want_read(conn->ws_ctx)) { if (wslay_event_recv(conn->ws_ctx) != 0) { goto Close; } handled = 1; } } while (handled); if (!h2o_socket_is_writing(conn->sock) && conn->_write_buf.cnt > 0) { /* write */ h2o_socket_write(conn->sock, conn->_write_buf.bufs, conn->_write_buf.cnt, on_write_complete); } if (wslay_event_want_read(conn->ws_ctx)) { h2o_socket_read_start(conn->sock, on_recv); } else if (h2o_socket_is_writing(conn->sock) || wslay_event_want_write(conn->ws_ctx)) { h2o_socket_read_stop(conn->sock); } else { /* nothing is going on... close the socket */ goto Close; } return; Close: on_close(conn); }
static int dslink_ws_send_internal(wslay_event_context_ptr ctx, const char *data, uint8_t resend) { (void) resend; struct wslay_event_msg msg; msg.msg = (const uint8_t *) data; msg.msg_length = strlen(data); msg.opcode = WSLAY_TEXT_FRAME; if (wslay_event_queue_msg(ctx, &msg) != 0) { return 1; } if (wslay_event_send(ctx) != 0) { return 1; } log_debug("Message sent: %s\n", data); return 0; }
int websocket_handler(websocket_t *websocket) { int r; int fd = websocket->fd; int timeout = 0; fd_set read_fds; fd_set write_fds; wslay_event_context_ptr ctx = (wslay_event_context_ptr) websocket->ctx; struct timeval tv; while (websocket->state != WEBSOCKET_STOP) { FD_ZERO(&read_fds); FD_ZERO(&write_fds); if (wslay_event_want_read(ctx)) { FD_SET(fd, &read_fds); } if (wslay_event_want_write(ctx)) { FD_SET(fd, &write_fds); } tv.tv_sec = (WEBSOCKET_HANDLER_TIMEOUT / 1000); tv.tv_usec = ((WEBSOCKET_HANDLER_TIMEOUT % 1000) * 1000); r = select(fd + 1, &read_fds, &write_fds, NULL, &tv); if (r < 0) { if (errno == EAGAIN || errno == EBUSY || errno == EINTR) { continue; } WEBSOCKET_DEBUG("select function returned errno == %d\n", errno); return WEBSOCKET_SOCKET_ERROR; } else if (r == 0) { if (WEBSOCKET_HANDLER_TIMEOUT != 0) { timeout++; if ((WEBSOCKET_HANDLER_TIMEOUT * timeout) >= (WEBSOCKET_PING_INTERVAL * 10)) { timeout = 0; if (websocket_ping_counter(websocket) != WEBSOCKET_SUCCESS) { return WEBSOCKET_SOCKET_ERROR; } } } continue; } else { timeout = 0; if (FD_ISSET(fd, &read_fds)) { r = wslay_event_recv(ctx); if (r != WEBSOCKET_SUCCESS) { WEBSOCKET_DEBUG("fail to process recv event, result : %d\n", r); websocket_update_state(websocket, WEBSOCKET_ERROR); return WEBSOCKET_SOCKET_ERROR; } } if (FD_ISSET(fd, &write_fds)) { r = wslay_event_send(ctx); if (r != WEBSOCKET_SUCCESS) { WEBSOCKET_DEBUG("fail to process send event, result : %d\n", r); websocket_update_state(websocket, WEBSOCKET_ERROR); return WEBSOCKET_SOCKET_ERROR; } } } } return WEBSOCKET_SUCCESS; }
/* * Communicate with the client. This function performs HTTP handshake * and WebSocket data transfer until close handshake is done or an * error occurs. *fd* is the file descriptor of the connection to the * client. This function returns 0 if it succeeds, or returns 0. */ int communicate(int fd) { wslay_event_context_ptr ctx; struct wslay_event_callbacks callbacks = { recv_callback, send_callback, NULL, NULL, NULL, NULL, on_msg_recv_callback }; struct Session session = { fd }; int val = 1; struct pollfd event; int res = 0; if(http_handshake(fd) == -1) { return -1; } if(make_non_block(fd) == -1) { return -1; } if(setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, (socklen_t)sizeof(val)) == -1) { perror("setsockopt: TCP_NODELAY"); return -1; } memset(&event, 0, sizeof(struct pollfd)); event.fd = fd; event.events = POLLIN; wslay_event_context_server_init(&ctx, &callbacks, &session); /* * Event loop: basically loop until both wslay_event_want_read(ctx) * and wslay_event_want_write(ctx) return 0. */ while(wslay_event_want_read(ctx) || wslay_event_want_write(ctx)) { int r; while((r = poll(&event, 1, -1)) == -1 && errno == EINTR); if(r == -1) { perror("poll"); res = -1; break; } if(((event.revents & POLLIN) && wslay_event_recv(ctx) != 0) || ((event.revents & POLLOUT) && wslay_event_send(ctx) != 0) || (event.revents & (POLLERR | POLLHUP | POLLNVAL))) { /* * If either wslay_event_recv() or wslay_event_send() return * non-zero value, it means serious error which prevents wslay * library from processing further data, so WebSocket connection * must be closed. */ res = -1; break; } event.events = 0; if(wslay_event_want_read(ctx)) { event.events |= POLLIN; } if(wslay_event_want_write(ctx)) { event.events |= POLLOUT; } } return res; }
int wslay_event_recv(wslay_event_context_ptr ctx) { struct wslay_frame_iocb iocb; ssize_t r; while (ctx->read_enabled) { memset(&iocb, 0, sizeof(iocb)); r = wslay_frame_recv(ctx->frame_ctx, &iocb); if (r >= 0) { int new_frame = 0; /* RSV1 is not allowed on control and continuation frames */ if ((!wslay_event_verify_rsv_bits(ctx, iocb.rsv)) || (wslay_get_rsv1(iocb.rsv) && (wslay_is_ctrl_frame(iocb.opcode) || iocb.opcode == WSLAY_CONTINUATION_FRAME)) || (ctx->server && !iocb.mask) || (!ctx->server && iocb.mask)) { if ((r = wslay_event_queue_close_wrapper(ctx, WSLAY_CODE_PROTOCOL_ERROR, NULL, 0)) != 0) { return r; } break; } if (ctx->imsg->opcode == 0xffu) { if (iocb.opcode == WSLAY_TEXT_FRAME || iocb.opcode == WSLAY_BINARY_FRAME || iocb.opcode == WSLAY_CONNECTION_CLOSE || iocb.opcode == WSLAY_PING || iocb.opcode == WSLAY_PONG) { wslay_event_imsg_set(ctx->imsg, iocb.fin, iocb.rsv, iocb.opcode); new_frame = 1; } else { if ((r = wslay_event_queue_close_wrapper(ctx, WSLAY_CODE_PROTOCOL_ERROR, NULL, 0)) != 0) { return r; } break; } } else if (ctx->ipayloadlen == 0 && ctx->ipayloadoff == 0) { if (iocb.opcode == WSLAY_CONTINUATION_FRAME) { ctx->imsg->fin = iocb.fin; } else if (iocb.opcode == WSLAY_CONNECTION_CLOSE || iocb.opcode == WSLAY_PING || iocb.opcode == WSLAY_PONG) { ctx->imsg = &ctx->imsgs[1]; wslay_event_imsg_set(ctx->imsg, iocb.fin, iocb.rsv, iocb.opcode); } else { if ((r = wslay_event_queue_close_wrapper(ctx, WSLAY_CODE_PROTOCOL_ERROR, NULL, 0)) != 0) { return r; } break; } new_frame = 1; } if (new_frame) { if (ctx->imsg->msg_length + iocb.payload_length > ctx->max_recv_msg_length) { if ((r = wslay_event_queue_close_wrapper(ctx, WSLAY_CODE_MESSAGE_TOO_BIG, NULL, 0)) != 0) { return r; } break; } ctx->ipayloadlen = iocb.payload_length; wslay_event_call_on_frame_recv_start_callback(ctx, &iocb); if (!wslay_event_config_get_no_buffering(ctx) || wslay_is_ctrl_frame(iocb.opcode)) { if ((r = wslay_event_imsg_append_chunk(ctx->imsg, iocb.payload_length)) != 0) { ctx->read_enabled = 0; return r; } } } /* If RSV1 bit is set then it is too early for utf-8 validation */ if ((!wslay_get_rsv1(iocb.rsv) && ctx->imsg->opcode == WSLAY_TEXT_FRAME) || ctx->imsg->opcode == WSLAY_CONNECTION_CLOSE) { size_t i; if (ctx->imsg->opcode == WSLAY_CONNECTION_CLOSE) { i = 2; } else { i = 0; } for (; i < iocb.data_length; ++i) { uint32_t codep; if (decode(&ctx->imsg->utf8state, &codep, iocb.data[i]) == UTF8_REJECT) { if ((r = wslay_event_queue_close_wrapper(ctx, WSLAY_CODE_INVALID_FRAME_PAYLOAD_DATA, NULL, 0)) != 0) { return r; } break; } } } if (ctx->imsg->utf8state == UTF8_REJECT) { break; } wslay_event_call_on_frame_recv_chunk_callback(ctx, &iocb); if (iocb.data_length > 0) { if (!wslay_event_config_get_no_buffering(ctx) || wslay_is_ctrl_frame(iocb.opcode)) { struct wslay_event_byte_chunk *chunk; chunk = wslay_queue_tail(ctx->imsg->chunks); wslay_event_byte_chunk_copy(chunk, ctx->ipayloadoff, iocb.data, iocb.data_length); } ctx->ipayloadoff += iocb.data_length; } if (ctx->ipayloadoff == ctx->ipayloadlen) { if (ctx->imsg->fin && (ctx->imsg->opcode == WSLAY_TEXT_FRAME || ctx->imsg->opcode == WSLAY_CONNECTION_CLOSE) && ctx->imsg->utf8state != UTF8_ACCEPT) { if ((r = wslay_event_queue_close_wrapper(ctx, WSLAY_CODE_INVALID_FRAME_PAYLOAD_DATA, NULL, 0)) != 0) { return r; } break; } wslay_event_call_on_frame_recv_end_callback(ctx); if (ctx->imsg->fin) { if (ctx->callbacks.on_msg_recv_callback || ctx->imsg->opcode == WSLAY_CONNECTION_CLOSE || ctx->imsg->opcode == WSLAY_PING || ctx->imsg->opcode == WSLAY_PONG) { struct wslay_event_on_msg_recv_arg arg; uint16_t status_code = 0; uint8_t *msg = NULL; size_t msg_length = 0; if (!wslay_event_config_get_no_buffering(ctx) || wslay_is_ctrl_frame(iocb.opcode)) { msg = wslay_event_flatten_queue(ctx->imsg->chunks, ctx->imsg->msg_length); if (ctx->imsg->msg_length && !msg) { ctx->read_enabled = 0; return WSLAY_ERR_NOMEM; } msg_length = ctx->imsg->msg_length; } if (ctx->imsg->opcode == WSLAY_CONNECTION_CLOSE) { const uint8_t *reason; size_t reason_length; if (ctx->imsg->msg_length >= 2) { memcpy(&status_code, msg, 2); status_code = ntohs(status_code); if (!wslay_event_is_valid_status_code(status_code)) { free(msg); if ((r = wslay_event_queue_close_wrapper(ctx, WSLAY_CODE_PROTOCOL_ERROR, NULL, 0)) != 0) { return r; } break; } reason = msg + 2; reason_length = ctx->imsg->msg_length - 2; } else { reason = NULL; reason_length = 0; } ctx->close_status |= WSLAY_CLOSE_RECEIVED; ctx->status_code_recv = status_code == 0 ? WSLAY_CODE_NO_STATUS_RCVD : status_code; if ((r = wslay_event_queue_close_wrapper(ctx, status_code, reason, reason_length)) != 0) { free(msg); return r; } } else if (ctx->imsg->opcode == WSLAY_PING) { struct wslay_event_msg pong_arg; pong_arg.opcode = WSLAY_PONG; pong_arg.msg = msg; pong_arg.msg_length = ctx->imsg->msg_length; if ((r = wslay_event_queue_msg(ctx, &pong_arg)) && r != WSLAY_ERR_NO_MORE_MSG) { ctx->read_enabled = 0; free(msg); return r; } } else if (ctx->imsg->opcode == WSLAY_PONG) { struct websocket_info_t *info = ctx->user_data; info->data->ping_cnt = 0; } if (ctx->callbacks.on_msg_recv_callback) { arg.rsv = ctx->imsg->rsv; arg.opcode = ctx->imsg->opcode; arg.msg = msg; arg.msg_length = msg_length; arg.status_code = status_code; ctx->error = 0; ctx->callbacks.on_msg_recv_callback(ctx, &arg, ctx->user_data); if (ctx->imsg->opcode != WSLAY_CONNECTION_CLOSE) { free(msg); wslay_event_imsg_reset(ctx->imsg); if (ctx->imsg == &ctx->imsgs[1]) { ctx->imsg = &ctx->imsgs[0]; } ctx->ipayloadlen = ctx->ipayloadoff = 0; break; } } if (ctx->imsg->opcode == WSLAY_CONNECTION_CLOSE) { struct websocket_info_t *info = ctx->user_data; if (!wslay_queue_empty(ctx->send_ctrl_queue)) { wslay_event_send(ctx); } websocket_update_state(info->data, WEBSOCKET_STOP); } free(msg); } wslay_event_imsg_reset(ctx->imsg); if (ctx->imsg == &ctx->imsgs[1]) { ctx->imsg = &ctx->imsgs[0]; } } ctx->ipayloadlen = ctx->ipayloadoff = 0; } } else { if (r != WSLAY_ERR_WANT_READ || (ctx->error != WSLAY_ERR_WOULDBLOCK && ctx->error != 0)) { if ((r = wslay_event_queue_close_wrapper(ctx, 0, NULL, 0)) != 0) { return r; } return WSLAY_ERR_CALLBACK_FAILURE; } break; } } return 0; }
/** * \brief The function with websocket infinite loop */ void *vs_websocket_loop(void *arg) { /* The vContext is passed as *user_data* in callback functions. */ struct vContext *C = (struct vContext*)arg; struct VS_CTX *vs_ctx = CTX_server_ctx(C); struct IO_CTX *io_ctx = CTX_io_ctx(C); struct VStreamConn *stream_conn = CTX_current_stream_conn(C); struct VSession *vsession = CTX_current_session(C); struct VMessage *r_message=NULL, *s_message=NULL; wslay_event_context_ptr wslay_ctx; fd_set read_set, write_set; struct timeval tv; int ret, flags; unsigned int int_size; struct wslay_event_callbacks callbacks = { vs_recv_ws_callback_data, vs_send_ws_callback_data, NULL, NULL, NULL, NULL, vs_ws_recv_msg_callback }; /* Set socket blocking */ flags = fcntl(io_ctx->sockfd, F_GETFL, 0); fcntl(io_ctx->sockfd, F_SETFL, flags & ~O_NONBLOCK); http_handshake(io_ctx->sockfd); /* Try to get size of TCP buffer */ int_size = sizeof(int_size); getsockopt(io_ctx->sockfd, SOL_SOCKET, SO_RCVBUF, (void *)&stream_conn->socket_buffer_size, &int_size); r_message = (struct VMessage*)calloc(1, sizeof(struct VMessage)); s_message = (struct VMessage*)calloc(1, sizeof(struct VMessage)); CTX_r_message_set(C, r_message); CTX_s_message_set(C, s_message); stream_conn->host_state = TCP_SERVER_STATE_RESPOND_METHODS; if(is_log_level(VRS_PRINT_DEBUG_MSG)) { printf("%c[%d;%dm", 27, 1, 31); v_print_log(VRS_PRINT_DEBUG_MSG, "Server TCP state: RESPOND_methods\n"); printf("%c[%dm", 27, 0); } /* Set non-blocking */ flags = fcntl(io_ctx->sockfd, F_GETFL, 0); fcntl(io_ctx->sockfd, F_SETFL, flags | O_NONBLOCK); wslay_event_context_server_init(&wslay_ctx, &callbacks, C); /* "Never ending" loop */ while(vsession->stream_conn->host_state != TCP_SERVER_STATE_CLOSED) { if(vs_ctx->state != SERVER_STATE_READY) { vsession->stream_conn->host_state = TCP_SERVER_STATE_CLOSING; /* Try to close connection with websocket client */ wslay_event_queue_close(wslay_ctx, WSLAY_CODE_GOING_AWAY, (uint8_t*)"Server shutdown", /* Close message */ 15); /* The length of close message s*/ } /* Initialize read set */ FD_ZERO(&read_set); FD_SET(io_ctx->sockfd, &read_set); /* Initialize write set */ FD_ZERO(&write_set); FD_SET(io_ctx->sockfd, &write_set); /* Set timeout for select() */ if(stream_conn->host_state == TCP_SERVER_STATE_STREAM_OPEN) { /* Use negotiated FPS */ tv.tv_sec = 0; tv.tv_usec = 1000000/vsession->fps_host; } else { /* User have to send something in 30 seconds */ tv.tv_sec = VRS_TIMEOUT; tv.tv_usec = 0; } if( (ret = select(io_ctx->sockfd+1, &read_set, &write_set, NULL, /* Exception*/ &tv)) == -1) { if(is_log_level(VRS_PRINT_ERROR)) v_print_log(VRS_PRINT_ERROR, "%s:%s():%d select(): %s\n", __FILE__, __FUNCTION__, __LINE__, strerror(errno)); goto end; /* Was event on the listen socket */ } else if(ret>0){ if(FD_ISSET(io_ctx->sockfd, &read_set)) { if( wslay_event_recv(wslay_ctx) != 0 ) { goto end; } } else if (FD_ISSET(io_ctx->sockfd, &write_set)) { if( wslay_event_send(wslay_ctx) != 0 ) { goto end; } } } if(stream_conn->host_state == TCP_SERVER_STATE_STREAM_OPEN) { /* Check if there is any command in outgouing queue * and eventually pack these commands to buffer */ if((ret = v_STREAM_pack_message(C)) == 0 ) { goto end; } /* When at least one command was packed to buffer, then * queue this buffer to WebSocket layer */ if(ret == 1) { struct wslay_event_msg msgarg; msgarg.opcode = WSLAY_BINARY_FRAME; msgarg.msg = (uint8_t*)io_ctx->buf; msgarg.msg_length = io_ctx->buf_size; wslay_event_queue_msg(wslay_ctx, &msgarg); } } } end: if(is_log_level(VRS_PRINT_DEBUG_MSG)) { printf("%c[%d;%dm", 27, 1, 31); v_print_log(VRS_PRINT_DEBUG_MSG, "Server TCP state: CLOSING\n"); printf("%c[%dm", 27, 0); } /* Set up TCP CLOSING state (non-blocking) */ vs_CLOSING(C); /* Receive and Send messages are not neccessary any more */ if(r_message!=NULL) { free(r_message); r_message = NULL; CTX_r_message_set(C, NULL); } if(s_message!=NULL) { free(s_message); s_message = NULL; CTX_s_message_set(C, NULL); } /* TCP connection is considered as CLOSED, but it is not possible to use * this connection for other client */ stream_conn->host_state = TCP_SERVER_STATE_CLOSED; /* NULL pointer at stream connection */ CTX_current_stream_conn_set(C, NULL); /* Set TCP connection to CLOSED */ if(is_log_level(VRS_PRINT_DEBUG_MSG)) { printf("%c[%d;%dm", 27, 1, 31); v_print_log(VRS_PRINT_DEBUG_MSG, "Server TCP state: CLOSED\n"); printf("%c[%dm", 27, 0); } pthread_mutex_lock(&vs_ctx->data.mutex); /* Unsubscribe this session (this avatar) from all nodes */ vs_node_free_avatar_reference(vs_ctx, vsession); /* Try to destroy avatar node */ vs_node_destroy_avatar_node(vs_ctx, vsession); pthread_mutex_unlock(&vs_ctx->data.mutex); /* This session could be used again for authentication */ stream_conn->host_state=TCP_SERVER_STATE_LISTEN; /* Clear session flags */ vsession->flags = 0; if(is_log_level(VRS_PRINT_DEBUG_MSG)) { printf("%c[%d;%dm", 27, 1, 31); v_print_log(VRS_PRINT_DEBUG_MSG, "Server TCP state: LISTEN\n"); printf("%c[%dm", 27, 0); } free(C); C = NULL; pthread_exit(NULL); return NULL; }
void rig_pb_stream_write(rig_pb_stream_t *stream, rig_pb_stream_write_closure_t *closure) { c_return_if_fail(stream->type != STREAM_TYPE_DISCONNECTED); switch (stream->type) { case STREAM_TYPE_BUFFER: { c_return_if_fail(stream->buffer.other_end != NULL); c_return_if_fail(stream->buffer.other_end->type == STREAM_TYPE_BUFFER); c_array_append_val(stream->buffer.other_end->buffer.incoming_write_closures, closure); queue_data_buffer_stream_read(stream->buffer.other_end); break; } #ifdef USE_UV case STREAM_TYPE_FD: case STREAM_TYPE_TCP: { closure->write_req.data = closure; uv_write(&closure->write_req, (uv_stream_t *)&stream->fd.uv_fd_pipe, &closure->buf, 1, /* n buffers */ uv_write_done_cb); break; } case STREAM_TYPE_WEBSOCKET_SERVER: { struct wslay_event_fragmented_msg arg; memset(&arg, 0, sizeof(arg)); arg.opcode = WSLAY_BINARY_FRAME; arg.source.data = closure; arg.read_callback = fragmented_wslay_read_cb; closure->current_offset = 0; wslay_event_queue_fragmented_msg(stream->websocket_server.ctx, &arg); wslay_event_send(stream->websocket_server.ctx); break; } #endif #ifdef __EMSCRIPTEN__ case STREAM_TYPE_WORKER_IPC: if (stream->worker_ipc.in_worker) rig_emscripten_worker_post_to_main(closure->buf.base, closure->buf.len); else rig_emscripten_worker_post(stream->worker_ipc.worker, "rig_pb_stream_worker_onmessage", closure->buf.base, closure->buf.len); closure->done_callback(closure); break; case STREAM_TYPE_WEBSOCKET_CLIENT: c_debug("stream: websocket send() %d bytes", closure->buf.len); send(stream->websocket_client.socket, closure->buf.base, closure->buf.len, 0 /* flags */); closure->done_callback(closure); break; #endif case STREAM_TYPE_DISCONNECTED: c_warn_if_reached(); break; } }
int on_write_event() { return wslay_event_send(ctx_); }