|
|
@@ -26,27 +26,34 @@ OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
-//Undefined in WinHeaders.h, but winsock2 ecc need it.
|
|
|
-#ifndef NEAR
|
|
|
-#define NEAR
|
|
|
-#endif
|
|
|
-#ifndef FAR
|
|
|
-#define FAR
|
|
|
-#endif
|
|
|
-
|
|
|
-#include <winsock2.h>
|
|
|
-#include "win_headers.h"
|
|
|
-
|
|
|
-//Re-undef NEAR and FAR after use
|
|
|
-#undef NEAR
|
|
|
-#undef FAR
|
|
|
-
|
|
|
+#include "config.h"
|
|
|
+#include "types.h"
|
|
|
#include "net_address.h"
|
|
|
#include "assert.h"
|
|
|
-#include "types.h"
|
|
|
#include "os.h"
|
|
|
|
|
|
-#pragma comment(lib, "Ws2_32.lib")
|
|
|
+#if CROWN_PLATFORM_POSIX
|
|
|
+ #include <sys/socket.h>
|
|
|
+ #include <sys/types.h>
|
|
|
+ #include <netinet/in.h>
|
|
|
+ #include <fcntl.h>
|
|
|
+ #include <unistd.h>
|
|
|
+ #include <errno.h>
|
|
|
+#elif CROWN_PLATFORM_WINDOWS
|
|
|
+ //Undefined in WinHeaders.h, but winsock2 ecc need it.
|
|
|
+ #ifndef NEAR
|
|
|
+ #define NEAR
|
|
|
+ #endif
|
|
|
+ #ifndef FAR
|
|
|
+ #define FAR
|
|
|
+ #endif
|
|
|
+ #include <winsock2.h>
|
|
|
+ #include "win_headers.h"
|
|
|
+ //Re-undef NEAR and FAR after use
|
|
|
+ #undef NEAR
|
|
|
+ #undef FAR
|
|
|
+ #pragma comment(lib, "Ws2_32.lib")
|
|
|
+#endif
|
|
|
|
|
|
namespace crown
|
|
|
{
|
|
|
@@ -68,9 +75,8 @@ struct AcceptResult
|
|
|
enum { NO_ERROR, NO_CONNECTION, UNKNOWN } error;
|
|
|
};
|
|
|
|
|
|
-class TCPSocket
|
|
|
+struct TCPSocket
|
|
|
{
|
|
|
-public:
|
|
|
//-----------------------------------------------------------------------------
|
|
|
TCPSocket()
|
|
|
: m_socket(0)
|
|
|
@@ -87,18 +93,18 @@ public:
|
|
|
bool connect(const NetAddress& destination, uint16_t port)
|
|
|
{
|
|
|
m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
|
|
-
|
|
|
CE_ASSERT(m_socket > 0, "Failed to create socket");
|
|
|
|
|
|
- sockaddr_in address;
|
|
|
- address.sin_family = AF_INET;
|
|
|
- address.sin_addr.s_addr = ::htonl(destination.address());
|
|
|
- address.sin_port = ::htons(port);
|
|
|
+ sockaddr_in addr_in;
|
|
|
+ addr_in.sin_family = AF_INET;
|
|
|
+ addr_in.sin_addr.s_addr = htonl(destination.address());
|
|
|
+ addr_in.sin_port = htons(port);
|
|
|
|
|
|
- if (::connect(m_socket, (const sockaddr*)&address, sizeof(sockaddr_in)) < 0)
|
|
|
+ if (::connect(m_socket, (const sockaddr*)&addr_in, sizeof(sockaddr_in)) < 0)
|
|
|
{
|
|
|
os::printf("Failed to connect socket\n");
|
|
|
close();
|
|
|
+
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
@@ -110,7 +116,7 @@ public:
|
|
|
{
|
|
|
if (m_socket != 0)
|
|
|
{
|
|
|
- ::closesocket(m_socket);
|
|
|
+ ::close(m_socket);
|
|
|
m_socket = 0;
|
|
|
}
|
|
|
}
|
|
|
@@ -119,22 +125,18 @@ public:
|
|
|
ReadResult read_nonblock(void* data, size_t size)
|
|
|
{
|
|
|
set_blocking(false);
|
|
|
- int read_bytes = ::recv(m_socket, (char*) data, size, 0);
|
|
|
+ ssize_t read_bytes = ::read(m_socket, (char*) data, size);
|
|
|
|
|
|
ReadResult result;
|
|
|
- if (read_bytes == SOCKET_ERROR && (errno == WSAEWOULDBLOCK))
|
|
|
+ if (read_bytes == -1 && (errno == EAGAIN || errno == EWOULDBLOCK))
|
|
|
{
|
|
|
result.error = ReadResult::NO_ERROR;
|
|
|
result.bytes_read = 0;
|
|
|
}
|
|
|
- else if (read_bytes == SOCKET_ERROR && errno == WSAETIMEDOUT)
|
|
|
+ else if (read_bytes == -1 && errno == ETIMEDOUT)
|
|
|
{
|
|
|
result.error = ReadResult::TIMEOUT;
|
|
|
}
|
|
|
- else if (read_bytes == SOCKET_ERROR)
|
|
|
- {
|
|
|
- result.error = ReadResult::UNKNOWN;
|
|
|
- }
|
|
|
else if (read_bytes == 0)
|
|
|
{
|
|
|
result.error = ReadResult::REMOTE_CLOSED;
|
|
|
@@ -162,10 +164,10 @@ public:
|
|
|
|
|
|
while (to_read > 0)
|
|
|
{
|
|
|
- int read_bytes = recv(m_socket, buf, to_read, 0);
|
|
|
+ ssize_t read_bytes = ::read(m_socket, buf, to_read);
|
|
|
|
|
|
- if (read_bytes == SOCKET_ERROR && (errno == WSAEWOULDBLOCK)) continue;
|
|
|
- else if (read_bytes == SOCKET_ERROR && errno == WSAETIMEDOUT)
|
|
|
+ if (read_bytes == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) continue;
|
|
|
+ else if (read_bytes == -1 && errno == ETIMEDOUT)
|
|
|
{
|
|
|
result.error = ReadResult::TIMEOUT;
|
|
|
return result;
|
|
|
@@ -189,15 +191,15 @@ public:
|
|
|
WriteResult write_nonblock(const void* data, size_t size)
|
|
|
{
|
|
|
set_blocking(false);
|
|
|
- int bytes_wrote = ::send(m_socket, (char*)data, size, 0);
|
|
|
+ ssize_t bytes_wrote = ::send(m_socket, data, size, 0);
|
|
|
|
|
|
WriteResult result;
|
|
|
- if (bytes_wrote == SOCKET_ERROR && (errno == WSAEWOULDBLOCK))
|
|
|
+ if (bytes_wrote == -1 && (errno == EAGAIN || errno == EWOULDBLOCK))
|
|
|
{
|
|
|
result.error = WriteResult::NO_ERROR;
|
|
|
result.bytes_wrote = 0;
|
|
|
}
|
|
|
- else if (bytes_wrote == SOCKET_ERROR && errno == WSAETIMEDOUT)
|
|
|
+ else if (bytes_wrote == -1 && errno == ETIMEDOUT)
|
|
|
{
|
|
|
result.error = WriteResult::TIMEOUT;
|
|
|
}
|
|
|
@@ -227,18 +229,18 @@ public:
|
|
|
// Ensure all data is sent
|
|
|
while (to_send > 0)
|
|
|
{
|
|
|
- int bytes_wrote = ::send(m_socket, (const char*) buf, to_send, 0);
|
|
|
+ ssize_t bytes_wrote = ::send(m_socket, (const char*) buf, to_send, 0);
|
|
|
|
|
|
// Check for errors
|
|
|
- if (bytes_wrote == SOCKET_ERROR)
|
|
|
+ if (bytes_wrote == -1)
|
|
|
{
|
|
|
switch (errno)
|
|
|
{
|
|
|
- case WSAEWOULDBLOCK:
|
|
|
+ case EAGAIN:
|
|
|
{
|
|
|
continue;
|
|
|
}
|
|
|
- case WSAETIMEDOUT:
|
|
|
+ case ETIMEDOUT:
|
|
|
{
|
|
|
result.error = WriteResult::TIMEOUT;
|
|
|
return result;
|
|
|
@@ -263,16 +265,15 @@ public:
|
|
|
//-----------------------------------------------------------------------------
|
|
|
void set_blocking(bool blocking)
|
|
|
{
|
|
|
- //Warning! Blocking sockets under windows seem to have some drawback, see http://www.sockets.com/winsock.htm#IoctlSocket
|
|
|
- u_long non_blocking = blocking ? 0 : 1;
|
|
|
- ioctlsocket(m_socket, FIONBIO, &non_blocking);
|
|
|
+ int flags = fcntl(m_socket, F_GETFL, 0);
|
|
|
+ fcntl(m_socket, F_SETFL, blocking ? (flags & ~O_NONBLOCK) : O_NONBLOCK);
|
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
void set_resuse_address(bool reuse)
|
|
|
{
|
|
|
int optval = (int) reuse;
|
|
|
- setsockopt(m_socket, SOL_SOCKET, SO_REUSEADDR, (char*)&optval, sizeof(optval));
|
|
|
+ setsockopt(m_socket, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
|
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
@@ -290,13 +291,11 @@ public:
|
|
|
|
|
|
public:
|
|
|
|
|
|
- SOCKET m_socket;
|
|
|
+ int m_socket;
|
|
|
};
|
|
|
|
|
|
-class TCPServer
|
|
|
+struct TCPServer
|
|
|
{
|
|
|
-public:
|
|
|
-
|
|
|
//-----------------------------------------------------------------------------
|
|
|
bool open(uint16_t port)
|
|
|
{
|
|
|
@@ -313,6 +312,7 @@ public:
|
|
|
|
|
|
int bind_ret = bind(m_server.m_socket, (const sockaddr*) &address, sizeof(sockaddr_in));
|
|
|
CE_ASSERT(bind_ret != -1, "Failed to bind socket: errno: %d", errno);
|
|
|
+ CE_UNUSED(bind_ret);
|
|
|
|
|
|
return true;
|
|
|
}
|
|
|
@@ -328,6 +328,7 @@ public:
|
|
|
{
|
|
|
int listen_ret = ::listen(m_server.m_socket, max);
|
|
|
CE_ASSERT(listen_ret != -1, "Failed to listen on socket: errno: %d", errno);
|
|
|
+ CE_UNUSED(listen_ret);
|
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
@@ -337,14 +338,14 @@ public:
|
|
|
|
|
|
sockaddr_in client;
|
|
|
size_t client_size = sizeof(client);
|
|
|
- int sock = ::accept(m_server.m_socket, (sockaddr*) &client, (int*) &client_size);
|
|
|
+ int sock = ::accept(m_server.m_socket, (sockaddr*) &client, (socklen_t*) &client_size);
|
|
|
|
|
|
AcceptResult result;
|
|
|
- if (sock == SOCKET_ERROR && (errno == WSAEWOULDBLOCK))
|
|
|
+ if (sock == -1 && (errno == EAGAIN || errno == EWOULDBLOCK))
|
|
|
{
|
|
|
result.error = AcceptResult::NO_CONNECTION;
|
|
|
}
|
|
|
- else if (sock == SOCKET_ERROR)
|
|
|
+ else if (sock == -1)
|
|
|
{
|
|
|
result.error = AcceptResult::UNKNOWN;
|
|
|
}
|
|
|
@@ -365,10 +366,10 @@ public:
|
|
|
sockaddr_in client;
|
|
|
size_t client_size = sizeof(client);
|
|
|
|
|
|
- int sock = ::accept(m_server.m_socket, (sockaddr*) &client, (int*) &client_size);
|
|
|
+ int sock = ::accept(m_server.m_socket, (sockaddr*) &client, (socklen_t*) &client_size);
|
|
|
|
|
|
AcceptResult result;
|
|
|
- if (sock == SOCKET_ERROR)
|
|
|
+ if (sock == -1)
|
|
|
{
|
|
|
result.error = AcceptResult::UNKNOWN;
|
|
|
}
|
|
|
@@ -410,53 +411,38 @@ private:
|
|
|
TCPSocket m_server;
|
|
|
};
|
|
|
|
|
|
-class UDPSocket
|
|
|
+/*
|
|
|
+class TCPSocket
|
|
|
{
|
|
|
public:
|
|
|
-
|
|
|
//-----------------------------------------------------------------------------
|
|
|
- UDPSocket()
|
|
|
+ TCPSocket()
|
|
|
: m_socket(0)
|
|
|
{
|
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
- bool open(uint16_t port)
|
|
|
+ TCPSocket(int socket)
|
|
|
+ : m_socket(socket)
|
|
|
{
|
|
|
- CE_ASSERT(!is_open(), "Socket is already open");
|
|
|
-
|
|
|
- m_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
|
|
+ }
|
|
|
|
|
|
- if (m_socket <= 0)
|
|
|
- {
|
|
|
- os::printf("Failed to create socket.\n");
|
|
|
- m_socket = 0;
|
|
|
+ //-----------------------------------------------------------------------------
|
|
|
+ bool connect(const NetAddress& destination, uint16_t port)
|
|
|
+ {
|
|
|
+ m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
|
|
|
|
|
- return false;
|
|
|
- }
|
|
|
+ CE_ASSERT(m_socket > 0, "Failed to create socket");
|
|
|
|
|
|
- // Bind to port
|
|
|
sockaddr_in address;
|
|
|
address.sin_family = AF_INET;
|
|
|
- address.sin_addr.s_addr = INADDR_ANY;
|
|
|
- address.sin_port = htons(port);
|
|
|
-
|
|
|
- if (bind(m_socket, (const sockaddr*) &address, sizeof(sockaddr_in)) < 0)
|
|
|
- {
|
|
|
- os::printf("Failed to bind socket\n");
|
|
|
- close();
|
|
|
-
|
|
|
- return false;
|
|
|
- }
|
|
|
+ address.sin_addr.s_addr = ::htonl(destination.address());
|
|
|
+ address.sin_port = ::htons(port);
|
|
|
|
|
|
- //Warning! Blocking sockets under windows seem to have some drawback, see http://www.sockets.com/winsock.htm#IoctlSocket
|
|
|
- u_long non_blocking = 1;
|
|
|
- //if (fcntl(m_socket, F_SETFL, O_NONBLOCK, 1) == -1)
|
|
|
- if (ioctlsocket(m_socket, FIONBIO, &non_blocking) == SOCKET_ERROR)
|
|
|
+ if (::connect(m_socket, (const sockaddr*)&address, sizeof(sockaddr_in)) < 0)
|
|
|
{
|
|
|
- os::printf("Failed to set non-blocking socket\n");
|
|
|
+ os::printf("Failed to connect socket\n");
|
|
|
close();
|
|
|
-
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
@@ -474,71 +460,176 @@ public:
|
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
- ReadResult read(NetAddress& sender, uint16_t& port, const void* data, size_t size)
|
|
|
+ ReadResult read_nonblock(void* data, size_t size)
|
|
|
{
|
|
|
- CE_ASSERT_NOT_NULL(data);
|
|
|
-
|
|
|
- sockaddr_in from;
|
|
|
- int from_length = sizeof(from);
|
|
|
-
|
|
|
- int received_bytes = recvfrom(m_socket, (char*)data, size, 0, (sockaddr*)&from, &from_length);
|
|
|
+ set_blocking(false);
|
|
|
+ int read_bytes = ::recv(m_socket, (char*) data, size, 0);
|
|
|
|
|
|
ReadResult result;
|
|
|
-
|
|
|
- if (received_bytes == SOCKET_ERROR && errno == WSAEWOULDBLOCK)
|
|
|
+ if (read_bytes == SOCKET_ERROR && (errno == WSAEWOULDBLOCK))
|
|
|
{
|
|
|
result.error = ReadResult::NO_ERROR;
|
|
|
result.bytes_read = 0;
|
|
|
}
|
|
|
- else if (received_bytes == SOCKET_ERROR)
|
|
|
+ else if (read_bytes == SOCKET_ERROR && errno == WSAETIMEDOUT)
|
|
|
+ {
|
|
|
+ result.error = ReadResult::TIMEOUT;
|
|
|
+ }
|
|
|
+ else if (read_bytes == SOCKET_ERROR)
|
|
|
{
|
|
|
result.error = ReadResult::UNKNOWN;
|
|
|
}
|
|
|
- else if (received_bytes == 0)
|
|
|
+ else if (read_bytes == 0)
|
|
|
{
|
|
|
result.error = ReadResult::REMOTE_CLOSED;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
result.error = ReadResult::NO_ERROR;
|
|
|
- result.bytes_read = received_bytes;
|
|
|
+ result.bytes_read = read_bytes;
|
|
|
}
|
|
|
|
|
|
- sender.set(ntohl(from.sin_addr.s_addr));
|
|
|
- port = ntohs(from.sin_port);
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ //-----------------------------------------------------------------------------
|
|
|
+ ReadResult read(void* data, size_t size)
|
|
|
+ {
|
|
|
+ set_blocking(true);
|
|
|
+
|
|
|
+ // Ensure all data is read
|
|
|
+ char* buf = (char*) data;
|
|
|
+ size_t to_read = size;
|
|
|
+ ReadResult result;
|
|
|
+ result.bytes_read = 0;
|
|
|
+ result.error = ReadResult::NO_ERROR;
|
|
|
+
|
|
|
+ while (to_read > 0)
|
|
|
+ {
|
|
|
+ int read_bytes = recv(m_socket, buf, to_read, 0);
|
|
|
+
|
|
|
+ if (read_bytes == SOCKET_ERROR && (errno == WSAEWOULDBLOCK)) continue;
|
|
|
+ else if (read_bytes == SOCKET_ERROR && errno == WSAETIMEDOUT)
|
|
|
+ {
|
|
|
+ result.error = ReadResult::TIMEOUT;
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ else if (read_bytes == 0)
|
|
|
+ {
|
|
|
+ result.error = ReadResult::REMOTE_CLOSED;
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ buf += read_bytes;
|
|
|
+ to_read -= read_bytes;
|
|
|
+ result.bytes_read += read_bytes;
|
|
|
+ }
|
|
|
|
|
|
+ result.error = ReadResult::NO_ERROR;
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
- WriteResult write(const NetAddress& receiver, uint16_t port, void* data, size_t size)
|
|
|
+ WriteResult write_nonblock(const void* data, size_t size)
|
|
|
{
|
|
|
- CE_ASSERT_NOT_NULL(data);
|
|
|
+ set_blocking(false);
|
|
|
+ int bytes_wrote = ::send(m_socket, (char*)data, size, 0);
|
|
|
|
|
|
- sockaddr_in address;
|
|
|
- address.sin_family = AF_INET;
|
|
|
- address.sin_addr.s_addr = htonl(receiver.address());
|
|
|
- address.sin_port = htons(port);
|
|
|
+ WriteResult result;
|
|
|
+ if (bytes_wrote == SOCKET_ERROR && (errno == WSAEWOULDBLOCK))
|
|
|
+ {
|
|
|
+ result.error = WriteResult::NO_ERROR;
|
|
|
+ result.bytes_wrote = 0;
|
|
|
+ }
|
|
|
+ else if (bytes_wrote == SOCKET_ERROR && errno == WSAETIMEDOUT)
|
|
|
+ {
|
|
|
+ result.error = WriteResult::TIMEOUT;
|
|
|
+ }
|
|
|
+ else if (bytes_wrote == 0)
|
|
|
+ {
|
|
|
+ result.error = WriteResult::REMOTE_CLOSED;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ result.error = WriteResult::UNKNOWN;
|
|
|
+ }
|
|
|
|
|
|
- int bytes_wrote = sendto(m_socket, (const char*) data, size, 0, (sockaddr*) &address, sizeof(sockaddr_in));
|
|
|
+ return result;
|
|
|
+ }
|
|
|
|
|
|
+ //-----------------------------------------------------------------------------
|
|
|
+ WriteResult write(const void* data, size_t size)
|
|
|
+ {
|
|
|
+ set_blocking(true);
|
|
|
+
|
|
|
+ const char* buf = (const char*) data;
|
|
|
+ size_t to_send = size;
|
|
|
WriteResult result;
|
|
|
+ result.bytes_wrote = 0;
|
|
|
+ result.error = WriteResult::NO_ERROR;
|
|
|
|
|
|
- if (bytes_wrote == SOCKET_ERROR)
|
|
|
+ // Ensure all data is sent
|
|
|
+ while (to_send > 0)
|
|
|
{
|
|
|
- result.error = WriteResult::UNKNOWN;
|
|
|
- return result;
|
|
|
+ int bytes_wrote = ::send(m_socket, (const char*) buf, to_send, 0);
|
|
|
+
|
|
|
+ // Check for errors
|
|
|
+ if (bytes_wrote == SOCKET_ERROR)
|
|
|
+ {
|
|
|
+ switch (errno)
|
|
|
+ {
|
|
|
+ case WSAEWOULDBLOCK:
|
|
|
+ {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ case WSAETIMEDOUT:
|
|
|
+ {
|
|
|
+ result.error = WriteResult::TIMEOUT;
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ default:
|
|
|
+ {
|
|
|
+ result.error = WriteResult::UNKNOWN;
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ buf += bytes_wrote;
|
|
|
+ to_send -= bytes_wrote;
|
|
|
+ result.bytes_wrote += bytes_wrote;
|
|
|
}
|
|
|
|
|
|
result.error = WriteResult::NO_ERROR;
|
|
|
- result.bytes_wrote = bytes_wrote;
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
- bool is_open()
|
|
|
+ void set_blocking(bool blocking)
|
|
|
+ {
|
|
|
+ //Warning! Blocking sockets under windows seem to have some drawback, see http://www.sockets.com/winsock.htm#IoctlSocket
|
|
|
+ u_long non_blocking = blocking ? 0 : 1;
|
|
|
+ ioctlsocket(m_socket, FIONBIO, &non_blocking);
|
|
|
+ }
|
|
|
+
|
|
|
+ //-----------------------------------------------------------------------------
|
|
|
+ void set_resuse_address(bool reuse)
|
|
|
+ {
|
|
|
+ int optval = (int) reuse;
|
|
|
+ setsockopt(m_socket, SOL_SOCKET, SO_REUSEADDR, (char*)&optval, sizeof(optval));
|
|
|
+ }
|
|
|
+
|
|
|
+ //-----------------------------------------------------------------------------
|
|
|
+ void set_timeout(uint32_t seconds)
|
|
|
{
|
|
|
- return m_socket != 0;
|
|
|
+ struct timeval timeout;
|
|
|
+ timeout.tv_sec = seconds;
|
|
|
+ timeout.tv_usec = 0;
|
|
|
+ int res;
|
|
|
+ res = setsockopt (m_socket, SOL_SOCKET, SO_RCVTIMEO, (char*) &timeout, sizeof(timeout));
|
|
|
+ CE_ASSERT(res == 0, "Failed to set timeout on socket: errno: %d", errno);
|
|
|
+ res = setsockopt (m_socket, SOL_SOCKET, SO_SNDTIMEO, (char*) &timeout, sizeof(timeout));
|
|
|
+ CE_ASSERT(res == 0, "Failed to set timeout on socket: errno: %d", errno);
|
|
|
}
|
|
|
|
|
|
public:
|
|
|
@@ -546,4 +637,122 @@ public:
|
|
|
SOCKET m_socket;
|
|
|
};
|
|
|
|
|
|
+class TCPServer
|
|
|
+{
|
|
|
+public:
|
|
|
+
|
|
|
+ //-----------------------------------------------------------------------------
|
|
|
+ bool open(uint16_t port)
|
|
|
+ {
|
|
|
+ m_server.m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
|
|
+ CE_ASSERT(m_server.m_socket > 0, "Failed to create socket");
|
|
|
+
|
|
|
+ m_server.set_resuse_address(true);
|
|
|
+
|
|
|
+ // Bind socket
|
|
|
+ sockaddr_in address;
|
|
|
+ address.sin_family = AF_INET;
|
|
|
+ address.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
|
+ address.sin_port = htons(port);
|
|
|
+
|
|
|
+ int bind_ret = bind(m_server.m_socket, (const sockaddr*) &address, sizeof(sockaddr_in));
|
|
|
+ CE_ASSERT(bind_ret != -1, "Failed to bind socket: errno: %d", errno);
|
|
|
+
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ //-----------------------------------------------------------------------------
|
|
|
+ void close()
|
|
|
+ {
|
|
|
+ m_server.close();
|
|
|
+ }
|
|
|
+
|
|
|
+ //-----------------------------------------------------------------------------
|
|
|
+ void listen(uint32_t max)
|
|
|
+ {
|
|
|
+ int listen_ret = ::listen(m_server.m_socket, max);
|
|
|
+ CE_ASSERT(listen_ret != -1, "Failed to listen on socket: errno: %d", errno);
|
|
|
+ }
|
|
|
+
|
|
|
+ //-----------------------------------------------------------------------------
|
|
|
+ AcceptResult accept_nonblock(TCPSocket& c)
|
|
|
+ {
|
|
|
+ m_server.set_blocking(false);
|
|
|
+
|
|
|
+ sockaddr_in client;
|
|
|
+ size_t client_size = sizeof(client);
|
|
|
+ int sock = ::accept(m_server.m_socket, (sockaddr*) &client, (int*) &client_size);
|
|
|
+
|
|
|
+ AcceptResult result;
|
|
|
+ if (sock == SOCKET_ERROR && (errno == WSAEWOULDBLOCK))
|
|
|
+ {
|
|
|
+ result.error = AcceptResult::NO_CONNECTION;
|
|
|
+ }
|
|
|
+ else if (sock == SOCKET_ERROR)
|
|
|
+ {
|
|
|
+ result.error = AcceptResult::UNKNOWN;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ result.error = AcceptResult::NO_ERROR;
|
|
|
+ c.m_socket = sock;
|
|
|
+ }
|
|
|
+
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ //-----------------------------------------------------------------------------
|
|
|
+ AcceptResult accept(TCPSocket& c)
|
|
|
+ {
|
|
|
+ m_server.set_blocking(true);
|
|
|
+
|
|
|
+ sockaddr_in client;
|
|
|
+ size_t client_size = sizeof(client);
|
|
|
+
|
|
|
+ int sock = ::accept(m_server.m_socket, (sockaddr*) &client, (int*) &client_size);
|
|
|
+
|
|
|
+ AcceptResult result;
|
|
|
+ if (sock == SOCKET_ERROR)
|
|
|
+ {
|
|
|
+ result.error = AcceptResult::UNKNOWN;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ result.error = AcceptResult::NO_ERROR;
|
|
|
+ c.m_socket = sock;
|
|
|
+ }
|
|
|
+
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ //-----------------------------------------------------------------------------
|
|
|
+ ReadResult read_nonblock(void* data, size_t size)
|
|
|
+ {
|
|
|
+ return m_server.read_nonblock(data, size);
|
|
|
+ }
|
|
|
+
|
|
|
+ //-----------------------------------------------------------------------------
|
|
|
+ ReadResult read(void* data, size_t size)
|
|
|
+ {
|
|
|
+ return m_server.read(data, size);
|
|
|
+ }
|
|
|
+
|
|
|
+ //-----------------------------------------------------------------------------
|
|
|
+ WriteResult write_nonblock(void* data, size_t size)
|
|
|
+ {
|
|
|
+ return m_server.write_nonblock(data, size);
|
|
|
+ }
|
|
|
+
|
|
|
+ //-----------------------------------------------------------------------------
|
|
|
+ WriteResult write(const void* data, size_t size)
|
|
|
+ {
|
|
|
+ return m_server.write(data, size);
|
|
|
+ }
|
|
|
+
|
|
|
+private:
|
|
|
+
|
|
|
+ TCPSocket m_server;
|
|
|
+};
|
|
|
+*/
|
|
|
+
|
|
|
} // namespace crown
|