struct ast_json *ast_ari_websocket_session_read( struct ast_ari_websocket_session *session) { RAII_VAR(struct ast_json *, message, NULL, ast_json_unref); if (ast_websocket_fd(session->ws_session) < 0) { return NULL; } while (!message) { int res; char *payload; uint64_t payload_len; enum ast_websocket_opcode opcode; int fragmented; res = ast_wait_for_input( ast_websocket_fd(session->ws_session), -1); if (res <= 0) { ast_log(LOG_WARNING, "WebSocket poll error: %s\n", strerror(errno)); return NULL; } res = ast_websocket_read(session->ws_session, &payload, &payload_len, &opcode, &fragmented); if (res != 0) { ast_log(LOG_WARNING, "WebSocket read error: %s\n", strerror(errno)); return NULL; } switch (opcode) { case AST_WEBSOCKET_OPCODE_CLOSE: ast_debug(1, "WebSocket closed\n"); return NULL; case AST_WEBSOCKET_OPCODE_TEXT: message = ast_json_load_buf(payload, payload_len, NULL); if (message == NULL) { ast_log(LOG_WARNING, "WebSocket input failed to parse\n"); } break; default: /* Ignore all other message types */ break; } } return ast_json_ref(message); }
/*! \brief WebSocket connection handler. */ static void websocket_cb(struct ast_websocket *session, struct ast_variable *parameters, struct ast_variable *headers) { struct ast_taskprocessor *serializer; struct transport_create_data create_data; struct ws_transport *transport; struct transport_read_data read_data; if (ast_websocket_set_nonblock(session)) { ast_websocket_unref(session); return; } if (ast_websocket_set_timeout(session, get_write_timeout())) { ast_websocket_unref(session); return; } serializer = create_websocket_serializer(); if (!serializer) { ast_websocket_unref(session); return; } create_data.ws_session = session; if (ast_sip_push_task_synchronous(serializer, transport_create, &create_data)) { ast_log(LOG_ERROR, "Could not create WebSocket transport.\n"); ast_websocket_unref(session); return; } transport = create_data.transport; read_data.transport = transport; while (ast_wait_for_input(ast_websocket_fd(session), -1) > 0) { enum ast_websocket_opcode opcode; int fragmented; if (ast_websocket_read(session, &read_data.payload, &read_data.payload_len, &opcode, &fragmented)) { break; } if (opcode == AST_WEBSOCKET_OPCODE_TEXT || opcode == AST_WEBSOCKET_OPCODE_BINARY) { ast_sip_push_task_synchronous(serializer, transport_read, &read_data); } else if (opcode == AST_WEBSOCKET_OPCODE_CLOSE) { break; } } ast_sip_push_task_synchronous(serializer, transport_shutdown, transport); ast_taskprocessor_unreference(serializer); ast_websocket_unref(session); }
static void *transport_websocket_init(const struct ast_socket_io_session *session) { struct ast_websocket *ws; struct ast_str *uri = ast_str_create(128); enum ast_websocket_result result; struct ast_uri *session_uri = ast_socket_io_uri(session); struct ast_tls_config *tls_cfg = NULL; if (!uri) { ast_log(LOG_ERROR, "Unable to allocate websocket uri\n"); return NULL; } ast_str_set(&uri, 0, "%s://%s:%s/socket.io/%s/websocket/%s", ast_uri_is_secure(session_uri) ? "wss" : "ws", ast_uri_host(session_uri), ast_uri_port(session_uri), SOCKET_IO_VERSION, ast_socket_io_id(session)); if (!ast_strlen_zero(ast_uri_query(session_uri))) { ast_str_append(&uri, 0, "?%s", ast_uri_query(session_uri)); } if (ast_uri_is_secure(session_uri)) { /* The websocket client expects a copy of the TLS configuration so provide it */ tls_cfg = ast_calloc(1, sizeof(*tls_cfg)); ast_set_flag(&tls_cfg->flags, AST_SSL_DONT_VERIFY_SERVER); } ws = ast_websocket_client_create( ast_str_buffer(uri), "socket.io", tls_cfg, &result); ast_free(uri); if (ws) { struct protoent *p; p = getprotobyname("tcp"); if (p) { int arg = 1; if (setsockopt(ast_websocket_fd(ws), p->p_proto, TCP_NODELAY, (char *) &arg, sizeof(arg) ) < 0) { ast_log(LOG_WARNING, "Failed to set TCP_NODELAY on HTTP connection: %s\n", strerror(errno)); ast_log(LOG_WARNING, "Some HTTP requests may be slow to respond.\n"); } } ast_websocket_set_nonblock(ws); } return ws; }
/*! * \brief Destroy the pjsip transport. * * Called by pjsip transport manager. */ static pj_status_t ws_destroy(pjsip_transport *transport) { struct ws_transport *wstransport = (struct ws_transport *)transport; int fd = ast_websocket_fd(wstransport->ws_session); if (fd > 0) { ast_websocket_close(wstransport->ws_session, 1000); shutdown(fd, SHUT_RDWR); } ao2_ref(wstransport, -1); return PJ_SUCCESS; }
static int transport_websocket_recv(void *obj, char **data, unsigned int timeout_secs) { int res; int timeout_ms = timeout_secs * 1000; /* In Socket.io, 0 means forever... */ if (timeout_ms == 0) { timeout_ms = -1; } res = ast_wait_for_input(ast_websocket_fd(obj), timeout_ms); if (res < 0) { ast_log(LOG_WARNING, "WebSocket poll error: %s\n", strerror(errno)); return -1; } else if (res == 0) { return 0; } res = ast_websocket_read_string(obj, data); return res; }