Newer
Older
Import / projects / Gameloft / glwebtools / source / glwebtools / glwebtools_socket_metro.cpp
#include <glwebtools/internal/glwebtools_default_config.h>

#if GLWEBTOOLS_USE_METRO_SOCKET

#include <glwebtools/os/glwebtools_socket.h>
#include <glwebtools/internal/glwebtools_memory.h>
#include <glwebtools/internal/glwebtools_macro.h>
#include <glwebtools/glwebtools_error.h>

#include <wrl\implements.h>
#include <wrl\module.h>
#include <wrl\async.h>

bool __uncaught_exception();

#include <ppltasks.h>

#include <windows.networking.sockets.h>
#include <windows.networking.connectivity.h>
#include <string>
#include <sstream>
#include <future>

namespace glwebtools
{
	namespace
	{
		std::wstring stows(const std::string& s)
		{
			return std::wstring(s.begin(), s.end());
		}

		std::wstring stows(const char* s)
		{
			return stows(std::string(s));
		}

		std::string wstos(const std::wstring& ws)
		{
			return std::string(ws.begin(), ws.end());
		}

		std::wstring htow(HSTRING hstr_)
		{
			unsigned int length;
			const wchar_t* buffer = WindowsGetStringRawBuffer(hstr_, &length);

			return std::wstring(buffer, length);
		}

		std::string htos(HSTRING hstr_)
		{
			return wstos(htow(hstr_));
		}

		unsigned long inet_addr(const char *str)
		{ 
			unsigned long a,b,c,d=0;
			char ch;

			std::stringstream s(str);
			s >> a >> ch >> b >> ch >> c >> ch >> d;

			return (a << 24) | (b << 16) | (c << 8) | d;
		}

		glwebtools::Error inet_wton(const std::wstring& in, AddrIpv4& out)
		{
			out.Addr.ulongAddr = inet_addr(wstos(in).c_str());

			return glwebtools::E_SUCCESS;
		}

		std::wstring inet_ntow(const AddrIpv4& in)
		{
			std::wstringstream s;
			s << in.Addr.uChar.Addr4 << '.' << in.Addr.uChar.Addr3 << '.'<< in.Addr.uChar.Addr2 << '.'<< in.Addr.uChar.Addr1;

			return s.str();
		}

		std::string inet_ntoa(const AddrIpv4& in)
		{
			std::stringstream s;
			s << in.Addr.uChar.Addr4 << '.' << in.Addr.uChar.Addr3 << '.'<< in.Addr.uChar.Addr2 << '.'<< in.Addr.uChar.Addr1;

			return s.str();
		}


		std::wstring port_itow(unsigned short port)
		{
			std::wstringstream s;
			s << port;

			return s.str();
		}

		unsigned short port_wtoi(const std::wstring& in)
		{
			std::wstringstream s(in);
			unsigned short port;
			s >> port;
			return port;
		}

		unsigned short port_htoi(HSTRING hstr_)
		{
			std::wstringstream s(htow(hstr_));
			unsigned short port;
			s >> port;
			return port;
		}

		glwebtools::Error GetIpv4Addr(ABI::Windows::Networking::IHostName* pHostName, AddrIpv4& addr_out)
		{
			if (pHostName == 0)
			{
				return glwebtools::E_INVALID_PARAMETER;
			}

			HRESULT hr;

			ABI::Windows::Networking::HostNameType hnt;
			hr = pHostName->get_Type(&hnt);
			if (FAILED(hr))
			{
				return glwebtools::E_INVALID_PARAMETER;
			}

			if (hnt != ABI::Windows::Networking::HostNameType::HostNameType_Ipv4)
			{
				return glwebtools::E_INVALID_PARAMETER;
			}

			Microsoft::WRL::Wrappers::HString hostname;
			hr = pHostName->get_RawName(hostname.GetAddressOf());
			if (FAILED(hr)) 
			{
				return glwebtools::E_INVALID_PARAMETER;
			}

			std::wstring wshostname = htow(hostname.Get());

			return inet_wton(wshostname, addr_out);
		}

		template <typename F>
		auto run_now(F f)->decltype(f())
		{
			typedef decltype(f()) result_type;

			result_type result;
			std::thread operation_wrapper(
			[f, &result]()
			{
				concurrency::task<result_type> operation = concurrency::task<result_type>(f);
				result = operation.get();
			});
			operation_wrapper.join();

			return result;
		}
		
		struct tcp_connection_handler
		{
			Microsoft::WRL::ComPtr<ABI::Windows::Networking::Sockets::IStreamSocket> m_socket;
			Microsoft::WRL::ComPtr<ABI::Windows::Storage::Streams::IDataReader> m_reader;
			Microsoft::WRL::ComPtr<ABI::Windows::Storage::Streams::IDataWriter> m_writer;

			bool valid() const
			{
				return m_socket;
			}

			glwebtools::Error Create()
			{
				HRESULT hr;

				Microsoft::WRL::ComPtr<IInspectable> pInspectable;
				hr = ::RoActivateInstance(Microsoft::WRL::Wrappers::HString::MakeReference(RuntimeClass_Windows_Networking_Sockets_StreamSocket).Get(), &pInspectable);
				if (FAILED(hr)) 
				{
					return glwebtools::E_INVALID_OPERATION;	
				}

				Microsoft::WRL::ComPtr<ABI::Windows::Networking::Sockets::IStreamSocket> socket;
				hr = pInspectable.As(&socket);
				if (FAILED(hr)) 
				{
					return glwebtools::E_INVALID_OPERATION;	
				}

				return Create(socket);
			}

			glwebtools::Error Create(Microsoft::WRL::ComPtr<ABI::Windows::Networking::Sockets::IStreamSocket> socket)
			{
				HRESULT hr;

				m_socket = socket;

				// Create writer
				Microsoft::WRL::ComPtr<ABI::Windows::Storage::Streams::IOutputStream> outputStream;
				hr = m_socket->get_OutputStream(&outputStream);
				if (FAILED(hr)) 
				{
					return glwebtools::E_INVALID_OPERATION;	
				}

				Microsoft::WRL::ComPtr<ABI::Windows::Storage::Streams::IDataWriterFactory> writerFactory;
				hr = Windows::Foundation::GetActivationFactory(Microsoft::WRL::Wrappers::HString::MakeReference(RuntimeClass_Windows_Storage_Streams_DataWriter).Get(), &writerFactory);
				if (FAILED(hr)) 
				{
					return glwebtools::E_INVALID_OPERATION;	
				}

				hr = writerFactory->CreateDataWriter(outputStream.Get(), &m_writer);
				if (FAILED(hr)) 
				{
					return glwebtools::E_INVALID_OPERATION;	
				}

				// Get socket input stream
				Microsoft::WRL::ComPtr<ABI::Windows::Storage::Streams::IInputStream> inputStream;
				hr = m_socket->get_InputStream(&inputStream);
				if (FAILED(hr)) 
				{
					return glwebtools::E_INVALID_OPERATION;	
				}

				//Create reader factory
				Microsoft::WRL::ComPtr<ABI::Windows::Storage::Streams::IDataReaderFactory> readerFactory;
				hr = Windows::Foundation::GetActivationFactory(Microsoft::WRL::Wrappers::HString::MakeReference(RuntimeClass_Windows_Storage_Streams_DataReader).Get(), &readerFactory);
				if (FAILED(hr)) 
				{
					return glwebtools::E_INVALID_OPERATION;	
				}

				// Create reader from input stream
				hr = readerFactory->CreateDataReader(inputStream.Get(), &m_reader);
				if (FAILED(hr)) 
				{
					return glwebtools::E_INVALID_OPERATION;	
				}

				ABI::Windows::Storage::Streams::InputStreamOptions value = ABI::Windows::Storage::Streams::InputStreamOptions_Partial;
				m_reader->put_InputStreamOptions(value);

				return glwebtools::E_SUCCESS;	
			}

			void Reset()
			{
				m_socket.Reset();
				m_writer.Reset();
				m_reader.Reset();
			}
		};

		struct socket_handler
		{
			typedef Socket::Error Error;
			typedef Socket::Option Option;
			typedef Socket::Type Type;
			typedef Socket::Proto Proto;

			// TCP
			Microsoft::WRL::ComPtr<ABI::Windows::Networking::Sockets::IStreamSocketListener> m_spListener;
			std::vector<tcp_connection_handler> m_tcpConnections;
			size_t m_lastAccepted;
			EventRegistrationToken m_ConnectionReceived_token;
			bool m_loadingAsync;

			static const size_t min_read_bytes = 4096;

			// UDP
			Microsoft::WRL::ComPtr<ABI::Windows::Networking::Sockets::IDatagramSocket> m_udpSocket;
			std::vector<std::tuple<Microsoft::WRL::ComPtr<ABI::Windows::Storage::Streams::IDataReader>, AddrIpv4> > m_udpMessageBuffer;
			std::mutex m_udpMessageBufferMutex;
			concurrency::task_completion_event<void> m_udpMessageEvent;
			EventRegistrationToken m_MessageReceived_token;

			// Type of socket (STREAM/TCP or DATAGRAM/UDP)
			Type m_type;

			bool m_blocking;

			int	m_connectState;

			enum NonBlockConnectState
			{
				NONBLOCK_CONNECT_STATE_START = 0,
				NONBLOCK_CONNECT_STATE_WAITING,
				NONBLOCK_CONNECT_STATE_CONNECTED,
				NONBLOCK_CONNECT_STATE_DISCONNECTED,
				NONBLOCK_CONNECT_STATE_FAILED
			};

			tcp_connection_handler& GetConnection(int id)
			{
				return m_tcpConnections[id];
			}

			Error m_lastError;

			bool IsOpened() const
			{
				return (bool)m_udpSocket || !m_tcpConnections.empty();
			}

			bool OpenTcp(Option option)
			{
				Close();


				tcp_connection_handler tcp_connection;
				if (GLWEBTOOLS_FAIL(tcp_connection.Create()))
					return false;

				m_tcpConnections.push_back(tcp_connection);
				
				m_type  = Socket::T_STREAM;
				m_blocking = (option & Socket::O_BLOCKING) != 0;

				m_connectState = NONBLOCK_CONNECT_STATE_DISCONNECTED;

				return true;
			}

			bool OpenUdp(Option option)
			{
				Close();

				HRESULT hr;

				Microsoft::WRL::ComPtr<IInspectable> pInspectable;
				hr = ::RoActivateInstance(Microsoft::WRL::Wrappers::HString::MakeReference(RuntimeClass_Windows_Networking_Sockets_DatagramSocket).Get(), &pInspectable);
				if (FAILED(hr)) 
				{
					this->SetLastError(Socket::E_UNKNOWN);
					return false;
				}

				hr = pInspectable.As(&m_udpSocket);
				if (FAILED(hr)) 
				{
					this->SetLastError(Socket::E_UNKNOWN);
					return false;
				}

				m_type  = Socket::T_DATAGRAM;
				m_blocking = (option & Socket::O_BLOCKING) != 0;

				return true;
			}

			bool Open(Type type, Proto protocol, Option option)
			{
				if (type == Socket::T_STREAM)
					return OpenTcp(option);

				if (type == Socket::T_DATAGRAM)
					return OpenUdp(option);

				return false;
			}

			void Close()
			{
				// udp
				if (m_udpSocket)
				{
					m_udpSocket->remove_MessageReceived(m_MessageReceived_token);
					{
						std::lock_guard<std::mutex> lock(m_udpMessageBufferMutex);
						m_udpMessageBuffer.clear();
					}

					m_udpSocket.Reset();
				}

				// tcp
				ResetTcpListener();
				m_loadingAsync = false;

				m_connectState = NONBLOCK_CONNECT_STATE_START;
			}

			bool Connect(const AddrIpv4& addr)
			{

				bool result = run_now(
				[this, addr]() -> bool
				{ 
					HRESULT hr;

					// Set serviceName
					Microsoft::WRL::Wrappers::HString serviceName;

					hr = serviceName.Set(port_itow(addr.port).c_str());
					if (FAILED(hr)) 
					{
						this->SetLastError(Socket::E_UNKNOWN);
						return false;
					}

					// Set hostName
					Microsoft::WRL::Wrappers::HString hostName;

					std::wstring s = inet_ntow(addr);
					hr = hostName.Set(s.c_str());
					if (FAILED(hr)) 
					{
						this->SetLastError(Socket::E_UNKNOWN);
						return false;
					}
					
					Microsoft::WRL::ComPtr<ABI::Windows::Networking::IHostNameFactory> pHostNameFactory;
					hr = Windows::Foundation::GetActivationFactory(Microsoft::WRL::Wrappers::HString::MakeReference(RuntimeClass_Windows_Networking_HostName).Get(), &pHostNameFactory);
					if (FAILED(hr)) 
					{
						this->SetLastError(Socket::E_UNKNOWN);
						return false;
					}

					Microsoft::WRL::ComPtr<ABI::Windows::Networking::IHostName> pHostName;
					hr = pHostNameFactory->CreateHostName(hostName.Get(), &pHostName);
					if (FAILED(hr)) 
					{
						this->SetLastError(Socket::E_UNKNOWN);
						return false;
					}

					concurrency::task_completion_event<bool> completionEvent;

					Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncAction> action;
					hr = m_tcpConnections.back().m_socket->ConnectAsync(pHostName.Get(), serviceName.Get(), &action);
					if (FAILED(hr)) 
					{
						this->SetLastError(Socket::E_UNKNOWN);
						return false;
					}
					hr = action->put_Completed(Microsoft::WRL::Callback<ABI::Windows::Foundation::IAsyncActionCompletedHandler>
					(
					[this, completionEvent](ABI::Windows::Foundation::IAsyncAction*, ABI::Windows::Foundation::AsyncStatus asyncStatus) -> HRESULT
					{
						completionEvent.set(asyncStatus == ABI::Windows::Foundation::AsyncStatus::Completed);
						return S_OK;
					}
					).Get());
					if (FAILED(hr)) 
					{
						this->SetLastError(Socket::E_UNKNOWN);
						return false;
					}
					
					m_connectState = NONBLOCK_CONNECT_STATE_WAITING;

					concurrency::task<bool> completion_task = concurrency::create_task(completionEvent);
					return completion_task.get();
				});

				if (result == true)
					m_connectState = NONBLOCK_CONNECT_STATE_CONNECTED;
				else
					m_connectState = NONBLOCK_CONNECT_STATE_FAILED;

				return result;
			}

			bool IsConnected() const
			{
				if (m_type == Socket::T_DATAGRAM)
				{
					return false;
				}

				if (m_type == Socket::T_STREAM)
				{
					return m_connectState == NONBLOCK_CONNECT_STATE_CONNECTED;
				}

				return false;
			}

			void ResetTcpListener()
			{
				if (m_spListener)
				{
					m_spListener->remove_ConnectionReceived(m_ConnectionReceived_token);
				}

				for (auto tcpconnection : m_tcpConnections)
				{
					tcpconnection.Reset();
				}

				m_tcpConnections.clear();
				m_lastAccepted = m_tcpConnections.size();
			}

			bool Bind(const AddrIpv4& addr)
			{
				if (IsOpened() == false)
					return false;

				if (m_type == Socket::T_STREAM)
				{
					return run_now(
					[this, &addr]() -> bool
					{ 
						ResetTcpListener();

						HRESULT hr = Windows::Foundation::ActivateInstance(Microsoft::WRL::Wrappers::HString::MakeReference(RuntimeClass_Windows_Networking_Sockets_StreamSocketListener).Get(), &m_spListener);
						if (FAILED(hr))
						{
							return false;
						}

						// Set serviceName
						Microsoft::WRL::Wrappers::HString serviceName;

						hr = serviceName.Set(port_itow(addr.port).c_str());
						if (FAILED(hr)) 
						{
							this->SetLastError(Socket::E_UNKNOWN);
							return false;
						}

						concurrency::task_completion_event<bool> completionEvent;

						Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncAction> action;
						hr = m_spListener->BindServiceNameAsync(serviceName.Get(), &action);
						if (FAILED(hr))
						{
							return false;
						}

						hr = action->put_Completed(Microsoft::WRL::Callback<ABI::Windows::Foundation::IAsyncActionCompletedHandler>
						(
						[this, completionEvent](ABI::Windows::Foundation::IAsyncAction*, ABI::Windows::Foundation::AsyncStatus asyncStatus) -> HRESULT
						{
							completionEvent.set(asyncStatus == ABI::Windows::Foundation::AsyncStatus::Completed);
							return S_OK;
						}
						).Get());
						if (FAILED(hr)) 
						{
							this->SetLastError(Socket::E_UNKNOWN);
							return false;
						}

						bool result = concurrency::create_task(completionEvent).get();
						if (result == true && m_blocking == false)
						{
							// todo: Start reading async to have available bytes
						}
						return result;
					});
				}
				else // udp socket
				{
					return run_now(
					[this, &addr]() -> bool
					{ 
						HRESULT hr;
						// Task completion event that is set when the request operation completes.
						hr = m_udpSocket->add_MessageReceived(Microsoft::WRL::Callback<ABI::Windows::Foundation::ITypedEventHandler<ABI::Windows::Networking::Sockets::DatagramSocket*, ABI::Windows::Networking::Sockets::DatagramSocketMessageReceivedEventArgs*> >
						(
						[this](ABI::Windows::Networking::Sockets::IDatagramSocket* socket, ABI::Windows::Networking::Sockets::IDatagramSocketMessageReceivedEventArgs* args) -> HRESULT
						{
							Microsoft::WRL::ComPtr<ABI::Windows::Storage::Streams::IDataReader> reader;
							// Get reader
							HRESULT hr;
							hr = args->GetDataReader(&reader);
							if (FAILED(hr)) 
							{
								this->SetLastError(Socket::E_UNKNOWN);
								return hr;
							}

							AddrIpv4 addr_out;

							Microsoft::WRL::ComPtr<ABI::Windows::Networking::IHostName> pHostName;

							hr = args->get_RemoteAddress(&pHostName);
							if (FAILED(hr)) 
							{
								this->SetLastError(Socket::E_UNKNOWN);
								return hr;
							}

							glwebtools::Error result = GetIpv4Addr(pHostName.Get(), addr_out);
							{
								if (GLWEBTOOLS_FAIL(result))
								{
									this->SetLastError(Socket::E_UNKNOWN);
									return hr;
								}
							}

							Microsoft::WRL::Wrappers::HString port;
							hr = args->get_RemotePort(port.GetAddressOf());
							if (FAILED(hr)) 
							{
								this->SetLastError(Socket::E_UNKNOWN);
								return hr;
							}

							addr_out.port = port_htoi(port.Get());

							{
								std::lock_guard<std::mutex> lock(m_udpMessageBufferMutex);
								m_udpMessageBuffer.insert(m_udpMessageBuffer.begin(), std::make_tuple(reader, addr_out));
							}

							if (m_blocking == true)
							{
								m_udpMessageEvent.set();
							}

							return S_OK;
						}
						).Get(), &m_MessageReceived_token);
						if (FAILED(hr)) 
						{
							this->SetLastError(Socket::E_UNKNOWN);
							return false;
						}

						// Set serviceName
						Microsoft::WRL::Wrappers::HString serviceName;

						hr = serviceName.Set(port_itow(addr.port).c_str());
						if (FAILED(hr)) 
						{
							this->SetLastError(Socket::E_UNKNOWN);
							return false;
						}

						concurrency::task_completion_event<bool> completionEvent;

						Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncAction> action;
						hr = m_udpSocket->BindServiceNameAsync(serviceName.Get(), &action);
						if (FAILED(hr))
						{
							return false;
						}

						hr = action->put_Completed(Microsoft::WRL::Callback<ABI::Windows::Foundation::IAsyncActionCompletedHandler>
						(
						[this, completionEvent](ABI::Windows::Foundation::IAsyncAction*, ABI::Windows::Foundation::AsyncStatus asyncStatus) -> HRESULT
						{
							completionEvent.set(asyncStatus == ABI::Windows::Foundation::AsyncStatus::Completed);
							return S_OK;
						}
						).Get());
						if (FAILED(hr)) 
						{
							this->SetLastError(Socket::E_UNKNOWN);
							return false;
						}

						return concurrency::create_task(completionEvent).get();
					});
				}

			}

			bool Listen(int backlog)
			{
				if (m_spListener == false)
					return false;

				if ((size_t)backlog < m_tcpConnections.size())
				{

					auto event = Microsoft::WRL::Callback<__FITypedEventHandler_2_Windows__CNetworking__CSockets__CStreamSocketListener_Windows__CNetworking__CSockets__CStreamSocketListenerConnectionReceivedEventArgs >
					([this](ABI::Windows::Networking::Sockets::IStreamSocketListener* listener, ABI::Windows::Networking::Sockets::IStreamSocketListenerConnectionReceivedEventArgs* args)->HRESULT
					{
						Microsoft::WRL::ComPtr<ABI::Windows::Networking::Sockets::IStreamSocket> tcpSocket;

						HRESULT hr = args->get_Socket(&tcpSocket);
						if (FAILED(hr)) 
						{
							this->SetLastError(Socket::E_UNKNOWN);
							return hr;
						}

						tcp_connection_handler tcp_connection;
						if (GLWEBTOOLS_FAIL(tcp_connection.Create(tcpSocket)))
						{
							this->SetLastError(Socket::E_UNKNOWN);
							return S_FALSE;
						}

						m_tcpConnections.push_back(tcp_connection);

						return S_OK;
					});
					m_spListener->add_ConnectionReceived(event.Get(), &m_ConnectionReceived_token);
					m_connectState = NONBLOCK_CONNECT_STATE_WAITING;
				}

				return true;
			}

			int Accept(AddrIpv4& addr)
			{
				if (m_connectState != NONBLOCK_CONNECT_STATE_WAITING)
					return -1;

				if (m_spListener == false)
					return -1;

				if (m_tcpConnections.empty())
					return -1;

				if (m_tcpConnections.back().valid() == false)
					return -1;

				// check if already accepted
				if (m_lastAccepted >= m_tcpConnections.size())
					return -1;

				if (GetRemoteAddress(addr) == false)
					return -1;
				
				++m_lastAccepted;

				m_connectState = NONBLOCK_CONNECT_STATE_CONNECTED;

				return m_lastAccepted-1;
			}

			bool Reject(int id)
			{
				if ((size_t)id < m_tcpConnections.size())
				{
					GetConnection(id).Reset();
				}

				return false;
			}

			int Send(const void* buf, int size, int id = 0)
			{
				if (IsConnected() == false)
					return -1;

				if (buf == 0 || size < 0)
					return -1;

				if (size == 0)
					return 0;

				return run_now(
				[this, buf, size, id]() -> int
				{ 
					HRESULT hr;

					if (GetConnection(id).valid() == false)
						return false;


					hr = GetConnection(id).m_writer->WriteBytes(size, (BYTE*)buf);
					if (FAILED(hr)) 
					{
						this->SetLastError(Socket::E_UNKNOWN);
						return -1;
					}
		
					Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncOperation<unsigned int> > action;
					hr = GetConnection(id).m_writer->StoreAsync(&action);
					if (FAILED(hr)) 
					{
						this->SetLastError(Socket::E_UNKNOWN);
						return -1;
					}

					// Task completion event that is set when the request operation completes.
					concurrency::task_completion_event<unsigned int> completionEvent;

					hr = action->put_Completed(Microsoft::WRL::Callback<ABI::Windows::Foundation::IAsyncOperationCompletedHandler<unsigned int> >(
					[this, completionEvent](ABI::Windows::Foundation::IAsyncOperation<unsigned int>* operation, ABI::Windows::Foundation::AsyncStatus asyncStatus)->HRESULT
					{
						unsigned int result = 0;
						if (asyncStatus == ABI::Windows::Foundation::AsyncStatus::Error)
						{
							this->SetLastError(Socket::E_UNKNOWN);
						}

						if (asyncStatus == ABI::Windows::Foundation::AsyncStatus::Completed)
						{
							HRESULT hr = operation->GetResults(&result);
							if (FAILED(hr)) 
							{
								this->SetLastError(Socket::E_UNKNOWN);
							}
						}

						completionEvent.set(result);
						return S_OK;
					}).Get());
					if (FAILED(hr)) 
					{
						this->SetLastError(Socket::E_UNKNOWN);
						return -1;
					}

					concurrency::task<unsigned int> completion_task = concurrency::create_task(completionEvent);
					return completion_task.get();
				});
			}

			int SendTo(const AddrIpv4& addr, const void* buf, int size)
			{
				if (m_udpSocket == false)
					return -1;

				if (buf == 0 || size < 0)
					return -1;

				if (size == 0)
					return 0;

				return run_now(
				[this, addr, buf, size]() -> int
				{ 
					HRESULT hr;

					// Set serviceName
					Microsoft::WRL::Wrappers::HString serviceName;		

					hr = serviceName.Set(port_itow(addr.port).c_str());
					if (FAILED(hr)) 
					{
						this->SetLastError(Socket::E_UNKNOWN);
						return false;
					}

					// Set hostName string
					Microsoft::WRL::Wrappers::HString hostName;

					std::wstring s = inet_ntow(addr);
					hr = hostName.Set(s.c_str());
					if (FAILED(hr)) 
					{
						this->SetLastError(Socket::E_UNKNOWN);
						return false;
					}
					
					// Create HostName Factory
					Microsoft::WRL::ComPtr<ABI::Windows::Networking::IHostNameFactory> pHostNameFactory;
					hr = Windows::Foundation::GetActivationFactory(Microsoft::WRL::Wrappers::HString::MakeReference(RuntimeClass_Windows_Networking_HostName).Get(), &pHostNameFactory);
					if (FAILED(hr)) 
					{
						this->SetLastError(Socket::E_UNKNOWN);
						return false;
					}

					// Create HostName from string
					Microsoft::WRL::ComPtr<ABI::Windows::Networking::IHostName> pHostName;
					hr = pHostNameFactory->CreateHostName(hostName.Get(), &pHostName);
					if (FAILED(hr)) 
					{
						this->SetLastError(Socket::E_UNKNOWN);
						return false;
					}

					// Create OuputStream
					Microsoft::WRL::ComPtr<ABI::Windows::Storage::Streams::IOutputStream> outputStream;
					{
						// local completionEvent
						concurrency::task_completion_event<ABI::Windows::Storage::Streams::IOutputStream*> completionEvent;

						Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncOperation<ABI::Windows::Storage::Streams::IOutputStream*> > operation;
						hr = m_udpSocket->GetOutputStreamAsync(pHostName.Get(), serviceName.Get(), operation.GetAddressOf());
						if (FAILED(hr)) 
						{
							this->SetLastError(Socket::E_UNKNOWN);
							return -1;
						}

						hr = operation->put_Completed(Microsoft::WRL::Callback<__FIAsyncOperationCompletedHandler_1_Windows__CStorage__CStreams__CIOutputStream>
						(
						[this, completionEvent](ABI::Windows::Foundation::IAsyncOperation<ABI::Windows::Storage::Streams::IOutputStream*>* operation, ABI::Windows::Foundation::AsyncStatus asyncStatus) -> HRESULT
						{
							ABI::Windows::Storage::Streams::IOutputStream* outputStream = 0;
							if (asyncStatus == ABI::Windows::Foundation::AsyncStatus::Error)
							{
								this->SetLastError(Socket::E_UNKNOWN);
							}

							// Get ouput stream
							HRESULT hr = operation->GetResults(&outputStream);
							if (FAILED(hr)) 
							{
								this->SetLastError(Socket::E_UNKNOWN);
							}

							completionEvent.set(outputStream);
							return S_OK;
						}
						).Get());
						if (FAILED(hr)) 
						{
							this->SetLastError(Socket::E_UNKNOWN);
							return -1;
						}

						outputStream = concurrency::create_task(completionEvent).get();
					}
					if (outputStream == 0)
						return -1;

					// Create writer factory
					Microsoft::WRL::ComPtr<ABI::Windows::Storage::Streams::IDataWriterFactory> writerFactory;
					hr = Windows::Foundation::GetActivationFactory(Microsoft::WRL::Wrappers::HString::MakeReference(RuntimeClass_Windows_Storage_Streams_DataWriter).Get(), &writerFactory);
					if (FAILED(hr)) 
					{
						this->SetLastError(Socket::E_UNKNOWN);
						return -1;
					}
					 
					// Create writer
					Microsoft::WRL::ComPtr<ABI::Windows::Storage::Streams::IDataWriter> writer;
					hr = writerFactory->CreateDataWriter(outputStream.Get(), &writer);
					if (FAILED(hr)) 
					{
						this->SetLastError(Socket::E_UNKNOWN);
						return -1;
					}

					hr = writer->WriteBytes(size, (BYTE*)buf);
					if (FAILED(hr)) 
					{
						this->SetLastError(Socket::E_UNKNOWN);
						return -1;
					}
		
					Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncOperation<unsigned int> > action;
					hr = writer->StoreAsync(&action);
					if (FAILED(hr)) 
					{
						this->SetLastError(Socket::E_UNKNOWN);
						return -1;
					}

					// Task completion event that is set when the request operation completes.
					concurrency::task_completion_event<unsigned int> completionEvent;

					hr = action->put_Completed(Microsoft::WRL::Callback<__FIAsyncOperationCompletedHandler_1_UINT32>(
					[this, completionEvent](ABI::Windows::Foundation::IAsyncOperation<unsigned int>* operation, ABI::Windows::Foundation::AsyncStatus asyncStatus)->HRESULT
					{
						unsigned int result = 0;

						if (asyncStatus == ABI::Windows::Foundation::AsyncStatus::Error)
						{
							this->SetLastError(Socket::E_UNKNOWN);
						}

						if (asyncStatus == ABI::Windows::Foundation::AsyncStatus::Completed)
						{
							HRESULT hr = operation->GetResults(&result);
							if (FAILED(hr)) 
							{
								this->SetLastError(Socket::E_UNKNOWN);
							}
						}

						completionEvent.set(result);
						return S_OK;
					}).Get());
					if (FAILED(hr)) 
					{
						this->SetLastError(Socket::E_UNKNOWN);
						return -1;
					}

					return concurrency::create_task(completionEvent).get();
				});

				return 0;
			}

			bool IsReadable(int id = 0) 
			{

				if (m_type == Socket::T_STREAM)
				{
					// In connection-oriented socket, if the socket is closed recv should return immmediately
					if (IsOpened() == false)
						return true;

					HRESULT hr;

					if (GetConnection(id).valid() == false)
						return false;

					unsigned int buffer_length;
					hr = GetConnection(id).m_reader->get_UnconsumedBufferLength(&buffer_length);
					if (FAILED(hr)) 
					{
						return false;
					}

					if (buffer_length > 0)
						return true;

					if (m_loadingAsync == false)
					{
						m_loadingAsync = true;

						return run_now(
						[this, id]() -> bool
						{ 
							HRESULT hr;
							// Try to read data
							Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncOperation<unsigned int> > action;
							hr = GetConnection(id).m_reader->LoadAsync(min_read_bytes, &action);
							if (FAILED(hr)) 
							{
								return false;
							}

							// Set receive completion handler
							hr = action->put_Completed(Microsoft::WRL::Callback<__FIAsyncOperationCompletedHandler_1_UINT32 >(
							[this](ABI::Windows::Foundation::IAsyncOperation<unsigned int>* operation, ABI::Windows::Foundation::AsyncStatus asyncStatus)->HRESULT
							{
								m_loadingAsync = false;
								return S_OK;
							}).Get());

							// not readable now, so return false
							return false;
						});
					}

					return false;
				}
				else
				{
					return (m_udpMessageBuffer.empty() == false);
				}

				return false;
			}

			int Receive(void* buf_out, int size, int id = 0)
			{
				if (IsConnected() == false)
					return -1;

				if (buf_out == 0 || size < 0)
					return -1;

				if (size == 0)
					return 0;

				return run_now(
				[this, buf_out, size, id]() -> int
				{ 
					HRESULT hr;
					if (GetConnection(id).valid() == false)
						return -1;

					UINT32 buffer_length;
					hr = GetConnection(id).m_reader->get_UnconsumedBufferLength(&buffer_length);
					if (buffer_length == 0)
					{
						if (m_loadingAsync == true)
							return -1; // already waiting for data. No data available.

						// Read async into reader
						Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncOperation<unsigned int> > action;
						hr = GetConnection(id).m_reader->LoadAsync(size-buffer_length, &action);
						if (FAILED(hr)) 
						{
							this->SetLastError(Socket::E_UNKNOWN);
							return -1;
						}

						// Task completion event that is set when the request operation completes.
						concurrency::task_completion_event<unsigned int> completionEvent;

						m_loadingAsync = true;

						// Set receive completion handler
						hr = action->put_Completed(Microsoft::WRL::Callback<__FIAsyncOperationCompletedHandler_1_UINT32 >(
						[this, id, buf_out, size, completionEvent](ABI::Windows::Foundation::IAsyncOperation<unsigned int>* operation, ABI::Windows::Foundation::AsyncStatus asyncStatus)->HRESULT
						{
							HRESULT hr;

							m_loadingAsync = false;

							unsigned int buffer_length = 0;

							if (asyncStatus == ABI::Windows::Foundation::AsyncStatus::Error)
							{
								this->SetLastError(Socket::E_UNKNOWN);
							}

							if (asyncStatus == ABI::Windows::Foundation::AsyncStatus::Completed)
							{
								hr = GetConnection(id).m_reader->get_UnconsumedBufferLength(&buffer_length);
								if (buffer_length > 0)
								{
									buffer_length = (std::min)(buffer_length, (unsigned int)size);
									hr = GetConnection(id).m_reader->ReadBytes(buffer_length, (BYTE*)buf_out);
									if (FAILED(hr)) 
									{
										this->SetLastError(Socket::E_UNKNOWN);
									}
								}
							}

							if (m_blocking == true)
							{
								completionEvent.set(buffer_length);
							}

							return S_OK;
						}).Get());
						if (FAILED(hr)) 
						{
							this->SetLastError(Socket::E_UNKNOWN);
							return -1;
						}


						if (m_blocking == true)
						{
							return concurrency::create_task(completionEvent).get();
						}

						return 0;
					}
					else
					{
						// read available bytes
						buffer_length = (std::min)(buffer_length, (unsigned int)size);
						hr = GetConnection(id).m_reader->ReadBytes(buffer_length, (BYTE*)buf_out);
						if (FAILED(hr)) 
						{
							return -1;
						}

						if (m_loadingAsync == false)
						{
							m_loadingAsync = true;

							// Try to read data
							Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncOperation<unsigned int> > action;
							hr = GetConnection(id).m_reader->LoadAsync(size-buffer_length, &action);
							if (FAILED(hr)) 
							{
								return false;
							}

							// Set receive completion handler
							hr = action->put_Completed(Microsoft::WRL::Callback<__FIAsyncOperationCompletedHandler_1_UINT32 >(
							[this](ABI::Windows::Foundation::IAsyncOperation<unsigned int>* operation, ABI::Windows::Foundation::AsyncStatus asyncStatus)->HRESULT
							{
								m_loadingAsync = false;
								return S_OK;
							}).Get());
						}

						return buffer_length;
					}
				});
			}

			int ReceiveFrom(AddrIpv4& addr_out, void* buf_out, int size)
			{
				if (IsOpened() == false)
					return -1;

				if (buf_out == 0 || size < 0)
					return -1;

				if (size == 0)
					return 0;

				return run_now(
				[this, &addr_out, buf_out, size]() -> int
				{ 

					HRESULT hr;

					if (m_blocking == true)
					{
						concurrency::create_task(m_udpMessageEvent).wait();
					}

					Microsoft::WRL::ComPtr<ABI::Windows::Storage::Streams::IDataReader> reader;
					{
						std::lock_guard<std::mutex> lock(m_udpMessageBufferMutex);
						if (m_udpMessageBuffer.empty())
							return 0;

						auto message = m_udpMessageBuffer.back();
						m_udpMessageBuffer.pop_back();

						reader = std::get<0>(message);
						addr_out = std::get<1>(message);
					}

					unsigned int result;
					hr = reader->get_UnconsumedBufferLength(&result);
					if (FAILED(hr)) 
					{
						this->SetLastError(Socket::E_UNKNOWN);
						return -1;
					}

					if (result == 0)
						return 0;

					result = (std::min)((unsigned int)size, result);

					hr = reader->ReadBytes(result, (BYTE*)buf_out);
					if (FAILED(hr)) 
					{
						this->SetLastError(Socket::E_UNKNOWN);
						return -1;
					}

					return (int)result;		
				});

				return false;
			}

			bool GetAddress(AddrIpv4& addr)
			{
				if (IsOpened() == false)
					return false;

				Microsoft::WRL::ComPtr<ABI::Windows::Networking::IHostName> pHostName;
				Microsoft::WRL::Wrappers::HString port;

				HRESULT hr;
				if (m_type == Socket::T_STREAM)
				{
					for (auto tcpConnection: m_tcpConnections)
					{
						if (tcpConnection.valid() == false)
							continue;

						Microsoft::WRL::ComPtr<ABI::Windows::Networking::Sockets::IStreamSocketInformation> socketinfo;
						hr = tcpConnection.m_socket->get_Information(&socketinfo);
						if (FAILED(hr)) 
						{
							return false;
						}

						hr = socketinfo->get_LocalAddress(&pHostName);
						if (FAILED(hr)) 
						{
							return false;
						}

						hr = socketinfo->get_LocalPort(port.GetAddressOf());
						if (FAILED(hr)) 
						{
							return false;
						}

						return true;
					}

					return false;

				}
				else // udp socket
				{
					Microsoft::WRL::ComPtr<ABI::Windows::Networking::Sockets::IDatagramSocketInformation> socketinfo;
					hr = m_udpSocket->get_Information(&socketinfo);
					if (FAILED(hr)) 
					{
						return false;
					}

					hr = socketinfo->get_LocalAddress(&pHostName);
					if (FAILED(hr)) 
					{
						return false;
					}

					hr = socketinfo->get_LocalPort(port.GetAddressOf());
					if (FAILED(hr)) 
					{
						return false;
					}
				}

				if (GLWEBTOOLS_FAIL(GetIpv4Addr(pHostName.Get(), addr)))
				{
					return false;
				}

				addr.port = port_htoi(port.Get());

				return true;
			}

			bool GetRemoteAddress(AddrIpv4& addr)
			{
				if (IsOpened() == false)
					return false;

				Microsoft::WRL::ComPtr<ABI::Windows::Networking::IHostName> pHostName;
				Microsoft::WRL::Wrappers::HString port;

				HRESULT hr;
				if (m_type == Socket::T_STREAM)
				{
					for (auto tcpConnection: m_tcpConnections)
					{
						if (tcpConnection.valid() == false)
							continue;

						Microsoft::WRL::ComPtr<ABI::Windows::Networking::Sockets::IStreamSocketInformation> socketinfo;
						hr = tcpConnection.m_socket->get_Information(&socketinfo);
						if (FAILED(hr)) 
						{
							return false;
						}

						hr = socketinfo->get_RemoteAddress(&pHostName);
						if (FAILED(hr)) 
						{
							return false;
						}

						hr = socketinfo->get_RemotePort(port.GetAddressOf());
						if (FAILED(hr)) 
						{
							return false;
						}

						return true;
					}

					return false;
				}
				else // udp socket
				{
					Microsoft::WRL::ComPtr<ABI::Windows::Networking::Sockets::IDatagramSocketInformation> socketinfo;
					hr = m_udpSocket->get_Information(&socketinfo);
					if (FAILED(hr)) 
					{
						return false;
					}

					hr = socketinfo->get_RemoteAddress(&pHostName);
					if (FAILED(hr)) 
					{
						return false;
					}

					hr = socketinfo->get_RemotePort(port.GetAddressOf());
					if (FAILED(hr)) 
					{
						return false;
					}
				}

				if (GLWEBTOOLS_FAIL(GetIpv4Addr(pHostName.Get(), addr)))
				{
					return false;
				}

				addr.port = port_htoi(port.Get());

				return true;
			}

			Error GetLastError() const
			{
				return m_lastError;
			}

			void SetLastError(Error error)
			{
				m_lastError = error;
			}

			void ClearError()
			{
				m_lastError = Socket::E_NONE;
			}

			static Error Init()
			{
				return Socket::E_NONE;
			}

			static Error Deinit()
			{
				return Socket::E_NONE;
			}

			static std::string GetHostName()
			{
				HRESULT hr;

				Microsoft::WRL::ComPtr<ABI::Windows::Networking::Connectivity::INetworkInformationStatics> networkInformation;
				hr = Windows::Foundation::GetActivationFactory(Microsoft::WRL::Wrappers::HString::MakeReference(RuntimeClass_Windows_Networking_Connectivity_NetworkInformation).Get(), &networkInformation);
				if (FAILED(hr)) 
				{
					return "";
				}

				Microsoft::WRL::ComPtr<__FIVectorView_1_Windows__CNetworking__CHostName> hostNames;
				hr = networkInformation->GetHostNames(&hostNames);
				if (FAILED(hr)) 
				{
					return "";
				}

				Microsoft::WRL::ComPtr<ABI::Windows::Networking::IHostName> hostName;
				hr = hostNames->GetAt(0, &hostName);
				if (FAILED(hr)) 
				{
					return "";
				}

				Microsoft::WRL::Wrappers::HString hsHostName;
				hr = hostName->get_DisplayName(hsHostName.GetAddressOf());
				if (FAILED(hr)) 
				{
					return "";
				}

				return htos(hsHostName.Get());
			}

			static const char *GetAddrIP(const AddrIpv4 &addr)
			{
				return inet_ntoa(addr).c_str();
			}

			static AddrIpv4 MakeAddr(const char *ip, int port)
			{
				AddrIpv4 addr;
				addr.Addr.ulongAddr = inet_addr(ip);
				addr.port = (unsigned short)port;

				return addr;
			}

			static int ResolveHostTCP(const char* host, int port, AddrIpv4 &address)
			{
				HRESULT hr;

				Microsoft::WRL::ComPtr<IInspectable> pInspectable;
				hr = ::RoActivateInstance(Microsoft::WRL::Wrappers::HString::MakeReference(RuntimeClass_Windows_Networking_Sockets_DatagramSocket).Get(), &pInspectable);
				if (FAILED(hr)) 
				{
					return -1;
				}

				Microsoft::WRL::ComPtr<ABI::Windows::Networking::Sockets::IDatagramSocket> udpSocket;
				hr = pInspectable.As(&udpSocket);
				if (FAILED(hr)) 
				{
					return -1;
				}

				bool result = run_now(
				[udpSocket, host, port]() -> bool
				{ 
					HRESULT hr;

					// Set serviceName
					Microsoft::WRL::Wrappers::HString serviceName;

					hr = serviceName.Set(port_itow(port).c_str());
					if (FAILED(hr)) 
					{
						return false;
					}

					// Set hostName
					Microsoft::WRL::Wrappers::HString hostName;

					std::wstring s = stows(host);
					hr = hostName.Set(s.c_str());
					if (FAILED(hr)) 
					{
						return false;
					}
					
					Microsoft::WRL::ComPtr<ABI::Windows::Networking::IHostNameFactory> pHostNameFactory;
					hr = Windows::Foundation::GetActivationFactory(Microsoft::WRL::Wrappers::HString::MakeReference(RuntimeClass_Windows_Networking_HostName).Get(), &pHostNameFactory);
					if (FAILED(hr)) 
					{
						return false;
					}

					Microsoft::WRL::ComPtr<ABI::Windows::Networking::IHostName> pHostName;
					hr = pHostNameFactory->CreateHostName(hostName.Get(), &pHostName);
					if (FAILED(hr)) 
					{
						return false;
					}

					concurrency::task_completion_event<bool> completionEvent;

					Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncAction> action;
					hr = udpSocket->ConnectAsync(pHostName.Get(), serviceName.Get(), &action);
					if (FAILED(hr)) 
					{
						return false;
					}
					hr = action->put_Completed(Microsoft::WRL::Callback<ABI::Windows::Foundation::IAsyncActionCompletedHandler>
					(
					[completionEvent](ABI::Windows::Foundation::IAsyncAction*, ABI::Windows::Foundation::AsyncStatus asyncStatus) -> HRESULT
					{
						completionEvent.set(asyncStatus == ABI::Windows::Foundation::AsyncStatus::Completed);
						return S_OK;
					}
					).Get());
					if (FAILED(hr)) 
					{
						return false;
					}
					
					concurrency::task<bool> completion_task = concurrency::create_task(completionEvent);
					return completion_task.get();
				});

				if (result == false)
					return -1;

				Microsoft::WRL::ComPtr<ABI::Windows::Networking::Sockets::IDatagramSocketInformation> socketinfo;
				hr = udpSocket->get_Information(&socketinfo);
				if (FAILED(hr)) 
				{
					return -1;
				}

				Microsoft::WRL::ComPtr<ABI::Windows::Networking::IHostName> pHostName;
				hr = socketinfo->get_RemoteAddress(&pHostName);
				if (FAILED(hr)) 
				{
					return -1;
				}

				Microsoft::WRL::Wrappers::HString hsport;
				hr = socketinfo->get_RemotePort(hsport.GetAddressOf());
				if (FAILED(hr)) 
				{
					return -1;
				}

				if (GLWEBTOOLS_FAIL(GetIpv4Addr(pHostName.Get(), address)))
				{
					return -1;
				}

				address.port = port_htoi(hsport.Get());

				return 0;
			}
		};

	}

	Socket::Socket()
	{
		m_handler = static_cast<void*>(GLWEBTOOLS_NEW socket_handler());
#if GLWEBTOOLS_DEBUG
		if(!m_handler)
		{
			GLWEBTOOLS_ASSERT(m_handler);
			GLWEBTOOLS_LOG_MAJOR_ERROR("%s", "Could not allocate socket");
		}
#endif
	}
	Socket::~Socket()
	{
		if(m_handler)
		{
			socket_handler* socket= static_cast<socket_handler*>(m_handler);
			GLWEBTOOLS_DELETE(socket);
			m_handler = 0;
		}
	}
	bool Socket::IsOpened() const
	{
		if(m_handler)
		{
			socket_handler* socket = static_cast<socket_handler*>(m_handler);
			return socket->IsOpened();
		}
		return false;
	}
	bool Socket::OpenTcp(Option option)
	{
		if(m_handler)
		{
			socket_handler* socket = static_cast<socket_handler*>(m_handler);
			return socket->OpenTcp(static_cast<socket_handler::Option>(option));
		}
		return false;
	}
	bool Socket::OpenUdp(Option option)
	{
		if(m_handler)
		{
			socket_handler* socket = static_cast<socket_handler*>(m_handler);
			return socket->OpenUdp(static_cast<socket_handler::Option>(option));
		}
		return false;
	}
	bool Socket::Open(Type type, Proto protocol, Option option)
	{
		if(m_handler)
		{
			socket_handler* socket = static_cast<socket_handler*>(m_handler);
			return socket->Open(static_cast<socket_handler::Type>(type), 
				static_cast<socket_handler::Proto>(protocol), 
				static_cast<socket_handler::Option>(option));
		}
		return false;
	}
	void Socket::Close()
	{
		if(m_handler)
		{
			socket_handler* socket = static_cast<socket_handler*>(m_handler);
			socket->Close();
		}
	}
	bool Socket::Connect(const AddrIpv4& addr)
	{
		if(m_handler)
		{
			socket_handler* socket = static_cast<socket_handler*>(m_handler);

			return socket->Connect(addr);
		}
		return false;
	}
	bool Socket::IsConnected() const
	{
		if(m_handler)
		{
			socket_handler* socket = static_cast<socket_handler*>(m_handler);
			return socket->IsConnected();
		}
		return false;
	}
	bool Socket::Bind(const AddrIpv4& addr)
	{
		if(m_handler)
		{
			socket_handler* socket = static_cast<socket_handler*>(m_handler);
			return socket->Bind(addr);
		}
		return false;
	}
	bool Socket::Listen(int backlog)
	{
		if(m_handler)
		{
			socket_handler* socket = static_cast<socket_handler*>(m_handler);
			return socket->Listen(backlog);
		}
		return false;
	}
	int Socket::Accept(AddrIpv4& addr)
	{
		if(m_handler)
		{
			socket_handler* socket = static_cast<socket_handler*>(m_handler);

			return socket->Accept(addr);
		}
		return -1;
	}
	bool Socket::Reject(int id)
	{
		if(m_handler)
		{
			socket_handler* socket = static_cast<socket_handler*>(m_handler);
			return socket->Reject(id);
		}
		return false;
	}
	int Socket::Send(const void* buf, int size, int id)
	{
		if(m_handler)
		{
			socket_handler* socket = static_cast<socket_handler*>(m_handler);
			return socket->Send(buf, size, id);
		}
		return -1;
	}
	int Socket::SendTo(const AddrIpv4& addr, const void* buf, int size)
	{
		if(m_handler)
		{
			socket_handler* socket = static_cast<socket_handler*>(m_handler);
			return socket->SendTo(addr, buf, size);
		}
		return -1;
	}
	bool Socket::IsReadable(int id) const
	{
		if(m_handler)
		{
			socket_handler* socket = static_cast<socket_handler*>(m_handler);
			return socket->IsReadable(id);
		}
		return false;
	}
	int Socket::Receive(void* buf_out, int size, int id)
	{
		if(m_handler)
		{
			socket_handler* socket = static_cast<socket_handler*>(m_handler);
			return socket->Receive(buf_out, size, id);
		}
		return -1;
	}
	int Socket::ReceiveFrom(AddrIpv4& addr_out, void* buf_out, int size)
	{
		if(m_handler)
		{
			socket_handler* socket = static_cast<socket_handler*>(m_handler);
			int result = socket->ReceiveFrom(addr_out, buf_out, size);
			return result;
		}
		return -1;
	}
	bool Socket::GetAddress(AddrIpv4& addr)
	{
		if(m_handler)
		{
			socket_handler* socket = static_cast<socket_handler*>(m_handler);
			bool result = socket->GetAddress(addr);

			return result;
		}
		return false;
	}
	Socket::Error Socket::GetLastError() const
	{
		if(m_handler)
		{
			socket_handler* socket = static_cast<socket_handler*>(m_handler);
			return static_cast<Socket::Error>(socket->GetLastError());
		}
		return E_NOTINITIALIZED;
	}
	void Socket::ClearError()
	{
		if(m_handler)
		{
			socket_handler* socket = static_cast<socket_handler*>(m_handler);
			socket->ClearError();
		}
	}
	int Socket::ResolveHostTCP(const char* host, int port, glwebtools::AddrIpv4 &address)
	{
		return socket_handler::ResolveHostTCP(host, port, address);
	}
	Socket::Error Socket::Init()
	{
		socket_handler::Error err = socket_handler::Init();
		return static_cast<Socket::Error>(err);
	}
	Socket::Error Socket::Deinit()
	{
		return static_cast<Socket::Error>(socket_handler::Deinit());
	}
	std::string Socket::GetHostName()
	{
		return socket_handler::GetHostName();
	}
	const char *Socket::GetAddrIP(const AddrIpv4 &address)
	{
		return socket_handler::GetAddrIP(address);
	}
	AddrIpv4 Socket::MakeAddr(const char *ip, int port)
	{
		glwebtools::AddrIpv4 address = socket_handler::MakeAddr(ip, port);

		return address;
	}
}

#endif //GLWEBTOOLS_USE_METRO_SOCKET