static ssize_t recv_cb(wslay_event_context_ptr ev, uint8_t *buf, size_t len, int flags __attribute__((unused)), void *user_data) { struct transaction_t *txn = (struct transaction_t *) user_data; struct protstream *pin = txn->conn->pin; ssize_t n; if (txn->conn->sess_ctx) { pin = ((struct ws_context *) txn->ws_ctx)->h2_pin; } n = prot_read(pin, (char *) buf, len); if (!n) { /* No data */ if (pin->eof && !pin->fixedsize) wslay_event_set_error(ev, WSLAY_ERR_NO_MORE_MSG); else if (pin->error) wslay_event_set_error(ev, WSLAY_ERR_CALLBACK_FAILURE); else wslay_event_set_error(ev, WSLAY_ERR_WOULDBLOCK); n = -1; } syslog(LOG_DEBUG, "ws_recv_cb(%zu): n = %zd, eof = %d, err = '%s', errno = %m", len, n, pin->eof, pin->error ? pin->error : ""); return n; }
/** * \brief WIP: Wslay send callback */ ssize_t vs_send_ws_callback_data(wslay_event_context_ptr ctx, const uint8_t *data, size_t len, int flags, void *user_data) { struct vContext *C = (struct vContext*)user_data; struct IO_CTX *io_ctx = CTX_io_ctx(C); ssize_t r; int sflags = 0; #ifdef MSG_MORE if(flags & WSLAY_MSG_MORE) { sflags |= MSG_MORE; } #endif while((r = send(io_ctx->sockfd, data, len, sflags)) == -1 && errno == EINTR); if(r == -1) { if(errno == EAGAIN || errno == EWOULDBLOCK) { wslay_event_set_error(ctx, WSLAY_ERR_WOULDBLOCK); } else { wslay_event_set_error(ctx, WSLAY_ERR_CALLBACK_FAILURE); } } v_print_log(VRS_PRINT_DEBUG_MSG, "WS Callback Send Data\n"); return r; }
/** * \brief WIP: Wslay receive callback */ ssize_t vs_recv_ws_callback_data(wslay_event_context_ptr ctx, uint8_t *buf, size_t len, int flags, void *user_data) { struct vContext *C = (struct vContext*)user_data; struct IO_CTX *io_ctx = CTX_io_ctx(C); ssize_t r; (void)flags; while((r = recv(io_ctx->sockfd, buf, len, 0)) == -1 && errno == EINTR); if(r == -1) { if(errno == EAGAIN || errno == EWOULDBLOCK) { wslay_event_set_error(ctx, WSLAY_ERR_WOULDBLOCK); } else { wslay_event_set_error(ctx, WSLAY_ERR_CALLBACK_FAILURE); } } else if(r == 0) { /* Unexpected EOF is also treated as an error */ wslay_event_set_error(ctx, WSLAY_ERR_CALLBACK_FAILURE); r = -1; } v_print_log(VRS_PRINT_DEBUG_MSG, "WS Callback Received Data, len: %ld, flags: %d\n", len, flags); return r; }
static ssize_t want_read_cb(wslay_event_context_ptr ctx, uint8_t *buf, size_t len, int flags, void *user_data) { (void) flags; DSLink *link = user_data; if (link->_delay == 0) { wslay_event_set_error(ctx, WSLAY_ERR_WOULDBLOCK); return -1; } int read = dslink_socket_read_timeout(link->_socket, (char *) buf,len, link->_delay); link->_delay = 0; if (read == 0) { wslay_event_set_error(ctx, WSLAY_ERR_NO_MORE_MSG); return -1; } else if (read == DSLINK_SOCK_READ_ERR) { if (errno == MBEDTLS_ERR_SSL_WANT_READ || errno == MBEDTLS_ERR_SSL_TIMEOUT) { wslay_event_set_error(ctx, WSLAY_ERR_WOULDBLOCK); } else { wslay_event_set_error(ctx, WSLAY_ERR_CALLBACK_FAILURE); } return -1; } return read; }
static ssize_t mrb_wslay_event_recv_callback(wslay_event_context_ptr ctx, uint8_t *buf, size_t len, int flags, void *user_data) { mrb_wslay_user_data *data = (mrb_wslay_user_data *) user_data; mrb_state*mrb = data->mrb; int ai = mrb_gc_arena_save(mrb); struct mrb_jmpbuf *prev_jmp = mrb->jmp; struct mrb_jmpbuf c_jmp; mrb_int ret = -1; MRB_TRY(&c_jmp) { mrb->jmp = &c_jmp; mrb_value argv[2]; argv[0] = mrb_cptr_value(mrb, buf); argv[1] = mrb_fixnum_value(len); errno = 0; mrb_assert(mrb_type(data->recv_callback) == MRB_TT_PROC); mrb_value buf_obj = mrb_yield_argv(mrb, data->recv_callback, NELEMS(argv), argv); if (mrb_fixnum_p(buf_obj)) { ret = mrb_fixnum(buf_obj); } else { buf_obj = mrb_str_to_str(mrb, buf_obj); ret = RSTRING_LEN(buf_obj); if (ret < 0||ret > len) { mrb_raise(mrb, E_RANGE_ERROR, "returned buf doesn't fit"); } if (ret > 0) { memmove(buf, (uint8_t *) RSTRING_PTR(buf_obj), ret); } } mrb->jmp = prev_jmp; } MRB_CATCH(&c_jmp) { mrb->jmp = prev_jmp; if (mrb_obj_is_kind_of(mrb, mrb_obj_value(mrb->exc), mrb_class_get_under(mrb, mrb_module_get(mrb, "Errno"), "EAGAIN"))|| mrb_obj_is_kind_of(mrb, mrb_obj_value(mrb->exc), mrb_class_get_under(mrb, mrb_module_get(mrb, "Errno"), "EWOULDBLOCK"))) { mrb->exc = NULL; wslay_event_set_error(ctx, WSLAY_ERR_WOULDBLOCK); } else { wslay_event_set_error(ctx, WSLAY_ERR_CALLBACK_FAILURE); } } MRB_END_EXC(&c_jmp); mrb_gc_arena_restore(mrb, ai); return ret; }
ssize_t send_callback(wslay_event_context_ptr ctx, const uint8_t *data, size_t len, int flags, void *user_data) { WebSocketClient *ws = (WebSocketClient*)user_data; ssize_t r = ws->send_data(data, len, flags); if(r == -1) { if(errno == EAGAIN || errno == EWOULDBLOCK) { wslay_event_set_error(ctx, WSLAY_ERR_WOULDBLOCK); } else { wslay_event_set_error(ctx, WSLAY_ERR_CALLBACK_FAILURE); } } return r; }
ssize_t WebSocket::wslaySendCallback(wslay_event_context* ctx, const uint8_t* data, size_t len, int /*flags*/, void* user_data) { WebSocket* socket = static_cast<WebSocket*>(user_data); if (!socket->mClient) { wslay_event_set_error(ctx, WSLAY_ERR_CALLBACK_FAILURE); return -1; } if (!socket->mClient->write(data, len)) { wslay_event_set_error(ctx, WSLAY_ERR_CALLBACK_FAILURE); return -1; } return len; }
static ssize_t send_cb(wslay_event_context_ptr ev, const uint8_t *data, size_t len, int flags, void *user_data) { struct transaction_t *txn = (struct transaction_t *) user_data; int r; if (txn->conn->sess_ctx) { int last_chunk = (txn->flags.conn & CONN_CLOSE) && !(flags & WSLAY_MSG_MORE); r = http2_data_chunk(txn, (const char *) data, len, last_chunk, NULL /* md5ctx */); } else { r = prot_write(txn->conn->pout, (const char *) data, len); } syslog(LOG_DEBUG, "ws_send_cb(%zu): %d", len, r); if (r) { wslay_event_set_error(ev, WSLAY_ERR_CALLBACK_FAILURE); return -1; } return len; }
static ssize_t mrb_wslay_event_send_callback(wslay_event_context_ptr ctx, const uint8_t *buf, size_t len, int flags, void *user_data) { mrb_wslay_user_data *data = (mrb_wslay_user_data *) user_data; mrb_state* mrb = data->mrb; int ai = mrb_gc_arena_save(mrb); struct mrb_jmpbuf *prev_jmp = mrb->jmp; struct mrb_jmpbuf c_jmp; mrb_int ret = -1; MRB_TRY(&c_jmp) { data->mrb->jmp = &c_jmp; errno = 0; mrb_value buf_obj = mrb_str_new_static(mrb, (const char *) buf, len); mrb_assert(mrb_type(data->send_callback) == MRB_TT_PROC); mrb_value sent = mrb_yield(mrb, data->send_callback, buf_obj); ret = mrb_int(mrb, sent); mrb_assert(ret >= 0&&ret <= len); mrb->jmp = prev_jmp; } MRB_CATCH(&c_jmp) { mrb->jmp = prev_jmp; if (mrb_obj_is_kind_of(mrb, mrb_obj_value(mrb->exc), mrb_class_get_under(mrb, mrb_module_get(mrb, "Errno"), "EAGAIN"))|| mrb_obj_is_kind_of(mrb, mrb_obj_value(mrb->exc), mrb_class_get_under(mrb, mrb_module_get(mrb, "Errno"), "EWOULDBLOCK"))) { mrb->exc = NULL; wslay_event_set_error(ctx, WSLAY_ERR_WOULDBLOCK); } else { wslay_event_set_error(ctx, WSLAY_ERR_CALLBACK_FAILURE); } } MRB_END_EXC(&c_jmp); mrb_gc_arena_restore(mrb, ai); return ret; }
static ssize_t want_write_cb(wslay_event_context_ptr ctx, const uint8_t *data, size_t len, int flags, void *user_data) { (void) flags; DSLink *link = user_data; int written = dslink_socket_write(link->_socket, (char *) data, len); if (written < 0) { if (errno == MBEDTLS_ERR_SSL_WANT_WRITE) { wslay_event_set_error(ctx, WSLAY_ERR_WANT_WRITE); } else { wslay_event_set_error(ctx, WSLAY_ERR_CALLBACK_FAILURE); } return -1; } return written; }
/** * \brief WSLay send callback */ ssize_t vs_send_ws_callback_data(wslay_event_context_ptr ctx, const uint8_t *data, size_t len, int flags, void *user_data) { struct vContext *C = (struct vContext*)user_data; struct IO_CTX *io_ctx = CTX_io_ctx(C); ssize_t ret = 0; int sflags = 0; #ifdef MSG_MORE if(flags & WSLAY_MSG_MORE) { sflags |= MSG_MORE; } #endif /* Try to send all data */ while((ret = send(io_ctx->sockfd, data, len, sflags)) == -1 && errno == EINTR) { #if DEBUG_WEB_SOCKET v_print_log(VRS_PRINT_DEBUG_MSG, "WS Callback Send Data, len: %ld, flags: %d -> %ld\n", len, sflags, ret); #endif } #if DEBUG_WEB_SOCKET v_print_log(VRS_PRINT_DEBUG_MSG, "WS Callback Send Data, len: %ld, flags: %d -> ret: %ld\n", len, sflags, ret); #endif if(ret == -1) { if(errno == EAGAIN || errno == EWOULDBLOCK) { wslay_event_set_error(ctx, WSLAY_ERR_WOULDBLOCK); } else { wslay_event_set_error(ctx, WSLAY_ERR_CALLBACK_FAILURE); } } return ret; }
ssize_t recv_callback(wslay_event_context_ptr ctx, uint8_t *buf, size_t len, int flags, void *user_data) { struct Session *session = (struct Session*)user_data; ssize_t r; while((r = recv(session->fd, buf, len, 0)) == -1 && errno == EINTR); if(r == -1) { if(errno == EAGAIN || errno == EWOULDBLOCK) { wslay_event_set_error(ctx, WSLAY_ERR_WOULDBLOCK); } else { wslay_event_set_error(ctx, WSLAY_ERR_CALLBACK_FAILURE); } } else if(r == 0) { /* Unexpected EOF is also treated as an error */ wslay_event_set_error(ctx, WSLAY_ERR_CALLBACK_FAILURE); r = -1; } return r; }
websocket_return_t websocket_set_error(websocket_t *websocket, int val) { if (websocket == NULL) { WEBSOCKET_DEBUG("NULL parameter\n"); return WEBSOCKET_ALLOCATION_ERROR; } wslay_event_set_error(websocket->ctx, val); return WEBSOCKET_SUCCESS; }
ssize_t send_callback(wslay_event_context_ptr ctx, const uint8_t *data, size_t len, int flags, void *user_data) { struct Session *session = (struct Session*)user_data; ssize_t r; int sflags = 0; #ifdef MSG_MORE if(flags & WSLAY_MSG_MORE) { sflags |= MSG_MORE; } #endif // MSG_MORE while((r = send(session->fd, data, len, sflags)) == -1 && errno == EINTR); if(r == -1) { if(errno == EAGAIN || errno == EWOULDBLOCK) { wslay_event_set_error(ctx, WSLAY_ERR_WOULDBLOCK); } else { wslay_event_set_error(ctx, WSLAY_ERR_CALLBACK_FAILURE); } } return r; }
ssize_t WebSocket::wslayRecvCallback(wslay_event_context* ctx, uint8_t* data, size_t len, int /*flags*/, void* user_data) { // return up to len bytes WebSocket* socket = static_cast<WebSocket*>(user_data); if (!socket->mClient) { wslay_event_set_error(ctx, WSLAY_ERR_CALLBACK_FAILURE); return -1; } if (socket->mBuffers.isEmpty()) { wslay_event_set_error(ctx, WSLAY_ERR_WOULDBLOCK); return -1; } size_t rem = len; uint8_t* ptr = data; auto it = socket->mBuffers.begin(); while (rem > 0 && it != socket->mBuffers.end()) { Buffer& buf = *it; if (rem >= buf.size()) { memcpy(ptr, buf.data(), buf.size()); ptr += buf.size(); rem -= buf.size(); } else { // read and move memcpy(ptr, buf.data(), rem); memmove(buf.data(), buf.data() + rem, buf.size() - rem); buf.resize(buf.size() - rem); return len; } socket->mBuffers.erase(it++); } return ptr - data; }
static ssize_t recv_callback(wslay_event_context_ptr ctx, uint8_t *buf, size_t len, int flags, void *_conn) { h2o_websocket_conn_t *conn = _conn; /* return WOULDBLOCK if no data */ if (conn->sock->input->size == 0) { wslay_event_set_error(conn->ws_ctx, WSLAY_ERR_WOULDBLOCK); return -1; } if (conn->sock->input->size < len) len = conn->sock->input->size; memcpy(buf, conn->sock->input->bytes, len); h2o_buffer_consume(&conn->sock->input, len); return len; }
static ssize_t send_callback(wslay_event_context_ptr ctx, const uint8_t *data, size_t len, int flags, void *_conn) { h2o_websocket_conn_t *conn = _conn; h2o_iovec_t *buf; /* return WOULDBLOCK if pending or no buffer available */ if (h2o_socket_is_writing(conn->sock) || conn->_write_buf.cnt == sizeof(conn->_write_buf.bufs) / sizeof(conn->_write_buf.bufs[0])) { wslay_event_set_error(conn->ws_ctx, WSLAY_ERR_WOULDBLOCK); return -1; } buf = &conn->_write_buf.bufs[conn->_write_buf.cnt]; /* copy data */ buf->base = h2o_mem_alloc(len); buf->len = len; memcpy(buf->base, data, len); ++conn->_write_buf.cnt; return len; }
static ssize_t send_callback(wslay_event_context_ptr ctx, const uint8_t *data, size_t len, int flags, void *_conn) { h2o_websocket_conn_t *conn = _conn; h2o_iovec_t buf; /* return WOULDBLOCK if pending (TODO: queue fixed number of chunks, instead of only one) */ if (h2o_socket_is_writing(conn->sock)) { wslay_event_set_error(conn->ws_ctx, WSLAY_ERR_WOULDBLOCK); return -1; } /* copy data */ conn->_write_buf = h2o_mem_realloc(conn->_write_buf, len); memcpy(conn->_write_buf, data, len); /* write */ buf.base = conn->_write_buf; buf.len = len; h2o_socket_write(conn->sock, &buf, 1, on_write_complete); return len; }
static void mrb_wslay_event_on_msg_recv_callback(wslay_event_context_ptr ctx, const struct wslay_event_on_msg_recv_arg *arg, void *user_data) { mrb_wslay_user_data *data = (mrb_wslay_user_data *) user_data; mrb_state *mrb = data->mrb; int ai = mrb_gc_arena_save(mrb); struct mrb_jmpbuf *prev_jmp = mrb->jmp; struct mrb_jmpbuf c_jmp; MRB_TRY(&c_jmp) { mrb->jmp = &c_jmp; mrb_value argv[4]; argv[0] = mrb_fixnum_value(arg->rsv); argv[1] = MRB_GET_OPCODE(mrb_fixnum_value(arg->opcode)); argv[2] = mrb_str_new(mrb, (const char *) arg->msg, arg->msg_length); argv[3] = MRB_GET_STATUSCODE(mrb_fixnum_value(arg->status_code)); mrb_value on_msg_recv_arg = mrb_obj_new(mrb, mrb_class_get_under(mrb, mrb_module_get_under(mrb, mrb_module_get(mrb, "Wslay"), "Event"), "OnMsgRecvArg"), NELEMS(argv), argv); mrb_assert(mrb_type(data->on_msg_recv_callback) == MRB_TT_PROC); mrb_yield(mrb, data->on_msg_recv_callback, on_msg_recv_arg); mrb_gc_arena_restore(mrb, ai); mrb->jmp = prev_jmp; } MRB_CATCH(&c_jmp) { mrb->jmp = prev_jmp; wslay_event_set_error(ctx, WSLAY_ERR_CALLBACK_FAILURE); mrb_gc_arena_restore(mrb, ai); MRB_THROW(mrb->jmp); } MRB_END_EXC(&c_jmp); }