136 lines
3.9 KiB
C++
136 lines
3.9 KiB
C++
/*
|
|
PolyGun
|
|
|
|
Copyright (c) 2023 mrkubax10 <mrkubax10@onet.pl>
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
of this software and associated documentation files (the "Software"), to deal
|
|
in the Software without restriction, including without limitation the rights
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
copies of the Software, and to permit persons to whom the Software is
|
|
furnished to do so, subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included in all
|
|
copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
SOFTWARE.
|
|
*/
|
|
|
|
#include "common/network/udp_socket.hpp"
|
|
|
|
#if defined(__unix__)
|
|
#include <sys/socket.h>
|
|
#include <sys/time.h>
|
|
#include <sys/types.h>
|
|
#include <arpa/inet.h>
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
#include <cstring>
|
|
|
|
#include "common/network/network_packet.hpp"
|
|
#include "common/logger.hpp"
|
|
|
|
using namespace polygun::network;
|
|
|
|
#if defined(__unix__)
|
|
#define INVALID_SOCK 1
|
|
#elif defined(_WIN32)
|
|
#define INVALID_SOCK static_cast<int>(INVALID_SOCKET)
|
|
unsigned g_initialized_sockets = 0;
|
|
typedef int socklen_t;
|
|
#endif
|
|
#if defined(_MSC_VER)
|
|
// Visual Studio doesn't define ssize_t by default
|
|
#include <basetsd.h>
|
|
typedef SSIZE_T ssize_t;
|
|
#endif
|
|
|
|
UDPSocket::UDPSocket() :
|
|
m_fd(0),
|
|
m_endpoint()
|
|
{
|
|
#if defined(_WIN32)
|
|
if(g_initialized_sockets==0) {
|
|
WSADATA data;
|
|
if(WSAStartup(MAKEWORD(2, 2), &data)!=0)
|
|
throw std::string("Failed to initialize WinSock2: "+std::to_string(WSAGetLastError()));
|
|
}
|
|
g_initialized_sockets++;
|
|
#endif
|
|
m_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
|
if(m_fd==INVALID_SOCK)
|
|
throw std::string("Failed to open UDPSocket");
|
|
memset((void*)&m_endpoint, 0, sizeof(m_endpoint));
|
|
|
|
// setup timeout for receiving
|
|
#if defined(__unix__)
|
|
struct timeval tv;
|
|
tv.tv_sec = 1;
|
|
tv.tv_usec = 0;
|
|
#elif defined(_WIN32)
|
|
const DWORD tv = 1000;
|
|
#endif
|
|
setsockopt(m_fd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof(tv));
|
|
}
|
|
|
|
UDPSocket::~UDPSocket() {
|
|
close();
|
|
}
|
|
|
|
void UDPSocket::connect(const std::string& ip, unsigned short port) {
|
|
m_endpoint.sin_family = AF_INET;
|
|
m_endpoint.sin_port = htons(port);
|
|
m_endpoint.sin_addr.s_addr = inet_addr(ip.c_str());
|
|
}
|
|
|
|
void UDPSocket::bind(unsigned short port) {
|
|
m_endpoint.sin_family = AF_INET;
|
|
m_endpoint.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
m_endpoint.sin_port = htons(port);
|
|
if(::bind(m_fd, (const struct sockaddr*)&m_endpoint, sizeof(m_endpoint))<0)
|
|
throw std::string("Failed to bind to address polygun://localhost:"+std::to_string(port));
|
|
LOG_INFO("Listening on polygun://localhost:%d", port);
|
|
}
|
|
|
|
bool UDPSocket::send(const NetworkPacket& packet, const NetworkEndpoint& target) const {
|
|
#if defined(_WIN32) || defined(__serenityos__) || defined(__FreeBSD__)
|
|
const int flags = 0;
|
|
#elif defined(__unix__)
|
|
const int flags = MSG_CONFIRM;
|
|
#endif
|
|
return sendto(m_fd, (const char*)packet.get_data().data(), packet.get_data().size(), flags, (const struct sockaddr*)&target, sizeof(target))>0;
|
|
}
|
|
|
|
bool UDPSocket::recv(NetworkPacket& packet, NetworkEndpoint* sender) {
|
|
struct sockaddr* sender_addr;
|
|
struct sockaddr dummy;
|
|
if(sender)
|
|
sender_addr = (struct sockaddr*)sender;
|
|
else
|
|
sender_addr = &dummy;
|
|
uint8_t data[65536];
|
|
socklen_t len=sizeof(*sender_addr);
|
|
ssize_t received = recvfrom(m_fd, (char*)data, 65536, 0, sender_addr, &len);
|
|
if(received>0)
|
|
return packet.load(data, received);
|
|
return false;
|
|
}
|
|
|
|
void UDPSocket::close() {
|
|
#if defined(__unix__)
|
|
::close(m_fd);
|
|
#elif defined(_WIN32)
|
|
g_initialized_sockets--;
|
|
if(g_initialized_sockets==0)
|
|
WSACleanup();
|
|
closesocket(m_fd);
|
|
#endif
|
|
}
|