Exemplo n.º 1
0
 //--------------------------------------------------------------
 void Connection::setupAddress(){
     int fd = libwebsocket_get_socket_fd( ws );
     
     client_ip.resize(128);
     client_name.resize(128);
     
     libwebsockets_get_peer_addresses(fd, &client_name[0], client_name.size(),
                                      &client_ip[0], client_ip.size());
 }
Exemplo n.º 2
0
 //--------------------------------------------------------------
 unsigned int
 Reactor::_allow(struct libwebsocket *ws, Protocol* const protocol, const long fd){
     std::string client_ip(128, 0);
     std::string client_name(128, 0);
     
     libwebsockets_get_peer_addresses(context, ws, libwebsocket_get_socket_fd(ws),
                                      &client_name[0], client_name.size(),
                                      &client_ip[0], client_ip.size());
     return protocol->_allowClient(client_name, client_ip);
 }
Exemplo n.º 3
0
FString FWebSocket::RemoteEndPoint()
{
#if !PLATFORM_HTML5
	ANSICHAR Peer_Name[128];
	ANSICHAR Peer_Ip[128];
	libwebsockets_get_peer_addresses(Context, Wsi, libwebsocket_get_socket_fd(Wsi), Peer_Name, sizeof Peer_Name, Peer_Ip, sizeof Peer_Ip);
	return FString(Peer_Name);
#endif

#if PLATFORM_HTML5
	return FString(TEXT("TODO:REMOTEENDPOINT"));
#endif
}
Exemplo n.º 4
0
int websocket_fd_set(int socket, fd_set *set)
{
	libwebsocket_context *context = contexts[socket].context;
	if(context == NULL)
		return -1;
	context_data *ctx_data = (context_data *)libwebsocket_context_user(context);
	int max = 0;
	for(int i = 0; i < WS_CLIENTS; i++)
	{
		per_session_data *pss = ctx_data->port_map[i];
		if(pss == NULL)
			continue;
		int fd = libwebsocket_get_socket_fd(pss->wsi);
		if(fd > max)
			max = fd;
		FD_SET(fd, set);
	}
	return max;
}
Exemplo n.º 5
0
static int websocket_callback(struct libwebsocket_context *context, struct libwebsocket *wsi, enum libwebsocket_callback_reasons reason, void *user, void *in, size_t len)
{
	struct per_session_data *pss = (struct per_session_data *)user;
	context_data *ctx_data = (context_data *)libwebsocket_context_user(context);

	switch(reason)
	{

	case LWS_CALLBACK_ESTABLISHED:
	{
		int port = -1;
		for(int i = 0; i < WS_CLIENTS; i++)
		{
			int j = (ctx_data->last_used_port + i + 1) % WS_CLIENTS;
			if(ctx_data->port_map[j] == NULL)
			{
				port = j;
				break;
			}
		}
		if(port == -1)
		{
			dbg_msg("websockets", "no free ports, dropping");
			pss->port = -1;
			return -1;
		}
		ctx_data->last_used_port = port;
		pss->wsi = wsi;
		int fd = libwebsocket_get_socket_fd(wsi);
		socklen_t addr_size = sizeof(pss->addr);
		getpeername(fd, (struct sockaddr *)&pss->addr, &addr_size);
		int orig_port = ntohs(pss->addr.sin_port);
		pss->addr.sin_port = htons(port);
		pss->send_buffer.Init();
		pss->port = port;
		ctx_data->port_map[port] = pss;
		char addr_str[NETADDR_MAXSTRSIZE];
		inet_ntop(AF_INET, &pss->addr.sin_addr, addr_str, sizeof(addr_str));
		dbg_msg("websockets", "connection established with %s:%d , assigned fake port %d", addr_str, orig_port, port);
	}
	break;

	case LWS_CALLBACK_CLOSED:
	{
		dbg_msg("websockets", "connection with fake port %d closed", pss->port);
		if (pss->port > -1) {
			unsigned char close_packet[] = { 0x10, 0x0e, 0x00, 0x04 };
			receive_chunk(ctx_data, pss, &close_packet, sizeof(close_packet));
			pss->wsi = 0;
			ctx_data->port_map[pss->port] = NULL;
		}
	}
	break;

	case LWS_CALLBACK_SERVER_WRITEABLE:
	{
		websocket_chunk *chunk = (websocket_chunk *)pss->send_buffer.First();
		if(chunk == NULL)
			break;
		int len = chunk->size - chunk->read;
		int n = libwebsocket_write(wsi, &chunk->data[LWS_SEND_BUFFER_PRE_PADDING + chunk->read], chunk->size - chunk->read, LWS_WRITE_BINARY);
		if(n < 0)
			return 1;
		if(n < len)
		{
			chunk->read += n;
			libwebsocket_callback_on_writable(context, wsi);
			break;
		}
		pss->send_buffer.PopFirst();
		libwebsocket_callback_on_writable(context, wsi);
	}
	break;

	case LWS_CALLBACK_RECEIVE:
		if(pss->port == -1)
			return -1;
		if(!receive_chunk(ctx_data, pss, in, len))
			return 1;
		break;

	default:
		break;
	}

	return 0;
}
Exemplo n.º 6
0
int janus_websockets_send_message(void *transport, void *request_id, gboolean admin, json_t *message) {
	if(message == NULL)
		return -1;
	if(transport == NULL) {
		json_decref(message);
		return -1;
	}
	/* Make sure this is not related to a closed /freed WebSocket session */
	janus_mutex_lock(&old_wss_mutex);
	janus_websockets_client *client = (janus_websockets_client *)transport;
#ifdef HAVE_LIBWEBSOCKETS_NEWAPI
	if(g_list_find(old_wss, client) != NULL || !client->wsi) {
#else
	if(g_list_find(old_wss, client) != NULL || !client->context || !client->wsi) {
#endif
		json_decref(message);
		message = NULL;
		transport = NULL;
		janus_mutex_unlock(&old_wss_mutex);
		return -1;
	}
	janus_mutex_lock(&client->mutex);
	/* Convert to string and enqueue */
	char *payload = json_dumps(message, json_format);
	g_async_queue_push(client->messages, payload);
#ifdef HAVE_LIBWEBSOCKETS_NEWAPI
	lws_callback_on_writable(client->wsi);
#else
	libwebsocket_callback_on_writable(client->context, client->wsi);
#endif
	janus_mutex_unlock(&client->mutex);
	janus_mutex_unlock(&old_wss_mutex);
	json_decref(message);
	return 0;
}

void janus_websockets_session_created(void *transport, guint64 session_id) {
	/* We don't care */
}

void janus_websockets_session_over(void *transport, guint64 session_id, gboolean timeout) {
	if(transport == NULL || !timeout)
		return;
	/* We only care if it's a timeout: if so, close the connection */
	janus_websockets_client *client = (janus_websockets_client *)transport;
	/* Make sure this is not related to a closed WebSocket session */
	janus_mutex_lock(&old_wss_mutex);
#ifdef HAVE_LIBWEBSOCKETS_NEWAPI
	if(g_list_find(old_wss, client) == NULL && client->wsi){
#else
	if(g_list_find(old_wss, client) == NULL && client->context && client->wsi){
#endif
		janus_mutex_lock(&client->mutex);
		client->session_timeout = 1;
#ifdef HAVE_LIBWEBSOCKETS_NEWAPI
		lws_callback_on_writable(client->wsi);
#else
		libwebsocket_callback_on_writable(client->context, client->wsi);
#endif
		janus_mutex_unlock(&client->mutex);
	}
	janus_mutex_unlock(&old_wss_mutex);
}


/* Thread */
void *janus_websockets_thread(void *data) {
#ifdef HAVE_LIBWEBSOCKETS_NEWAPI
	struct lws_context *service = (struct lws_context *)data;
#else
	struct libwebsocket_context *service = (struct libwebsocket_context *)data;
#endif
	if(service == NULL) {
		JANUS_LOG(LOG_ERR, "Invalid service\n");
		return NULL;
	}

	const char *type = NULL;
	if(service == wss)
		type = "WebSocket (Janus API)";
	else if(service == swss)
		type = "Secure WebSocket (Janus API)";
	else if(service == admin_wss)
		type = "WebSocket (Admin API)";
	else if(service == admin_swss)
		type = "Secure WebSocket (Admin API)";

	JANUS_LOG(LOG_INFO, "%s thread started\n", type);

	while(g_atomic_int_get(&initialized) && !g_atomic_int_get(&stopping)) {
		/* libwebsockets is single thread, we cycle through events here */
#ifdef HAVE_LIBWEBSOCKETS_NEWAPI
		lws_service(service, 50);
#else
		libwebsocket_service(service, 50);
#endif
	}

	/* Get rid of the WebSockets server */
#ifdef HAVE_LIBWEBSOCKETS_NEWAPI
	lws_cancel_service(service);
#else
	libwebsocket_cancel_service(service);
#endif
	/* Done */
	JANUS_LOG(LOG_INFO, "%s thread ended\n", type);
	return NULL;
}


/* WebSockets */
static int janus_websockets_callback_http(
#ifdef HAVE_LIBWEBSOCKETS_NEWAPI
		struct lws *wsi,
		enum lws_callback_reasons reason,
#else
		struct libwebsocket_context *this,
		struct libwebsocket *wsi,
		enum libwebsocket_callback_reasons reason,
#endif
		void *user, void *in, size_t len)
{
	/* This endpoint cannot be used for HTTP */
	switch(reason) {
		case LWS_CALLBACK_HTTP:
			JANUS_LOG(LOG_VERB, "Rejecting incoming HTTP request on WebSockets endpoint\n");
#ifdef HAVE_LIBWEBSOCKETS_NEWAPI
			lws_return_http_status(wsi, 403, NULL);
#else
			libwebsockets_return_http_status(this, wsi, 403, NULL);
#endif
			/* Close and free connection */
			return -1;
		case LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION:
			if (!in) {
				JANUS_LOG(LOG_VERB, "Rejecting incoming HTTP request on WebSockets endpoint: no sub-protocol specified\n");
				return -1;
			}
			break;
		default:
			break;
	}
	return 0;
}

static int janus_websockets_callback_https(
#ifdef HAVE_LIBWEBSOCKETS_NEWAPI
		struct lws *wsi,
		enum lws_callback_reasons reason,
#else
		struct libwebsocket_context *this,
		struct libwebsocket *wsi,
		enum libwebsocket_callback_reasons reason,
#endif
		void *user, void *in, size_t len)
{
	/* We just forward the event to the HTTP handler */
#ifdef HAVE_LIBWEBSOCKETS_NEWAPI
	return janus_websockets_callback_http(wsi, reason, user, in, len);
#else
	return janus_websockets_callback_http(this, wsi, reason, user, in, len);
#endif
}

/* This callback handles Janus API requests */
static int janus_websockets_common_callback(
#ifdef HAVE_LIBWEBSOCKETS_NEWAPI
		struct lws *wsi,
		enum lws_callback_reasons reason,
#else
		struct libwebsocket_context *this,
		struct libwebsocket *wsi,
		enum libwebsocket_callback_reasons reason,
#endif
		void *user, void *in, size_t len, gboolean admin)
{
	const char *log_prefix = admin ? "AdminWSS" : "WSS";
	janus_websockets_client *ws_client = (janus_websockets_client *)user;
	switch(reason) {
		case LWS_CALLBACK_ESTABLISHED: {
			/* Is there any filtering we should apply? */
			char name[256], ip[256];
#ifdef HAVE_LIBWEBSOCKETS_NEWAPI
			lws_get_peer_addresses(wsi, lws_get_socket_fd(wsi), name, 256, ip, 256);
#else
			libwebsockets_get_peer_addresses(this, wsi, libwebsocket_get_socket_fd(wsi), name, 256, ip, 256);
#endif
			JANUS_LOG(LOG_VERB, "[%s-%p] WebSocket connection opened from %s by %s\n", log_prefix, wsi, ip, name);
			if(!janus_websockets_is_allowed(ip, admin)) {
				JANUS_LOG(LOG_ERR, "[%s-%p] IP %s is unauthorized to connect to the WebSockets %s API interface\n", log_prefix, wsi, ip, admin ? "Admin" : "Janus");
				/* Close the connection */
#ifdef HAVE_LIBWEBSOCKETS_NEWAPI
				lws_callback_on_writable(wsi);
#else
				libwebsocket_callback_on_writable(this, wsi);
#endif
				return -1;
			}
			JANUS_LOG(LOG_VERB, "[%s-%p] WebSocket connection accepted\n", log_prefix, wsi);
			if(ws_client == NULL) {
				JANUS_LOG(LOG_ERR, "[%s-%p] Invalid WebSocket client instance...\n", log_prefix, wsi);
				return -1;
			}
			/* Clean the old sessions list, in case this pointer was used before */
			janus_mutex_lock(&old_wss_mutex);
			if(g_list_find(old_wss, ws_client) != NULL)
				old_wss = g_list_remove(old_wss, ws_client);
			janus_mutex_unlock(&old_wss_mutex);
			/* Prepare the session */
#ifndef HAVE_LIBWEBSOCKETS_NEWAPI
			ws_client->context = this;
#endif
			ws_client->wsi = wsi;
			ws_client->messages = g_async_queue_new();
			ws_client->buffer = NULL;
			ws_client->buflen = 0;
			ws_client->bufpending = 0;
			ws_client->bufoffset = 0;
			ws_client->session_timeout = 0;
			ws_client->destroy = 0;
			janus_mutex_init(&ws_client->mutex);
			/* Let us know when the WebSocket channel becomes writeable */
#ifdef HAVE_LIBWEBSOCKETS_NEWAPI
			lws_callback_on_writable(wsi);
#else
			libwebsocket_callback_on_writable(this, wsi);
#endif
			JANUS_LOG(LOG_VERB, "[%s-%p]   -- Ready to be used!\n", log_prefix, wsi);
			/* Notify handlers about this new transport */
			if(notify_events && gateway->events_is_enabled()) {
				json_t *info = json_object();
				json_object_set_new(info, "event", json_string("connected"));
				json_object_set_new(info, "admin_api", admin ? json_true() : json_false());
				json_object_set_new(info, "ip", json_string(ip));
				gateway->notify_event(&janus_websockets_transport, ws_client, info);
			}
			return 0;
		}
		case LWS_CALLBACK_RECEIVE: {
			JANUS_LOG(LOG_HUGE, "[%s-%p] Got %zu bytes:\n", log_prefix, wsi, len);
#ifdef HAVE_LIBWEBSOCKETS_NEWAPI
			if(ws_client == NULL || ws_client->wsi == NULL) {
#else
			if(ws_client == NULL || ws_client->context == NULL || ws_client->wsi == NULL) {
#endif
				JANUS_LOG(LOG_ERR, "[%s-%p] Invalid WebSocket client instance...\n", log_prefix, wsi);
				return -1;
			}
			/* Is this a new message, or part of a fragmented one? */
#ifdef HAVE_LIBWEBSOCKETS_NEWAPI
			const size_t remaining = lws_remaining_packet_payload(wsi);
#else
			const size_t remaining = libwebsockets_remaining_packet_payload(wsi);
#endif
			if(ws_client->incoming == NULL) {
				JANUS_LOG(LOG_HUGE, "[%s-%p] First fragment: %zu bytes, %zu remaining\n", log_prefix, wsi, len, remaining);
				ws_client->incoming = g_malloc0(len+1);
				memcpy(ws_client->incoming, in, len);
				ws_client->incoming[len] = '\0';
				JANUS_LOG(LOG_HUGE, "%s\n", ws_client->incoming);
			} else {
				size_t offset = strlen(ws_client->incoming);
				JANUS_LOG(LOG_HUGE, "[%s-%p] Appending fragment: offset %zu, %zu bytes, %zu remaining\n", log_prefix, wsi, offset, len, remaining);
				ws_client->incoming = g_realloc(ws_client->incoming, offset+len+1);
				memcpy(ws_client->incoming+offset, in, len);
				ws_client->incoming[offset+len] = '\0';
				JANUS_LOG(LOG_HUGE, "%s\n", ws_client->incoming+offset);
			}
#ifdef HAVE_LIBWEBSOCKETS_NEWAPI
			if(remaining > 0 || !lws_is_final_fragment(wsi)) {
#else
			if(remaining > 0 || !libwebsocket_is_final_fragment(wsi)) {
#endif
				/* Still waiting for some more fragments */
				JANUS_LOG(LOG_HUGE, "[%s-%p] Waiting for more fragments\n", log_prefix, wsi);
				return 0;
			}
			JANUS_LOG(LOG_HUGE, "[%s-%p] Done, parsing message: %zu bytes\n", log_prefix, wsi, strlen(ws_client->incoming));
			/* If we got here, the message is complete: parse the JSON payload */
			json_error_t error;
			json_t *root = json_loads(ws_client->incoming, 0, &error);
			g_free(ws_client->incoming);
			ws_client->incoming = NULL;
			/* Notify the core, passing both the object and, since it may be needed, the error */
			gateway->incoming_request(&janus_websockets_transport, ws_client, NULL, admin, root, &error);
			return 0;
		}
		case LWS_CALLBACK_SERVER_WRITEABLE: {
#ifdef HAVE_LIBWEBSOCKETS_NEWAPI
			if(ws_client == NULL || ws_client->wsi == NULL) {
#else
			if(ws_client == NULL || ws_client->context == NULL || ws_client->wsi == NULL) {
#endif
				JANUS_LOG(LOG_ERR, "[%s-%p] Invalid WebSocket client instance...\n", log_prefix, wsi);
				return -1;
			}
			if(!ws_client->destroy && !g_atomic_int_get(&stopping)) {
				janus_mutex_lock(&ws_client->mutex);
				/* Check if we have a pending/partial write to complete first */
				if(ws_client->buffer && ws_client->bufpending > 0 && ws_client->bufoffset > 0
						&& !ws_client->destroy && !g_atomic_int_get(&stopping)) {
					JANUS_LOG(LOG_HUGE, "[%s-%p] Completing pending WebSocket write (still need to write last %d bytes)...\n",
						log_prefix, wsi, ws_client->bufpending);
#ifdef HAVE_LIBWEBSOCKETS_NEWAPI
					int sent = lws_write(wsi, ws_client->buffer + ws_client->bufoffset, ws_client->bufpending, LWS_WRITE_TEXT);
#else
					int sent = libwebsocket_write(wsi, ws_client->buffer + ws_client->bufoffset, ws_client->bufpending, LWS_WRITE_TEXT);
#endif
					JANUS_LOG(LOG_HUGE, "[%s-%p]   -- Sent %d/%d bytes\n", log_prefix, wsi, sent, ws_client->bufpending);
					if(sent > -1 && sent < ws_client->bufpending) {
						/* We still couldn't send everything that was left, we'll try and complete this in the next round */
						ws_client->bufpending -= sent;
						ws_client->bufoffset += sent;
					} else {
						/* Clear the pending/partial write queue */
						ws_client->bufpending = 0;
						ws_client->bufoffset = 0;
					}
					/* Done for this round, check the next response/notification later */
#ifdef HAVE_LIBWEBSOCKETS_NEWAPI
					lws_callback_on_writable(wsi);
#else
					libwebsocket_callback_on_writable(this, wsi);
#endif
					janus_mutex_unlock(&ws_client->mutex);
					return 0;
				}
				/* Shoot all the pending messages */
				char *response = g_async_queue_try_pop(ws_client->messages);
				if(response && !ws_client->destroy && !g_atomic_int_get(&stopping)) {
					/* Gotcha! */
					int buflen = LWS_SEND_BUFFER_PRE_PADDING + strlen(response) + LWS_SEND_BUFFER_POST_PADDING;
					if(ws_client->buffer == NULL) {
						/* Let's allocate a shared buffer */
						JANUS_LOG(LOG_HUGE, "[%s-%p] Allocating %d bytes (response is %zu bytes)\n", log_prefix, wsi, buflen, strlen(response));
						ws_client->buflen = buflen;
						ws_client->buffer = g_malloc0(buflen);
					} else if(buflen > ws_client->buflen) {
						/* We need a larger shared buffer */
						JANUS_LOG(LOG_HUGE, "[%s-%p] Re-allocating to %d bytes (was %d, response is %zu bytes)\n", log_prefix, wsi, buflen, ws_client->buflen, strlen(response));
						ws_client->buflen = buflen;
						ws_client->buffer = g_realloc(ws_client->buffer, buflen);
					}
					memcpy(ws_client->buffer + LWS_SEND_BUFFER_PRE_PADDING, response, strlen(response));
					JANUS_LOG(LOG_HUGE, "[%s-%p] Sending WebSocket message (%zu bytes)...\n", log_prefix, wsi, strlen(response));
#ifdef HAVE_LIBWEBSOCKETS_NEWAPI
					int sent = lws_write(wsi, ws_client->buffer + LWS_SEND_BUFFER_PRE_PADDING, strlen(response), LWS_WRITE_TEXT);
#else
					int sent = libwebsocket_write(wsi, ws_client->buffer + LWS_SEND_BUFFER_PRE_PADDING, strlen(response), LWS_WRITE_TEXT);
#endif
					JANUS_LOG(LOG_HUGE, "[%s-%p]   -- Sent %d/%zu bytes\n", log_prefix, wsi, sent, strlen(response));
					if(sent > -1 && sent < (int)strlen(response)) {
						/* We couldn't send everything in a single write, we'll complete this in the next round */
						ws_client->bufpending = strlen(response) - sent;
						ws_client->bufoffset = LWS_SEND_BUFFER_PRE_PADDING + sent;
						JANUS_LOG(LOG_HUGE, "[%s-%p]   -- Couldn't write all bytes (%d missing), setting offset %d\n",
							log_prefix, wsi, ws_client->bufpending, ws_client->bufoffset);
					}
					/* We can get rid of the message */
					free(response);
					/* Done for this round, check the next response/notification later */
#ifdef HAVE_LIBWEBSOCKETS_NEWAPI
					lws_callback_on_writable(wsi);
#else
					libwebsocket_callback_on_writable(this, wsi);
#endif
					janus_mutex_unlock(&ws_client->mutex);
					return 0;
				}
				janus_mutex_unlock(&ws_client->mutex);
			}
			return 0;
		}
		case LWS_CALLBACK_CLOSED: {
			JANUS_LOG(LOG_VERB, "[%s-%p] WS connection down, closing\n", log_prefix, wsi);
			janus_websockets_destroy_client(ws_client, wsi, log_prefix);
			JANUS_LOG(LOG_VERB, "[%s-%p]   -- closed\n", log_prefix, wsi);
			return 0;
		}
		case LWS_CALLBACK_WSI_DESTROY: {
			JANUS_LOG(LOG_VERB, "[%s-%p] WS connection down, destroying\n", log_prefix, wsi);
			janus_websockets_destroy_client(ws_client, wsi, log_prefix);
			JANUS_LOG(LOG_VERB, "[%s-%p]   -- destroyed\n", log_prefix, wsi);
			return 0;
		}
		default:
			if(wsi != NULL) {
				JANUS_LOG(LOG_HUGE, "[%s-%p] %d (%s)\n", log_prefix, wsi, reason, janus_websockets_reason_string(reason));
			} else {
				JANUS_LOG(LOG_HUGE, "[%s] %d (%s)\n", log_prefix, reason, janus_websockets_reason_string(reason));
			}
			break;
	}
	return 0;
}

/* This callback handles Janus API requests */
static int janus_websockets_callback(
#ifdef HAVE_LIBWEBSOCKETS_NEWAPI
		struct lws *wsi,
		enum lws_callback_reasons reason,
#else
		struct libwebsocket_context *this,
		struct libwebsocket *wsi,
		enum libwebsocket_callback_reasons reason,
#endif
		void *user, void *in, size_t len)
{
#ifdef HAVE_LIBWEBSOCKETS_NEWAPI
	return janus_websockets_common_callback(wsi, reason, user, in, len, FALSE);
#else
	return janus_websockets_common_callback(this, wsi, reason, user, in, len, FALSE);
#endif
}

static int janus_websockets_callback_secure(
#ifdef HAVE_LIBWEBSOCKETS_NEWAPI
		struct lws *wsi,
		enum lws_callback_reasons reason,
#else
		struct libwebsocket_context *this,
		struct libwebsocket *wsi,
		enum libwebsocket_callback_reasons reason,
#endif
		void *user, void *in, size_t len)
{
	/* We just forward the event to the Janus API handler */
#ifdef HAVE_LIBWEBSOCKETS_NEWAPI
	return janus_websockets_callback(wsi, reason, user, in, len);
#else
	return janus_websockets_callback(this, wsi, reason, user, in, len);
#endif
}

/* This callback handles Admin API requests */
static int janus_websockets_admin_callback(
#ifdef HAVE_LIBWEBSOCKETS_NEWAPI
		struct lws *wsi,
		enum lws_callback_reasons reason,
#else
		struct libwebsocket_context *this,
		struct libwebsocket *wsi,
		enum libwebsocket_callback_reasons reason,
#endif
		void *user, void *in, size_t len)
{
#ifdef HAVE_LIBWEBSOCKETS_NEWAPI
	return janus_websockets_common_callback(wsi, reason, user, in, len, TRUE);
#else
	return janus_websockets_common_callback(this, wsi, reason, user, in, len, TRUE);
#endif
}

static int janus_websockets_admin_callback_secure(
#ifdef HAVE_LIBWEBSOCKETS_NEWAPI
		struct lws *wsi,
		enum lws_callback_reasons reason,
#else
		struct libwebsocket_context *this,
		struct libwebsocket *wsi,
		enum libwebsocket_callback_reasons reason,
#endif
		void *user, void *in, size_t len)
{
	/* We just forward the event to the Admin API handler */
#ifdef HAVE_LIBWEBSOCKETS_NEWAPI
	return janus_websockets_admin_callback(wsi, reason, user, in, len);
#else
	return janus_websockets_admin_callback(this, wsi, reason, user, in, len);
#endif
}
Exemplo n.º 7
0
static int callback_mqtt(struct libwebsocket_context *context,
#endif
		struct libwebsocket *wsi,
		enum libwebsocket_callback_reasons reason,
		void *user,
		void *in,
		size_t len)
{
	struct mosquitto_db *db;
	struct mosquitto *mosq = NULL;
	struct mosquitto__packet *packet;
	int count, i, j;
	const struct libwebsocket_protocols *p;
	struct libws_mqtt_data *u = (struct libws_mqtt_data *)user;
	size_t pos;
	uint8_t *buf;
	int rc;
	uint8_t byte;

	db = &int_db;

	switch (reason) {
		case LWS_CALLBACK_ESTABLISHED:
			mosq = context__init(db, WEBSOCKET_CLIENT);
			if(mosq){
				p = libwebsockets_get_protocol(wsi);
				for (i=0; i<db->config->listener_count; i++){
					if (db->config->listeners[i].protocol == mp_websockets) {
						for (j=0; db->config->listeners[i].ws_protocol[j].name; j++){
							if (p == &db->config->listeners[i].ws_protocol[j]){
								mosq->listener = &db->config->listeners[i];
								mosq->listener->client_count++;
							}
						}
					}
				}
				if(!mosq->listener){
					mosquitto__free(mosq);
					return -1;
				}
#if !defined(LWS_LIBRARY_VERSION_NUMBER)
				mosq->ws_context = context;
#endif
				mosq->wsi = wsi;
#ifdef WITH_TLS
				if(in){
					mosq->ssl = (SSL *)in;
					if(!mosq->listener->ssl_ctx){
						mosq->listener->ssl_ctx = SSL_get_SSL_CTX(mosq->ssl);
					}
				}
#endif
				u->mosq = mosq;
			}else{
				return -1;
			}
			easy_address(libwebsocket_get_socket_fd(wsi), mosq);
			if(!mosq->address){
				/* getpeername and inet_ntop failed and not a bridge */
				mosquitto__free(mosq);
				u->mosq = NULL;
				return -1;
			}
			if(mosq->listener->max_connections > 0 && mosq->listener->client_count > mosq->listener->max_connections){
				if(db->config->connection_messages == true){
					log__printf(NULL, MOSQ_LOG_NOTICE, "Client connection from %s denied: max_connections exceeded.", mosq->address);
				}
				mosquitto__free(mosq);
				u->mosq = NULL;
				return -1;
			}
			mosq->sock = libwebsocket_get_socket_fd(wsi);
			HASH_ADD(hh_sock, db->contexts_by_sock, sock, sizeof(mosq->sock), mosq);
			break;

		case LWS_CALLBACK_CLOSED:
			if(!u){
				return -1;
			}
			mosq = u->mosq;
			if(mosq){
				if(mosq->sock != INVALID_SOCKET){
					HASH_DELETE(hh_sock, db->contexts_by_sock, mosq);
					mosq->sock = INVALID_SOCKET;
					mosq->pollfd_index = -1;
				}
				mosq->wsi = NULL;
#ifdef WITH_TLS
				mosq->ssl = NULL;
#endif
				do_disconnect(db, mosq);
			}
			break;

		case LWS_CALLBACK_SERVER_WRITEABLE:
			if(!u){
				return -1;
			}
			mosq = u->mosq;
			if(!mosq){
				return -1;
			}

			db__message_write(db, mosq);

			if(mosq->out_packet && !mosq->current_out_packet){
				mosq->current_out_packet = mosq->out_packet;
				mosq->out_packet = mosq->out_packet->next;
				if(!mosq->out_packet){
					mosq->out_packet_last = NULL;
				}
			}

			if(mosq->current_out_packet && !lws_send_pipe_choked(mosq->wsi)){
				packet = mosq->current_out_packet;

				if(packet->pos == 0 && packet->to_process == packet->packet_length){
					/* First time this packet has been dealt with.
					 * libwebsockets requires that the payload has
					 * LWS_SEND_BUFFER_PRE_PADDING space available before the
					 * actual data and LWS_SEND_BUFFER_POST_PADDING afterwards.
					 * We've already made the payload big enough to allow this,
					 * but need to move it into position here. */
					memmove(&packet->payload[LWS_SEND_BUFFER_PRE_PADDING], packet->payload, packet->packet_length);
					packet->pos += LWS_SEND_BUFFER_PRE_PADDING;
				}
				count = libwebsocket_write(wsi, &packet->payload[packet->pos], packet->to_process, LWS_WRITE_BINARY);
				if(count < 0){
					if (mosq->state == mosq_cs_disconnect_ws || mosq->state == mosq_cs_disconnecting){
						return -1;
					}
					return 0;
				}
#ifdef WITH_SYS_TREE
				g_bytes_sent += count;
#endif
				packet->to_process -= count;
				packet->pos += count;
				if(packet->to_process > 0){
					if (mosq->state == mosq_cs_disconnect_ws || mosq->state == mosq_cs_disconnecting){
						return -1;
					}
					break;
				}

#ifdef WITH_SYS_TREE
				g_msgs_sent++;
				if(((packet->command)&0xF6) == PUBLISH){
					g_pub_msgs_sent++;
				}
#endif

				/* Free data and reset values */
				mosq->current_out_packet = mosq->out_packet;
				if(mosq->out_packet){
					mosq->out_packet = mosq->out_packet->next;
					if(!mosq->out_packet){
						mosq->out_packet_last = NULL;
					}
				}

				packet__cleanup(packet);
				mosquitto__free(packet);

				mosq->next_msg_out = mosquitto_time() + mosq->keepalive;
			}
			if (mosq->state == mosq_cs_disconnect_ws || mosq->state == mosq_cs_disconnecting){
				return -1;
			}
			if(mosq->current_out_packet){
				libwebsocket_callback_on_writable(mosq->ws_context, mosq->wsi);
			}
			break;

		case LWS_CALLBACK_RECEIVE:
			if(!u || !u->mosq){
				return -1;
			}
			mosq = u->mosq;
			pos = 0;
			buf = (uint8_t *)in;
			G_BYTES_RECEIVED_INC(len);
			while(pos < len){
				if(!mosq->in_packet.command){
					mosq->in_packet.command = buf[pos];
					pos++;
					/* Clients must send CONNECT as their first command. */
					if(mosq->state == mosq_cs_new && (mosq->in_packet.command&0xF0) != CONNECT){
						return -1;
					}
				}
				if(mosq->in_packet.remaining_count <= 0){
					do{
						if(pos == len){
							return 0;
						}
						byte = buf[pos];
						pos++;

						mosq->in_packet.remaining_count--;
						/* Max 4 bytes length for remaining length as defined by protocol.
						* Anything more likely means a broken/malicious client.
						*/
						if(mosq->in_packet.remaining_count < -4){
							return -1;
						}

						mosq->in_packet.remaining_length += (byte & 127) * mosq->in_packet.remaining_mult;
						mosq->in_packet.remaining_mult *= 128;
					}while((byte & 128) != 0);
					mosq->in_packet.remaining_count *= -1;

					if(mosq->in_packet.remaining_length > 0){
						mosq->in_packet.payload = mosquitto__malloc(mosq->in_packet.remaining_length*sizeof(uint8_t));
						if(!mosq->in_packet.payload){
							return -1;
						}
						mosq->in_packet.to_process = mosq->in_packet.remaining_length;
					}
				}
				if(mosq->in_packet.to_process>0){
					if(len - pos >= mosq->in_packet.to_process){
						memcpy(&mosq->in_packet.payload[mosq->in_packet.pos], &buf[pos], mosq->in_packet.to_process);
						mosq->in_packet.pos += mosq->in_packet.to_process;
						pos += mosq->in_packet.to_process;
						mosq->in_packet.to_process = 0;
					}else{
						memcpy(&mosq->in_packet.payload[mosq->in_packet.pos], &buf[pos], len-pos);
						mosq->in_packet.pos += len-pos;
						mosq->in_packet.to_process -= len-pos;
						return 0;
					}
				}
				/* All data for this packet is read. */
				mosq->in_packet.pos = 0;

#ifdef WITH_SYS_TREE
				G_MSGS_RECEIVED_INC(1);
				if(((mosq->in_packet.command)&0xF5) == PUBLISH){
					G_PUB_MSGS_RECEIVED_INC(1);
				}
#endif
				rc = handle__packet(db, mosq);

				/* Free data and reset values */
				packet__cleanup(&mosq->in_packet);

				mosq->last_msg_in = mosquitto_time();

				if(rc && (mosq->out_packet || mosq->current_out_packet)) {
					if(mosq->state != mosq_cs_disconnecting){
						mosq->state = mosq_cs_disconnect_ws;
					}
					libwebsocket_callback_on_writable(mosq->ws_context, mosq->wsi);
				} else if (rc) {
					do_disconnect(db, mosq);
					return -1;
				}
			}
			break;

		default:
			break;
	}

	return 0;
}
Exemplo n.º 8
0
void _ortc_parse_message(ortc_context *context, char *message){
  char *messageId, *messageCount, *messageTotal, *messagePart, *channelNameStr, *messageStr, *params, *permissionsStr, *exceptionStr, *validateString, *operationType;
  struct cap pmatch[3], pmatch2[5];
  int iMessageTotal, wsSock, opt;
  size_t len, hbLen;
  ortc_dnode *ch;
  char hbStr[24];
  
  if(message[0] == 'a') {
    if (slre_match(&context->reMessage, message, (int)strlen(message), pmatch)) {         //is message   
      channelNameStr = _ortc_get_from_slre(1, pmatch);
      messageStr = _ortc_get_from_slre(2, pmatch);
      if(slre_match(&context->reMultipart, messageStr, (int)strlen(messageStr), pmatch2)){
		messageId =    _ortc_get_from_slre(1, pmatch2);
		messageCount = _ortc_get_from_slre(2, pmatch2);
		messageTotal = _ortc_get_from_slre(3, pmatch2);
		messagePart =  _ortc_get_from_slre(4, pmatch2);
		iMessageTotal = atoi(messageTotal);
		if(iMessageTotal > 1){ //multipart message
			_ortc_dlist_insert(context->multiparts, messageId, channelNameStr, messagePart, atoi(messageCount), NULL);
		_ortc_check_if_got_all_parts(context, messageId, iMessageTotal);
		} else {
			_ortc_fire_onMessage(context, channelNameStr, messagePart);
		}
		free(messageId);
		free(messageCount);
		free(messageTotal);
		free(messagePart);
      } else {
        _ortc_fire_onMessage(context, channelNameStr, messageStr);
      }
      free(channelNameStr);
      free(messageStr);
    } else if (slre_match(&context->reOperation, message, (int)strlen(message), pmatch)) {
      params = _ortc_get_from_slre(2, pmatch);
      operationType = _ortc_get_from_slre(1, pmatch);
      if(strncmp(operationType, "ortc-validated", 14)==0){
		if(slre_match(&context->rePermissions, params, (int)strlen(params), pmatch2)){
			permissionsStr = _ortc_get_from_slre(1, pmatch2);
			_ortc_save_permissions(context, permissionsStr);
			free(permissionsStr);
		}
		_ortc_change_state(context, CONNECTED);
		
      } else if(strncmp(operationType, "ortc-subscribed", 15)==0){
	if(slre_match(&context->reChannel, params, (int)strlen(params), pmatch2)){
	  channelNameStr = _ortc_get_from_slre(1, pmatch2);
	  ch = _ortc_dlist_search(context->channels, channelNameStr);
	  if(ch != NULL)
	    ch->num += 2; //isSubscribed
	  if(context->onSubscribed != NULL)
	    context->onSubscribed(context, channelNameStr);	  
	  free(channelNameStr);
	}
      } else if(strncmp(operationType, "ortc-unsubscribed", 17)==0){
	if(slre_match(&context->reChannel, params, (int)strlen(params), pmatch2)){
	  channelNameStr = _ortc_get_from_slre(1, pmatch2);
	  _ortc_dlist_delete(context->channels, channelNameStr);
	  if(context->onUnsubscribed != NULL)
	    context->onUnsubscribed(context, channelNameStr);
	  free(channelNameStr);
	}
      } else if(strncmp(operationType, "ortc-error", 10)==0){
	if(slre_match(&context->reException, params, (int)strlen(params), pmatch2)){
		_ortc_cancel_connecting(context);
		exceptionStr = _ortc_get_from_slre(1, pmatch2);
		_ortc_exception(context, exceptionStr);
		free(exceptionStr);
	}
      }
      free(params);
      free(operationType);
    }

  } else if(message[0] == 'o' && strlen(message)==1){
    wsSock = libwebsocket_get_socket_fd(context->wsi);
    opt = ORTC_SNDBUF_SIZE;
    setsockopt(wsSock, SOL_SOCKET, SO_SNDBUF, (const char*)&opt, sizeof(opt));
	
	
	if(context->heartbeatActive){
		snprintf(hbStr, sizeof(hbStr), "%d;%d;", context->heartbeatTime, context->heartbeatFails);
		hbLen = strlen(hbStr);
	} else {
		hbLen = 0;
	}
    len = 17 + strlen(context->appKey) +  strlen(context->authToken) + strlen(context->announcementSubChannel) + strlen(context->sessionId) + strlen(context->metadata) + hbLen;
	
    validateString = malloc(len+1);
    if(validateString == NULL){
      _ortc_exception(context, "malloc() failed in ortc parese message");
      return;
    }
	if(context->heartbeatActive)
		snprintf(validateString, len, "\"validate;%s;%s;%s;%s;%s;%s\"", context->appKey, context->authToken, context->announcementSubChannel, context->sessionId, context->metadata, hbStr);
	else
		snprintf(validateString, len, "\"validate;%s;%s;%s;%s;%s;\"", context->appKey, context->authToken, context->announcementSubChannel, context->sessionId, context->metadata);
    _ortc_send_command(context, validateString);
	
  } else if(strncmp(message, "c[1000,\"Normal closure\"]", 20)==0){
	_ortc_exception(context, "Server is about to close the websocket!");
  }
}
static int websocket_callback(struct libwebsocket_context *context,struct libwebsocket *wsi,enum libwebsocket_callback_reasons reason, void *user,void *in, size_t len)
{
	//printf("Switch: %i\n",reason);
	DebugOut(5) << __SMALLFILE__ << ":" << __LINE__ << "websocket_callback:" << reason << endl;


	switch (reason)
	{
		case LWS_CALLBACK_CLIENT_WRITEABLE:
		{
			break;
		}
		case LWS_CALLBACK_CLOSED:
		{
			sinkManager->disconnectAll(wsi);
			break;
		}
		case LWS_CALLBACK_CLIENT_RECEIVE:
		{
			break;
		}
		case LWS_CALLBACK_SERVER_WRITEABLE:
		{
			break;
		}

		case LWS_CALLBACK_RECEIVE:
		{

		}
		case LWS_CALLBACK_HTTP:
		{
			//TODO: Verify that ALL requests get sent via LWS_CALLBACK_HTTP, so we can use that instead of LWS_CALLBACK_RECIEVE
			//TODO: Do we want exceptions, or just to return an invalid json reply? Probably an invalid json reply.
			DebugOut() << __SMALLFILE__ << ":" << __LINE__ << " Requested: " << (char*)in << "\n";

			QByteArray d((char*)in,len);

			WebSocketSinkManager * manager = sinkManager;

			if(manager->expectedMessageFrames && manager->partialMessageIndex < manager->expectedMessageFrames)
			{
				manager->incompleteMessage += d;
				manager->partialMessageIndex++;
				break;
			}
			else if(manager->expectedMessageFrames && manager->partialMessageIndex == manager->expectedMessageFrames)
			{
				d = manager->incompleteMessage + d;
				manager->expectedMessageFrames = 0;
			}

			QJsonDocument doc;
			if(doBinary)
				doc = QJsonDocument::fromBinaryData(d);
			else
				doc = QJsonDocument::fromJson(d);

			if(doc.isNull())
			{
				DebugOut(DebugOut::Error)<<"Invalid message"<<endl;
				return 0;
			}

			QVariantMap call = doc.toVariant().toMap();

			string type = call["type"].toString().toStdString();
			string name = call["name"].toString().toStdString();
			string id = call["transactionid"].toString().toStdString();

			if (type == "multiframe")
			{

				manager->expectedMessageFrames = call["frames"].toInt();
				manager->partialMessageIndex = 1;
				manager->incompleteMessage = "";
			}
			else if (type == "method")
			{
				if(name == "getRanged")
				{
					QVariantMap data = call["data"].toMap();

					PropertyList propertyList;

					propertyList.push_back(data["property"].toString().toStdString());

					double timeBegin = data["timeBegin"].toDouble();
					double timeEnd = data["timeEnd"].toDouble();
					double sequenceBegin = data["sequenceBegin"].toInt();
					double sequenceEnd = data["sequenceEnd"].toInt();

					if ((timeBegin < 0 && timeEnd > 0) || (timeBegin > 0 && timeEnd < 0))
					{
						DebugOut(DebugOut::Warning)<<"Invalid time begin/end pair"<<endl;
					}
					else if ((sequenceBegin < 0 && sequenceEnd > 0) || (sequenceBegin > 0 && sequenceEnd < 0))
					{
						DebugOut(DebugOut::Warning)<<"Invalid sequence begin/end pair"<<endl;
					}
					else
					{
						sinkManager->addSingleShotRangedSink(wsi,propertyList,timeBegin,timeEnd,sequenceBegin,sequenceEnd,id);
					}
				}
				else if (name == "get")
				{
					QVariantMap data = call["data"].toMap();
					Zone::Type zone = Zone::None;
					if(data.contains("zone"))
					{
						zone = data["zone"].toInt();
					}
					sinkManager->addSingleShotSink(wsi,data["property"].toString().toStdString(),zone,id);

				}
				else if (name == "set")
				{
					QVariantMap data = call["data"].toMap();
					Zone::Type zone(Zone::None);
					if(data.contains("zone"))
					{
						zone = data["zone"].toInt();
					}
					sinkManager->setValue(wsi,data["property"].toString().toStdString(), data["value"].toString().toStdString(), zone, id);
				}
				else if (name == "subscribe")
				{
					std::string data = call["data"].toString().toStdString();
					sinkManager->addSink(wsi, data, id);

				}
				else if (name == "unsubscribe")
				{
					std::string data = call["data"].toString().toStdString();
					sinkManager->removeSink(wsi,data,id);

				}
				else if (name == "getSupportedEventTypes")
				{
					QVariantMap reply;
					QStringList list;

					PropertyList supported = sinkManager->getSupportedProperties();
					for(VehicleProperty::Property i : supported)
					{
						list.append(i.c_str());
					}

					reply["type"] = "methodReply";
					reply["name"] = "getSupportedEventTypes";
					reply["transactionid"] = id.c_str();
					reply["data"] = list;

					QByteArray replystr;

					if(doBinary)
						replystr = QJsonDocument::fromVariant(reply).toBinaryData();
					else
					{
						replystr = QJsonDocument::fromVariant(reply).toJson();
						cleanJson(replystr);
					}

					lwsWrite(wsi, replystr, replystr.length());
				}
				else
				{
					DebugOut(0)<<"Unknown method called."<<endl;
				}
			}
			break;
		}
		case LWS_CALLBACK_ADD_POLL_FD:
		{
			//printf("Adding poll %i\n",sinkManager);
			DebugOut(5) << __SMALLFILE__ <<":"<< __LINE__ << "Adding poll" << endl;
			if (sinkManager != 0)
			{
				//sinkManager->addPoll((int)(long)user);
				sinkManager->addPoll(libwebsocket_get_socket_fd(wsi));
			}
			else
			{
				DebugOut(5) << "Error, invalid sink manager!!" << endl;
			}
			break;
		}
		case LWS_CALLBACK_DEL_POLL_FD:
		{
			sinkManager->removePoll(libwebsocket_get_socket_fd(wsi));
			break;
		}
		case LWS_CALLBACK_SET_MODE_POLL_FD:
		{
			//Set the poll mode
			break;
		}
		case LWS_CALLBACK_CLEAR_MODE_POLL_FD:
		{
			//Don't handle this yet.
			break;
		}
		default:
		{
			//printf("Unhandled callback: %i\n",reason);
			DebugOut() << __SMALLFILE__ <<":"<< __LINE__ << "Unhandled callback:" << reason << "\n";
			break;
		}
	}
	return 0; 
}
Exemplo n.º 10
0
int WebSocketClient2::lws_callback_vopp(struct libwebsocket_context * ctx,
                                        struct libwebsocket *wsi,
                                        enum libwebsocket_callback_reasons reason,
                                        void *user, void *in, size_t len)
{
	unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 4096 +
                      LWS_SEND_BUFFER_POST_PADDING];
	int l;
    int n;
    std::string str1, str2;

    struct client_session_user_data *ssd = (struct client_session_user_data*)user;
    WebSocketClient2 *wsc = (WebSocketClient2*)(libwebsocket_context_user_data(ctx));

	switch (reason) {
	case LWS_CALLBACK_CLOSED:
		fprintf(stderr, "mirror: LWS_CALLBACK_CLOSED\n");
        if (ssd->pc != NULL) {
            delete ssd->pc; ssd->pc = NULL;
        }
        wsc->lws_connection_closed(wsi);
		break;

	case LWS_CALLBACK_CLIENT_ESTABLISHED:
        // 因为在调用libwebsocket_client_connect的时候,事件循环还没有启动,
        // 所以事件不会传递出来。
        qLogx()<<"connection state:"
               <<libwebsockets_remaining_packet_payload(wsi)
               <<libwebsocket_get_socket_fd(wsi)
               <<libwebsocket_get_connect_state(wsi);

        ssd->pc = new PackageCombiner;

        wsc->lws_new_connection_established(wsi);
		/*
		 * start the ball rolling,
		 * LWS_CALLBACK_CLIENT_WRITEABLE will come next service
		 */

		// libwebsocket_callback_on_writable(ctx, wsi);
		break;

	case LWS_CALLBACK_CLIENT_RECEIVE:
        /*		fprintf(stderr, "rx %d '%s'\n", (int)len, (char *)in); */
        // wsc->lws_ws_message_ready(wsi, (char*)in, len);

        str1 = std::string((char*)in, len);
        ssd->pc->save_fragment(str1);
        if (ssd->pc->is_package_finish(str1)) {
            str2 = ssd->pc->get_full_package(str1);
            strncpy(ssd->full_message, str2.c_str(), sizeof(ssd->full_message)-1);
            n = wsc->lws_ws_message_ready(wsi, ssd->full_message, str2.length());
        }

		break;

	case LWS_CALLBACK_CLIENT_WRITEABLE:
		// l = sprintf((char *)&buf[LWS_SEND_BUFFER_PRE_PADDING],
		// 			"c #%06X %d %d %d;",
		// 			(int)random() & 0xffffff,
		// 			(int)random() % 500,
		// 			(int)random() % 250,
		// 			(int)random() % 24);

		// libwebsocket_write(wsi,
        //                    &buf[LWS_SEND_BUFFER_PRE_PADDING], l, LWS_WRITE_TEXT);

		// /* get notified as soon as we can write again */

		// libwebsocket_callback_on_writable(ctx, wsi);
        libwebsocket_callback_on_writable(ctx, wsi);
		// /*
		//  * Without at least this delay, we choke the browser
		//  * and the connection stalls, despite we now take care about
		//  * flow control
		//  */

		// usleep(200);
		break;

	default:
		break;
	}

    return 0;
}
Exemplo n.º 11
0
bool WebSocketClient2::on_wsctx_inited()
{
    QUrl mu(this->m_uri);
    qLogx()<<mu;

    unsigned short port = mu.port(18080);
    QString host = mu.host();
    QString path = mu.path();

    // 默认为1,最安全
    int ssl_mode = 1; // 0,ws://, 1,wss://encrypt, 2,wss://self signed

    if (mu.scheme().toLower() == "ws") {
        ssl_mode = 0;
    } else if (mu.scheme().toLower() == "wss") {
        ssl_mode = 2;
    } else {
        Q_ASSERT(1==2);
    }

    int conn_retry = 3;
    while (conn_retry -- > 0) {
        // 需要关注测试一下,这个调用是否是阻塞式的,如果是非阻塞式,则可以这么用
        // 否则,还需要考虑其他解决方式。
        qLogx()<<this->m_uri<<host<<path<<port;
        qLogx()<<"Before libwss clint connect..."<<QDateTime::currentDateTime();
        this->m_wsi = libwebsocket_client_connect(this->m_lws_ctx, host.toAscii().data(), port, ssl_mode,
                                                  path.toAscii().data(), 
                                                  host.toAscii().data(), host.toAscii().data(),
                                                  vopp_client_protocols[0].name, -1);
        // this->m_wsi = libwebsocket_client_connect(this->m_lws_ctx, host.toAscii().data(), port, 0,
        //                                           path.toAscii().data(), 
        //                                           host.toAscii().data(), host.toAscii().data(),
        //                                           vopp_client_protocols[0].name, -1);

        if (this->m_wsi == NULL) {
            qLogx()<<"libwebsocket dumb connect failed.";
            return false;
        }

        // here the conn state is 4, but when run to CALLBACK_ESTABLISH, the state will be 3 ok
        qLogx()<<"After libwss client connect..."<<QDateTime::currentDateTime()
               <<libwebsockets_remaining_packet_payload(this->m_wsi)
               <<libwebsocket_get_socket_fd(this->m_wsi)
               <<libwebsocket_get_connect_state(this->m_wsi);
        
        qLogx()<<"client wsi:"<<this->m_wsi;
        if (libwebsocket_client_is_connected(this->m_wsi)) {
            break;
        } else {
            break;
            this->m_wsi = NULL;
            qLogx()<<"Invalid client wsi state, retry.. "<<conn_retry;
            if (conn_retry == 0) {
                Q_ASSERT(1==2);
                return false;
            }
        }
    }
    return true;
}
Exemplo n.º 12
0
static int websocketCallback(struct libwebsocket_context *context, struct libwebsocket *wsi, enum libwebsocket_callback_reasons reason, void *user, void *in, size_t len)
{
	switch (reason) {
	case LWS_CALLBACK_ESTABLISHED:
		{
			// TODO: should be earlier?
			int fd = libwebsocket_get_socket_fd(wsi);
			struct sockaddr sadr;
			memset(&sadr, 0, sizeof(sadr));
			socklen_t len = sizeof(sadr);
			int retval = getpeername(fd, &sadr, &len);
			if (retval < 0) {
				Com_Printf("getpeername failed: %s (%d)\n", LOG_NET, strerror(errno), errno);
				return -1;
			}

			STUBBED("FIXME: bad macro shit");
			netadr_t addr;
			netadr_t *temp = &addr;
			SockadrToNetadr(&sadr, temp);

			auto it = wsState->connections.find(addr);
			if (it != wsState->connections.end()) {
				// must not exist yet
				Com_Printf("ERROR: New connection from \"%s\" but it already exists", LOG_NET, NET_AdrToString(&addr));
				return -1;
			}

			std::unique_ptr<Connection> conn(new Connection(addr, wsi));
			conn->setReadyState(Open);
			wsState->wsiLookup.emplace(wsi, conn.get());

			bool success = false;
			std::tie(it, success) = wsState->connections.emplace(addr, std::move(conn));
			assert(success);  // it wasn't there before so this can't fail

			libwebsocket_callback_on_writable(wsState->websocketContext, wsi);
		}
		break;

	case LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH:
		Com_Printf("websocketCallback LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH\n", LOG_NET);
		break;

	case LWS_CALLBACK_CLIENT_ESTABLISHED:
		{
			auto wsiIt = wsState->wsiLookup.find(wsi);
			if (wsiIt == wsState->wsiLookup.end()) {
				Com_Printf("ERROR: Established on connection we don't know\n", LOG_NET);
				return -1;
			}
			Connection *conn = wsiIt->second;
			assert(conn->wsi == wsi);
			assert(conn->readyState == Connecting);
			conn->setReadyState(Open);

		libwebsocket_callback_on_writable(wsState->websocketContext, wsi);
		}
		break;

	case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
	case LWS_CALLBACK_CLOSED:
		{
			assert(wsi != NULL);

			auto wsiIt = wsState->wsiLookup.find(wsi);
			if (wsiIt == wsState->wsiLookup.end()) {
				Com_Printf("ERROR: Close on connection we don't know\n", LOG_NET);
				return -1;
			}
			Connection *conn = wsiIt->second;
			assert(conn->wsi == wsi);
			assert(conn->readyState != Closed);
			conn->setReadyState(Closed);

			netadr_t addr = conn->addr;
			auto connIt = wsState->connections.find(addr);
			// it must be there
			assert(connIt != wsState->connections.end());
			assert(conn == connIt->second.get());

			bool hasDataRemaining = !conn->recvBuffer.empty();
			if (hasDataRemaining) {
				// if there's data remaining it must also be in pendingData
				assert(wsState->pendingData.find(conn) != wsState->pendingData.end());
			}

			Com_Printf("Disconnecting from %s\n", LOG_NET, NET_AdrToString(&addr));

			wsState->connections.erase(connIt);

			// Connection destructor should have removed this
			wsiIt = wsState->wsiLookup.find(wsi);
			assert(wsiIt == wsState->wsiLookup.end());

			if (hasDataRemaining) {
				// if it was in pendingData the destructor must have removed it
				assert(wsState->pendingData.find(conn) == wsState->pendingData.end());
			}
		}
		break;

	case LWS_CALLBACK_RECEIVE:
	case LWS_CALLBACK_CLIENT_RECEIVE:
		{
			assert(wsi != NULL);

			Connection *conn = wsState->findConnection(wsi);
			if (!conn) {
				Com_Printf("ERROR: Receive on connection we don't know\n", LOG_NET);
				return -1;
			}

			assert(conn->readyState == Open);

			bool alreadyHasData = !conn->recvBuffer.empty();
			if (alreadyHasData) {
				// if there's data already in the buffer the connection must also be in pendingData
				assert(wsState->pendingData.find(conn) != wsState->pendingData.end());
			}

			assert(conn->wsi == wsi);
			const char *buf = reinterpret_cast<char *>(in);
			conn->recvBuffer.insert(conn->recvBuffer.end(), buf, buf + len);

			if (!alreadyHasData) {
				wsState->pendingData.insert(conn);
			}
		}
		break;

	case LWS_CALLBACK_CLIENT_WRITEABLE:
	case LWS_CALLBACK_SERVER_WRITEABLE:
		{
			assert(wsi != NULL);

			Connection *conn = wsState->findConnection(wsi);
			if (!conn) {
				Com_Printf("ERROR: Writable on connection we don't know\n", LOG_NET);
				return -1;
			}

			assert(conn->wsi == wsi);
			if (conn->readyState == Closed || conn->readyState == Closing) {
				// game has closed, close the actual connection
				return -1;
			}

			conn->writable = true;
		}
		break;

	case LWS_CALLBACK_FILTER_NETWORK_CONNECTION:
		Com_Printf("websocketCallback LWS_CALLBACK_FILTER_NETWORK_CONNECTION\n", LOG_NET);
		break;

	case LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED:
		Com_Printf("websocketCallback LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED\n", LOG_NET);
		break;

	case LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION:
		Com_Printf("websocketCallback LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION\n", LOG_NET);
		break;

	case LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER:
		Com_Printf("websocketCallback LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER\n", LOG_NET);
		break;

	case LWS_CALLBACK_PROTOCOL_INIT:
		// ignored
		break;

	case LWS_CALLBACK_PROTOCOL_DESTROY:
		// ignored
		break;

	case LWS_CALLBACK_WSI_CREATE:
		Com_Printf("websocketCallback LWS_CALLBACK_WSI_CREATE\n", LOG_NET);
		break;

	case LWS_CALLBACK_WSI_DESTROY:
		Com_Printf("websocketCallback LWS_CALLBACK_WSI_DESTROY\n", LOG_NET);
		break;

	case LWS_CALLBACK_GET_THREAD_ID:
		// ignored
		break;

	case LWS_CALLBACK_ADD_POLL_FD:
		// ignored
		break;

	case LWS_CALLBACK_DEL_POLL_FD:
		// ignored
		break;

	case LWS_CALLBACK_CHANGE_MODE_POLL_FD:
		// ignored
		break;

	case LWS_CALLBACK_LOCK_POLL:
		// ignored
		break;

	case LWS_CALLBACK_UNLOCK_POLL:
		// ignored
		break;

	default:
		Com_Printf ("websocketCallback reason %d\n", LOG_NET, reason);
		break;
	}

	return 0;
}
Exemplo n.º 13
0
int EchoDataWebSocket::callback_dumb_increment(struct libwebsocket_context * context,
			struct libwebsocket *wsi,
			enum libwebsocket_callback_reasons reason,
					       void *user, void *in, size_t len)
{
#ifdef DEBUG_WEBSERVER
	fprintf(stderr, "callback Data websocket, fd: %d, reason: %s\n", libwebsocket_get_socket_fd(wsi), ServerConstants::getCallbackReasonText(reason));
#endif
	int n;
	//unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 512 +
		//				  LWS_SEND_BUFFER_POST_PADDING];
	//unsigned char *p = &buf[LWS_SEND_BUFFER_PRE_PADDING];
	struct sessionDataProtocol_1 *pss = (sessionDataProtocol_1 *)user;


	switch (reason) {

	case LWS_CALLBACK_ESTABLISHED:
#ifdef DEBUG_WEBSERVER
		fprintf(stdout, "********Data websocket established\n");
#endif
		break;

	/*
	 * in this protocol, we just use the broadcast action as the chance to
	 * send our own connection-specific data and ignore the broadcast info
	 * that is available in the 'in' parameter
	 */

	case LWS_CALLBACK_BROADCAST:
#ifdef DEBUG_WEBSERVER
		fprintf(stdout, "********Data websocket LWS_CALLBACK_BROADCAST\n");
#endif

		n = libwebsocket_write(wsi, &broadcastEchoMsg[LWS_SEND_BUFFER_PRE_PADDING], broadcastEchoLength, LWS_WRITE_TEXT);
#ifdef DEBUG_WEBSERVER
		fprintf(stdout, "** END **Data websocket LWS_CALLBACK_BROADCAST, length: %d\n", broadcastEchoLength);
#endif

		break;

	case LWS_CALLBACK_RECEIVE:
#ifdef DEBUG_WEBSERVER
		fprintf(stdout, "Data websocket LWS_CALLBACK_RECEIVE\n");
#endif
		fprintf(stderr, "rx %d\n", (int)len);
		if (len < 6)
			break;
		if (strcmp((char*)in, "reset\n") == 0)
			pss->number = 0;
		break;
	/*
	 * this just demonstrates how to use the protocol filter. If you won't
	 * study and reject connections based on header content, you don't need
	 * to handle this callback
	 */

	case LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION:
		//dump_handshake_info((struct lws_tokens *)(long)user);
		/* you could return non-zero here and kill the connection */
		break;

	default:
#ifdef DEBUG_WEBSERVER
		fprintf(stderr, "!!! callback Data websocket, default case? Reason %d**********\n", (int)reason);
#endif
		break;
	}

	return 0;
}