blob: 48d5bb65456aae945d378f6317fe92bc19228b55 [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:361/*
Donald E Curtisa8736442015-08-05 22:48:132 * Copyright 2012 The WebRTC Project Authors. All rights reserved.
henrike@webrtc.org28e20752013-07-10 00:45:363 *
Donald E Curtisa8736442015-08-05 22:48:134 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
henrike@webrtc.org28e20752013-07-10 00:45:369 */
10
Mirko Bonadei92ea95e2017-09-15 04:47:3111#include "examples/peerconnection/client/peer_connection_client.h"
henrike@webrtc.org28e20752013-07-10 00:45:3612
Danil Chapovalovb9201b02022-08-17 15:12:2913#include "api/units/time_delta.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3114#include "examples/peerconnection/client/defaults.h"
Harald Alvestrand60362c12023-10-10 11:30:1815#include "rtc_base/async_dns_resolver.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3116#include "rtc_base/checks.h"
17#include "rtc_base/logging.h"
Steve Anton10542f22019-01-11 17:11:0018#include "rtc_base/net_helpers.h"
henrike@webrtc.org28e20752013-07-10 00:45:3619
henrike@webrtc.org28e20752013-07-10 00:45:3620namespace {
21
22// This is our magical hangup signal.
Danil Chapovalovb9201b02022-08-17 15:12:2923constexpr char kByeMessage[] = "BYE";
henrike@webrtc.org28e20752013-07-10 00:45:3624// Delay between server connection retries, in milliseconds
Danil Chapovalovb9201b02022-08-17 15:12:2925constexpr webrtc::TimeDelta kReconnectDelay = webrtc::TimeDelta::Seconds(2);
henrike@webrtc.org28e20752013-07-10 00:45:3626
Niels Möllerd0b88792021-08-12 08:32:3027rtc::Socket* CreateClientSocket(int family) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:5228 rtc::Thread* thread = rtc::Thread::Current();
nisseede5da42017-01-12 13:15:3629 RTC_DCHECK(thread != NULL);
Niels Möllerd0b88792021-08-12 08:32:3030 return thread->socketserver()->CreateSocket(family, SOCK_STREAM);
henrike@webrtc.org28e20752013-07-10 00:45:3631}
32
jbauch70625e52015-12-09 22:18:1433} // namespace
henrike@webrtc.org28e20752013-07-10 00:45:3634
35PeerConnectionClient::PeerConnectionClient()
Harald Alvestrand60362c12023-10-10 11:30:1836 : callback_(NULL), resolver_(nullptr), state_(NOT_CONNECTED), my_id_(-1) {}
henrike@webrtc.org28e20752013-07-10 00:45:3637
Danil Chapovalovb9201b02022-08-17 15:12:2938PeerConnectionClient::~PeerConnectionClient() = default;
henrike@webrtc.org28e20752013-07-10 00:45:3639
40void PeerConnectionClient::InitSocketSignals() {
nisseede5da42017-01-12 13:15:3641 RTC_DCHECK(control_socket_.get() != NULL);
42 RTC_DCHECK(hanging_get_.get() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:3643 control_socket_->SignalCloseEvent.connect(this,
Yves Gerey665174f2018-06-19 13:03:0544 &PeerConnectionClient::OnClose);
45 hanging_get_->SignalCloseEvent.connect(this, &PeerConnectionClient::OnClose);
henrike@webrtc.org28e20752013-07-10 00:45:3646 control_socket_->SignalConnectEvent.connect(this,
Yves Gerey665174f2018-06-19 13:03:0547 &PeerConnectionClient::OnConnect);
48 hanging_get_->SignalConnectEvent.connect(
49 this, &PeerConnectionClient::OnHangingGetConnect);
50 control_socket_->SignalReadEvent.connect(this, &PeerConnectionClient::OnRead);
51 hanging_get_->SignalReadEvent.connect(
52 this, &PeerConnectionClient::OnHangingGetRead);
henrike@webrtc.org28e20752013-07-10 00:45:3653}
54
55int PeerConnectionClient::id() const {
56 return my_id_;
57}
58
59bool PeerConnectionClient::is_connected() const {
60 return my_id_ != -1;
61}
62
63const Peers& PeerConnectionClient::peers() const {
64 return peers_;
65}
66
67void PeerConnectionClient::RegisterObserver(
68 PeerConnectionClientObserver* callback) {
nisseede5da42017-01-12 13:15:3669 RTC_DCHECK(!callback_);
henrike@webrtc.org28e20752013-07-10 00:45:3670 callback_ = callback;
71}
72
Yves Gerey665174f2018-06-19 13:03:0573void PeerConnectionClient::Connect(const std::string& server,
74 int port,
henrike@webrtc.org28e20752013-07-10 00:45:3675 const std::string& client_name) {
nisseede5da42017-01-12 13:15:3676 RTC_DCHECK(!server.empty());
77 RTC_DCHECK(!client_name.empty());
henrike@webrtc.org28e20752013-07-10 00:45:3678
79 if (state_ != NOT_CONNECTED) {
Harald Alvestrandef5b21e2021-11-27 21:31:0880 RTC_LOG(LS_WARNING)
henrike@webrtc.org28e20752013-07-10 00:45:3681 << "The client must not be connected before you can call Connect()";
82 callback_->OnServerConnectionFailure();
83 return;
84 }
85
86 if (server.empty() || client_name.empty()) {
87 callback_->OnServerConnectionFailure();
88 return;
89 }
90
91 if (port <= 0)
92 port = kDefaultServerPort;
93
94 server_address_.SetIP(server);
95 server_address_.SetPort(port);
96 client_name_ = client_name;
97
tfarina20a34612015-11-03 00:20:2298 if (server_address_.IsUnresolvedIP()) {
Harald Alvestrand60362c12023-10-10 11:30:1899 RTC_DCHECK_NE(state_, RESOLVING);
100 RTC_DCHECK(!resolver_);
henrike@webrtc.org28e20752013-07-10 00:45:36101 state_ = RESOLVING;
Harald Alvestrand60362c12023-10-10 11:30:18102 resolver_ = std::make_unique<webrtc::AsyncDnsResolver>();
103 resolver_->Start(server_address_,
104 [this] { OnResolveResult(resolver_->result()); });
henrike@webrtc.org28e20752013-07-10 00:45:36105 } else {
106 DoConnect();
107 }
108}
109
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52110void PeerConnectionClient::OnResolveResult(
Harald Alvestrand60362c12023-10-10 11:30:18111 const webrtc::AsyncDnsResolverResult& result) {
112 if (result.GetError() != 0) {
henrike@webrtc.org28e20752013-07-10 00:45:36113 callback_->OnServerConnectionFailure();
Harald Alvestrand60362c12023-10-10 11:30:18114 resolver_.reset();
henrike@webrtc.org28e20752013-07-10 00:45:36115 state_ = NOT_CONNECTED;
Harald Alvestrand60362c12023-10-10 11:30:18116 return;
henrike@webrtc.org28e20752013-07-10 00:45:36117 }
Harald Alvestrand60362c12023-10-10 11:30:18118 if (!result.GetResolvedAddress(AF_INET, &server_address_)) {
119 callback_->OnServerConnectionFailure();
120 resolver_.reset();
121 state_ = NOT_CONNECTED;
122 return;
123 }
124 DoConnect();
henrike@webrtc.org28e20752013-07-10 00:45:36125}
126
127void PeerConnectionClient::DoConnect() {
128 control_socket_.reset(CreateClientSocket(server_address_.ipaddr().family()));
129 hanging_get_.reset(CreateClientSocket(server_address_.ipaddr().family()));
130 InitSocketSignals();
131 char buffer[1024];
Niels Mölleraba06332018-10-16 13:14:15132 snprintf(buffer, sizeof(buffer), "GET /sign_in?%s HTTP/1.0\r\n\r\n",
Yves Gerey665174f2018-06-19 13:03:05133 client_name_.c_str());
henrike@webrtc.org28e20752013-07-10 00:45:36134 onconnect_data_ = buffer;
135
136 bool ret = ConnectControlSocket();
137 if (ret)
138 state_ = SIGNING_IN;
139 if (!ret) {
140 callback_->OnServerConnectionFailure();
141 }
142}
143
144bool PeerConnectionClient::SendToPeer(int peer_id, const std::string& message) {
145 if (state_ != CONNECTED)
146 return false;
147
nisseede5da42017-01-12 13:15:36148 RTC_DCHECK(is_connected());
149 RTC_DCHECK(control_socket_->GetState() == rtc::Socket::CS_CLOSED);
henrike@webrtc.org28e20752013-07-10 00:45:36150 if (!is_connected() || peer_id == -1)
151 return false;
152
153 char headers[1024];
Niels Mölleraba06332018-10-16 13:14:15154 snprintf(headers, sizeof(headers),
Yves Gerey665174f2018-06-19 13:03:05155 "POST /message?peer_id=%i&to=%i HTTP/1.0\r\n"
Niels Mölleraba06332018-10-16 13:14:15156 "Content-Length: %zu\r\n"
Yves Gerey665174f2018-06-19 13:03:05157 "Content-Type: text/plain\r\n"
158 "\r\n",
159 my_id_, peer_id, message.length());
henrike@webrtc.org28e20752013-07-10 00:45:36160 onconnect_data_ = headers;
161 onconnect_data_ += message;
162 return ConnectControlSocket();
163}
164
165bool PeerConnectionClient::SendHangUp(int peer_id) {
166 return SendToPeer(peer_id, kByeMessage);
167}
168
169bool PeerConnectionClient::IsSendingMessage() {
170 return state_ == CONNECTED &&
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52171 control_socket_->GetState() != rtc::Socket::CS_CLOSED;
henrike@webrtc.org28e20752013-07-10 00:45:36172}
173
174bool PeerConnectionClient::SignOut() {
175 if (state_ == NOT_CONNECTED || state_ == SIGNING_OUT)
176 return true;
177
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52178 if (hanging_get_->GetState() != rtc::Socket::CS_CLOSED)
henrike@webrtc.org28e20752013-07-10 00:45:36179 hanging_get_->Close();
180
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52181 if (control_socket_->GetState() == rtc::Socket::CS_CLOSED) {
henrike@webrtc.org28e20752013-07-10 00:45:36182 state_ = SIGNING_OUT;
183
184 if (my_id_ != -1) {
185 char buffer[1024];
Niels Mölleraba06332018-10-16 13:14:15186 snprintf(buffer, sizeof(buffer),
Yves Gerey665174f2018-06-19 13:03:05187 "GET /sign_out?peer_id=%i HTTP/1.0\r\n\r\n", my_id_);
henrike@webrtc.org28e20752013-07-10 00:45:36188 onconnect_data_ = buffer;
189 return ConnectControlSocket();
190 } else {
191 // Can occur if the app is closed before we finish connecting.
192 return true;
193 }
194 } else {
195 state_ = SIGNING_OUT_WAITING;
196 }
197
198 return true;
199}
200
201void PeerConnectionClient::Close() {
202 control_socket_->Close();
203 hanging_get_->Close();
204 onconnect_data_.clear();
205 peers_.clear();
Harald Alvestrand60362c12023-10-10 11:30:18206 resolver_.reset();
henrike@webrtc.org28e20752013-07-10 00:45:36207 my_id_ = -1;
208 state_ = NOT_CONNECTED;
209}
210
211bool PeerConnectionClient::ConnectControlSocket() {
nisseede5da42017-01-12 13:15:36212 RTC_DCHECK(control_socket_->GetState() == rtc::Socket::CS_CLOSED);
henrike@webrtc.org28e20752013-07-10 00:45:36213 int err = control_socket_->Connect(server_address_);
214 if (err == SOCKET_ERROR) {
215 Close();
216 return false;
217 }
218 return true;
219}
220
Niels Möllerd0b88792021-08-12 08:32:30221void PeerConnectionClient::OnConnect(rtc::Socket* socket) {
nisseede5da42017-01-12 13:15:36222 RTC_DCHECK(!onconnect_data_.empty());
henrike@webrtc.org28e20752013-07-10 00:45:36223 size_t sent = socket->Send(onconnect_data_.c_str(), onconnect_data_.length());
nisseede5da42017-01-12 13:15:36224 RTC_DCHECK(sent == onconnect_data_.length());
henrike@webrtc.org28e20752013-07-10 00:45:36225 onconnect_data_.clear();
226}
227
Niels Möllerd0b88792021-08-12 08:32:30228void PeerConnectionClient::OnHangingGetConnect(rtc::Socket* socket) {
henrike@webrtc.org28e20752013-07-10 00:45:36229 char buffer[1024];
Niels Mölleraba06332018-10-16 13:14:15230 snprintf(buffer, sizeof(buffer), "GET /wait?peer_id=%i HTTP/1.0\r\n\r\n",
Yves Gerey665174f2018-06-19 13:03:05231 my_id_);
henrike@webrtc.org28654cb2013-07-22 21:07:49232 int len = static_cast<int>(strlen(buffer));
henrike@webrtc.org28e20752013-07-10 00:45:36233 int sent = socket->Send(buffer, len);
nisseede5da42017-01-12 13:15:36234 RTC_DCHECK(sent == len);
henrike@webrtc.org28e20752013-07-10 00:45:36235}
236
237void PeerConnectionClient::OnMessageFromPeer(int peer_id,
238 const std::string& message) {
239 if (message.length() == (sizeof(kByeMessage) - 1) &&
240 message.compare(kByeMessage) == 0) {
241 callback_->OnPeerDisconnected(peer_id);
242 } else {
243 callback_->OnMessageFromPeer(peer_id, message);
244 }
245}
246
247bool PeerConnectionClient::GetHeaderValue(const std::string& data,
248 size_t eoh,
249 const char* header_pattern,
250 size_t* value) {
nisseede5da42017-01-12 13:15:36251 RTC_DCHECK(value != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36252 size_t found = data.find(header_pattern);
253 if (found != std::string::npos && found < eoh) {
254 *value = atoi(&data[found + strlen(header_pattern)]);
255 return true;
256 }
257 return false;
258}
259
Yves Gerey665174f2018-06-19 13:03:05260bool PeerConnectionClient::GetHeaderValue(const std::string& data,
261 size_t eoh,
henrike@webrtc.org28e20752013-07-10 00:45:36262 const char* header_pattern,
263 std::string* value) {
nisseede5da42017-01-12 13:15:36264 RTC_DCHECK(value != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36265 size_t found = data.find(header_pattern);
266 if (found != std::string::npos && found < eoh) {
267 size_t begin = found + strlen(header_pattern);
268 size_t end = data.find("\r\n", begin);
269 if (end == std::string::npos)
270 end = eoh;
271 value->assign(data.substr(begin, end - begin));
272 return true;
273 }
274 return false;
275}
276
Niels Möllerd0b88792021-08-12 08:32:30277bool PeerConnectionClient::ReadIntoBuffer(rtc::Socket* socket,
henrike@webrtc.org28e20752013-07-10 00:45:36278 std::string* data,
279 size_t* content_length) {
280 char buffer[0xffff];
281 do {
Stefan Holmer9131efd2016-05-23 16:19:26282 int bytes = socket->Recv(buffer, sizeof(buffer), nullptr);
henrike@webrtc.org28e20752013-07-10 00:45:36283 if (bytes <= 0)
284 break;
285 data->append(buffer, bytes);
286 } while (true);
287
288 bool ret = false;
289 size_t i = data->find("\r\n\r\n");
290 if (i != std::string::npos) {
Harald Alvestrand97597c02021-11-04 12:01:23291 RTC_LOG(LS_INFO) << "Headers received";
henrike@webrtc.org28e20752013-07-10 00:45:36292 if (GetHeaderValue(*data, i, "\r\nContent-Length: ", content_length)) {
293 size_t total_response_size = (i + 4) + *content_length;
294 if (data->length() >= total_response_size) {
295 ret = true;
296 std::string should_close;
297 const char kConnection[] = "\r\nConnection: ";
298 if (GetHeaderValue(*data, i, kConnection, &should_close) &&
299 should_close.compare("close") == 0) {
300 socket->Close();
301 // Since we closed the socket, there was no notification delivered
302 // to us. Compensate by letting ourselves know.
303 OnClose(socket, 0);
304 }
305 } else {
306 // We haven't received everything. Just continue to accept data.
307 }
308 } else {
Mirko Bonadei675513b2017-11-09 10:09:25309 RTC_LOG(LS_ERROR) << "No content length field specified by the server.";
henrike@webrtc.org28e20752013-07-10 00:45:36310 }
311 }
312 return ret;
313}
314
Niels Möllerd0b88792021-08-12 08:32:30315void PeerConnectionClient::OnRead(rtc::Socket* socket) {
henrike@webrtc.org28e20752013-07-10 00:45:36316 size_t content_length = 0;
317 if (ReadIntoBuffer(socket, &control_data_, &content_length)) {
318 size_t peer_id = 0, eoh = 0;
Yves Gerey665174f2018-06-19 13:03:05319 bool ok =
320 ParseServerResponse(control_data_, content_length, &peer_id, &eoh);
henrike@webrtc.org28e20752013-07-10 00:45:36321 if (ok) {
322 if (my_id_ == -1) {
323 // First response. Let's store our server assigned ID.
nisseede5da42017-01-12 13:15:36324 RTC_DCHECK(state_ == SIGNING_IN);
henrike@webrtc.org28654cb2013-07-22 21:07:49325 my_id_ = static_cast<int>(peer_id);
nisseede5da42017-01-12 13:15:36326 RTC_DCHECK(my_id_ != -1);
henrike@webrtc.org28e20752013-07-10 00:45:36327
328 // The body of the response will be a list of already connected peers.
329 if (content_length) {
330 size_t pos = eoh + 4;
331 while (pos < control_data_.size()) {
332 size_t eol = control_data_.find('\n', pos);
333 if (eol == std::string::npos)
334 break;
335 int id = 0;
336 std::string name;
337 bool connected;
338 if (ParseEntry(control_data_.substr(pos, eol - pos), &name, &id,
Yves Gerey665174f2018-06-19 13:03:05339 &connected) &&
340 id != my_id_) {
henrike@webrtc.org28e20752013-07-10 00:45:36341 peers_[id] = name;
342 callback_->OnPeerConnected(id, name);
343 }
344 pos = eol + 1;
345 }
346 }
nisseede5da42017-01-12 13:15:36347 RTC_DCHECK(is_connected());
henrike@webrtc.org28e20752013-07-10 00:45:36348 callback_->OnSignedIn();
349 } else if (state_ == SIGNING_OUT) {
350 Close();
351 callback_->OnDisconnected();
352 } else if (state_ == SIGNING_OUT_WAITING) {
353 SignOut();
354 }
355 }
356
357 control_data_.clear();
358
359 if (state_ == SIGNING_IN) {
nisseede5da42017-01-12 13:15:36360 RTC_DCHECK(hanging_get_->GetState() == rtc::Socket::CS_CLOSED);
henrike@webrtc.org28e20752013-07-10 00:45:36361 state_ = CONNECTED;
362 hanging_get_->Connect(server_address_);
363 }
364 }
365}
366
Niels Möllerd0b88792021-08-12 08:32:30367void PeerConnectionClient::OnHangingGetRead(rtc::Socket* socket) {
Harald Alvestrand97597c02021-11-04 12:01:23368 RTC_LOG(LS_INFO) << __FUNCTION__;
henrike@webrtc.org28e20752013-07-10 00:45:36369 size_t content_length = 0;
370 if (ReadIntoBuffer(socket, &notification_data_, &content_length)) {
371 size_t peer_id = 0, eoh = 0;
Yves Gerey665174f2018-06-19 13:03:05372 bool ok =
373 ParseServerResponse(notification_data_, content_length, &peer_id, &eoh);
henrike@webrtc.org28e20752013-07-10 00:45:36374
375 if (ok) {
376 // Store the position where the body begins.
377 size_t pos = eoh + 4;
378
379 if (my_id_ == static_cast<int>(peer_id)) {
380 // A notification about a new member or a member that just
381 // disconnected.
382 int id = 0;
383 std::string name;
384 bool connected = false;
385 if (ParseEntry(notification_data_.substr(pos), &name, &id,
386 &connected)) {
387 if (connected) {
388 peers_[id] = name;
389 callback_->OnPeerConnected(id, name);
390 } else {
391 peers_.erase(id);
392 callback_->OnPeerDisconnected(id);
393 }
394 }
395 } else {
henrike@webrtc.org28654cb2013-07-22 21:07:49396 OnMessageFromPeer(static_cast<int>(peer_id),
397 notification_data_.substr(pos));
henrike@webrtc.org28e20752013-07-10 00:45:36398 }
399 }
400
401 notification_data_.clear();
402 }
403
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52404 if (hanging_get_->GetState() == rtc::Socket::CS_CLOSED &&
henrike@webrtc.org28e20752013-07-10 00:45:36405 state_ == CONNECTED) {
406 hanging_get_->Connect(server_address_);
407 }
408}
409
410bool PeerConnectionClient::ParseEntry(const std::string& entry,
411 std::string* name,
412 int* id,
413 bool* connected) {
nisseede5da42017-01-12 13:15:36414 RTC_DCHECK(name != NULL);
415 RTC_DCHECK(id != NULL);
416 RTC_DCHECK(connected != NULL);
417 RTC_DCHECK(!entry.empty());
henrike@webrtc.org28e20752013-07-10 00:45:36418
419 *connected = false;
420 size_t separator = entry.find(',');
421 if (separator != std::string::npos) {
422 *id = atoi(&entry[separator + 1]);
423 name->assign(entry.substr(0, separator));
424 separator = entry.find(',', separator + 1);
425 if (separator != std::string::npos) {
426 *connected = atoi(&entry[separator + 1]) ? true : false;
427 }
428 }
429 return !name->empty();
430}
431
432int PeerConnectionClient::GetResponseStatus(const std::string& response) {
433 int status = -1;
434 size_t pos = response.find(' ');
435 if (pos != std::string::npos)
436 status = atoi(&response[pos + 1]);
437 return status;
438}
439
440bool PeerConnectionClient::ParseServerResponse(const std::string& response,
441 size_t content_length,
442 size_t* peer_id,
443 size_t* eoh) {
444 int status = GetResponseStatus(response.c_str());
445 if (status != 200) {
Mirko Bonadei675513b2017-11-09 10:09:25446 RTC_LOG(LS_ERROR) << "Received error from server";
henrike@webrtc.org28e20752013-07-10 00:45:36447 Close();
448 callback_->OnDisconnected();
449 return false;
450 }
451
452 *eoh = response.find("\r\n\r\n");
nisseede5da42017-01-12 13:15:36453 RTC_DCHECK(*eoh != std::string::npos);
henrike@webrtc.org28e20752013-07-10 00:45:36454 if (*eoh == std::string::npos)
455 return false;
456
457 *peer_id = -1;
458
Philipp Hancke0240cf82020-09-07 20:13:42459 // See comment in peer_channel.cc for why we use the Pragma header.
henrike@webrtc.org28e20752013-07-10 00:45:36460 GetHeaderValue(response, *eoh, "\r\nPragma: ", peer_id);
461
462 return true;
463}
464
Niels Möllerd0b88792021-08-12 08:32:30465void PeerConnectionClient::OnClose(rtc::Socket* socket, int err) {
Harald Alvestrand97597c02021-11-04 12:01:23466 RTC_LOG(LS_INFO) << __FUNCTION__;
henrike@webrtc.org28e20752013-07-10 00:45:36467
468 socket->Close();
469
470#ifdef WIN32
471 if (err != WSAECONNREFUSED) {
472#else
473 if (err != ECONNREFUSED) {
474#endif
475 if (socket == hanging_get_.get()) {
476 if (state_ == CONNECTED) {
477 hanging_get_->Close();
478 hanging_get_->Connect(server_address_);
479 }
480 } else {
481 callback_->OnMessageSent(err);
482 }
483 } else {
484 if (socket == control_socket_.get()) {
Harald Alvestrandef5b21e2021-11-27 21:31:08485 RTC_LOG(LS_WARNING) << "Connection refused; retrying in 2 seconds";
Danil Chapovalovb9201b02022-08-17 15:12:29486 rtc::Thread::Current()->PostDelayedTask(
487 SafeTask(safety_.flag(), [this] { DoConnect(); }), kReconnectDelay);
henrike@webrtc.org28e20752013-07-10 00:45:36488 } else {
489 Close();
490 callback_->OnDisconnected();
491 }
492 }
493}