mikymod 12 лет назад
Родитель
Сommit
ef62def9e0
1 измененных файлов с 410 добавлено и 0 удалено
  1. 410 0
      engine/os/win/OsSocket.h

+ 410 - 0
engine/os/win/OsSocket.h

@@ -0,0 +1,410 @@
+/*
+Copyright (c) 2013 Daniele Bartolini, Michele Rossi
+Copyright (c) 2012 Daniele Bartolini, Simone Boscaratto
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include <winsock2.h>
+#pragma comment(lib, "wsock32.lib")
+
+#include "NetAddress.h"
+#include "Assert.h"
+#include "Types.h"
+#include "OS.h"
+
+namespace crown
+{
+
+struct ReadResult
+{
+	enum { NO_ERROR, UNKNOWN, REMOTE_CLOSED } error;
+	size_t received_bytes;
+};
+
+struct WriteResult
+{
+	enum { NO_ERROR, UNKNOWN, REMOTE_CLOSED } error;
+	size_t sent_bytes;
+};
+
+//-----------------------------------------------------------------------------
+class TCPSocket
+{
+public:
+	//-----------------------------------------------------------------------------
+	TCPSocket()
+		: m_socket(0)
+	{
+
+	}
+
+	//-----------------------------------------------------------------------------
+	TCPSocket(int socket)
+		: m_socket(socket)
+	{
+	}
+
+	//-----------------------------------------------------------------------------
+	TCPSocket::~TCPSocket()
+	{
+		close();
+	}
+
+/*	//-----------------------------------------------------------------------------
+	bool TCPSocket::open(uint16_t port)
+	{
+		int32_t sd = socket(AF_INET, SOCK_STREAM, 0);
+
+		if (sd <= 0)
+		{
+			os::print32_tf("failed to open socket\n");
+			set_socket_id(0);
+			return false;
+		}
+
+		set_socket_id(sd);
+
+		// Bind socket
+		sockaddr_in address;
+		address.sin_family = AF_INET;
+		address.sin_addr.s_addr = htonl(INADDR_ANY);
+		address.sin_port = htons(port);
+
+		if (bind(sd, (const sockaddr*)&address, sizeof(sockaddr_in)) < 0)
+		{
+			os::print32_tf("failed to bind socket\n");
+			close();
+			return false;
+		}
+
+		listen(sd, 5);
+		os::print32_tf("listening on port %d", port);
+
+		sockaddr_in client;
+		uint32_t client_length = sizeof(client);
+
+		int32_t active_sd = accept(sd, (sockaddr*)&client, &client_length);
+		if (active_sd < 0)
+		{
+			os::print32_tf("failed to accept connections");
+		}
+
+		set_active_socket_id(active_sd);
+
+		return true;  
+	}*/
+
+	//-----------------------------------------------------------------------------
+	bool TCPSocket::connect(const NetAddress& destination, uint16_t port)
+	{		
+		int sd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+
+		if (sd <= 0)
+		{
+			os::printf("failed to open socket\n");
+			m_socket = 0;
+			return false;
+		}
+		
+		m_socket = sd;
+
+		sockaddr_in address;
+		address.sin_family = AF_INET;
+		address.sin_addr.s_addr = htonl(destination.address());
+		address.sin_port = htons(port);
+
+		if (::connect(sd, (const sockaddr*)&address, sizeof(sockaddr_in)) < 0)
+		{
+			os::printf("failed to connect socket\n");
+			close();
+			return false;
+		}
+	}
+
+	//-----------------------------------------------------------------------------
+	int32_t	TCPSocket::close()
+	{
+		if (m_socket != 0)
+		{
+			::close(m_socket);
+			m_socket = 0;
+		}
+	}
+
+	//-----------------------------------------------------------------------------
+	ReadResult TCPSocket::read(void* data, int32_t size)
+	{
+		CE_ASSERT_NOT_NULL(data);
+
+		int received_bytes = recv(m_socket, (char*)data, size, 0);
+
+		ReadResult result;
+
+		if (received_bytes < 0)
+		{
+			result.error = ReadResult::NO_ERROR;
+			result.received_bytes = 0;
+		}
+		if (received_bytes == 0)
+		{
+			result.error = ReadResult::REMOTE_CLOSED;
+		}
+		else
+		{
+			result.error = ReadResult::NO_ERROR;
+			result.received_bytes = received_bytes;
+		}
+
+		return result;
+	}
+
+	//-----------------------------------------------------------------------------
+	bool TCPSocket::write(const void* data, int32_t size)
+	{
+		CE_ASSERT_NOT_NULL(data);
+
+		int sent_bytes = ::send(sd, (const char*)data, size, 0);
+
+		WriteResult result;
+
+		if (sent_bytes < 0)
+		{
+			result.error = WriteResult::UNKNOWN;
+		}
+		else
+		{
+			result.error = WriteResult::NO_ERROR;
+			result.sent_bytes = sent_bytes;
+		}
+
+		return result;  
+	}
+
+public:
+
+	int m_socket;
+};
+
+//-----------------------------------------------------------------------------
+class TCPListener
+{
+public:
+
+	//-----------------------------------------------------------------------------
+	bool open(uint16_t port)
+	{
+		int& sock_id = m_listener.m_socket;
+
+		sock_id = socket(AF_INET, SOCK_STREAM, 0);
+		CE_ASSERT(socket_id != INVALID_SOCKET, "Unable to open socket");
+
+		// set non-blocking io
+		DWORD non_blocking = 1;
+		int result = ioctlsocket(sock_id, FIONBIO, &non_blocking);
+		CE_ASSERT(result == 0, "Unable to set socket non-blocking");
+
+		// Bind socket
+		sockaddr_in address;
+		address.sin_family = AF_INET;
+		address.sin_addr.s_addr = htonl(INADDR_ANY);
+		address.sin_port = htons(port);
+
+		result = ::bind(sock_id, (const sockaddr*)&address, sizeof(sockaddr_in));
+		CE_ASSERT(result == 0, "Unable to bind socket");
+		
+		result = ::listen(sd, 5);
+		CE_ASSERT(result == 0, "Unable to listen on socket");
+
+		return true;  
+	}
+
+	//-----------------------------------------------------------------------------
+	void close()
+	{
+		m_listener.close();
+	}
+
+	//-----------------------------------------------------------------------------
+	bool listen(TCPSocket& c)
+	{
+		int& sock_id = m_listener.m_socket;
+
+		sockaddr_in client;
+		uint32_t client_length = sizeof(client);
+
+		int32_t asd = accept(sd, (sockaddr*)&client, &client_length);
+		if (asd < 0)
+		{
+			return false;
+		}
+
+		int result = ioctlsocket(asd, FIONBIO, &non_blocking);
+		CE_ASSERT(result == 0, "Unable to set socket non-blocking");		
+
+		c.m_socket = asd;
+
+		return true;
+	}
+
+	//-----------------------------------------------------------------------------
+	ReadResult read(void* data, size_t size)
+	{
+		return m_listener.read(data, size);
+	}
+
+	//-----------------------------------------------------------------------------
+	WriteResult write(const void* data, size_t size)
+	{
+		return m_listener.write(data, size);
+	}
+
+private:
+
+	TCPSocket m_listener;
+};
+
+//-----------------------------------------------------------------------------
+class UDPSocket
+{
+	//-----------------------------------------------------------------------------
+	UDPSocket::UDPSocket()
+		: m_socket(0)
+	{
+	}
+
+	//-----------------------------------------------------------------------------
+	UDPSocket::~UDPSocket()
+	{
+		close();
+	}
+
+	//-----------------------------------------------------------------------------
+	bool UDPSocket::open(uint16_t port)
+	{
+		CE_ASSERT(!is_open(), "Socket is already open");
+
+		m_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+		CE_ASSERT(m_socket != INVALID_SOCKET, "Unable to open socket");
+
+		// bind to port
+		sockaddr_in address;
+		address.sin_family = AF_INET;
+		address.sin_addr.s_addr = INADDR_ANY;
+		address.sin_port = htons(port);
+
+		int result = ::bind(m_socket, (const sockaddr*)&address, sizeof(sockaddr_in));
+		CE_ASSERT(result == 0, "Unable to bind socket");
+
+		// set non-blocking io
+		DWORD non_blocking = 1;
+		result = ioctlsocket(socket, FIONBIO, &non_blocking);
+		CE_ASSERT(result == 0, "Unable to bind socket");
+
+		return true;
+	}
+
+	//-----------------------------------------------------------------------------
+	ReadResult UDPSocket::read(NetAddress& sender, uint16_t& port, const void* data, size_t size)
+	{
+		CE_ASSERT_NOT_NULL(data);
+
+		typedef int socklen_t;
+
+		sockaddr_in from;
+		socklen_t from_length = sizeof(from);
+
+		int received_bytes = recvfrom(m_socket, (char*)data, size, 0, (sockaddr*)&from, &from_length);
+
+		ReadResult result;
+
+		if (received_bytes < 0)
+		{
+			result.error = ReadResult::NO_ERROR;
+			result.received_bytes = 0;
+		}
+		else if (received_bytes == 0)
+		{
+			result.error = ReadResult::REMOTE_CLOSED;
+		}
+		else
+		{
+			result.error = ReadResult::NO_ERROR;
+			result.received_bytes = received_bytes;
+		}
+
+		sender.set(ntohl(from.sin_addr.s_addr));
+		port = ntohs(from.sin_port);
+
+		return result;
+	}
+
+	//-----------------------------------------------------------------------------
+	WriteResult UDPSocket::write(const NetAddress& receiver, uint16_t port, void* data, size_t size)
+	{
+		CE_ASSERT_NOT_NULL(data);
+
+		if (m_socket == 0)
+		{
+			return false;
+		}
+
+		sockaddr_in address;
+		address.sin_family = AF_INET;
+		address.sin_addr.s_addr = htonl(receiver.get_address());
+		address.sin_port = htons(receiver.get_port());
+
+		int32_t sent_bytes = sendto(m_socket, (const char*)data, size, 0, (sockaddr*)&address, sizeof(sockaddr_in));
+
+		WriteResult result;
+
+		if (sent_bytes < 0)
+		{
+			result.error = WriteResult::UNKNOWN;
+			return result;
+		}
+
+		result.error = WriteResult::NO_ERROR;
+		result.sent_bytes = sent_bytes;
+
+		return result;
+	}
+
+	//-----------------------------------------------------------------------------
+	void UDPSocket::close()
+	{
+		if (m_socket != 0)
+		{
+			::close(m_socket);
+			m_socket = 0;
+		}
+	}
+
+	//-----------------------------------------------------------------------------
+	bool UDPSocket::is_open()
+	{
+		return m_socket != 0; 
+	}
+
+};
+
+} // namespace crown