Exemplo n.º 1
0
void RequestAuthenticate::Dump() {
    MS_DEBUG("[Request Authenticate]");
    MS_DEBUG("- transaction: %zu", (size_t)this->transaction);
    MS_DEBUG("- user: %s", this->user.c_str());
    MS_DEBUG("- passwd: %s", this->passwd.c_str());
    MS_DEBUG("[/Request Authenticate]");
}
Exemplo n.º 2
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;
		}
	}
Exemplo n.º 3
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);
	}
}
Exemplo n.º 4
0
inline
void TcpConnection::onUvShutdown(uv_shutdown_t* req, int status)
{
	MS_TRACE();

	delete req;

	if (status == UV_EPIPE || status == UV_ENOTCONN || status == UV_ECANCELED)
		MS_DEBUG("shutdown error: %s", uv_strerror(status));
	else if (status)
		MS_DEBUG("shutdown error: %s", uv_strerror(status));

	// Now do close the handle.
	uv_close((uv_handle_t*)this->uvHandle, (uv_close_cb)on_close);
}
Exemplo n.º 5
0
void TcpConnection::Dump()
{
	MS_DEBUG("[Tcp, local:%s :%" PRIu16 ", remote:%s :%" PRIu16 ", status:%s]",
		this->localIP.c_str(), (uint16_t)this->localPort,
		this->peerIP.c_str(), (uint16_t)this->peerPort,
		(!this->isClosing) ? "open" : "closed");
}
Exemplo n.º 6
0
	inline
	RTC::SrtpSession::Profile DtlsTransport::GetNegotiatedSrtpProfile()
	{
		MS_TRACE();

		RTC::SrtpSession::Profile negotiated_srtp_profile = RTC::SrtpSession::Profile::NONE;

		// Ensure that the SRTP profile has been negotiated.
		SRTP_PROTECTION_PROFILE* ssl_srtp_profile = SSL_get_selected_srtp_profile(this->ssl);
		if (!ssl_srtp_profile)
		{
			return negotiated_srtp_profile;
		}

		// Get the negotiated SRTP profile.
		for (auto it = DtlsTransport::srtpProfiles.begin(); it != DtlsTransport::srtpProfiles.end(); ++it)
		{
			SrtpProfileMapEntry* profile_entry = &(*it);

			if (std::strcmp(ssl_srtp_profile->name, profile_entry->name) == 0)
			{
				MS_DEBUG("chosen SRTP profile: %s", profile_entry->name);

				negotiated_srtp_profile = profile_entry->profile;
			}
		}

		MS_ASSERT(negotiated_srtp_profile != RTC::SrtpSession::Profile::NONE, "chosen SRTP profile is not an available one");

		return negotiated_srtp_profile;
	}
Exemplo n.º 7
0
void OpenSSL::ClassInit() {
	MS_TRACE();

	MS_DEBUG("loaded openssl version: %s", SSLeay_version(SSLEAY_VERSION));

	// First initialize OpenSSL stuff.
	SSL_load_error_strings();
	SSL_library_init();
	RAND_poll();

	// Make OpenSSL thread-safe.
	OpenSSL::mutexes = new pthread_mutex_t[CRYPTO_num_locks()];
	if (! OpenSSL::mutexes)
		MS_THROW_ERROR("allocation of mutexes failed");

	OpenSSL::numMutexes = CRYPTO_num_locks();

	for (int i=0; i<OpenSSL::numMutexes; i++) {
		int err = pthread_mutex_init(&OpenSSL::mutexes[i], nullptr);
		if (err)
			MS_THROW_ERROR("pthread_mutex_init() failed with return code %d\n", err);
	}

	CRYPTO_THREADID_set_callback(OpenSSL::SetThreadId);
	CRYPTO_set_locking_callback(OpenSSL::LockingFunction);
	CRYPTO_set_dynlock_create_callback(OpenSSL::DynCreateFunction);
	CRYPTO_set_dynlock_lock_callback(OpenSSL::DynLockFunction);
	CRYPTO_set_dynlock_destroy_callback(OpenSSL::DynDestroyFunction);
}
Exemplo n.º 8
0
	void DtlsTransport::Reset()
	{
		MS_TRACE();

		int ret;

		if (!IsRunning())
			return;

		MS_DEBUG("resetting DTLS transport");

		// Stop the DTLS timer.
		this->timer->Stop();

		// We need to reset the SSL instance so we need to "shutdown" it, but we don't
		// want to send a Close Alert to the peer, so just don't call to
		// SendPendingOutgoingDTLSData().
		SSL_shutdown(this->ssl);

		this->localRole = Role::NONE;
		this->state = DtlsState::NEW;
		this->handshakeDone = false;
		this->handshakeDoneNow = false;

		// Reset SSL status.
		// NOTE: For this to properly work, SSL_shutdown() must be called before.
		// NOTE: This may fail if not enough DTLS handshake data has been received,
		// but we don't care so just clear the error queue.
		ret = SSL_clear(this->ssl);
		if (ret == 0)
			ERR_clear_error();
	}
Exemplo n.º 9
0
	inline
	void DtlsTransport::onSSLInfo(int where, int ret)
	{
		MS_TRACE();

		int w = where & -SSL_ST_MASK;
		const char* role;

		if (w & SSL_ST_CONNECT)     role = "client";
		else if (w & SSL_ST_ACCEPT) role = "server";
		else                        role = "undefined";

		if (where & SSL_CB_LOOP)
		{
			MS_DEBUG("[role:%s, action:'%s']", role, SSL_state_string_long(this->ssl));
		}
		else if (where & SSL_CB_ALERT)
		{
			const char* alert_type;

			switch (*SSL_alert_type_string(ret))
			{
				case 'W':  alert_type = "warning";    break;
				case 'F':  alert_type = "fatal";      break;
				default:   alert_type = "undefined";
			}

			if (where & SSL_CB_READ)
				MS_DEBUG("received DTLS %s alert: %s", alert_type, SSL_alert_desc_string_long(ret));
			else if (where & SSL_CB_WRITE)
				MS_DEBUG("sending DTLS %s alert: %s", alert_type, SSL_alert_desc_string_long(ret));
			else
				MS_DEBUG("DTLS %s alert: %s", alert_type, SSL_alert_desc_string_long(ret));
		}
		else if (where & SSL_CB_EXIT)
		{
			if (ret == 0)
				MS_DEBUG("[role:%s, failed:'%s']", role, SSL_state_string_long(this->ssl));
			else if (ret < 0)
				MS_DEBUG("role: %s, waiting:'%s']", role, SSL_state_string_long(this->ssl));
		}
		else if (where & SSL_CB_HANDSHAKE_START)
		{
			MS_DEBUG("DTLS handshake start");
		}
		else if (where & SSL_CB_HANDSHAKE_DONE)
		{
			MS_DEBUG("DTLS handshake done");

			this->handshakeDoneNow = true;
		}

		// NOTE: checking SSL_get_shutdown(this->ssl) & SSL_RECEIVED_SHUTDOWN here upon
		// receipt of a close alert does not work (the flag is set after this callback).
	}
Exemplo n.º 10
0
	void DtlsTransport::Dump()
	{
		MS_TRACE();

		MS_DEBUG("[role:%s, running:%s, handshake done:%s, connected:%s]",
			(this->localRole == Role::SERVER ? "server" : (this->localRole == Role::CLIENT ? "client" : "none")),
			IsRunning() ? "yes" : "no",
			this->handshakeDone ? "yes" : "no",
			this->state == DtlsState::CONNECTED ? "yes" : "no");
	}
Exemplo n.º 11
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;
		}
	}
Exemplo n.º 12
0
void Loop::onSignal(SignalsHandler* signalsHandler, int signum)
{
	MS_TRACE();

	switch (signum)
	{
		case SIGINT:
			MS_DEBUG("signal INT received, exiting");
			Close();
			break;

		case SIGTERM:
			MS_DEBUG("signal TERM received, exiting");
			Close();
			break;

		default:
			MS_WARN("received a signal (with signum %d) for which there is no handling code", signum);
	}
}
Exemplo n.º 13
0
inline
void TcpConnection::onUvRead(ssize_t nread, const uv_buf_t* buf)
{
	MS_TRACE();

	if (this->isClosing)
		return;

	if (nread == 0)
		return;

	// Data received.
	if (nread > 0)
	{
		// Update the buffer data length.
		this->bufferDataLen += (size_t)nread;

		// Notify the subclass.
		userOnTcpConnectionRead();
	}
	// Client disconneted.
	else if (nread == UV_EOF || nread == UV_ECONNRESET)
	{
		MS_DEBUG("connection closed by peer, closing server side");

		this->isClosedByPeer = true;

		// Close server side of the connection.
		Close();
	}
	// Some error.
	else
	{
		MS_DEBUG("read error, closing the connection: %s", uv_strerror(nread));

		this->hasError = true;

		// Close server side of the connection.
		Close();
	}
}
Exemplo n.º 14
0
inline
void TcpConnection::onUvWriteError(int error)
{
	MS_TRACE();

	if (this->isClosing)
		return;

	if (error == UV_EPIPE || error == UV_ENOTCONN)
	{
		MS_DEBUG("write error, closing the connection: %s", uv_strerror(error));
	}
	else
	{
		MS_DEBUG("write error, closing the connection: %s", uv_strerror(error));

		this->hasError = true;
	}

	Close();
}
Exemplo n.º 15
0
Loop::Loop(Channel::UnixStreamSocket* channel) :
	channel(channel)
{
	MS_TRACE();

	// Set us as Channel's listener.
	this->channel->SetListener(this);

	// Create the Notifier instance.
	this->notifier = new Channel::Notifier(this->channel);

	// Set the signals handler.
	this->signalsHandler = new SignalsHandler(this);

	// Add signals to handle.
	this->signalsHandler->AddSignal(SIGINT, "INT");
	this->signalsHandler->AddSignal(SIGTERM, "TERM");

	MS_DEBUG("starting libuv loop");
	DepLibUV::RunLoop();
	MS_DEBUG("libuv loop ended");
}
Exemplo n.º 16
0
	inline
	void DtlsTransport::ProcessHandshake()
	{
		MS_TRACE();

		MS_ASSERT(this->handshakeDone, "handshake not done yet");

		// If the remote fingerprint is not yet set then do nothing (this method
		// will be called when the fingerprint is set).
		if (this->remoteFingerprint.algorithm == FingerprintAlgorithm::NONE)
		{
			MS_DEBUG("remote fingerprint not yet set, waiting for it");

			return;
		}

		// Validate the remote fingerprint.
		if (!CheckRemoteFingerprint())
		{
			Reset();

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

			return;
		}

		// Get the negotiated SRTP profile.
		RTC::SrtpSession::Profile srtp_profile;
		srtp_profile = GetNegotiatedSrtpProfile();

		if (srtp_profile != RTC::SrtpSession::Profile::NONE)
		{
			// Extract the SRTP keys (will notify the listener with them).
			ExtractSrtpKeys(srtp_profile);
		}
		else
		{
			// NOTE: We assume that "use_srtp" DTLS extension is required even if
			// there is no audio/video.
			MS_WARN("SRTP profile not negotiated");

			Reset();

			// Set state and notify the listener.
			this->state = DtlsState::FAILED;
			this->listener->onDtlsFailed(this);
		}
	}
Exemplo n.º 17
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);
		}
	}
Exemplo n.º 18
0
void Settings::SetDefaultNumWorkers() {
	MS_TRACE();

	int err;
	uv_cpu_info_t* cpus;
	int num_cpus;

	err = uv_cpu_info(&cpus, &num_cpus);
	if (err)
		MS_ABORT("uv_cpu_info() failed: %s", uv_strerror(err));

	uv_free_cpu_info(cpus, num_cpus);

	MS_DEBUG("auto-detected value for numWorkers: %d", num_cpus);
	Settings::configuration.numWorkers = num_cpus;
}
Exemplo n.º 19
0
	void DtlsTransport::SetRemoteFingerprint(Fingerprint fingerprint)
	{
		MS_TRACE();

		MS_ASSERT(fingerprint.algorithm != FingerprintAlgorithm::NONE, "no fingerprint algorithm provided");

		this->remoteFingerprint = fingerprint;

		// The remote fingerpring may have been set after DTLS handshake was done,
		// so we may need to process it now.
		if (this->handshakeDone && this->state != DtlsState::CONNECTED)
		{
			MS_DEBUG("handshake already done, processing it right now");

			ProcessHandshake();
		}
	}
Exemplo n.º 20
0
	inline
	bool DtlsTransport::SetTimeout()
	{
		MS_TRACE();

		long int ret;
		struct timeval dtls_timeout;
		uint64_t timeout_ms;

		// NOTE: If ret == 0 then ignore the value in dtls_timeout.
		// NOTE: No DTLSv_1_2_get_timeout() or DTLS_get_timeout() in OpenSSL 1.1.0-dev.
		ret = DTLSv1_get_timeout(this->ssl, (void*)&dtls_timeout);
		if (ret == 0)
			return true;

		timeout_ms = (dtls_timeout.tv_sec * (uint64_t)1000) + (dtls_timeout.tv_usec / 1000);
		if (timeout_ms == 0)
		{
			return true;
		}
		else if (timeout_ms < 30000)
		{
			MS_DEBUG("DTLS timer set in %" PRIu64 "ms", timeout_ms);

			this->timer->Start(timeout_ms);

			return true;
		}
		// NOTE: Don't start the timer again if the timeout is greater than 30 seconds.
		else
		{
			MS_WARN("DTLS timeout too high (%" PRIu64 "ms), resetting DLTS", timeout_ms);

			Reset();

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

			return false;
		}
	}
Exemplo n.º 21
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);
}
Exemplo n.º 22
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();
	}
Exemplo n.º 23
0
	inline
	void DtlsTransport::SendPendingOutgoingDtlsData()
	{
		MS_TRACE();

		if (BIO_eof(this->sslBioToNetwork))
			return;

		long read;
		char* data = nullptr;

		read = BIO_get_mem_data(this->sslBioToNetwork, &data);
		if (read <= 0)
			return;

		MS_DEBUG("%ld bytes of DTLS data ready to sent to the peer", read);

		// Notify the listener.
		this->listener->onOutgoingDtlsData(this, (uint8_t*)data, (size_t)read);

		// Clear the BIO buffer.
		// NOTE: the (void) avoids the -Wunused-value warning.
		(void)BIO_reset(this->sslBioToNetwork);
	}
Exemplo n.º 24
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();
	}
}
Exemplo n.º 25
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");
	}
Exemplo n.º 26
0
void Settings::SetDefaultRTClistenIP(int requested_family) {
	MS_TRACE();

	int err;
	uv_interface_address_t* addresses;
	int num_addresses;
	std::string ipv4;
	std::string ipv6;
	int _bind_err;

	err = uv_interface_addresses(&addresses, &num_addresses);
	if (err)
		MS_ABORT("uv_interface_addresses() failed: %s", uv_strerror(err));

	for (int i=0; i<num_addresses; i++) {
		uv_interface_address_t address = addresses[i];

		// Ignore internal addresses.
		if (address.is_internal)
			continue;

		int family;
		MS_PORT port;
		std::string ip;
		Utils::IP::GetAddressInfo((struct sockaddr*)(&address.address.address4), &family, ip, &port);

		if (family != requested_family)
			continue;

		switch(family) {
			case AF_INET:
				// Ignore if already got an IPv4.
				if (! ipv4.empty())
					continue;

				// Check if it is bindable.
				if (! IsBindableIP(ip, AF_INET, &_bind_err)) {
					MS_DEBUG("ignoring '%s' for RTC.listenIPv4: %s", ip.c_str(), std::strerror(errno));
					continue;
				}

				MS_DEBUG("auto-discovered '%s' for RTC.listenIPv4", ip.c_str());
				ipv4 = ip;
				break;

			case AF_INET6:
				// Ignore if already got an IPv6.
				if (! ipv6.empty())
					continue;

				// Check if it is bindable.
				if (! IsBindableIP(ip, AF_INET6, &_bind_err)) {
					MS_DEBUG("ignoring '%s' for RTC.listenIPv6: %s", ip.c_str(), std::strerror(errno));
					continue;
				}

				MS_DEBUG("auto-discovered '%s' for RTC.listenIPv6", ip.c_str());
				ipv6 = ip;
				break;
		}
	}

	if (! ipv4.empty()) {
		Settings::configuration.RTC.listenIPv4 = ipv4;
		Settings::configuration.RTC.hasIPv4 = true;
	}

	if (! ipv6.empty()) {
		Settings::configuration.RTC.listenIPv6 = ipv6;
		Settings::configuration.RTC.hasIPv6 = true;
	}

	uv_free_interface_addresses(addresses, num_addresses);
}
void Fat16_Read(MassStorageType *ms, uint32 logical_address, uint32 transfer_length)
{       
    uint32 end_address = logical_address + transfer_length - 1;
    Sink sink_bulk_out = StreamUsbEndPointSink(end_point_bulk_out);
    
    MS_DEBUG(("FAT16: Read log addr: %ld end addr: %ld\n", logical_address, end_address));
    
    if (!ms->info_read)
    {
        /* information read once from read-only file system */
        uint32 fat_number_sectors;
        uint32 root_number_sectors;
        uint32 data_number_sectors;   
    
        /* FAT size calculations */
        fat_number_sectors = ms->file_info[FILE_INFO_FAT].size / BYTES_PER_SECTOR + 1;       
        if ((ms->file_info[FILE_INFO_FAT].size % BYTES_PER_SECTOR) == 0)
        {            
            fat_number_sectors--;
        }
        ms->file_info[FILE_INFO_FAT].end_sector = FAT1_SECTOR + fat_number_sectors - 1;
    
        /* Root dir size calculations */
        root_number_sectors = ms->file_info[FILE_INFO_ROOT_DIR].size / BYTES_PER_SECTOR + 1;        
        if ((ms->file_info[FILE_INFO_ROOT_DIR].size % BYTES_PER_SECTOR) == 0)
        {            
            root_number_sectors--;
        }
        ms->file_info[FILE_INFO_ROOT_DIR].end_sector = ROOT_SECTOR + root_number_sectors - 1;
    
        /* Data area size calculations */
        data_number_sectors = ms->file_info[FILE_INFO_DATA].size / BYTES_PER_SECTOR + 1;       
        if ((ms->file_info[FILE_INFO_DATA].size % BYTES_PER_SECTOR) == 0)
        {            
            data_number_sectors--;
        }
        ms->file_info[FILE_INFO_DATA].end_sector = DATA_SECTOR + data_number_sectors - 1;
    
        /* don't read this information again to speed things up */
        ms->info_read = TRUE;
    }
    
    while (logical_address <= end_address)
    {
        MS_DEBUG(("FAT16: log addr: %ld\n", logical_address));
        if (logical_address == MBR_SECTOR) /* Master Boot Record */
        {            
            uint8 *buffer = 0;
            
            /* wait for free space in Sink */
            Fat16_WaitAvailable(sink_bulk_out, BYTES_PER_SECTOR);
            
            if ((buffer = claimSink(sink_bulk_out, BYTES_PER_SECTOR)) != 0)
            {
                uint16 offset = 0;
                uint16 size_data = sizeof(MasterBootRecordExeType);
                memmove(buffer, &mbr_exe, size_data);
                offset += size_data;            
                size_data = sizeof(MasterBootRecordPartitionType);
                memmove(buffer + offset, &mbr_partition, size_data);
                offset += size_data;
                memset(buffer + offset, 0, size_data * 3);
                size_data = sizeof(ExeSignatureType);            
                memmove(buffer + BYTES_PER_SECTOR - size_data, &exe_signature, size_data);                
                SinkConfigure(sink_bulk_out, VM_SINK_USB_TRANSFER_LENGTH, BYTES_PER_SECTOR);
                SinkFlush(sink_bulk_out, BYTES_PER_SECTOR);
                MS_DEBUG(("FAT16: MBR returned data\n"));                
            }
            logical_address++;
        }
        else if (logical_address == BOOT_SECTOR) /* Boot Sector */
        {       
            uint8 *buffer = 0;  
            
            /* wait for free space in Sink */
            Fat16_WaitAvailable(sink_bulk_out, BYTES_PER_SECTOR);
                          
            if ((buffer = claimSink(sink_bulk_out, BYTES_PER_SECTOR)) != 0)
            {
                uint16 offset = 0;
                uint16 size_data = sizeof(BootSectorType);
                memmove(buffer, &boot_sector, size_data);
                offset += size_data;
                size_data = sizeof(BootSectorExeType);
                memmove(buffer + offset, &boot_exe, size_data);
                offset += size_data;
                size_data = sizeof(ExeSignatureType);
                memmove(buffer + offset, &exe_signature, size_data);
                SinkConfigure(sink_bulk_out, VM_SINK_USB_TRANSFER_LENGTH, BYTES_PER_SECTOR);
                SinkFlush(sink_bulk_out, BYTES_PER_SECTOR);
                MS_DEBUG(("FAT16: BOOT returned data\n"));
            }
            logical_address++;
        }
        else if ((logical_address >= FAT1_SECTOR) && (logical_address <= ms->file_info[FILE_INFO_FAT].end_sector)) /* FAT 1 */
        {
            MS_DEBUG(("FAT16: FAT1 sector\n"));
            logical_address = read_sectors(&ms->file_info[FILE_INFO_FAT], logical_address, end_address - logical_address + 1, FAT1_SECTOR);
        }
        else if ((logical_address >= FAT2_SECTOR) && (logical_address <= (ms->file_info[FILE_INFO_FAT].end_sector + SECTORS_PER_FAT))) /* FAT 2 */
        {
            MS_DEBUG(("FAT16: FAT2 sector\n"));
            logical_address = read_sectors(&ms->file_info[FILE_INFO_FAT], logical_address, end_address - logical_address + 1, FAT2_SECTOR);
        }
        else if ((logical_address >= ROOT_SECTOR) && (logical_address <= ms->file_info[FILE_INFO_ROOT_DIR].end_sector)) /* Root Directory */
        {
            MS_DEBUG(("FAT16: root sector\n"));
            logical_address = read_sectors(&ms->file_info[FILE_INFO_ROOT_DIR], logical_address, end_address - logical_address + 1, ROOT_SECTOR);
        }
        else if ((logical_address >= DATA_SECTOR) && (logical_address <= ms->file_info[FILE_INFO_DATA].end_sector)) /* Data Area */
        {
            MS_DEBUG(("FAT16: data sector\n"));
            logical_address = read_sectors(&ms->file_info[FILE_INFO_DATA], logical_address, end_address - logical_address + 1, DATA_SECTOR);
        }
        else /* sector with no data */
        {
            uint8 *buffer = 0;
            
            /* wait for free space in Sink */
            Fat16_WaitAvailable(sink_bulk_out, BYTES_PER_SECTOR);
                
            if ((buffer = claimSink(sink_bulk_out, BYTES_PER_SECTOR)) != 0)
            {
                memset(buffer, 0, BYTES_PER_SECTOR);                
                SinkConfigure(sink_bulk_out, VM_SINK_USB_TRANSFER_LENGTH, BYTES_PER_SECTOR);
                SinkFlush(sink_bulk_out, BYTES_PER_SECTOR);
                MS_DEBUG(("FAT16: empty sector\n"));
            }
            logical_address++;
        }
    }
}
static uint32 read_sectors(FileInfoType *file_info, uint32 logical_address, uint32 transfer_length, uint32 area_start_sector)
{
    uint32 start_sector;
    uint32 end_sector;
    uint32 file_end_sector = file_info->end_sector;
    uint16 i = 0;
    Sink sink = StreamUsbEndPointSink(end_point_bulk_out);
    
    /* correct end sector for FAT2, as it's otherwise treated as FAT1 */
    if (area_start_sector == FAT2_SECTOR)
        file_end_sector += SECTORS_PER_FAT;
    
    /* find the start sector and end sector for this type of data */
    start_sector = logical_address - area_start_sector;
    end_sector = start_sector + transfer_length - 1;
    if (end_sector > (file_end_sector - area_start_sector))
        end_sector = file_end_sector - area_start_sector;

    MS_DEBUG(("FAT16: start %ld end %ld fileend %ld log %ld areastart %ld\n",start_sector,end_sector,file_info->end_sector,logical_address,area_start_sector));
    
    /* check to see if the file read should begin at the start of the file */
    if ((file_info->src == 0) || (start_sector < file_info->current_start_sector))
    {
        if (file_info->params)
            file_info->src = StreamRegionSource(file_info->params, file_info->size);
        else
            file_info->src = StreamFileSource(file_info->index);
        file_info->current_start_sector = 0;
        
        MS_DEBUG(("FAT16: new file\n"));
    }
    
    /* seek through the file until the correct sector is reached */
    while ((start_sector > file_info->current_start_sector) && (file_info->current_start_sector < end_sector))
    {
        SourceDrop(file_info->src, BYTES_PER_SECTOR);
        file_info->current_start_sector++;   
        MS_DEBUG(("FAT16: src drop %ld\n",file_info->current_start_sector));
    }    
    
    /* send the data in the sectors from start_sector to end_sector */
    while (i <= (end_sector - start_sector))
    {
        uint8 *buffer = 0;
        uint16 sink_slack = 0;
        uint16 source_size;
        uint16 blocks_in_sink;
        uint16 blocks_in_source;
        uint16 blocks_to_read;
        uint32 bytes_to_read;
        uint32 remaining_bytes;
        uint16 bytes_to_copy = 0;          
        
        /* wait for free space in Sink */
        Fat16_WaitAvailable(sink, BYTES_PER_SECTOR);
        
        sink_slack = SinkSlack(sink);
        source_size = SourceSize(file_info->src);
        blocks_in_sink = sink_slack / BYTES_PER_SECTOR;
        
        /* find the maximum sectors that can be sent */
        if ((source_size % BYTES_PER_SECTOR) == 0)
            blocks_in_source = source_size / BYTES_PER_SECTOR;
        else
            blocks_in_source = source_size / BYTES_PER_SECTOR + 1;
        blocks_to_read = blocks_in_sink > blocks_in_source ? blocks_in_source : blocks_in_sink;
        if (blocks_to_read > (end_sector - i + 1))
            blocks_to_read = end_sector - i + 1;
        bytes_to_read = blocks_to_read * BYTES_PER_SECTOR;
        remaining_bytes = file_info->size - (file_info->current_start_sector * BYTES_PER_SECTOR);
        
        MS_DEBUG(("FAT16: info sink_slack:%d source_size:%d blocks_to_read:%d\n",sink_slack,source_size,blocks_to_read));
        
        if (blocks_to_read == 0)
            break;
        
        if (remaining_bytes < bytes_to_read)
            bytes_to_copy = remaining_bytes;
        else
            bytes_to_copy = bytes_to_read;
                             
        if ((buffer = claimSink(sink, bytes_to_read)) != 0)
        {            
            const uint8 *data_ptr = SourceMap(file_info->src);
            bool flush;

            if (bytes_to_copy < bytes_to_read)
                memset(buffer + bytes_to_copy, 0, bytes_to_read - bytes_to_copy); 
            memmove(buffer, data_ptr, bytes_to_copy);            
            SinkConfigure(sink, VM_SINK_USB_TRANSFER_LENGTH, bytes_to_read);
            flush = SinkFlush(sink, bytes_to_read);
            SourceDrop(file_info->src, bytes_to_copy);
            file_info->current_start_sector += blocks_to_read;
            i += blocks_to_read;
            MS_DEBUG(("FAT16: send bytes %d pos %ld i %d flush %d\n",bytes_to_copy,file_info->current_start_sector,i,flush));
        }   
        else
        {
            break;
        }
    }
    
    /* return the next logical address to process */
    return logical_address + end_sector - start_sector + 1;
}
Exemplo n.º 29
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;
	}
Exemplo n.º 30
0
	inline
	bool DtlsTransport::CheckStatus(int return_code)
	{
		MS_TRACE();

		int err;
		bool was_handshake_done = this->handshakeDone;

		err = SSL_get_error(this->ssl, return_code);
		switch (err)
		{
			case SSL_ERROR_NONE:
				break;
			case SSL_ERROR_SSL:
				LOG_OPENSSL_ERROR("SSL status: SSL_ERROR_SSL");
				break;
			case SSL_ERROR_WANT_READ:
				break;
			case SSL_ERROR_WANT_WRITE:
				MS_DEBUG("SSL status: SSL_ERROR_WANT_WRITE");
				break;
			case SSL_ERROR_WANT_X509_LOOKUP:
				MS_DEBUG("SSL status: SSL_ERROR_WANT_X509_LOOKUP");
				break;
			case SSL_ERROR_SYSCALL:
				LOG_OPENSSL_ERROR("SSL status: SSL_ERROR_SYSCALL");
				break;
			case SSL_ERROR_ZERO_RETURN:
				break;
			case SSL_ERROR_WANT_CONNECT:
				MS_DEBUG("SSL status: SSL_ERROR_WANT_CONNECT");
				break;
			case SSL_ERROR_WANT_ACCEPT:
				MS_DEBUG("SSL status: SSL_ERROR_WANT_ACCEPT");
				break;
		}

		// Check if the handshake (or re-handshake) has been done right now.
		if (this->handshakeDoneNow)
		{
			this->handshakeDoneNow = false;
			this->handshakeDone = true;

			// Stop the timer.
			this->timer->Stop();

			// Process the handshake just once (ignore if DTLS renegotiation).
			if (!was_handshake_done)
				ProcessHandshake();
		}
		// Check if the peer sent close alert or a fatal error happened.
		else if ((SSL_get_shutdown(this->ssl) & SSL_RECEIVED_SHUTDOWN) || err == SSL_ERROR_SSL || err == SSL_ERROR_SYSCALL)
		{
			if (this->state == DtlsState::CONNECTED)
			{
				MS_DEBUG("disconnected");

				Reset();

				// Set state and notify the listener.
				this->state = DtlsState::CLOSED;
				this->listener->onDtlsClosed(this);
			}
			else
			{
				MS_DEBUG("connection failed");

				Reset();

				// Set state and notify the listener.
				this->state = DtlsState::FAILED;
				this->listener->onDtlsFailed(this);
			}

			return false;
		}

		return true;
	}