diff --git a/Src/Network/UDPPacket.h b/Src/Network/UDPPacket.h new file mode 100644 index 0000000..43113ec --- /dev/null +++ b/Src/Network/UDPPacket.h @@ -0,0 +1,82 @@ +#ifndef _UDP_H_ +#define _UDP_H_ + +namespace SMUDP +{ + struct Packet + { + + static const UINT32 BUFFER_SIZE = 1460; + + UINT32 crc; + UINT16 currentID; + UINT16 totalIDs; + UINT16 flags; + UINT16 length; + UCHAR data[1460]; + + Packet() { + Init(); + } + + enum class PacketFlags { + newConnection = (1 << 0), + resend = (1 << 1), + ping = (1 << 2) + }; + + void Init() { + crc = 0; + currentID = 0; + totalIDs = 0; + flags = 0; + length = 0; + } + + UINT32 CalcCRC() { + crc = CalcCRCVal(); + } + + UINT32 CalcCRCVal() { + + UINT32 val = 0; + + for (int i = 0; i < _countof(data); i++) { + val += data[i]; // crude but will catch the odd off by one error + } + + return val; + } + + bool ValidateCRC() { + return CalcCRCVal() == crc; + } + + void CreatePacket(PacketFlags p) { + flags |= (UINT16)p; + } + + void CalcTotalIDs(int bytes) { + totalIDs = bytes / sizeof(data); + + if (bytes % sizeof(data)) { + totalIDs++; + } + } + + int HeaderSize() { + return 12; + } + + int Size() { + return HeaderSize() + length; + } + + operator char*() { return (char*)this; } + operator const char*() { return (char*)this; } + }; + + typedef char PacketReply; +} + +#endif \ No newline at end of file diff --git a/Src/Network/UDPReceive.cpp b/Src/Network/UDPReceive.cpp new file mode 100644 index 0000000..b9b283b --- /dev/null +++ b/Src/Network/UDPReceive.cpp @@ -0,0 +1,89 @@ +#include +#include +#include "UDPReceive.h" +#include "UDPPacket.h" + +namespace SMUDP +{ + +UDPReceive::UDPReceive() +{ + m_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); // create the socket + m_readEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + + WSAEventSelect(m_socket, m_readEvent, FD_READ); +} + +UDPReceive::~UDPReceive() +{ + closesocket(m_socket); + CloseHandle(m_readEvent); +} + +bool UDPReceive::Bind(UINT16 port) +{ + //=========================== + int err; + SOCKADDR_IN serverInfo = {}; + //=========================== + + serverInfo.sin_family = AF_INET; // address family Internet + serverInfo.sin_port = htons(port); // set server’s port number + serverInfo.sin_addr.s_addr = INADDR_ANY; // set server’s IP + + err = bind(m_socket, (LPSOCKADDR)&serverInfo, sizeof(struct sockaddr)); + + return (err == 0); +} + +std::vector& UDPReceive::ReadData(int timeout) +{ + m_data.clear(); + + while (true) { + + //======== + DWORD res; + //======== + + res = WaitForSingleObject(m_readEvent, timeout); + + if (res == WAIT_OBJECT_0) { + + //========================= + int result; + int slen; + sockaddr_in si_other; + Packet packet; + //========================= + + slen = sizeof(sockaddr_in); + + result = recvfrom(m_socket, packet, sizeof(packet), 0, (struct sockaddr *) &si_other, &slen); + + if (result == SOCKET_ERROR) { + auto error = WSAGetLastError(); // clear error code + m_data.clear(); + break; + } + + // copy data to array + m_data.insert(m_data.end(), packet.data, packet.data + packet.length); + + PacketReply r = 1; + result = sendto(m_socket, &r, sizeof(r), 0, (struct sockaddr *)&si_other, sizeof(SOCKADDR_IN)); + + if (packet.currentID + 1 == packet.totalIDs) { + break; // reached the end + } + } + else { + m_data.clear(); // reset any memory because we have failed + break; // timeout + } + } + + return m_data; +} + +} diff --git a/Src/Network/UDPReceive.h b/Src/Network/UDPReceive.h new file mode 100644 index 0000000..8da3260 --- /dev/null +++ b/Src/Network/UDPReceive.h @@ -0,0 +1,30 @@ +#ifndef _UDP_RECEIVE_H_ +#define _UDP_RECEIVE_H_ + +#include "UDPPacket.h" +#include "WinSockWrap.h" +#include + +namespace SMUDP +{ + class UDPReceive + { + public: + UDPReceive(); + ~UDPReceive(); + + bool Bind(UINT16 port); + + std::vector& ReadData(int timeout); + + private: + + std::vector m_data; + SOCKET m_socket; + HANDLE m_readEvent; + HANDLE m_exitEvent; + WinSockWrap m_winSockWrap; + }; +} + +#endif \ No newline at end of file diff --git a/Src/Network/UDPSend.cpp b/Src/Network/UDPSend.cpp new file mode 100644 index 0000000..c3dc35f --- /dev/null +++ b/Src/Network/UDPSend.cpp @@ -0,0 +1,133 @@ +#include +#include +#include "UDPSend.h" +#include +#include + +namespace SMUDP +{ + +UDPSend::UDPSend() +{ + m_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); // create the socket + m_event = CreateEvent(NULL, FALSE, FALSE, NULL); + + WSAEventSelect(m_socket, m_event, FD_READ | FD_WRITE); +} + +UDPSend::~UDPSend() +{ + closesocket(m_socket); + CloseHandle(m_event); +} + +bool UDPSend::Send(const char* ip, int port, int length, const void *data, int timeout) +{ + UINT8* pData = (UINT8*)data; + + Packet packet; + packet.CalcTotalIDs(length); + + SOCKADDR_IN address = {}; + address.sin_family = AF_INET; // address family Internet + address.sin_port = htons(port); // set server’s port number + inet_pton(AF_INET, ip, &address.sin_addr); + + while (length > 0) { + + packet.flags = 0; // reset the flags (not used currently) + + if (length > packet.BUFFER_SIZE) { + packet.length = packet.BUFFER_SIZE; + } + else { + packet.length = length; + } + + memcpy(packet.data, pData, packet.length); + + int sent = SendDataPacket(packet, m_socket, address, m_event); + + if (sent == SOCKET_ERROR) { + return false; // send failure + } + + if (!ProcessReply(m_socket, m_event, timeout)) { + return false; // reply failure + } + + length -= packet.length; + pData += packet.length; + + packet.currentID++; + } + + return true; +} + +bool UDPSend::WaitForEvent(SOCKET s, HANDLE hEvent, long nEvents, int timeout) +{ + //======== + DWORD res; + //======== + + res = WaitForSingleObject(hEvent, timeout); + + if (res == WAIT_OBJECT_0) { + + WSANETWORKEVENTS events = {}; + WSAEnumNetworkEvents(s, hEvent, &events); + + if (events.lNetworkEvents & nEvents) { + return true; + } + } + + return false; +} + +int UDPSend::SendDataPacket(Packet &p, SOCKET s, SOCKADDR_IN& address, HANDLE events) +{ + while (true) { + + int sent = sendto(s, p, p.Size(), 0, (struct sockaddr *)&address, sizeof(SOCKADDR_IN)); + + if (sent == SOCKET_ERROR) { + + int error = WSAGetLastError(); // clear error code + + if (error == WSAEWOULDBLOCK) { + WaitForEvent(s, events, FD_WRITE, INFINITE); // wait until write event is triggered + continue; + } + + return sent; // send failure + } + + return p.Size(); + } +} + +bool UDPSend::ProcessReply(SOCKET s, HANDLE event, int timeout) +{ + //================= + int result; + PacketReply rp; + //================= + + if (WaitForEvent(s, event, FD_READ, timeout)) { + + result = recv(s, &rp, sizeof(rp), 0); + + if (result == SOCKET_ERROR) { + auto error = WSAGetLastError(); // clear error code + return false; + } + + return true; + } + + return false; +} + +} \ No newline at end of file diff --git a/Src/Network/UDPSend.h b/Src/Network/UDPSend.h new file mode 100644 index 0000000..efcfae9 --- /dev/null +++ b/Src/Network/UDPSend.h @@ -0,0 +1,29 @@ +#ifndef _UDPSEND_H_ +#define _UDPSEND_H_ + +#include "UDPPacket.h" +#include "WinSockWrap.h" + +namespace SMUDP +{ + class UDPSend + { + public: + UDPSend(); + ~UDPSend(); + + bool Send(const char* address, int port, int length, const void *data, int timeout); + + private: + + bool WaitForEvent(SOCKET s, HANDLE hEvent, long nEvents, int timeout); + bool ProcessReply(SOCKET s, HANDLE event, int timeout); + int SendDataPacket(Packet& p, SOCKET s, SOCKADDR_IN& address, HANDLE events); + + SOCKET m_socket; + HANDLE m_event; + WinSockWrap m_winsockWrap; + }; +} + +#endif \ No newline at end of file diff --git a/Src/Network/WinSockWrap.cpp b/Src/Network/WinSockWrap.cpp new file mode 100644 index 0000000..acedc0a --- /dev/null +++ b/Src/Network/WinSockWrap.cpp @@ -0,0 +1,28 @@ +#include "WinSockWrap.h" +#include +#include + +#pragma comment(lib, "ws2_32.lib") + +WinSockWrap::WinSockWrap() +{ + //============== + WSADATA wsaData; + int err; + //============== + + m_count = 0; + + err = WSAStartup(MAKEWORD(2, 2), &wsaData); // don't really need to care for checking supported version, we should be good from win95 onwards + + if (err == 0) { + m_count++; + } +} + +WinSockWrap::~WinSockWrap() +{ + if (m_count) { + WSACleanup(); + } +} \ No newline at end of file diff --git a/Src/Network/WinSockWrap.h b/Src/Network/WinSockWrap.h new file mode 100644 index 0000000..8bbdd44 --- /dev/null +++ b/Src/Network/WinSockWrap.h @@ -0,0 +1,14 @@ +#ifndef _WINSOCKWRAP_H_ +#define _WINSOCKWRAP_H_ + +class WinSockWrap +{ +public: + WinSockWrap(); + ~WinSockWrap(); + +private: + int m_count; +}; + +#endif \ No newline at end of file diff --git a/VS2008/Supermodel.vcxproj b/VS2008/Supermodel.vcxproj index c90a0e5..60fb6ce 100644 --- a/VS2008/Supermodel.vcxproj +++ b/VS2008/Supermodel.vcxproj @@ -345,6 +345,9 @@ xcopy /D /Y "$(ProjectDir)\SDL\$(Platform)\$(Configuration)\SDL.dll" "$(TargetDi + + + @@ -569,6 +572,10 @@ xcopy /D /Y "$(ProjectDir)\SDL\$(Platform)\$(Configuration)\SDL.dll" "$(TargetDi + + + + diff --git a/VS2008/Supermodel.vcxproj.filters b/VS2008/Supermodel.vcxproj.filters index f64f5de..79bb952 100644 --- a/VS2008/Supermodel.vcxproj.filters +++ b/VS2008/Supermodel.vcxproj.filters @@ -132,6 +132,12 @@ {ea54ba9d-b27d-48e1-b576-fd245fd4d6c3} + + {5a9e8f32-b937-4026-86c3-485581ae15c1} + + + {284c6ebd-9a90-4283-9ee6-ea097974c8f4} + @@ -446,6 +452,15 @@ Source Files\Sound\MPEG + + Source Files\Network + + + Source Files\Network + + + Source Files\Network + @@ -829,6 +844,18 @@ Header Files\Sound\MPEG + + Header Files\Network + + + Header Files\Network + + + Header Files\Network + + + Header Files\Network +