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]"); }
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; } }
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); } }
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); }
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"); }
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; }
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); }
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(); }
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). }
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"); }
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; } }
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); } }
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(); } }
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(); }
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"); }
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); } }
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); } }
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; }
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(); } }
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; } }
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); }
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(); }
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); }
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(); } }
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"); }
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; }
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; }
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; }