blob: a92b40812ed9625a050e53826af4f1fda0106c0c [file] [log] [blame]
Austin Schuh52e5e3a2021-04-24 22:30:02 -07001#include "aos/network/rawrtc.h"
2
3extern "C" {
4#include <rawrtc.h>
5
6#include "external/com_github_rawrtc_rawrtc_common/include/rawrtcc/utils.h"
7}
8
9#include <functional>
10#include <string>
11
12#include "flatbuffers/flatbuffers.h"
13#include "glog/logging.h"
14
15namespace aos {
16namespace web_proxy {
17namespace {
18enum {
19 TRANSPORT_BUFFER_LENGTH = 1048576, // 1 MiB
20};
21}
22
23ScopedDataChannel::ScopedDataChannel() {}
24
25void ScopedDataChannel::Open(struct rawrtc_peer_connection *connection,
26 const std::string &label) {
27 label_ = label;
28 VLOG(1) << "(" << this << ") Opening " << label_;
29 struct rawrtc_data_channel_parameters *channel_parameters;
30 // Create data channel parameters
31 // TODO(austin): TYPE?
32 CHECK_RAWRTC(rawrtc_data_channel_parameters_create(
33 &channel_parameters, label.c_str(),
34 RAWRTC_DATA_CHANNEL_TYPE_RELIABLE_ORDERED, 0, NULL, false, 0));
35
36 // Create data channel
37 CHECK_RAWRTC(rawrtc_peer_connection_create_data_channel(
38 &data_channel_, connection, channel_parameters,
39 StaticDataChannelOpenHandler, StaticBufferedAmountLowHandler,
40 StaticDataChannelErrorHandler, StaticDataChannelCloseHandler,
41 StaticDataChannelMessageHandler, this));
42
43 // Un-reference data channel parameters
44 mem_deref(channel_parameters);
45}
46
47void ScopedDataChannel::Open(struct rawrtc_data_channel *const channel) {
48 struct rawrtc_data_channel_parameters *parameters;
49 enum rawrtc_code const ignore[] = {RAWRTC_CODE_NO_VALUE};
50 char *label = NULL;
51
52 // Get data channel label and protocol
53 CHECK_RAWRTC(rawrtc_data_channel_get_parameters(&parameters, channel));
54 CHECK_RAWRTC_IGNORE(
55 rawrtc_data_channel_parameters_get_label(&label, parameters), ignore);
56 if (label) {
57 label_ = label;
58 mem_deref(label);
59 }
60 mem_deref(parameters);
61
62 VLOG(1) << "(" << this << ") New data channel instance: " << label_;
63
64 mem_ref(channel);
65 data_channel_ = channel;
66
67 CHECK_RAWRTC(rawrtc_data_channel_set_arg(data_channel_, this));
68
69 CHECK_RAWRTC(rawrtc_data_channel_set_open_handler(
70 data_channel_, StaticDataChannelOpenHandler));
71
72 CHECK_RAWRTC(rawrtc_data_channel_set_buffered_amount_low_handler(
73 data_channel_, StaticBufferedAmountLowHandler));
74
75 CHECK_RAWRTC(rawrtc_data_channel_set_error_handler(
76 data_channel_, StaticDataChannelErrorHandler));
77
78 CHECK_RAWRTC(rawrtc_data_channel_set_close_handler(
79 data_channel_, StaticDataChannelCloseHandler));
80
81 CHECK_RAWRTC(rawrtc_data_channel_set_message_handler(
82 data_channel_, StaticDataChannelMessageHandler));
83}
84
85ScopedDataChannel::~ScopedDataChannel() {
86 CHECK(opened_);
87 CHECK(closed_);
88 CHECK(data_channel_ == nullptr)
89 << ": Destroying open data channel " << this << ".";
90}
91
92void ScopedDataChannel::StaticDataChannelOpenHandler(void *const arg) {
93 ScopedDataChannel *const client = reinterpret_cast<ScopedDataChannel *>(arg);
94 CHECK(!client->opened_);
95 CHECK(!client->closed_);
96 if (client->on_open_) client->on_open_();
97 client->opened_ = true;
98}
99
100void ScopedDataChannel::StaticBufferedAmountLowHandler(void *const arg) {
101 ScopedDataChannel *const client = reinterpret_cast<ScopedDataChannel *>(arg);
102 if (client->on_buffered_amount_low_) client->on_buffered_amount_low_();
103}
104
105void ScopedDataChannel::StaticDataChannelErrorHandler(void *const arg) {
106 ScopedDataChannel *const client = reinterpret_cast<ScopedDataChannel *>(arg);
107 if (client->on_error_) client->on_error_();
108}
109
110void ScopedDataChannel::StaticDataChannelCloseHandler(void *const arg) {
111 ScopedDataChannel *const client = reinterpret_cast<ScopedDataChannel *>(arg);
112 CHECK(client->opened_);
113 CHECK(!client->closed_);
114 // Close() assumes that this method will do the final cleanup. The destructor
115 // CHECKs that.
116 client->closed_ = true;
117 struct rawrtc_data_channel *data_channel = client->data_channel_;
118 client->data_channel_ = nullptr;
119 if (client->on_close_) {
120 // Take the function so we can call it without referencing client.
121 // This could destroy the client when the function is deleted by releasing
122 // any shared_ptrs.
123 std::function<void()> on_close = std::move(client->on_close_);
124 on_close();
125 }
126 mem_deref(data_channel);
127}
128
129void ScopedDataChannel::StaticDataChannelMessageHandler(
130 struct mbuf *const
131 buffer, // nullable (in case partial delivery has been requested)
132 enum rawrtc_data_channel_message_flag const flags, void *const arg) {
133 ScopedDataChannel *const client = reinterpret_cast<ScopedDataChannel *>(arg);
134 if (client->on_message_) client->on_message_(buffer, flags);
135}
136
137void ScopedDataChannel::Close() {
138 CHECK(opened_);
139 CHECK(!closed_);
140 CHECK_RAWRTC(rawrtc_data_channel_close(data_channel_));
141}
142
143void ScopedDataChannel::Send(const ::flatbuffers::DetachedBuffer &buffer) {
144 struct mbuf *mbuffer = mbuf_alloc(buffer.size());
145 mbuf_write_mem(mbuffer, buffer.data(), buffer.size());
146 mbuf_set_pos(mbuffer, 0);
147
148 Send(mbuffer);
149
150 mem_deref(mbuffer);
151}
152
153void ScopedDataChannel::Send(struct mbuf *buffer) {
154 // TODO(austin): Checking isn't right, handle errors more gracefully.
155 CHECK_RAWRTC(
156 rawrtc_data_channel_send(CHECK_NOTNULL(data_channel_), buffer, true));
157}
158
159uint64_t ScopedDataChannel::buffered_amount() {
160 return 0;
161
162 // TODO(austin): Not implemented yet...
163 uint64_t result;
164 CHECK_RAWRTC(rawrtc_data_channel_get_buffered_amount(
165 &result, CHECK_NOTNULL(data_channel_)));
166 return result;
167}
168
169RawRTCConnection::RawRTCConnection() {}
170
171void RawRTCConnection::Open() {
172 const char *const stun_google_com_urls[] = {"stun:stun.l.google.com:19302",
173 "stun:stun1.l.google.com:19302"};
174
175 struct rawrtc_peer_connection_configuration *configuration = nullptr;
176
177 CHECK_RAWRTC(rawrtc_peer_connection_configuration_create(
178 &configuration, RAWRTC_ICE_GATHER_POLICY_ALL));
179
180 // Add ICE servers to configuration
181 CHECK_RAWRTC(rawrtc_peer_connection_configuration_add_ice_server(
182 configuration, stun_google_com_urls, ARRAY_SIZE(stun_google_com_urls),
183 NULL, NULL, RAWRTC_ICE_CREDENTIAL_TYPE_NONE));
184
185 // Set the SCTP transport's buffer length
186 CHECK_RAWRTC(rawrtc_peer_connection_configuration_set_sctp_buffer_length(
187 configuration, TRANSPORT_BUFFER_LENGTH, TRANSPORT_BUFFER_LENGTH));
188
189 // Create peer connection
190 CHECK_RAWRTC(rawrtc_peer_connection_create(
191 &connection_, configuration, StaticNegotiationNeededHandler,
192 StaticLocalCandidateHandler,
193 StaticPeerConnectionLocalCandidateErrorHandler,
194 StaticSignalingStateChangeHandler, StaticIceTransportStateChangeHandler,
195 StaticIceGathererStateChangeHandler, StaticConnectionStateChangeHandler,
196 StaticDataChannelHandler, this));
197
198 mem_deref(configuration);
199}
200
201RawRTCConnection::~RawRTCConnection() {
202 CHECK_RAWRTC(rawrtc_peer_connection_close(connection_));
203 mem_deref(connection_);
204 connection_ = nullptr;
205}
206
207void RawRTCConnection::StaticNegotiationNeededHandler(void *const arg) {
208 RawRTCConnection *const client = reinterpret_cast<RawRTCConnection *>(arg);
209 if (client->on_negotiation_needed_) client->on_negotiation_needed_();
210}
211
212void RawRTCConnection::StaticLocalCandidateHandler(
213 struct rawrtc_peer_connection_ice_candidate *const candidate,
214 char const *const url, // read-only
215 void *const arg) {
216 RawRTCConnection *const client = reinterpret_cast<RawRTCConnection *>(arg);
217 if (client->on_local_candidate_) client->on_local_candidate_(candidate, url);
218}
219
220void RawRTCConnection::StaticPeerConnectionLocalCandidateErrorHandler(
221 struct rawrtc_peer_connection_ice_candidate *const candidate,
222 char const *const url, uint16_t const error_code,
223 char const *const error_text, void *const arg) {
224 RawRTCConnection *const client = reinterpret_cast<RawRTCConnection *>(arg);
225 LOG(ERROR) << "(" << client << ") ICE candidate error, URL: " << url
226 << ", reason: " << error_text;
227 if (client->on_peer_connection_local_candidate_error_)
228 client->on_peer_connection_local_candidate_error_(candidate, url,
229 error_code, error_text);
230}
231
232void RawRTCConnection::StaticSignalingStateChangeHandler(
233 const enum rawrtc_signaling_state state, void *const arg) {
234 RawRTCConnection *const client = reinterpret_cast<RawRTCConnection *>(arg);
235 VLOG(1) << "(" << client << ") Signaling state change: "
236 << rawrtc_signaling_state_to_name(state);
237 if (client->on_signaling_state_change_)
238 client->on_signaling_state_change_(state);
239}
240
241void RawRTCConnection::StaticIceTransportStateChangeHandler(
242 const enum rawrtc_ice_transport_state state, void *const arg) {
243 RawRTCConnection *const client = reinterpret_cast<RawRTCConnection *>(arg);
244 VLOG(1) << "(" << client << ") ICE transport state: "
245 << rawrtc_ice_transport_state_to_name(state);
246 if (client->on_ice_transport_state_change_)
247 client->on_ice_transport_state_change_(state);
248}
249
250void RawRTCConnection::StaticIceGathererStateChangeHandler(
251 const enum rawrtc_ice_gatherer_state state, void *const arg) {
252 RawRTCConnection *const client = reinterpret_cast<RawRTCConnection *>(arg);
253 VLOG(1) << "(" << client << ") ICE gatherer state: "
254 << rawrtc_ice_gatherer_state_to_name(state);
255 if (client->on_ice_gatherer_state_change_)
256 client->on_ice_gatherer_state_change_(state);
257}
258
259void RawRTCConnection::StaticConnectionStateChangeHandler(
260 const enum rawrtc_peer_connection_state state, // read-only
261 void *const arg) {
262 RawRTCConnection *const client = reinterpret_cast<RawRTCConnection *>(arg);
263 VLOG(1) << "(" << client << ") Peer connection state change: "
264 << rawrtc_peer_connection_state_to_name(state);
265 if (client->on_connection_state_change_)
266 client->on_connection_state_change_(state);
267}
268
269void RawRTCConnection::StaticDataChannelHandler(
270 struct rawrtc_data_channel
271 *const channel, // read-only, MUST be referenced when used
272 void *const arg) {
273 RawRTCConnection *const client = reinterpret_cast<RawRTCConnection *>(arg);
274 if (client->on_data_channel_) {
275 std::shared_ptr<ScopedDataChannel> new_channel =
276 std::make_shared<ScopedDataChannel>();
277 new_channel->Open(channel);
278 client->on_data_channel_(std::move(new_channel));
279 }
280}
281
282} // namespace web_proxy
283} // namespace aos