Example #1
0
void Loop::Close()
{
	MS_TRACE();

	int err;
	sigset_t signal_mask;

	if (this->closed)
	{
		MS_ERROR("already closed");

		return;
	}
	this->closed = true;

	// First block all the signals to not be interrupted while closing.
	sigfillset(&signal_mask);
	err = pthread_sigmask(SIG_BLOCK, &signal_mask, nullptr);
	if (err)
		MS_ERROR("pthread_sigmask() failed: %s", std::strerror(errno));

	// Close the SignalsHandler.
	if (this->signalsHandler)
		this->signalsHandler->Close();

	// Close all the Rooms.
	// NOTE: Upon Room closure the onRoomClosed() method is called which
	// removes it from the map, so this is the safe way to iterate the map
	// and remove elements.
	for (auto it = this->rooms.begin(); it != this->rooms.end();)
	{
		RTC::Room* room = it->second;

		it = this->rooms.erase(it);
		room->Close();
	}

	// Close the Notifier.
	this->notifier->Close();

	// Close the Channel socket.
	if (this->channel)
		this->channel->Close();
}
Example #2
0
	void DtlsTransport::GenerateFingerprints()
	{
		MS_TRACE();

		for (auto it = DtlsTransport::string2FingerprintAlgorithm.begin(); it != DtlsTransport::string2FingerprintAlgorithm.end(); ++it)
		{
			std::string algorithm_str = it->first;
			FingerprintAlgorithm algorithm = it->second;
			uint8_t binary_fingerprint[EVP_MAX_MD_SIZE];
			unsigned int size = 0;
			char hex_fingerprint[(EVP_MAX_MD_SIZE * 2) + 1];
			const EVP_MD* hash_function;
			int ret;

			switch (algorithm)
			{
				case FingerprintAlgorithm::SHA1:
					hash_function = EVP_sha1();
					break;
				case FingerprintAlgorithm::SHA224:
					hash_function = EVP_sha224();
					break;
				case FingerprintAlgorithm::SHA256:
					hash_function = EVP_sha256();
					break;
				case FingerprintAlgorithm::SHA384:
					hash_function = EVP_sha384();
					break;
				case FingerprintAlgorithm::SHA512:
					hash_function = EVP_sha512();
					break;
				default:
					MS_ABORT("unknown algorithm");
			}

			ret = X509_digest(DtlsTransport::certificate, hash_function, binary_fingerprint, &size);
			if (ret == 0)
			{
				MS_ERROR("X509_digest() failed");
				MS_THROW_ERROR("Fingerprints generation failed");
			}

			// Convert to hexadecimal format in lowecase without colons.
			for (unsigned int i = 0; i < size; i++)
			{
				std::sprintf(hex_fingerprint + (i * 2), "%.2x", binary_fingerprint[i]);
			}
			hex_fingerprint[size * 2] = '\0';

			MS_DEBUG("%-7s fingerprint: %s", algorithm_str.c_str(), hex_fingerprint);

			// Store in the JSON.
			DtlsTransport::localFingerprints[algorithm_str] = hex_fingerprint;
		}
	}
Example #3
0
bool Settings::ReloadConfigurationFile() {
	MS_TRACE();

	if (Settings::arguments.configFile.empty()) {
		MS_ERROR("no configuration file was given in command line options");
		return false;
	}

	libconfig::Config* config;

	try {
		config = ParseConfigFile();
	}
	catch (const MediaSoupError &error) {
		MS_ERROR("%s", error.what());
		return false;
	}

	std::string str_value;

	// Just some configuration settings can be reloaded.

	try {
		/* First level settings. */

		if (config->lookupValue("logLevel", str_value))
			SetLogLevel(str_value);
		else
			Settings::configuration.logLevel = LOG_DEBUG;
	}
	catch (const MediaSoupError &error) {
		MS_ERROR("error in configuration file: %s", error.what());
		delete config;
		return false;
	}

	delete config;
	return true;
}
Example #4
0
	void DtlsTransport::ReadCertificateAndPrivateKeyFromFiles()
	{
		MS_TRACE();

		FILE* file = nullptr;

		file = fopen(Settings::configuration.dtlsCertificateFile.c_str(), "r");
		if (!file)
		{
			MS_ERROR("error reading DTLS certificate file: %s", std::strerror(errno));
			goto error;
		}
		DtlsTransport::certificate = PEM_read_X509(file, nullptr, nullptr, nullptr);
		if (!DtlsTransport::certificate)
		{
			LOG_OPENSSL_ERROR("PEM_read_X509() failed");
			goto error;
		}
		fclose(file);

		file = fopen(Settings::configuration.dtlsPrivateKeyFile.c_str(), "r");
		if (!file)
		{
			MS_ERROR("error reading DTLS private key file: %s", std::strerror(errno));
			goto error;
		}
		DtlsTransport::privateKey = PEM_read_PrivateKey(file, nullptr, nullptr, nullptr);
		if (!DtlsTransport::privateKey)
		{
			LOG_OPENSSL_ERROR("PEM_read_PrivateKey() failed");
			goto error;
		}
		fclose(file);

		return;

	error:
		MS_THROW_ERROR("error reading DTLS certificate and private key PEM files");
	}
Example #5
0
	void DtlsTransport::Run(Role localRole)
	{
		MS_TRACE();

		MS_ASSERT(localRole == Role::CLIENT || localRole == Role::SERVER, "local DTLS role must be 'client' or 'server'");

		Role previousLocalRole = this->localRole;

		if (localRole == previousLocalRole)
		{
			MS_ERROR("same local DTLS role provided, doing nothing");

			return;
		}

		// If the previous local DTLS role was 'client' or 'server' do reset.
		if (previousLocalRole == Role::CLIENT || previousLocalRole == Role::SERVER)
		{
			MS_DEBUG("resetting DTLS due to local role change");

			Reset();
		}

		// Update local role.
		this->localRole = localRole;

		// Set state and notify the listener.
		this->state = DtlsState::CONNECTING;
		this->listener->onDtlsConnecting(this);

		switch (this->localRole)
		{
			case Role::CLIENT:
				MS_DEBUG("running [role:client]");

				SSL_set_connect_state(this->ssl);
				SSL_do_handshake(this->ssl);
				SendPendingOutgoingDtlsData();
				SetTimeout();
				break;
			case Role::SERVER:
				MS_DEBUG("running [role:server]");

				SSL_set_accept_state(this->ssl);
				SSL_do_handshake(this->ssl);
				break;
			default:
				MS_ABORT("invalid local DTLS role");
				break;
		}
	}
Example #6
0
void Room::onRTPPacket(RTC::Peer* peer, RTC::RTPPacket* packet) {
	MS_TRACE();

	int peer_id = *(int*)peer->GetUserData();
	MS_BYTE payload_type = packet->GetPayloadType();
	MS_4BYTES original_ssrc = packet->GetSSRC();

	MS_DEBUG("valid RTP packet received from Peer %d [ssrc: %llu | payload: %hu]",
		peer_id, (unsigned long long)packet->GetSSRC(), (unsigned short)packet->GetPayloadType());


	switch(payload_type) {
		case PAYLOAD_TYPE_AUDIO:
		case PAYLOAD_TYPE_VIDEO:
			break;
		default:
			MS_ERROR("payload is not OPUS %d nor VP8 %d, packet ignored", PAYLOAD_TYPE_AUDIO, PAYLOAD_TYPE_VIDEO);
			return;
	}

	// Deliver to all the peers.
	// TODO: but this one? yes (TODO)
	for (auto dst_peer : this->peers) {
		// if (dst_peer == peer)
		// 	continue;

		int dst_peer_id = *(int*)dst_peer->GetUserData();

		switch(payload_type) {
			case PAYLOAD_TYPE_AUDIO:
				packet->SetSSRC((MS_4BYTES)(SSRC_AUDIO_BASE + (peer_id * 10) + dst_peer_id));
				break;
			case PAYLOAD_TYPE_VIDEO:
				packet->SetSSRC((MS_4BYTES)(SSRC_VIDEO_BASE + (peer_id * 10) + dst_peer_id));
				break;
			default:
				MS_ABORT("no puede ser!!!");
				return;
		}

		MS_DEBUG("sending RTP packet to Peer %d [ssrc: %llu | payload: %hu | size: %zu]",
			dst_peer_id, (unsigned long long)packet->GetSSRC(), (unsigned short)packet->GetPayloadType(), packet->GetLength());

		dst_peer->SendRTPPacket(packet);

		// NOTE: recover the previous SSRC since other peers are going to
		// send this same RTPPacket!
		packet->SetSSRC(original_ssrc);
	}
}
Example #7
0
	void DtlsTransport::ProcessDtlsData(const uint8_t* data, size_t len)
	{
		MS_TRACE();

		int written;
		int read;

		if (!IsRunning())
		{
			MS_ERROR("cannot process data while not running");

			return;
		}

		// Write the received DTLS data into the sslBioFromNetwork.
		written = BIO_write(this->sslBioFromNetwork, (const void*)data, (int)len);
		if (written != (int)len)
			MS_WARN("OpenSSL BIO_write() wrote less (%zu bytes) than given data (%zu bytes)", (size_t)written, len);

		// Must call SSL_read() to process received DTLS data.
		read = SSL_read(this->ssl, (void*)DtlsTransport::sslReadBuffer, MS_SSL_READ_BUFFER_SIZE);

		// Send data if it's ready.
		SendPendingOutgoingDtlsData();

		// Check SSL status and return if it is bad/closed.
		if (!CheckStatus(read))
			return;

		// Set/update the DTLS timeout.
		if (!SetTimeout())
			return;

		// Application data received. Notify to the listener.
		if (read > 0)
		{
			// It is allowed to receive DTLS data even before validating remote fingerprint.
			if (!this->handshakeDone)
			{
				MS_DEBUG("ignoring application data received while DTLS handshake not done");

				return;
			}

			// Notify the listener.
			this->listener->onDtlsApplicationData(this, (uint8_t*)DtlsTransport::sslReadBuffer, (size_t)read);
		}
	}
Example #8
0
bool TcpConnection::SetPeerAddress()
{
	MS_TRACE();

	int err;
	int len = sizeof(this->peerAddr);

	err = uv_tcp_getpeername(this->uvHandle, (struct sockaddr*)&this->peerAddr, &len);
	if (err)
	{
		MS_ERROR("uv_tcp_getpeername() failed: %s", uv_strerror(err));

		return false;
	}

	int family;
	Utils::IP::GetAddressInfo((const struct sockaddr*)&this->peerAddr, &family, this->peerIP, &this->peerPort);

	return true;
}
Example #9
0
void OpenSSL::ClassDestroy() {
	MS_TRACE();

	MS_DEBUG("unloading openssl");

	// FAQ: https://www.openssl.org/support/faq.html#PROG13

	// Thread-local cleanup functions.
	ERR_remove_thread_state(nullptr);

	// Application-global cleanup functions that are aware of usage (and
	// therefore thread-safe).
	ENGINE_cleanup();

	// "Brutal" (thread-unsafe) Application-global cleanup functions.
	ERR_free_strings();
	EVP_cleanup();  // Removes all ciphers and digests.
	CRYPTO_cleanup_all_ex_data();

	// https://bugs.launchpad.net/percona-server/+bug/1341067.
	sk_SSL_COMP_free(SSL_COMP_get_compression_methods());

	// Free mutexes.
	for (int i=0; i<OpenSSL::numMutexes; i++) {
		int err = pthread_mutex_destroy(&OpenSSL::mutexes[i]);
		if (err)
			MS_ERROR("pthread_mutex_destroy() failed with return code %d\n", err);
	}
	if (OpenSSL::mutexes)
		delete[] OpenSSL::mutexes;

	// Reset callbacks.
	CRYPTO_THREADID_set_callback(nullptr);
	CRYPTO_set_locking_callback(nullptr);
	CRYPTO_set_dynlock_create_callback(nullptr);
	CRYPTO_set_dynlock_lock_callback(nullptr);
	CRYPTO_set_dynlock_destroy_callback(nullptr);
}
Example #10
0
	void RtpSender::HandleRequest(Channel::Request* request)
	{
		MS_TRACE();

		switch (request->methodId)
		{
			case Channel::Request::MethodId::rtpSender_dump:
			{
				Json::Value json = toJson();

				request->Accept(json);

				break;
			}

			default:
			{
				MS_ERROR("unknown method");

				request->Reject("unknown method");
			}
		}
	}
Example #11
0
	void DtlsTransport::SendApplicationData(const uint8_t* data, size_t len)
	{
		MS_TRACE();

		// We cannot send data to the peer if its remote fingerprint is not validated.
		if (this->state != DtlsState::CONNECTED)
		{
			MS_ERROR("cannot send application data while DTLS is not fully connected");

			return;
		}

		if (len == 0)
		{
			MS_DEBUG("ignoring 0 length data");

			return;
		}

		int written;

		written = SSL_write(this->ssl, (const void*)data, (int)len);
		if (written < 0)
		{
			LOG_OPENSSL_ERROR("SSL_write() failed");

			CheckStatus(written);
		}
		else if (written != (int)len)
		{
			MS_WARN("OpenSSL SSL_write() wrote less (%d bytes) than given data (%zu bytes)", written, len);
		}

		// Send data.
		SendPendingOutgoingDtlsData();
	}
Example #12
0
int main(int argc, char* argv[])
{
	// Ensure we are called by our Node library.
	if (argc == 1 || !std::getenv("MEDIASOUP_CHANNEL_FD"))
	{
		std::cerr << "ERROR: you don't seem to be my real father" << std::endl;
		std::_Exit(EXIT_FAILURE);
	}

	std::string id = std::string(argv[1]);
	int channelFd = std::stoi(std::getenv("MEDIASOUP_CHANNEL_FD"));

	// Initialize libuv stuff (we need it for the Channel).
	DepLibUV::ClassInit();

	// Set the Channel socket (this will be handled and deleted by the Loop).
	Channel::UnixStreamSocket* channel = new Channel::UnixStreamSocket(channelFd);

	// Initialize the Logger.
	Logger::Init(id, channel);

	// Setup the configuration.
	try
	{
		Settings::SetConfiguration(argc, argv);
	}
	catch (const MediaSoupError &error)
	{
		MS_ERROR("configuration error: %s", error.what());

		exitWithError();
	}

	// Print the effective configuration.
	Settings::PrintConfiguration();

	MS_DEBUG("starting " MS_PROCESS_NAME " [pid:%ld]", (long)getpid());

	#if defined(MS_LITTLE_ENDIAN)
		MS_DEBUG("detected Little-Endian CPU");
	#elif defined(MS_BIG_ENDIAN)
		MS_DEBUG("detected Big-Endian CPU");
	#endif

	#if defined(INTPTR_MAX) && defined(INT32_MAX) && (INTPTR_MAX == INT32_MAX)
		MS_DEBUG("detected 32 bits architecture");
	#elif defined(INTPTR_MAX) && defined(INT64_MAX) && (INTPTR_MAX == INT64_MAX)
		MS_DEBUG("detected 64 bits architecture");
	#else
		MS_WARN("cannot determine whether the architecture is 32 or 64 bits");
	#endif

	try
	{
		init();

		// Run the Loop.
		Loop loop(channel);

		destroy();

		MS_DEBUG_STD("success exit");
		exitSuccess();
	}
	catch (const MediaSoupError &error)
	{
		destroy();

		MS_ERROR_STD("failure exit: %s", error.what());
		exitWithError();
	}
}
Example #13
0
void Settings::ReadArguments(int argc, char* argv[]) {
	MS_TRACE();

	/* Variables for getopt. */

	int c;
	int option_index = 0;
	extern char *optarg;
	extern int optind, opterr, optopt;

	// For getopt_long().
	// Begin with ":" so we get ':' error in case a valid option requires argument.
	std::string short_options = ":c:dp:u:g:vh";

	// For getopt_long().
	struct option long_options[] = {
		{ "configfile", required_argument, nullptr, 'c' },
		{ "daemonize",  no_argument,       nullptr, 'd' },
		{ "pidfile",    required_argument, nullptr, 'p' },
		{ "user",       required_argument, nullptr, 'u' },
		{ "group",      required_argument, nullptr, 'g' },
		{ "version",    no_argument,       nullptr, 'v' },
		{ "help",       no_argument,       nullptr, 'h' },
		{ 0, 0, 0, 0 }
	};

	// A map for associating short and long option names.
	std::map<char, std::string> long_option_names = {
		{ 'c', "configfile" },
		{ 'd', "daemonize"  },
		{ 'p', "pidfile"    },
		{ 'u', "user"       },
		{ 'g', "group"      },
		{ 'v', "version"    },
		{ 'h', "help"       }
	};

	/* Parse command line options. */

	opterr = 0;  // Don't allow getopt to print error messages.
	while ((c = getopt_long(argc, argv, short_options.c_str(), long_options, &option_index)) != -1) {
		switch(c) {
			case 'c':
				Settings::arguments.configFile = optarg;
				break;

			case 'd':
				Settings::arguments.daemonize = true;
				break;

			case 'p':
				Settings::arguments.pidFile = optarg;
				break;

			case 'u':
				Settings::arguments.user = optarg;
				break;

			case 'g':
				Settings::arguments.group = optarg;
				break;

			case 'v':
				Settings::PrintVersion();
				std::_Exit(EXIT_SUCCESS);
				break;

			case 'h':
				Settings::PrintVersion();
				Settings::PrintHelp(false);
				std::_Exit(EXIT_SUCCESS);
				break;

			// Invalid option.
			case '?':
				if (isprint(optopt)) {
					MS_ERROR("invalid option '-%c'", (char)optopt);
					Settings::PrintHelp(true);
					std::_Exit(EXIT_FAILURE);
				}
				else {
					MS_ERROR("unknown long option given as argument");
					Settings::PrintHelp(true);
					std::_Exit(EXIT_FAILURE);
				}

			// Valid option, but it requires and argument that is not given.
			case ':':
				MS_ERROR("option '-%c' or '--%s' requires an argument", (char)optopt, long_option_names[(char)optopt].c_str());
				Settings::PrintHelp(true);
				std::_Exit(EXIT_FAILURE);
				break;

			// This should never happen.
			default:
				MS_ABORT("'default' should never happen");
		}
	}

	// Ensure there are no more command line arguments after parsed options.
	if (optind != argc)
		MS_EXIT_FAILURE("there are remaining arguments after parsing command line options");

	// Ensure that PID file is not given when in foreground mode.
	if (! Settings::arguments.pidFile.empty() && ! Settings::arguments.daemonize)
		MS_EXIT_FAILURE("PID file option requires daemon mode");
}
Example #14
0
	inline
	bool DtlsTransport::CheckRemoteFingerprint()
	{
		MS_TRACE();

		MS_ASSERT(this->remoteFingerprint.algorithm != FingerprintAlgorithm::NONE, "remote fingerprint not set");

		X509* certificate;
		uint8_t binary_fingerprint[EVP_MAX_MD_SIZE];
		unsigned int size = 0;
		char hex_fingerprint[(EVP_MAX_MD_SIZE * 2) + 1];
		const EVP_MD* hash_function;
		int ret;

		certificate = SSL_get_peer_certificate(this->ssl);
		if (!certificate)
		{
			MS_WARN("no certificate was provided by the peer");

			return false;
		}

		switch (this->remoteFingerprint.algorithm)
		{
			case FingerprintAlgorithm::SHA1:
				hash_function = EVP_sha1();
				break;
			case FingerprintAlgorithm::SHA224:
				hash_function = EVP_sha224();
				break;
			case FingerprintAlgorithm::SHA256:
				hash_function = EVP_sha256();
				break;
			case FingerprintAlgorithm::SHA384:
				hash_function = EVP_sha384();
				break;
			case FingerprintAlgorithm::SHA512:
				hash_function = EVP_sha512();
				break;
			default:
				MS_ABORT("unknown algorithm");
		}

		ret = X509_digest(certificate, hash_function, binary_fingerprint, &size);
		X509_free(certificate);
		if (ret == 0)
		{
			MS_ERROR("X509_digest() failed");

			return false;
		}

		// Convert to hexadecimal format in lowecase without colons.
		for (unsigned int i = 0; i < size; i++)
		{
			std::sprintf(hex_fingerprint + (i * 2), "%.2x", binary_fingerprint[i]);
		}
		hex_fingerprint[size * 2] = '\0';

		if (this->remoteFingerprint.value.compare(hex_fingerprint) != 0)
		{
			MS_WARN("fingerprint in the remote certificate (%s) does not match the announced one (%s)", hex_fingerprint, this->remoteFingerprint.value.c_str());

			return false;
		}

		MS_DEBUG("valid remote fingerprint");

		return true;
	}
Example #15
0
	void DtlsTransport::CreateSSL_CTX()
	{
		MS_TRACE();

		std::string ssl_srtp_profiles;
		EC_KEY* ecdh = nullptr;
		int ret;

		/* Set the global DTLS context. */

		// - Both DTLS 1.0 and 1.2 (requires OpenSSL >= 1.1.0).
		#if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
			DtlsTransport::sslCtx = SSL_CTX_new(DTLS_method());
		// - Just DTLS 1.0 (requires OpenSSL >= 1.0.1).
		#elif (OPENSSL_VERSION_NUMBER >= 0x10001000L)
			DtlsTransport::sslCtx = SSL_CTX_new(DTLSv1_method());
		#else
			#error "too old OpenSSL version"
		#endif

		if (!DtlsTransport::sslCtx)
		{
			LOG_OPENSSL_ERROR("SSL_CTX_new() failed");
			goto error;
		}

		ret = SSL_CTX_use_certificate(DtlsTransport::sslCtx, DtlsTransport::certificate);
		if (ret == 0)
		{
			LOG_OPENSSL_ERROR("SSL_CTX_use_certificate() failed");
			goto error;
		}

		ret = SSL_CTX_use_PrivateKey(DtlsTransport::sslCtx, DtlsTransport::privateKey);
		if (ret == 0)
		{
			LOG_OPENSSL_ERROR("SSL_CTX_use_PrivateKey() failed");
			goto error;
		}

		ret = SSL_CTX_check_private_key(DtlsTransport::sslCtx);
		if (ret == 0)
		{
			LOG_OPENSSL_ERROR("SSL_CTX_check_private_key() failed");
			goto error;
		}

		// Set options.
		SSL_CTX_set_options(DtlsTransport::sslCtx, SSL_OP_CIPHER_SERVER_PREFERENCE | SSL_OP_NO_TICKET | SSL_OP_SINGLE_ECDH_USE);

		// Don't use sessions cache.
		SSL_CTX_set_session_cache_mode(DtlsTransport::sslCtx, SSL_SESS_CACHE_OFF);

		// Read always as much into the buffer as possible.
		// NOTE: This is the default for DTLS, but a bug in non latest OpenSSL
		// versions makes this call required.
		SSL_CTX_set_read_ahead(DtlsTransport::sslCtx, 1);

		SSL_CTX_set_verify_depth(DtlsTransport::sslCtx, 4);

		// Require certificate from peer.
		SSL_CTX_set_verify(DtlsTransport::sslCtx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, on_ssl_certificate_verify);

		// Set SSL info callback.
		SSL_CTX_set_info_callback(DtlsTransport::sslCtx, on_ssl_info);

		// Set ciphers.
		ret = SSL_CTX_set_cipher_list(DtlsTransport::sslCtx, "ALL:!ADH:!LOW:!EXP:!MD5:!aNULL:!eNULL:@STRENGTH");
		if (ret == 0)
		{
			LOG_OPENSSL_ERROR("SSL_CTX_set_cipher_list() failed");
			goto error;
		}

		// Enable ECDH ciphers.
		// DOC: http://en.wikibooks.org/wiki/OpenSSL/Diffie-Hellman_parameters
		// NOTE: https://code.google.com/p/chromium/issues/detail?id=406458
		// For OpenSSL >= 1.0.2:
		#if (OPENSSL_VERSION_NUMBER >= 0x10002000L)
			SSL_CTX_set_ecdh_auto(DtlsTransport::sslCtx, 1);
		#else
			ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
			if (!ecdh)
			{
				LOG_OPENSSL_ERROR("EC_KEY_new_by_curve_name() failed");
				goto error;
			}
			if (SSL_CTX_set_tmp_ecdh(DtlsTransport::sslCtx, ecdh) != 1)
			{
				LOG_OPENSSL_ERROR("SSL_CTX_set_tmp_ecdh() failed");
				goto error;
			}
			EC_KEY_free(ecdh);
			ecdh = nullptr;
		#endif

		// Set the "use_srtp" DTLS extension.
		for (auto it = DtlsTransport::srtpProfiles.begin(); it != DtlsTransport::srtpProfiles.end(); ++it)
		{
			if (it != DtlsTransport::srtpProfiles.begin())
				ssl_srtp_profiles += ":";

			SrtpProfileMapEntry* profile_entry = &(*it);
			ssl_srtp_profiles += profile_entry->name;
		}
		MS_DEBUG("setting SRTP profiles for DTLS: %s", ssl_srtp_profiles.c_str());
		// NOTE: This function returns 0 on success.
		ret = SSL_CTX_set_tlsext_use_srtp(DtlsTransport::sslCtx, ssl_srtp_profiles.c_str());
		if (ret != 0)
		{
			MS_ERROR("SSL_CTX_set_tlsext_use_srtp() failed when entering '%s'", ssl_srtp_profiles.c_str());
			LOG_OPENSSL_ERROR("SSL_CTX_set_tlsext_use_srtp() failed");
			goto error;
		}

		return;

	error:
		if (DtlsTransport::sslCtx)
		{
			SSL_CTX_free(DtlsTransport::sslCtx);
			DtlsTransport::sslCtx = nullptr;
		}

		if (ecdh)
			EC_KEY_free(ecdh);

		MS_THROW_ERROR("SSL context creation failed");
	}
Example #16
0
void Loop::onChannelRequest(Channel::UnixStreamSocket* channel, Channel::Request* request)
{
	MS_TRACE();

	MS_DEBUG("'%s' request", request->method.c_str());

	switch (request->methodId)
	{
		case Channel::Request::MethodId::worker_dump:
		{
			static const Json::StaticString k_workerId("workerId");
			static const Json::StaticString k_rooms("rooms");

			Json::Value json(Json::objectValue);
			Json::Value json_rooms(Json::arrayValue);

			json[k_workerId] = Logger::id;

			for (auto& kv : this->rooms)
			{
				auto room = kv.second;

				json_rooms.append(room->toJson());
			}
			json[k_rooms] = json_rooms;

			request->Accept(json);

			break;
		}

		case Channel::Request::MethodId::worker_updateSettings:
		{
			Settings::HandleRequest(request);

			break;
		}

		case Channel::Request::MethodId::worker_createRoom:
		{
			RTC::Room* room;
			uint32_t roomId;

			try
			{
				room = GetRoomFromRequest(request, &roomId);
			}
			catch (const MediaSoupError &error)
			{
				request->Reject(error.what());
				return;
			}

			if (room)
			{
				request->Reject("Room already exists");
				return;
			}

			try
			{
				room = new RTC::Room(this, this->notifier, roomId);
			}
			catch (const MediaSoupError &error)
			{
				request->Reject(error.what());
				return;
			}

			this->rooms[roomId] = room;

			MS_DEBUG("Room created [roomId:%" PRIu32 "]", roomId);
			request->Accept();

			break;
		}

		case Channel::Request::MethodId::room_close:
		case Channel::Request::MethodId::room_dump:
		case Channel::Request::MethodId::room_createPeer:
		case Channel::Request::MethodId::room_getCapabilities:
		case Channel::Request::MethodId::peer_close:
		case Channel::Request::MethodId::peer_dump:
		case Channel::Request::MethodId::peer_createTransport:
		case Channel::Request::MethodId::peer_createRtpReceiver:
		case Channel::Request::MethodId::transport_close:
		case Channel::Request::MethodId::transport_dump:
		case Channel::Request::MethodId::transport_setRemoteDtlsParameters:
		case Channel::Request::MethodId::rtpReceiver_close:
		case Channel::Request::MethodId::rtpReceiver_dump:
		case Channel::Request::MethodId::rtpReceiver_receive:
		case Channel::Request::MethodId::rtpReceiver_setRtpRawEvent:
		case Channel::Request::MethodId::rtpReceiver_setRtpObjectEvent:
		case Channel::Request::MethodId::rtpSender_dump:
		case Channel::Request::MethodId::rtpSender_setTransport:
		{
			RTC::Room* room;

			try
			{
				room = GetRoomFromRequest(request);
			}
			catch (const MediaSoupError &error)
			{
				request->Reject(error.what());
				return;
			}

			if (!room)
			{
				request->Reject("Room does not exist");
				return;
			}

			room->HandleRequest(request);

			break;
		}

		default:
		{
			MS_ERROR("unknown method");

			request->Reject("unknown method");
		}
	}
}