<commit_before>/*

Copyright (c) 2008, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * 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.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.

*/

#ifndef TORRENT_CREATE_TORRENT_HPP_INCLUDED
#define TORRENT_CREATE_TORRENT_HPP_INCLUDED

#include "libtorrent/bencode.hpp"
#include "libtorrent/peer_id.hpp"
#include "libtorrent/file_storage.hpp"
#include "libtorrent/file_pool.hpp"
#include "libtorrent/config.hpp"
#include "libtorrent/storage.hpp"
#include "libtorrent/hasher.hpp"

#include <vector>
#include <string>
#include <utility>

#ifdef _MSC_VER
#pragma warning(push, 1)
#endif

#include <boost/filesystem/path.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/optional.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/scoped_ptr.hpp>

#ifdef _MSC_VER
#pragma warning(pop)
#endif

namespace libtorrent
{
	namespace fs = boost::filesystem;
	namespace pt = boost::posix_time;

	struct TORRENT_EXPORT create_torrent
	{
		create_torrent(file_storage& fs, int piece_size);
		create_torrent(file_storage& fs);
		entry generate() const;

		file_storage const& files() const { return m_files; }

		void set_comment(char const* str);
		void set_creator(char const* str);
		void set_hash(int index, sha1_hash const& h);
		void add_url_seed(std::string const& url);
		void add_node(std::pair<std::string, int> const& node);
		void add_tracker(std::string const& url, int tier = 0);

		int num_pieces() const { return m_files.num_pieces(); }
		int piece_length() const { return m_files.piece_length(); }
		int piece_size(int i) const { return m_files.piece_size(i); }

	private:

		file_storage& m_files;

		// the urls to the trackers
		typedef std::pair<std::string, int> announce_entry;
		std::vector<announce_entry> m_urls;

		std::vector<std::string> m_url_seeds;

		std::vector<sha1_hash> m_piece_hash;

		// dht nodes to add to the routing table/bootstrap from
		typedef std::vector<std::pair<std::string, int> > nodes_t;
		nodes_t m_nodes;

		// the hash that identifies this torrent
		// is mutable because it's calculated
		// lazily
		mutable sha1_hash m_info_hash;

		// if a creation date is found in the torrent file
		// this will be set to that, otherwise it'll be
		// 1970, Jan 1
		pt::ptime m_creation_date;

		// if a comment is found in the torrent file
		// this will be set to that comment
		std::string m_comment;

		// an optional string naming the software used
		// to create the torrent file
		std::string m_created_by;

		// this is used when creating a torrent. If there's
		// only one file there are cases where it's impossible
		// to know if it should be written as a multifile torrent
		// or not. e.g. test/test  there's one file and one directory
		// and they have the same name.
		bool m_multifile;

		// this is true if the torrent is private. i.e., is should not
		// be announced on the dht
		bool m_private;
	};

	namespace detail
	{
		inline bool default_pred(boost::filesystem::path const&) { return true; }

		inline void nop(int i) {}

		template <class Pred>
		void add_files_impl(file_storage& fs, boost::filesystem::path const& p
			, boost::filesystem::path const& l, Pred pred)
		{
			using boost::filesystem::path;
			using boost::filesystem::directory_iterator;
			std::string const& leaf = l.leaf();
			if (leaf == ".." || leaf == ".") return;
			if (!pred(l)) return;
			path f(p / l);
			if (is_directory(f))
			{
				for (directory_iterator i(f), end; i != end; ++i)
					add_files_impl(fs, p, l / i->leaf(), pred);
			}
			else
			{
				fs.add_file(l, file_size(f));
			}
		}
	}

	template <class Pred>
	void add_files(file_storage& fs, boost::filesystem::path const& file, Pred p)
	{
		detail::add_files_impl(fs, complete(file).branch_path(), file.leaf(), p);
	}

	inline void add_files(file_storage& fs, boost::filesystem::path const& file)
	{
		detail::add_files_impl(fs, complete(file).branch_path(), file.leaf(), detail::default_pred);
	}

	template <class Fun>
	void set_piece_hashes(create_torrent& t, boost::filesystem::path const& p, Fun f)
	{
		file_pool fp;
		boost::scoped_ptr<storage_interface> st(
			default_storage_constructor(const_cast<file_storage&>(t.files()), p, fp));

		// calculate the hash for all pieces
		int num = t.num_pieces();
		std::vector<char> buf(t.piece_length());
		for (int i = 0; i < num; ++i)
		{
			// read hits the disk and will block. Progress should
			// be updated in between reads
			st->read(&buf[0], i, 0, t.piece_size(i));
			hasher h(&buf[0], t.piece_size(i));
			t.set_hash(i, h.final());
			f(i);
		}
	}

	inline void set_piece_hashes(create_torrent& t, boost::filesystem::path const& p)
	{
		set_piece_hashes(t, p, detail::nop);
	}

}

#endif

<commit_msg>add set_priv and priv to create_torrent<commit_after>/*

Copyright (c) 2008, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * 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.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.

*/

#ifndef TORRENT_CREATE_TORRENT_HPP_INCLUDED
#define TORRENT_CREATE_TORRENT_HPP_INCLUDED

#include "libtorrent/bencode.hpp"
#include "libtorrent/peer_id.hpp"
#include "libtorrent/file_storage.hpp"
#include "libtorrent/file_pool.hpp"
#include "libtorrent/config.hpp"
#include "libtorrent/storage.hpp"
#include "libtorrent/hasher.hpp"

#include <vector>
#include <string>
#include <utility>

#ifdef _MSC_VER
#pragma warning(push, 1)
#endif

#include <boost/filesystem/path.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/optional.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/scoped_ptr.hpp>

#ifdef _MSC_VER
#pragma warning(pop)
#endif

namespace libtorrent
{
	namespace fs = boost::filesystem;
	namespace pt = boost::posix_time;

	struct TORRENT_EXPORT create_torrent
	{
		create_torrent(file_storage& fs, int piece_size);
		create_torrent(file_storage& fs);
		entry generate() const;

		file_storage const& files() const { return m_files; }

		void set_comment(char const* str);
		void set_creator(char const* str);
		void set_hash(int index, sha1_hash const& h);
		void add_url_seed(std::string const& url);
		void add_node(std::pair<std::string, int> const& node);
		void add_tracker(std::string const& url, int tier = 0);
		void set_priv(bool p) const { return m_private = p; }

		int num_pieces() const { return m_files.num_pieces(); }
		int piece_length() const { return m_files.piece_length(); }
		int piece_size(int i) const { return m_files.piece_size(i); }
		bool priv() const { return m_private; }

	private:

		file_storage& m_files;

		// the urls to the trackers
		typedef std::pair<std::string, int> announce_entry;
		std::vector<announce_entry> m_urls;

		std::vector<std::string> m_url_seeds;

		std::vector<sha1_hash> m_piece_hash;

		// dht nodes to add to the routing table/bootstrap from
		typedef std::vector<std::pair<std::string, int> > nodes_t;
		nodes_t m_nodes;

		// the hash that identifies this torrent
		// is mutable because it's calculated
		// lazily
		mutable sha1_hash m_info_hash;

		// if a creation date is found in the torrent file
		// this will be set to that, otherwise it'll be
		// 1970, Jan 1
		pt::ptime m_creation_date;

		// if a comment is found in the torrent file
		// this will be set to that comment
		std::string m_comment;

		// an optional string naming the software used
		// to create the torrent file
		std::string m_created_by;

		// this is used when creating a torrent. If there's
		// only one file there are cases where it's impossible
		// to know if it should be written as a multifile torrent
		// or not. e.g. test/test  there's one file and one directory
		// and they have the same name.
		bool m_multifile;

		// this is true if the torrent is private. i.e., is should not
		// be announced on the dht
		bool m_private;
	};

	namespace detail
	{
		inline bool default_pred(boost::filesystem::path const&) { return true; }

		inline void nop(int i) {}

		template <class Pred>
		void add_files_impl(file_storage& fs, boost::filesystem::path const& p
			, boost::filesystem::path const& l, Pred pred)
		{
			using boost::filesystem::path;
			using boost::filesystem::directory_iterator;
			std::string const& leaf = l.leaf();
			if (leaf == ".." || leaf == ".") return;
			if (!pred(l)) return;
			path f(p / l);
			if (is_directory(f))
			{
				for (directory_iterator i(f), end; i != end; ++i)
					add_files_impl(fs, p, l / i->leaf(), pred);
			}
			else
			{
				fs.add_file(l, file_size(f));
			}
		}
	}

	template <class Pred>
	void add_files(file_storage& fs, boost::filesystem::path const& file, Pred p)
	{
		detail::add_files_impl(fs, complete(file).branch_path(), file.leaf(), p);
	}

	inline void add_files(file_storage& fs, boost::filesystem::path const& file)
	{
		detail::add_files_impl(fs, complete(file).branch_path(), file.leaf(), detail::default_pred);
	}

	template <class Fun>
	void set_piece_hashes(create_torrent& t, boost::filesystem::path const& p, Fun f)
	{
		file_pool fp;
		boost::scoped_ptr<storage_interface> st(
			default_storage_constructor(const_cast<file_storage&>(t.files()), p, fp));

		// calculate the hash for all pieces
		int num = t.num_pieces();
		std::vector<char> buf(t.piece_length());
		for (int i = 0; i < num; ++i)
		{
			// read hits the disk and will block. Progress should
			// be updated in between reads
			st->read(&buf[0], i, 0, t.piece_size(i));
			hasher h(&buf[0], t.piece_size(i));
			t.set_hash(i, h.final());
			f(i);
		}
	}

	inline void set_piece_hashes(create_torrent& t, boost::filesystem::path const& p)
	{
		set_piece_hashes(t, p, detail::nop);
	}

}

#endif

<|endoftext|>


<commit_before>/*

Copyright (c) 2003, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * 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.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.

*/

#ifndef TORRENT_TORRENT_HANDLE_HPP_INCLUDED
#define TORRENT_TORRENT_HANDLE_HPP_INCLUDED

#include <vector>
#include <set>

#ifdef _MSC_VER
#pragma warning(push, 1)
#endif

#include <boost/date_time/posix_time/posix_time_types.hpp>

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#include "libtorrent/peer_id.hpp"
#include "libtorrent/peer_info.hpp"
#include "libtorrent/piece_picker.hpp"
#include "libtorrent/torrent_info.hpp"
#include "libtorrent/time.hpp"
#include "libtorrent/config.hpp"
#include "libtorrent/storage.hpp"

namespace libtorrent
{
	namespace fs = boost::filesystem;

	namespace aux
	{
		struct session_impl;
		struct checker_impl;
	}

	struct torrent_plugin;

	struct TORRENT_EXPORT duplicate_torrent: std::exception
	{
		virtual const char* what() const throw()
		{ return "torrent already exists in session"; }
	};

	struct TORRENT_EXPORT invalid_handle: std::exception
	{
		virtual const char* what() const throw()
		{ return "invalid torrent handle used"; }
	};

	struct TORRENT_EXPORT torrent_status
	{
		torrent_status()
			: state(queued_for_checking)
			, paused(false)
			, progress(0.f)
			, total_download(0)
			, total_upload(0)
			, total_payload_download(0)
			, total_payload_upload(0)
			, total_failed_bytes(0)
			, total_redundant_bytes(0)
			, download_rate(0)
			, upload_rate(0)
			, download_payload_rate(0)
			, upload_payload_rate(0)
			, num_seeds(0)
			, num_peers(0)
			, num_complete(-1)
			, num_incomplete(-1)
			, list_seeds(0)
			, list_peers(0)
			, pieces(0)
			, num_pieces(0)
			, total_done(0)
			, total_wanted_done(0)
			, total_wanted(0)
			, distributed_copies(0.f)
			, block_size(0)
			, num_uploads(0)
			, num_connections(0)
			, uploads_limit(0)
			, connections_limit(0)
			, storage_mode(storage_mode_sparse)
		{}

		enum state_t
		{
			queued_for_checking,
			checking_files,
			connecting_to_tracker,
			downloading_metadata,
			downloading,
			finished,
			seeding,
			allocating
		};

		state_t state;
		bool paused;
		float progress;
		boost::posix_time::time_duration next_announce;
		boost::posix_time::time_duration announce_interval;

		std::string current_tracker;

		// transferred this session!
		// total, payload plus protocol
		size_type total_download;
		size_type total_upload;

		// payload only
		size_type total_payload_download;
		size_type total_payload_upload;

		// the amount of payload bytes that
		// has failed their hash test
		size_type total_failed_bytes;

		// the number of payload bytes that
		// has been received redundantly.
		size_type total_redundant_bytes;

		// current transfer rate
		// payload plus protocol
		float download_rate;
		float upload_rate;

		// the rate of payload that is
		// sent and received
		float download_payload_rate;
		float upload_payload_rate;

		// the number of peers this torrent is connected to
		// that are seeding.
		int num_seeds;

		// the number of peers this torrent
		// is connected to (including seeds).
		int num_peers;

		// if the tracker sends scrape info in its
		// announce reply, these fields will be
		// set to the total number of peers that
		// have the whole file and the total number
		// of peers that are still downloading
		int num_complete;
		int num_incomplete;

		// this is the number of seeds whose IP we know
		// but are not necessarily connected to
		int list_seeds;

		// this is the number of peers whose IP we know
		// (including seeds), but are not necessarily
		// connected to
		int list_peers;

		const std::vector<bool>* pieces;

		// this is the number of pieces the client has
		// downloaded. it is equal to:
		// std::accumulate(pieces->begin(), pieces->end());
		int num_pieces;

		// the number of bytes of the file we have
		// including pieces that may have been filtered
		// after we downloaded them
		size_type total_done;

		// the number of bytes we have of those that we
		// want. i.e. not counting bytes from pieces that
		// are filtered as not wanted.
		size_type total_wanted_done;

		// the total number of bytes we want to download
		// this may be smaller than the total torrent size
		// in case any pieces are filtered as not wanted
		size_type total_wanted;

		// the number of distributed copies of the file.
		// note that one copy may be spread out among many peers.
		//
		// the integer part tells how many copies
		//   there are of the rarest piece(s)
		//
		// the fractional part tells the fraction of pieces that
		//   have more copies than the rarest piece(s).
		float distributed_copies;

		// the block size that is used in this torrent. i.e.
		// the number of bytes each piece request asks for
		// and each bit in the download queue bitfield represents
		int block_size;

		int num_uploads;
		int num_connections;
		int uploads_limit;
		int connections_limit;

		// true if the torrent is saved in compact mode
		// false if it is saved in full allocation mode
		storage_mode_t storage_mode;
	};

	struct TORRENT_EXPORT block_info
	{
		enum block_state_t
		{ none, requested, writing, finished };

		tcp::endpoint peer;
		// number of bytes downloaded in this block
		unsigned bytes_progress:16;
		// the total number of bytes in this block
		unsigned block_size:16;
		// the state this block is in (see block_state_t)
		unsigned state:2;
		// the number of peers that has requested this block
		// typically 0 or 1. If > 1, this block is in
		// end game mode
		unsigned num_peers:14;
	};

	struct TORRENT_EXPORT partial_piece_info
	{
		enum { max_blocks_per_piece = 256 };
		int piece_index;
		int blocks_in_piece;
		// the number of blocks in the finished state
		int finished;
		// the number of blocks in the writing state
		int writing;
		// the number of blocks in the requested state
		int requested;
		block_info blocks[max_blocks_per_piece];
		enum state_t { none, slow, medium, fast };
		state_t piece_state;
	};

	struct TORRENT_EXPORT torrent_handle
	{
		friend class invariant_access;
		friend struct aux::session_impl;
		friend class torrent;

		torrent_handle(): m_ses(0), m_chk(0), m_info_hash(0) {}

		void get_peer_info(std::vector<peer_info>& v) const;
		bool send_chat_message(tcp::endpoint ip, std::string message) const;
		torrent_status status() const;
		void get_download_queue(std::vector<partial_piece_info>& queue) const;

		// fills the specified vector with the download progress [0, 1]
		// of each file in the torrent. The files are ordered as in
		// the torrent_info.
		void file_progress(std::vector<float>& progress);

		std::vector<announce_entry> const& trackers() const;
		void replace_trackers(std::vector<announce_entry> const&) const;

		void add_url_seed(std::string const& url) const;
		void remove_url_seed(std::string const& url) const;
		std::set<std::string> url_seeds() const;

#ifndef TORRENT_DISABLE_EXTENSIONS
		void add_extension(boost::function<boost::shared_ptr<torrent_plugin>(torrent*, void*)> const& ext
			, void* userdata = 0);
#endif

		bool has_metadata() const;
		const torrent_info& get_torrent_info() const;
		bool is_valid() const;

		bool is_seed() const;
		bool is_paused() const;
		void pause() const;
		void resume() const;

#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
		void resolve_countries(bool r);
		bool resolve_countries() const;
#endif

		// all these are deprecated, use piece
		// priority functions instead

		// ================ start deprecation ============

		// marks the piece with the given index as filtered
		// it will not be downloaded
		void filter_piece(int index, bool filter) const TORRENT_DEPRECATED;
		void filter_pieces(std::vector<bool> const& pieces) const TORRENT_DEPRECATED;
		bool is_piece_filtered(int index) const TORRENT_DEPRECATED;
		std::vector<bool> filtered_pieces() const TORRENT_DEPRECATED;
		// marks the file with the given index as filtered
		// it will not be downloaded
		void filter_files(std::vector<bool> const& files) const TORRENT_DEPRECATED;

		// ================ end deprecation ============

		void piece_availability(std::vector<int>& avail) const;

		// priority must be within the range [0, 7]
		void piece_priority(int index, int priority) const;
		int piece_priority(int index) const;

		void prioritize_pieces(std::vector<int> const& pieces) const;
		std::vector<int> piece_priorities() const;

		void prioritize_files(std::vector<int> const& files) const;

		// set the interface to bind outgoing connections
		// to.
		void use_interface(const char* net_interface) const;

		entry write_resume_data() const;

		// forces this torrent to reannounce
		// (make a rerequest from the tracker)
		void force_reannounce() const;

		// forces a reannounce in the specified amount of time.
		// This overrides the default announce interval, and no
		// announce will take place until the given time has
		// timed out.
		void force_reannounce(boost::posix_time::time_duration) const;

		// performs a scrape request
		void scrape_tracker() const;

		// returns the name of this torrent, in case it doesn't
		// have metadata it returns the name assigned to it
		// when it was added.
		std::string name() const;

		// TODO: add a feature where the user can tell the torrent
		// to finish all pieces currently in the pipeline, and then
		// abort the torrent.

		void set_upload_limit(int limit) const;
		int upload_limit() const;
		void set_download_limit(int limit) const;
		int download_limit() const;

		void set_sequenced_download_threshold(int threshold) const;

		void set_peer_upload_limit(tcp::endpoint ip, int limit) const;
		void set_peer_download_limit(tcp::endpoint ip, int limit) const;

		// manually connect a peer
		void connect_peer(tcp::endpoint const& adr, int source = 0) const;

		// valid ratios are 0 (infinite ratio) or [ 1.0 , inf )
		// the ratio is uploaded / downloaded. less than 1 is not allowed
		void set_ratio(float up_down_ratio) const;

		fs::path save_path() const;

		// -1 means unlimited unchokes
		void set_max_uploads(int max_uploads) const;

		// -1 means unlimited connections
		void set_max_connections(int max_connections) const;

		void set_tracker_login(std::string const& name
			, std::string const& password) const;

		// post condition: save_path() == save_path if true is returned
		void move_storage(fs::path const& save_path) const;

		const sha1_hash& info_hash() const
		{ return m_info_hash; }

		bool operator==(const torrent_handle& h) const
		{ return m_info_hash == h.m_info_hash; }

		bool operator!=(const torrent_handle& h) const
		{ return m_info_hash != h.m_info_hash; }

		bool operator<(const torrent_handle& h) const
		{ return m_info_hash < h.m_info_hash; }

	private:

		torrent_handle(aux::session_impl* s,
			aux::checker_impl* c,
			const sha1_hash& h)
			: m_ses(s)
			, m_chk(c)
			, m_info_hash(h)
		{
			TORRENT_ASSERT(m_ses != 0);
			TORRENT_ASSERT(m_chk != 0);
		}

#ifndef NDEBUG
		void check_invariant() const;
#endif

		aux::session_impl* m_ses;
		aux::checker_impl* m_chk;
		sha1_hash m_info_hash;

	};

}

#endif // TORRENT_TORRENT_HANDLE_HPP_INCLUDED

<commit_msg>removed downloading_metadata state. Fixes #188<commit_after>/*

Copyright (c) 2003, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * 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.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.

*/

#ifndef TORRENT_TORRENT_HANDLE_HPP_INCLUDED
#define TORRENT_TORRENT_HANDLE_HPP_INCLUDED

#include <vector>
#include <set>

#ifdef _MSC_VER
#pragma warning(push, 1)
#endif

#include <boost/date_time/posix_time/posix_time_types.hpp>

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#include "libtorrent/peer_id.hpp"
#include "libtorrent/peer_info.hpp"
#include "libtorrent/piece_picker.hpp"
#include "libtorrent/torrent_info.hpp"
#include "libtorrent/time.hpp"
#include "libtorrent/config.hpp"
#include "libtorrent/storage.hpp"

namespace libtorrent
{
	namespace fs = boost::filesystem;

	namespace aux
	{
		struct session_impl;
		struct checker_impl;
	}

	struct torrent_plugin;

	struct TORRENT_EXPORT duplicate_torrent: std::exception
	{
		virtual const char* what() const throw()
		{ return "torrent already exists in session"; }
	};

	struct TORRENT_EXPORT invalid_handle: std::exception
	{
		virtual const char* what() const throw()
		{ return "invalid torrent handle used"; }
	};

	struct TORRENT_EXPORT torrent_status
	{
		torrent_status()
			: state(queued_for_checking)
			, paused(false)
			, progress(0.f)
			, total_download(0)
			, total_upload(0)
			, total_payload_download(0)
			, total_payload_upload(0)
			, total_failed_bytes(0)
			, total_redundant_bytes(0)
			, download_rate(0)
			, upload_rate(0)
			, download_payload_rate(0)
			, upload_payload_rate(0)
			, num_seeds(0)
			, num_peers(0)
			, num_complete(-1)
			, num_incomplete(-1)
			, list_seeds(0)
			, list_peers(0)
			, pieces(0)
			, num_pieces(0)
			, total_done(0)
			, total_wanted_done(0)
			, total_wanted(0)
			, distributed_copies(0.f)
			, block_size(0)
			, num_uploads(0)
			, num_connections(0)
			, uploads_limit(0)
			, connections_limit(0)
			, storage_mode(storage_mode_sparse)
		{}

		enum state_t
		{
			queued_for_checking,
			checking_files,
			connecting_to_tracker,
			downloading,
			finished,
			seeding,
			allocating
		};

		state_t state;
		bool paused;
		float progress;
		boost::posix_time::time_duration next_announce;
		boost::posix_time::time_duration announce_interval;

		std::string current_tracker;

		// transferred this session!
		// total, payload plus protocol
		size_type total_download;
		size_type total_upload;

		// payload only
		size_type total_payload_download;
		size_type total_payload_upload;

		// the amount of payload bytes that
		// has failed their hash test
		size_type total_failed_bytes;

		// the number of payload bytes that
		// has been received redundantly.
		size_type total_redundant_bytes;

		// current transfer rate
		// payload plus protocol
		float download_rate;
		float upload_rate;

		// the rate of payload that is
		// sent and received
		float download_payload_rate;
		float upload_payload_rate;

		// the number of peers this torrent is connected to
		// that are seeding.
		int num_seeds;

		// the number of peers this torrent
		// is connected to (including seeds).
		int num_peers;

		// if the tracker sends scrape info in its
		// announce reply, these fields will be
		// set to the total number of peers that
		// have the whole file and the total number
		// of peers that are still downloading
		int num_complete;
		int num_incomplete;

		// this is the number of seeds whose IP we know
		// but are not necessarily connected to
		int list_seeds;

		// this is the number of peers whose IP we know
		// (including seeds), but are not necessarily
		// connected to
		int list_peers;

		const std::vector<bool>* pieces;

		// this is the number of pieces the client has
		// downloaded. it is equal to:
		// std::accumulate(pieces->begin(), pieces->end());
		int num_pieces;

		// the number of bytes of the file we have
		// including pieces that may have been filtered
		// after we downloaded them
		size_type total_done;

		// the number of bytes we have of those that we
		// want. i.e. not counting bytes from pieces that
		// are filtered as not wanted.
		size_type total_wanted_done;

		// the total number of bytes we want to download
		// this may be smaller than the total torrent size
		// in case any pieces are filtered as not wanted
		size_type total_wanted;

		// the number of distributed copies of the file.
		// note that one copy may be spread out among many peers.
		//
		// the integer part tells how many copies
		//   there are of the rarest piece(s)
		//
		// the fractional part tells the fraction of pieces that
		//   have more copies than the rarest piece(s).
		float distributed_copies;

		// the block size that is used in this torrent. i.e.
		// the number of bytes each piece request asks for
		// and each bit in the download queue bitfield represents
		int block_size;

		int num_uploads;
		int num_connections;
		int uploads_limit;
		int connections_limit;

		// true if the torrent is saved in compact mode
		// false if it is saved in full allocation mode
		storage_mode_t storage_mode;
	};

	struct TORRENT_EXPORT block_info
	{
		enum block_state_t
		{ none, requested, writing, finished };

		tcp::endpoint peer;
		// number of bytes downloaded in this block
		unsigned bytes_progress:16;
		// the total number of bytes in this block
		unsigned block_size:16;
		// the state this block is in (see block_state_t)
		unsigned state:2;
		// the number of peers that has requested this block
		// typically 0 or 1. If > 1, this block is in
		// end game mode
		unsigned num_peers:14;
	};

	struct TORRENT_EXPORT partial_piece_info
	{
		enum { max_blocks_per_piece = 256 };
		int piece_index;
		int blocks_in_piece;
		// the number of blocks in the finished state
		int finished;
		// the number of blocks in the writing state
		int writing;
		// the number of blocks in the requested state
		int requested;
		block_info blocks[max_blocks_per_piece];
		enum state_t { none, slow, medium, fast };
		state_t piece_state;
	};

	struct TORRENT_EXPORT torrent_handle
	{
		friend class invariant_access;
		friend struct aux::session_impl;
		friend class torrent;

		torrent_handle(): m_ses(0), m_chk(0), m_info_hash(0) {}

		void get_peer_info(std::vector<peer_info>& v) const;
		bool send_chat_message(tcp::endpoint ip, std::string message) const;
		torrent_status status() const;
		void get_download_queue(std::vector<partial_piece_info>& queue) const;

		// fills the specified vector with the download progress [0, 1]
		// of each file in the torrent. The files are ordered as in
		// the torrent_info.
		void file_progress(std::vector<float>& progress);

		std::vector<announce_entry> const& trackers() const;
		void replace_trackers(std::vector<announce_entry> const&) const;

		void add_url_seed(std::string const& url) const;
		void remove_url_seed(std::string const& url) const;
		std::set<std::string> url_seeds() const;

#ifndef TORRENT_DISABLE_EXTENSIONS
		void add_extension(boost::function<boost::shared_ptr<torrent_plugin>(torrent*, void*)> const& ext
			, void* userdata = 0);
#endif

		bool has_metadata() const;
		const torrent_info& get_torrent_info() const;
		bool is_valid() const;

		bool is_seed() const;
		bool is_paused() const;
		void pause() const;
		void resume() const;

#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
		void resolve_countries(bool r);
		bool resolve_countries() const;
#endif

		// all these are deprecated, use piece
		// priority functions instead

		// ================ start deprecation ============

		// marks the piece with the given index as filtered
		// it will not be downloaded
		void filter_piece(int index, bool filter) const TORRENT_DEPRECATED;
		void filter_pieces(std::vector<bool> const& pieces) const TORRENT_DEPRECATED;
		bool is_piece_filtered(int index) const TORRENT_DEPRECATED;
		std::vector<bool> filtered_pieces() const TORRENT_DEPRECATED;
		// marks the file with the given index as filtered
		// it will not be downloaded
		void filter_files(std::vector<bool> const& files) const TORRENT_DEPRECATED;

		// ================ end deprecation ============

		void piece_availability(std::vector<int>& avail) const;

		// priority must be within the range [0, 7]
		void piece_priority(int index, int priority) const;
		int piece_priority(int index) const;

		void prioritize_pieces(std::vector<int> const& pieces) const;
		std::vector<int> piece_priorities() const;

		void prioritize_files(std::vector<int> const& files) const;

		// set the interface to bind outgoing connections
		// to.
		void use_interface(const char* net_interface) const;

		entry write_resume_data() const;

		// forces this torrent to reannounce
		// (make a rerequest from the tracker)
		void force_reannounce() const;

		// forces a reannounce in the specified amount of time.
		// This overrides the default announce interval, and no
		// announce will take place until the given time has
		// timed out.
		void force_reannounce(boost::posix_time::time_duration) const;

		// performs a scrape request
		void scrape_tracker() const;

		// returns the name of this torrent, in case it doesn't
		// have metadata it returns the name assigned to it
		// when it was added.
		std::string name() const;

		// TODO: add a feature where the user can tell the torrent
		// to finish all pieces currently in the pipeline, and then
		// abort the torrent.

		void set_upload_limit(int limit) const;
		int upload_limit() const;
		void set_download_limit(int limit) const;
		int download_limit() const;

		void set_sequenced_download_threshold(int threshold) const;

		void set_peer_upload_limit(tcp::endpoint ip, int limit) const;
		void set_peer_download_limit(tcp::endpoint ip, int limit) const;

		// manually connect a peer
		void connect_peer(tcp::endpoint const& adr, int source = 0) const;

		// valid ratios are 0 (infinite ratio) or [ 1.0 , inf )
		// the ratio is uploaded / downloaded. less than 1 is not allowed
		void set_ratio(float up_down_ratio) const;

		fs::path save_path() const;

		// -1 means unlimited unchokes
		void set_max_uploads(int max_uploads) const;

		// -1 means unlimited connections
		void set_max_connections(int max_connections) const;

		void set_tracker_login(std::string const& name
			, std::string const& password) const;

		// post condition: save_path() == save_path if true is returned
		void move_storage(fs::path const& save_path) const;

		const sha1_hash& info_hash() const
		{ return m_info_hash; }

		bool operator==(const torrent_handle& h) const
		{ return m_info_hash == h.m_info_hash; }

		bool operator!=(const torrent_handle& h) const
		{ return m_info_hash != h.m_info_hash; }

		bool operator<(const torrent_handle& h) const
		{ return m_info_hash < h.m_info_hash; }

	private:

		torrent_handle(aux::session_impl* s,
			aux::checker_impl* c,
			const sha1_hash& h)
			: m_ses(s)
			, m_chk(c)
			, m_info_hash(h)
		{
			TORRENT_ASSERT(m_ses != 0);
			TORRENT_ASSERT(m_chk != 0);
		}

#ifndef NDEBUG
		void check_invariant() const;
#endif

		aux::session_impl* m_ses;
		aux::checker_impl* m_chk;
		sha1_hash m_info_hash;

	};

}

#endif // TORRENT_TORRENT_HANDLE_HPP_INCLUDED

<|endoftext|>


<commit_before>
#include <iostream>
#include <limits>
#include <random>

#include <gtest/gtest.h>

using namespace std;

extern "C" {
   #include <common/string_util.h>
}

#define CHECK_hex(num, bits)                      \
   do {                                           \
      memset(expected, 0xff, sizeof(expected));   \
      memset(got, 0xff, sizeof(got));             \
      u64 __val = num;                            \
      sprintf(expected, "%lx", __val);            \
      uitoa##bits##_hex(__val, got);              \
      ASSERT_STREQ(got, expected);                \
   } while (0)

#define CHECK_hex_fixed(num, bits)                \
   do {                                           \
      memset(expected, 0xff, sizeof(expected));   \
      memset(got, 0xff, sizeof(got));             \
      u64 __val = num;                            \
      if (bits == 32)                             \
         sprintf(expected, "%08lx", __val);       \
      else                                        \
         sprintf(expected, "%016lx", __val);      \
      uitoa##bits##_hex_fixed(__val, got);        \
      ASSERT_STREQ(got, expected);                \
   } while (0)

#define CHECK_udec(num, bits)                    \
   do {                                          \
      memset(expected, 0xff, sizeof(expected));  \
      memset(got, 0xff, sizeof(got));            \
      u64 __val = num;                           \
      sprintf(expected, "%lu", __val);           \
      uitoa##bits##_dec(__val, got);             \
      ASSERT_STREQ(got, expected);               \
   } while (0)

#define CHECK_sdec(num, bits)                    \
   do {                                          \
      memset(expected, 0xff, sizeof(expected));  \
      memset(got, 0xff, sizeof(got));            \
      u64 __val = num;                           \
      sprintf(expected, "%ld", __val);           \
      itoa##bits(__val, got);                    \
      ASSERT_STREQ(got, expected);               \
   } while (0)

TEST(itoa, u32_hex)
{
   char expected[32];
   char got[32];

   CHECK_hex(0, 32);
   CHECK_hex(numeric_limits<u32>::min(), 32);
   CHECK_hex(numeric_limits<u32>::max(), 32);
   CHECK_hex(numeric_limits<u32>::min() + 1, 32);
   CHECK_hex(numeric_limits<u32>::max() - 1, 32);

   random_device rdev;
   const auto seed = rdev();
   default_random_engine e(seed);
   lognormal_distribution<> dist(5.0, 3);

   for (int i = 0; i < 100000; i++) {
      CHECK_hex((u32)dist(e), 32);
   }
}

TEST(itoa, u64_hex)
{
   char expected[64];
   char got[64];

   CHECK_hex(0, 64);
   CHECK_hex(numeric_limits<u64>::min(), 64);
   CHECK_hex(numeric_limits<u64>::max(), 64);
   CHECK_hex(numeric_limits<u64>::min() + 1, 64);
   CHECK_hex(numeric_limits<u64>::max() - 1, 64);

   random_device rdev;
   const auto seed = rdev();
   default_random_engine e(seed);
   lognormal_distribution<> dist(12.0, 4);

   for (int i = 0; i < 100000; i++) {
      CHECK_hex((u64)dist(e), 64);
   }
}

TEST(itoa, u32_dec)
{
   char expected[32];
   char got[32];

   CHECK_udec(0, 32);
   CHECK_udec(numeric_limits<u32>::min(), 32);
   CHECK_udec(numeric_limits<u32>::max(), 32);
   CHECK_udec(numeric_limits<u32>::min() + 1, 32);
   CHECK_udec(numeric_limits<u32>::max() - 1, 32);

   random_device rdev;
   const auto seed = rdev();
   default_random_engine e(seed);
   lognormal_distribution<> dist(5.0, 3);

   for (int i = 0; i < 100000; i++) {
      CHECK_udec((u32)dist(e), 32);
   }
}

TEST(itoa, u64_dec)
{
   char expected[64];
   char got[64];

   CHECK_udec(0, 64);
   CHECK_udec(numeric_limits<u64>::min(), 64);
   CHECK_udec(numeric_limits<u64>::max(), 64);
   CHECK_udec(numeric_limits<u64>::min() + 1, 64);
   CHECK_udec(numeric_limits<u64>::max() - 1, 64);

   random_device rdev;
   const auto seed = rdev();
   default_random_engine e(seed);
   lognormal_distribution<> dist(12.0, 4.0);

   for (int i = 0; i < 100000; i++) {
      CHECK_udec((u32)dist(e), 64);
   }
}

TEST(itoa, u32_hex_fixed)
{
   char expected[32];
   char got[32];

   CHECK_hex_fixed(0, 32);
   CHECK_hex_fixed(numeric_limits<u32>::min(), 32);
   CHECK_hex_fixed(numeric_limits<u32>::max(), 32);
   CHECK_hex_fixed(numeric_limits<u32>::min() + 1, 32);
   CHECK_hex_fixed(numeric_limits<u32>::max() - 1, 32);

   random_device rdev;
   const auto seed = rdev();
   default_random_engine e(seed);
   lognormal_distribution<> dist(5.0, 3);

   for (int i = 0; i < 100000; i++) {
      CHECK_hex_fixed((u32)dist(e), 32);
   }
}

TEST(itoa, u64_hex_fixed)
{
   char expected[64];
   char got[64];

   CHECK_hex_fixed(0, 64);
   CHECK_hex_fixed(numeric_limits<u64>::min(), 64);
   CHECK_hex_fixed(numeric_limits<u64>::max(), 64);
   CHECK_hex_fixed(numeric_limits<u64>::min() + 1, 64);
   CHECK_hex_fixed(numeric_limits<u64>::max() - 1, 64);

   random_device rdev;
   const auto seed = rdev();
   default_random_engine e(seed);
   lognormal_distribution<> dist(12.0, 4);

   for (int i = 0; i < 100000; i++) {
      CHECK_hex_fixed((u64)dist(e), 64);
   }
}

TEST(itoa, s32_dec)
{
   char expected[32];
   char got[32];

   CHECK_sdec(0, 32);
   CHECK_sdec(numeric_limits<s32>::min(), 32);
   CHECK_sdec(numeric_limits<s32>::max(), 32);
   CHECK_sdec(numeric_limits<s32>::min() + 1, 32);
   CHECK_sdec(numeric_limits<s32>::max() - 1, 32);

   random_device rdev;
   const auto seed = rdev();
   default_random_engine e(seed);

   uniform_int_distribution<s32>
      dist(numeric_limits<s32>::min(), numeric_limits<s32>::max());

   for (int i = 0; i < 100000; i++) {
      CHECK_sdec((s32)dist(e), 32);
   }
}

TEST(itoa, s64_dec)
{
   char expected[64];
   char got[64];

   CHECK_sdec(0, 64);
   CHECK_sdec(numeric_limits<s64>::min(), 64);
   CHECK_sdec(numeric_limits<s64>::max(), 64);
   CHECK_sdec(numeric_limits<s64>::min() + 1, 64);
   CHECK_sdec(numeric_limits<s64>::max() - 1, 64);

   random_device rdev;
   const auto seed = rdev();
   default_random_engine e(seed);

   uniform_int_distribution<s64>
      dist(numeric_limits<s64>::min(), numeric_limits<s64>::max());

   for (int i = 0; i < 100000; i++) {
      CHECK_sdec((s64)dist(e), 64);
   }
}

<commit_msg>[gtests] Using C++'s features to remove the macros<commit_after>
#include <iostream>
#include <limits>
#include <random>
#include <string>
#include <type_traits>
#include <gtest/gtest.h>

using namespace std;

extern "C" {
   #include <common/string_util.h>
}

inline void itoa_wrapper(s32 val, char *buf) { itoa32(val, buf); }
inline void itoa_wrapper(s64 val, char *buf) { itoa64(val, buf); }
inline void itoa_wrapper(u32 val, char *buf) { uitoa32_dec(val, buf); }
inline void itoa_wrapper(u64 val, char *buf) { uitoa64_dec(val, buf); }

template <typename T>
inline void uitoa_hex_wrapper(T val, char *buf, bool fixed)
{
   abort();
}

template<>
inline void uitoa_hex_wrapper<u32>(u32 val, char *buf, bool fixed)
{
   if (!fixed)
      uitoa32_hex(val, buf);
   else
      uitoa32_hex_fixed(val, buf);
}

template<>
inline void uitoa_hex_wrapper<u64>(u64 val, char *buf, bool fixed)
{
   if (!fixed)
      uitoa64_hex(val, buf);
   else
      uitoa64_hex_fixed(val, buf);
}

template <typename T>
inline void sprintf_hex_wrapper(T val, char *buf, bool fixed)
{
   abort();
}

template <>
inline void sprintf_hex_wrapper<u32>(u32 val, char *buf, bool fixed)
{
   if (fixed)
      sprintf(buf, "%08x", val);
   else
      sprintf(buf, "%x", val);
}

template <>
inline void sprintf_hex_wrapper<u64>(u64 val, char *buf, bool fixed)
{
   if (fixed)
      sprintf(buf, "%016lx", val);
   else
      sprintf(buf, "%lx", val);
}

template <typename T, bool hex = false, bool fixed = false>
void check(T val)
{
   char expected[64];
   char got[64];

   memset(expected, '*', sizeof(expected));
   memset(got, '*', sizeof(got));

   if (!hex) {

      strcpy(expected, to_string(val).c_str());
      itoa_wrapper(val, got);

   } else {

      sprintf_hex_wrapper<T>(val, expected, fixed);
      uitoa_hex_wrapper<T>(val, got, fixed);

   }

   ASSERT_STREQ(got, expected);
}

template <typename T, bool hex = false, bool fixed = false>
void check_set()
{
   auto check_func = check<T, hex, fixed>;

   check_func(0);
   check_func(numeric_limits<u32>::min());
   check_func(numeric_limits<u32>::max());
   check_func(numeric_limits<u32>::min() + 1);
   check_func(numeric_limits<u32>::max() - 1);
}

TEST(itoa, u32_hex)
{
   typedef u32 T;
   auto check_func = check<T, true>;
   auto check_set_func = check_set<T, true>;

   ASSERT_NO_FATAL_FAILURE({ check_set_func(); });

   random_device rdev;
   const auto seed = rdev();
   default_random_engine e(seed);

   uniform_int_distribution<T>
      dist(numeric_limits<T>::min(), numeric_limits<T>::max());

   for (int i = 0; i < 100000; i++)
      ASSERT_NO_FATAL_FAILURE({ check_func(dist(e)); });
}

TEST(itoa, u64_hex)
{
   typedef u64 T;
   auto check_func = check<T, true>;
   auto check_set_func = check_set<T, true>;

   ASSERT_NO_FATAL_FAILURE({ check_set_func(); });

   random_device rdev;
   const auto seed = rdev();
   default_random_engine e(seed);

   uniform_int_distribution<T>
      dist(numeric_limits<T>::min(), numeric_limits<T>::max());

   for (int i = 0; i < 100000; i++)
      ASSERT_NO_FATAL_FAILURE({ check_func(dist(e)); });
}

TEST(itoa, u32_dec)
{
   typedef u32 T;
   auto check_func = check<T>;
   auto check_set_func = check_set<T>;

   ASSERT_NO_FATAL_FAILURE({ check_set_func(); });

   random_device rdev;
   const auto seed = rdev();
   default_random_engine e(seed);

   uniform_int_distribution<T>
      dist(numeric_limits<T>::min(), numeric_limits<T>::max());

   for (int i = 0; i < 100000; i++)
      ASSERT_NO_FATAL_FAILURE({ check_func(dist(e)); });
}

TEST(itoa, u64_dec)
{
   typedef u64 T;
   auto check_func = check<T>;
   auto check_set_func = check_set<T>;

   ASSERT_NO_FATAL_FAILURE({ check_set_func(); });

   random_device rdev;
   const auto seed = rdev();
   default_random_engine e(seed);

   uniform_int_distribution<T>
      dist(numeric_limits<T>::min(), numeric_limits<T>::max());

   for (int i = 0; i < 100000; i++)
      ASSERT_NO_FATAL_FAILURE({ check_func(dist(e)); });
}

TEST(itoa, u32_hex_fixed)
{
   typedef u32 T;
   auto check_func = check<T, true, true>;
   auto check_set_func = check_set<T, true, true>;

   ASSERT_NO_FATAL_FAILURE({ check_set_func(); });

   random_device rdev;
   const auto seed = rdev();
   default_random_engine e(seed);

   uniform_int_distribution<T>
      dist(numeric_limits<T>::min(), numeric_limits<T>::max());

   for (int i = 0; i < 100000; i++)
      ASSERT_NO_FATAL_FAILURE({ check_func(dist(e)); });
}

TEST(itoa, u64_hex_fixed)
{
   typedef u64 T;
   auto check_func = check<T, true, true>;
   auto check_set_func = check_set<T, true, true>;

   ASSERT_NO_FATAL_FAILURE({ check_set_func(); });

   random_device rdev;
   const auto seed = rdev();
   default_random_engine e(seed);

   uniform_int_distribution<T>
      dist(numeric_limits<T>::min(), numeric_limits<T>::max());

   for (int i = 0; i < 100000; i++)
      ASSERT_NO_FATAL_FAILURE({ check_func(dist(e)); });
}

TEST(itoa, s32_dec)
{
   typedef s32 T;
   auto check_func = check<T>;
   auto check_set_func = check_set<T>;

   ASSERT_NO_FATAL_FAILURE({ check_set_func(); });

   random_device rdev;
   const auto seed = rdev();
   default_random_engine e(seed);

   uniform_int_distribution<T>
      dist(numeric_limits<T>::min(), numeric_limits<T>::max());

   for (int i = 0; i < 100000; i++)
      ASSERT_NO_FATAL_FAILURE({ check_func(dist(e)); });
}

TEST(itoa, s64_dec)
{
   typedef s32 T;
   auto check_func = check<T>;
   auto check_set_func = check_set<T>;

   ASSERT_NO_FATAL_FAILURE({ check_set_func(); });

   random_device rdev;
   const auto seed = rdev();
   default_random_engine e(seed);

   uniform_int_distribution<T>
      dist(numeric_limits<T>::min(), numeric_limits<T>::max());

   for (int i = 0; i < 100000; i++)
      ASSERT_NO_FATAL_FAILURE({ check_func(dist(e)); });
}

<|endoftext|>


<commit_before>/*! \file uobject.cc
 *******************************************************************************

 File: uobject.cc\n
 Implementation of the UObject class.

 This file is part of
 %URBI Kernel, version __kernelversion__\n
 (c) Jean-Christophe Baillie, 2004-2006.

 Permission to use, copy, modify, and redistribute this software for
 non-commercial use is hereby granted.

 This software is provided "as is" without warranty of any kind,
 either expressed or implied, including but not limited to the
 implied warranties of fitness for a particular purpose.

 For more information, comments, bug reports: http://www.urbiforge.com

 **************************************************************************** */

#include <stdarg.h>
#include <stdio.h>
#include <list>
#include "userver.h"
#include "uobject.h"
using namespace urbi;
using namespace std;

#define LIBURBIDEBUG

//! Global definition of the starterlist
namespace urbi {

  UObject* lastUObject;

  STATIC_INSTANCE(UStartlist, objectlist);
  STATIC_INSTANCE(UStartlistHub, objecthublist);

  const string externalModuleTag = "__ExternalMessage__";

  UVarTable varmap;
  UTable functionmap;
  UTable monitormap;
  UTable accessmap;
  UTable eventmap;
  UTable eventendmap;

  UTimerTable timermap;
  UTimerTable updatemap;

  UVar& cast(UValue &v, UVar *) {
    return (*((UVar*)v.storage));
  };

  UBinary cast(UValue &v, UBinary *) {
	if (v.type != DATA_BINARY) {
	  return UBinary();
	}
	return UBinary(*v.binary);
  }

  UList cast(UValue &v, UList *) {
	if (v.type != DATA_LIST)
	  return UList();
	return UList(*v.list);
  }

  UObjectStruct cast(UValue &v, UObjectStruct*) {
	if (v.type != DATA_OBJECT)
	  return UObjectStruct();
	return UObjectStruct(*v.object);
  }

}

using namespace urbi;

void urbi::main(int argc, char *argv[]) {} // no effect here

// **************************************************************************
//! UGenericCallback constructor.
UGenericCallback::UGenericCallback(string type, string name, int size,  UTable &t) :
  name(name) , storage(0)
{
  nbparam = size;

  if ((type == "function") || (type== "event") || (type=="eventend")) {};

  t[this->name].push_back(this);

  if (type == "var") {

    HMvariabletab::iterator it = ::urbiserver->variabletab.find(name.c_str());
    if (it == ::urbiserver->variabletab.end()) {

      UVariable *variable = new UVariable(name.c_str(), new ::UValue());
      if (variable) variable->internalBinder.push_back(this);
    }
    else
      it->second->internalBinder.push_back(this);
  }

  if (type == "varaccess") {

    HMvariabletab::iterator it = ::urbiserver->variabletab.find(name.c_str());
    if (it == ::urbiserver->variabletab.end()) {

      UVariable *variable = new UVariable(name.c_str(), new ::UValue());
      if (variable) variable->internalAccessBinder.push_back(this);
    }
    else
      it->second->internalAccessBinder.push_back(this);
  }

  // Note pour la suite:
  // ucommand.cc:3342 => mise en place de bindings. C'est là que se trouve
  // l'info pour traiter les callback function/event
  //
  // Voir aussi uvariable.cc:354 pour gérer la mise à jour d'une variable =>
  // rien à faire du côté de UVar qui a un pointeur sur UVariable de toute
  // façon, mais il faut appeller les callback des variables monitorées
  //
  // Ensuite, chercher les /// EXTERNAL et gérer la version internal au même
  // endroit.
  //
  // A priori, l'affectation dans les UVar est reglée (UVar x;  x=42)
  //
  // Penser à sortir les méthodes de parsing des object UBinary et urbi::UValue,
  // ça n'a rien à faire dans le kernel.
  //
  // Mettre en place des castings pour les UVar et les urbi::UValue

  /* Principe de l'object UObjectHub:

  L'diée est d'avoir un object UObjectHub perso du genre:

  class myhub : UObjectHub {
    virtual void callmeAfterAllCallbacks();
  }

  callmeAfterAllCallbacks est appellé après l'appel concommitant de n callback
  de UObject appartenant au hub. Ca veut dire que si deux objets sont callbackés
  en même temps (pour ne pas dire au même tour de boucle), cette fonction est
  appellé après que les deux cb ai été executé. On peut mettre là le code qui
  envoit le message OPENR pour bouger les moteurs par exemple. Et on peut savoir
  quels sont les objets qui ont callbacké et préparer le tableau en fonction.
  Voir comment le hub et les objets partagent des données.

  L'autre idée est de permettre de définir au niveau de la couche OS-specific la
  notion de timer. Un hub peut demander à être reveillé à intervalles réguliers.
  Comme par hasard, dans le cas Aibo, il va demander une fréquence correspondant
  à la fréquence de rafraichissement des sensors et il sera appelé après que
  l'OS ai rangé les valeurs neuves des senseurs dans une structure accessible au
  hub. Le hub appelle ensuite les objets sous jacents et ceux ci transfèrent les
  valeurs de senseurs à leur variable associée.
  A priori, en créant des hubs différents, on peut avoir en principe des taux de
  rafraichissement variables selons les devices, par catégories. Ce n'est pas
  encore clair comment le kernel pourrait en tirer partie puisque pour l'instant
  le modèle est encore celui d'une execution monolithique de toutes les
  commandes de l'arbre à chaque tour. Donc, ça force à faire fonctionner le tout
  à la plus petite période demandée. Intuitivement, le kernel2 sera plus à même
  de gérer mais il faut voir si le kernel1 ne peut pas faire qqch d'intéressant
  aussi, ce n'est pas sur que non.

  Pour qu'un softdevice plugin se rattache à un UObjectHub, il suffit de passer
  son nom en paramètre au constructeur de UObject.

  NB: toutes ces structures ne sont bien entendues pas intialisées en static
  dans le vide intersidéral, mais sont gérée par une structure d'intialisation
  qui fait les choses au bon moment et dans le bon ordre (les hubs en premier,
  les UObjects ensuite, par exemple...). => étendre les baseURBIStarter pour les
  hubs? Pas forcément nécessaire.

   */

  /*
  if ((type == "event") || (type == "function"))
    URBI() << "external " << type << "(" << size << ") " << name <<";";
  */
};

//! UGenericCallback constructor.
UGenericCallback::UGenericCallback(string type, string name, UTable &t) :
  name(name) , storage(0)
{
  t[this->name].push_back(this);
  /*
  URBI() << "external " << type << " " << name <<";";
  */
};

UGenericCallback::~UGenericCallback()
{
};

UGenericCallback* createUCallback(string type, void (*fun) (), string funname,UTable &t)
{
  return ((UGenericCallback*) new UCallbackGlobalvoid0 (type,fun,funname,t));
}

// **************************************************************************
//! UTimerCallbacl constructor.

UTimerCallback::UTimerCallback(ufloat period, UTimerTable &tt) : period(period)
{
  tt.push_back(this);
  lastTimeCalled = -9999999;
}

UTimerCallback::~UTimerCallback()
{
}

// **************************************************************************
//  Monitoring functions

int voidfun() {/*echo("void fun call\n");*/};

//! Generic UVar monitoring without callback
void
urbi::USync(UVar &v)
{
  urbi::UNotifyChange(v,&voidfun);
}

//! UVar monitoring with callback
void
urbi::UNotifyChange(UVar &v, int (*fun) ())
{
  createUCallback("var",fun,v.get_name(), monitormap);
}

//! UVar monitoring with callback including a pointeur to the UVar&
void
urbi::UNotifyChange(UVar &v, int (*fun) (UVar&))
{
  UGenericCallback* cb = createUCallback("var",fun,v.get_name(), monitormap);
  if (cb) cb->storage = (void*)(&v);
}

//! UVar monitoring with callback including a pointeur to the UVar&
void
urbi::UNotifyAccess(UVar &v, int (*fun) (UVar&))
{
  UGenericCallback* cb = createUCallback("varaccess",fun,v.get_name(), accessmap);
  if (cb) cb->storage = (void*)(&v);
}

//! UVar monitoring with callback, based on var name: creates a hidden UVar
void
urbi::UNotifyChange(string varname, int (*fun) ())
{
  createUCallback("var",fun,varname, monitormap);
}

//! UVar monitoring with callback, based on var name: creates a hidden UVar
//! and pass it as a param in the callback
void
urbi::UNotifyChange(string varname, int (*fun) (UVar&))
{
  UVar *hidden = new UVar(varname);
  UGenericCallback* cb = createUCallback("var",fun,varname, monitormap);
  if (cb) cb->storage = (void*)(hidden);
}

//! Timer definition
void
urbi::USetTimer(ufloat t, int (*fun) ())
{
  new UTimerCallbacknoobj(t,fun,timermap);
}

// **************************************************************************
//! UObject constructor.
UObject::UObject(const string &s) :
  __name(s)
{
  objecthub = 0;
  lastUObject = this;
  UString tmps(__name.c_str()); // quelle merde ces UString!!!!
  UObj* tmpobj = new UObj(&tmps);

  for (urbi::UStartlist::iterator retr = urbi::objectlist->begin();
       retr != urbi::objectlist->end();
       retr++)
    if ((*retr)->name == __name)
      tmpobj->internalBinder = (*retr);

  // default
  derived = false;
  classname = __name;

  UBindVar(UObject,load);
  load = 1;
}

//! UObject destructor.
UObject::~UObject()
{
}

void
UObject::USetUpdate(ufloat t)
{
  period = t;
  new UTimerCallbackobj<UObject>(t, this, &UObject::update, updatemap);
}

/*
int
UObject::updateGlobal()
{
  update();
  for (UObjectList::iterator it = members.begin();
       it != members.end();
       it++)
    (*it)->updateGlobal();
}
*/

// **************************************************************************
//! UObjectHub constructor.

UObjectHub::UObjectHub(const string& s) : name(s)
{
}

//! UObjectHub destructor.
UObjectHub::~UObjectHub()
{
}

void
UObjectHub::USetUpdate(ufloat t)
{
  period = t;
  new UTimerCallbackobj<UObjectHub>(t, this, &UObjectHub::updateGlobal, updatemap);
}

int
UObjectHub::updateGlobal()
{
  for (UObjectList::iterator it = members.begin();
       it != members.end();
       it++)
    (*it)->update();
  update();
}

void
UObjectHub::addMember(UObject* obj)
{
  members.push_back(obj);
}

UObjectList*
UObjectHub::getSubClass(string subclass)
{
  UObjectList* res = new UObjectList();
  for (UObjectList::iterator it = members.begin();
       it != members.end();
       it++)
    if ((*it)->classname == subclass)
      res->push_back(*it);

  return(res);
}

//! retrieve a UObjectHub based on its name
urbi::UObjectHub*
urbi::getUObjectHub(string name) {

  for (urbi::UStartlistHub::iterator retr = urbi::objecthublist->begin();
       retr != urbi::objecthublist->end();
       retr++)
    if ((*retr)->name == name)
      return (*retr)->getUObjectHub();

  return 0;
}

//! retrieve a UObject based on its name
urbi::UObject*
urbi::getUObject(string name) {

  for (urbi::UStartlist::iterator retr = urbi::objectlist->begin();
       retr != urbi::objectlist->end();
       retr++)
    if ((*retr)->name == name)
      return (*retr)->getUObject();

  return 0;
}

//! echo method
void
urbi::echo(const char* format, ... ) {

  char tmpoutput[1024];

  va_list arg;
  va_start(arg, format);
  vsnprintf(tmpoutput, 1024, format, arg);
  va_end(arg);

  ::urbiserver->debug(tmpoutput);
}

<commit_msg>modified uobject.cc for visual c++ compatibility<commit_after>/*! \file uobject.cc
 *******************************************************************************

 File: uobject.cc\n
 Implementation of the UObject class.

 This file is part of
 %URBI Kernel, version __kernelversion__\n
 (c) Jean-Christophe Baillie, 2004-2006.

 Permission to use, copy, modify, and redistribute this software for
 non-commercial use is hereby granted.

 This software is provided "as is" without warranty of any kind,
 either expressed or implied, including but not limited to the
 implied warranties of fitness for a particular purpose.

 For more information, comments, bug reports: http://www.urbiforge.com

 **************************************************************************** */

#include <stdarg.h>
#include <stdio.h>
#include <list>
#include "userver.h"
#include "uobject.h"
using namespace urbi;
using namespace std;
#ifdef _MSC_VER
#define snprintf _snprintf
#define vsnprintf _vsnprintf
#endif
#define LIBURBIDEBUG

//! Global definition of the starterlist
namespace urbi {

  UObject* lastUObject;

  STATIC_INSTANCE(UStartlist, objectlist);
  STATIC_INSTANCE(UStartlistHub, objecthublist);

  const string externalModuleTag = "__ExternalMessage__";

  UVarTable varmap;
  UTable functionmap;
  UTable monitormap;
  UTable accessmap;
  UTable eventmap;
  UTable eventendmap;

  UTimerTable timermap;
  UTimerTable updatemap;

  UVar& cast(UValue &v, UVar *) {
    return (*((UVar*)v.storage));
  };

  UBinary cast(UValue &v, UBinary *) {
	if (v.type != DATA_BINARY) {
	  return UBinary();
	}
	return UBinary(*v.binary);
  }

  UList cast(UValue &v, UList *) {
	if (v.type != DATA_LIST)
	  return UList();
	return UList(*v.list);
  }

  UObjectStruct cast(UValue &v, UObjectStruct*) {
	if (v.type != DATA_OBJECT)
	  return UObjectStruct();
	return UObjectStruct(*v.object);
  }

}

using namespace urbi;

void urbi::main(int argc, char *argv[]) {} // no effect here

// **************************************************************************
//! UGenericCallback constructor.
UGenericCallback::UGenericCallback(string type, string name, int size,  UTable &t) :
  name(name) , storage(0)
{
  nbparam = size;

  if ((type == "function") || (type== "event") || (type=="eventend")) {};

  t[this->name].push_back(this);

  if (type == "var") {

    HMvariabletab::iterator it = ::urbiserver->variabletab.find(name.c_str());
    if (it == ::urbiserver->variabletab.end()) {

      UVariable *variable = new UVariable(name.c_str(), new ::UValue());
      if (variable) variable->internalBinder.push_back(this);
    }
    else
      it->second->internalBinder.push_back(this);
  }

  if (type == "varaccess") {

    HMvariabletab::iterator it = ::urbiserver->variabletab.find(name.c_str());
    if (it == ::urbiserver->variabletab.end()) {

      UVariable *variable = new UVariable(name.c_str(), new ::UValue());
      if (variable) variable->internalAccessBinder.push_back(this);
    }
    else
      it->second->internalAccessBinder.push_back(this);
  }

  // Note pour la suite:
  // ucommand.cc:3342 => mise en place de bindings. C'est là que se trouve
  // l'info pour traiter les callback function/event
  //
  // Voir aussi uvariable.cc:354 pour gérer la mise à jour d'une variable =>
  // rien à faire du côté de UVar qui a un pointeur sur UVariable de toute
  // façon, mais il faut appeller les callback des variables monitorées
  //
  // Ensuite, chercher les /// EXTERNAL et gérer la version internal au même
  // endroit.
  //
  // A priori, l'affectation dans les UVar est reglée (UVar x;  x=42)
  //
  // Penser à sortir les méthodes de parsing des object UBinary et urbi::UValue,
  // ça n'a rien à faire dans le kernel.
  //
  // Mettre en place des castings pour les UVar et les urbi::UValue

  /* Principe de l'object UObjectHub:

  L'diée est d'avoir un object UObjectHub perso du genre:

  class myhub : UObjectHub {
    virtual void callmeAfterAllCallbacks();
  }

  callmeAfterAllCallbacks est appellé après l'appel concommitant de n callback
  de UObject appartenant au hub. Ca veut dire que si deux objets sont callbackés
  en même temps (pour ne pas dire au même tour de boucle), cette fonction est
  appellé après que les deux cb ai été executé. On peut mettre là le code qui
  envoit le message OPENR pour bouger les moteurs par exemple. Et on peut savoir
  quels sont les objets qui ont callbacké et préparer le tableau en fonction.
  Voir comment le hub et les objets partagent des données.

  L'autre idée est de permettre de définir au niveau de la couche OS-specific la
  notion de timer. Un hub peut demander à être reveillé à intervalles réguliers.
  Comme par hasard, dans le cas Aibo, il va demander une fréquence correspondant
  à la fréquence de rafraichissement des sensors et il sera appelé après que
  l'OS ai rangé les valeurs neuves des senseurs dans une structure accessible au
  hub. Le hub appelle ensuite les objets sous jacents et ceux ci transfèrent les
  valeurs de senseurs à leur variable associée.
  A priori, en créant des hubs différents, on peut avoir en principe des taux de
  rafraichissement variables selons les devices, par catégories. Ce n'est pas
  encore clair comment le kernel pourrait en tirer partie puisque pour l'instant
  le modèle est encore celui d'une execution monolithique de toutes les
  commandes de l'arbre à chaque tour. Donc, ça force à faire fonctionner le tout
  à la plus petite période demandée. Intuitivement, le kernel2 sera plus à même
  de gérer mais il faut voir si le kernel1 ne peut pas faire qqch d'intéressant
  aussi, ce n'est pas sur que non.

  Pour qu'un softdevice plugin se rattache à un UObjectHub, il suffit de passer
  son nom en paramètre au constructeur de UObject.

  NB: toutes ces structures ne sont bien entendues pas intialisées en static
  dans le vide intersidéral, mais sont gérée par une structure d'intialisation
  qui fait les choses au bon moment et dans le bon ordre (les hubs en premier,
  les UObjects ensuite, par exemple...). => étendre les baseURBIStarter pour les
  hubs? Pas forcément nécessaire.

   */

  /*
  if ((type == "event") || (type == "function"))
    URBI() << "external " << type << "(" << size << ") " << name <<";";
  */
};

//! UGenericCallback constructor.
UGenericCallback::UGenericCallback(string type, string name, UTable &t) :
  name(name) , storage(0)
{
  t[this->name].push_back(this);
  /*
  URBI() << "external " << type << " " << name <<";";
  */
};

UGenericCallback::~UGenericCallback()
{
};

UGenericCallback* createUCallback(string type, void (*fun) (), string funname,UTable &t)
{
  return ((UGenericCallback*) new UCallbackGlobalvoid0 (type,fun,funname,t));
}

// **************************************************************************
//! UTimerCallbacl constructor.

UTimerCallback::UTimerCallback(ufloat period, UTimerTable &tt) : period(period)
{
  tt.push_back(this);
  lastTimeCalled = -9999999;
}

UTimerCallback::~UTimerCallback()
{
}

// **************************************************************************
//  Monitoring functions

int voidfun() {/*echo("void fun call\n");*/ return 0;};

//! Generic UVar monitoring without callback
void
urbi::USync(UVar &v)
{
  urbi::UNotifyChange(v,&voidfun);
}

//! UVar monitoring with callback
void
urbi::UNotifyChange(UVar &v, int (*fun) ())
{
  createUCallback("var",fun,v.get_name(), monitormap);
}

//! UVar monitoring with callback including a pointeur to the UVar&
void
urbi::UNotifyChange(UVar &v, int (*fun) (UVar&))
{
  UGenericCallback* cb = createUCallback("var",fun,v.get_name(), monitormap);
  if (cb) cb->storage = (void*)(&v);
}

//! UVar monitoring with callback including a pointeur to the UVar&
void
urbi::UNotifyAccess(UVar &v, int (*fun) (UVar&))
{
  UGenericCallback* cb = createUCallback("varaccess",fun,v.get_name(), accessmap);
  if (cb) cb->storage = (void*)(&v);
}

//! UVar monitoring with callback, based on var name: creates a hidden UVar
void
urbi::UNotifyChange(string varname, int (*fun) ())
{
  createUCallback("var",fun,varname, monitormap);
}

//! UVar monitoring with callback, based on var name: creates a hidden UVar
//! and pass it as a param in the callback
void
urbi::UNotifyChange(string varname, int (*fun) (UVar&))
{
  UVar *hidden = new UVar(varname);
  UGenericCallback* cb = createUCallback("var",fun,varname, monitormap);
  if (cb) cb->storage = (void*)(hidden);
}

//! Timer definition
void
urbi::USetTimer(ufloat t, int (*fun) ())
{
  new UTimerCallbacknoobj(t,fun,timermap);
}

// **************************************************************************
//! UObject constructor.
UObject::UObject(const string &s) :
  __name(s)
{
  objecthub = 0;
  lastUObject = this;
  UString tmps(__name.c_str()); // quelle merde ces UString!!!!
  UObj* tmpobj = new UObj(&tmps);

  for (urbi::UStartlist::iterator retr = urbi::objectlist->begin();
       retr != urbi::objectlist->end();
       retr++)
    if ((*retr)->name == __name)
      tmpobj->internalBinder = (*retr);

  // default
  derived = false;
  classname = __name;

  UBindVar(UObject,load);
  load = 1;
}

//! UObject destructor.
UObject::~UObject()
{
}

void
UObject::USetUpdate(ufloat t)
{
  period = t;
  new UTimerCallbackobj<UObject>(t, this, &UObject::update, updatemap);
}

/*
int
UObject::updateGlobal()
{
  update();
  for (UObjectList::iterator it = members.begin();
       it != members.end();
       it++)
    (*it)->updateGlobal();
}
*/

// **************************************************************************
//! UObjectHub constructor.

UObjectHub::UObjectHub(const string& s) : name(s)
{
}

//! UObjectHub destructor.
UObjectHub::~UObjectHub()
{
}

void
UObjectHub::USetUpdate(ufloat t)
{
  period = t;
  new UTimerCallbackobj<UObjectHub>(t, this, &UObjectHub::updateGlobal, updatemap);
}

int
UObjectHub::updateGlobal()
{
  for (UObjectList::iterator it = members.begin();
       it != members.end();
       it++)
    (*it)->update();
  update();
  return 0;
}

void
UObjectHub::addMember(UObject* obj)
{
  members.push_back(obj);
}

UObjectList*
UObjectHub::getSubClass(string subclass)
{
  UObjectList* res = new UObjectList();
  for (UObjectList::iterator it = members.begin();
       it != members.end();
       it++)
    if ((*it)->classname == subclass)
      res->push_back(*it);

  return(res);
}

//! retrieve a UObjectHub based on its name
urbi::UObjectHub*
urbi::getUObjectHub(string name) {

  for (urbi::UStartlistHub::iterator retr = urbi::objecthublist->begin();
       retr != urbi::objecthublist->end();
       retr++)
    if ((*retr)->name == name)
      return (*retr)->getUObjectHub();

  return 0;
}

//! retrieve a UObject based on its name
urbi::UObject*
urbi::getUObject(string name) {

  for (urbi::UStartlist::iterator retr = urbi::objectlist->begin();
       retr != urbi::objectlist->end();
       retr++)
    if ((*retr)->name == name)
      return (*retr)->getUObject();

  return 0;
}

//! echo method
void
urbi::echo(const char* format, ... ) {

  char tmpoutput[1024];

  va_list arg;
  va_start(arg, format);
  vsnprintf(tmpoutput, 1024, format, arg);
  va_end(arg);

  ::urbiserver->debug(tmpoutput);
}

<|endoftext|>


<commit_before>/*
 * Copyright 2015 Cloudius Systems
 */

#pragma once

#include <seastar/core/scollectd.hh>
#include <seastar/core/metrics_api.hh>

namespace seastar {

namespace scollectd {

using collectd_value  = seastar::metrics::impl::metric_value;

std::vector<collectd_value> get_collectd_value(
        const scollectd::type_instance_id& id);

std::vector<scollectd::type_instance_id> get_collectd_ids();

sstring get_collectd_description_str(const scollectd::type_instance_id&);

bool is_enabled(const scollectd::type_instance_id& id);
/**
 * Enable or disable collectd metrics on local instance
 * @id - the metric to enable or disable
 * @enable - should the collectd metrics be enable or disable
 */
void enable(const scollectd::type_instance_id& id, bool enable);

metrics::impl::value_map get_value_map();
}

}
<commit_msg>doc: scollectd_api: fix @param doc<commit_after>/*
 * Copyright 2015 Cloudius Systems
 */

#pragma once

#include <seastar/core/scollectd.hh>
#include <seastar/core/metrics_api.hh>

namespace seastar {

namespace scollectd {

using collectd_value  = seastar::metrics::impl::metric_value;

std::vector<collectd_value> get_collectd_value(
        const scollectd::type_instance_id& id);

std::vector<scollectd::type_instance_id> get_collectd_ids();

sstring get_collectd_description_str(const scollectd::type_instance_id&);

bool is_enabled(const scollectd::type_instance_id& id);
/**
 * Enable or disable collectd metrics on local instance
 * @param id - the metric to enable or disable
 * @param enable - should the collectd metrics be enable or disable
 */
void enable(const scollectd::type_instance_id& id, bool enable);

metrics::impl::value_map get_value_map();
}

}
<|endoftext|>


<commit_before>/**
 * @file llhost_test.cpp
 * @author Adroit
 * @date 2007-02
 * @brief llhost test cases.
 *
 * $LicenseInfo:firstyear=2007&license=viewergpl$
 *
 * Copyright (c) 2007-2009, Linden Research, Inc.
 *
 * Second Life Viewer Source Code
 * The source code in this file ("Source Code") is provided by Linden Lab
 * to you under the terms of the GNU General Public License, version 2.0
 * ("GPL"), unless you have obtained a separate licensing agreement
 * ("Other License"), formally executed by you and Linden Lab.  Terms of
 * the GPL can be found in doc/GPL-license.txt in this distribution, or
 * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
 *
 * There are special exceptions to the terms and conditions of the GPL as
 * it is applied to this Source Code. View the full text of the exception
 * in the file doc/FLOSS-exception.txt in this software distribution, or
 * online at
 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
 *
 * By copying, modifying or distributing this software, you acknowledge
 * that you have read and understood your obligations described above,
 * and agree to abide by those obligations.
 *
 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
 * COMPLETENESS OR PERFORMANCE.
 * $/LicenseInfo$
 */

#include "linden_common.h"

#include "../llhost.h"

#include "../test/lltut.h"

namespace tut
{
	struct host_data
	{
	};
	typedef test_group<host_data> host_test;
	typedef host_test::object host_object;
	tut::host_test host_testcase("llhost");

	template<> template<>
	void host_object::test<1>()
	{
		LLHost host;
		ensure("IP address is not NULL", (0 == host.getAddress()) && (0 == host.getPort()) && !host.isOk());
	}
	template<> template<>
	void host_object::test<2>()
	{
		U32 ip_addr = 0xc098017d;
		U32 port = 8080;
		LLHost host(ip_addr, port);
		ensure("IP address is invalid", ip_addr == host.getAddress());
		ensure("Port Number is invalid", port == host.getPort());
		ensure("IP address and port number both should be ok", host.isOk());
	}

	template<> template<>
	void host_object::test<3>()
	{
		const char* str = "192.168.1.1";
		U32 port = 8080;
		LLHost host(str, port);
		ensure("IP address could not be processed", (host.getAddress() == ip_string_to_u32(str)));
		ensure("Port Number is invalid", (port == host.getPort()));
	}

	template<> template<>
	void host_object::test<4>()
	{
		U32 ip = ip_string_to_u32("192.168.1.1");
		U32 port = 22;
		U64 ip_port = (((U64) ip) << 32) | port;
		LLHost host(ip_port);
		ensure("IP address is invalid", ip == host.getAddress());
		ensure("Port Number is invalid", port == host.getPort());
	}

	template<> template<>
	void host_object::test<5>()
	{
		std::string ip_port_string = "192.168.1.1:8080";
		U32 ip = ip_string_to_u32("192.168.1.1");
		U32 port = 8080;

		LLHost host(ip_port_string);
		ensure("IP address from IP:port is invalid", ip == host.getAddress());
		ensure("Port Number from from IP:port is invalid", port == host.getPort());
	}

	template<> template<>
	void host_object::test<6>()
	{
		U32 ip = 0xc098017d, port = 8080;
		LLHost host;
		host.set(ip,port);
		ensure("IP address is invalid", (ip == host.getAddress()));
		ensure("Port Number is invalid", (port == host.getPort()));
	}

	template<> template<>
	void host_object::test<7>()
	{
		const char* str = "192.168.1.1";
		U32 port = 8080, ip;
		LLHost host;
		host.set(str,port);
		ip = ip_string_to_u32(str);
		ensure("IP address is invalid", (ip == host.getAddress()));
		ensure("Port Number is invalid", (port == host.getPort()));

		str = "64.233.187.99";
		ip = ip_string_to_u32(str);
		host.setAddress(str);
		ensure("IP address is invalid", (ip == host.getAddress()));

		ip = 0xc098017b;
		host.setAddress(ip);
		ensure("IP address is invalid", (ip == host.getAddress()));
		// should still use the old port
		ensure("Port Number is invalid", (port == host.getPort()));

		port = 8084;
		host.setPort(port);
		ensure("Port Number is invalid", (port == host.getPort()));
		// should still use the old address
		ensure("IP address is invalid", (ip == host.getAddress()));
	}

	template<> template<>
	void host_object::test<8>()
	{
		const std::string str("192.168.1.1");
		U32 port = 8080;
		LLHost host;
		host.set(str,port);

		std::string ip_string = host.getIPString();
		ensure("Function Failed", (ip_string == str));

		std::string ip_string_port = host.getIPandPort();
		ensure("Function Failed", (ip_string_port == "192.168.1.1:8080"));
	}

//	getHostName()  and setHostByName
	template<> template<>
	void host_object::test<9>()
	{
		std::string hostStr = "google.com";
		LLHost host;
		host.setHostByName(hostStr);

		// reverse DNS will likely result in appending of some
		// sub-domain to the main hostname. so look for
		// the main domain name and not do the exact compare

		std::string hostname = host.getHostName();
/*==========================================================================*|
		// nat 2009-10-20: not sure this ensure() is such a good idea, at
		// least with "google.com". The logic below is failing for me with:
		// set 'google.com'; reported 'yx-in-f100.1e100.net'
		// Disabling test until we can replace it with something more robust.
		try
		{
			ensure("getHostName failed", hostname.find(hostStr) != std::string::npos);
		}
		catch (const std::exception&)
		{
			std::cerr << "set '" << hostStr << "'; reported '" << hostname << "'" << std::endl;
			throw;
		}
|*==========================================================================*/
	}

//	setHostByName for dotted IP
	template<> template<>
	void host_object::test<10>()
	{
		std::string hostStr = "64.233.167.99";
		LLHost host;
		host.setHostByName(hostStr);
		ensure("SetHostByName for dotted IP Address failed", host.getAddress() == ip_string_to_u32(hostStr.c_str()));
	}

	template<> template<>
	void host_object::test<11>()
	{
		LLHost host1(0xc098017d, 8080);
		LLHost host2 = host1;
		ensure("Both IP addresses are not same", (host1.getAddress() == host2.getAddress()));
		ensure("Both port numbers are not same", (host1.getPort() == host2.getPort()));
	}

	template<> template<>
	void host_object::test<12>()
	{
		LLHost host1("192.168.1.1", 8080);
		std::string str1 = "192.168.1.1:8080";
		std::ostringstream stream;
		stream << host1;
		ensure("Operator << failed", ( stream.str()== str1));

		// There is no istream >> llhost operator.
		//std::istringstream is(stream.str());
		//LLHost host2;
		//is >> host2;
		//ensure("Operator >> failed. Not compatible with <<", host1 == host2);
	}

	// operators ==, !=, <
	template<> template<>
	void host_object::test<13>()
	{
		U32 ip_addr = 0xc098017d;
		U32 port = 8080;
		LLHost host1(ip_addr, port);
		LLHost host2(ip_addr, port);
		ensure("operator== failed", host1 == host2);

		// change port
		host2.setPort(7070);
		ensure("operator!= failed", host1 != host2);

		// set port back to 8080 and change IP address now
		host2.setPort(8080);
		host2.setAddress(ip_addr+10);
		ensure("operator!= failed", host1 != host2);

		ensure("operator<  failed", host1 < host2);

		// set IP address back to same value and change port
		host2.setAddress(ip_addr);
		host2.setPort(host1.getPort() + 10);
		ensure("operator<  failed", host1 < host2);
	}

	// invalid ip address string
	template<> template<>
	void host_object::test<14>()
	{
		LLHost host1("10.0.1.2", 6143);
		ensure("10.0.1.2 should be a valid address", host1.isOk());

		LLHost host2("booger-brains", 6143);
		ensure("booger-brains should be an invalid ip addess", !host2.isOk());

		LLHost host3("255.255.255.255", 6143);
		ensure("255.255.255.255 should be valid broadcast address", host3.isOk());
	}
}
<commit_msg>skip() failing test rather than silently commenting out<commit_after>/**
 * @file llhost_test.cpp
 * @author Adroit
 * @date 2007-02
 * @brief llhost test cases.
 *
 * $LicenseInfo:firstyear=2007&license=viewergpl$
 *
 * Copyright (c) 2007-2009, Linden Research, Inc.
 *
 * Second Life Viewer Source Code
 * The source code in this file ("Source Code") is provided by Linden Lab
 * to you under the terms of the GNU General Public License, version 2.0
 * ("GPL"), unless you have obtained a separate licensing agreement
 * ("Other License"), formally executed by you and Linden Lab.  Terms of
 * the GPL can be found in doc/GPL-license.txt in this distribution, or
 * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
 *
 * There are special exceptions to the terms and conditions of the GPL as
 * it is applied to this Source Code. View the full text of the exception
 * in the file doc/FLOSS-exception.txt in this software distribution, or
 * online at
 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
 *
 * By copying, modifying or distributing this software, you acknowledge
 * that you have read and understood your obligations described above,
 * and agree to abide by those obligations.
 *
 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
 * COMPLETENESS OR PERFORMANCE.
 * $/LicenseInfo$
 */

#include "linden_common.h"

#include "../llhost.h"

#include "../test/lltut.h"

namespace tut
{
	struct host_data
	{
	};
	typedef test_group<host_data> host_test;
	typedef host_test::object host_object;
	tut::host_test host_testcase("llhost");

	template<> template<>
	void host_object::test<1>()
	{
		LLHost host;
		ensure("IP address is not NULL", (0 == host.getAddress()) && (0 == host.getPort()) && !host.isOk());
	}
	template<> template<>
	void host_object::test<2>()
	{
		U32 ip_addr = 0xc098017d;
		U32 port = 8080;
		LLHost host(ip_addr, port);
		ensure("IP address is invalid", ip_addr == host.getAddress());
		ensure("Port Number is invalid", port == host.getPort());
		ensure("IP address and port number both should be ok", host.isOk());
	}

	template<> template<>
	void host_object::test<3>()
	{
		const char* str = "192.168.1.1";
		U32 port = 8080;
		LLHost host(str, port);
		ensure("IP address could not be processed", (host.getAddress() == ip_string_to_u32(str)));
		ensure("Port Number is invalid", (port == host.getPort()));
	}

	template<> template<>
	void host_object::test<4>()
	{
		U32 ip = ip_string_to_u32("192.168.1.1");
		U32 port = 22;
		U64 ip_port = (((U64) ip) << 32) | port;
		LLHost host(ip_port);
		ensure("IP address is invalid", ip == host.getAddress());
		ensure("Port Number is invalid", port == host.getPort());
	}

	template<> template<>
	void host_object::test<5>()
	{
		std::string ip_port_string = "192.168.1.1:8080";
		U32 ip = ip_string_to_u32("192.168.1.1");
		U32 port = 8080;

		LLHost host(ip_port_string);
		ensure("IP address from IP:port is invalid", ip == host.getAddress());
		ensure("Port Number from from IP:port is invalid", port == host.getPort());
	}

	template<> template<>
	void host_object::test<6>()
	{
		U32 ip = 0xc098017d, port = 8080;
		LLHost host;
		host.set(ip,port);
		ensure("IP address is invalid", (ip == host.getAddress()));
		ensure("Port Number is invalid", (port == host.getPort()));
	}

	template<> template<>
	void host_object::test<7>()
	{
		const char* str = "192.168.1.1";
		U32 port = 8080, ip;
		LLHost host;
		host.set(str,port);
		ip = ip_string_to_u32(str);
		ensure("IP address is invalid", (ip == host.getAddress()));
		ensure("Port Number is invalid", (port == host.getPort()));

		str = "64.233.187.99";
		ip = ip_string_to_u32(str);
		host.setAddress(str);
		ensure("IP address is invalid", (ip == host.getAddress()));

		ip = 0xc098017b;
		host.setAddress(ip);
		ensure("IP address is invalid", (ip == host.getAddress()));
		// should still use the old port
		ensure("Port Number is invalid", (port == host.getPort()));

		port = 8084;
		host.setPort(port);
		ensure("Port Number is invalid", (port == host.getPort()));
		// should still use the old address
		ensure("IP address is invalid", (ip == host.getAddress()));
	}

	template<> template<>
	void host_object::test<8>()
	{
		const std::string str("192.168.1.1");
		U32 port = 8080;
		LLHost host;
		host.set(str,port);

		std::string ip_string = host.getIPString();
		ensure("Function Failed", (ip_string == str));

		std::string ip_string_port = host.getIPandPort();
		ensure("Function Failed", (ip_string_port == "192.168.1.1:8080"));
	}

//	getHostName()  and setHostByName
	template<> template<>
	void host_object::test<9>()
	{
		skip("setHostByName(\"google.com\"); getHostName() -> (e.g.) \"yx-in-f100.1e100.net\"");
		std::string hostStr = "google.com";
		LLHost host;
		host.setHostByName(hostStr);

		// reverse DNS will likely result in appending of some
		// sub-domain to the main hostname. so look for
		// the main domain name and not do the exact compare

		std::string hostname = host.getHostName();
		try
		{
			ensure("getHostName failed", hostname.find(hostStr) != std::string::npos);
		}
		catch (const std::exception&)
		{
			std::cerr << "set '" << hostStr << "'; reported '" << hostname << "'" << std::endl;
			throw;
		}
	}

//	setHostByName for dotted IP
	template<> template<>
	void host_object::test<10>()
	{
		std::string hostStr = "64.233.167.99";
		LLHost host;
		host.setHostByName(hostStr);
		ensure("SetHostByName for dotted IP Address failed", host.getAddress() == ip_string_to_u32(hostStr.c_str()));
	}

	template<> template<>
	void host_object::test<11>()
	{
		LLHost host1(0xc098017d, 8080);
		LLHost host2 = host1;
		ensure("Both IP addresses are not same", (host1.getAddress() == host2.getAddress()));
		ensure("Both port numbers are not same", (host1.getPort() == host2.getPort()));
	}

	template<> template<>
	void host_object::test<12>()
	{
		LLHost host1("192.168.1.1", 8080);
		std::string str1 = "192.168.1.1:8080";
		std::ostringstream stream;
		stream << host1;
		ensure("Operator << failed", ( stream.str()== str1));

		// There is no istream >> llhost operator.
		//std::istringstream is(stream.str());
		//LLHost host2;
		//is >> host2;
		//ensure("Operator >> failed. Not compatible with <<", host1 == host2);
	}

	// operators ==, !=, <
	template<> template<>
	void host_object::test<13>()
	{
		U32 ip_addr = 0xc098017d;
		U32 port = 8080;
		LLHost host1(ip_addr, port);
		LLHost host2(ip_addr, port);
		ensure("operator== failed", host1 == host2);

		// change port
		host2.setPort(7070);
		ensure("operator!= failed", host1 != host2);

		// set port back to 8080 and change IP address now
		host2.setPort(8080);
		host2.setAddress(ip_addr+10);
		ensure("operator!= failed", host1 != host2);

		ensure("operator<  failed", host1 < host2);

		// set IP address back to same value and change port
		host2.setAddress(ip_addr);
		host2.setPort(host1.getPort() + 10);
		ensure("operator<  failed", host1 < host2);
	}

	// invalid ip address string
	template<> template<>
	void host_object::test<14>()
	{
		LLHost host1("10.0.1.2", 6143);
		ensure("10.0.1.2 should be a valid address", host1.isOk());

		LLHost host2("booger-brains", 6143);
		ensure("booger-brains should be an invalid ip addess", !host2.isOk());

		LLHost host3("255.255.255.255", 6143);
		ensure("255.255.255.255 should be valid broadcast address", host3.isOk());
	}
}
<|endoftext|>