<commit_before>#ifndef IF3_WORLD_PRECOMPILED_HPP
#define IF3_WORLD_PRECOMPILED_HPP

#if defined(__APPLE__)
# define IF3_CONFIG_MACOSX
#elif defined(__linux__)
# define IF3_CONFIG_LINUX
#elif defined(WIN32) || defined( _MSC_VER )
# define IF3_CONFIG_WIN32
#endif

  // platform options
#if defined(IF3_CONFIG_WIN32)
# define IF3_CONFIG_NEW
# undef IF3_CONFIG_NEWNOTHROW
# undef IF3_CONFIG_THROW
#elif defined(IF3_CONFIG_MACOSX)
# define IF3_CONFIG_NEW
# undef IF3_CONFIG_NEWNOTHROW
# undef IF3_CONFIG_THROW
# define IF3_CONFIG_POSIX
# define IF3_CONFIG_PTHREADS
# define IF3_CONFIG_FORK
#elif defined(IF3_CONFIG_LINUX)
# define IF3_CONFIG_NEW
# undef IF3_CONFIG_NEWNOTHROW
# undef IF3_CONFIG_THROW
# define IF3_CONFIG_POSIX
# define IF3_CONFIG_PTHREADS
# define IF3_CONFIG_FORK
#else
# error please define one of IF3_CONFIG_WIN32 IF3_CONFIG_MACOSX IF3_CONFIG_LINUX
#endif

#ifndef IF3_CONFIG_DEBUG
# define IF3_CONFIG_DEBUG (1)
#endif

  // for win32 we need windows.h and friends
#if defined(IF3_CONFIG_WIN32)

# include <winsock2.h>
# include <windows.h>
# include <io.h>
# include <process.h>
#endif

#if defined(IF3_CONFIG_PTHREADS)
# ifndef __STL_PTHREADS
#  define __STL_PTHREADS
# endif
# define _PTHREADS 1
# include <pthread.h>
#endif

#if defined(IF3_CONFIG_POSIX)
# include <signal.h>
# include <sys/time.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <sys/wait.h>
# include <sys/mman.h>
# include <sys/stat.h>
# include <netdb.h>
# include <unistd.h>
# include <netinet/in.h>
# include <sys/poll.h>
# include <unistd.h>
# include <sys/socket.h>
# include <arpa/inet.h>
# include <net/if.h>
# include <sys/resource.h>
# include <sys/stat.h>
# include <fcntl.h>
# include <sys/types.h>
# include <syslog.h>
# include <pwd.h>
#endif

  // include the normal standard c library stuff
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include <stdarg.h>

#ifdef __cplusplus
# if defined(IF3_CONFIG_NEW)
#  include <new>
# endif

# include <string>
# include <iostream>
# include <sstream>
# include <list>
# include <valarray>
# include <vector>
# include <algorithm>
# include <exception>
# include <stdexcept>
# include <cstring>
# include <cstdlib>
# include <queue>
# include <deque>
# include <functional>
# include <tr1/functional>
# include <map>

# if defined(IF3_CONFIG_NEWNOTHROW)
#  define newnothrow new (std::nothrow)
# else
#  define newnothrow new
# endif

# if defined(IF3_CONFIG_THROW)
#  define if3_throw( a, b ) throw( a(b) )
# elif defined(IF3_CONFIG_POSIX)
#  define if3_throw( a, b ) do { fprintf(stderr,"%s(\"%s\")",#a,b); abort(); } while(0)
# elif defined(IF3_CONFIG_WIN32)
#  define if3_throw( a, b ) do { fprintf(stderr,"%s(\"%s\")",#a,b); abort(); } while(0)
# endif
#endif

namespace if3
{
  using tr1::function;

  template< typename T1, typename T2 > inline T1 lexical_cast ( const T2 &v )
  {
    T1 newval;
    std::stringstream os;

    if ( ! ( os << v ) || ! ( os >> newval ) )
    {
      if3_throw( std::invalid_argument, "lexical_cast" );
    }

    return newval;
  }

}

#endif

<commit_msg>fixed functional tr1 reference<commit_after>#ifndef IF3_WORLD_PRECOMPILED_HPP
#define IF3_WORLD_PRECOMPILED_HPP

#if defined(__APPLE__)
# define IF3_CONFIG_MACOSX
#elif defined(__linux__)
# define IF3_CONFIG_LINUX
#elif defined(WIN32) || defined( _MSC_VER )
# define IF3_CONFIG_WIN32
#endif

  // platform options
#if defined(IF3_CONFIG_WIN32)
# define IF3_CONFIG_NEW
# undef IF3_CONFIG_NEWNOTHROW
# undef IF3_CONFIG_THROW
#elif defined(IF3_CONFIG_MACOSX)
# define IF3_CONFIG_NEW
# undef IF3_CONFIG_NEWNOTHROW
# undef IF3_CONFIG_THROW
# define IF3_CONFIG_POSIX
# define IF3_CONFIG_PTHREADS
# define IF3_CONFIG_FORK
#elif defined(IF3_CONFIG_LINUX)
# define IF3_CONFIG_NEW
# undef IF3_CONFIG_NEWNOTHROW
# undef IF3_CONFIG_THROW
# define IF3_CONFIG_POSIX
# define IF3_CONFIG_PTHREADS
# define IF3_CONFIG_FORK
#else
# error please define one of IF3_CONFIG_WIN32 IF3_CONFIG_MACOSX IF3_CONFIG_LINUX
#endif

#ifndef IF3_CONFIG_DEBUG
# define IF3_CONFIG_DEBUG (1)
#endif

  // for win32 we need windows.h and friends
#if defined(IF3_CONFIG_WIN32)

# include <winsock2.h>
# include <windows.h>
# include <io.h>
# include <process.h>
#endif

#if defined(IF3_CONFIG_PTHREADS)
# ifndef __STL_PTHREADS
#  define __STL_PTHREADS
# endif
# define _PTHREADS 1
# include <pthread.h>
#endif

#if defined(IF3_CONFIG_POSIX)
# include <signal.h>
# include <sys/time.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <sys/wait.h>
# include <sys/mman.h>
# include <sys/stat.h>
# include <netdb.h>
# include <unistd.h>
# include <netinet/in.h>
# include <sys/poll.h>
# include <unistd.h>
# include <sys/socket.h>
# include <arpa/inet.h>
# include <net/if.h>
# include <sys/resource.h>
# include <sys/stat.h>
# include <fcntl.h>
# include <sys/types.h>
# include <syslog.h>
# include <pwd.h>
#endif

  // include the normal standard c library stuff
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include <stdarg.h>

#ifdef __cplusplus
# if defined(IF3_CONFIG_NEW)
#  include <new>
# endif

# include <string>
# include <iostream>
# include <sstream>
# include <list>
# include <valarray>
# include <vector>
# include <algorithm>
# include <exception>
# include <stdexcept>
# include <cstring>
# include <cstdlib>
# include <queue>
# include <deque>
# include <functional>
# include <tr1/functional>
# include <map>

# if defined(IF3_CONFIG_NEWNOTHROW)
#  define newnothrow new (std::nothrow)
# else
#  define newnothrow new
# endif

# if defined(IF3_CONFIG_THROW)
#  define if3_throw( a, b ) throw( a(b) )
# elif defined(IF3_CONFIG_POSIX)
#  define if3_throw( a, b ) do { fprintf(stderr,"%s(\"%s\")",#a,b); abort(); } while(0)
# elif defined(IF3_CONFIG_WIN32)
#  define if3_throw( a, b ) do { fprintf(stderr,"%s(\"%s\")",#a,b); abort(); } while(0)
# endif
#endif

namespace if3
{
  using std::tr1::function;

  template< typename T1, typename T2 > inline T1 lexical_cast ( const T2 &v )
  {
    T1 newval;
    std::stringstream os;

    if ( ! ( os << v ) || ! ( os >> newval ) )
    {
      if3_throw( std::invalid_argument, "lexical_cast" );
    }

    return newval;
  }

}

#endif

<|endoftext|>


<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_ERROR_CODE_HPP_INCLUDED
#define TORRENT_ERROR_CODE_HPP_INCLUDED

#include <boost/version.hpp>
#include <boost/shared_ptr.hpp>

#if BOOST_VERSION < 103500
#include <asio/error_code.hpp>
#else
#include <boost/system/error_code.hpp>
#endif

#include "libtorrent/config.hpp"

namespace libtorrent
{

	namespace errors
	{
		enum error_code_enum
		{
			no_error = 0,
			file_collision,
			failed_hash_check,
			torrent_is_no_dict,
			torrent_missing_info,
			torrent_info_no_dict,
			torrent_missing_piece_length,
			torrent_missing_name,
			torrent_invalid_name,
			torrent_invalid_length,
			torrent_file_parse_failed,
			torrent_missing_pieces,
			torrent_invalid_hashes,
			too_many_pieces_in_torrent,
			invalid_swarm_metadata,
			invalid_bencoding,
			no_files_in_torrent,
			invalid_escaped_string,
			session_is_closing,
			duplicate_torrent,
			invalid_torrent_handle,
			invalid_entry_type,
			missing_info_hash_in_uri,
			file_too_short,
			unsupported_url_protocol,
			url_parse_error,
			peer_sent_empty_piece,
			parse_failed,
			invalid_file_tag,
			missing_info_hash,
			mismatching_info_hash,
			invalid_hostname,
			invalid_port,
			port_blocked,
			expected_close_bracket_in_address,
			destructing_torrent,
			timed_out,
			upload_upload_connection,
			uninteresting_upload_peer,
			invalid_info_hash,
			torrent_paused,
			invalid_have,
			invalid_bitfield_size,
			too_many_requests_when_choked,
			invalid_piece,
			no_memory,
			torrent_aborted,
			self_connection,
			invalid_piece_size,
			timed_out_no_interest,
			timed_out_inactivity,
			timed_out_no_handshake,
			timed_out_no_request,
			invalid_choke,
			invalid_unchoke,
			invalid_interested,
			invalid_not_interested,
			invalid_request,
			invalid_hash_list,
			invalid_hash_piece,
			invalid_cancel,
			invalid_dht_port,
			invalid_suggest,
			invalid_have_all,
			invalid_have_none,
			invalid_reject,
			invalid_allow_fast,
			invalid_extended,
			invalid_message,
			sync_hash_not_found,
			invalid_encryption_constant,
			no_plaintext_mode,
			no_rc4_mode,
			unsupported_encryption_mode,
			unsupported_encryption_mode_selected,
			invalid_pad_size,
			invalid_encrypt_handshake,
			no_incoming_encrypted,
			no_incoming_regular,
			duplicate_peer_id,
			torrent_removed,
			packet_too_large,
			http_parse_error,
			http_error,
			missing_location,
			invalid_redirection,
			redirecting,
			invalid_range,
			no_content_length,
			banned_by_ip_filter,
			too_many_connections,
			peer_banned,
			stopping_torrent,
			too_many_corrupt_pieces,
			torrent_not_ready,
			peer_not_constructed,
			session_closing,
			optimistic_disconnect,
			torrent_finished,
			no_router,
			metadata_too_large,
			invalid_metadata_request,
			invalid_metadata_size,
			invalid_metadata_offset,
			invalid_metadata_message,
			pex_message_too_large,
			invalid_pex_message,
			invalid_lt_tracker_message,

// natpmp errors
			unsupported_protocol_version,
			natpmp_not_authorized,
			network_failure,
			no_resources,
			unsupported_opcode,

// fastresume errors
			missing_file_sizes,
			no_files_in_resume_data,
			missing_pieces,
			mismatching_number_of_files,
			mismatching_file_size,
			mismatching_file_timestamp,
			not_a_dictionary,
			invalid_blocks_per_piece,
			missing_slots,
			too_many_slots,
			invalid_slot_list,
			invalid_piece_index,
			pieces_need_reorder,
			reserved1,
			reserved2,
			reserved3,
			reserved4,
			reserved5,
			reserved6,
			reserved7,
			reserved8,
		};
	}

#if BOOST_VERSION < 103500
	typedef asio::error_code error_code;
	inline asio::error::error_category get_posix_category() { return asio::error::system_category; }
	inline asio::error::error_category get_system_category() { return asio::error::system_category; }

	extern TORRENT_EXPORT asio::error::error_category libtorrent_category;
#else

	class TORRENT_EXPORT boost::system::error_category;

	struct TORRENT_EXPORT libtorrent_error_category : boost::system::error_category
	{
		virtual const char* name() const;
		virtual std::string message(int ev) const;
		virtual boost::system::error_condition default_error_condition(int ev) const
		{ return boost::system::error_condition(ev, *this); }
	};

	extern TORRENT_EXPORT libtorrent_error_category libtorrent_category;

	using boost::system::error_code;
	inline boost::system::error_category const& get_system_category()
	{ return boost::system::get_system_category(); }
	inline boost::system::error_category const& get_posix_category()
#if BOOST_VERSION < 103600
	{ return boost::system::get_posix_category(); }
#else
	{ return boost::system::get_generic_category(); }
#endif
#endif

#ifndef BOOST_NO_EXCEPTIONS
	struct TORRENT_EXPORT libtorrent_exception: std::exception
	{
		libtorrent_exception(error_code const& s): m_error(s) {}
		virtual const char* what() const throw()
		{
			if (!m_msg) m_msg.reset(new std::string(m_error.message()));
			return m_msg->c_str();
		}
		virtual ~libtorrent_exception() throw() {}
		error_code error() const { return m_error; }
	private:
		error_code m_error;
		mutable boost::shared_ptr<std::string> m_msg;
	};
#endif
}

#endif

<commit_msg>remove useless declaration<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_ERROR_CODE_HPP_INCLUDED
#define TORRENT_ERROR_CODE_HPP_INCLUDED

#include <boost/version.hpp>
#include <boost/shared_ptr.hpp>

#if BOOST_VERSION < 103500
#include <asio/error_code.hpp>
#else
#include <boost/system/error_code.hpp>
#endif

#include "libtorrent/config.hpp"

namespace libtorrent
{

	namespace errors
	{
		enum error_code_enum
		{
			no_error = 0,
			file_collision,
			failed_hash_check,
			torrent_is_no_dict,
			torrent_missing_info,
			torrent_info_no_dict,
			torrent_missing_piece_length,
			torrent_missing_name,
			torrent_invalid_name,
			torrent_invalid_length,
			torrent_file_parse_failed,
			torrent_missing_pieces,
			torrent_invalid_hashes,
			too_many_pieces_in_torrent,
			invalid_swarm_metadata,
			invalid_bencoding,
			no_files_in_torrent,
			invalid_escaped_string,
			session_is_closing,
			duplicate_torrent,
			invalid_torrent_handle,
			invalid_entry_type,
			missing_info_hash_in_uri,
			file_too_short,
			unsupported_url_protocol,
			url_parse_error,
			peer_sent_empty_piece,
			parse_failed,
			invalid_file_tag,
			missing_info_hash,
			mismatching_info_hash,
			invalid_hostname,
			invalid_port,
			port_blocked,
			expected_close_bracket_in_address,
			destructing_torrent,
			timed_out,
			upload_upload_connection,
			uninteresting_upload_peer,
			invalid_info_hash,
			torrent_paused,
			invalid_have,
			invalid_bitfield_size,
			too_many_requests_when_choked,
			invalid_piece,
			no_memory,
			torrent_aborted,
			self_connection,
			invalid_piece_size,
			timed_out_no_interest,
			timed_out_inactivity,
			timed_out_no_handshake,
			timed_out_no_request,
			invalid_choke,
			invalid_unchoke,
			invalid_interested,
			invalid_not_interested,
			invalid_request,
			invalid_hash_list,
			invalid_hash_piece,
			invalid_cancel,
			invalid_dht_port,
			invalid_suggest,
			invalid_have_all,
			invalid_have_none,
			invalid_reject,
			invalid_allow_fast,
			invalid_extended,
			invalid_message,
			sync_hash_not_found,
			invalid_encryption_constant,
			no_plaintext_mode,
			no_rc4_mode,
			unsupported_encryption_mode,
			unsupported_encryption_mode_selected,
			invalid_pad_size,
			invalid_encrypt_handshake,
			no_incoming_encrypted,
			no_incoming_regular,
			duplicate_peer_id,
			torrent_removed,
			packet_too_large,
			http_parse_error,
			http_error,
			missing_location,
			invalid_redirection,
			redirecting,
			invalid_range,
			no_content_length,
			banned_by_ip_filter,
			too_many_connections,
			peer_banned,
			stopping_torrent,
			too_many_corrupt_pieces,
			torrent_not_ready,
			peer_not_constructed,
			session_closing,
			optimistic_disconnect,
			torrent_finished,
			no_router,
			metadata_too_large,
			invalid_metadata_request,
			invalid_metadata_size,
			invalid_metadata_offset,
			invalid_metadata_message,
			pex_message_too_large,
			invalid_pex_message,
			invalid_lt_tracker_message,

// natpmp errors
			unsupported_protocol_version,
			natpmp_not_authorized,
			network_failure,
			no_resources,
			unsupported_opcode,

// fastresume errors
			missing_file_sizes,
			no_files_in_resume_data,
			missing_pieces,
			mismatching_number_of_files,
			mismatching_file_size,
			mismatching_file_timestamp,
			not_a_dictionary,
			invalid_blocks_per_piece,
			missing_slots,
			too_many_slots,
			invalid_slot_list,
			invalid_piece_index,
			pieces_need_reorder,
			reserved1,
			reserved2,
			reserved3,
			reserved4,
			reserved5,
			reserved6,
			reserved7,
			reserved8,
		};
	}

#if BOOST_VERSION < 103500
	typedef asio::error_code error_code;
	inline asio::error::error_category get_posix_category() { return asio::error::system_category; }
	inline asio::error::error_category get_system_category() { return asio::error::system_category; }

	extern TORRENT_EXPORT asio::error::error_category libtorrent_category;
#else

	struct TORRENT_EXPORT libtorrent_error_category : boost::system::error_category
	{
		virtual const char* name() const;
		virtual std::string message(int ev) const;
		virtual boost::system::error_condition default_error_condition(int ev) const
		{ return boost::system::error_condition(ev, *this); }
	};

	extern TORRENT_EXPORT libtorrent_error_category libtorrent_category;

	using boost::system::error_code;
	inline boost::system::error_category const& get_system_category()
	{ return boost::system::get_system_category(); }
	inline boost::system::error_category const& get_posix_category()
#if BOOST_VERSION < 103600
	{ return boost::system::get_posix_category(); }
#else
	{ return boost::system::get_generic_category(); }
#endif
#endif

#ifndef BOOST_NO_EXCEPTIONS
	struct TORRENT_EXPORT libtorrent_exception: std::exception
	{
		libtorrent_exception(error_code const& s): m_error(s) {}
		virtual const char* what() const throw()
		{
			if (!m_msg) m_msg.reset(new std::string(m_error.message()));
			return m_msg->c_str();
		}
		virtual ~libtorrent_exception() throw() {}
		error_code error() const { return m_error; }
	private:
		error_code m_error;
		mutable boost::shared_ptr<std::string> m_msg;
	};
#endif
}

#endif

<|endoftext|>


<commit_before>/*

Copyright (c) 2006, 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_EXTENSIONS_HPP_INCLUDED
#define TORRENT_EXTENSIONS_HPP_INCLUDED

#ifndef TORRENT_DISABLE_EXTENSIONS

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

#include <boost/weak_ptr.hpp>

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#include <vector>
#include "libtorrent/config.hpp"
#include "libtorrent/buffer.hpp"

namespace libtorrent
{
	namespace aux { struct session_impl; }

	struct peer_plugin;
	class bt_peer_connection;
	struct peer_request;
	class peer_connection;
	class entry;
	struct lazy_entry;
	struct disk_buffer_holder;
	struct bitfield;
	class alert;
	struct torrent_plugin;

	struct TORRENT_EXPORT plugin
	{
		virtual ~plugin() {}

		virtual boost::shared_ptr<torrent_plugin> new_torrent(torrent* t, void* user)
		{ return boost::shared_ptr<torrent_plugin>(); }

		// called when plugin is added to a session
		virtual void added(boost::weak_ptr<aux::session_impl> s) {}

		// called when an alert is posted
		// alerts that are filtered are not
		// posted
		virtual void on_alert(alert const* a) {}

		// called once per second
		virtual void on_tick() {}

		// called when saving settings state
		virtual void save_state(entry& ent) const {}

		// called when loading settings state
		virtual void load_state(lazy_entry const& ent) {}
	};

	struct TORRENT_EXPORT torrent_plugin
	{
		virtual ~torrent_plugin() {}
		// throwing an exception closes the connection
		// returning a 0 pointer is valid and will not add
		// the peer_plugin to the peer_connection
		virtual boost::shared_ptr<peer_plugin> new_connection(peer_connection*)
		{ return boost::shared_ptr<peer_plugin>(); }

		virtual void on_piece_pass(int index) {}
		virtual void on_piece_failed(int index) {}

		// called aproximately once every second
		virtual void tick() {}

		// if true is returned, it means the handler handled the event,
		// and no other plugins will have their handlers called, and the
		// default behavior will be skipped
		virtual bool on_pause() { return false; }
		virtual bool on_resume() { return false; }

		// this is called when the initial checking of
		// files is completed.
		virtual void on_files_checked() {}

		// called when the torrent changes state
		// the state is one of torrent_status::state_t
		// enum members
		virtual void on_state(int s) {}
	};

	struct TORRENT_EXPORT peer_plugin
	{
		virtual ~peer_plugin() {}

		virtual char const* type() const { return ""; }

		// can add entries to the extension handshake
		// this is not called for web seeds
		virtual void add_handshake(entry&) {}

		// throwing an exception from any of the handlers (except add_handshake)
		// closes the connection

		// this is called when the initial BT handshake is received. Returning false
		// means that the other end doesn't support this extension and will remove
		// it from the list of plugins.
		// this is not called for web seeds
		virtual bool on_handshake(char const* reserved_bits) { return true; }

		// called when the extension handshake from the other end is received
		// if this returns false, it means that this extension isn't
		// supported by this peer. It will result in this peer_plugin
		// being removed from the peer_connection and destructed.
		// this is not called for web seeds
		virtual bool on_extension_handshake(lazy_entry const& h) { return true; }

		// returning true from any of the message handlers
		// indicates that the plugin has handeled the message.
		// it will break the plugin chain traversing and not let
		// anyone else handle the message, including the default
		// handler.

		virtual bool on_choke()
		{ return false; }

		virtual bool on_unchoke()
		{ return false; }

		virtual bool on_interested()
		{ return false; }

		virtual bool on_not_interested()
		{ return false; }

		virtual bool on_have(int index)
		{ return false; }

		virtual bool on_bitfield(bitfield const& bitfield)
		{ return false; }

		virtual bool on_have_all()
		{ return false; }

		virtual bool on_have_none()
		{ return false; }

		virtual bool on_allowed_fast(int index)
		{ return false; }

		virtual bool on_request(peer_request const& req)
		{ return false; }

		virtual bool on_piece(peer_request const& piece, disk_buffer_holder& data)
		{ return false; }

		virtual bool on_cancel(peer_request const& req)
		{ return false; }

		virtual bool on_reject(peer_request const& req)
		{ return false; }

		virtual bool on_suggest(int index)
		{ return false; }

		// called when an extended message is received. If returning true,
		// the message is not processed by any other plugin and if false
		// is returned the next plugin in the chain will receive it to
		// be able to handle it
		// this is not called for web seeds
		virtual bool on_extended(int length
			, int msg, buffer::const_interval body)
		{ return false; }

		// this is not called for web seeds
		virtual bool on_unknown_message(int length, int msg
			, buffer::const_interval body)
		{ return false; }

		// called when a piece that this peer participated in either
		// fails or passes the hash_check
		virtual void on_piece_pass(int index) {}
		virtual void on_piece_failed(int index) {}

		// called aproximately once every second
		virtual void tick() {}

		// called each time a request message is to be sent. If true
		// is returned, the original request message won't be sent and
		// no other plugin will have this function called.
		virtual bool write_request(peer_request const& r) { return false; }
	};

}

#endif

#endif // TORRENT_EXTENSIONS_HPP_INCLUDED

<commit_msg>fix build<commit_after>/*

Copyright (c) 2006, 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_EXTENSIONS_HPP_INCLUDED
#define TORRENT_EXTENSIONS_HPP_INCLUDED

#ifndef TORRENT_DISABLE_EXTENSIONS

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

#include <boost/weak_ptr.hpp>

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#include <vector>
#include "libtorrent/config.hpp"
#include "libtorrent/buffer.hpp"

namespace libtorrent
{
	namespace aux { struct session_impl; }

	struct peer_plugin;
	class bt_peer_connection;
	struct peer_request;
	class peer_connection;
	class entry;
	struct lazy_entry;
	struct disk_buffer_holder;
	struct bitfield;
	class alert;
	struct torrent_plugin;
	class torrent;

	struct TORRENT_EXPORT plugin
	{
		virtual ~plugin() {}

		virtual boost::shared_ptr<torrent_plugin> new_torrent(torrent* t, void* user)
		{ return boost::shared_ptr<torrent_plugin>(); }

		// called when plugin is added to a session
		virtual void added(boost::weak_ptr<aux::session_impl> s) {}

		// called when an alert is posted
		// alerts that are filtered are not
		// posted
		virtual void on_alert(alert const* a) {}

		// called once per second
		virtual void on_tick() {}

		// called when saving settings state
		virtual void save_state(entry& ent) const {}

		// called when loading settings state
		virtual void load_state(lazy_entry const& ent) {}
	};

	struct TORRENT_EXPORT torrent_plugin
	{
		virtual ~torrent_plugin() {}
		// throwing an exception closes the connection
		// returning a 0 pointer is valid and will not add
		// the peer_plugin to the peer_connection
		virtual boost::shared_ptr<peer_plugin> new_connection(peer_connection*)
		{ return boost::shared_ptr<peer_plugin>(); }

		virtual void on_piece_pass(int index) {}
		virtual void on_piece_failed(int index) {}

		// called aproximately once every second
		virtual void tick() {}

		// if true is returned, it means the handler handled the event,
		// and no other plugins will have their handlers called, and the
		// default behavior will be skipped
		virtual bool on_pause() { return false; }
		virtual bool on_resume() { return false; }

		// this is called when the initial checking of
		// files is completed.
		virtual void on_files_checked() {}

		// called when the torrent changes state
		// the state is one of torrent_status::state_t
		// enum members
		virtual void on_state(int s) {}
	};

	struct TORRENT_EXPORT peer_plugin
	{
		virtual ~peer_plugin() {}

		virtual char const* type() const { return ""; }

		// can add entries to the extension handshake
		// this is not called for web seeds
		virtual void add_handshake(entry&) {}

		// throwing an exception from any of the handlers (except add_handshake)
		// closes the connection

		// this is called when the initial BT handshake is received. Returning false
		// means that the other end doesn't support this extension and will remove
		// it from the list of plugins.
		// this is not called for web seeds
		virtual bool on_handshake(char const* reserved_bits) { return true; }

		// called when the extension handshake from the other end is received
		// if this returns false, it means that this extension isn't
		// supported by this peer. It will result in this peer_plugin
		// being removed from the peer_connection and destructed.
		// this is not called for web seeds
		virtual bool on_extension_handshake(lazy_entry const& h) { return true; }

		// returning true from any of the message handlers
		// indicates that the plugin has handeled the message.
		// it will break the plugin chain traversing and not let
		// anyone else handle the message, including the default
		// handler.

		virtual bool on_choke()
		{ return false; }

		virtual bool on_unchoke()
		{ return false; }

		virtual bool on_interested()
		{ return false; }

		virtual bool on_not_interested()
		{ return false; }

		virtual bool on_have(int index)
		{ return false; }

		virtual bool on_bitfield(bitfield const& bitfield)
		{ return false; }

		virtual bool on_have_all()
		{ return false; }

		virtual bool on_have_none()
		{ return false; }

		virtual bool on_allowed_fast(int index)
		{ return false; }

		virtual bool on_request(peer_request const& req)
		{ return false; }

		virtual bool on_piece(peer_request const& piece, disk_buffer_holder& data)
		{ return false; }

		virtual bool on_cancel(peer_request const& req)
		{ return false; }

		virtual bool on_reject(peer_request const& req)
		{ return false; }

		virtual bool on_suggest(int index)
		{ return false; }

		// called when an extended message is received. If returning true,
		// the message is not processed by any other plugin and if false
		// is returned the next plugin in the chain will receive it to
		// be able to handle it
		// this is not called for web seeds
		virtual bool on_extended(int length
			, int msg, buffer::const_interval body)
		{ return false; }

		// this is not called for web seeds
		virtual bool on_unknown_message(int length, int msg
			, buffer::const_interval body)
		{ return false; }

		// called when a piece that this peer participated in either
		// fails or passes the hash_check
		virtual void on_piece_pass(int index) {}
		virtual void on_piece_failed(int index) {}

		// called aproximately once every second
		virtual void tick() {}

		// called each time a request message is to be sent. If true
		// is returned, the original request message won't be sent and
		// no other plugin will have this function called.
		virtual bool write_request(peer_request const& r) { return false; }
	};

}

#endif

#endif // TORRENT_EXTENSIONS_HPP_INCLUDED

<|endoftext|>


<commit_before>/*

Copyright (c) 2008-2012, 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_SSL_STREAM_HPP_INCLUDED
#define TORRENT_SSL_STREAM_HPP_INCLUDED

#include "libtorrent/socket.hpp"
#include <boost/bind.hpp>
#if BOOST_VERSION < 103500
#include <asio/ssl.hpp>
#else
#include <boost/asio/ssl.hpp>
#endif
// openssl seems to believe it owns
// this name in every single scope
#undef set_key

namespace libtorrent {

template <class Stream>
class ssl_stream
{
public:

	explicit ssl_stream(io_service& io_service, asio::ssl::context& ctx)
		: m_sock(io_service, ctx)
	{
	}

	typedef typename asio::ssl::stream<Stream> sock_type;
	typedef typename sock_type::next_layer_type next_layer_type;
	typedef typename Stream::lowest_layer_type lowest_layer_type;
	typedef typename Stream::endpoint_type endpoint_type;
	typedef typename Stream::protocol_type protocol_type;

	void set_host_name(std::string name)
	{
#if OPENSSL_VERSION_NUMBER >= 0x90812f
		SSL_set_tlsext_host_name(m_sock.native_handle(), name.c_str());
#endif
	}

	template <class T>
	void set_verify_callback(T const& fun, error_code& ec)
	{ m_sock.set_verify_callback(fun, ec); }

#if BOOST_VERSION >= 104700
	SSL* native_handle() { return m_sock.native_handle(); }
#endif

	typedef boost::function<void(error_code const&)> handler_type;

	template <class Handler>
	void async_connect(endpoint_type const& endpoint, Handler const& handler)
	{
		// the connect is split up in the following steps:
		// 1. connect to peer
		// 2. perform SSL client handshake

		// to avoid unnecessary copying of the handler,
		// store it in a shared_ptr
		boost::shared_ptr<handler_type> h(new handler_type(handler));

		m_sock.next_layer().async_connect(endpoint
			, boost::bind(&ssl_stream::connected, this, _1, h));
	}

	template <class Handler>
	void async_accept_handshake(Handler const& handler)
	{
		// this is used for accepting SSL connections
		boost::shared_ptr<handler_type> h(new handler_type(handler));
		m_sock.async_handshake(asio::ssl::stream_base::server
			, boost::bind(&ssl_stream::handshake, this, _1, h));
	}

	void accept_handshake(error_code& ec)
	{
		// this is used for accepting SSL connections
		m_sock.handshake(asio::ssl::stream_base::server, ec);
	}

	template <class Handler>
	void async_shutdown(Handler const& handler)
	{
		m_sock.async_shutdown(handler);
	}

	void shutdown(error_code& ec)
	{
		m_sock.shutdown(ec);
	}

	template <class Mutable_Buffers, class Handler>
	void async_read_some(Mutable_Buffers const& buffers, Handler const& handler)
	{
		m_sock.async_read_some(buffers, handler);
	}

	template <class Mutable_Buffers>
	std::size_t read_some(Mutable_Buffers const& buffers, error_code& ec)
	{
		return m_sock.read_some(buffers, ec);
	}

#ifndef BOOST_NO_EXCEPTIONS
	template <class SettableSocketOption>
	void set_option(SettableSocketOption const& opt)
	{
		m_sock.next_layer().set_option(opt);
	}
#endif

	template <class SettableSocketOption>
	error_code set_option(SettableSocketOption const& opt, error_code& ec)
	{
		return m_sock.next_layer().set_option(opt, ec);
	}

#ifndef BOOST_NO_EXCEPTIONS
	template <class GettableSocketOption>
	void get_option(GettableSocketOption& opt)
	{
		m_sock.get_option(opt);
	}
#endif

	template <class GettableSocketOption>
	error_code get_option(GettableSocketOption& opt, error_code& ec)
	{
		return m_sock.get_option(opt, ec);
	}

#ifndef BOOST_NO_EXCEPTIONS
	template <class Mutable_Buffers>
	std::size_t read_some(Mutable_Buffers const& buffers)
	{
		return m_sock.read_some(buffers);
	}

	template <class IO_Control_Command>
	void io_control(IO_Control_Command& ioc)
	{
		m_sock.next_layer().io_control(ioc);
	}
#endif

	template <class IO_Control_Command>
	void io_control(IO_Control_Command& ioc, error_code& ec)
	{
		m_sock.next_layer().io_control(ioc, ec);
	}

	template <class Const_Buffers, class Handler>
	void async_write_some(Const_Buffers const& buffers, Handler const& handler)
	{
		m_sock.async_write_some(buffers, handler);
	}

	template <class Const_Buffers>
	std::size_t write_some(Const_Buffers const& buffers, error_code& ec)
	{
		return m_sock.write_some(buffers, ec);
	}

#ifndef BOOST_NO_EXCEPTIONS
	std::size_t available() const
	{ return const_cast<sock_type&>(m_sock).next_layer().available(); }
#endif

	std::size_t available(error_code& ec) const
	{ return const_cast<sock_type&>(m_sock).next_layer().available(ec); }

#ifndef BOOST_NO_EXCEPTIONS
	void bind(endpoint_type const& endpoint)
	{
		m_sock.next_layer().bind(endpoint);
	}
#endif

	void bind(endpoint_type const& endpoint, error_code& ec)
	{
		m_sock.next_layer().bind(endpoint, ec);
	}

#ifndef BOOST_NO_EXCEPTIONS
	void open(protocol_type const& p)
	{
		m_sock.next_layer().open(p);
	}
#endif

	void open(protocol_type const& p, error_code& ec)
	{
		m_sock.next_layer().open(p, ec);
	}

	bool is_open() const
	{
		return const_cast<sock_type&>(m_sock).next_layer().is_open();
	}

#ifndef BOOST_NO_EXCEPTIONS
	void close()
	{
		m_sock.next_layer().close();
	}
#endif

	void close(error_code& ec)
	{
		m_sock.next_layer().close(ec);
	}

#ifndef BOOST_NO_EXCEPTIONS
	endpoint_type remote_endpoint() const
	{
		return const_cast<sock_type&>(m_sock).next_layer().remote_endpoint();
	}
#endif

	endpoint_type remote_endpoint(error_code& ec) const
	{
		return const_cast<sock_type&>(m_sock).next_layer().remote_endpoint(ec);
	}

#ifndef BOOST_NO_EXCEPTIONS
	endpoint_type local_endpoint() const
	{
		return const_cast<sock_type&>(m_sock).next_layer().local_endpoint();
	}
#endif

	endpoint_type local_endpoint(error_code& ec) const
	{
		return const_cast<sock_type&>(m_sock).next_layer().local_endpoint(ec);
	}

	io_service& get_io_service()
	{
		return m_sock.get_io_service();
	}

	lowest_layer_type& lowest_layer()
	{
		return m_sock.lowest_layer();
	}

	next_layer_type& next_layer()
	{
		return m_sock.next_layer();
	}

private:

	void connected(error_code const& e, boost::shared_ptr<handler_type> h)
	{
		if (e)
		{
			(*h)(e);
			return;
		}

		m_sock.async_handshake(asio::ssl::stream_base::client
			, boost::bind(&ssl_stream::handshake, this, _1, h));
	}

	void handshake(error_code const& e, boost::shared_ptr<handler_type> h)
	{
		(*h)(e);
	}

	asio::ssl::stream<Stream> m_sock;
};

}

#endif

<commit_msg>fix ssl_stream typo<commit_after>/*

Copyright (c) 2008-2012, 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_SSL_STREAM_HPP_INCLUDED
#define TORRENT_SSL_STREAM_HPP_INCLUDED

#include "libtorrent/socket.hpp"
#include <boost/bind.hpp>
#if BOOST_VERSION < 103500
#include <asio/ssl.hpp>
#else
#include <boost/asio/ssl.hpp>
#endif
// openssl seems to believe it owns
// this name in every single scope
#undef set_key

namespace libtorrent {

template <class Stream>
class ssl_stream
{
public:

	explicit ssl_stream(io_service& io_service, asio::ssl::context& ctx)
		: m_sock(io_service, ctx)
	{
	}

	typedef typename asio::ssl::stream<Stream> sock_type;
	typedef typename sock_type::next_layer_type next_layer_type;
	typedef typename Stream::lowest_layer_type lowest_layer_type;
	typedef typename Stream::endpoint_type endpoint_type;
	typedef typename Stream::protocol_type protocol_type;

	void set_host_name(std::string name)
	{
#if OPENSSL_VERSION_NUMBER >= 0x90812f
		SSL_set_tlsext_host_name(m_sock.native_handle(), name.c_str());
#endif
	}

	template <class T>
	void set_verify_callback(T const& fun, error_code& ec)
	{ m_sock.set_verify_callback(fun, ec); }

#if BOOST_VERSION >= 104700
	SSL* native_handle() { return m_sock.native_handle(); }
#endif

	typedef boost::function<void(error_code const&)> handler_type;

	template <class Handler>
	void async_connect(endpoint_type const& endpoint, Handler const& handler)
	{
		// the connect is split up in the following steps:
		// 1. connect to peer
		// 2. perform SSL client handshake

		// to avoid unnecessary copying of the handler,
		// store it in a shared_ptr
		boost::shared_ptr<handler_type> h(new handler_type(handler));

		m_sock.next_layer().async_connect(endpoint
			, boost::bind(&ssl_stream::connected, this, _1, h));
	}

	template <class Handler>
	void async_accept_handshake(Handler const& handler)
	{
		// this is used for accepting SSL connections
		boost::shared_ptr<handler_type> h(new handler_type(handler));
		m_sock.async_handshake(asio::ssl::stream_base::server
			, boost::bind(&ssl_stream::handshake, this, _1, h));
	}

	void accept_handshake(error_code& ec)
	{
		// this is used for accepting SSL connections
		m_sock.handshake(asio::ssl::stream_base::server, ec);
	}

	template <class Handler>
	void async_shutdown(Handler const& handler)
	{
		m_sock.async_shutdown(handler);
	}

	void shutdown(error_code& ec)
	{
		m_sock.shutdown(ec);
	}

	template <class Mutable_Buffers, class Handler>
	void async_read_some(Mutable_Buffers const& buffers, Handler const& handler)
	{
		m_sock.async_read_some(buffers, handler);
	}

	template <class Mutable_Buffers>
	std::size_t read_some(Mutable_Buffers const& buffers, error_code& ec)
	{
		return m_sock.read_some(buffers, ec);
	}

#ifndef BOOST_NO_EXCEPTIONS
	template <class SettableSocketOption>
	void set_option(SettableSocketOption const& opt)
	{
		m_sock.next_layer().set_option(opt);
	}
#endif

	template <class SettableSocketOption>
	error_code set_option(SettableSocketOption const& opt, error_code& ec)
	{
		return m_sock.next_layer().set_option(opt, ec);
	}

#ifndef BOOST_NO_EXCEPTIONS
	template <class GettableSocketOption>
	void get_option(GettableSocketOption& opt)
	{
		m_sock.next_layer().get_option(opt);
	}
#endif

	template <class GettableSocketOption>
	error_code get_option(GettableSocketOption& opt, error_code& ec)
	{
		return m_sock.next_layer().get_option(opt, ec);
	}

#ifndef BOOST_NO_EXCEPTIONS
	template <class Mutable_Buffers>
	std::size_t read_some(Mutable_Buffers const& buffers)
	{
		return m_sock.read_some(buffers);
	}

	template <class IO_Control_Command>
	void io_control(IO_Control_Command& ioc)
	{
		m_sock.next_layer().io_control(ioc);
	}
#endif

	template <class IO_Control_Command>
	void io_control(IO_Control_Command& ioc, error_code& ec)
	{
		m_sock.next_layer().io_control(ioc, ec);
	}

	template <class Const_Buffers, class Handler>
	void async_write_some(Const_Buffers const& buffers, Handler const& handler)
	{
		m_sock.async_write_some(buffers, handler);
	}

	template <class Const_Buffers>
	std::size_t write_some(Const_Buffers const& buffers, error_code& ec)
	{
		return m_sock.write_some(buffers, ec);
	}

#ifndef BOOST_NO_EXCEPTIONS
	std::size_t available() const
	{ return const_cast<sock_type&>(m_sock).next_layer().available(); }
#endif

	std::size_t available(error_code& ec) const
	{ return const_cast<sock_type&>(m_sock).next_layer().available(ec); }

#ifndef BOOST_NO_EXCEPTIONS
	void bind(endpoint_type const& endpoint)
	{
		m_sock.next_layer().bind(endpoint);
	}
#endif

	void bind(endpoint_type const& endpoint, error_code& ec)
	{
		m_sock.next_layer().bind(endpoint, ec);
	}

#ifndef BOOST_NO_EXCEPTIONS
	void open(protocol_type const& p)
	{
		m_sock.next_layer().open(p);
	}
#endif

	void open(protocol_type const& p, error_code& ec)
	{
		m_sock.next_layer().open(p, ec);
	}

	bool is_open() const
	{
		return const_cast<sock_type&>(m_sock).next_layer().is_open();
	}

#ifndef BOOST_NO_EXCEPTIONS
	void close()
	{
		m_sock.next_layer().close();
	}
#endif

	void close(error_code& ec)
	{
		m_sock.next_layer().close(ec);
	}

#ifndef BOOST_NO_EXCEPTIONS
	endpoint_type remote_endpoint() const
	{
		return const_cast<sock_type&>(m_sock).next_layer().remote_endpoint();
	}
#endif

	endpoint_type remote_endpoint(error_code& ec) const
	{
		return const_cast<sock_type&>(m_sock).next_layer().remote_endpoint(ec);
	}

#ifndef BOOST_NO_EXCEPTIONS
	endpoint_type local_endpoint() const
	{
		return const_cast<sock_type&>(m_sock).next_layer().local_endpoint();
	}
#endif

	endpoint_type local_endpoint(error_code& ec) const
	{
		return const_cast<sock_type&>(m_sock).next_layer().local_endpoint(ec);
	}

	io_service& get_io_service()
	{
		return m_sock.get_io_service();
	}

	lowest_layer_type& lowest_layer()
	{
		return m_sock.lowest_layer();
	}

	next_layer_type& next_layer()
	{
		return m_sock.next_layer();
	}

private:

	void connected(error_code const& e, boost::shared_ptr<handler_type> h)
	{
		if (e)
		{
			(*h)(e);
			return;
		}

		m_sock.async_handshake(asio::ssl::stream_base::client
			, boost::bind(&ssl_stream::handshake, this, _1, h));
	}

	void handshake(error_code const& e, boost::shared_ptr<handler_type> h)
	{
		(*h)(e);
	}

	asio::ssl::stream<Stream> m_sock;
};

}

#endif

<|endoftext|>


<commit_before>/*

Copyright (c) 2009, 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_UTP_STREAM_HPP_INCLUDED
#define TORRENT_UTP_STREAM_HPP_INCLUDED

#include "libtorrent/connection_queue.hpp"
#include "libtorrent/proxy_base.hpp"
#include "libtorrent/udp_socket.hpp"
#include "libtorrent/io.hpp"
#include "libtorrent/packet_buffer.hpp"
#include "libtorrent/error_code.hpp"

#include <boost/bind.hpp>
#include <boost/function/function1.hpp>
#include <boost/function/function2.hpp>

#define CCONTROL_TARGET 100

namespace libtorrent
{
	struct utp_socket_manager;

	// some MTU and protocol header sizes constants
	enum
	{
		TORRENT_IPV4_HEADER = 20,
		TORRENT_IPV6_HEADER = 40,
		TORRENT_UDP_HEADER = 8,
		TORRENT_SOCKS5_HEADER = 6, // plus the size of the destination address

		TORRENT_ETHERNET_MTU = 1500,
		TORRENT_TEREDO_MTU = 1280,
		TORRENT_INET_MIN_MTU = 576,
		TORRENT_INET_MAX_MTU = 0xffff
	};

	// the point of the bif_endian_int is two-fold
	// one purpuse is to not have any alignment requirements
	// so that any byffer received from the network can be cast
	// to it and read as an integer of various sizes without
	// triggering a bus error. The other purpose is to convert
	// from network byte order to host byte order when read and
	// written, to offer a convenient interface to both interpreting
	// and writing network packets
	template <class T> struct big_endian_int
	{
		big_endian_int& operator=(T v)
		{
			char* p = m_storage;
			detail::write_impl(v, p);
			return *this;
		}
		operator T() const
		{
			const char* p = m_storage;
			return detail::read_impl(p, detail::type<T>());
		}
	private:
		char m_storage[sizeof(T)];
	};

	typedef big_endian_int<boost::uint64_t> be_uint64;
	typedef big_endian_int<boost::uint32_t> be_uint32;
	typedef big_endian_int<boost::uint16_t> be_uint16;
	typedef big_endian_int<boost::int64_t> be_int64;
	typedef big_endian_int<boost::int32_t> be_int32;
	typedef big_endian_int<boost::int16_t> be_int16;

/*
	uTP header from BEP 29

	0       4       8               16              24              32
	+-------+-------+---------------+---------------+---------------+
	| type  | ver   | extension     | connection_id                 |
	+-------+-------+---------------+---------------+---------------+
	| timestamp_microseconds                                        |
	+---------------+---------------+---------------+---------------+
	| timestamp_difference_microseconds                             |
	+---------------+---------------+---------------+---------------+
	| wnd_size                                                      |
	+---------------+---------------+---------------+---------------+
	| seq_nr                        | ack_nr                        |
	+---------------+---------------+---------------+---------------+

*/

	enum type { ST_DATA = 0, ST_FIN, ST_STATE, ST_RESET, ST_SYN, NUM_TYPES };

	struct utp_header
	{
		unsigned char type_ver;
		unsigned char extension;
		be_uint16 connection_id;
		be_uint32 timestamp_microseconds;
		be_uint32 timestamp_difference_microseconds;
		be_uint32 wnd_size;
		be_uint16 seq_nr;
		be_uint16 ack_nr;

		int get_type() const { return type_ver >> 4; }
		int get_version() const { return type_ver & 0xf; }
	};

struct utp_socket_impl;

utp_socket_impl* construct_utp_impl(boost::uint16_t recv_id
	, boost::uint16_t send_id, void* userdata
	, utp_socket_manager* sm);
void detach_utp_impl(utp_socket_impl* s);
void delete_utp_impl(utp_socket_impl* s);
bool should_delete(utp_socket_impl* s);
void tick_utp_impl(utp_socket_impl* s, ptime const& now);
void utp_init_mtu(utp_socket_impl* s, int link_mtu, int utp_mtu);
bool utp_incoming_packet(utp_socket_impl* s, char const* p
	, int size, udp::endpoint const& ep, ptime receive_time);
bool utp_match(utp_socket_impl* s, udp::endpoint const& ep, boost::uint16_t id);
udp::endpoint utp_remote_endpoint(utp_socket_impl* s);
boost::uint16_t utp_receive_id(utp_socket_impl* s);
int utp_socket_state(utp_socket_impl const* s);

#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
int socket_impl_size();
#endif

// this is the user-level stream interface to utp sockets.
// the reason why it's split up in a utp_stream class and
// an implementation class is because the socket state has
// to be able to out-live the user level socket. For instance
// when sending data on a stream and then closing it, the
// state holding the send buffer has to be kept around until
// it has been flushed, which may be longer than the client
// will keep the utp_stream object around for.
// for more details, see utp_socket_impl, which is analogous
// to the kernel state for a socket. It's defined in utp_stream.cpp
class TORRENT_EXPORT utp_stream
{
public:

	typedef stream_socket::endpoint_type endpoint_type;
	typedef stream_socket::protocol_type protocol_type;

	explicit utp_stream(asio::io_service& io_service);
	~utp_stream();

	// used for incoming connections
	void set_impl(utp_socket_impl* s);
	utp_socket_impl* get_impl();

#ifndef BOOST_NO_EXCEPTIONS
	template <class IO_Control_Command>
	void io_control(IO_Control_Command& ioc) {}
#endif

	template <class IO_Control_Command>
	void io_control(IO_Control_Command& ioc, error_code& ec) {}

#ifndef BOOST_NO_EXCEPTIONS
	void bind(endpoint_type const& endpoint) {}
#endif

	void bind(endpoint_type const& endpoint, error_code& ec);

#ifndef BOOST_NO_EXCEPTIONS
	template <class SettableSocketOption>
	void set_option(SettableSocketOption const& opt) {}
#endif

	template <class SettableSocketOption>
	error_code set_option(SettableSocketOption const& opt, error_code& ec) { return ec; }

	void close();
	void close(error_code const& ec) { close(); }
	bool is_open() const { return m_open; }

	int read_buffer_size() const;
	static void on_read(void* self, size_t bytes_transferred, error_code const& ec, bool kill);
	static void on_write(void* self, size_t bytes_transferred, error_code const& ec, bool kill);
	static void on_connect(void* self, error_code const& ec, bool kill);

	typedef void(*handler_t)(void*, size_t, error_code const&, bool);
	typedef void(*connect_handler_t)(void*, error_code const&, bool);

	void add_read_buffer(void* buf, size_t len);
	void set_read_handler(handler_t h);
	void add_write_buffer(void const* buf, size_t len);
	void set_write_handler(handler_t h);
	size_t read_some(bool clear_buffers);

	void do_connect(tcp::endpoint const& ep, connect_handler_t h);

	endpoint_type local_endpoint() const
	{
		error_code ec;
		return local_endpoint(ec);
	}

	endpoint_type local_endpoint(error_code& ec) const;

	endpoint_type remote_endpoint() const
	{
		error_code ec;
		return remote_endpoint(ec);
	}

	endpoint_type remote_endpoint(error_code& ec) const;

	std::size_t available() const;
	std::size_t available(error_code& ec) const { return available(); }

	asio::io_service& io_service()
	{ return m_io_service; }

	template <class Handler>
	void async_connect(endpoint_type const& endpoint, Handler const& handler)
	{
		if (!endpoint.address().is_v4())
		{
			error_code ec = asio::error::operation_not_supported;
			m_io_service.post(boost::bind<void>(handler, asio::error::operation_not_supported, 0));
			return;
		}

		if (m_impl == 0)
		{
			m_io_service.post(boost::bind<void>(handler, asio::error::not_connected, 0));
			return;
		}

		m_connect_handler = handler;
		do_connect(endpoint, &utp_stream::on_connect);
	}

	template <class Mutable_Buffers, class Handler>
	void async_read_some(Mutable_Buffers const& buffers, Handler const& handler)
	{
		if (m_impl == 0)
		{
			m_io_service.post(boost::bind<void>(handler, asio::error::not_connected, 0));
			return;
		}

		TORRENT_ASSERT(!m_read_handler);
		if (m_read_handler)
		{
			m_io_service.post(boost::bind<void>(handler, asio::error::operation_not_supported, 0));
			return;
		}
		for (typename Mutable_Buffers::const_iterator i = buffers.begin()
			, end(buffers.end()); i != end; ++i)
		{
			TORRENT_ASSERT(buffer_size(*i) > 0);
			using asio::buffer_cast;
			using asio::buffer_size;
			add_read_buffer(buffer_cast<void*>(*i), buffer_size(*i));
		}
		m_read_handler = handler;
		set_read_handler(&utp_stream::on_read);
	}

	void do_async_connect(endpoint_type const& ep
		, boost::function<void(error_code const&)> const& handler);

	template <class Protocol>
	void open(Protocol const& p, error_code& ec)
	{ m_open = true; }

	template <class Protocol>
	void open(Protocol const& p)
	{ m_open = true; }

	template <class Mutable_Buffers>
	std::size_t read_some(Mutable_Buffers const& buffers, error_code& ec)
	{
		TORRENT_ASSERT(!m_read_handler);
		if (m_impl == 0)
		{
			ec = asio::error::not_connected;
			return 0;
		}

		if (read_buffer_size() == 0)
		{
			ec = asio::error::would_block;
			return 0;
		}
#ifdef TORRENT_DEBUG
		size_t buf_size = 0;
#endif

		for (typename Mutable_Buffers::const_iterator i = buffers.begin()
			, end(buffers.end()); i != end; ++i)
		{
			using asio::buffer_cast;
			using asio::buffer_size;
			add_read_buffer(buffer_cast<void*>(*i), buffer_size(*i));
#ifdef TORRENT_DEBUG
			buf_size += buffer_size(*i);
#endif
		}
		std::size_t ret = read_some(true);
		TORRENT_ASSERT(int(ret) <= buf_size);
		TORRENT_ASSERT(ret > 0);
		return ret;
	}

	template <class Const_Buffers>
	std::size_t write_some(Const_Buffers const& buffers, error_code& ec)
	{
		// TODO: implement
		return 0;
	}

	template <class Const_Buffers, class Handler>
	void async_write_some(Const_Buffers const& buffers, Handler const& handler)
	{
		if (m_impl == 0)
		{
			m_io_service.post(boost::bind<void>(handler, asio::error::not_connected, 0));
			return;
		}

		TORRENT_ASSERT(!m_write_handler);
		if (m_write_handler)
		{
			m_io_service.post(boost::bind<void>(handler, asio::error::operation_not_supported, 0));
			return;
		}

		for (typename Const_Buffers::const_iterator i = buffers.begin()
			, end(buffers.end()); i != end; ++i)
		{
			TORRENT_ASSERT(buffer_size(*i) > 0);
			using asio::buffer_cast;
			using asio::buffer_size;
			add_write_buffer((void*)buffer_cast<void const*>(*i), buffer_size(*i));
		}
		m_write_handler = handler;
		set_write_handler(&utp_stream::on_write);
	}

//private:

	void cancel_handlers(error_code const&);

	boost::function1<void, error_code const&> m_connect_handler;
	boost::function2<void, error_code const&, std::size_t> m_read_handler;
	boost::function2<void, error_code const&, std::size_t> m_write_handler;

	asio::io_service& m_io_service;
	utp_socket_impl* m_impl;
	bool m_open;
};

}

#endif
<commit_msg>fix warning in utp_stream<commit_after>/*

Copyright (c) 2009, 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_UTP_STREAM_HPP_INCLUDED
#define TORRENT_UTP_STREAM_HPP_INCLUDED

#include "libtorrent/connection_queue.hpp"
#include "libtorrent/proxy_base.hpp"
#include "libtorrent/udp_socket.hpp"
#include "libtorrent/io.hpp"
#include "libtorrent/packet_buffer.hpp"
#include "libtorrent/error_code.hpp"

#include <boost/bind.hpp>
#include <boost/function/function1.hpp>
#include <boost/function/function2.hpp>

#define CCONTROL_TARGET 100

namespace libtorrent
{
	struct utp_socket_manager;

	// some MTU and protocol header sizes constants
	enum
	{
		TORRENT_IPV4_HEADER = 20,
		TORRENT_IPV6_HEADER = 40,
		TORRENT_UDP_HEADER = 8,
		TORRENT_SOCKS5_HEADER = 6, // plus the size of the destination address

		TORRENT_ETHERNET_MTU = 1500,
		TORRENT_TEREDO_MTU = 1280,
		TORRENT_INET_MIN_MTU = 576,
		TORRENT_INET_MAX_MTU = 0xffff
	};

	// the point of the bif_endian_int is two-fold
	// one purpuse is to not have any alignment requirements
	// so that any byffer received from the network can be cast
	// to it and read as an integer of various sizes without
	// triggering a bus error. The other purpose is to convert
	// from network byte order to host byte order when read and
	// written, to offer a convenient interface to both interpreting
	// and writing network packets
	template <class T> struct big_endian_int
	{
		big_endian_int& operator=(T v)
		{
			char* p = m_storage;
			detail::write_impl(v, p);
			return *this;
		}
		operator T() const
		{
			const char* p = m_storage;
			return detail::read_impl(p, detail::type<T>());
		}
	private:
		char m_storage[sizeof(T)];
	};

	typedef big_endian_int<boost::uint64_t> be_uint64;
	typedef big_endian_int<boost::uint32_t> be_uint32;
	typedef big_endian_int<boost::uint16_t> be_uint16;
	typedef big_endian_int<boost::int64_t> be_int64;
	typedef big_endian_int<boost::int32_t> be_int32;
	typedef big_endian_int<boost::int16_t> be_int16;

/*
	uTP header from BEP 29

	0       4       8               16              24              32
	+-------+-------+---------------+---------------+---------------+
	| type  | ver   | extension     | connection_id                 |
	+-------+-------+---------------+---------------+---------------+
	| timestamp_microseconds                                        |
	+---------------+---------------+---------------+---------------+
	| timestamp_difference_microseconds                             |
	+---------------+---------------+---------------+---------------+
	| wnd_size                                                      |
	+---------------+---------------+---------------+---------------+
	| seq_nr                        | ack_nr                        |
	+---------------+---------------+---------------+---------------+

*/

	enum type { ST_DATA = 0, ST_FIN, ST_STATE, ST_RESET, ST_SYN, NUM_TYPES };

	struct utp_header
	{
		unsigned char type_ver;
		unsigned char extension;
		be_uint16 connection_id;
		be_uint32 timestamp_microseconds;
		be_uint32 timestamp_difference_microseconds;
		be_uint32 wnd_size;
		be_uint16 seq_nr;
		be_uint16 ack_nr;

		int get_type() const { return type_ver >> 4; }
		int get_version() const { return type_ver & 0xf; }
	};

struct utp_socket_impl;

utp_socket_impl* construct_utp_impl(boost::uint16_t recv_id
	, boost::uint16_t send_id, void* userdata
	, utp_socket_manager* sm);
void detach_utp_impl(utp_socket_impl* s);
void delete_utp_impl(utp_socket_impl* s);
bool should_delete(utp_socket_impl* s);
void tick_utp_impl(utp_socket_impl* s, ptime const& now);
void utp_init_mtu(utp_socket_impl* s, int link_mtu, int utp_mtu);
bool utp_incoming_packet(utp_socket_impl* s, char const* p
	, int size, udp::endpoint const& ep, ptime receive_time);
bool utp_match(utp_socket_impl* s, udp::endpoint const& ep, boost::uint16_t id);
udp::endpoint utp_remote_endpoint(utp_socket_impl* s);
boost::uint16_t utp_receive_id(utp_socket_impl* s);
int utp_socket_state(utp_socket_impl const* s);

#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
int socket_impl_size();
#endif

// this is the user-level stream interface to utp sockets.
// the reason why it's split up in a utp_stream class and
// an implementation class is because the socket state has
// to be able to out-live the user level socket. For instance
// when sending data on a stream and then closing it, the
// state holding the send buffer has to be kept around until
// it has been flushed, which may be longer than the client
// will keep the utp_stream object around for.
// for more details, see utp_socket_impl, which is analogous
// to the kernel state for a socket. It's defined in utp_stream.cpp
class TORRENT_EXPORT utp_stream
{
public:

	typedef stream_socket::endpoint_type endpoint_type;
	typedef stream_socket::protocol_type protocol_type;

	explicit utp_stream(asio::io_service& io_service);
	~utp_stream();

	// used for incoming connections
	void set_impl(utp_socket_impl* s);
	utp_socket_impl* get_impl();

#ifndef BOOST_NO_EXCEPTIONS
	template <class IO_Control_Command>
	void io_control(IO_Control_Command& ioc) {}
#endif

	template <class IO_Control_Command>
	void io_control(IO_Control_Command& ioc, error_code& ec) {}

#ifndef BOOST_NO_EXCEPTIONS
	void bind(endpoint_type const& endpoint) {}
#endif

	void bind(endpoint_type const& endpoint, error_code& ec);

#ifndef BOOST_NO_EXCEPTIONS
	template <class SettableSocketOption>
	void set_option(SettableSocketOption const& opt) {}
#endif

	template <class SettableSocketOption>
	error_code set_option(SettableSocketOption const& opt, error_code& ec) { return ec; }

	void close();
	void close(error_code const& ec) { close(); }
	bool is_open() const { return m_open; }

	int read_buffer_size() const;
	static void on_read(void* self, size_t bytes_transferred, error_code const& ec, bool kill);
	static void on_write(void* self, size_t bytes_transferred, error_code const& ec, bool kill);
	static void on_connect(void* self, error_code const& ec, bool kill);

	typedef void(*handler_t)(void*, size_t, error_code const&, bool);
	typedef void(*connect_handler_t)(void*, error_code const&, bool);

	void add_read_buffer(void* buf, size_t len);
	void set_read_handler(handler_t h);
	void add_write_buffer(void const* buf, size_t len);
	void set_write_handler(handler_t h);
	size_t read_some(bool clear_buffers);

	void do_connect(tcp::endpoint const& ep, connect_handler_t h);

	endpoint_type local_endpoint() const
	{
		error_code ec;
		return local_endpoint(ec);
	}

	endpoint_type local_endpoint(error_code& ec) const;

	endpoint_type remote_endpoint() const
	{
		error_code ec;
		return remote_endpoint(ec);
	}

	endpoint_type remote_endpoint(error_code& ec) const;

	std::size_t available() const;
	std::size_t available(error_code& ec) const { return available(); }

	asio::io_service& io_service()
	{ return m_io_service; }

	template <class Handler>
	void async_connect(endpoint_type const& endpoint, Handler const& handler)
	{
		if (!endpoint.address().is_v4())
		{
			error_code ec = asio::error::operation_not_supported;
			m_io_service.post(boost::bind<void>(handler, asio::error::operation_not_supported, 0));
			return;
		}

		if (m_impl == 0)
		{
			m_io_service.post(boost::bind<void>(handler, asio::error::not_connected, 0));
			return;
		}

		m_connect_handler = handler;
		do_connect(endpoint, &utp_stream::on_connect);
	}

	template <class Mutable_Buffers, class Handler>
	void async_read_some(Mutable_Buffers const& buffers, Handler const& handler)
	{
		if (m_impl == 0)
		{
			m_io_service.post(boost::bind<void>(handler, asio::error::not_connected, 0));
			return;
		}

		TORRENT_ASSERT(!m_read_handler);
		if (m_read_handler)
		{
			m_io_service.post(boost::bind<void>(handler, asio::error::operation_not_supported, 0));
			return;
		}
		for (typename Mutable_Buffers::const_iterator i = buffers.begin()
			, end(buffers.end()); i != end; ++i)
		{
			TORRENT_ASSERT(buffer_size(*i) > 0);
			using asio::buffer_cast;
			using asio::buffer_size;
			add_read_buffer(buffer_cast<void*>(*i), buffer_size(*i));
		}
		m_read_handler = handler;
		set_read_handler(&utp_stream::on_read);
	}

	void do_async_connect(endpoint_type const& ep
		, boost::function<void(error_code const&)> const& handler);

	template <class Protocol>
	void open(Protocol const& p, error_code& ec)
	{ m_open = true; }

	template <class Protocol>
	void open(Protocol const& p)
	{ m_open = true; }

	template <class Mutable_Buffers>
	std::size_t read_some(Mutable_Buffers const& buffers, error_code& ec)
	{
		TORRENT_ASSERT(!m_read_handler);
		if (m_impl == 0)
		{
			ec = asio::error::not_connected;
			return 0;
		}

		if (read_buffer_size() == 0)
		{
			ec = asio::error::would_block;
			return 0;
		}
#ifdef TORRENT_DEBUG
		size_t buf_size = 0;
#endif

		for (typename Mutable_Buffers::const_iterator i = buffers.begin()
			, end(buffers.end()); i != end; ++i)
		{
			using asio::buffer_cast;
			using asio::buffer_size;
			add_read_buffer(buffer_cast<void*>(*i), buffer_size(*i));
#ifdef TORRENT_DEBUG
			buf_size += buffer_size(*i);
#endif
		}
		std::size_t ret = read_some(true);
		TORRENT_ASSERT(ret <= buf_size);
		TORRENT_ASSERT(ret > 0);
		return ret;
	}

	template <class Const_Buffers>
	std::size_t write_some(Const_Buffers const& buffers, error_code& ec)
	{
		// TODO: implement
		return 0;
	}

	template <class Const_Buffers, class Handler>
	void async_write_some(Const_Buffers const& buffers, Handler const& handler)
	{
		if (m_impl == 0)
		{
			m_io_service.post(boost::bind<void>(handler, asio::error::not_connected, 0));
			return;
		}

		TORRENT_ASSERT(!m_write_handler);
		if (m_write_handler)
		{
			m_io_service.post(boost::bind<void>(handler, asio::error::operation_not_supported, 0));
			return;
		}

		for (typename Const_Buffers::const_iterator i = buffers.begin()
			, end(buffers.end()); i != end; ++i)
		{
			TORRENT_ASSERT(buffer_size(*i) > 0);
			using asio::buffer_cast;
			using asio::buffer_size;
			add_write_buffer((void*)buffer_cast<void const*>(*i), buffer_size(*i));
		}
		m_write_handler = handler;
		set_write_handler(&utp_stream::on_write);
	}

//private:

	void cancel_handlers(error_code const&);

	boost::function1<void, error_code const&> m_connect_handler;
	boost::function2<void, error_code const&, std::size_t> m_read_handler;
	boost::function2<void, error_code const&, std::size_t> m_write_handler;

	asio::io_service& m_io_service;
	utp_socket_impl* m_impl;
	bool m_open;
};

}

#endif
<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2015 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#ifndef MAPNIK_MARKER_HELPERS_HPP
#define MAPNIK_MARKER_HELPERS_HPP

#include <mapnik/feature.hpp>
#include <mapnik/geometry.hpp>
#include <mapnik/geometry_type.hpp>
#include <mapnik/geometry_centroid.hpp>
#include <mapnik/symbolizer.hpp>
#include <mapnik/svg/svg_path_attributes.hpp>
#include <mapnik/marker.hpp> // for svg_storage_type
#include <mapnik/markers_placement.hpp>
#include <mapnik/attribute.hpp>
#include <mapnik/box2d.hpp>
#include <mapnik/vertex_processor.hpp>
#include <mapnik/renderer_common/apply_vertex_converter.hpp>
#include <mapnik/renderer_common/render_markers_symbolizer.hpp>

// agg
#include "agg_trans_affine.h"

// stl
#include <memory>

namespace mapnik {

struct clip_poly_tag;

using svg_attribute_type = agg::pod_bvector<svg::path_attributes>;

template <typename Detector>
struct vector_markers_dispatch : util::noncopyable
{
    vector_markers_dispatch(svg_path_ptr const& src,
                            svg_path_adapter & path,
                            svg_attribute_type const& attrs,
                            agg::trans_affine const& marker_trans,
                            symbolizer_base const& sym,
                            Detector & detector,
                            double scale_factor,
                            feature_impl const& feature,
                            attributes const& vars,
                            bool snap_to_pixels,
                            markers_renderer_context & renderer_context)
        : params_(src->bounding_box(), recenter(src) * marker_trans,
                  sym, feature, vars, scale_factor, snap_to_pixels)
        , renderer_context_(renderer_context)
        , src_(src)
        , path_(path)
        , attrs_(attrs)
        , detector_(detector)
    {}

    template <typename T>
    void add_path(T & path)
    {
        markers_placement_finder<T, Detector> placement_finder(
            params_.placement_method, path, detector_, params_.placement_params);
        double x, y, angle = .0;
        while (placement_finder.get_point(x, y, angle, params_.ignore_placement))
        {
            agg::trans_affine matrix = params_.placement_params.tr;
            matrix.rotate(angle);
            matrix.translate(x, y);
            renderer_context_.render_marker(src_, path_, attrs_, params_, matrix);
        }
    }

protected:
    static agg::trans_affine recenter(svg_path_ptr const& src)
    {
        coord2d center = src->bounding_box().center();
        return agg::trans_affine_translation(-center.x, -center.y);
    }

    markers_dispatch_params params_;
    markers_renderer_context & renderer_context_;
    svg_path_ptr const& src_;
    svg_path_adapter & path_;
    svg_attribute_type const& attrs_;
    Detector & detector_;
};

template <typename Detector>
struct raster_markers_dispatch : util::noncopyable
{
    raster_markers_dispatch(image_rgba8 const& src,
                            agg::trans_affine const& marker_trans,
                            symbolizer_base const& sym,
                            Detector & detector,
                            double scale_factor,
                            feature_impl const& feature,
                            attributes const& vars,
                            markers_renderer_context & renderer_context)
        : params_(box2d<double>(0, 0, src.width(), src.height()),
                  marker_trans, sym, feature, vars, scale_factor)
        , renderer_context_(renderer_context)
        , src_(src)
        , detector_(detector)
    {}

    template <typename T>
    void add_path(T & path)
    {
        markers_placement_finder<T, Detector> placement_finder(
            params_.placement_method, path, detector_, params_.placement_params);
        double x, y, angle = .0;
        while (placement_finder.get_point(x, y, angle, params_.ignore_placement))
        {
            agg::trans_affine matrix = params_.placement_params.tr;
            matrix.rotate(angle);
            matrix.translate(x, y);
            renderer_context_.render_marker(src_, params_, matrix);
        }
    }

protected:
    markers_dispatch_params params_;
    markers_renderer_context & renderer_context_;
    image_rgba8 const& src_;
    Detector & detector_;
};

void build_ellipse(symbolizer_base const& sym, mapnik::feature_impl & feature, attributes const& vars,
                   svg_storage_type & marker_ellipse, svg::svg_path_adapter & svg_path);

bool push_explicit_style(svg_attribute_type const& src,
                         svg_attribute_type & dst,
                         symbolizer_base const& sym,
                         feature_impl & feature,
                         attributes const& vars);

void setup_transform_scaling(agg::trans_affine & tr,
                             double svg_width,
                             double svg_height,
                             mapnik::feature_impl & feature,
                             attributes const& vars,
                             symbolizer_base const& sym);

// Apply markers to a feature with multiple geometries
template <typename Converter, typename Processor>
void apply_markers_single(Converter & converter, Processor & proc, geometry::geometry<double> const& geom, geometry::geometry_types type)
{
    if (type == geometry::geometry_types::Point)
    {
        geometry::point_vertex_adapter<double> va(geom.get<geometry::point<double>>());
        converter.apply(va, proc);
    }
    else if (type == geometry::geometry_types::LineString)
    {
        geometry::line_string_vertex_adapter<double> va(geom.get<geometry::line_string<double>>());
        converter.apply(va, proc);
    }
    else if (type == geometry::geometry_types::Polygon)
    {
        geometry::polygon_vertex_adapter<double> va(geom.get<geometry::polygon<double>>());
        converter.apply(va, proc);
    }
    else if (type == geometry::geometry_types::MultiPoint)
    {
        for (auto const& pt : geom.get<geometry::multi_point<double>>())
        {
            geometry::point_vertex_adapter<double> va(pt);
            converter.apply(va, proc);
        }
    }
    else if (type == geometry::geometry_types::MultiLineString)
    {
        for (auto const& line : geom.get<geometry::multi_line_string<double>>())
        {
            geometry::line_string_vertex_adapter<double> va(line);
            converter.apply(va, proc);
        }
    }
    else if (type == geometry::geometry_types::MultiPolygon)
    {
        for (auto const& poly : geom.get<geometry::multi_polygon<double>>())
        {
            geometry::polygon_vertex_adapter<double> va(poly);
            converter.apply(va, proc);
        }
    }
}

template <typename Converter, typename Processor>
void apply_markers_multi(feature_impl const& feature, attributes const& vars, Converter & converter, Processor & proc, symbolizer_base const& sym)
{
    using apply_vertex_converter_type = detail::apply_vertex_converter<Converter,Processor>;
    apply_vertex_converter_type apply(converter, proc);
    auto const& geom = feature.get_geometry();
    geometry::geometry_types type = geometry::geometry_type(geom);

    if (type == geometry::geometry_types::Point
        ||
        type == geometry::geometry_types::LineString
        ||
        type == geometry::geometry_types::Polygon)
    {
        apply_markers_single(converter, proc, geom, type);
    }
    else
    {

        marker_multi_policy_enum multi_policy = get<marker_multi_policy_enum, keys::markers_multipolicy>(sym, feature, vars);
        marker_placement_enum placement = get<marker_placement_enum, keys::markers_placement_type>(sym, feature, vars);

        if (placement == MARKER_POINT_PLACEMENT &&
            multi_policy == MARKER_WHOLE_MULTI)
        {
            geometry::point<double> pt;
            // test if centroid is contained by bounding box
            if (geometry::centroid(geom, pt) && converter.disp_.args_.bbox.contains(pt.x, pt.y))
            {
                // unset any clipping since we're now dealing with a point
                converter.template unset<clip_poly_tag>();
                geometry::point_vertex_adapter<double> va(pt);
                converter.apply(va, proc);
            }
        }
        else if ((placement == MARKER_POINT_PLACEMENT || placement == MARKER_INTERIOR_PLACEMENT) &&
                 multi_policy == MARKER_LARGEST_MULTI)
        {
            // Only apply to path with largest envelope area
            // TODO: consider using true area for polygon types
            if (type == geometry::geometry_types::MultiPolygon)
            {
                geometry::multi_polygon<double> const& multi_poly = mapnik::util::get<geometry::multi_polygon<double> >(geom);
                double maxarea = 0;
                geometry::polygon<double> const* largest = 0;
                for (geometry::polygon<double> const& poly : multi_poly)
                {
                    box2d<double> bbox = geometry::envelope(poly);
                    double area = bbox.width() * bbox.height();
                    if (area > maxarea)
                    {
                        maxarea = area;
                        largest = &poly;
                    }
                }
                if (largest)
                {
                    geometry::polygon_vertex_adapter<double> va(*largest);
                    converter.apply(va, proc);
                }
            }
            else
            {
                MAPNIK_LOG_WARN(marker_symbolizer) << "TODO: if you get here -> open an issue";
            }
        }
        else
        {
            if (multi_policy != MARKER_EACH_MULTI && placement != MARKER_POINT_PLACEMENT)
            {
                MAPNIK_LOG_WARN(marker_symbolizer) << "marker_multi_policy != 'each' has no effect with marker_placement != 'point'";
            }
            if (type == geometry::geometry_types::GeometryCollection)
            {
                for (auto const& g : geom.get<geometry::geometry_collection<double>>())
                {
                    apply_markers_single(converter, proc, g, geometry::geometry_type(g));
                }
            }
            else
            {
                apply_markers_single(converter, proc, geom, type);
            }
        }
    }
}

}

#endif //MAPNIK_MARKER_HELPERS_HPP
<commit_msg>remove unused vars/cleanup<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2015 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#ifndef MAPNIK_MARKER_HELPERS_HPP
#define MAPNIK_MARKER_HELPERS_HPP

#include <mapnik/feature.hpp>
#include <mapnik/geometry.hpp>
#include <mapnik/geometry_type.hpp>
#include <mapnik/geometry_centroid.hpp>
#include <mapnik/symbolizer.hpp>
#include <mapnik/svg/svg_path_attributes.hpp>
#include <mapnik/marker.hpp> // for svg_storage_type
#include <mapnik/markers_placement.hpp>
#include <mapnik/attribute.hpp>
#include <mapnik/box2d.hpp>
#include <mapnik/vertex_processor.hpp>
#include <mapnik/renderer_common/apply_vertex_converter.hpp>
#include <mapnik/renderer_common/render_markers_symbolizer.hpp>

// agg
#include "agg_trans_affine.h"

// stl
#include <memory>

namespace mapnik {

struct clip_poly_tag;

using svg_attribute_type = agg::pod_bvector<svg::path_attributes>;

template <typename Detector>
struct vector_markers_dispatch : util::noncopyable
{
    vector_markers_dispatch(svg_path_ptr const& src,
                            svg_path_adapter & path,
                            svg_attribute_type const& attrs,
                            agg::trans_affine const& marker_trans,
                            symbolizer_base const& sym,
                            Detector & detector,
                            double scale_factor,
                            feature_impl const& feature,
                            attributes const& vars,
                            bool snap_to_pixels,
                            markers_renderer_context & renderer_context)
        : params_(src->bounding_box(), recenter(src) * marker_trans,
                  sym, feature, vars, scale_factor, snap_to_pixels)
        , renderer_context_(renderer_context)
        , src_(src)
        , path_(path)
        , attrs_(attrs)
        , detector_(detector)
    {}

    template <typename T>
    void add_path(T & path)
    {
        markers_placement_finder<T, Detector> placement_finder(
            params_.placement_method, path, detector_, params_.placement_params);
        double x, y, angle = .0;
        while (placement_finder.get_point(x, y, angle, params_.ignore_placement))
        {
            agg::trans_affine matrix = params_.placement_params.tr;
            matrix.rotate(angle);
            matrix.translate(x, y);
            renderer_context_.render_marker(src_, path_, attrs_, params_, matrix);
        }
    }

protected:
    static agg::trans_affine recenter(svg_path_ptr const& src)
    {
        coord2d center = src->bounding_box().center();
        return agg::trans_affine_translation(-center.x, -center.y);
    }

    markers_dispatch_params params_;
    markers_renderer_context & renderer_context_;
    svg_path_ptr const& src_;
    svg_path_adapter & path_;
    svg_attribute_type const& attrs_;
    Detector & detector_;
};

template <typename Detector>
struct raster_markers_dispatch : util::noncopyable
{
    raster_markers_dispatch(image_rgba8 const& src,
                            agg::trans_affine const& marker_trans,
                            symbolizer_base const& sym,
                            Detector & detector,
                            double scale_factor,
                            feature_impl const& feature,
                            attributes const& vars,
                            markers_renderer_context & renderer_context)
        : params_(box2d<double>(0, 0, src.width(), src.height()),
                  marker_trans, sym, feature, vars, scale_factor)
        , renderer_context_(renderer_context)
        , src_(src)
        , detector_(detector)
    {}

    template <typename T>
    void add_path(T & path)
    {
        markers_placement_finder<T, Detector> placement_finder(
            params_.placement_method, path, detector_, params_.placement_params);
        double x, y, angle = .0;
        while (placement_finder.get_point(x, y, angle, params_.ignore_placement))
        {
            agg::trans_affine matrix = params_.placement_params.tr;
            matrix.rotate(angle);
            matrix.translate(x, y);
            renderer_context_.render_marker(src_, params_, matrix);
        }
    }

protected:
    markers_dispatch_params params_;
    markers_renderer_context & renderer_context_;
    image_rgba8 const& src_;
    Detector & detector_;
};

void build_ellipse(symbolizer_base const& sym, mapnik::feature_impl & feature, attributes const& vars,
                   svg_storage_type & marker_ellipse, svg::svg_path_adapter & svg_path);

bool push_explicit_style(svg_attribute_type const& src,
                         svg_attribute_type & dst,
                         symbolizer_base const& sym,
                         feature_impl & feature,
                         attributes const& vars);

void setup_transform_scaling(agg::trans_affine & tr,
                             double svg_width,
                             double svg_height,
                             mapnik::feature_impl & feature,
                             attributes const& vars,
                             symbolizer_base const& sym);

// Apply markers to a feature with multiple geometries
template <typename Converter, typename Processor>
void apply_markers_single(Converter & converter, Processor & proc, geometry::geometry<double> const& geom, geometry::geometry_types type)
{
    if (type == geometry::geometry_types::Point)
    {
        geometry::point_vertex_adapter<double> va(geom.get<geometry::point<double>>());
        converter.apply(va, proc);
    }
    else if (type == geometry::geometry_types::LineString)
    {
        geometry::line_string_vertex_adapter<double> va(geom.get<geometry::line_string<double>>());
        converter.apply(va, proc);
    }
    else if (type == geometry::geometry_types::Polygon)
    {
        geometry::polygon_vertex_adapter<double> va(geom.get<geometry::polygon<double>>());
        converter.apply(va, proc);
    }
    else if (type == geometry::geometry_types::MultiPoint)
    {
        for (auto const& pt : geom.get<geometry::multi_point<double>>())
        {
            geometry::point_vertex_adapter<double> va(pt);
            converter.apply(va, proc);
        }
    }
    else if (type == geometry::geometry_types::MultiLineString)
    {
        for (auto const& line : geom.get<geometry::multi_line_string<double>>())
        {
            geometry::line_string_vertex_adapter<double> va(line);
            converter.apply(va, proc);
        }
    }
    else if (type == geometry::geometry_types::MultiPolygon)
    {
        for (auto const& poly : geom.get<geometry::multi_polygon<double>>())
        {
            geometry::polygon_vertex_adapter<double> va(poly);
            converter.apply(va, proc);
        }
    }
}

template <typename Converter, typename Processor>
void apply_markers_multi(feature_impl const& feature, attributes const& vars, Converter & converter, Processor & proc, symbolizer_base const& sym)
{
    auto const& geom = feature.get_geometry();
    geometry::geometry_types type = geometry::geometry_type(geom);

    if (type == geometry::geometry_types::Point
        ||
        type == geometry::geometry_types::LineString
        ||
        type == geometry::geometry_types::Polygon)
    {
        apply_markers_single(converter, proc, geom, type);
    }
    else
    {

        marker_multi_policy_enum multi_policy = get<marker_multi_policy_enum, keys::markers_multipolicy>(sym, feature, vars);
        marker_placement_enum placement = get<marker_placement_enum, keys::markers_placement_type>(sym, feature, vars);

        if (placement == MARKER_POINT_PLACEMENT &&
            multi_policy == MARKER_WHOLE_MULTI)
        {
            geometry::point<double> pt;
            // test if centroid is contained by bounding box
            if (geometry::centroid(geom, pt) && converter.disp_.args_.bbox.contains(pt.x, pt.y))
            {
                // unset any clipping since we're now dealing with a point
                converter.template unset<clip_poly_tag>();
                geometry::point_vertex_adapter<double> va(pt);
                converter.apply(va, proc);
            }
        }
        else if ((placement == MARKER_POINT_PLACEMENT || placement == MARKER_INTERIOR_PLACEMENT) &&
                 multi_policy == MARKER_LARGEST_MULTI)
        {
            // Only apply to path with largest envelope area
            // TODO: consider using true area for polygon types
            if (type == geometry::geometry_types::MultiPolygon)
            {
                geometry::multi_polygon<double> const& multi_poly = mapnik::util::get<geometry::multi_polygon<double> >(geom);
                double maxarea = 0;
                geometry::polygon<double> const* largest = 0;
                for (geometry::polygon<double> const& poly : multi_poly)
                {
                    box2d<double> bbox = geometry::envelope(poly);
                    double area = bbox.width() * bbox.height();
                    if (area > maxarea)
                    {
                        maxarea = area;
                        largest = &poly;
                    }
                }
                if (largest)
                {
                    geometry::polygon_vertex_adapter<double> va(*largest);
                    converter.apply(va, proc);
                }
            }
            else
            {
                MAPNIK_LOG_WARN(marker_symbolizer) << "TODO: if you get here -> open an issue";
            }
        }
        else
        {
            if (multi_policy != MARKER_EACH_MULTI && placement != MARKER_POINT_PLACEMENT)
            {
                MAPNIK_LOG_WARN(marker_symbolizer) << "marker_multi_policy != 'each' has no effect with marker_placement != 'point'";
            }
            if (type == geometry::geometry_types::GeometryCollection)
            {
                for (auto const& g : geom.get<geometry::geometry_collection<double>>())
                {
                    apply_markers_single(converter, proc, g, geometry::geometry_type(g));
                }
            }
            else
            {
                apply_markers_single(converter, proc, geom, type);
            }
        }
    }
}

}

#endif //MAPNIK_MARKER_HELPERS_HPP
<|endoftext|>