Ejemplo n.º 1
0
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);
}
Ejemplo n.º 2
0
/*! \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;
}
Ejemplo n.º 4
0
/*!
 * \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;
}
Ejemplo n.º 5
0
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;
}