⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 relayport.cc

📁 本人收集整理的一份c/c++跨平台网络库
💻 CC
📖 第 1 页 / 共 2 页
字号:
/* * libjingle * Copyright 2004--2005, 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. */#if defined(_MSC_VER) && _MSC_VER < 1300#pragma warning(disable:4786)#endif#include "talk/base/logging.h"#include "talk/base/asynctcpsocket.h"#include "talk/base/helpers.h"#include "talk/p2p/base/relayport.h"#include <iostream>#include <cassert>#ifdef OSX#include <errno.h>#endif#if defined(_MSC_VER) && _MSC_VER < 1300namespace std {  using ::strerror;}#endif#ifdef POSIXextern "C" {#include <errno.h>}#endif // POSIXnamespace talk_base {class AsyncTCPSocket;};namespace cricket {const int KEEPALIVE_DELAY = 10 * 60 * 1000;const int RETRY_DELAY = 50; // 50ms, from ICE specconst uint32 RETRY_TIMEOUT = 50 * 1000; // ICE says 50 secs// Manages a single connection to the relayserver.  We aim to use each// connection for only a specific destination address so that we can avoid// wrapping every packet in a STUN send / data indication.class RelayEntry : public sigslot::has_slots<> {public:  RelayEntry(RelayPort* port, const talk_base::SocketAddress& ext_addr,     const talk_base::SocketAddress& local_addr);  ~RelayEntry();  RelayPort* port() { return port_; }  const talk_base::SocketAddress& address() const { return ext_addr_; }  void set_address(const talk_base::SocketAddress& addr) { ext_addr_ = addr; }  talk_base::AsyncPacketSocket* socket() { return socket_; }  bool connected() const { return connected_; }  bool locked() const { return locked_; }  // Returns the last error on the socket of this entry.  int GetError() const { return socket_->GetError(); }  // Sends the STUN requests to the server to initiate this connection.  void Connect();  // Called when this entry becomes connected.  The address given is the one  // exposed to the outside world on the relay server.  void OnConnect(const talk_base::SocketAddress& mapped_addr);  // Sends a packet to the given destination address using the socket of this  // entry.  This will wrap the packet in STUN if necessary.  int SendTo(const void* data, size_t size,     const talk_base::SocketAddress& addr);  // Schedules a keep-alive allocate request.  void ScheduleKeepAlive();  void SetServerIndex(size_t sindex) { server_index_ = sindex; }  size_t ServerIndex() const { return server_index_; }  // Try a different server address  void HandleConnectFailure();private:  RelayPort* port_;  talk_base::SocketAddress ext_addr_, local_addr_;  size_t server_index_;  talk_base::AsyncPacketSocket* socket_;  bool connected_;  bool locked_;  StunRequestManager requests_;  // Called when a TCP connection is established or fails  void OnSocketConnect(talk_base::AsyncTCPSocket* socket);  void OnSocketClose(talk_base::AsyncTCPSocket* socket, int error);  // Called when a packet is received on this socket.  void OnReadPacket(      const char* data, size_t size,       const talk_base::SocketAddress& remote_addr,      talk_base::AsyncPacketSocket* socket);  // Called on behalf of a StunRequest to write data to the socket.  This is  // already STUN intended for the server, so no wrapping is necessary.  void OnSendPacket(const void* data, size_t size, StunRequest* req);  // Sends the given data on the socket to the server with no wrapping.  This  // returns the number of bytes written or -1 if an error occurred.  int SendPacket(const void* data, size_t size);};// Handles an allocate request for a particular RelayEntry.class AllocateRequest : public StunRequest {public:  AllocateRequest(RelayEntry* entry);  virtual ~AllocateRequest() {}  virtual void Prepare(StunMessage* request);  virtual int GetNextDelay();  virtual void OnResponse(StunMessage* response);  virtual void OnErrorResponse(StunMessage* response);  virtual void OnTimeout();private:  RelayEntry* entry_;  uint32 start_time_;};const std::string RELAY_PORT_TYPE("relay");RelayPort::RelayPort(    talk_base::Thread* thread, talk_base::SocketFactory* factory,     talk_base::Network* network, const talk_base::SocketAddress& local_addr,     const std::string& username, const std::string& password,     const std::string& magic_cookie)  : Port(thread, RELAY_PORT_TYPE, factory, network), local_addr_(local_addr),    ready_(false), magic_cookie_(magic_cookie), error_(0) {  entries_.push_back(    new RelayEntry(this, talk_base::SocketAddress(), local_addr_));  set_username_fragment(username);  set_password(password);  if (magic_cookie_.size() == 0)    magic_cookie_.append(STUN_MAGIC_COOKIE_VALUE, 4);}RelayPort::~RelayPort() {  for (unsigned i = 0; i < entries_.size(); ++i)    delete entries_[i];  thread_->Clear(this);}void RelayPort::AddServerAddress(const ProtocolAddress& addr) {  // Since HTTP proxies usually only allow 443, let's up the priority on PROTO_SSLTCP  if ((addr.proto == PROTO_SSLTCP)      && ((proxy().type == talk_base::PROXY_HTTPS)           || (proxy().type == talk_base::PROXY_UNKNOWN))) {    server_addr_.push_front(addr);  } else {    server_addr_.push_back(addr);  }}void RelayPort::AddExternalAddress(const ProtocolAddress& addr) {  std::string proto_name = ProtoToString(addr.proto);  for (std::vector<Candidate>::const_iterator it = candidates().begin(); it != candidates().end(); ++it) {    if ((it->address() == addr.address) && (it->protocol() == proto_name)) {      LOG(INFO) << "Redundant relay address: " << proto_name << " @ " << addr.address.ToString();      return;    }  }  AddAddress(addr.address, proto_name, false);}void RelayPort::SetReady() {  if (!ready_) {    ready_ = true;    SignalAddressReady(this);  }}const ProtocolAddress * RelayPort::ServerAddress(size_t index) const {  if ((index >= 0) && (index < server_addr_.size()))    return &server_addr_[index];  return 0;}bool RelayPort::HasMagicCookie(const char* data, size_t size) {  if (size < 24 + magic_cookie_.size()) {    return false;  } else {    return 0 == std::memcmp(data + 24,                            magic_cookie_.c_str(),                            magic_cookie_.size());  }}void RelayPort::PrepareAddress() {  // We initiate a connect on the first entry.  If this completes, it will fill  // in the server address as the address of this port.  assert(entries_.size() == 1);  entries_[0]->Connect();  ready_ = false;}Connection* RelayPort::CreateConnection(const Candidate& address, CandidateOrigin origin) {  // We only create connections to non-udp sockets if they are incoming on this port  if ((address.protocol() != "udp") && (origin != ORIGIN_THIS_PORT))    return 0;  // We don't support loopback on relays  if (address.type() == type())    return 0;  size_t index = 0;  for (size_t i = 0; i < candidates().size(); ++i) {    const Candidate& local = candidates()[i];    if (local.protocol() == address.protocol()) {      index = i;      break;    }  }  Connection * conn = new ProxyConnection(this, index, address);  AddConnection(conn);  return conn;}int RelayPort::SendTo(const void* data, size_t size,                      const talk_base::SocketAddress& addr, bool payload) {  // Try to find an entry for this specific address.  Note that the first entry  // created was not given an address initially, so it can be set to the first  // address that comes along.  RelayEntry* entry = 0;  for (unsigned i = 0; i < entries_.size(); ++i) {    if (entries_[i]->address().IsAny() && payload) {      entry = entries_[i];      entry->set_address(addr);      break;    } else if (entries_[i]->address() == addr) {      entry = entries_[i];      break;    }  }  // If we did not find one, then we make a new one.  This will not be useable  // until it becomes connected, however.  if (!entry && payload) {    entry = new RelayEntry(this, addr, local_addr_);    if (!entries_.empty()) {      // Use the same port to connect to relay server      entry->SetServerIndex(entries_[0]->ServerIndex());    }    entry->Connect();    entries_.push_back(entry);  }  // If the entry is connected, then we can send on it (though wrapping may  // still be necessary).  Otherwise, we can't yet use this connection, so we  // default to the first one.  if (!entry || !entry->connected()) {    assert(!entries_.empty());    entry = entries_[0];    if (!entry->connected()) {      error_ = EWOULDBLOCK;      return SOCKET_ERROR;    }  }  // Send the actual contents to the server using the usual mechanism.  int sent = entry->SendTo(data, size, addr);  if (sent <= 0) {    assert(sent < 0);    error_ = entry->GetError();    return SOCKET_ERROR;  }  // The caller of the function is expecting the number of user data bytes,  // rather than the size of the packet.  return (int)size;}int RelayPort::SetOption(talk_base::Socket::Option opt, int value) {  int result = 0;  for (unsigned i = 0; i < entries_.size(); ++i) {    if (entries_[i]->socket()->SetOption(opt, value) < 0) {      result = -1;      error_ = entries_[i]->socket()->GetError();    }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -