1*d9f75844SAndroid Build Coastguard Worker /*
2*d9f75844SAndroid Build Coastguard Worker * Copyright 2011 The WebRTC Project Authors. All rights reserved.
3*d9f75844SAndroid Build Coastguard Worker *
4*d9f75844SAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license
5*d9f75844SAndroid Build Coastguard Worker * that can be found in the LICENSE file in the root of the source
6*d9f75844SAndroid Build Coastguard Worker * tree. An additional intellectual property rights grant can be found
7*d9f75844SAndroid Build Coastguard Worker * in the file PATENTS. All contributing project authors may
8*d9f75844SAndroid Build Coastguard Worker * be found in the AUTHORS file in the root of the source tree.
9*d9f75844SAndroid Build Coastguard Worker */
10*d9f75844SAndroid Build Coastguard Worker
11*d9f75844SAndroid Build Coastguard Worker #include "examples/peerconnection/server/peer_channel.h"
12*d9f75844SAndroid Build Coastguard Worker
13*d9f75844SAndroid Build Coastguard Worker #include <stdio.h>
14*d9f75844SAndroid Build Coastguard Worker #include <stdlib.h>
15*d9f75844SAndroid Build Coastguard Worker
16*d9f75844SAndroid Build Coastguard Worker #include <algorithm>
17*d9f75844SAndroid Build Coastguard Worker
18*d9f75844SAndroid Build Coastguard Worker #include "examples/peerconnection/server/data_socket.h"
19*d9f75844SAndroid Build Coastguard Worker #include "examples/peerconnection/server/utils.h"
20*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/checks.h"
21*d9f75844SAndroid Build Coastguard Worker
22*d9f75844SAndroid Build Coastguard Worker // Set to the peer id of the originator when messages are being
23*d9f75844SAndroid Build Coastguard Worker // exchanged between peers, but set to the id of the receiving peer
24*d9f75844SAndroid Build Coastguard Worker // itself when notifications are sent from the server about the state
25*d9f75844SAndroid Build Coastguard Worker // of other peers.
26*d9f75844SAndroid Build Coastguard Worker //
27*d9f75844SAndroid Build Coastguard Worker // WORKAROUND: Since support for CORS varies greatly from one browser to the
28*d9f75844SAndroid Build Coastguard Worker // next, we don't use a custom name for our peer-id header (originally it was
29*d9f75844SAndroid Build Coastguard Worker // "X-Peer-Id: "). Instead, we use a "simple header", "Pragma" which should
30*d9f75844SAndroid Build Coastguard Worker // always be exposed to CORS requests. There is a special CORS header devoted
31*d9f75844SAndroid Build Coastguard Worker // to exposing proprietary headers (Access-Control-Expose-Headers), however
32*d9f75844SAndroid Build Coastguard Worker // at this point it is not working correctly in some popular browsers.
33*d9f75844SAndroid Build Coastguard Worker static const char kPeerIdHeader[] = "Pragma: ";
34*d9f75844SAndroid Build Coastguard Worker
35*d9f75844SAndroid Build Coastguard Worker static const char* kRequestPaths[] = {
36*d9f75844SAndroid Build Coastguard Worker "/wait",
37*d9f75844SAndroid Build Coastguard Worker "/sign_out",
38*d9f75844SAndroid Build Coastguard Worker "/message",
39*d9f75844SAndroid Build Coastguard Worker };
40*d9f75844SAndroid Build Coastguard Worker
41*d9f75844SAndroid Build Coastguard Worker enum RequestPathIndex {
42*d9f75844SAndroid Build Coastguard Worker kWait,
43*d9f75844SAndroid Build Coastguard Worker kSignOut,
44*d9f75844SAndroid Build Coastguard Worker kMessage,
45*d9f75844SAndroid Build Coastguard Worker };
46*d9f75844SAndroid Build Coastguard Worker
47*d9f75844SAndroid Build Coastguard Worker const size_t kMaxNameLength = 512;
48*d9f75844SAndroid Build Coastguard Worker
49*d9f75844SAndroid Build Coastguard Worker //
50*d9f75844SAndroid Build Coastguard Worker // ChannelMember
51*d9f75844SAndroid Build Coastguard Worker //
52*d9f75844SAndroid Build Coastguard Worker
53*d9f75844SAndroid Build Coastguard Worker int ChannelMember::s_member_id_ = 0;
54*d9f75844SAndroid Build Coastguard Worker
ChannelMember(DataSocket * socket)55*d9f75844SAndroid Build Coastguard Worker ChannelMember::ChannelMember(DataSocket* socket)
56*d9f75844SAndroid Build Coastguard Worker : waiting_socket_(NULL),
57*d9f75844SAndroid Build Coastguard Worker id_(++s_member_id_),
58*d9f75844SAndroid Build Coastguard Worker connected_(true),
59*d9f75844SAndroid Build Coastguard Worker timestamp_(time(NULL)) {
60*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(socket);
61*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_EQ(socket->method(), DataSocket::GET);
62*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(socket->PathEquals("/sign_in"));
63*d9f75844SAndroid Build Coastguard Worker name_ = socket->request_arguments();
64*d9f75844SAndroid Build Coastguard Worker if (name_.empty())
65*d9f75844SAndroid Build Coastguard Worker name_ = "peer_" + int2str(id_);
66*d9f75844SAndroid Build Coastguard Worker else if (name_.length() > kMaxNameLength)
67*d9f75844SAndroid Build Coastguard Worker name_.resize(kMaxNameLength);
68*d9f75844SAndroid Build Coastguard Worker
69*d9f75844SAndroid Build Coastguard Worker std::replace(name_.begin(), name_.end(), ',', '_');
70*d9f75844SAndroid Build Coastguard Worker }
71*d9f75844SAndroid Build Coastguard Worker
~ChannelMember()72*d9f75844SAndroid Build Coastguard Worker ChannelMember::~ChannelMember() {}
73*d9f75844SAndroid Build Coastguard Worker
is_wait_request(DataSocket * ds) const74*d9f75844SAndroid Build Coastguard Worker bool ChannelMember::is_wait_request(DataSocket* ds) const {
75*d9f75844SAndroid Build Coastguard Worker return ds && ds->PathEquals(kRequestPaths[kWait]);
76*d9f75844SAndroid Build Coastguard Worker }
77*d9f75844SAndroid Build Coastguard Worker
TimedOut()78*d9f75844SAndroid Build Coastguard Worker bool ChannelMember::TimedOut() {
79*d9f75844SAndroid Build Coastguard Worker return waiting_socket_ == NULL && (time(NULL) - timestamp_) > 30;
80*d9f75844SAndroid Build Coastguard Worker }
81*d9f75844SAndroid Build Coastguard Worker
GetPeerIdHeader() const82*d9f75844SAndroid Build Coastguard Worker std::string ChannelMember::GetPeerIdHeader() const {
83*d9f75844SAndroid Build Coastguard Worker std::string ret(kPeerIdHeader + int2str(id_) + "\r\n");
84*d9f75844SAndroid Build Coastguard Worker return ret;
85*d9f75844SAndroid Build Coastguard Worker }
86*d9f75844SAndroid Build Coastguard Worker
NotifyOfOtherMember(const ChannelMember & other)87*d9f75844SAndroid Build Coastguard Worker bool ChannelMember::NotifyOfOtherMember(const ChannelMember& other) {
88*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_NE(&other, this);
89*d9f75844SAndroid Build Coastguard Worker QueueResponse("200 OK", "text/plain", GetPeerIdHeader(), other.GetEntry());
90*d9f75844SAndroid Build Coastguard Worker return true;
91*d9f75844SAndroid Build Coastguard Worker }
92*d9f75844SAndroid Build Coastguard Worker
93*d9f75844SAndroid Build Coastguard Worker // Returns a string in the form "name,id,connected\n".
GetEntry() const94*d9f75844SAndroid Build Coastguard Worker std::string ChannelMember::GetEntry() const {
95*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(name_.length() <= kMaxNameLength);
96*d9f75844SAndroid Build Coastguard Worker
97*d9f75844SAndroid Build Coastguard Worker // name, 11-digit int, 1-digit bool, newline, null
98*d9f75844SAndroid Build Coastguard Worker char entry[kMaxNameLength + 15];
99*d9f75844SAndroid Build Coastguard Worker snprintf(entry, sizeof(entry), "%s,%d,%d\n",
100*d9f75844SAndroid Build Coastguard Worker name_.substr(0, kMaxNameLength).c_str(), id_, connected_);
101*d9f75844SAndroid Build Coastguard Worker return entry;
102*d9f75844SAndroid Build Coastguard Worker }
103*d9f75844SAndroid Build Coastguard Worker
ForwardRequestToPeer(DataSocket * ds,ChannelMember * peer)104*d9f75844SAndroid Build Coastguard Worker void ChannelMember::ForwardRequestToPeer(DataSocket* ds, ChannelMember* peer) {
105*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(peer);
106*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(ds);
107*d9f75844SAndroid Build Coastguard Worker
108*d9f75844SAndroid Build Coastguard Worker std::string extra_headers(GetPeerIdHeader());
109*d9f75844SAndroid Build Coastguard Worker
110*d9f75844SAndroid Build Coastguard Worker if (peer == this) {
111*d9f75844SAndroid Build Coastguard Worker ds->Send("200 OK", true, ds->content_type(), extra_headers, ds->data());
112*d9f75844SAndroid Build Coastguard Worker } else {
113*d9f75844SAndroid Build Coastguard Worker printf("Client %s sending to %s\n", name_.c_str(), peer->name().c_str());
114*d9f75844SAndroid Build Coastguard Worker peer->QueueResponse("200 OK", ds->content_type(), extra_headers,
115*d9f75844SAndroid Build Coastguard Worker ds->data());
116*d9f75844SAndroid Build Coastguard Worker ds->Send("200 OK", true, "text/plain", "", "");
117*d9f75844SAndroid Build Coastguard Worker }
118*d9f75844SAndroid Build Coastguard Worker }
119*d9f75844SAndroid Build Coastguard Worker
OnClosing(DataSocket * ds)120*d9f75844SAndroid Build Coastguard Worker void ChannelMember::OnClosing(DataSocket* ds) {
121*d9f75844SAndroid Build Coastguard Worker if (ds == waiting_socket_) {
122*d9f75844SAndroid Build Coastguard Worker waiting_socket_ = NULL;
123*d9f75844SAndroid Build Coastguard Worker timestamp_ = time(NULL);
124*d9f75844SAndroid Build Coastguard Worker }
125*d9f75844SAndroid Build Coastguard Worker }
126*d9f75844SAndroid Build Coastguard Worker
QueueResponse(const std::string & status,const std::string & content_type,const std::string & extra_headers,const std::string & data)127*d9f75844SAndroid Build Coastguard Worker void ChannelMember::QueueResponse(const std::string& status,
128*d9f75844SAndroid Build Coastguard Worker const std::string& content_type,
129*d9f75844SAndroid Build Coastguard Worker const std::string& extra_headers,
130*d9f75844SAndroid Build Coastguard Worker const std::string& data) {
131*d9f75844SAndroid Build Coastguard Worker if (waiting_socket_) {
132*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(queue_.empty());
133*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_EQ(waiting_socket_->method(), DataSocket::GET);
134*d9f75844SAndroid Build Coastguard Worker bool ok =
135*d9f75844SAndroid Build Coastguard Worker waiting_socket_->Send(status, true, content_type, extra_headers, data);
136*d9f75844SAndroid Build Coastguard Worker if (!ok) {
137*d9f75844SAndroid Build Coastguard Worker printf("Failed to deliver data to waiting socket\n");
138*d9f75844SAndroid Build Coastguard Worker }
139*d9f75844SAndroid Build Coastguard Worker waiting_socket_ = NULL;
140*d9f75844SAndroid Build Coastguard Worker timestamp_ = time(NULL);
141*d9f75844SAndroid Build Coastguard Worker } else {
142*d9f75844SAndroid Build Coastguard Worker QueuedResponse qr;
143*d9f75844SAndroid Build Coastguard Worker qr.status = status;
144*d9f75844SAndroid Build Coastguard Worker qr.content_type = content_type;
145*d9f75844SAndroid Build Coastguard Worker qr.extra_headers = extra_headers;
146*d9f75844SAndroid Build Coastguard Worker qr.data = data;
147*d9f75844SAndroid Build Coastguard Worker queue_.push(qr);
148*d9f75844SAndroid Build Coastguard Worker }
149*d9f75844SAndroid Build Coastguard Worker }
150*d9f75844SAndroid Build Coastguard Worker
SetWaitingSocket(DataSocket * ds)151*d9f75844SAndroid Build Coastguard Worker void ChannelMember::SetWaitingSocket(DataSocket* ds) {
152*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_EQ(ds->method(), DataSocket::GET);
153*d9f75844SAndroid Build Coastguard Worker if (ds && !queue_.empty()) {
154*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(!waiting_socket_);
155*d9f75844SAndroid Build Coastguard Worker const QueuedResponse& response = queue_.front();
156*d9f75844SAndroid Build Coastguard Worker ds->Send(response.status, true, response.content_type,
157*d9f75844SAndroid Build Coastguard Worker response.extra_headers, response.data);
158*d9f75844SAndroid Build Coastguard Worker queue_.pop();
159*d9f75844SAndroid Build Coastguard Worker } else {
160*d9f75844SAndroid Build Coastguard Worker waiting_socket_ = ds;
161*d9f75844SAndroid Build Coastguard Worker }
162*d9f75844SAndroid Build Coastguard Worker }
163*d9f75844SAndroid Build Coastguard Worker
164*d9f75844SAndroid Build Coastguard Worker //
165*d9f75844SAndroid Build Coastguard Worker // PeerChannel
166*d9f75844SAndroid Build Coastguard Worker //
167*d9f75844SAndroid Build Coastguard Worker
168*d9f75844SAndroid Build Coastguard Worker // static
IsPeerConnection(const DataSocket * ds)169*d9f75844SAndroid Build Coastguard Worker bool PeerChannel::IsPeerConnection(const DataSocket* ds) {
170*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(ds);
171*d9f75844SAndroid Build Coastguard Worker return (ds->method() == DataSocket::POST && ds->content_length() > 0) ||
172*d9f75844SAndroid Build Coastguard Worker (ds->method() == DataSocket::GET && ds->PathEquals("/sign_in"));
173*d9f75844SAndroid Build Coastguard Worker }
174*d9f75844SAndroid Build Coastguard Worker
Lookup(DataSocket * ds) const175*d9f75844SAndroid Build Coastguard Worker ChannelMember* PeerChannel::Lookup(DataSocket* ds) const {
176*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(ds);
177*d9f75844SAndroid Build Coastguard Worker
178*d9f75844SAndroid Build Coastguard Worker if (ds->method() != DataSocket::GET && ds->method() != DataSocket::POST)
179*d9f75844SAndroid Build Coastguard Worker return NULL;
180*d9f75844SAndroid Build Coastguard Worker
181*d9f75844SAndroid Build Coastguard Worker size_t i = 0;
182*d9f75844SAndroid Build Coastguard Worker for (; i < ARRAYSIZE(kRequestPaths); ++i) {
183*d9f75844SAndroid Build Coastguard Worker if (ds->PathEquals(kRequestPaths[i]))
184*d9f75844SAndroid Build Coastguard Worker break;
185*d9f75844SAndroid Build Coastguard Worker }
186*d9f75844SAndroid Build Coastguard Worker
187*d9f75844SAndroid Build Coastguard Worker if (i == ARRAYSIZE(kRequestPaths))
188*d9f75844SAndroid Build Coastguard Worker return NULL;
189*d9f75844SAndroid Build Coastguard Worker
190*d9f75844SAndroid Build Coastguard Worker std::string args(ds->request_arguments());
191*d9f75844SAndroid Build Coastguard Worker static const char kPeerId[] = "peer_id=";
192*d9f75844SAndroid Build Coastguard Worker size_t found = args.find(kPeerId);
193*d9f75844SAndroid Build Coastguard Worker if (found == std::string::npos)
194*d9f75844SAndroid Build Coastguard Worker return NULL;
195*d9f75844SAndroid Build Coastguard Worker
196*d9f75844SAndroid Build Coastguard Worker int id = atoi(&args[found + ARRAYSIZE(kPeerId) - 1]);
197*d9f75844SAndroid Build Coastguard Worker Members::const_iterator iter = members_.begin();
198*d9f75844SAndroid Build Coastguard Worker for (; iter != members_.end(); ++iter) {
199*d9f75844SAndroid Build Coastguard Worker if (id == (*iter)->id()) {
200*d9f75844SAndroid Build Coastguard Worker if (i == kWait)
201*d9f75844SAndroid Build Coastguard Worker (*iter)->SetWaitingSocket(ds);
202*d9f75844SAndroid Build Coastguard Worker if (i == kSignOut)
203*d9f75844SAndroid Build Coastguard Worker (*iter)->set_disconnected();
204*d9f75844SAndroid Build Coastguard Worker return *iter;
205*d9f75844SAndroid Build Coastguard Worker }
206*d9f75844SAndroid Build Coastguard Worker }
207*d9f75844SAndroid Build Coastguard Worker
208*d9f75844SAndroid Build Coastguard Worker return NULL;
209*d9f75844SAndroid Build Coastguard Worker }
210*d9f75844SAndroid Build Coastguard Worker
IsTargetedRequest(const DataSocket * ds) const211*d9f75844SAndroid Build Coastguard Worker ChannelMember* PeerChannel::IsTargetedRequest(const DataSocket* ds) const {
212*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(ds);
213*d9f75844SAndroid Build Coastguard Worker // Regardless of GET or POST, we look for the peer_id parameter
214*d9f75844SAndroid Build Coastguard Worker // only in the request_path.
215*d9f75844SAndroid Build Coastguard Worker const std::string& path = ds->request_path();
216*d9f75844SAndroid Build Coastguard Worker size_t args = path.find('?');
217*d9f75844SAndroid Build Coastguard Worker if (args == std::string::npos)
218*d9f75844SAndroid Build Coastguard Worker return NULL;
219*d9f75844SAndroid Build Coastguard Worker size_t found;
220*d9f75844SAndroid Build Coastguard Worker const char kTargetPeerIdParam[] = "to=";
221*d9f75844SAndroid Build Coastguard Worker do {
222*d9f75844SAndroid Build Coastguard Worker found = path.find(kTargetPeerIdParam, args);
223*d9f75844SAndroid Build Coastguard Worker if (found == std::string::npos)
224*d9f75844SAndroid Build Coastguard Worker return NULL;
225*d9f75844SAndroid Build Coastguard Worker if (found == (args + 1) || path[found - 1] == '&') {
226*d9f75844SAndroid Build Coastguard Worker found += ARRAYSIZE(kTargetPeerIdParam) - 1;
227*d9f75844SAndroid Build Coastguard Worker break;
228*d9f75844SAndroid Build Coastguard Worker }
229*d9f75844SAndroid Build Coastguard Worker args = found + ARRAYSIZE(kTargetPeerIdParam) - 1;
230*d9f75844SAndroid Build Coastguard Worker } while (true);
231*d9f75844SAndroid Build Coastguard Worker int id = atoi(&path[found]);
232*d9f75844SAndroid Build Coastguard Worker Members::const_iterator i = members_.begin();
233*d9f75844SAndroid Build Coastguard Worker for (; i != members_.end(); ++i) {
234*d9f75844SAndroid Build Coastguard Worker if ((*i)->id() == id) {
235*d9f75844SAndroid Build Coastguard Worker return *i;
236*d9f75844SAndroid Build Coastguard Worker }
237*d9f75844SAndroid Build Coastguard Worker }
238*d9f75844SAndroid Build Coastguard Worker return NULL;
239*d9f75844SAndroid Build Coastguard Worker }
240*d9f75844SAndroid Build Coastguard Worker
AddMember(DataSocket * ds)241*d9f75844SAndroid Build Coastguard Worker bool PeerChannel::AddMember(DataSocket* ds) {
242*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(IsPeerConnection(ds));
243*d9f75844SAndroid Build Coastguard Worker ChannelMember* new_guy = new ChannelMember(ds);
244*d9f75844SAndroid Build Coastguard Worker Members failures;
245*d9f75844SAndroid Build Coastguard Worker BroadcastChangedState(*new_guy, &failures);
246*d9f75844SAndroid Build Coastguard Worker HandleDeliveryFailures(&failures);
247*d9f75844SAndroid Build Coastguard Worker members_.push_back(new_guy);
248*d9f75844SAndroid Build Coastguard Worker
249*d9f75844SAndroid Build Coastguard Worker printf("New member added (total=%s): %s\n",
250*d9f75844SAndroid Build Coastguard Worker size_t2str(members_.size()).c_str(), new_guy->name().c_str());
251*d9f75844SAndroid Build Coastguard Worker
252*d9f75844SAndroid Build Coastguard Worker // Let the newly connected peer know about other members of the channel.
253*d9f75844SAndroid Build Coastguard Worker std::string content_type;
254*d9f75844SAndroid Build Coastguard Worker std::string response = BuildResponseForNewMember(*new_guy, &content_type);
255*d9f75844SAndroid Build Coastguard Worker ds->Send("200 Added", true, content_type, new_guy->GetPeerIdHeader(),
256*d9f75844SAndroid Build Coastguard Worker response);
257*d9f75844SAndroid Build Coastguard Worker return true;
258*d9f75844SAndroid Build Coastguard Worker }
259*d9f75844SAndroid Build Coastguard Worker
CloseAll()260*d9f75844SAndroid Build Coastguard Worker void PeerChannel::CloseAll() {
261*d9f75844SAndroid Build Coastguard Worker Members::const_iterator i = members_.begin();
262*d9f75844SAndroid Build Coastguard Worker for (; i != members_.end(); ++i) {
263*d9f75844SAndroid Build Coastguard Worker (*i)->QueueResponse("200 OK", "text/plain", "", "Server shutting down");
264*d9f75844SAndroid Build Coastguard Worker }
265*d9f75844SAndroid Build Coastguard Worker DeleteAll();
266*d9f75844SAndroid Build Coastguard Worker }
267*d9f75844SAndroid Build Coastguard Worker
OnClosing(DataSocket * ds)268*d9f75844SAndroid Build Coastguard Worker void PeerChannel::OnClosing(DataSocket* ds) {
269*d9f75844SAndroid Build Coastguard Worker for (Members::iterator i = members_.begin(); i != members_.end(); ++i) {
270*d9f75844SAndroid Build Coastguard Worker ChannelMember* m = (*i);
271*d9f75844SAndroid Build Coastguard Worker m->OnClosing(ds);
272*d9f75844SAndroid Build Coastguard Worker if (!m->connected()) {
273*d9f75844SAndroid Build Coastguard Worker i = members_.erase(i);
274*d9f75844SAndroid Build Coastguard Worker Members failures;
275*d9f75844SAndroid Build Coastguard Worker BroadcastChangedState(*m, &failures);
276*d9f75844SAndroid Build Coastguard Worker HandleDeliveryFailures(&failures);
277*d9f75844SAndroid Build Coastguard Worker delete m;
278*d9f75844SAndroid Build Coastguard Worker if (i == members_.end())
279*d9f75844SAndroid Build Coastguard Worker break;
280*d9f75844SAndroid Build Coastguard Worker }
281*d9f75844SAndroid Build Coastguard Worker }
282*d9f75844SAndroid Build Coastguard Worker printf("Total connected: %s\n", size_t2str(members_.size()).c_str());
283*d9f75844SAndroid Build Coastguard Worker }
284*d9f75844SAndroid Build Coastguard Worker
CheckForTimeout()285*d9f75844SAndroid Build Coastguard Worker void PeerChannel::CheckForTimeout() {
286*d9f75844SAndroid Build Coastguard Worker for (Members::iterator i = members_.begin(); i != members_.end(); ++i) {
287*d9f75844SAndroid Build Coastguard Worker ChannelMember* m = (*i);
288*d9f75844SAndroid Build Coastguard Worker if (m->TimedOut()) {
289*d9f75844SAndroid Build Coastguard Worker printf("Timeout: %s\n", m->name().c_str());
290*d9f75844SAndroid Build Coastguard Worker m->set_disconnected();
291*d9f75844SAndroid Build Coastguard Worker i = members_.erase(i);
292*d9f75844SAndroid Build Coastguard Worker Members failures;
293*d9f75844SAndroid Build Coastguard Worker BroadcastChangedState(*m, &failures);
294*d9f75844SAndroid Build Coastguard Worker HandleDeliveryFailures(&failures);
295*d9f75844SAndroid Build Coastguard Worker delete m;
296*d9f75844SAndroid Build Coastguard Worker if (i == members_.end())
297*d9f75844SAndroid Build Coastguard Worker break;
298*d9f75844SAndroid Build Coastguard Worker }
299*d9f75844SAndroid Build Coastguard Worker }
300*d9f75844SAndroid Build Coastguard Worker }
301*d9f75844SAndroid Build Coastguard Worker
DeleteAll()302*d9f75844SAndroid Build Coastguard Worker void PeerChannel::DeleteAll() {
303*d9f75844SAndroid Build Coastguard Worker for (Members::iterator i = members_.begin(); i != members_.end(); ++i)
304*d9f75844SAndroid Build Coastguard Worker delete (*i);
305*d9f75844SAndroid Build Coastguard Worker members_.clear();
306*d9f75844SAndroid Build Coastguard Worker }
307*d9f75844SAndroid Build Coastguard Worker
BroadcastChangedState(const ChannelMember & member,Members * delivery_failures)308*d9f75844SAndroid Build Coastguard Worker void PeerChannel::BroadcastChangedState(const ChannelMember& member,
309*d9f75844SAndroid Build Coastguard Worker Members* delivery_failures) {
310*d9f75844SAndroid Build Coastguard Worker // This function should be called prior to DataSocket::Close().
311*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(delivery_failures);
312*d9f75844SAndroid Build Coastguard Worker
313*d9f75844SAndroid Build Coastguard Worker if (!member.connected()) {
314*d9f75844SAndroid Build Coastguard Worker printf("Member disconnected: %s\n", member.name().c_str());
315*d9f75844SAndroid Build Coastguard Worker }
316*d9f75844SAndroid Build Coastguard Worker
317*d9f75844SAndroid Build Coastguard Worker Members::iterator i = members_.begin();
318*d9f75844SAndroid Build Coastguard Worker for (; i != members_.end(); ++i) {
319*d9f75844SAndroid Build Coastguard Worker if (&member != (*i)) {
320*d9f75844SAndroid Build Coastguard Worker if (!(*i)->NotifyOfOtherMember(member)) {
321*d9f75844SAndroid Build Coastguard Worker (*i)->set_disconnected();
322*d9f75844SAndroid Build Coastguard Worker delivery_failures->push_back(*i);
323*d9f75844SAndroid Build Coastguard Worker i = members_.erase(i);
324*d9f75844SAndroid Build Coastguard Worker if (i == members_.end())
325*d9f75844SAndroid Build Coastguard Worker break;
326*d9f75844SAndroid Build Coastguard Worker }
327*d9f75844SAndroid Build Coastguard Worker }
328*d9f75844SAndroid Build Coastguard Worker }
329*d9f75844SAndroid Build Coastguard Worker }
330*d9f75844SAndroid Build Coastguard Worker
HandleDeliveryFailures(Members * failures)331*d9f75844SAndroid Build Coastguard Worker void PeerChannel::HandleDeliveryFailures(Members* failures) {
332*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(failures);
333*d9f75844SAndroid Build Coastguard Worker
334*d9f75844SAndroid Build Coastguard Worker while (!failures->empty()) {
335*d9f75844SAndroid Build Coastguard Worker Members::iterator i = failures->begin();
336*d9f75844SAndroid Build Coastguard Worker ChannelMember* member = *i;
337*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(!member->connected());
338*d9f75844SAndroid Build Coastguard Worker failures->erase(i);
339*d9f75844SAndroid Build Coastguard Worker BroadcastChangedState(*member, failures);
340*d9f75844SAndroid Build Coastguard Worker delete member;
341*d9f75844SAndroid Build Coastguard Worker }
342*d9f75844SAndroid Build Coastguard Worker }
343*d9f75844SAndroid Build Coastguard Worker
344*d9f75844SAndroid Build Coastguard Worker // Builds a simple list of "name,id\n" entries for each member.
BuildResponseForNewMember(const ChannelMember & member,std::string * content_type)345*d9f75844SAndroid Build Coastguard Worker std::string PeerChannel::BuildResponseForNewMember(const ChannelMember& member,
346*d9f75844SAndroid Build Coastguard Worker std::string* content_type) {
347*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(content_type);
348*d9f75844SAndroid Build Coastguard Worker
349*d9f75844SAndroid Build Coastguard Worker *content_type = "text/plain";
350*d9f75844SAndroid Build Coastguard Worker // The peer itself will always be the first entry.
351*d9f75844SAndroid Build Coastguard Worker std::string response(member.GetEntry());
352*d9f75844SAndroid Build Coastguard Worker for (Members::iterator i = members_.begin(); i != members_.end(); ++i) {
353*d9f75844SAndroid Build Coastguard Worker if (member.id() != (*i)->id()) {
354*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK((*i)->connected());
355*d9f75844SAndroid Build Coastguard Worker response += (*i)->GetEntry();
356*d9f75844SAndroid Build Coastguard Worker }
357*d9f75844SAndroid Build Coastguard Worker }
358*d9f75844SAndroid Build Coastguard Worker
359*d9f75844SAndroid Build Coastguard Worker return response;
360*d9f75844SAndroid Build Coastguard Worker }
361