Example #1
0
void janus_rabbitmq_destroy(void) {
	if(!g_atomic_int_get(&initialized))
		return;
	g_atomic_int_set(&stopping, 1);

	if(rmq_client) {
		rmq_client->destroy = 1;
		g_async_queue_push(rmq_client->messages, &exit_message);
		if(rmq_client->in_thread)
			g_thread_join(rmq_client->in_thread);
		if(rmq_client->out_thread)
			g_thread_join(rmq_client->out_thread);
		if(rmq_client->rmq_conn && rmq_client->rmq_channel) {
			amqp_channel_close(rmq_client->rmq_conn, rmq_client->rmq_channel, AMQP_REPLY_SUCCESS);
			amqp_connection_close(rmq_client->rmq_conn, AMQP_REPLY_SUCCESS);
			amqp_destroy_connection(rmq_client->rmq_conn);
		}
	}
	g_free(rmq_client);
	janus_transport_session_destroy(rmq_session);

	g_free(rmqhost);
	g_free(vhost);
	g_free(username);
	g_free(password);
	g_free(janus_exchange);
	g_free(to_janus);
	g_free(from_janus);
	g_free(to_janus_admin);
	g_free(from_janus_admin);
	g_free(ssl_cacert_file);
	g_free(ssl_cert_file);
	g_free(ssl_key_file);

	g_atomic_int_set(&initialized, 0);
	g_atomic_int_set(&stopping, 0);
	JANUS_LOG(LOG_INFO, "%s destroyed!\n", JANUS_RABBITMQ_NAME);
}
Example #2
0
static void janus_websockets_destroy_client(
		janus_websockets_client *ws_client,
		struct lws *wsi,
		const char *log_prefix) {
	if(!ws_client || !g_atomic_int_compare_and_exchange(&ws_client->destroyed, 0, 1))
		return;
	/* Cleanup */
	janus_mutex_lock(&ws_client->ts->mutex);
	JANUS_LOG(LOG_INFO, "[%s-%p] Destroying WebSocket client\n", log_prefix, wsi);
	ws_client->wsi = NULL;
	/* Notify handlers about this transport being gone */
	if(notify_events && gateway->events_is_enabled()) {
		json_t *info = json_object();
		json_object_set_new(info, "event", json_string("disconnected"));
		gateway->notify_event(&janus_websockets_transport, ws_client->ts, info);
	}
	/* Notify core */
	gateway->transport_gone(&janus_websockets_transport, ws_client->ts);
	ws_client->ts->transport_p = NULL;
	/* Remove messages queue too, if needed */
	if(ws_client->messages != NULL) {
		char *response = NULL;
		while((response = g_async_queue_try_pop(ws_client->messages)) != NULL) {
			g_free(response);
		}
		g_async_queue_unref(ws_client->messages);
	}
	/* ... and the shared buffers */
	g_free(ws_client->incoming);
	ws_client->incoming = NULL;
	g_free(ws_client->buffer);
	ws_client->buffer = NULL;
	ws_client->buflen = 0;
	ws_client->bufpending = 0;
	ws_client->bufoffset = 0;
	janus_mutex_unlock(&ws_client->ts->mutex);
	janus_transport_session_destroy(ws_client->ts);
}
void janus_mqtt_destroy(void) {
	JANUS_LOG(LOG_INFO, "Disconnecting MQTT client...\n");

	janus_transport_session_destroy(mqtt_session);
	janus_mqtt_client_disconnect(context_);
}
int janus_mqtt_init(janus_transport_callbacks *callback, const char *config_path) {
	if(callback == NULL || config_path == NULL) {
		/* Invalid arguments */
		return -1;
	}

	/* Initializing context */
	janus_mqtt_context *ctx = g_malloc0(sizeof(struct janus_mqtt_context));
	ctx->gateway = callback;
	context_ = ctx;
	/* Prepare the transport session (again, just one) */
	mqtt_session = janus_transport_session_create(context_, NULL);

	/* Read configuration */
	char filename[255];
	g_snprintf(filename, 255, "%s/%s.cfg", config_path, JANUS_MQTT_PACKAGE);
	JANUS_LOG(LOG_VERB, "Configuration file: %s\n", filename);
	janus_config *config = janus_config_parse(filename);
	if(config != NULL) {
		janus_config_print(config);
	}

	/* Handle configuration */
	janus_config_item *url_item = janus_config_get_item_drilldown(config, "general", "url");
	const char *url = g_strdup((url_item && url_item->value) ? url_item->value : "tcp://localhost:1883");

	janus_config_item *client_id_item = janus_config_get_item_drilldown(config, "general", "client_id");
	const char *client_id = g_strdup((client_id_item && client_id_item->value) ? client_id_item->value : "guest");

	janus_config_item *username_item = janus_config_get_item_drilldown(config, "general", "username");
	ctx->connect.username = g_strdup((username_item && username_item->value) ? username_item->value : "guest");

	janus_config_item *password_item = janus_config_get_item_drilldown(config, "general", "password");
	ctx->connect.password = g_strdup((password_item && password_item->value) ? password_item->value : "guest");

	janus_config_item *json_item = janus_config_get_item_drilldown(config, "general", "json");
	if(json_item && json_item->value) {
		/* Check how we need to format/serialize the JSON output */
		if(!strcasecmp(json_item->value, "indented")) {
			/* Default: indented, we use three spaces for that */
			json_format_ = JSON_INDENT(3) | JSON_PRESERVE_ORDER;
		} else if(!strcasecmp(json_item->value, "plain")) {
			/* Not indented and no new lines, but still readable */
			json_format_ = JSON_INDENT(0) | JSON_PRESERVE_ORDER;
		} else if(!strcasecmp(json_item->value, "compact")) {
			/* Compact, so no spaces between separators */
			json_format_ = JSON_COMPACT | JSON_PRESERVE_ORDER;
		} else {
			JANUS_LOG(LOG_WARN, "Unsupported JSON format option '%s', using default (indented)\n", json_item->value);
			json_format_ = JSON_INDENT(3) | JSON_PRESERVE_ORDER;
		}
	}

	/* Check if we need to send events to handlers */
	janus_config_item *events = janus_config_get_item_drilldown(config, "general", "events");
	if(events != NULL && events->value != NULL)
		notify_events = janus_is_true(events->value);
	if(!notify_events && callback->events_is_enabled()) {
		JANUS_LOG(LOG_WARN, "Notification of events to handlers disabled for %s\n", JANUS_MQTT_NAME);
	}

	/* Check if we need to enable SSL support */
	janus_config_item *ssl = janus_config_get_item_drilldown(config, "general", "ssl_enable");
	if(ssl && ssl->value && janus_is_true(ssl->value)) {
		if(strstr(url, "ssl://") != url)
			JANUS_LOG(LOG_WARN, "SSL enabled, but MQTT url doesn't start with ssl://...\n");

		ctx->ssl_enable = TRUE;

		janus_config_item *cacertfile = janus_config_get_item_drilldown(config, "general", "cacertfile");
		if(!cacertfile || !cacertfile->value) {
			JANUS_LOG(LOG_FATAL, "Missing CA certificate for MQTT integration...\n");
			goto error;
		}
		ctx->cacert_file = g_strdup(cacertfile->value);

		janus_config_item *certfile = janus_config_get_item_drilldown(config, "general", "certfile");
		ctx->cert_file = (certfile && certfile->value) ? g_strdup(certfile->value) : NULL;

		janus_config_item *keyfile = janus_config_get_item_drilldown(config, "general", "keyfile");
		ctx->key_file = (keyfile && keyfile->value) ? g_strdup(keyfile->value) : NULL;

		if(ctx->cert_file && !ctx->key_file) {
			JANUS_LOG(LOG_FATAL, "Certificate is set but key isn't for MQTT integration...\n");
			goto error;
		}
		if(!ctx->cert_file && ctx->key_file) {
			JANUS_LOG(LOG_FATAL, "Key is set but certificate isn't for MQTT integration...\n");
			goto error;
		}

		janus_config_item *verify = janus_config_get_item_drilldown(config, "general", "verify_peer");
		ctx->verify_peer = (verify && verify->value && janus_is_true(verify->value)) ? TRUE : FALSE;
	} else {
		JANUS_LOG(LOG_INFO, "MQTT SSL support disabled\n");
		if(strstr(url, "ssl://") == url)
			JANUS_LOG(LOG_WARN, "SSL disabled, but MQTT url starts with ssl:// instead of tcp://...\n");
	}

	/* Connect configuration */
	janus_config_item *keep_alive_interval_item = janus_config_get_item_drilldown(config, "general", "keep_alive_interval");
	ctx->connect.keep_alive_interval = (keep_alive_interval_item && keep_alive_interval_item->value) ? atoi(keep_alive_interval_item->value) : 20;

	janus_config_item *cleansession_item = janus_config_get_item_drilldown(config, "general", "cleansession");
	ctx->connect.cleansession = (cleansession_item && cleansession_item->value) ? atoi(cleansession_item->value) : 0;

	/* Disconnect configuration */
	janus_config_item *disconnect_timeout_item = janus_config_get_item_drilldown(config, "general", "disconnect_timeout");
	ctx->disconnect.timeout = (disconnect_timeout_item && disconnect_timeout_item->value) ? atoi(disconnect_timeout_item->value) : 100;

	janus_config_item *enable_item = janus_config_get_item_drilldown(config, "general", "enable");
	if(enable_item && enable_item->value && janus_is_true(enable_item->value)) {
		janus_mqtt_api_enabled_ = TRUE;

		/* Subscribe configuration */
		{
			janus_config_item *topic_item = janus_config_get_item_drilldown(config, "general", "subscribe_topic");
			if(!topic_item || !topic_item->value) {
				JANUS_LOG(LOG_FATAL, "Missing topic for incoming messages for MQTT integration...\n");
				goto error;
			}
			ctx->subscribe.topic = g_strdup(topic_item->value);

			janus_config_item *qos_item = janus_config_get_item_drilldown(config, "general", "subscribe_qos");
			ctx->subscribe.qos = (qos_item && qos_item->value) ? atoi(qos_item->value) : 1;
		}

		/* Publish configuration */
		{
			janus_config_item *topic_item = janus_config_get_item_drilldown(config, "general", "publish_topic");
			if(!topic_item || !topic_item->value) {
				JANUS_LOG(LOG_FATAL, "Missing topic for outgoing messages for MQTT integration...\n");
				goto error;
			}
			ctx->publish.topic = g_strdup(topic_item->value);

			janus_config_item *qos_item = janus_config_get_item_drilldown(config, "general", "publish_qos");
			ctx->publish.qos = (qos_item && qos_item->value) ? atoi(qos_item->value) : 1;
		}
	} else {
		janus_mqtt_api_enabled_ = FALSE;
		ctx->subscribe.topic = NULL;
		ctx->publish.topic = NULL;
	}

	/* Admin configuration */
	janus_config_item *admin_enable_item = janus_config_get_item_drilldown(config, "admin", "admin_enable");
	if(admin_enable_item && admin_enable_item->value && janus_is_true(admin_enable_item->value)) {
		janus_mqtt_admin_api_enabled_ = TRUE;

		/* Admin subscribe configuration */
		{
			janus_config_item *topic_item = janus_config_get_item_drilldown(config, "admin", "subscribe_topic");
			if(!topic_item || !topic_item->value) {
				JANUS_LOG(LOG_FATAL, "Missing topic for incoming admin messages for MQTT integration...\n");
				goto error;
			}
			ctx->admin.subscribe.topic = g_strdup(topic_item->value);

			janus_config_item *qos_item = janus_config_get_item_drilldown(config, "admin", "subscribe_qos");
			ctx->admin.subscribe.qos = (qos_item && qos_item->value) ? atoi(qos_item->value) : 1;
		}

		/* Admin publish configuration */
		{
			janus_config_item *topic_item = janus_config_get_item_drilldown(config, "admin", "publish_topic");
			if(!topic_item || !topic_item->value) {
				JANUS_LOG(LOG_FATAL, "Missing topic for outgoing admin messages for MQTT integration...\n");
				goto error;
			}
			ctx->admin.publish.topic = g_strdup(topic_item->value);

			janus_config_item *qos_item = janus_config_get_item_drilldown(config, "admin", "publish_qos");
			ctx->admin.publish.qos = (qos_item && qos_item->value) ? atoi(qos_item->value) : 1;
		}
	} else {
		janus_mqtt_admin_api_enabled_ = FALSE;
		ctx->admin.subscribe.topic = NULL;
		ctx->admin.publish.topic = NULL;
	}

	if(!janus_mqtt_api_enabled_ && !janus_mqtt_admin_api_enabled_) {
		JANUS_LOG(LOG_WARN, "MQTT support disabled for both Janus and Admin API, giving up\n");
		goto error;
	}

	/* Creating a client */
	if(MQTTAsync_create(
			&ctx->client,
			url,
			client_id,
			MQTTCLIENT_PERSISTENCE_NONE,
			NULL) != MQTTASYNC_SUCCESS) {
		JANUS_LOG(LOG_FATAL, "Can't connect to MQTT broker: error creating client...\n");
		goto error;
	}
	if(MQTTAsync_setCallbacks(
			ctx->client,
			ctx,
			janus_mqtt_client_connection_lost,
			janus_mqtt_client_message_arrived,
			janus_mqtt_client_delivery_complete) != MQTTASYNC_SUCCESS) {
		JANUS_LOG(LOG_FATAL, "Can't connect to MQTT broker: error setting up callbacks...\n");
		goto error;
	}

	/* Connecting to the broker */
	int rc = janus_mqtt_client_connect(ctx);
	if(rc != MQTTASYNC_SUCCESS) {
		JANUS_LOG(LOG_FATAL, "Can't connect to MQTT broker, return code: %d\n", rc);
		goto error;
	}

	return 0;

error:
	/* If we got here, something went wrong */
	janus_transport_session_destroy(mqtt_session);
	janus_mqtt_client_destroy_context(&ctx);
	g_free((char *)url);
	g_free((char *)client_id);
	g_free(config);

	return -1;
}
Example #5
0
/* Thread */
void *janus_pfunix_thread(void *data) {
	JANUS_LOG(LOG_INFO, "Unix Sockets thread started\n");

	int fds = 0;
	struct pollfd poll_fds[1024];	/* FIXME Should we allow for more clients? */
	char buffer[BUFFER_SIZE];
	struct iovec iov[1];
	struct msghdr msg;
	memset(&msg, 0, sizeof(msg));
	memset(iov, 0, sizeof(iov));
	iov[0].iov_base = buffer;
	iov[0].iov_len = sizeof(buffer);
	msg.msg_iov = iov;
	msg.msg_iovlen = 1;

	while(g_atomic_int_get(&initialized) && !g_atomic_int_get(&stopping)) {
		/* Prepare poll list of file descriptors */
		fds = 0;
		/* Writeable monitor */
		poll_fds[fds].fd = write_fd[0];
		poll_fds[fds].events = POLLIN;
		fds++;
		if(pfd > -1) {
			/* Janus API */
			poll_fds[fds].fd = pfd;
			poll_fds[fds].events = POLLIN;
			fds++;
		}
		if(admin_pfd > -1) {
			/* Admin API */
			poll_fds[fds].fd = admin_pfd;
			poll_fds[fds].events = POLLIN;
			fds++;
		}
		/* Iterate on available clients, to see if we need to POLLIN or POLLOUT too */
		janus_mutex_lock(&clients_mutex);
		GHashTableIter iter;
		gpointer value;
		g_hash_table_iter_init(&iter, clients_by_fd);
		while(g_hash_table_iter_next(&iter, NULL, &value)) {
			janus_pfunix_client *client = value;
			if(client->fd > -1) {
				poll_fds[fds].fd = client->fd;
				poll_fds[fds].events = g_async_queue_length(client->messages) > 0 ? POLLIN | POLLOUT : POLLIN;
				fds++;
			}
		}
		janus_mutex_unlock(&clients_mutex);

		/* Start polling */
		int res = poll(poll_fds, fds, -1);
		if(res == 0)
			continue;
		if(res < 0) {
			if(errno == EINTR) {
				JANUS_LOG(LOG_HUGE, "Got an EINTR (%s) polling the Unix Sockets descriptors, ignoring...\n", strerror(errno));
				continue;
			}
			JANUS_LOG(LOG_ERR, "poll() failed: %d (%s)\n", errno, strerror(errno));
			break;
		}
		int i = 0;
		for(i=0; i<fds; i++) {
			if(poll_fds[i].revents & (POLLERR | POLLHUP)) {
				/* Socket error? Shall we do something? */
				if(poll_fds[i].fd == write_fd[0]) {
					/* Error in the wake-up socketpair, that sucks: try recreating it */
					JANUS_LOG(LOG_WARN, "Error polling wake-up socketpair: %s...\n",
						poll_fds[i].revents & POLLERR ? "POLLERR" : "POLLHUP");
					close(write_fd[0]);
					write_fd[0] = -1;
					close(write_fd[1]);
					write_fd[1] = -1;
					if(socketpair(PF_LOCAL, SOCK_STREAM, 0, write_fd) < 0) {
						JANUS_LOG(LOG_FATAL, "Error creating socket pair for writeable events: %d, %s\n", errno, strerror(errno));
						continue;
					}
				} else if(poll_fds[i].fd == pfd) {
					/* Error in the Janus API socket */
					JANUS_LOG(LOG_WARN, "Error polling Unix Sockets Janus API interface (%s), disabling it\n",
						poll_fds[i].revents & POLLERR ? "POLLERR" : "POLLHUP");
					close(pfd);
					pfd = -1;
					continue;
				} else if(poll_fds[i].fd == admin_pfd) {
					/* Error in the Admin API socket */
					JANUS_LOG(LOG_WARN, "Error polling Unix Sockets Admin API interface (%s), disabling it\n",
						poll_fds[i].revents & POLLERR ? "POLLERR" : "POLLHUP");
					close(admin_pfd);
					admin_pfd = -1;
					continue;
				} else {
					/* Error in a client socket, find and remove it */
					janus_mutex_lock(&clients_mutex);
					janus_pfunix_client *client = g_hash_table_lookup(clients_by_fd, GINT_TO_POINTER(poll_fds[i].fd));
					if(client == NULL) {
						/* We're not handling this, ignore */
						janus_mutex_unlock(&clients_mutex);
						continue;
					}
					JANUS_LOG(LOG_INFO, "Unix Sockets client disconnected (%d)\n", poll_fds[i].fd);
					/* Notify core */
					gateway->transport_gone(&janus_pfunix_transport, client->ts);
					/* Notify handlers about this transport being gone */
					if(notify_events && gateway->events_is_enabled()) {
						json_t *info = json_object();
						json_object_set_new(info, "event", json_string("disconnected"));
						gateway->notify_event(&janus_pfunix_transport, client->ts, info);
					}
					/* Close socket */
					shutdown(SHUT_RDWR, poll_fds[i].fd);
					close(poll_fds[i].fd);
					client->fd = -1;
					/* Destroy the client */
					g_hash_table_remove(clients_by_fd, GINT_TO_POINTER(poll_fds[i].fd));
					g_hash_table_remove(clients, client);
					/* Unref the transport instance */
					janus_transport_session_destroy(client->ts);
					janus_mutex_unlock(&clients_mutex);
					continue;
				}
				continue;
			}
			if(poll_fds[i].revents & POLLOUT) {
				/* Find the client from its file descriptor */
				janus_mutex_lock(&clients_mutex);
				janus_pfunix_client *client = g_hash_table_lookup(clients_by_fd, GINT_TO_POINTER(poll_fds[i].fd));
				if(client != NULL) {
					char *payload = NULL;
					while((payload = g_async_queue_try_pop(client->messages)) != NULL) {
						int res = 0;
						do {
							if(client->fd < 0)
								break;
							res = write(client->fd, payload, strlen(payload));
						} while(res == -1 && errno == EINTR);
						/* FIXME Should we check if sent everything? */
						JANUS_LOG(LOG_HUGE, "Written %d/%zu bytes on %d\n", res, strlen(payload), client->fd);
						g_free(payload);
					}
					if(client->session_timeout) {
						/* We should actually get rid of this connection, now */
						shutdown(SHUT_RDWR, poll_fds[i].fd);
						close(poll_fds[i].fd);
						client->fd = -1;
						/* Destroy the client */
						g_hash_table_remove(clients_by_fd, GINT_TO_POINTER(poll_fds[i].fd));
						g_hash_table_remove(clients, client);
						if(client->messages != NULL) {
							char *response = NULL;
							while((response = g_async_queue_try_pop(client->messages)) != NULL) {
								g_free(response);
							}
							g_async_queue_unref(client->messages);
						}
						g_free(client);
					}
				}
				janus_mutex_unlock(&clients_mutex);
			}
			if(poll_fds[i].revents & POLLIN) {
				if(poll_fds[i].fd == write_fd[0]) {
					/* Read and ignore: we use this to unlock the poll if there's data to write */
					(void)read(poll_fds[i].fd, buffer, BUFFER_SIZE);
				} else if(poll_fds[i].fd == pfd || poll_fds[i].fd == admin_pfd) {
					/* Janus/Admin API: accept the new client (SOCK_SEQPACKET) or receive data (SOCK_DGRAM) */
					struct sockaddr_un address;
					socklen_t addrlen = sizeof(address);
					if((poll_fds[i].fd == pfd && !dgram) || (poll_fds[i].fd == admin_pfd && !admin_dgram)) {
						/* SOCK_SEQPACKET */
						int cfd = accept(poll_fds[i].fd, (struct sockaddr *) &address, &addrlen);
						if(cfd > -1) {
							JANUS_LOG(LOG_INFO, "Got new Unix Sockets %s API client: %d\n",
								poll_fds[i].fd == pfd ? "Janus" : "Admin", cfd);
							/* Allocate new client */
							janus_pfunix_client *client = g_malloc(sizeof(janus_pfunix_client));
							client->fd = cfd;
							memset(&client->addr, 0, sizeof(client->addr));
							client->admin = (poll_fds[i].fd == admin_pfd);	/* API client type */
							client->messages = g_async_queue_new();
							client->session_timeout = FALSE;
							/* Create a transport instance as well */
							client->ts = janus_transport_session_create(client, janus_pfunix_client_free);
							/* Take note of this new client */
							janus_mutex_lock(&clients_mutex);
							g_hash_table_insert(clients_by_fd, GINT_TO_POINTER(cfd), client);
							g_hash_table_insert(clients, client, client);
							janus_mutex_unlock(&clients_mutex);
							/* 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", client->admin ? json_true() : json_false());
								json_object_set_new(info, "fd", json_integer(client->fd));
								gateway->notify_event(&janus_pfunix_transport, client->ts, info);
							}
						}
					} else {
						/* SOCK_DGRAM */
						struct sockaddr_storage address;
						res = recvfrom(poll_fds[i].fd, buffer, sizeof(buffer), 0, (struct sockaddr *)&address, &addrlen);
						if(res < 0) {
							if(errno != EAGAIN && errno != EWOULDBLOCK) {
								JANUS_LOG(LOG_ERR, "Error reading from client (%s API)...\n",
									poll_fds[i].fd == pfd ? "Janus" : "Admin");
							}
							continue;
						}
						buffer[res] = '\0';
						/* Is this a new client, or one we knew about already? */
						struct sockaddr_un *uaddr = (struct sockaddr_un *)&address;
						if(strlen(uaddr->sun_path) == 0) {
							/* No path provided, drop the packet */
							JANUS_LOG(LOG_WARN, "Dropping packet from unknown source (no path provided)\n");
							continue;
						}
						janus_mutex_lock(&clients_mutex);
						janus_pfunix_client *client = g_hash_table_lookup(clients_by_path, uaddr->sun_path);
						if(client == NULL) {
							JANUS_LOG(LOG_INFO, "Got new Unix Sockets %s API client: %s\n",
								poll_fds[i].fd == pfd ? "Janus" : "Admin", uaddr->sun_path);
							/* Allocate new client */
							client = g_malloc(sizeof(janus_pfunix_client));
							client->fd = -1;
							memcpy(&client->addr, uaddr, sizeof(struct sockaddr_un));
							client->admin = (poll_fds[i].fd == admin_pfd);	/* API client type */
							client->messages = g_async_queue_new();
							client->session_timeout = FALSE;
							/* Create a transport instance as well */
							client->ts = janus_transport_session_create(client, janus_pfunix_client_free);
							/* Take note of this new client */
							g_hash_table_insert(clients_by_path, uaddr->sun_path, client);
							g_hash_table_insert(clients, client, client);
							/* 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", client->admin ? json_true() : json_false());
								json_object_set_new(info, "fd", json_integer(client->fd));
								json_object_set_new(info, "type", json_string("SOCK_DGRAM"));
								gateway->notify_event(&janus_pfunix_transport, client->ts, info);
							}
						}
						janus_mutex_unlock(&clients_mutex);
						JANUS_LOG(LOG_VERB, "Message from client %s (%d bytes)\n", uaddr->sun_path, res);
						JANUS_LOG(LOG_HUGE, "%s\n", buffer);
						/* Parse the JSON payload */
						json_error_t error;
						json_t *root = json_loads(buffer, 0, &error);
						/* Notify the core, passing both the object and, since it may be needed, the error */
						gateway->incoming_request(&janus_pfunix_transport, client->ts, NULL, client->admin, root, &error);
					}
				} else {
					/* Client data: receive message */
					iov[0].iov_len = sizeof(buffer);
					res = recvmsg(poll_fds[i].fd, &msg, MSG_WAITALL);
					if(res < 0) {
						if(errno != EAGAIN && errno != EWOULDBLOCK) {
							JANUS_LOG(LOG_ERR, "Error reading from client %d...\n", poll_fds[i].fd);
						}
						continue;
					}
					if(msg.msg_flags & MSG_TRUNC) {
						/* Apparently our buffer is not large enough? */
						JANUS_LOG(LOG_WARN, "Incoming message from client %d truncated (%d bytes), dropping it...\n", poll_fds[i].fd, res);
						continue;
					}
					/* Find the client from its file descriptor */
					janus_mutex_lock(&clients_mutex);
					janus_pfunix_client *client = g_hash_table_lookup(clients_by_fd, GINT_TO_POINTER(poll_fds[i].fd));
					if(client == NULL) {
						janus_mutex_unlock(&clients_mutex);
						JANUS_LOG(LOG_WARN, "Got data from unknown Unix Sockets client %d, closing connection...\n", poll_fds[i].fd);
						/* Close socket */
						shutdown(SHUT_RDWR, poll_fds[i].fd);
						close(poll_fds[i].fd);
						continue;
					}
					if(res == 0) {
						JANUS_LOG(LOG_INFO, "Unix Sockets client disconnected (%d)\n", poll_fds[i].fd);
						/* Notify core */
						gateway->transport_gone(&janus_pfunix_transport, client->ts);
						/* Notify handlers about this transport being gone */
						if(notify_events && gateway->events_is_enabled()) {
							json_t *info = json_object();
							json_object_set_new(info, "event", json_string("disconnected"));
							gateway->notify_event(&janus_pfunix_transport, client->ts, info);
						}
						/* Close socket */
						shutdown(SHUT_RDWR, poll_fds[i].fd);
						close(poll_fds[i].fd);
						client->fd = -1;
						/* Destroy the client */
						g_hash_table_remove(clients_by_fd, GINT_TO_POINTER(poll_fds[i].fd));
						g_hash_table_remove(clients, client);
						/* Unref the transport instance */
						janus_transport_session_destroy(client->ts);
						janus_mutex_unlock(&clients_mutex);
						continue;
					}
					janus_mutex_unlock(&clients_mutex);
					/* If we got here, there's data to handle */
					buffer[res] = '\0';
					JANUS_LOG(LOG_VERB, "Message from client %d (%d bytes)\n", poll_fds[i].fd, res);
					JANUS_LOG(LOG_HUGE, "%s\n", buffer);
					/* Parse the JSON payload */
					json_error_t error;
					json_t *root = json_loads(buffer, 0, &error);
					/* Notify the core, passing both the object and, since it may be needed, the error */
					gateway->incoming_request(&janus_pfunix_transport, client->ts, NULL, client->admin, root, &error);
				}
			}
		}
	}

	socklen_t addrlen = sizeof(struct sockaddr_un);
	void *addr = g_malloc(addrlen+1);
	if(pfd > -1) {
		/* Unlink the path name first */
#ifdef HAVE_LIBSYSTEMD
		if((getsockname(pfd, (struct sockaddr *)addr, &addrlen) != -1) && (FALSE == sd_socket)) {
#else
		if(getsockname(pfd, (struct sockaddr *)addr, &addrlen) != -1) {
#endif
			JANUS_LOG(LOG_INFO, "Unlinking %s\n", ((struct sockaddr_un *)addr)->sun_path);
			unlink(((struct sockaddr_un *)addr)->sun_path);
		}
		/* Close the socket */
		close(pfd);
	}
	pfd = -1;
	if(admin_pfd > -1) {
		/* Unlink the path name first */
#ifdef HAVE_LIBSYSTEMD
		if((getsockname(admin_pfd, (struct sockaddr *)addr, &addrlen) != -1) && (FALSE == admin_sd_socket)) {
#else
		if(getsockname(admin_pfd, (struct sockaddr *)addr, &addrlen) != -1) {
#endif
			JANUS_LOG(LOG_INFO, "Unlinking %s\n", ((struct sockaddr_un *)addr)->sun_path);
			unlink(((struct sockaddr_un *)addr)->sun_path);
		}
		/* Close the socket */
		close(admin_pfd);
	}
	admin_pfd = -1;
	g_free(addr);

	g_hash_table_destroy(clients_by_path);
	g_hash_table_destroy(clients_by_fd);
	g_hash_table_destroy(clients);

	/* Done */
	JANUS_LOG(LOG_INFO, "Unix Sockets thread ended\n");
	return NULL;
}
Example #6
0
/* Transport implementation */
int janus_rabbitmq_init(janus_transport_callbacks *callback, const char *config_path) {
	if(g_atomic_int_get(&stopping)) {
		/* Still stopping from before */
		return -1;
	}
	if(callback == NULL || config_path == NULL) {
		/* Invalid arguments */
		return -1;
	}

	/* This is the callback we'll need to invoke to contact the Janus core */
	gateway = callback;

	/* Read configuration */
	char filename[255];
	g_snprintf(filename, 255, "%s/%s.jcfg", config_path, JANUS_RABBITMQ_PACKAGE);
	JANUS_LOG(LOG_VERB, "Configuration file: %s\n", filename);
	janus_config *config = janus_config_parse(filename);
	if(config == NULL) {
		JANUS_LOG(LOG_WARN, "Couldn't find .jcfg configuration file (%s), trying .cfg\n", JANUS_RABBITMQ_PACKAGE);
		g_snprintf(filename, 255, "%s/%s.cfg", config_path, JANUS_RABBITMQ_PACKAGE);
		JANUS_LOG(LOG_VERB, "Configuration file: %s\n", filename);
		config = janus_config_parse(filename);
	}
	if(config != NULL)
		janus_config_print(config);
	janus_config_category *config_general = janus_config_get_create(config, NULL, janus_config_type_category, "general");
	janus_config_category *config_admin = janus_config_get_create(config, NULL, janus_config_type_category, "admin");

	janus_config_item *item = janus_config_get(config, config_general, janus_config_type_item, "json");
	if(item && item->value) {
		/* Check how we need to format/serialize the JSON output */
		if(!strcasecmp(item->value, "indented")) {
			/* Default: indented, we use three spaces for that */
			json_format = JSON_INDENT(3) | JSON_PRESERVE_ORDER;
		} else if(!strcasecmp(item->value, "plain")) {
			/* Not indented and no new lines, but still readable */
			json_format = JSON_INDENT(0) | JSON_PRESERVE_ORDER;
		} else if(!strcasecmp(item->value, "compact")) {
			/* Compact, so no spaces between separators */
			json_format = JSON_COMPACT | JSON_PRESERVE_ORDER;
		} else {
			JANUS_LOG(LOG_WARN, "Unsupported JSON format option '%s', using default (indented)\n", item->value);
			json_format = JSON_INDENT(3) | JSON_PRESERVE_ORDER;
		}
	}

	/* Check if we need to send events to handlers */
	janus_config_item *events = janus_config_get(config, config_general, janus_config_type_item, "events");
	if(events != NULL && events->value != NULL)
		notify_events = janus_is_true(events->value);
	if(!notify_events && callback->events_is_enabled()) {
		JANUS_LOG(LOG_WARN, "Notification of events to handlers disabled for %s\n", JANUS_RABBITMQ_NAME);
	}

	/* Handle configuration, starting from the server details */
	item = janus_config_get(config, config_general, janus_config_type_item, "host");
	if(item && item->value)
		rmqhost = g_strdup(item->value);
	else
		rmqhost = g_strdup("localhost");
	int rmqport = AMQP_PROTOCOL_PORT;
	item = janus_config_get(config, config_general, janus_config_type_item, "port");
	if(item && item->value)
		rmqport = atoi(item->value);

	/* Credentials and Virtual Host */
	item = janus_config_get(config, config_general, janus_config_type_item, "vhost");
	if(item && item->value)
		vhost = g_strdup(item->value);
	else
		vhost = g_strdup("/");
	item = janus_config_get(config, config_general, janus_config_type_item, "username");
	if(item && item->value)
		username = g_strdup(item->value);
	else
		username = g_strdup("guest");
	item = janus_config_get(config, config_general, janus_config_type_item, "password");
	if(item && item->value)
		password = g_strdup(item->value);
	else
		password = g_strdup("guest");

	/* SSL config*/
	gboolean ssl_enabled = FALSE;
	gboolean ssl_verify_peer = FALSE;
	gboolean ssl_verify_hostname = FALSE;
	item = janus_config_get(config, config_general, janus_config_type_item, "ssl_enabled");
	if(item == NULL) {
		/* Try legacy property */
		item = janus_config_get(config, config_general, janus_config_type_item, "ssl_enable");
		if (item && item->value) {
			JANUS_LOG(LOG_WARN, "Found deprecated 'ssl_enable' property, please update it to 'ssl_enabled' instead\n");
		}
	}
	if(!item || !item->value || !janus_is_true(item->value)) {
		JANUS_LOG(LOG_INFO, "RabbitMQ SSL support disabled\n");
	} else {
		ssl_enabled = TRUE;
		item = janus_config_get(config, config_general, janus_config_type_item, "ssl_cacert");
		if(item && item->value)
			ssl_cacert_file = g_strdup(item->value);
		item = janus_config_get(config, config_general, janus_config_type_item, "ssl_cert");
		if(item && item->value)
			ssl_cert_file = g_strdup(item->value);
		item = janus_config_get(config, config_general, janus_config_type_item, "ssl_key");
		if(item && item->value)
			ssl_key_file = g_strdup(item->value);
		item = janus_config_get(config, config_general, janus_config_type_item, "ssl_verify_peer");
		if(item && item->value && janus_is_true(item->value))
			ssl_verify_peer = TRUE;
		item = janus_config_get(config, config_general, janus_config_type_item, "ssl_verify_hostname");
		if(item && item->value && janus_is_true(item->value))
			ssl_verify_hostname = TRUE;
	}

	/* Now check if the Janus API must be supported */
	item = janus_config_get(config, config_general, janus_config_type_item, "enabled");
	if(item == NULL) {
		/* Try legacy property */
		item = janus_config_get(config, config_general, janus_config_type_item, "enable");
		if (item && item->value) {
			JANUS_LOG(LOG_WARN, "Found deprecated 'enable' property, please update it to 'enabled' instead\n");
		}
	}
	if(!item || !item->value || !janus_is_true(item->value)) {
		JANUS_LOG(LOG_WARN, "RabbitMQ support disabled (Janus API)\n");
	} else {
		/* Parse configuration */
		item = janus_config_get(config, config_general, janus_config_type_item, "to_janus");
		if(!item || !item->value) {
			JANUS_LOG(LOG_FATAL, "Missing name of incoming queue for RabbitMQ integration...\n");
			goto error;
		}
		to_janus = g_strdup(item->value);
		item = janus_config_get(config, config_general, janus_config_type_item, "from_janus");
		if(!item || !item->value) {
			JANUS_LOG(LOG_FATAL, "Missing name of outgoing queue for RabbitMQ integration...\n");
			goto error;
		}
		from_janus = g_strdup(item->value);
		item = janus_config_get(config, config_general, janus_config_type_item, "janus_exchange");
		if(!item || !item->value) {
			JANUS_LOG(LOG_INFO, "Missing name of outgoing exchange for RabbitMQ integration, using default\n");
		} else {
			janus_exchange = g_strdup(item->value);
		}
		if (janus_exchange == NULL) {
			JANUS_LOG(LOG_INFO, "RabbitMQ support for Janus API enabled, %s:%d (%s/%s)\n", rmqhost, rmqport, to_janus, from_janus);
		} else {
			JANUS_LOG(LOG_INFO, "RabbitMQ support for Janus API enabled, %s:%d (%s/%s) exch: (%s)\n", rmqhost, rmqport, to_janus, from_janus, janus_exchange);
		}
		rmq_janus_api_enabled = TRUE;
	}
	/* Do the same for the admin API */
	item = janus_config_get(config, config_admin, janus_config_type_item, "admin_enabled");
	if(item == NULL) {
		/* Try legacy property */
		item = janus_config_get(config, config_general, janus_config_type_item, "admin_enable");
		if (item && item->value) {
			JANUS_LOG(LOG_WARN, "Found deprecated 'admin_enable' property, please update it to 'admin_enabled' instead\n");
		}
	}
	if(!item || !item->value || !janus_is_true(item->value)) {
		JANUS_LOG(LOG_WARN, "RabbitMQ support disabled (Admin API)\n");
	} else {
		/* Parse configuration */
		item = janus_config_get(config, config_admin, janus_config_type_item, "to_janus_admin");
		if(!item || !item->value) {
			JANUS_LOG(LOG_FATAL, "Missing name of incoming queue for RabbitMQ integration...\n");
			goto error;
		}
		to_janus_admin = g_strdup(item->value);
		item = janus_config_get(config, config_admin, janus_config_type_item, "from_janus_admin");
		if(!item || !item->value) {
			JANUS_LOG(LOG_FATAL, "Missing name of outgoing queue for RabbitMQ integration...\n");
			goto error;
		}
		from_janus_admin = g_strdup(item->value);
		JANUS_LOG(LOG_INFO, "RabbitMQ support for Admin API enabled, %s:%d (%s/%s)\n", rmqhost, rmqport, to_janus_admin, from_janus_admin);
		rmq_admin_api_enabled = TRUE;
	}
	if(!rmq_janus_api_enabled && !rmq_admin_api_enabled) {
		JANUS_LOG(LOG_WARN, "RabbitMQ support disabled for both Janus and Admin API, giving up\n");
		goto error;
	} else {
		/* FIXME We currently support a single application, create a new janus_rabbitmq_client instance */
		rmq_client = g_malloc0(sizeof(janus_rabbitmq_client));
		/* Connect */
		rmq_client->rmq_conn = amqp_new_connection();
		amqp_socket_t *socket = NULL;
		int status;
		JANUS_LOG(LOG_VERB, "Creating RabbitMQ socket...\n");
		if (ssl_enabled) {
			socket = amqp_ssl_socket_new(rmq_client->rmq_conn);
			if(socket == NULL) {
				JANUS_LOG(LOG_FATAL, "Can't connect to RabbitMQ server: error creating socket...\n");
				goto error;
			}
			if(ssl_verify_peer) {
				amqp_ssl_socket_set_verify_peer(socket, 1);
			} else {
				amqp_ssl_socket_set_verify_peer(socket, 0);
			}
			if(ssl_verify_hostname) {
				amqp_ssl_socket_set_verify_hostname(socket, 1);
			} else {
				amqp_ssl_socket_set_verify_hostname(socket, 0);
			}
			if(ssl_cacert_file) {
				status = amqp_ssl_socket_set_cacert(socket, ssl_cacert_file);
				if(status != AMQP_STATUS_OK) {
					JANUS_LOG(LOG_FATAL, "Can't connect to RabbitMQ server: error setting CA certificate... (%s)\n", amqp_error_string2(status));
					goto error;
				}
			}
			if(ssl_cert_file && ssl_key_file) {
				status = amqp_ssl_socket_set_key(socket, ssl_cert_file, ssl_key_file);
				if(status != AMQP_STATUS_OK) {
					JANUS_LOG(LOG_FATAL, "Can't connect to RabbitMQ server: error setting key... (%s)\n", amqp_error_string2(status));
					goto error;
				}
			}
		} else {
			socket = amqp_tcp_socket_new(rmq_client->rmq_conn);
			if(socket == NULL) {
				JANUS_LOG(LOG_FATAL, "Can't connect to RabbitMQ server: error creating socket...\n");
				goto error;
			}
		}
		JANUS_LOG(LOG_VERB, "Connecting to RabbitMQ server...\n");
		status = amqp_socket_open(socket, rmqhost, rmqport);
		if(status != AMQP_STATUS_OK) {
			JANUS_LOG(LOG_FATAL, "Can't connect to RabbitMQ server: error opening socket... (%s)\n", amqp_error_string2(status));
			goto error;
		}
		JANUS_LOG(LOG_VERB, "Logging in...\n");
		amqp_rpc_reply_t result = amqp_login(rmq_client->rmq_conn, vhost, 0, 131072, 0, AMQP_SASL_METHOD_PLAIN, username, password);
		if(result.reply_type != AMQP_RESPONSE_NORMAL) {
			JANUS_LOG(LOG_FATAL, "Can't connect to RabbitMQ server: error logging in... %s, %s\n", amqp_error_string2(result.library_error), amqp_method_name(result.reply.id));
			goto error;
		}
		rmq_client->rmq_channel = 1;
		JANUS_LOG(LOG_VERB, "Opening channel...\n");
		amqp_channel_open(rmq_client->rmq_conn, rmq_client->rmq_channel);
		result = amqp_get_rpc_reply(rmq_client->rmq_conn);
		if(result.reply_type != AMQP_RESPONSE_NORMAL) {
			JANUS_LOG(LOG_FATAL, "Can't connect to RabbitMQ server: error opening channel... %s, %s\n", amqp_error_string2(result.library_error), amqp_method_name(result.reply.id));
			goto error;
		}
		rmq_client->janus_exchange = amqp_empty_bytes;
		if(janus_exchange != NULL) {
			JANUS_LOG(LOG_VERB, "Declaring exchange...\n");
			rmq_client->janus_exchange = amqp_cstring_bytes(janus_exchange);
			amqp_exchange_declare(rmq_client->rmq_conn, rmq_client->rmq_channel, rmq_client->janus_exchange, amqp_cstring_bytes(JANUS_RABBITMQ_EXCHANGE_TYPE), 0, 0, 0, 0, amqp_empty_table);
			result = amqp_get_rpc_reply(rmq_client->rmq_conn);
			if(result.reply_type != AMQP_RESPONSE_NORMAL) {
				JANUS_LOG(LOG_FATAL, "Can't connect to RabbitMQ server: error diclaring exchange... %s, %s\n", amqp_error_string2(result.library_error), amqp_method_name(result.reply.id));
				goto error;
			}
		}
		rmq_client->janus_api_enabled = FALSE;
		if(rmq_janus_api_enabled) {
			rmq_client->janus_api_enabled = TRUE;
			JANUS_LOG(LOG_VERB, "Declaring incoming queue... (%s)\n", to_janus);
			rmq_client->to_janus_queue = amqp_cstring_bytes(to_janus);
			amqp_queue_declare(rmq_client->rmq_conn, rmq_client->rmq_channel, rmq_client->to_janus_queue, 0, 0, 0, 0, amqp_empty_table);
			result = amqp_get_rpc_reply(rmq_client->rmq_conn);
			if(result.reply_type != AMQP_RESPONSE_NORMAL) {
				JANUS_LOG(LOG_FATAL, "Can't connect to RabbitMQ server: error declaring queue... %s, %s\n", amqp_error_string2(result.library_error), amqp_method_name(result.reply.id));
				goto error;
			}
			JANUS_LOG(LOG_VERB, "Declaring outgoing queue... (%s)\n", from_janus);
			rmq_client->from_janus_queue = amqp_cstring_bytes(from_janus);
			amqp_queue_declare(rmq_client->rmq_conn, rmq_client->rmq_channel, rmq_client->from_janus_queue, 0, 0, 0, 0, amqp_empty_table);
			result = amqp_get_rpc_reply(rmq_client->rmq_conn);
			if(result.reply_type != AMQP_RESPONSE_NORMAL) {
				JANUS_LOG(LOG_FATAL, "Can't connect to RabbitMQ server: error declaring queue... %s, %s\n", amqp_error_string2(result.library_error), amqp_method_name(result.reply.id));
				goto error;
			}
			amqp_basic_consume(rmq_client->rmq_conn, rmq_client->rmq_channel, rmq_client->to_janus_queue, amqp_empty_bytes, 0, 1, 0, amqp_empty_table);
			result = amqp_get_rpc_reply(rmq_client->rmq_conn);
			if(result.reply_type != AMQP_RESPONSE_NORMAL) {
				JANUS_LOG(LOG_FATAL, "Can't connect to RabbitMQ server: error consuming... %s, %s\n", amqp_error_string2(result.library_error), amqp_method_name(result.reply.id));
				goto error;
			}
		}
		rmq_client->admin_api_enabled = FALSE;
		if(rmq_admin_api_enabled) {
			rmq_client->admin_api_enabled = TRUE;
			JANUS_LOG(LOG_VERB, "Declaring incoming queue... (%s)\n", to_janus_admin);
			rmq_client->to_janus_admin_queue = amqp_cstring_bytes(to_janus_admin);
			amqp_queue_declare(rmq_client->rmq_conn, rmq_client->rmq_channel, rmq_client->to_janus_admin_queue, 0, 0, 0, 0, amqp_empty_table);
			result = amqp_get_rpc_reply(rmq_client->rmq_conn);
			if(result.reply_type != AMQP_RESPONSE_NORMAL) {
				JANUS_LOG(LOG_FATAL, "Can't connect to RabbitMQ server: error declaring queue... %s, %s\n", amqp_error_string2(result.library_error), amqp_method_name(result.reply.id));
				goto error;
			}
			JANUS_LOG(LOG_VERB, "Declaring outgoing queue... (%s)\n", from_janus_admin);
			rmq_client->from_janus_admin_queue = amqp_cstring_bytes(from_janus_admin);
			amqp_queue_declare(rmq_client->rmq_conn, rmq_client->rmq_channel, rmq_client->from_janus_admin_queue, 0, 0, 0, 0, amqp_empty_table);
			result = amqp_get_rpc_reply(rmq_client->rmq_conn);
			if(result.reply_type != AMQP_RESPONSE_NORMAL) {
				JANUS_LOG(LOG_FATAL, "Can't connect to RabbitMQ server: error declaring queue... %s, %s\n", amqp_error_string2(result.library_error), amqp_method_name(result.reply.id));
				goto error;
			}
			amqp_basic_consume(rmq_client->rmq_conn, rmq_client->rmq_channel, rmq_client->to_janus_admin_queue, amqp_empty_bytes, 0, 1, 0, amqp_empty_table);
			result = amqp_get_rpc_reply(rmq_client->rmq_conn);
			if(result.reply_type != AMQP_RESPONSE_NORMAL) {
				JANUS_LOG(LOG_FATAL, "Can't connect to RabbitMQ server: error consuming... %s, %s\n", amqp_error_string2(result.library_error), amqp_method_name(result.reply.id));
				goto error;
			}
		}
		rmq_client->messages = g_async_queue_new();
		rmq_client->destroy = 0;
		/* Prepare the transport session (again, just one) */
		rmq_session = janus_transport_session_create(rmq_client, NULL);
		/* Start the threads */
		GError *error = NULL;
		rmq_client->in_thread = g_thread_try_new("rmq_in_thread", &janus_rmq_in_thread, rmq_client, &error);
		if(error != NULL) {
			/* Something went wrong... */
			JANUS_LOG(LOG_FATAL, "Got error %d (%s) trying to launch the RabbitMQ incoming thread...\n", error->code, error->message ? error->message : "??");
			janus_transport_session_destroy(rmq_session);
			g_free(rmq_client);
			janus_config_destroy(config);
			return -1;
		}
		rmq_client->out_thread = g_thread_try_new("rmq_out_thread", &janus_rmq_out_thread, rmq_client, &error);
		if(error != NULL) {
			/* Something went wrong... */
			JANUS_LOG(LOG_FATAL, "Got error %d (%s) trying to launch the RabbitMQ outgoing thread...\n", error->code, error->message ? error->message : "??");
			janus_transport_session_destroy(rmq_session);
			g_free(rmq_client);
			janus_config_destroy(config);
			return -1;
		}
		janus_mutex_init(&rmq_client->mutex);
		/* Done */
		JANUS_LOG(LOG_INFO, "Setup of RabbitMQ integration completed\n");
		/* 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"));
			gateway->notify_event(&janus_rabbitmq_transport, rmq_session, info);
		}
	}
	janus_config_destroy(config);
	config = NULL;

	/* Done */
	g_atomic_int_set(&initialized, 1);
	JANUS_LOG(LOG_INFO, "%s initialized!\n", JANUS_RABBITMQ_NAME);
	return 0;

error:
	/* If we got here, something went wrong */
	g_free(rmq_client);
	g_free(rmqhost);
	g_free(vhost);
	g_free(username);
	g_free(password);
	g_free(janus_exchange);
	g_free(to_janus);
	g_free(from_janus);
	g_free(to_janus_admin);
	g_free(from_janus_admin);
	g_free(ssl_cacert_file);
	g_free(ssl_cert_file);
	g_free(ssl_key_file);
	if(config)
		janus_config_destroy(config);
	return -1;
}
Example #7
0
/* Thread */
void *janus_nanomsg_thread(void *data) {
	JANUS_LOG(LOG_INFO, "Nanomsg thread started\n");

	int fds = 0;
	struct nn_pollfd poll_nfds[3];	/* FIXME Should we allow for more clients? */
	char buffer[BUFFER_SIZE];

	while(g_atomic_int_get(&initialized) && !g_atomic_int_get(&stopping)) {
		/* Prepare poll list of file descriptors */
		fds = 0;
		/* Writeable monitor */
		poll_nfds[fds].fd = write_nfd[0];
		poll_nfds[fds].events = NN_POLLIN;
		fds++;
		if(nfd > -1) {
			/* Janus API */
			poll_nfds[fds].fd = nfd;
			poll_nfds[fds].events = NN_POLLIN;
			if(client.messages != NULL && g_async_queue_length(client.messages) > 0)
				poll_nfds[fds].events |= NN_POLLOUT;
			fds++;
		}
		if(admin_nfd > -1) {
			/* Admin API */
			poll_nfds[fds].fd = admin_nfd;
			poll_nfds[fds].events = NN_POLLIN;
			if(admin_client.messages != NULL && g_async_queue_length(admin_client.messages) > 0)
				poll_nfds[fds].events |= NN_POLLOUT;
			fds++;
		}
		/* Start polling */
		int res = nn_poll(poll_nfds, fds, -1);
		if(res == 0)
			continue;
		if(res < 0) {
			if(errno == EINTR) {
				JANUS_LOG(LOG_HUGE, "Got an EINTR (%s) polling the Nanomsg descriptors, ignoring...\n", nn_strerror(errno));
				continue;
			}
			JANUS_LOG(LOG_ERR, "poll() failed: %d (%s)\n", errno, nn_strerror(errno));
			break;
		}
		int i = 0;
		for(i=0; i<fds; i++) {
			/* FIXME Is there a Nanomsg equivalent of POLLERR? */
			if(poll_nfds[i].revents & NN_POLLOUT) {
				/* Find the client from its file descriptor */
				if(poll_nfds[i].fd == nfd || poll_nfds[i].fd == admin_nfd) {
					char *payload = NULL;
					while((payload = g_async_queue_try_pop(poll_nfds[i].fd == nfd ? client.messages : admin_client.messages)) != NULL) {
						int res = nn_send(poll_nfds[i].fd, payload, strlen(payload), 0);
						/* FIXME Should we check if sent everything? */
						JANUS_LOG(LOG_HUGE, "Written %d/%zu bytes on %d\n", res, strlen(payload), poll_nfds[i].fd);
						g_free(payload);
					}
				}
			}
			if(poll_nfds[i].revents & NN_POLLIN) {
				if(poll_nfds[i].fd == write_nfd[0]) {
					/* Read and ignore: we use this to unlock the poll if there's data to write */
					(void)nn_recv(poll_nfds[i].fd, buffer, BUFFER_SIZE, 0);
				} else if(poll_nfds[i].fd == nfd || poll_nfds[i].fd == admin_nfd) {
					/* Janus/Admin API: get the message from the client */
					int res = nn_recv(poll_nfds[i].fd, buffer, BUFFER_SIZE, 0);
					if(res < 0) {
						JANUS_LOG(LOG_WARN, "Error receiving %s API message... %d (%s)\n",
							poll_nfds[i].fd == nfd ? "Janus" : "Admin", errno, nn_strerror(errno));
						continue;
					}
					/* If we got here, there's data to handle */
					buffer[res] = '\0';
					JANUS_LOG(LOG_VERB, "Got %s API message (%d bytes)\n",
						poll_nfds[i].fd == nfd ? "Janus" : "Admin", res);
					JANUS_LOG(LOG_HUGE, "%s\n", buffer);
					/* Parse the JSON payload */
					json_error_t error;
					json_t *root = json_loads(buffer, 0, &error);
					/* Notify the core, passing both the object and, since it may be needed, the error */
					gateway->incoming_request(&janus_nanomsg_transport,
						poll_nfds[i].fd == nfd ? client.ts : admin_client.ts,
						NULL,
						poll_nfds[i].fd == nfd ? FALSE : TRUE,
						root, &error);
				}
			}
		}
	}

	nn_close(write_nfd[0]);
	nn_close(write_nfd[1]);
	if(nfd > -1) {
		nn_shutdown(nfd, nfd_addr);
		nn_close(nfd);
		janus_transport_session_destroy(client.ts);
		client.ts = NULL;
	}
	if(admin_nfd > -1) {
		nn_shutdown(admin_nfd, admin_nfd_addr);
		nn_close(admin_nfd);
		janus_transport_session_destroy(admin_client.ts);
		admin_client.ts = NULL;
	}

	/* Done */
	JANUS_LOG(LOG_INFO, "Nanomsg thread ended\n");
	return NULL;
}