Skip to content

Commit

Permalink
ルート証明書の設定を統一してカスタマイズできるようにした
Browse files Browse the repository at this point in the history
shiguredo/momo#135 に合わせた
  • Loading branch information
melpon committed Dec 29, 2020
1 parent fece6fc commit 3a39801
Show file tree
Hide file tree
Showing 12 changed files with 762 additions and 184 deletions.
11 changes: 7 additions & 4 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -58,21 +58,24 @@ set_target_properties(SoraUnitySdk PROPERTIES CXX_STANDARD 14 C_STANDARD 99)

target_sources(SoraUnitySdk
PRIVATE
src/id_pointer.cpp
src/sora.cpp
src/sora_signaling.cpp
src/ssl_verifier.cpp
src/unity.cpp
src/sora.cpp
src/id_pointer.cpp
src/unity_camera_capturer.cpp
src/unity_context.cpp
src/unity_renderer.cpp
src/unity_camera_capturer.cpp
src/websocket.cpp
src/rtc/device_list.cpp
src/rtc/device_video_capturer.cpp
src/rtc/h264_format.cpp
src/rtc/native_buffer.cpp
src/rtc/peer_connection_observer.cpp
src/rtc/rtc_connection.cpp
src/rtc/rtc_manager.cpp
src/rtc/rtc_ssl_verifier.cpp
src/rtc/scalable_track_source.cpp
src/rtc/h264_format.cpp
)

string(SUBSTRING ${SORA_UNITY_SDK_COMMIT} 0 8 SORA_UNITY_SDK_COMMIT_SHORT)
Expand Down
13 changes: 11 additions & 2 deletions src/rtc/rtc_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

#include "peer_connection_observer.h"
#include "rtc_manager.h"
#include "rtc_ssl_verifier.h"
#include "scalable_track_source.h"

#if defined(SORA_UNITY_SDK_MACOS) || defined(SORA_UNITY_SDK_IOS)
Expand Down Expand Up @@ -287,9 +288,17 @@ std::shared_ptr<RTCConnection> RTCManager::createConnection(
rtc_config.sdp_semantics = webrtc::SdpSemantics::kUnifiedPlan;
std::unique_ptr<PeerConnectionObserver> observer(
new PeerConnectionObserver(sender, receiver_));
webrtc::PeerConnectionDependencies dependencies(observer.get());

// WebRTC の SSL 接続の検証は自前のルート証明書(rtc_base/ssl_roots.h)でやっていて、
// その中に Let's Encrypt の証明書が無いため、接続先によっては接続できないことがある。
//
// それを解消するために tls_cert_verifier を設定して自前で検証を行う。
dependencies.tls_cert_verifier = std::unique_ptr<rtc::SSLCertificateVerifier>(
new RTCSSLVerifier(config_.insecure));

rtc::scoped_refptr<webrtc::PeerConnectionInterface> connection =
factory_->CreatePeerConnection(rtc_config, nullptr, nullptr,
observer.get());
factory_->CreatePeerConnection(rtc_config, std::move(dependencies));
if (!connection) {
RTC_LOG(LS_ERROR) << __FUNCTION__ << ": CreatePeerConnection failed";
return nullptr;
Expand Down
2 changes: 2 additions & 0 deletions src/rtc/rtc_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ struct RTCManagerConfig {
// webrtc::DegradationPreference::MAINTAIN_FRAMERATE;
webrtc::DegradationPreference priority =
webrtc::DegradationPreference::BALANCED;

bool insecure = false;
};

class RTCManager {
Expand Down
21 changes: 21 additions & 0 deletions src/rtc/rtc_ssl_verifier.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#include "rtc_ssl_verifier.h"

// WebRTC
#include <rtc_base/openssl_certificate.h>

#include "../ssl_verifier.h"

namespace sora {

RTCSSLVerifier::RTCSSLVerifier(bool insecure) : insecure_(insecure) {}

bool RTCSSLVerifier::Verify(const rtc::SSLCertificate& certificate) {
// insecure の場合は証明書をチェックしない
if (insecure_) {
return true;
}
return SSLVerifier::VerifyX509(
static_cast<const rtc::OpenSSLCertificate&>(certificate).x509());
}

}
20 changes: 20 additions & 0 deletions src/rtc/rtc_ssl_verifier.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#ifndef SORA_RTC_SSL_VERIFIER
#define SORA_RTC_SSL_VERIFIER

// WebRTC
#include <rtc_base/ssl_certificate.h>

namespace sora {

class RTCSSLVerifier : public rtc::SSLCertificateVerifier {
public:
RTCSSLVerifier(bool insecure);
bool Verify(const rtc::SSLCertificate& certificate) override;

private:
bool insecure_;
};

} // namespace sora

#endif
185 changes: 30 additions & 155 deletions src/sora_signaling.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,42 +70,11 @@ SoraSignaling::SoraSignaling(boost::asio::io_context& ioc,
SoraSignalingConfig config,
std::function<void(std::string)> on_notify)
: ioc_(ioc),
resolver_(ioc),
manager_(manager),
config_(config),
on_notify_(std::move(on_notify)) {}

bool SoraSignaling::Init() {
if (!URLParts::parse(config_.signaling_url, parts_)) {
RTC_LOG(LS_ERROR) << "Invalid Signaling URL: " << config_.signaling_url;
return false;
}

if (parts_.scheme != "wss") {
RTC_LOG(LS_ERROR) << "Signaling URL Scheme is not secure web socket (wss): "
<< config_.signaling_url;
return false;
}

boost::asio::ssl::context ssl_ctx(boost::asio::ssl::context::tlsv12);
ssl_ctx.set_default_verify_paths();
ssl_ctx.set_options(boost::asio::ssl::context::default_workarounds |
boost::asio::ssl::context::no_sslv2 |
boost::asio::ssl::context::no_sslv3 |
boost::asio::ssl::context::single_dh_use);

wss_.reset(new ssl_websocket_t(ioc_, ssl_ctx));
wss_->write_buffer_bytes(8192);

// SNI の設定を行う
if (!SSL_set_tlsext_host_name(wss_->next_layer().native_handle(),
parts_.host.c_str())) {
boost::system::error_code ec{static_cast<int>(::ERR_get_error()),
boost::asio::error::get_ssl_category()};
RTC_LOG(LS_ERROR) << "Failed SSL_set_tlsext_host_name: ec=" << ec;
return false;
}

return true;
}

Expand All @@ -128,64 +97,29 @@ bool SoraSignaling::Connect() {
port = parts_.port;
}

RTC_LOG(LS_INFO) << "Start to resolve DNS: host=" << parts_.host
<< " port=" << port;

// DNS ルックアップ
resolver_.async_resolve(parts_.host, port,
boost::beast::bind_front_handler(
&SoraSignaling::OnResolve, shared_from_this()));

return true;
}
RTC_LOG(LS_INFO) << "Connect to " << parts_.host;

void SoraSignaling::OnResolve(
boost::system::error_code ec,
boost::asio::ip::tcp::resolver::results_type results) {
RTC_LOG(LS_INFO) << __FUNCTION__;

if (ec) {
RTC_LOG(LS_ERROR) << "Failed to resolve DNS: " << ec;
return;
URLParts parts;
if (!URLParts::Parse(config_.signaling_url, parts)) {
RTC_LOG(LS_ERROR) << "Invalid Signaling URL: " << config_.signaling_url;
return false;
}

// DNS ルックアップで得られたエンドポイントに対して接続する
boost::asio::async_connect(
wss_->next_layer().next_layer(), results.begin(), results.end(),
std::bind(&SoraSignaling::OnSSLConnect, shared_from_this(),
std::placeholders::_1));
}

void SoraSignaling::OnSSLConnect(boost::system::error_code ec) {
RTC_LOG(LS_INFO) << __FUNCTION__;

if (ec) {
RTC_LOG(LS_ERROR) << "Failed to Connect: " << ec;
return;
if (parts.scheme == "ws") {
ws_.reset(new Websocket(ioc_));
} else if (parts.scheme == "wss") {
ws_.reset(new Websocket(Websocket::ssl_tag(), ioc_, config_.insecure));
} else {
return false;
}

// SSL のハンドシェイク
wss_->next_layer().async_handshake(
boost::asio::ssl::stream_base::client,
boost::beast::bind_front_handler(&SoraSignaling::OnSSLHandshake,
shared_from_this()));
}

void SoraSignaling::OnSSLHandshake(boost::system::error_code ec) {
RTC_LOG(LS_INFO) << __FUNCTION__;
ws_->Connect(config_.signaling_url,
std::bind(&SoraSignaling::OnConnect, shared_from_this(),
std::placeholders::_1));

if (ec) {
RTC_LOG(LS_ERROR) << "Failed SSL handshake: " << ec;
return;
}

// Websocket のハンドシェイク
wss_->async_handshake(parts_.host, parts_.path_query_fragment,
boost::beast::bind_front_handler(
&SoraSignaling::OnHandshake, shared_from_this()));
return true;
}

void SoraSignaling::OnHandshake(boost::system::error_code ec) {
void SoraSignaling::OnConnect(boost::system::error_code ec) {
RTC_LOG(LS_INFO) << __FUNCTION__;

if (ec) {
Expand Down Expand Up @@ -238,18 +172,18 @@ void SoraSignaling::DoSendConnect() {
json_message["audio"]["bit_rate"] = config_.audio_bitrate;
}

SendText(json_message.dump());
ws_->WriteText(json_message.dump());
}
void SoraSignaling::DoSendPong() {
json json_message = {{"type", "pong"}};
SendText(json_message.dump());
ws_->WriteText(json_message.dump());
}
void SoraSignaling::DoSendPong(
const rtc::scoped_refptr<const webrtc::RTCStatsReport>& report) {
std::string stats = report->ToJson();
json json_message = {{"type", "pong"}, {"stats", stats}};
std::string str = R"({"type":"pong","stats":)" + stats + "}";
SendText(std::move(str));
ws_->WriteText(std::move(str));
}

void SoraSignaling::CreatePeerFromConfig(json jconfig) {
Expand All @@ -276,9 +210,8 @@ void SoraSignaling::CreatePeerFromConfig(json jconfig) {
}

void SoraSignaling::Close() {
wss_->async_close(boost::beast::websocket::close_code::normal,
boost::beast::bind_front_handler(&SoraSignaling::OnClose,
shared_from_this()));
ws_->Close(std::bind(&SoraSignaling::OnClose, shared_from_this(),
std::placeholders::_1));
}

void SoraSignaling::OnClose(boost::system::error_code ec) {
Expand All @@ -289,13 +222,14 @@ void SoraSignaling::OnClose(boost::system::error_code ec) {
}

void SoraSignaling::DoRead() {
wss_->async_read(read_buffer_,
boost::beast::bind_front_handler(&SoraSignaling::onRead,
shared_from_this()));
ws_->Read(std::bind(&SoraSignaling::OnRead, shared_from_this(),
std::placeholders::_1, std::placeholders::_2,
std::placeholders::_3));
}

void SoraSignaling::onRead(boost::system::error_code ec,
std::size_t bytes_transferred) {
void SoraSignaling::OnRead(boost::system::error_code ec,
std::size_t bytes_transferred,
std::string text) {
boost::ignore_unused(bytes_transferred);

if (ec == boost::asio::error::operation_aborted) {
Expand All @@ -307,15 +241,11 @@ void SoraSignaling::onRead(boost::system::error_code ec,
return;
}

const auto text = boost::beast::buffers_to_string(read_buffer_.data());
read_buffer_.consume(read_buffer_.size());

RTC_LOG(LS_INFO) << __FUNCTION__ << ": text=" << text;

auto json_message = json::parse(text);
const std::string type = json_message["type"];
if (type == "offer") {
answer_sent_ = false;
CreatePeerFromConfig(json_message["config"]);
const std::string sdp = json_message["sdp"];
connection_->SetOffer(sdp, [this, json_message]() {
Expand All @@ -324,7 +254,7 @@ void SoraSignaling::onRead(boost::system::error_code ec,
std::string sdp;
desc->ToString(&sdp);
json json_message = {{"type", "answer"}, {"sdp", sdp}};
SendText(json_message.dump());
ws_->WriteText(json_message.dump());
});
});
} else if (type == "update") {
Expand All @@ -335,7 +265,7 @@ void SoraSignaling::onRead(boost::system::error_code ec,
std::string sdp;
desc->ToString(&sdp);
json json_message = {{"type", "update"}, {"sdp", sdp}};
SendText(json_message.dump());
ws_->WriteText(json_message.dump());
});
});
} else if (type == "notify") {
Expand Down Expand Up @@ -363,61 +293,6 @@ void SoraSignaling::onRead(boost::system::error_code ec,
DoRead();
}

void SoraSignaling::SendText(std::string text) {
RTC_LOG(LS_INFO) << __FUNCTION__;

boost::asio::post(boost::beast::bind_front_handler(
&SoraSignaling::DoSendText, shared_from_this(), std::move(text)));
}

void SoraSignaling::DoSendText(std::string text) {
RTC_LOG(LS_INFO) << __FUNCTION__ << ": " << text;

bool empty = write_buffer_.empty();
boost::beast::flat_buffer buffer;

const auto n = boost::asio::buffer_copy(buffer.prepare(text.size()),
boost::asio::buffer(text));
buffer.commit(n);

write_buffer_.push_back(std::move(buffer));

if (empty) {
DoWrite();
}
}

void SoraSignaling::DoWrite() {
RTC_LOG(LS_INFO) << __FUNCTION__;

auto& buffer = write_buffer_.front();

wss_->text(true);
wss_->async_write(buffer.data(),
boost::beast::bind_front_handler(&SoraSignaling::OnWrite,
shared_from_this()));
}

void SoraSignaling::OnWrite(boost::system::error_code ec,
std::size_t bytes_transferred) {
RTC_LOG(LS_INFO) << __FUNCTION__;

if (ec == boost::asio::error::operation_aborted) {
return;
}

if (ec) {
RTC_LOG(LS_ERROR) << "Failed to write: ec=" << ec;
return;
}

write_buffer_.erase(write_buffer_.begin());

if (!write_buffer_.empty()) {
DoWrite();
}
}

// WebRTC からのコールバック
// これらは別スレッドからやってくるので取り扱い注意
void SoraSignaling::OnIceConnectionStateChange(
Expand All @@ -431,7 +306,7 @@ void SoraSignaling::OnIceCandidate(const std::string sdp_mid,
const int sdp_mlineindex,
const std::string sdp) {
json json_message = {{"type", "candidate"}, {"candidate", sdp}};
SendText(json_message.dump());
ws_->WriteText(json_message.dump());
}
void SoraSignaling::DoIceConnectionStateChange(
webrtc::PeerConnectionInterface::IceConnectionState new_state) {
Expand Down
Loading

0 comments on commit 3a39801

Please # to comment.