Exemplo n.º 1
0
	bool dos_blocker::incoming(address const& addr, time_point const now, dht_logger* logger)
	{
		TORRENT_UNUSED(logger);
		node_ban_entry* match = nullptr;
		node_ban_entry* min = m_ban_nodes;
		for (node_ban_entry* i = m_ban_nodes; i < m_ban_nodes + num_ban_nodes; ++i)
		{
			if (i->src == addr)
			{
				match = i;
				break;
			}
			if (i->count < min->count) min = i;
			else if (i->count == min->count
				&& i->limit < min->limit) min = i;
		}

		if (match)
		{
			++match->count;

			if (match->count >= m_message_rate_limit * 10)
			{
				if (now < match->limit)
				{
					if (match->count == m_message_rate_limit * 10)
					{
#ifndef TORRENT_DISABLE_LOGGING
						if (logger != nullptr && logger->should_log(dht_logger::tracker))
						{
							logger->log(dht_logger::tracker, "BANNING PEER [ ip: %s time: %d ms count: %d ]"
								, print_address(addr).c_str()
								, int(total_milliseconds((now - match->limit) + seconds(10)))
								, match->count);
						}
#else
						TORRENT_UNUSED(logger);
#endif // TORRENT_DISABLE_LOGGING
						// we've received too many messages in less than 10 seconds
						// from this node. Ignore it until it's silent for 5 minutes
						match->limit = now + seconds(m_block_timeout);
					}

					return false;
				}

				// the messages we received from this peer took more than 10
				// seconds. Reset the counter and the timer
				match->count = 0;
				match->limit = now + seconds(10);
			}
		}
		else
		{
			min->count = 1;
			min->limit = now + seconds(10);
			min->src = addr;
		}
		return true;
	}
Exemplo n.º 2
0
	void condition_variable::wait_for(mutex::scoped_lock& l, time_duration rel_time)
	{
		TORRENT_ASSERT(l.locked());
		++m_num_waiters;
		l.unlock();
		WaitForSingleObject(m_sem, total_milliseconds(rel_time));
		l.lock();
		--m_num_waiters;
	}
Exemplo n.º 3
0
	char const* time_now_string()
	{
		static const time_point start = clock_type::now();
		static char ret[200];
		int t = int(total_milliseconds(clock_type::now() - start));
		int h = t / 1000 / 60 / 60;
		t -= h * 60 * 60 * 1000;
		int m = t / 1000 / 60;
		t -= m * 60 * 1000;
		int s = t / 1000;
		t -= s * 1000;
		int ms = t;
		std::snprintf(ret, sizeof(ret), "%02d:%02d:%02d.%03d", h, m, s, ms);
		return ret;
	}
Exemplo n.º 4
0
	TORRENT_EXTRA_EXPORT char const* time_now_string()
	{
		static const ptime start = time_now_hires();
		static char ret[200];
		int t = total_milliseconds(time_now_hires() - start);
		int h = t / 1000 / 60 / 60;
		t -= h * 60 * 60 * 1000;
		int m = t / 1000 / 60;
		t -= m * 60 * 1000;
		int s = t / 1000;
		t -= s * 1000;
		int ms = t;
		snprintf(ret, sizeof(ret), "%02d:%02d:%02d.%03d", h, m, s, ms);
		return ret;
	}
Exemplo n.º 5
0
void ConnectionImpl <WebSocket04>::setPingTimer ()
{
    if (pingFreq_ <= 0)
        return;
    if (auto con = m_connection.lock ())
    {
        auto t = boost::posix_time::seconds (pingFreq_);
        auto ms = t.total_milliseconds();
        con->set_timer (
            ms,
            std::bind (
                beast::weak_fn (&ConnectionImpl <WebSocket04>::pingTimer,
                                shared_from_this()),
                beast::asio::placeholders::error));
    }
}
Exemplo n.º 6
0
void ConnectionImpl <WebSocket04>::setPingTimer ()
{
    auto freq = getConfig ().WEBSOCKET_PING_FREQ;
    if (freq <= 0)
        return;
    if (auto con = m_connection.lock ())
    {
        auto t = boost::posix_time::seconds (freq);
        auto ms = t.total_milliseconds();
        con->set_timer (
            ms,
            std::bind (
                beast::weak_fn (&ConnectionImpl <WebSocket04>::pingTimer,
                                shared_from_this()),
                beast::asio::placeholders::error));
    }
}
Exemplo n.º 7
0
	int unchoke_sort(std::vector<peer_connection*>& peers
		, int max_upload_rate
		, time_duration unchoke_interval
		, aux::session_settings const& sett)
	{
		int upload_slots = sett.get_int(settings_pack::unchoke_slots_limit);

		// ==== BitTyrant ====
		//
		// if we're using the bittyrant unchoker, go through all peers that
		// we have unchoked already, and adjust our estimated reciprocation
		// rate. If the peer has reciprocated, lower the estimate, if it hasn't,
		// increase the estimate (this attempts to optimize "ROI" of upload
		// capacity, by sending just enough to be reciprocated).
		// For more information, see: http://bittyrant.cs.washington.edu/
		if (sett.get_int(settings_pack::choking_algorithm)
			== settings_pack::bittyrant_choker)
		{
			for (std::vector<peer_connection*>::const_iterator i = peers.begin()
				, end(peers.end()); i != end; ++i)
			{
				peer_connection* p = *i;
				if (p->is_choked() || !p->is_interesting()) continue;

				if (!p->has_peer_choked())
				{
					// we're unchoked, we may want to lower our estimated
					// reciprocation rate
					p->decrease_est_reciprocation_rate();
				}
				else
				{
					// we've unchoked this peer, and it hasn't reciprocated
					// we may want to increase our estimated reciprocation rate
					p->increase_est_reciprocation_rate();
				}
			}

			// if we're using the bittyrant choker, sort peers by their return
			// on investment. i.e. download rate / upload rate
			std::sort(peers.begin(), peers.end()
				, boost::bind(&bittyrant_unchoke_compare, _1, _2));

			int upload_capacity_left = max_upload_rate;

			// now, figure out how many peers should be unchoked. We deduct the
			// estimated reciprocation rate from our upload_capacity estimate
			// until there none left
			upload_slots = 0;

			for (std::vector<peer_connection*>::iterator i = peers.begin()
				, end(peers.end()); i != end; ++i)
			{
				peer_connection* p = *i;
				TORRENT_ASSERT(p);

				if (p->est_reciprocation_rate() > upload_capacity_left) break;

				++upload_slots;
				upload_capacity_left -= p->est_reciprocation_rate();
			}

			return upload_slots;
		}

		// ==== rate-based ====
		//
		// The rate based unchoker looks at our upload rate to peers, and find
		// a balance between number of upload slots and the rate we achieve. The
		// intention is to not spread upload bandwidth too thin, but also to not
		// unchoke few enough peers to not be able to saturate the up-link.
		// this is done by traversing the peers sorted by our upload rate to
		// them in decreasing rates. For each peer we increase our threshold
		// by 1 kB/s. The first peer we get to to whom we upload slower than
		// the threshold, we stop and that's the number of unchoke slots we have.
		if (sett.get_int(settings_pack::choking_algorithm)
			== settings_pack::rate_based_choker)
		{
			// first reset the number of unchoke slots, because we'll calculate
			// it purely based on the current state of our peers.
			upload_slots = 0;

			// TODO: optimize this using partial_sort or something. We don't need
			// to sort the entire list
			
			// TODO: make the comparison function a free function and move it
			// into this cpp file
			std::sort(peers.begin(), peers.end()
				, boost::bind(&upload_rate_compare, _1, _2));

			// TODO: make configurable
			int rate_threshold = 1024;

			for (std::vector<peer_connection*>::const_iterator i = peers.begin()
				, end(peers.end()); i != end; ++i)
			{
				peer_connection const& p = **i;
				int rate = int(p.uploaded_in_last_round()
					* 1000 / total_milliseconds(unchoke_interval));

				if (rate < rate_threshold) break;

				++upload_slots;

				// TODO: make configurable
				rate_threshold += 1024;
			}
			++upload_slots;
		}

		// sorts the peers that are eligible for unchoke by download rate and
		// secondary by total upload. The reason for this is, if all torrents are
		// being seeded, the download rate will be 0, and the peers we have sent
		// the least to should be unchoked
		
		// we use partial sort here, because we only care about the top
		// upload_slots peers.

		if (sett.get_int(settings_pack::seed_choking_algorithm)
			== settings_pack::round_robin)
		{
			int pieces = sett.get_int(settings_pack::seeding_piece_quota);

			std::partial_sort(peers.begin(), peers.begin()
				+ (std::min)(upload_slots, int(peers.size())), peers.end()
				, boost::bind(&unchoke_compare_rr, _1, _2, pieces));
		}
		else if (sett.get_int(settings_pack::seed_choking_algorithm)
			== settings_pack::fastest_upload)
		{
			std::partial_sort(peers.begin(), peers.begin()
				+ (std::min)(upload_slots, int(peers.size())), peers.end()
				, boost::bind(&unchoke_compare_fastest_upload, _1, _2));
		}
		else if (sett.get_int(settings_pack::seed_choking_algorithm)
			== settings_pack::anti_leech)
		{
			std::partial_sort(peers.begin(), peers.begin()
				+ (std::min)(upload_slots, int(peers.size())), peers.end()
				, boost::bind(&unchoke_compare_anti_leech, _1, _2));
		}
		else
		{
			TORRENT_ASSERT(false && "unknown seed choking algorithm");

			int pieces = sett.get_int(settings_pack::seeding_piece_quota);
			std::partial_sort(peers.begin(), peers.begin()
				+ (std::min)(upload_slots, int(peers.size())), peers.end()
				, boost::bind(&unchoke_compare_rr, _1, _2, pieces));
		}

		return upload_slots;
	}
Exemplo n.º 8
0
bool rpc_manager::incoming(msg const& m, node_id* id)
{
	INVARIANT_CHECK;

	if (m_destructing) return false;

	// we only deal with replies and errors, not queries
	TORRENT_ASSERT(m.message.dict_find_string_value("y") == "r"
		|| m.message.dict_find_string_value("y") == "e");

	// if we don't have the transaction id in our
	// request list, ignore the packet

	std::string transaction_id = m.message.dict_find_string_value("t");
	if (transaction_id.empty()) return false;

	std::string::const_iterator ptr = transaction_id.begin();
	int tid = transaction_id.size() != 2 ? -1 : io::read_uint16(ptr);

	observer_ptr o;
	std::pair<transactions_t::iterator, transactions_t::iterator> range = m_transactions.equal_range(tid);
	for (transactions_t::iterator i = range.first; i != range.second; ++i)
	{
		if (m.addr.address() != i->second->target_addr()) continue;
		o = i->second;
		i = m_transactions.erase(i);
		break;
	}

	if (!o)
	{
#ifndef TORRENT_DISABLE_LOGGING
		if (m_table.native_endpoint(m.addr))
		{
			m_log->log(dht_logger::rpc_manager, "reply with unknown transaction id size: %d from %s"
				, int(transaction_id.size()), print_endpoint(m.addr).c_str());
		}
#endif
		// this isn't necessarily because the other end is doing
		// something wrong. This can also happen when we restart
		// the node, and we prematurely abort all outstanding
		// requests. Also, this opens up a potential magnification
		// attack.
//		entry e;
//		incoming_error(e, "invalid transaction id");
//		m_sock->send_packet(e, m.addr);
		return false;
	}

	time_point now = clock_type::now();

#ifndef TORRENT_DISABLE_LOGGING
	m_log->log(dht_logger::rpc_manager, "round trip time(ms): %" PRId64 " from %s"
		, total_milliseconds(now - o->sent()), print_endpoint(m.addr).c_str());
#endif

	if (m.message.dict_find_string_value("y") == "e")
	{
		// It's an error.
#ifndef TORRENT_DISABLE_LOGGING
		bdecode_node err = m.message.dict_find_list("e");
		if (err && err.list_size() >= 2
			&& err.list_at(0).type() == bdecode_node::int_t
			&& err.list_at(1).type() == bdecode_node::string_t)
		{
			m_log->log(dht_logger::rpc_manager, "reply with error from %s: (%" PRId64 ") %s"
				, print_endpoint(m.addr).c_str()
				, err.list_int_value_at(0)
				, err.list_string_value_at(1).c_str());
		}
		else
		{
			m_log->log(dht_logger::rpc_manager, "reply with (malformed) error from %s"
				, print_endpoint(m.addr).c_str());
		}
#endif
		// Logically, we should call o->reply(m) since we get a reply.
		// a reply could be "response" or "error", here the reply is an "error".
		// if the reply is an "error", basically the observer could/will
		// do nothing with it, especially when observer::reply() is intended to
		// handle a "response", not an "error".
		// A "response" should somehow call algorithm->finished(), and an error/timeout
		// should call algorithm->failed(). From this point of view,
		// we should call o->timeout() instead of o->reply(m) because o->reply()
		// will call algorithm->finished().
		o->timeout();
		return false;
	}

	bdecode_node ret_ent = m.message.dict_find_dict("r");
	if (!ret_ent)
	{
		o->timeout();
		return false;
	}

	bdecode_node node_id_ent = ret_ent.dict_find_string("id");
	if (!node_id_ent || node_id_ent.string_length() != 20)
	{
		o->timeout();
		return false;
	}

	node_id nid = node_id(node_id_ent.string_ptr());
	if (m_settings.enforce_node_id && !verify_id(nid, m.addr.address()))
	{
		o->timeout();
		return false;
	}

#ifndef TORRENT_DISABLE_LOGGING
	m_log->log(dht_logger::rpc_manager, "[%p] reply with transaction id: %d from %s"
		, static_cast<void*>(o->algorithm()), int(transaction_id.size())
		, print_endpoint(m.addr).c_str());
#endif
	o->reply(m);
	*id = nid;

	int rtt = int(total_milliseconds(now - o->sent()));

	// we found an observer for this reply, hence the node is not spoofing
	// add it to the routing table
	return m_table.node_seen(*id, m.addr, rtt);
}
Exemplo n.º 9
0
void STORCommand::Execute()
{
  namespace pt = boost::posix_time;
  namespace gd = boost::gregorian;
  
  fs::VirtualPath path(fs::PathFromUser(argStr));
  
  util::Error e(acl::path::Filter(client.User(), path.Basename()));
  if (!e)
  {
    control.Reply(ftp::ActionNotOkay, "File name contains one or more invalid characters.");
    throw cmd::NoPostScriptError();
  }

  off_t offset = data.RestartOffset();
  if (offset > 0 && data.DataType() == ftp::DataType::ASCII)
  {
    control.Reply(ftp::BadCommandSequence, "Resume not supported on ASCII data type.");
    throw cmd::NoPostScriptError();
  }
  
  if (!exec::PreCheck(client, path)) throw cmd::NoPostScriptError();

  switch(ftp::Counter::Upload().Start(client.User().ID(), 
         client.User().MaxSimUp(), 
         client.User().HasFlag(acl::Flag::Exempt)))
  {
    case ftp::CounterResult::PersonalFail  :
    {
      std::ostringstream os;
      os << "You have reached your maximum of " << client.User().MaxSimUp() 
         << " simultaneous uploads(s).";
      control.Reply(ftp::ActionNotOkay, os.str());
      throw cmd::NoPostScriptError();
    }
    case ftp::CounterResult::GlobalFail    :
    {
      control.Reply(ftp::ActionNotOkay, 
          "The server has reached it's maximum number of simultaneous uploads.");
      throw cmd::NoPostScriptError();          
    }
    case ftp::CounterResult::Okay          :
      break;
  }  
  
  auto countGuard = util::MakeScopeExit([&]{ ftp::Counter::Upload().Stop(client.User().ID()); });  

  if (data.DataType() == ftp::DataType::ASCII && !cfg::Get().AsciiUploads().Allowed(path.ToString()))
  {
    control.Reply(ftp::ActionNotOkay, "File can't be uploaded in ASCII, change to BINARY.");
    throw cmd::NoPostScriptError();
  }
  
  fs::FileSinkPtr fout;
  try
  {
    if (data.RestartOffset() > 0)
      fout = fs::AppendFile(client.User(), path, data.RestartOffset());
    else
      fout = fs::CreateFile(client.User(), path);
  }
  catch (const util::SystemError& e)
  {
    if (data.RestartOffset() == 0 && e.Errno() == EEXIST)
    {
      DupeMessage(path);
    }
    else
    {
      std::ostringstream os;
      os << "Unable to " << (data.RestartOffset() > 0 ? "append" : "create")
         << " file: " << e.Message();
      control.Reply(ftp::ActionNotOkay, os.str());
    }
    throw cmd::NoPostScriptError();
  }
  catch (const util::RuntimeError& e)
  {
    std::ostringstream os;
    os << "Unable to " << (data.RestartOffset() > 0 ? "append" : "create")
       << " file: " << e.Message();
    control.Reply(ftp::ActionNotOkay, os.str());
    throw cmd::NoPostScriptError();
  }

  bool fileOkay = data.RestartOffset() > 0;
  auto fileGuard = util::MakeScopeExit([&]
  {
    if (!fileOkay)
    {
      try
      {
        fs::DeleteFile(fs::MakeReal(path));
      }
      catch (std::exception& e)
      {
        logs::Error("Failed to delete failed upload: %1%", e.what());
      }
    }
  });  
  
  std::stringstream os;
  os << "Opening " << (data.DataType() == ftp::DataType::ASCII ? "ASCII" : "BINARY") 
     << " connection for upload of " 
     << fs::MakePretty(path).ToString();
  if (data.Protection()) os << " using TLS/SSL";
  os << ".";
  control.Reply(ftp::TransferStatusOkay, os.str());
  
  try
  {
    data.Open(ftp::TransferType::Upload);
  }
  catch (const util::net::NetworkError&e )
  {
    if (!data.RestartOffset()) fs::DeleteFile(fs::MakeReal(path));
    control.Reply(ftp::CantOpenDataConnection,
                 "Unable to open data connection: " + e.Message());
    throw cmd::NoPostScriptError();
  }

  auto dataGuard = util::MakeScopeExit([&]
  {
    if (data.State().Type() != ftp::TransferType::None)
    {
      data.Close();
      if (data.State().Bytes() > 0)
      {
        db::stats::Upload(client.User(), data.State().Bytes() / 1024, 
                          data.State().Duration().total_milliseconds());
      }
    }
  });  
  
  if (!data.ProtectionOkay())
  {
    std::ostringstream os;
    os << "TLS is enforced on " << (data.IsFXP() ? "FXP" : "data") << " transfers.";
    control.Reply(ftp::ProtocolNotSupported, os.str());
    return;
  }

  auto section = cfg::Get().SectionMatch(path.ToString());
  
  auto transferLogGuard = util::MakeScopeExit([&]
  {
    if (cfg::Get().TransferLog().Uploads())
    {
      bool okay = !std::uncaught_exception();
      logs::Transfer(fs::MakeReal(path).ToString(), "up", client.User().Name(), client.User().PrimaryGroup(), 
                     (data.State().StartTime() - pt::ptime(gd::date(1970, 1, 1))).total_microseconds() / 1000000.0, 
                     data.State().Bytes() / 1024, data.State().Duration().total_microseconds() / 1000000.0,
                     okay, section ? section->Name() : std::string());
      }
  });
  
  const size_t bufferSize = cfg::Get().DataBufferSize();
  bool calcCrc = CalcCRC(path);
  std::unique_ptr<util::CRC32> crc32(cfg::Get().AsyncCRC() ? 
                                     new util::AsyncCRC32(bufferSize, 10) :
                                     new util::CRC32());
  bool aborted = false;
  fileOkay = false;
  
  try
  {
    ftp::UploadSpeedControl speedControl(client, path);
    ftp::OnlineTransferUpdater onlineUpdater(boost::this_thread::get_id(), stats::Direction::Upload,
                                             data.State().StartTime());
    std::vector<char> asciiBuffer;
    std::vector<char> buffer;
    buffer.resize(bufferSize);
    
    while (true)
    {
      size_t len = data.Read(&buffer[0], buffer.size());
      
      const char *bufp  = buffer.data();
      if (data.DataType() == ftp::DataType::ASCII)
      {
        ftp::ASCIITranscodeSTOR(bufp, len, asciiBuffer);
        len = asciiBuffer.size();
        bufp = asciiBuffer.data();
      }
      
      data.State().Update(len);
      
      fout->write(bufp, len);
      
      if (calcCrc) crc32->Update(reinterpret_cast<const uint8_t*>(bufp), len);
      onlineUpdater.Update(data.State().Bytes());
      speedControl.Apply();
    }
  }
  catch (const util::net::EndOfStream&) { }
  catch (const ftp::TransferAborted&) { aborted = true; }
  catch (const util::net::NetworkError& e)
  {
    control.Reply(ftp::DataCloseAborted,
                 "Error while reading from data connection: " + e.Message());
    throw cmd::NoPostScriptError();
  }
  catch (const std::ios_base::failure& e)
  {
    control.Reply(ftp::DataCloseAborted,
                  "Error while writing to disk: " + std::string(e.what()));
    throw cmd::NoPostScriptError();
  }
  catch (const ftp::ControlError& e)
  {
    e.Rethrow();
  }
  catch (const ftp::MinimumSpeedError& e)
  {
    logs::Debug("Aborted slow upload by %1%. %2% lower than %3%", 
                client.User().Name(),
                stats::AutoUnitSpeedString(e.Speed()),
                stats::AutoUnitSpeedString(e.Limit()));
    aborted = true;
  }

  fout->close();
  data.Close();
  
  e = fs::Chmod(fs::MakeReal(path), completeMode);
  if (!e) control.PartReply(ftp::DataClosedOkay, "Failed to chmod upload: " + e.Message());

  auto duration = data.State().Duration();
  double speed = stats::CalculateSpeed(data.State().Bytes(), duration);

  if (aborted)
  {
    control.Reply(ftp::DataClosedOkay, "Transfer aborted @ " + stats::AutoUnitSpeedString(speed / 1024)); 
    throw cmd::NoPostScriptError();
  }
  
  if (exec::PostCheck(client, path, 
                      calcCrc ? crc32->HexString() : "000000", speed, 
                      section ? section->Name() : ""))
  {
    fileOkay = true;
    bool nostats = !section || acl::path::FileAllowed<acl::path::Nostats>(client.User(), path);
    db::stats::Upload(client.User(), data.State().Bytes() / 1024,
                      duration.total_milliseconds(),
                      nostats ? "" : section->Name());    

    client.User().IncrSectionCredits(section && section->SeparateCredits() ? section->Name() : "", 
            data.State().Bytes() / 1024 * stats::UploadRatio(client.User(), path, section));
  }

  control.Reply(ftp::DataClosedOkay, "Transfer finished @ " + stats::AutoUnitSpeedString(speed / 1024)); 
  
  (void) countGuard;
  (void) fileGuard;
  (void) dataGuard;
}
Exemplo n.º 10
0
bool rpc_manager::incoming(msg const& m, node_id* id)
{
	INVARIANT_CHECK;

	if (m_destructing) return false;

	// we only deal with replies, not queries
	TORRENT_ASSERT(m.message.dict_find_string_value("y") == "r");

	// if we don't have the transaction id in our
	// request list, ignore the packet

	std::string transaction_id = m.message.dict_find_string_value("t");

	std::string::const_iterator i = transaction_id.begin();	
	int tid = transaction_id.size() != 2 ? -1 : io::read_uint16(i);

	observer_ptr o;

	for (transactions_t::iterator i = m_transactions.begin()
		, end(m_transactions.end()); i != end; ++i)
	{
		TORRENT_ASSERT(*i);
		if ((*i)->transaction_id() != tid) continue;
		if (m.addr.address() != (*i)->target_addr()) continue;
		o = *i;
		m_transactions.erase(i);
		break;
	}

	if (!o)
	{
#ifdef TORRENT_DHT_VERBOSE_LOGGING
		TORRENT_LOG(rpc) << "Reply with invalid transaction id size: " 
			<< transaction_id.size() << " from " << m.addr;
#endif
		entry e;
		incoming_error(e, "invalid transaction id");
		m_send(m_userdata, e, m.addr, 0);
		return false;
	}

#ifdef TORRENT_DHT_VERBOSE_LOGGING
	std::ofstream reply_stats("round_trip_ms.log", std::ios::app);
	reply_stats << m.addr << "\t" << total_milliseconds(time_now_hires() - o->sent())
		<< std::endl;
#endif

	lazy_entry const* ret_ent = m.message.dict_find_dict("r");
	if (ret_ent == 0)
	{
		entry e;
		incoming_error(e, "missing 'r' key");
		m_send(m_userdata, e, m.addr, 0);
		return false;
	}

	lazy_entry const* node_id_ent = ret_ent->dict_find_string("id");
	if (node_id_ent == 0 || node_id_ent->string_length() != 20)
	{
		entry e;
		incoming_error(e, "missing 'id' key");
		m_send(m_userdata, e, m.addr, 0);
		return false;
	}

	lazy_entry const* ext_ip = ret_ent->dict_find_string("ip");
	if (ext_ip && ext_ip->string_length() == 4)
	{
		// this node claims we use the wrong node-ID!
		address_v4::bytes_type b;
		memcpy(&b[0], ext_ip->string_ptr(), 4);
		m_ext_ip(address_v4(b), aux::session_impl::source_dht, m.addr.address());
	}
#if TORRENT_USE_IPV6
	else if (ext_ip && ext_ip->string_length() == 16)
	{
		// this node claims we use the wrong node-ID!
		address_v6::bytes_type b;
		memcpy(&b[0], ext_ip->string_ptr(), 16);
		m_ext_ip(address_v6(b), aux::session_impl::source_dht, m.addr.address());
	}
#endif

#ifdef TORRENT_DHT_VERBOSE_LOGGING
	TORRENT_LOG(rpc) << "[" << o->m_algorithm.get() << "] Reply with transaction id: " 
		<< tid << " from " << m.addr;
#endif
	o->reply(m);
	*id = node_id(node_id_ent->string_ptr());

	// we found an observer for this reply, hence the node is not spoofing
	// add it to the routing table
	return m_table.node_seen(*id, m.addr);
}
Exemplo n.º 11
0
double TimeDuration::operator /(const TimeDuration& b) const {
    return double(total_milliseconds()) / double(b.total_milliseconds());
}
Exemplo n.º 12
0
TimeDuration TimeDuration::operator *(const double& b) const {
    return ptime::milliseconds(double(total_milliseconds()) *  b);
}
Exemplo n.º 13
0
	void bandwidth_manager::update_quotas(time_duration const& dt)
	{
		if (m_abort) return;
		if (m_queue.empty()) return;

		INVARIANT_CHECK;

		boost::int64_t dt_milliseconds = total_milliseconds(dt);
		if (dt_milliseconds > 3000) dt_milliseconds = 3000;

		// for each bandwidth channel, call update_quota(dt)

		std::vector<bandwidth_channel*> channels;

		queue_t tm;

		for (queue_t::iterator i = m_queue.begin();
			i != m_queue.end();)
		{
			if (i->peer->is_disconnecting())
			{
				m_queued_bytes -= i->request_size - i->assigned;

				// return all assigned quota to all the
				// bandwidth channels this peer belongs to
				for (int j = 0; j < bw_request::max_bandwidth_channels && i->channel[j]; ++j)
				{
					bandwidth_channel* bwc = i->channel[j];
					bwc->return_quota(i->assigned);
				}

				i->assigned = 0;
				tm.push_back(*i);
				i = m_queue.erase(i);
				continue;
			}
			for (int j = 0; j < bw_request::max_bandwidth_channels && i->channel[j]; ++j)
			{
				bandwidth_channel* bwc = i->channel[j];
				bwc->tmp = 0;
			}
			++i;
		}

		for (queue_t::iterator i = m_queue.begin()
			, end(m_queue.end()); i != end; ++i)
		{
			for (int j = 0; j < bw_request::max_bandwidth_channels && i->channel[j]; ++j)
			{
				bandwidth_channel* bwc = i->channel[j];
				if (bwc->tmp == 0) channels.push_back(bwc);
				TORRENT_ASSERT(INT_MAX - bwc->tmp > i->priority);
				bwc->tmp += i->priority;
			}
		}

		for (std::vector<bandwidth_channel*>::iterator i = channels.begin()
			, end(channels.end()); i != end; ++i)
		{
			(*i)->update_quota(int(dt_milliseconds));
		}

		for (queue_t::iterator i = m_queue.begin();
			i != m_queue.end();)
		{
			int a = i->assign_bandwidth();
			if (i->assigned == i->request_size
				|| (i->ttl <= 0 && i->assigned > 0))
			{
				a += i->request_size - i->assigned;
				TORRENT_ASSERT(i->assigned <= i->request_size);
				tm.push_back(*i);
				i = m_queue.erase(i);
			}
			else
			{
				++i;
			}
			m_queued_bytes -= a;
		}

		while (!tm.empty())
		{
			bw_request& bwr = tm.back();
			bwr.peer->assign_bandwidth(m_channel, bwr.assigned);
			tm.pop_back();
		}
	}
Exemplo n.º 14
0
bool rpc_manager::incoming(msg const& m, node_id* id
	, libtorrent::dht_settings const& settings)
{
	INVARIANT_CHECK;

	if (m_destructing) return false;

	// we only deal with replies and errors, not queries
	TORRENT_ASSERT(m.message.dict_find_string_value("y") == "r"
		|| m.message.dict_find_string_value("y") == "e");

	// if we don't have the transaction id in our
	// request list, ignore the packet

	std::string transaction_id = m.message.dict_find_string_value("t");
	if (transaction_id.empty()) return false;

	std::string::const_iterator i = transaction_id.begin();	
	int tid = transaction_id.size() != 2 ? -1 : io::read_uint16(i);

	observer_ptr o;
	std::pair<transactions_t::iterator, transactions_t::iterator> range = m_transactions.equal_range(tid);
	for (transactions_t::iterator i = range.first; i != range.second; ++i)
	{
		if (m.addr.address() != i->second->target_addr()) continue;
		o = i->second;
		i = m_transactions.erase(i);
		break;
	}

	if (!o)
	{
#ifndef TORRENT_DISABLE_LOGGING
		m_log->log(dht_logger::rpc_manager, "reply with unknown transaction id size: %d from %s"
			, int(transaction_id.size()), print_endpoint(m.addr).c_str());
#endif
		// this isn't necessarily because the other end is doing
		// something wrong. This can also happen when we restart
		// the node, and we prematurely abort all outstanding
		// requests. Also, this opens up a potential magnification
		// attack.
//		entry e;
//		incoming_error(e, "invalid transaction id");
//		m_sock->send_packet(e, m.addr, 0);
		return false;
	}

	time_point now = clock_type::now();

#ifndef TORRENT_DISABLE_LOGGING
	std::ofstream reply_stats("round_trip_ms.log", std::ios::app);
	reply_stats << m.addr << "\t" << total_milliseconds(now - o->sent())
		<< std::endl;
#endif

	bdecode_node ret_ent = m.message.dict_find_dict("r");
	if (!ret_ent)
	{
		// it may be an error
		ret_ent = m.message.dict_find("e");
		o->timeout();
		if (!ret_ent)
		{
			entry e;
			incoming_error(e, "missing 'r' key");
			m_sock->send_packet(e, m.addr, 0);
		}
		return false;
	}

	bdecode_node node_id_ent = ret_ent.dict_find_string("id");
	if (!node_id_ent || node_id_ent.string_length() != 20)
	{
		o->timeout();
		entry e;
		incoming_error(e, "missing 'id' key");
		m_sock->send_packet(e, m.addr, 0);
		return false;
	}

	node_id nid = node_id(node_id_ent.string_ptr());
	if (settings.enforce_node_id && !verify_id(nid, m.addr.address()))
	{
		o->timeout();
		entry e;
		incoming_error(e, "invalid node ID");
		m_sock->send_packet(e, m.addr, 0);
		return false;
	}

#ifndef TORRENT_DISABLE_LOGGING
	m_log->log(dht_logger::rpc_manager, "[%p] reply with transaction id: %d from %s"
		, o->algorithm(), int(transaction_id.size())
		, print_endpoint(m.addr).c_str());
#endif
	o->reply(m);
	*id = nid;

	int rtt = int(total_milliseconds(now - o->sent()));

	// we found an observer for this reply, hence the node is not spoofing
	// add it to the routing table
	return m_table.node_seen(*id, m.addr, rtt);
}