|
@@ -26,6 +26,14 @@ OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
|
|
|
|
#pragma once
|
|
#pragma once
|
|
|
|
|
|
|
|
|
|
+//Undefined in Frustum.h, but winsock2 ecc need it.
|
|
|
|
|
+#ifndef NEAR
|
|
|
|
|
+#define NEAR
|
|
|
|
|
+#endif
|
|
|
|
|
+#ifndef FAR
|
|
|
|
|
+#define FAR
|
|
|
|
|
+#endif
|
|
|
|
|
+
|
|
|
#include <winsock2.h>
|
|
#include <winsock2.h>
|
|
|
#include <windows.h>
|
|
#include <windows.h>
|
|
|
|
|
|
|
@@ -35,25 +43,28 @@ OTHER DEALINGS IN THE SOFTWARE.
|
|
|
#include "OS.h"
|
|
#include "OS.h"
|
|
|
|
|
|
|
|
#pragma comment(lib, "Ws2_32.lib")
|
|
#pragma comment(lib, "Ws2_32.lib")
|
|
|
|
|
+#undef NO_ERROR
|
|
|
|
|
|
|
|
namespace crown
|
|
namespace crown
|
|
|
{
|
|
{
|
|
|
|
|
|
|
|
-//-----------------------------------------------------------------------------
|
|
|
|
|
struct ReadResult
|
|
struct ReadResult
|
|
|
{
|
|
{
|
|
|
- enum { NO_RESULT_ERROR, UNKNOWN, REMOTE_CLOSED } error;
|
|
|
|
|
- size_t received_bytes;
|
|
|
|
|
|
|
+ enum { NO_ERROR, REMOTE_CLOSED, TIMEOUT, UNKNOWN } error;
|
|
|
|
|
+ size_t bytes_read;
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
-//-----------------------------------------------------------------------------
|
|
|
|
|
struct WriteResult
|
|
struct WriteResult
|
|
|
{
|
|
{
|
|
|
- enum { NO_RESULT_ERROR, UNKNOWN, REMOTE_CLOSED } error;
|
|
|
|
|
- size_t sent_bytes;
|
|
|
|
|
|
|
+ enum { NO_ERROR, REMOTE_CLOSED, TIMEOUT, UNKNOWN } error;
|
|
|
|
|
+ size_t bytes_wrote;
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+struct AcceptResult
|
|
|
|
|
+{
|
|
|
|
|
+ enum { NO_ERROR, NO_CONNECTION, UNKNOWN } error;
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
-//-----------------------------------------------------------------------------
|
|
|
|
|
class TCPSocket
|
|
class TCPSocket
|
|
|
{
|
|
{
|
|
|
public:
|
|
public:
|
|
@@ -72,17 +83,10 @@ public:
|
|
|
//-----------------------------------------------------------------------------
|
|
//-----------------------------------------------------------------------------
|
|
|
bool connect(const NetAddress& destination, uint16_t port)
|
|
bool connect(const NetAddress& destination, uint16_t port)
|
|
|
{
|
|
{
|
|
|
- int sd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
|
|
|
|
|
|
+ m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
|
|
|
|
|
|
|
- if (sd <= 0)
|
|
|
|
|
- {
|
|
|
|
|
- os::printf("failed to open socket\n");
|
|
|
|
|
- m_socket = 0;
|
|
|
|
|
- return false;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ CE_ASSERT(m_socket > 0, "Failed to create socket");
|
|
|
|
|
|
|
|
- m_socket = sd;
|
|
|
|
|
-
|
|
|
|
|
sockaddr_in address;
|
|
sockaddr_in address;
|
|
|
address.sin_family = AF_INET;
|
|
address.sin_family = AF_INET;
|
|
|
address.sin_addr.s_addr = ::htonl(destination.address());
|
|
address.sin_addr.s_addr = ::htonl(destination.address());
|
|
@@ -90,7 +94,7 @@ public:
|
|
|
|
|
|
|
|
if (::connect(m_socket, (const sockaddr*)&address, sizeof(sockaddr_in)) < 0)
|
|
if (::connect(m_socket, (const sockaddr*)&address, sizeof(sockaddr_in)) < 0)
|
|
|
{
|
|
{
|
|
|
- os::printf("failed to connect socket\n");
|
|
|
|
|
|
|
+ os::printf("Failed to connect socket\n");
|
|
|
close();
|
|
close();
|
|
|
return false;
|
|
return false;
|
|
|
}
|
|
}
|
|
@@ -109,52 +113,176 @@ public:
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//-----------------------------------------------------------------------------
|
|
|
- ReadResult read(void* data, int32_t size)
|
|
|
|
|
|
|
+ ReadResult read_nonblock(void* data, size_t size)
|
|
|
{
|
|
{
|
|
|
- CE_ASSERT_NOT_NULL(data);
|
|
|
|
|
-
|
|
|
|
|
- int received_bytes = ::recv(m_socket, (char*)data, size, 0);
|
|
|
|
|
|
|
+ set_blocking(false);
|
|
|
|
|
+ int read_bytes = ::recv(m_socket, (char*) data, size, 0);
|
|
|
|
|
|
|
|
ReadResult result;
|
|
ReadResult result;
|
|
|
-
|
|
|
|
|
- if (received_bytes < 0)
|
|
|
|
|
|
|
+ if (read_bytes == SOCKET_ERROR && (errno == WSAEWOULDBLOCK))
|
|
|
|
|
+ {
|
|
|
|
|
+ result.error = ReadResult::NO_ERROR;
|
|
|
|
|
+ result.bytes_read = 0;
|
|
|
|
|
+ }
|
|
|
|
|
+ else if (read_bytes == SOCKET_ERROR && errno == WSAETIMEDOUT)
|
|
|
|
|
+ {
|
|
|
|
|
+ result.error = ReadResult::TIMEOUT;
|
|
|
|
|
+ }
|
|
|
|
|
+ else if (read_bytes == SOCKET_ERROR)
|
|
|
{
|
|
{
|
|
|
- result.error = ReadResult::NO_RESULT_ERROR;
|
|
|
|
|
- result.received_bytes = 0;
|
|
|
|
|
|
|
+ result.error = ReadResult::UNKNOWN;
|
|
|
}
|
|
}
|
|
|
- if (received_bytes == 0)
|
|
|
|
|
|
|
+ else if (read_bytes == 0)
|
|
|
{
|
|
{
|
|
|
result.error = ReadResult::REMOTE_CLOSED;
|
|
result.error = ReadResult::REMOTE_CLOSED;
|
|
|
}
|
|
}
|
|
|
else
|
|
else
|
|
|
{
|
|
{
|
|
|
- result.error = ReadResult::NO_RESULT_ERROR;
|
|
|
|
|
- result.received_bytes = received_bytes;
|
|
|
|
|
|
|
+ result.error = ReadResult::NO_ERROR;
|
|
|
|
|
+ result.bytes_read = read_bytes;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- return result;
|
|
|
|
|
|
|
+ return result;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//-----------------------------------------------------------------------------
|
|
|
- WriteResult write(const void* data, int32_t size)
|
|
|
|
|
|
|
+ ReadResult read(void* data, size_t size)
|
|
|
{
|
|
{
|
|
|
- CE_ASSERT_NOT_NULL(data);
|
|
|
|
|
|
|
+ set_blocking(true);
|
|
|
|
|
|
|
|
- int sent_bytes = ::send(m_socket, (const char*)data, size, 0);
|
|
|
|
|
|
|
+ // 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;
|
|
|
|
|
|
|
|
- WriteResult result;
|
|
|
|
|
|
|
+ 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;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- if (sent_bytes < 0)
|
|
|
|
|
|
|
+ //-----------------------------------------------------------------------------
|
|
|
|
|
+ WriteResult write_nonblock(const void* data, size_t size)
|
|
|
|
|
+ {
|
|
|
|
|
+ set_blocking(false);
|
|
|
|
|
+ int bytes_wrote = ::send(m_socket, (char*)data, size, 0);
|
|
|
|
|
+
|
|
|
|
|
+ WriteResult result;
|
|
|
|
|
+ if (bytes_wrote == SOCKET_ERROR && (errno == WSAEWOULDBLOCK))
|
|
|
{
|
|
{
|
|
|
- result.error = WriteResult::UNKNOWN;
|
|
|
|
|
|
|
+ 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
|
|
else
|
|
|
{
|
|
{
|
|
|
- result.error = WriteResult::NO_RESULT_ERROR;
|
|
|
|
|
- result.sent_bytes = sent_bytes;
|
|
|
|
|
|
|
+ result.error = WriteResult::UNKNOWN;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- return result;
|
|
|
|
|
|
|
+ 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;
|
|
|
|
|
+
|
|
|
|
|
+ // Ensure all data is sent
|
|
|
|
|
+ while (to_send > 0)
|
|
|
|
|
+ {
|
|
|
|
|
+ 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;
|
|
|
|
|
+ return result;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ //-----------------------------------------------------------------------------
|
|
|
|
|
+ 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)
|
|
|
|
|
+ {
|
|
|
|
|
+ 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:
|
|
public:
|
|
@@ -162,88 +290,127 @@ public:
|
|
|
int m_socket;
|
|
int m_socket;
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
-//-----------------------------------------------------------------------------
|
|
|
|
|
-class TCPListener
|
|
|
|
|
|
|
+class TCPServer
|
|
|
{
|
|
{
|
|
|
public:
|
|
public:
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//-----------------------------------------------------------------------------
|
|
|
bool open(uint16_t port)
|
|
bool open(uint16_t port)
|
|
|
{
|
|
{
|
|
|
- int& sock_id = m_listener.m_socket;
|
|
|
|
|
|
|
+ m_server.m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
|
|
|
|
+ CE_ASSERT(m_server.m_socket > 0, "Failed to create socket");
|
|
|
|
|
|
|
|
- sock_id = ::socket(AF_INET, SOCK_STREAM, 0);
|
|
|
|
|
- CE_ASSERT(sock_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");
|
|
|
|
|
|
|
+ m_server.set_resuse_address(true);
|
|
|
|
|
|
|
|
// Bind socket
|
|
// Bind socket
|
|
|
sockaddr_in address;
|
|
sockaddr_in address;
|
|
|
address.sin_family = AF_INET;
|
|
address.sin_family = AF_INET;
|
|
|
- address.sin_addr.s_addr = ::htonl(INADDR_ANY);
|
|
|
|
|
- address.sin_port = ::htons(port);
|
|
|
|
|
|
|
+ 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(sock_id, 5);
|
|
|
|
|
- CE_ASSERT(result == 0, "Unable to listen on socket");
|
|
|
|
|
|
|
+ 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;
|
|
|
|
|
|
|
+ return true;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//-----------------------------------------------------------------------------
|
|
|
void close()
|
|
void close()
|
|
|
{
|
|
{
|
|
|
- m_listener.close();
|
|
|
|
|
|
|
+ m_server.close();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//-----------------------------------------------------------------------------
|
|
|
- bool listen(TCPSocket& c)
|
|
|
|
|
|
|
+ void listen(uint32_t max)
|
|
|
{
|
|
{
|
|
|
- int& sock_id = m_listener.m_socket;
|
|
|
|
|
|
|
+ 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;
|
|
sockaddr_in client;
|
|
|
- int client_length = sizeof(client);
|
|
|
|
|
|
|
+ size_t client_size = sizeof(client);
|
|
|
|
|
+ int sock = ::accept(m_server.m_socket, (sockaddr*) &client, (int*) &client_size);
|
|
|
|
|
|
|
|
- int asd = ::accept(sock_id, (sockaddr*)&client, &client_length);
|
|
|
|
|
- if (asd < 0)
|
|
|
|
|
|
|
+ AcceptResult result;
|
|
|
|
|
+ if (sock == SOCKET_ERROR && (errno == WSAEWOULDBLOCK))
|
|
|
{
|
|
{
|
|
|
- return false;
|
|
|
|
|
|
|
+ result.error = AcceptResult::NO_CONNECTION;
|
|
|
|
|
+ }
|
|
|
|
|
+ else if (sock == SOCKET_ERROR)
|
|
|
|
|
+ {
|
|
|
|
|
+ result.error = AcceptResult::UNKNOWN;
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ result.error = AcceptResult::NO_ERROR;
|
|
|
|
|
+ c.m_socket = sock;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- DWORD non_blocking = 1;
|
|
|
|
|
- int result = ::ioctlsocket(asd, FIONBIO, &non_blocking);
|
|
|
|
|
- CE_ASSERT(result == 0, "Unable to set socket non-blocking");
|
|
|
|
|
|
|
+ return result;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- c.m_socket = asd;
|
|
|
|
|
|
|
+ //-----------------------------------------------------------------------------
|
|
|
|
|
+ AcceptResult accept(TCPSocket& c)
|
|
|
|
|
+ {
|
|
|
|
|
+ m_server.set_blocking(true);
|
|
|
|
|
|
|
|
- return 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)
|
|
ReadResult read(void* data, size_t size)
|
|
|
{
|
|
{
|
|
|
- return m_listener.read(data, 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)
|
|
WriteResult write(const void* data, size_t size)
|
|
|
{
|
|
{
|
|
|
- return m_listener.write(data, size);
|
|
|
|
|
|
|
+ return m_server.write(data, size);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
private:
|
|
|
|
|
|
|
|
- TCPSocket m_listener;
|
|
|
|
|
|
|
+ TCPSocket m_server;
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
-//-----------------------------------------------------------------------------
|
|
|
|
|
class UDPSocket
|
|
class UDPSocket
|
|
|
{
|
|
{
|
|
|
|
|
+public:
|
|
|
|
|
+
|
|
|
//-----------------------------------------------------------------------------
|
|
//-----------------------------------------------------------------------------
|
|
|
UDPSocket()
|
|
UDPSocket()
|
|
|
: m_socket(0)
|
|
: m_socket(0)
|
|
@@ -253,59 +420,89 @@ class UDPSocket
|
|
|
//-----------------------------------------------------------------------------
|
|
//-----------------------------------------------------------------------------
|
|
|
bool open(uint16_t port)
|
|
bool open(uint16_t port)
|
|
|
{
|
|
{
|
|
|
- // CE_ASSERT(!is_open(), "Socket is already open");
|
|
|
|
|
|
|
+ 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");
|
|
|
|
|
|
|
+ m_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
|
|
|
|
|
|
|
- // // bind to port
|
|
|
|
|
- // sockaddr_in address;
|
|
|
|
|
- // address.sin_family = AF_INET;
|
|
|
|
|
- // address.sin_addr.s_addr = INADDR_ANY;
|
|
|
|
|
- // address.sin_port = ::htons(port);
|
|
|
|
|
|
|
+ if (m_socket <= 0)
|
|
|
|
|
+ {
|
|
|
|
|
+ os::printf("Failed to create socket.\n");
|
|
|
|
|
+ m_socket = 0;
|
|
|
|
|
|
|
|
- // int result = ::bind(m_socket, (const sockaddr*)&address, sizeof(sockaddr_in));
|
|
|
|
|
- // CE_ASSERT(result == 0, "Unable to bind socket");
|
|
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- // // set non-blocking io
|
|
|
|
|
- // DWORD non_blocking = 1;
|
|
|
|
|
- // result = ::ioctlsocket(m_socket, FIONBIO, &non_blocking);
|
|
|
|
|
- // CE_ASSERT(result == 0, "Unable to bind 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;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ //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)
|
|
|
|
|
+ {
|
|
|
|
|
+ os::printf("Failed to set non-blocking socket\n");
|
|
|
|
|
+ close();
|
|
|
|
|
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
return true;
|
|
return true;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//-----------------------------------------------------------------------------
|
|
|
- ReadResult read(NetAddress& sender, uint16_t& port, const void* data, size_t size)
|
|
|
|
|
|
|
+ void close()
|
|
|
{
|
|
{
|
|
|
- // CE_ASSERT_NOT_NULL(data);
|
|
|
|
|
|
|
+ if (m_socket != 0)
|
|
|
|
|
+ {
|
|
|
|
|
+ ::closesocket(m_socket);
|
|
|
|
|
+ m_socket = 0;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- // typedef int socklen_t;
|
|
|
|
|
|
|
+ //-----------------------------------------------------------------------------
|
|
|
|
|
+ ReadResult read(NetAddress& sender, uint16_t& port, const void* data, size_t size)
|
|
|
|
|
+ {
|
|
|
|
|
+ CE_ASSERT_NOT_NULL(data);
|
|
|
|
|
|
|
|
- // sockaddr_in from;
|
|
|
|
|
- // socklen_t from_length = sizeof(from);
|
|
|
|
|
|
|
+ sockaddr_in from;
|
|
|
|
|
+ int from_length = sizeof(from);
|
|
|
|
|
|
|
|
- // int received_bytes = ::recvfrom(m_socket, (char*)data, size, 0, (sockaddr*)&from, &from_length);
|
|
|
|
|
|
|
+ int received_bytes = recvfrom(m_socket, (char*)data, size, 0, (sockaddr*)&from, &from_length);
|
|
|
|
|
|
|
|
ReadResult result;
|
|
ReadResult result;
|
|
|
|
|
|
|
|
- // if (received_bytes < 0)
|
|
|
|
|
- // {
|
|
|
|
|
- // result.error = ReadResult::NO_RESULT_ERROR;
|
|
|
|
|
- // result.received_bytes = 0;
|
|
|
|
|
- // }
|
|
|
|
|
- // else if (received_bytes == 0)
|
|
|
|
|
- // {
|
|
|
|
|
- // result.error = ReadResult::REMOTE_CLOSED;
|
|
|
|
|
- // }
|
|
|
|
|
- // else
|
|
|
|
|
- // {
|
|
|
|
|
- // result.error = ReadResult::NO_RESULT_ERROR;
|
|
|
|
|
- // result.received_bytes = received_bytes;
|
|
|
|
|
- // }
|
|
|
|
|
-
|
|
|
|
|
- // sender.set(::ntohl(from.sin_addr.s_addr));
|
|
|
|
|
- // port = ::ntohs(from.sin_port);
|
|
|
|
|
|
|
+ if (received_bytes == SOCKET_ERROR && errno == WSAEWOULDBLOCK)
|
|
|
|
|
+ {
|
|
|
|
|
+ result.error = ReadResult::NO_ERROR;
|
|
|
|
|
+ result.bytes_read = 0;
|
|
|
|
|
+ }
|
|
|
|
|
+ else if (received_bytes == SOCKET_ERROR)
|
|
|
|
|
+ {
|
|
|
|
|
+ result.error = ReadResult::UNKNOWN;
|
|
|
|
|
+ }
|
|
|
|
|
+ else if (received_bytes == 0)
|
|
|
|
|
+ {
|
|
|
|
|
+ result.error = ReadResult::REMOTE_CLOSED;
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ result.error = ReadResult::NO_ERROR;
|
|
|
|
|
+ result.bytes_read = received_bytes;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ sender.set(ntohl(from.sin_addr.s_addr));
|
|
|
|
|
+ port = ntohs(from.sin_port);
|
|
|
|
|
|
|
|
return result;
|
|
return result;
|
|
|
}
|
|
}
|
|
@@ -313,43 +510,32 @@ class UDPSocket
|
|
|
//-----------------------------------------------------------------------------
|
|
//-----------------------------------------------------------------------------
|
|
|
WriteResult write(const NetAddress& receiver, uint16_t port, void* data, size_t size)
|
|
WriteResult write(const NetAddress& receiver, uint16_t port, void* data, size_t size)
|
|
|
{
|
|
{
|
|
|
- // CE_ASSERT_NOT_NULL(data);
|
|
|
|
|
|
|
+ CE_ASSERT_NOT_NULL(data);
|
|
|
|
|
|
|
|
- // sockaddr_in address;
|
|
|
|
|
- // address.sin_family = AF_INET;
|
|
|
|
|
- // address.sin_addr.s_addr = htonl(receiver.address());
|
|
|
|
|
- // address.sin_port = htons(port);
|
|
|
|
|
|
|
+ sockaddr_in address;
|
|
|
|
|
+ address.sin_family = AF_INET;
|
|
|
|
|
+ address.sin_addr.s_addr = htonl(receiver.address());
|
|
|
|
|
+ address.sin_port = htons(port);
|
|
|
|
|
|
|
|
- // int sent_bytes = sendto(m_socket, (const char*)data, size, 0, (sockaddr*)&address, sizeof(sockaddr_in));
|
|
|
|
|
|
|
+ int bytes_wrote = sendto(m_socket, (const char*) data, size, 0, (sockaddr*) &address, sizeof(sockaddr_in));
|
|
|
|
|
|
|
|
WriteResult result;
|
|
WriteResult result;
|
|
|
|
|
|
|
|
- // if (sent_bytes < 0)
|
|
|
|
|
- // {
|
|
|
|
|
- // result.error = WriteResult::UNKNOWN;
|
|
|
|
|
- // return result;
|
|
|
|
|
- // }
|
|
|
|
|
-
|
|
|
|
|
- // result.error = WriteResult::NO_RESULT_ERROR;
|
|
|
|
|
- // result.sent_bytes = sent_bytes;
|
|
|
|
|
|
|
+ if (bytes_wrote == SOCKET_ERROR)
|
|
|
|
|
+ {
|
|
|
|
|
+ result.error = WriteResult::UNKNOWN;
|
|
|
|
|
+ return result;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
|
|
+ result.error = WriteResult::NO_ERROR;
|
|
|
|
|
+ result.bytes_wrote = bytes_wrote;
|
|
|
return result;
|
|
return result;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- //-----------------------------------------------------------------------------
|
|
|
|
|
- void close()
|
|
|
|
|
- {
|
|
|
|
|
- // if (m_socket != 0)
|
|
|
|
|
- // {
|
|
|
|
|
- // ::closesocket(m_socket);
|
|
|
|
|
- // m_socket = 0;
|
|
|
|
|
- // }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//-----------------------------------------------------------------------------
|
|
|
bool is_open()
|
|
bool is_open()
|
|
|
{
|
|
{
|
|
|
- return m_socket != 0;
|
|
|
|
|
|
|
+ return m_socket != 0;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
public:
|
|
public:
|