blob: c6d7336b5f3b33a4462073a7b134db87f6aab37c [file] [log] [blame]
Alex Perryb3b50792020-01-18 16:13:45 -08001#include "aos/network/web_proxy.h"
2#include "aos/network/web_proxy_generated.h"
3#include "api/create_peerconnection_factory.h"
4#include "glog/logging.h"
5
6namespace aos {
7namespace web_proxy {
8
9namespace {
10// Based on webrtc examples. In our controlled environment we expect setting sdp
11// to always succeed, and we can't do anything about a failure, so just ignore
12// everything.
13class DummySetSessionDescriptionObserver
14 : public webrtc::SetSessionDescriptionObserver {
15 public:
16 static DummySetSessionDescriptionObserver *Create() {
17 return new rtc::RefCountedObject<DummySetSessionDescriptionObserver>();
18 }
19 virtual void OnSuccess() {}
20 virtual void OnFailure(webrtc::RTCError error) {}
21};
22
23} // namespace
24
25WebsocketHandler::WebsocketHandler(::seasocks::Server *server)
26 : server_(server) {}
27
28void WebsocketHandler::onConnect(::seasocks::WebSocket *sock) {
29 std::unique_ptr<Connection> conn =
30 std::make_unique<Connection>(sock, server_);
31 connections_.insert({sock, std::move(conn)});
32}
33
34void WebsocketHandler::onData(::seasocks::WebSocket *sock, const uint8_t *data,
35 size_t size) {
36 connections_[sock]->HandleWebSocketData(data, size);
37}
38
39void WebsocketHandler::onDisconnect(::seasocks::WebSocket *sock) {
40 connections_.erase(sock);
41}
42
43Connection::Connection(::seasocks::WebSocket *sock, ::seasocks::Server *server)
44 : sock_(sock), server_(server) {}
45
46// Function called for web socket data. Parses the flatbuffer and handles it
47// appropriately.
48void Connection::HandleWebSocketData(const uint8_t *data, size_t size) {
49 const WebSocketMessage *message =
50 flatbuffers::GetRoot<WebSocketMessage>(data);
51 switch (message->payload_type()) {
52 case Payload::WebSocketSdp: {
53 const WebSocketSdp *offer = message->payload_as_WebSocketSdp();
54 if (offer->type() != SdpType::OFFER) {
55 LOG(WARNING) << "Got the wrong sdp type from client";
56 break;
57 }
58 const flatbuffers::String *sdp = offer->payload();
59 webrtc::SdpParseError error;
60 std::unique_ptr<webrtc::SessionDescriptionInterface> desc =
61 CreateSessionDescription(webrtc::SdpType::kOffer, sdp->str(), &error);
62 if (!desc) {
63 LOG(WARNING) << "Failed to parse sdp description: "
64 << error.description;
65 // TODO(alex): send a message back to browser for failure.
66 break;
67 }
68
69 // We can only start creating the PeerConnection once we have something to
70 // give it, so we wait until we get an offer before starting.
71 webrtc::PeerConnectionInterface::RTCConfiguration config;
72 config.sdp_semantics = webrtc::SdpSemantics::kUnifiedPlan;
73 config.enable_dtls_srtp = true;
74
75 std::unique_ptr<rtc::Thread> signaling_thread = rtc::Thread::Create();
76 signaling_thread->SetName("signaling_thread", nullptr);
77 signaling_thread->Start();
78
79 webrtc::PeerConnectionFactoryDependencies factory_deps;
80 factory_deps.signaling_thread = signaling_thread.release();
81 rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface> factory =
82 CreateModularPeerConnectionFactory(std::move(factory_deps));
83
84 peer_connection_ =
85 factory->CreatePeerConnection(config, nullptr, nullptr, this);
86
87 peer_connection_->SetRemoteDescription(
88 DummySetSessionDescriptionObserver::Create(), desc.release());
89
90 peer_connection_->CreateAnswer(
91 this, webrtc::PeerConnectionInterface::RTCOfferAnswerOptions());
92 break;
93 }
94 case Payload::WebSocketIce: {
95 const WebSocketIce *ice = message->payload_as_WebSocketIce();
96 std::string candidate = ice->candidate()->str();
97 std::string sdpMid = ice->sdpMid()->str();
98 int sdpMLineIndex = ice->sdpMLineIndex();
99 webrtc::SdpParseError error;
100 webrtc::IceCandidateInterface *ice_candidate =
101 webrtc::CreateIceCandidate(sdpMid, sdpMLineIndex, candidate, &error);
102 if (!ice_candidate) {
103 LOG(WARNING) << "Failed to parse ice candidate: " << error.description;
104 // TODO(alex): send a message back to browser for failure.
105 break;
106 }
107 peer_connection_->AddIceCandidate(ice_candidate);
108 break;
109 }
110 default: { break; }
111 }
112}
113
114void Connection::OnDataChannel(
115 rtc::scoped_refptr<webrtc::DataChannelInterface> channel) {
116 data_channel_ = channel;
117 data_channel_->RegisterObserver(this);
118}
119
120void Connection::OnIceCandidate(
121 const webrtc::IceCandidateInterface *candidate) {
122 flatbuffers::FlatBufferBuilder fbb(512);
123 std::string ice_string;
124 candidate->ToString(&ice_string);
125
126 flatbuffers::Offset<WebSocketIce> ice_fb = CreateWebSocketIceDirect(
127 fbb, ice_string.c_str(), candidate->sdp_mid().c_str(),
128 candidate->sdp_mline_index());
129 flatbuffers::Offset<WebSocketMessage> ice_message =
130 CreateWebSocketMessage(fbb, Payload::WebSocketIce, ice_fb.Union());
131 fbb.Finish(ice_message);
132
133 server_->execute(std::make_shared<UpdateData>(sock_, fbb.Release()));
134}
135
136// This is the callback for creating an sdp. We have to manually assign it
137// locally and send it to the client.
138void Connection::OnSuccess(webrtc::SessionDescriptionInterface *desc) {
139 peer_connection_->SetLocalDescription(
140 DummySetSessionDescriptionObserver::Create(), desc);
141 flatbuffers::FlatBufferBuilder fbb(512);
142 std::string answer_string;
143 desc->ToString(&answer_string);
144 flatbuffers::Offset<WebSocketSdp> sdp_fb =
145 CreateWebSocketSdpDirect(fbb, SdpType::ANSWER, answer_string.c_str());
146 flatbuffers::Offset<WebSocketMessage> answer_message =
147 CreateWebSocketMessage(fbb, Payload::WebSocketSdp, sdp_fb.Union());
148 fbb.Finish(answer_message);
149
150 server_->execute(std::make_shared<UpdateData>(sock_, fbb.Release()));
151}
152
153// Receive and respond to a DataChannel message. Temporarily acting as a
154// "PONG", but will change to handle "Connect" subscription messages.
155void Connection::OnMessage(const webrtc::DataBuffer &buffer) {
156 // This is technically disallowed by webrtc, But doesn't seem to cause major
157 // problems. At least for the small data tested manually. Send should be
158 // called from outside this call stack.
159 data_channel_->Send(buffer);
160}
161
162} // namespace web_proxy
163} // namespace aos