text: /*
  
  Copyright (c) 2016, 2020, Arvid Norberg
  All rights reserved.
  
  You may use, distribute and modify this code under the terms of the BSD license,
  see LICENSE file.
  */
  
  #ifndef TORRENT_BIND_TO_DEVICE_HPP_INCLUDED
  #define TORRENT_BIND_TO_DEVICE_HPP_INCLUDED
  
  #include "libTAU/config.hpp"
  #include "libTAU/socket.hpp"
  #include "libTAU/error_code.hpp"
  
  #if TORRENT_USE_IFCONF || TORRENT_USE_NETLINK || TORRENT_USE_SYSCTL
  #include <sys/socket.h> // for SO_BINDTODEVICE
  #include <netinet/in.h>
  #endif
  
  namespace libTAU { namespace aux {
  
  #if defined SO_BINDTODEVICE
  
  	struct bind_to_device
  	{
  		explicit bind_to_device(char const* device): m_value(device) {}
  		template<class Protocol>
  		int level(Protocol const&) const { return SOL_SOCKET; }
  		template<class Protocol>
  		int name(Protocol const&) const { return SO_BINDTODEVICE; }
  		template<class Protocol>
  		char const* data(Protocol const&) const { return m_value; }
  		template<class Protocol>
  		size_t size(Protocol const&) const { return strlen(m_value) + 1; }
  	private:
  		char const* m_value;
  	};
  
  	template <typename T>
  	void bind_device(T& sock, char const* device, error_code& ec)
  	{
  		sock.set_option(bind_to_device(device), ec);
  	}
  
  #define TORRENT_HAS_BINDTODEVICE 1
  
  #elif defined IP_BOUND_IF
  
  	struct bind_to_device
  	{
  		explicit bind_to_device(unsigned int idx): m_value(idx) {}
  		template<class Protocol>
  		int level(Protocol const&) const { return IPPROTO_IP; }
  		template<class Protocol>
  		int name(Protocol const&) const { return IP_BOUND_IF; }
  		template<class Protocol>
  		char const* data(Protocol const&) const { return reinterpret_cast<char const*>(&m_value); }
  		template<class Protocol>
  		size_t size(Protocol const&) const { return sizeof(m_value); }
  	private:
  		unsigned int m_value;
  	};
  
  	template <typename T>
  	void bind_device(T& sock, char const* device, error_code& ec)
  	{
  		unsigned int const if_idx = if_nametoindex(device);
  		if (if_idx == 0)
  		{
  			ec.assign(errno, system_category());
  			return;
  		}
  		sock.set_option(bind_to_device(if_idx), ec);
  	}
  
  #define TORRENT_HAS_BINDTODEVICE 1
  
  #elif defined IP_FORCE_OUT_IFP
  
  	struct bind_to_device
  	{
  		explicit bind_to_device(char const* device): m_value(device) {}
  		template<class Protocol>
  		int level(Protocol const&) const { return SOL_SOCKET; }
  		template<class Protocol>
  		int name(Protocol const&) const { return IP_FORCE_OUT_IFP; }
  		template<class Protocol>
  		char const* data(Protocol const&) const { return m_value; }
  		template<class Protocol>
  		size_t size(Protocol const&) const { return strlen(m_value) + 1; }
  	private:
  		char const* m_value;
  	};
  
  	template <typename T>
  	void bind_device(T& sock, char const* device, error_code& ec)
  	{
  		sock.set_option(bind_to_device(device), ec);
  	}
  
  #define TORRENT_HAS_BINDTODEVICE 1
  
  #else
  
  #define TORRENT_HAS_BINDTODEVICE 0
  
  #endif
  
  } }
  
  #endif
  
  