Quellcode durchsuchen

Refactor TCPSocket

Daniele Bartolini vor 12 Jahren
Ursprung
Commit
af12b205c5
1 geänderte Dateien mit 173 neuen und 57 gelöschten Zeilen
  1. 173 57
      engine/os/posix/TCPSocket.h

+ 173 - 57
engine/os/posix/TCPSocket.h

@@ -26,98 +26,214 @@ OTHER DEALINGS IN THE SOFTWARE.
 
 #pragma once
 
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
 #include "Types.h"
 #include "NetAddress.h"
+#include "Assert.h"
+#include "OS.h"
 
 namespace crown
 {
 
-class TCPClient
+struct ReadResult
 {
-public:
-
-					TCPClient();
-					TCPClient(const TCPClient& c);
-					~TCPClient();
-
-	bool			connect(const os::NetAddress& destination);
-	void			close();
-	size_t			read(void* data, size_t size);
-	size_t			write(const void* data, size_t size);
-
-private:
+	enum { NO_ERROR, UNKNOWN, REMOTE_CLOSED } error;
+	size_t received_bytes;
+};
 
-					TCPClient(int socket);
+struct WriteResult
+{
+	enum { NO_ERROR, UNKNOWN, REMOTE_CLOSED } error;
+	size_t sent_bytes;
+};
 
-private:
+class TCPSocket
+{
+public:
 
-	int				m_socket;
+	//-----------------------------------------------------------------------------
+	TCPSocket()
+		: m_socket(0)
+	{
+	}
+
+	//-----------------------------------------------------------------------------
+	TCPSocket(int socket)
+		: m_socket(socket)
+	{
+	}
+
+	//-----------------------------------------------------------------------------
+	bool open(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;
+		}
+
+		return true;
+	}
+
+	//-----------------------------------------------------------------------------
+	void close()
+	{
+		if (m_socket != 0)
+		{
+			::close(m_socket);
+			m_socket = 0;
+		}
+	}
+
+	//-----------------------------------------------------------------------------
+	ReadResult read(void* data, size_t size)
+	{
+		CE_ASSERT_NOT_NULL(data);
+
+		ssize_t received_bytes = ::read(m_socket, (char*) data, size);
+
+		ReadResult result;
+
+		if (received_bytes == -1 && errno == EAGAIN)
+		{
+			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;
+		}
+
+		return result;
+	}
+
+	//-----------------------------------------------------------------------------
+	WriteResult write(const void* data, size_t size)
+	{
+		CE_ASSERT_NOT_NULL(data);
+
+		ssize_t sent_bytes = ::send(m_socket, (const char*) data, size, 0);
+
+		WriteResult result;
+
+		if (sent_bytes == -1)
+		{
+			result.error = WriteResult::UNKNOWN;
+		}
+		else
+		{
+			result.error = WriteResult::NO_ERROR;
+			result.sent_bytes = sent_bytes;
+		}
+
+		return result;
+	}
 
-private:
+public:
 
-	friend class	TCPListener;
+	int m_socket;
 };
 
 class TCPListener
 {
 public:
 
-					TCPListener(uint16_t port);
-					~TCPListener();
+	//-----------------------------------------------------------------------------
+	bool open(uint16_t port)
+	{
+		int& sock_id = m_listener.m_socket;
 
-	bool			listen(TCPClient& c);
-	void			close();
-	size_t			read(void* data, size_t size);
-	size_t			write(const void* data, size_t size);
+		sock_id = socket(AF_INET, SOCK_STREAM, 0);
+		CE_ASSERT(sock_id != -1, "Failed to open socket: errno: %d", errno);
 
-private:
+		fcntl(sock_id, F_SETFL, O_NONBLOCK);
 
-	int			m_socket;
-};
+		// Bind socket
+		sockaddr_in address;
+		address.sin_family = AF_INET;
+		address.sin_addr.s_addr = htonl(INADDR_ANY);
+		address.sin_port = htons(port);
 
-namespace os
-{
+		int bind_ret = bind(sock_id, (const sockaddr*) &address, sizeof(sockaddr_in));
+		CE_ASSERT(bind_ret != -1, "Failed to bind socket: errno: %d", errno);
 
-/// OS level TCP socket.
-class TCPSocket
-{
-public:
+		int listen_ret = ::listen(sock_id, 5);
+		CE_ASSERT(listen_ret != -1, "Failed to listen on socket: errno: %d", errno);
+
+		return true;
+	}
 
-				TCPSocket();
-				~TCPSocket();
+	//-----------------------------------------------------------------------------
+	void close()
+	{
+		m_listener.close();
+	}
 
-	// Open connection (server side)
-	bool 		open(uint16_t port);
+	//-----------------------------------------------------------------------------
+	bool listen(TCPSocket& c)
+	{
+		int& sock_id = m_listener.m_socket;
 
-	// Connect (client side)
-	bool		connect(const NetAddress& destination);
+		sockaddr_in client;
+		size_t client_length = sizeof(client);
 
-	// Close connection
-	void		close();
+		int asd = accept(sock_id, (sockaddr*)&client, (socklen_t*)&client_length);
 
-	// Send data through socket
-	bool 		send(const void* data, size_t size);
+		if (asd == -1 && errno == EWOULDBLOCK)
+		{
+			return false;
+		}
 
-	// Receive data through socket
-	size_t		receive(void* data, size_t size);
+		fcntl(asd, F_SETFL, O_NONBLOCK);
+		c.m_socket = asd;
 
-	// Is connection open?
-	bool 		is_open();
+		return true;
+	}
 
-	// Getter method for socket descriptor
-	int 		socket_id();
+	//-----------------------------------------------------------------------------
+	ReadResult read(void* data, size_t size)
+	{
+		return m_listener.read(data, size);
+	}
 
-	// Getter method for active socket descriptor
-	int 		active_socket_id();
+	//-----------------------------------------------------------------------------
+	WriteResult write(const void* data, size_t size)
+	{
+		return m_listener.write(data, size);
+	}
 
 private:
-	
-	// Generated by ::socket
-	int 		m_socket;
 
-	// Generated by ::accept
-	int 		m_active_socket;
+	TCPSocket m_listener;
 };
 
-} // namespace os
 } // namespace crown