Index: talk/examples/peerconnection/client/peer_connection_client.cc |
diff --git a/talk/examples/peerconnection/client/peer_connection_client.cc b/talk/examples/peerconnection/client/peer_connection_client.cc |
deleted file mode 100644 |
index 85e5b56425cb212c2797a8c48e0f89f241bab3ef..0000000000000000000000000000000000000000 |
--- a/talk/examples/peerconnection/client/peer_connection_client.cc |
+++ /dev/null |
@@ -1,531 +0,0 @@ |
-/* |
- * libjingle |
- * Copyright 2012 Google Inc. |
- * |
- * Redistribution and use in source and binary forms, with or without |
- * modification, are permitted provided that the following conditions are met: |
- * |
- * 1. Redistributions of source code must retain the above copyright notice, |
- * this list of conditions and the following disclaimer. |
- * 2. Redistributions in binary form must reproduce the above copyright notice, |
- * this list of conditions and the following disclaimer in the documentation |
- * and/or other materials provided with the distribution. |
- * 3. The name of the author may not be used to endorse or promote products |
- * derived from this software without specific prior written permission. |
- * |
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED |
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO |
- * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; |
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
- */ |
- |
-#include "talk/examples/peerconnection/client/peer_connection_client.h" |
- |
-#include "talk/examples/peerconnection/client/defaults.h" |
-#include "webrtc/base/common.h" |
-#include "webrtc/base/logging.h" |
-#include "webrtc/base/nethelpers.h" |
-#include "webrtc/base/stringutils.h" |
- |
-#ifdef WIN32 |
-#include "webrtc/base/win32socketserver.h" |
-#endif |
- |
-using rtc::sprintfn; |
- |
-namespace { |
- |
-// This is our magical hangup signal. |
-const char kByeMessage[] = "BYE"; |
-// Delay between server connection retries, in milliseconds |
-const int kReconnectDelay = 2000; |
- |
-rtc::AsyncSocket* CreateClientSocket(int family) { |
-#ifdef WIN32 |
- rtc::Win32Socket* sock = new rtc::Win32Socket(); |
- sock->CreateT(family, SOCK_STREAM); |
- return sock; |
-#elif defined(WEBRTC_POSIX) |
- rtc::Thread* thread = rtc::Thread::Current(); |
- ASSERT(thread != NULL); |
- return thread->socketserver()->CreateAsyncSocket(family, SOCK_STREAM); |
-#else |
-#error Platform not supported. |
-#endif |
-} |
- |
-} |
- |
-PeerConnectionClient::PeerConnectionClient() |
- : callback_(NULL), |
- resolver_(NULL), |
- state_(NOT_CONNECTED), |
- my_id_(-1) { |
-} |
- |
-PeerConnectionClient::~PeerConnectionClient() { |
-} |
- |
-void PeerConnectionClient::InitSocketSignals() { |
- ASSERT(control_socket_.get() != NULL); |
- ASSERT(hanging_get_.get() != NULL); |
- control_socket_->SignalCloseEvent.connect(this, |
- &PeerConnectionClient::OnClose); |
- hanging_get_->SignalCloseEvent.connect(this, |
- &PeerConnectionClient::OnClose); |
- control_socket_->SignalConnectEvent.connect(this, |
- &PeerConnectionClient::OnConnect); |
- hanging_get_->SignalConnectEvent.connect(this, |
- &PeerConnectionClient::OnHangingGetConnect); |
- control_socket_->SignalReadEvent.connect(this, |
- &PeerConnectionClient::OnRead); |
- hanging_get_->SignalReadEvent.connect(this, |
- &PeerConnectionClient::OnHangingGetRead); |
-} |
- |
-int PeerConnectionClient::id() const { |
- return my_id_; |
-} |
- |
-bool PeerConnectionClient::is_connected() const { |
- return my_id_ != -1; |
-} |
- |
-const Peers& PeerConnectionClient::peers() const { |
- return peers_; |
-} |
- |
-void PeerConnectionClient::RegisterObserver( |
- PeerConnectionClientObserver* callback) { |
- ASSERT(!callback_); |
- callback_ = callback; |
-} |
- |
-void PeerConnectionClient::Connect(const std::string& server, int port, |
- const std::string& client_name) { |
- ASSERT(!server.empty()); |
- ASSERT(!client_name.empty()); |
- |
- if (state_ != NOT_CONNECTED) { |
- LOG(WARNING) |
- << "The client must not be connected before you can call Connect()"; |
- callback_->OnServerConnectionFailure(); |
- return; |
- } |
- |
- if (server.empty() || client_name.empty()) { |
- callback_->OnServerConnectionFailure(); |
- return; |
- } |
- |
- if (port <= 0) |
- port = kDefaultServerPort; |
- |
- server_address_.SetIP(server); |
- server_address_.SetPort(port); |
- client_name_ = client_name; |
- |
- if (server_address_.IsUnresolved()) { |
- state_ = RESOLVING; |
- resolver_ = new rtc::AsyncResolver(); |
- resolver_->SignalDone.connect(this, &PeerConnectionClient::OnResolveResult); |
- resolver_->Start(server_address_); |
- } else { |
- DoConnect(); |
- } |
-} |
- |
-void PeerConnectionClient::OnResolveResult( |
- rtc::AsyncResolverInterface* resolver) { |
- if (resolver_->GetError() != 0) { |
- callback_->OnServerConnectionFailure(); |
- resolver_->Destroy(false); |
- resolver_ = NULL; |
- state_ = NOT_CONNECTED; |
- } else { |
- server_address_ = resolver_->address(); |
- DoConnect(); |
- } |
-} |
- |
-void PeerConnectionClient::DoConnect() { |
- control_socket_.reset(CreateClientSocket(server_address_.ipaddr().family())); |
- hanging_get_.reset(CreateClientSocket(server_address_.ipaddr().family())); |
- InitSocketSignals(); |
- char buffer[1024]; |
- sprintfn(buffer, sizeof(buffer), |
- "GET /sign_in?%s HTTP/1.0\r\n\r\n", client_name_.c_str()); |
- onconnect_data_ = buffer; |
- |
- bool ret = ConnectControlSocket(); |
- if (ret) |
- state_ = SIGNING_IN; |
- if (!ret) { |
- callback_->OnServerConnectionFailure(); |
- } |
-} |
- |
-bool PeerConnectionClient::SendToPeer(int peer_id, const std::string& message) { |
- if (state_ != CONNECTED) |
- return false; |
- |
- ASSERT(is_connected()); |
- ASSERT(control_socket_->GetState() == rtc::Socket::CS_CLOSED); |
- if (!is_connected() || peer_id == -1) |
- return false; |
- |
- char headers[1024]; |
- sprintfn(headers, sizeof(headers), |
- "POST /message?peer_id=%i&to=%i HTTP/1.0\r\n" |
- "Content-Length: %i\r\n" |
- "Content-Type: text/plain\r\n" |
- "\r\n", |
- my_id_, peer_id, message.length()); |
- onconnect_data_ = headers; |
- onconnect_data_ += message; |
- return ConnectControlSocket(); |
-} |
- |
-bool PeerConnectionClient::SendHangUp(int peer_id) { |
- return SendToPeer(peer_id, kByeMessage); |
-} |
- |
-bool PeerConnectionClient::IsSendingMessage() { |
- return state_ == CONNECTED && |
- control_socket_->GetState() != rtc::Socket::CS_CLOSED; |
-} |
- |
-bool PeerConnectionClient::SignOut() { |
- if (state_ == NOT_CONNECTED || state_ == SIGNING_OUT) |
- return true; |
- |
- if (hanging_get_->GetState() != rtc::Socket::CS_CLOSED) |
- hanging_get_->Close(); |
- |
- if (control_socket_->GetState() == rtc::Socket::CS_CLOSED) { |
- state_ = SIGNING_OUT; |
- |
- if (my_id_ != -1) { |
- char buffer[1024]; |
- sprintfn(buffer, sizeof(buffer), |
- "GET /sign_out?peer_id=%i HTTP/1.0\r\n\r\n", my_id_); |
- onconnect_data_ = buffer; |
- return ConnectControlSocket(); |
- } else { |
- // Can occur if the app is closed before we finish connecting. |
- return true; |
- } |
- } else { |
- state_ = SIGNING_OUT_WAITING; |
- } |
- |
- return true; |
-} |
- |
-void PeerConnectionClient::Close() { |
- control_socket_->Close(); |
- hanging_get_->Close(); |
- onconnect_data_.clear(); |
- peers_.clear(); |
- if (resolver_ != NULL) { |
- resolver_->Destroy(false); |
- resolver_ = NULL; |
- } |
- my_id_ = -1; |
- state_ = NOT_CONNECTED; |
-} |
- |
-bool PeerConnectionClient::ConnectControlSocket() { |
- ASSERT(control_socket_->GetState() == rtc::Socket::CS_CLOSED); |
- int err = control_socket_->Connect(server_address_); |
- if (err == SOCKET_ERROR) { |
- Close(); |
- return false; |
- } |
- return true; |
-} |
- |
-void PeerConnectionClient::OnConnect(rtc::AsyncSocket* socket) { |
- ASSERT(!onconnect_data_.empty()); |
- size_t sent = socket->Send(onconnect_data_.c_str(), onconnect_data_.length()); |
- ASSERT(sent == onconnect_data_.length()); |
- RTC_UNUSED(sent); |
- onconnect_data_.clear(); |
-} |
- |
-void PeerConnectionClient::OnHangingGetConnect(rtc::AsyncSocket* socket) { |
- char buffer[1024]; |
- sprintfn(buffer, sizeof(buffer), |
- "GET /wait?peer_id=%i HTTP/1.0\r\n\r\n", my_id_); |
- int len = static_cast<int>(strlen(buffer)); |
- int sent = socket->Send(buffer, len); |
- ASSERT(sent == len); |
- RTC_UNUSED2(sent, len); |
-} |
- |
-void PeerConnectionClient::OnMessageFromPeer(int peer_id, |
- const std::string& message) { |
- if (message.length() == (sizeof(kByeMessage) - 1) && |
- message.compare(kByeMessage) == 0) { |
- callback_->OnPeerDisconnected(peer_id); |
- } else { |
- callback_->OnMessageFromPeer(peer_id, message); |
- } |
-} |
- |
-bool PeerConnectionClient::GetHeaderValue(const std::string& data, |
- size_t eoh, |
- const char* header_pattern, |
- size_t* value) { |
- ASSERT(value != NULL); |
- size_t found = data.find(header_pattern); |
- if (found != std::string::npos && found < eoh) { |
- *value = atoi(&data[found + strlen(header_pattern)]); |
- return true; |
- } |
- return false; |
-} |
- |
-bool PeerConnectionClient::GetHeaderValue(const std::string& data, size_t eoh, |
- const char* header_pattern, |
- std::string* value) { |
- ASSERT(value != NULL); |
- size_t found = data.find(header_pattern); |
- if (found != std::string::npos && found < eoh) { |
- size_t begin = found + strlen(header_pattern); |
- size_t end = data.find("\r\n", begin); |
- if (end == std::string::npos) |
- end = eoh; |
- value->assign(data.substr(begin, end - begin)); |
- return true; |
- } |
- return false; |
-} |
- |
-bool PeerConnectionClient::ReadIntoBuffer(rtc::AsyncSocket* socket, |
- std::string* data, |
- size_t* content_length) { |
- char buffer[0xffff]; |
- do { |
- int bytes = socket->Recv(buffer, sizeof(buffer)); |
- if (bytes <= 0) |
- break; |
- data->append(buffer, bytes); |
- } while (true); |
- |
- bool ret = false; |
- size_t i = data->find("\r\n\r\n"); |
- if (i != std::string::npos) { |
- LOG(INFO) << "Headers received"; |
- if (GetHeaderValue(*data, i, "\r\nContent-Length: ", content_length)) { |
- size_t total_response_size = (i + 4) + *content_length; |
- if (data->length() >= total_response_size) { |
- ret = true; |
- std::string should_close; |
- const char kConnection[] = "\r\nConnection: "; |
- if (GetHeaderValue(*data, i, kConnection, &should_close) && |
- should_close.compare("close") == 0) { |
- socket->Close(); |
- // Since we closed the socket, there was no notification delivered |
- // to us. Compensate by letting ourselves know. |
- OnClose(socket, 0); |
- } |
- } else { |
- // We haven't received everything. Just continue to accept data. |
- } |
- } else { |
- LOG(LS_ERROR) << "No content length field specified by the server."; |
- } |
- } |
- return ret; |
-} |
- |
-void PeerConnectionClient::OnRead(rtc::AsyncSocket* socket) { |
- size_t content_length = 0; |
- if (ReadIntoBuffer(socket, &control_data_, &content_length)) { |
- size_t peer_id = 0, eoh = 0; |
- bool ok = ParseServerResponse(control_data_, content_length, &peer_id, |
- &eoh); |
- if (ok) { |
- if (my_id_ == -1) { |
- // First response. Let's store our server assigned ID. |
- ASSERT(state_ == SIGNING_IN); |
- my_id_ = static_cast<int>(peer_id); |
- ASSERT(my_id_ != -1); |
- |
- // The body of the response will be a list of already connected peers. |
- if (content_length) { |
- size_t pos = eoh + 4; |
- while (pos < control_data_.size()) { |
- size_t eol = control_data_.find('\n', pos); |
- if (eol == std::string::npos) |
- break; |
- int id = 0; |
- std::string name; |
- bool connected; |
- if (ParseEntry(control_data_.substr(pos, eol - pos), &name, &id, |
- &connected) && id != my_id_) { |
- peers_[id] = name; |
- callback_->OnPeerConnected(id, name); |
- } |
- pos = eol + 1; |
- } |
- } |
- ASSERT(is_connected()); |
- callback_->OnSignedIn(); |
- } else if (state_ == SIGNING_OUT) { |
- Close(); |
- callback_->OnDisconnected(); |
- } else if (state_ == SIGNING_OUT_WAITING) { |
- SignOut(); |
- } |
- } |
- |
- control_data_.clear(); |
- |
- if (state_ == SIGNING_IN) { |
- ASSERT(hanging_get_->GetState() == rtc::Socket::CS_CLOSED); |
- state_ = CONNECTED; |
- hanging_get_->Connect(server_address_); |
- } |
- } |
-} |
- |
-void PeerConnectionClient::OnHangingGetRead(rtc::AsyncSocket* socket) { |
- LOG(INFO) << __FUNCTION__; |
- size_t content_length = 0; |
- if (ReadIntoBuffer(socket, ¬ification_data_, &content_length)) { |
- size_t peer_id = 0, eoh = 0; |
- bool ok = ParseServerResponse(notification_data_, content_length, |
- &peer_id, &eoh); |
- |
- if (ok) { |
- // Store the position where the body begins. |
- size_t pos = eoh + 4; |
- |
- if (my_id_ == static_cast<int>(peer_id)) { |
- // A notification about a new member or a member that just |
- // disconnected. |
- int id = 0; |
- std::string name; |
- bool connected = false; |
- if (ParseEntry(notification_data_.substr(pos), &name, &id, |
- &connected)) { |
- if (connected) { |
- peers_[id] = name; |
- callback_->OnPeerConnected(id, name); |
- } else { |
- peers_.erase(id); |
- callback_->OnPeerDisconnected(id); |
- } |
- } |
- } else { |
- OnMessageFromPeer(static_cast<int>(peer_id), |
- notification_data_.substr(pos)); |
- } |
- } |
- |
- notification_data_.clear(); |
- } |
- |
- if (hanging_get_->GetState() == rtc::Socket::CS_CLOSED && |
- state_ == CONNECTED) { |
- hanging_get_->Connect(server_address_); |
- } |
-} |
- |
-bool PeerConnectionClient::ParseEntry(const std::string& entry, |
- std::string* name, |
- int* id, |
- bool* connected) { |
- ASSERT(name != NULL); |
- ASSERT(id != NULL); |
- ASSERT(connected != NULL); |
- ASSERT(!entry.empty()); |
- |
- *connected = false; |
- size_t separator = entry.find(','); |
- if (separator != std::string::npos) { |
- *id = atoi(&entry[separator + 1]); |
- name->assign(entry.substr(0, separator)); |
- separator = entry.find(',', separator + 1); |
- if (separator != std::string::npos) { |
- *connected = atoi(&entry[separator + 1]) ? true : false; |
- } |
- } |
- return !name->empty(); |
-} |
- |
-int PeerConnectionClient::GetResponseStatus(const std::string& response) { |
- int status = -1; |
- size_t pos = response.find(' '); |
- if (pos != std::string::npos) |
- status = atoi(&response[pos + 1]); |
- return status; |
-} |
- |
-bool PeerConnectionClient::ParseServerResponse(const std::string& response, |
- size_t content_length, |
- size_t* peer_id, |
- size_t* eoh) { |
- int status = GetResponseStatus(response.c_str()); |
- if (status != 200) { |
- LOG(LS_ERROR) << "Received error from server"; |
- Close(); |
- callback_->OnDisconnected(); |
- return false; |
- } |
- |
- *eoh = response.find("\r\n\r\n"); |
- ASSERT(*eoh != std::string::npos); |
- if (*eoh == std::string::npos) |
- return false; |
- |
- *peer_id = -1; |
- |
- // See comment in peer_channel.cc for why we use the Pragma header and |
- // not e.g. "X-Peer-Id". |
- GetHeaderValue(response, *eoh, "\r\nPragma: ", peer_id); |
- |
- return true; |
-} |
- |
-void PeerConnectionClient::OnClose(rtc::AsyncSocket* socket, int err) { |
- LOG(INFO) << __FUNCTION__; |
- |
- socket->Close(); |
- |
-#ifdef WIN32 |
- if (err != WSAECONNREFUSED) { |
-#else |
- if (err != ECONNREFUSED) { |
-#endif |
- if (socket == hanging_get_.get()) { |
- if (state_ == CONNECTED) { |
- hanging_get_->Close(); |
- hanging_get_->Connect(server_address_); |
- } |
- } else { |
- callback_->OnMessageSent(err); |
- } |
- } else { |
- if (socket == control_socket_.get()) { |
- LOG(WARNING) << "Connection refused; retrying in 2 seconds"; |
- rtc::Thread::Current()->PostDelayed(kReconnectDelay, this, 0); |
- } else { |
- Close(); |
- callback_->OnDisconnected(); |
- } |
- } |
-} |
- |
-void PeerConnectionClient::OnMessage(rtc::Message* msg) { |
- // ignore msg; there is currently only one supported message ("retry") |
- DoConnect(); |
-} |