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

📄 fileshare.cc

📁 本人收集整理的一份c/c++跨平台网络库
💻 CC
📖 第 1 页 / 共 3 页
字号:
/* * libjingle * Copyright 2004--2006, 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/session/fileshare/fileshare.h"#include "talk/base/httpcommon-inl.h"#include "talk/base/fileutils.h"#include "talk/base/streamutils.h"#include "talk/base/event.h"#include "talk/base/helpers.h"#include "talk/base/httpclient.h"#include "talk/base/httpserver.h"#include "talk/base/pathutils.h"#include "talk/base/socketstream.h"#include "talk/base/stringdigest.h"#include "talk/base/stringencode.h"#include "talk/base/stringutils.h"#include "talk/base/tarstream.h"#include "talk/base/thread.h"#include "talk/session/tunnel/pseudotcpchannel.h"#include "talk/session/tunnel/tunnelsessionclient.h"///////////////////////////////////////////////////////////////////////////////// <description xmlns="http://www.google.com/session/share">//   <manifest>//     <file size='341'>//       <name>foo.txt</name>//     </file>//     <file size='51321'>//       <name>foo.jpg</name>//       <image width='480' height='320'/>//     </file>//     <folder>//       <name>stuff</name>//     </folder>//   </manifest>//   <protocol>//     <http>//       <url name='source-path'>/temporary/23A53F01/</url>//       <url name='preview-path'>/temporary/90266EA1/</url>//     </http>//     <raw/>//   </protocol>// </description>// <p:transport xmns:p="p2p"/>//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Constants and private functions///////////////////////////////////////////////////////////////////////////////const std::string NS_GOOGLE_SHARE("http://www.google.com/session/share");namespace {const buzz::QName QN_SHARE_DESCRIPTION(true, NS_GOOGLE_SHARE, "description");const buzz::QName QN_SHARE_MANIFEST(true, NS_GOOGLE_SHARE, "manifest");const buzz::QName QN_SHARE_FOLDER(true, NS_GOOGLE_SHARE, "folder");const buzz::QName QN_SHARE_FILE(true, NS_GOOGLE_SHARE, "file");const buzz::QName QN_SHARE_NAME(true, NS_GOOGLE_SHARE, "name");const buzz::QName QN_SHARE_IMAGE(true, NS_GOOGLE_SHARE, "image");const buzz::QName QN_SHARE_PROTOCOL(true, NS_GOOGLE_SHARE, "protocol");const buzz::QName QN_SHARE_HTTP(true, NS_GOOGLE_SHARE, "http");const buzz::QName QN_SHARE_URL(true, NS_GOOGLE_SHARE, "url");const buzz::QName QN_SHARE_CHANNEL(true, NS_GOOGLE_SHARE, "channel");const buzz::QName QN_SHARE_COMPLETE(true, NS_GOOGLE_SHARE, "complete");const buzz::QName QN_SIZE(true, buzz::STR_EMPTY, "size");const buzz::QName QN_WIDTH(true, buzz::STR_EMPTY, "width");const buzz::QName QN_HEIGHT(true, buzz::STR_EMPTY, "height");const std::string kHttpSourcePath("source-path");const std::string kHttpPreviewPath("preview-path");const size_t kMinImageSize = 16U;const size_t kMaxImageSize = 0x8000U; // (32k)const size_t kMaxPreviewSize = 1024;// Wait 10 seconds to see if any new proxies get establishedconst uint32 kProxyWait = 10000; const int MSG_RETRY = 1;const uint32 kFileTransferEnableRetryMs = 1000 * 60 * 4; // 4 minutesconst std::string MIME_OCTET_STREAM("application/octet-stream");enum {  MSG_PROXY_WAIT,};bool AllowedImageDimensions(size_t width, size_t height) {  return (width >= kMinImageSize) && (width <= kMaxImageSize)      && (height >= kMinImageSize) && (height <= kMaxImageSize);}}  // anon namespacenamespace cricket {///////////////////////////////////////////////////////////////////////////////// FileShareManifest///////////////////////////////////////////////////////////////////////////////voidFileShareManifest::AddFile(const std::string& name, size_t size) {  Item i = { T_FILE, name, size };  items_.push_back(i);}voidFileShareManifest::AddImage(const std::string& name, size_t size,                            size_t width, size_t height) {  Item i = { T_IMAGE, name, size, width, height };  items_.push_back(i);}voidFileShareManifest::AddFolder(const std::string& name, size_t size) {  Item i = { T_FOLDER, name, size };  items_.push_back(i);}size_tFileShareManifest::GetItemCount(Type t) const {  size_t count = 0;  for (size_t i=0; i<items_.size(); ++i) {    if (items_[i].type == t)      ++count;  }  return count;}///////////////////////////////////////////////////////////////////////////////// FileShareSession///////////////////////////////////////////////////////////////////////////////FileShareSession::FileShareSession(cricket::Session* session, const std::string &user_agent)  : session_(session), state_(FS_NONE),    is_closed_(false),    is_sender_(false), manifest_(NULL), pool_(this), http_client_(NULL),     http_server_(NULL),     transfer_connection_id_(talk_base::HTTP_INVALID_CONNECTION_ID),    counter_(NULL), item_transferring_(0), bytes_transferred_(0),    local_cancel_(false), local_listener_(NULL), remote_listener_(NULL),    next_channel_id_(1), user_agent_(user_agent) {  session_->SignalState.connect(this, &FileShareSession::OnSessionState);  session_->SignalInfoMessage.connect(this,    &FileShareSession::OnSessionInfoMessage);  session_->SignalChannelGone.connect(this,    &FileShareSession::OnSessionChannelGone);}FileShareSession::~FileShareSession() {  ASSERT(FS_NONE != state_);  // If we haven't closed, do cleanup now.  if (!IsClosed()) {    if (!IsComplete()) {      state_ = FS_FAILURE;    }    DoClose(true);  }  if (session_) {    // Make sure we don't get future state changes on this session.    session_->SignalState.disconnect(this);    session_->SignalInfoMessage.disconnect(this);    session_ = NULL;  }    for (TransactionList::const_iterator trans_it = transactions_.begin();       trans_it != transactions_.end(); ++trans_it) {    (*trans_it)->response()->set_error(talk_base::HC_NOT_FOUND);    http_server_->Respond(*trans_it);  }    delete http_client_;  delete http_server_;  delete manifest_;  delete local_listener_;  delete remote_listener_;}boolFileShareSession::IsComplete() const {  return (state_ >= FS_COMPLETE);}boolFileShareSession::IsClosed() const {  return is_closed_;}FileShareStateFileShareSession::state() const {  return state_;}boolFileShareSession::is_sender() const {  ASSERT(FS_NONE != state_);  return is_sender_;}const buzz::Jid&FileShareSession::jid() const {  ASSERT(FS_NONE != state_);  return jid_;}const FileShareManifest*FileShareSession::manifest() const {  ASSERT(FS_NONE != state_);  return manifest_;}const std::string&FileShareSession::local_folder() const {  ASSERT(!local_folder_.empty());  return local_folder_;}voidFileShareSession::Share(const buzz::Jid& jid, FileShareManifest* manifest) {  ASSERT(FS_NONE == state_);  ASSERT(NULL != session_);  http_server_ = new talk_base::HttpServer;  http_server_->SignalHttpRequest.connect(this,    &FileShareSession::OnHttpRequest);  http_server_->SignalHttpRequestComplete.connect(this,    &FileShareSession::OnHttpRequestComplete);  http_server_->SignalConnectionClosed.connect(this,    &FileShareSession::OnHttpConnectionClosed);  FileShareDescription* desc = new FileShareDescription;  desc->supports_http = true;  desc->manifest = *manifest;  GenerateTemporaryPrefix(&desc->source_path);  GenerateTemporaryPrefix(&desc->preview_path);  session_->Initiate(jid.Str(), NULL, desc);  delete manifest;}voidFileShareSession::Accept() {  ASSERT(FS_OFFER == state_);  ASSERT(NULL != session_);  ASSERT(NULL != manifest_);  ASSERT(!http_client_);  ASSERT(item_transferring_ == 0);  http_client_ = new talk_base::HttpClient(user_agent_,                                           &pool_);  http_client_->SignalHttpClientComplete.connect(this,    &FileShareSession::OnHttpClientComplete);  http_client_->SignalHttpClientClosed.connect(this,    &FileShareSession::OnHttpClientClosed);  // The receiver now has a need for the http_server_, when previewing already  // downloaded content.  http_server_ = new talk_base::HttpServer;  http_server_->SignalHttpRequest.connect(this,    &FileShareSession::OnHttpRequest);  http_server_->SignalHttpRequestComplete.connect(this,    &FileShareSession::OnHttpRequestComplete);  http_server_->SignalConnectionClosed.connect(this,    &FileShareSession::OnHttpConnectionClosed);  FileShareDescription* desc = new FileShareDescription;  desc->supports_http = description()->supports_http;  session_->Accept(desc);  SetState(FS_TRANSFER, false);  NextDownload();}voidFileShareSession::Decline() {  ASSERT(FS_OFFER == state_);  ASSERT(NULL != session_);  local_cancel_ = true;  session_->Reject();}voidFileShareSession::Cancel() {  ASSERT(!IsComplete());  ASSERT(NULL != session_);  local_cancel_ = true;  session_->Terminate();}boolFileShareSession::GetItemUrl(size_t index, std::string* url) {  return GetItemBaseUrl(index, false, url);}bool FileShareSession::GetImagePreviewUrl(size_t index, size_t width,                                          size_t height, std::string* url) {  if (!GetItemBaseUrl(index, true, url))    return false;  if (FileShareManifest::T_IMAGE != manifest_->item(index).type) {    ASSERT(false);    return false;  }  char query[256];  talk_base::sprintfn(query, ARRAY_SIZE(query), "?width=%u&height=%u",                      width, height);  url->append(query);  return true;}void FileShareSession::ResampleComplete(talk_base::StreamInterface *i, talk_base::HttpTransaction *trans, bool success) {  bool found = false;  for (TransactionList::const_iterator trans_it = transactions_.begin();       trans_it != transactions_.end(); ++trans_it) {    if (*trans_it == trans) {      found = true;      break;    }  }    if (!found)    return;    transactions_.remove(trans);    if (success) {      trans->response()->set_success(MIME_OCTET_STREAM, i);      http_server_->Respond(trans);     }  trans->response()->set_error(talk_base::HC_NOT_FOUND);  http_server_->Respond(trans);}bool FileShareSession::GetProgress(size_t& bytes) const {  bool known = true;  bytes = bytes_transferred_;  if (counter_) {    size_t current_size = manifest_->item(item_transferring_).size;    size_t current_pos = counter_->GetByteCount();    if (current_size == FileShareManifest::SIZE_UNKNOWN) {      known = false;    } else if (current_pos > current_size) {      // Don't allow the size of a 'known' item to be reported as larger than      // it claimed to be.      ASSERT(false);      current_pos = current_size;    }    bytes += current_pos;  }  return known;}bool FileShareSession::GetTotalSize(size_t& bytes) const {  bool known = true;  bytes = 0;  for (size_t i=0; i<manifest_->size(); ++i) {    if (manifest_->item(i).size == FileShareManifest::SIZE_UNKNOWN) {      // We make files of unknown length worth a single byte.      known = false;      bytes += 1;    } else {      bytes += manifest_->item(i).size;    }  }  return known;}bool FileShareSession::GetCurrentItemName(std::string* name) {  if (FS_TRANSFER != state_) {    name->clear();    return false;  }  ASSERT(item_transferring_ < manifest_->size());  if (transfer_name_.empty()) {    const FileShareManifest::Item& item = manifest_->item(item_transferring_);    *name = item.name;  } else {    *name = transfer_name_;  }  return !name->empty();}// StreamPool Implementationtalk_base::StreamInterface* FileShareSession::RequestConnectedStream(    const talk_base::SocketAddress& remote, int* err) {  ASSERT(remote.IPAsString() == jid_.Str());  ASSERT(!IsClosed());  ASSERT(NULL != session_);  if (!session_) {    if (err)      *err = -1;    return NULL;  }  char channel_name[64];  talk_base::sprintfn(channel_name, ARRAY_SIZE(channel_name),                      "private-%u", next_channel_id_++);  if (err)    *err = 0;  return CreateChannel(channel_name);}void FileShareSession::ReturnConnectedStream(    talk_base::StreamInterface* stream) {  talk_base::Thread::Current()->Dispose(stream);}// MessageHandler Implementation

⌨️ 快捷键说明

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