Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 83 additions & 0 deletions Src/Network/UDPPacket.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
#ifndef _UDP_H_
#define _UDP_H_
#include <WinDef.h>

namespace SMUDP
{
struct Packet
{

static const UINT32 BUFFER_SIZE_UDP = 1460;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we convert tabs to spaces everywhere? I think we are using a 4-character tab stop.


UINT32 crc;
UINT16 currentID;
UINT16 totalIDs;
UINT16 flags;
UINT16 length;
UCHAR data[BUFFER_SIZE_UDP];

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
89 changes: 89 additions & 0 deletions Src/Network/UDPReceive.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
#include <winsock2.h>
#include <windows.h>
#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<UINT8>& 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;
}

}
29 changes: 29 additions & 0 deletions Src/Network/UDPReceive.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#ifndef _UDP_RECEIVE_H_
#define _UDP_RECEIVE_H_

#include "UDPPacket.h"
#include "WinSockWrap.h"
#include <vector>

namespace SMUDP
{
class UDPReceive
{
public:
UDPReceive();
~UDPReceive();

bool Bind(UINT16 port);

std::vector<UINT8>& ReadData(int timeout);

private:

std::vector<UINT8> m_data;
SOCKET m_socket;
HANDLE m_readEvent;
WinSockWrap m_winSockWrap;
};
}

#endif
187 changes: 187 additions & 0 deletions Src/Network/UDPSend.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
#include <winsock2.h>
#include <windows.h>
#include "UDPSend.h"
#include <WS2tcpip.h>
#include <stdio.h>

#ifdef __GNUC__
extern "C" {
WINSOCK_API_LINKAGE INT WSAAPI inet_pton(INT Family, PCSTR pszAddrString, PVOID pAddrBuf);
}
#endif

namespace SMUDP
{

UDPSend::UDPSend()
{
m_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); // create the socket
m_event = CreateEvent(NULL, FALSE, FALSE, NULL);
m_exitEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
m_dataReady = CreateEvent(NULL, FALSE, FALSE, NULL);
m_sendComplete = CreateEvent(NULL, FALSE, TRUE, NULL); // start off ready

m_sendThread = std::thread(&UDPSend::SendThread, this);

WSAEventSelect(m_socket, m_event, FD_READ | FD_WRITE);
}

UDPSend::~UDPSend()
{
SetEvent(m_exitEvent); // trigger thread to exit
m_sendThread.join(); // block until thread has exited
CloseHandle(m_exitEvent); // clean up the rest of the resources
CloseHandle(m_dataReady);
CloseHandle(m_sendComplete);

closesocket(m_socket);
CloseHandle(m_event);
}

bool UDPSend::SendAsync(const char* address, int port, int length, const void *data, int timeout)
{
WaitForSingleObject(m_sendComplete, INFINITE); // block until previous sends have completed, don't want overlapping

m_data.clear();
m_data.insert(m_data.end(), (UINT8*)data, (UINT8*)data + length);

m_address = address;
m_port = port;
m_timeout = timeout;

SetEvent(m_dataReady);

return true;
}

void UDPSend::SendThread()
{
HANDLE events[2];

events[0] = m_exitEvent;
events[1] = m_dataReady;

while (true) {

auto result = WaitForMultipleObjects(_countof(events), events, FALSE, INFINITE);

if (result == WAIT_OBJECT_0) { // exit event triggered
break;
}
else if (result == (WAIT_OBJECT_0 + 1)) { // data ready
Send(m_address.c_str(), m_port, (int)m_data.size(), m_data.data(), m_timeout);
SetEvent(m_sendComplete);
}
}
}

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_UDP) {
packet.length = packet.BUFFER_SIZE_UDP;
}
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;
}

}
Loading