/** Receive from stream. * * @retval -1 error * @retval 0 end-of-stream * @retval 1 normal receive * @retval 2 incomplete recv, recv again * */ int tport_recv_stream_ws(tport_t *self) { msg_t *msg; ssize_t n, N, veclen, i, m; int err; msg_iovec_t iovec[msg_n_fragments] = {{ 0 }}; tport_ws_t *wstp = (tport_ws_t *)self; uint8_t *data; ws_opcode_t oc; if (wstp->ws_initialized < 0) { return -1; } N = ws_read_frame(&wstp->ws, &oc, &data); if (N == -2) { return 2; } if ((N == -1000) || (N == 0)) { if (self->tp_msg) { msg_recv_commit(self->tp_msg, 0, 1); } return 0; /* End of stream */ } if (N < 0) { err = errno = EHOSTDOWN; SU_DEBUG_1(("%s(%p): su_getmsgsize(): %s (%d)\n", __func__, (void *)self, su_strerror(err), err)); return 0; } veclen = tport_recv_iovec(self, &self->tp_msg, iovec, N, 0); if (veclen < 0) return -1; msg = self->tp_msg; msg_set_address(msg, self->tp_addr, self->tp_addrlen); for (i = 0, n = 0; i < veclen; i++) { m = iovec[i].mv_len; assert(N >= n + m); memcpy(iovec[i].mv_base, data + n, m); n += m; } assert(N == n); /* Write the received data to the message dump file */ if (self->tp_master->mr_dump_file) tport_dump_iovec(self, msg, n, iovec, veclen, "recv", "from"); /* Mark buffer as used */ msg_recv_commit(msg, N, 0); return 1; }
abyss_bool websocket_hook(TSession *r) { wsh_t *wsh; int ret; int i; ws_opcode_t opcode; uint8_t *data; switch_event_node_t *nodes[MAX_EVENT_BIND_SLOTS]; int node_count = 0; char *p; char *key = NULL; char *version = NULL; char *proto = NULL; char *upgrade = NULL; for (i = 0; i < r->requestHeaderFields.size; i++) { TTableItem * const item = &r->requestHeaderFields.item[i]; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "headers %s: %s\n", item->name, item->value); } key = RequestHeaderValue(r, "sec-websocket-key"); version = RequestHeaderValue(r, "sec-websocket-version"); proto = RequestHeaderValue(r, "sec-websocket-protocol"); upgrade = RequestHeaderValue(r, "upgrade"); if (!key || !version || !proto || !upgrade) return FALSE; if (strncasecmp(upgrade, "websocket", 9) || strncasecmp(proto, "websocket", 9)) return FALSE; wsh = ws_init(r); if (!wsh) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "websocket error %d\n", ret); return FALSE; } ret = ws_handshake_kvp(wsh, key, version, proto); if (ret < 0) wsh->down = 1; if (ret != 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "handshake error %d\n", ret); return FALSE; } if (switch_event_bind_removable("websocket", SWITCH_EVENT_CUSTOM, "websocket::stophook", stop_hook_event_handler, wsh, &nodes[node_count++]) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't bind!\n"); node_count--; } while (!wsh->down) { int bytes = ws_read_frame(wsh, &opcode, &data); if (bytes < 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%d %s\n", opcode, (char *)data); switch_yield(100000); continue; } switch (opcode) { case WSOC_CLOSE: ws_close(wsh, 1000); break; case WSOC_CONTINUATION: switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "continue\n"); continue; case WSOC_TEXT: p = data; if (!p) continue; if (!strncasecmp(data, "event ", 6)) { switch_event_types_t type; char *subclass; if (node_count == MAX_EVENT_BIND_SLOTS - 1) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "cannot subscribe more than %d events\n", node_count); continue; } p += 6; if (p = strchr(p, ' ')) p++; if (!strncasecmp(p, "json ", 5)) { p += 5; } else if (!strncasecmp(p, "xml ", 4)) { p += 4; } else if (!strncasecmp(p, "plain ", 6)) { p += 6; } if (!*p) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "missing event type in [%s]\n", data); break; } else { } if (subclass = strchr(p, ' ')) { *subclass++ = '\0'; if (!*subclass) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "missing subclass\n"); continue; } } else { subclass = SWITCH_EVENT_SUBCLASS_ANY; } if (switch_name_event(p, &type) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unknown event %s\n", p); continue; } if (switch_event_bind_removable("websocket", type, subclass, event_handler, wsh, &nodes[node_count++]) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't bind!\n"); node_count--; continue; } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Bind %s\n", data); } } break; default: break; } } switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "wsh->down = %d, node_count = %d\n", wsh->down, node_count); switch_yield(2000); while (--node_count >= 0) switch_event_unbind(&nodes[node_count]); switch_safe_free(wsh); return FALSE; }