228 lines
7.9 KiB
C++
228 lines
7.9 KiB
C++
#include "Network/UDPClient.h"
|
|
#include "boost/asio/basic_datagram_socket.hpp"
|
|
|
|
using namespace boost::asio::ip;
|
|
|
|
UDPClient::UDPClient()
|
|
{ }
|
|
|
|
UDPClient::~UDPClient()
|
|
{ }
|
|
|
|
bool UDPClient::Connect(std::string playerName, std::string address, int port)
|
|
{
|
|
if (m_Socket) {
|
|
return false;
|
|
}
|
|
m_ReceiverEndpoint = udp::endpoint(boost::asio::ip::address().from_string(address), port);
|
|
m_Socket = boost::shared_ptr<boost::asio::ip::udp::socket>(new boost::asio::ip::udp::socket(m_IOService));
|
|
m_Socket->open(boost::asio::ip::udp::v4());
|
|
boost::asio::socket_base::receive_buffer_size option(m_SizeOfSocketBuffer);
|
|
m_Socket->set_option(option);
|
|
return true;
|
|
}
|
|
|
|
void UDPClient::Disconnect()
|
|
{
|
|
m_Socket->shutdown(boost::asio::ip::tcp::socket::shutdown_both);
|
|
m_Socket->close();
|
|
m_Socket = nullptr;
|
|
|
|
m_LastReceivedSnapshotGroup = 0;
|
|
m_PacketSegmentMap.clear();
|
|
PacketID m_SendPacketID = 0;
|
|
}
|
|
|
|
void UDPClient::Receive(Packet& packet)
|
|
{
|
|
int bytesRead = readBuffer();
|
|
if (bytesRead > 0) {
|
|
packet.ReconstructFromData(m_ReadBuffer, bytesRead);
|
|
}
|
|
}
|
|
|
|
void UDPClient::ReceivePackets()
|
|
{
|
|
readPartOfPacket();
|
|
}
|
|
|
|
int UDPClient::readBuffer()
|
|
{
|
|
if (!m_Socket) {
|
|
return 0;
|
|
}
|
|
boost::system::error_code error;
|
|
// Read size of packet
|
|
m_Socket->receive(boost
|
|
::asio::buffer((void*)m_ReadBuffer, sizeof(int)),
|
|
boost::asio::ip::udp::socket::message_peek, error);
|
|
int sizeOfPacket = 0;
|
|
memcpy(&sizeOfPacket, m_ReadBuffer, sizeof(int));
|
|
if (sizeOfPacket > m_Socket->available()) {
|
|
LOG_WARNING("UDPClient::readBuffer(): We haven't got the whole packet yet.");
|
|
//return 0;
|
|
}
|
|
// if the buffer is to small increase the size of it
|
|
if (sizeOfPacket > m_BufferSize) {
|
|
delete[] m_ReadBuffer;
|
|
m_ReadBuffer = new char[sizeOfPacket];
|
|
m_BufferSize = sizeOfPacket;
|
|
}
|
|
|
|
size_t availableData = m_Socket->available();
|
|
// Read the rest of the message
|
|
size_t bytesReceived = m_Socket->receive_from(boost
|
|
::asio::buffer((void*)(m_ReadBuffer),
|
|
sizeOfPacket),
|
|
m_ReceiverEndpoint, 0, error);
|
|
if (error) {
|
|
//LOG_ERROR("receive: %s", error.message().c_str());
|
|
}
|
|
if (sizeOfPacket > 1000000)
|
|
LOG_WARNING("The packets received are bigger than 1MB");
|
|
|
|
return bytesReceived;
|
|
}
|
|
|
|
void UDPClient::readPartOfPacket()
|
|
{
|
|
if (!m_Socket) {
|
|
return;
|
|
}
|
|
boost::system::error_code error;
|
|
// Peek header
|
|
m_Socket->receive(boost
|
|
::asio::buffer((void*)m_ReadBuffer, 5 * sizeof(int)),
|
|
boost::asio::ip::udp::socket::message_peek, error);
|
|
|
|
int sizeOfPacket = 0;
|
|
memcpy(&sizeOfPacket, m_ReadBuffer, sizeof(int));
|
|
if (sizeOfPacket == 0) {
|
|
return;
|
|
}
|
|
int packetGroup = *reinterpret_cast<int*>(m_ReadBuffer + sizeof(int));
|
|
int packetGroupIndex = *reinterpret_cast<int*>(m_ReadBuffer + 2 * sizeof(int));
|
|
int packetGroupSize = *reinterpret_cast<int*>(m_ReadBuffer + 3 * sizeof(int));
|
|
//LOG_INFO("Packet group: %i. Group index: %i. Group size: %i. Packet size: %i.", packetGroup, packetGroupIndex, packetGroupSize, sizeOfPacket);
|
|
if (sizeOfPacket > m_Socket->available()) {
|
|
LOG_WARNING("UDPClient::readBuffer(): We haven't got the whole packet yet.");
|
|
// return;
|
|
}
|
|
// if the buffer is to small increase the size of it
|
|
boost::shared_ptr<char> packetData(new char[sizeOfPacket]);
|
|
|
|
// Read the message
|
|
size_t bytesReceived = m_Socket->receive_from(boost
|
|
::asio::buffer((void*)(packetData.get()),
|
|
sizeOfPacket),
|
|
m_ReceiverEndpoint, 0, error);
|
|
if (error) {
|
|
LOG_ERROR("UDPClient::readPartOfPacket: %s", error.message().c_str());
|
|
}
|
|
// Might want to do this earlier when i figure out a good way to
|
|
// remove data from network buffer.
|
|
if (hasReceivedPacket(packetGroup, packetGroupIndex)) {
|
|
return;
|
|
}
|
|
// If group exists
|
|
PacketMap::iterator it;
|
|
it = m_PacketSegmentMap.find(packetGroup);
|
|
if (it != m_PacketSegmentMap.end()) {
|
|
it->second.push_back(std::make_pair(packetGroupIndex, std::move(packetData)));
|
|
} else { // Create group and add element
|
|
m_PacketSegmentMap[packetGroup].push_back(std::make_pair(packetGroupIndex, std::move(packetData)));
|
|
}
|
|
return;
|
|
}
|
|
|
|
bool UDPClient::hasReceivedPacket(int packetGroup, int groupIndex)
|
|
{
|
|
PacketMap::iterator it;
|
|
it = m_PacketSegmentMap.find(packetGroup);
|
|
if (it != m_PacketSegmentMap.end()) {
|
|
const std::vector<std::pair<int, boost::shared_ptr<char>>>& loopPacketGroup = it->second;
|
|
for (size_t i = 0; i < loopPacketGroup.size(); i++) {
|
|
if (loopPacketGroup.at(i).first == groupIndex) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void UDPClient::Send(Packet& packet)
|
|
{
|
|
packet.UpdateSize();
|
|
m_Socket->send_to(boost::asio::buffer(
|
|
packet.Data(),
|
|
packet.Size()),
|
|
m_ReceiverEndpoint, 0);
|
|
}
|
|
|
|
void UDPClient::Broadcast(Packet& packet, int port)
|
|
{
|
|
packet.UpdateSize();
|
|
m_Socket->set_option(boost::asio::socket_base::broadcast(true));
|
|
m_Socket->send_to(boost::asio::buffer(
|
|
packet.Data(),
|
|
packet.Size()),
|
|
udp::endpoint(boost::asio::ip::address_v4().broadcast(), port)
|
|
, 0);
|
|
m_Socket->set_option(boost::asio::socket_base::broadcast(false));
|
|
}
|
|
|
|
bool UDPClient::IsSocketAvailable()
|
|
{
|
|
if (!m_Socket) {
|
|
return false;
|
|
}
|
|
return m_Socket->available();
|
|
}
|
|
|
|
bool UDPClient::GetNextPacket(Packet & packet)
|
|
{
|
|
// A duplicate packet should not be present in the vector!
|
|
// Soo we will assume that this is true and only look if size
|
|
// of vector is correct.
|
|
PacketMap::iterator it = m_PacketSegmentMap.begin();
|
|
while (it != m_PacketSegmentMap.end()) {
|
|
// pair(Group index, packetData)
|
|
std::vector<std::pair<int, boost::shared_ptr<char>>>& currentVector = it->second;
|
|
Packet headerInfoPacket(currentVector.at(0).second.get(), packet.HeaderSize());
|
|
int groupSize = headerInfoPacket.GroupSize();
|
|
//LOG_INFO("UDPClient::GetNextPacket: Packet group : %i.Group index : %i.Group size : %i. lastReceivedSnapshotGroup: %i. MessageType(Ples 4): %i", headerInfoPacket.Group(), headerInfoPacket.GroupIndex(), groupSize, lastReceivedSnapshotGroup, headerInfoPacket.GetMessageType());
|
|
//LOG_INFO("UDPClient::GetNextPacket: Packet group : %i.lastReceivedSnapshotGroup: %i. MessageType(Ples 4): %i", headerInfoPacket.Group(), lastReceivedSnapshotGroup, headerInfoPacket.GetMessageType());
|
|
int mapSize = m_PacketSegmentMap.size();
|
|
if (mapSize > 5) {
|
|
it = m_PacketSegmentMap.erase(it);
|
|
LOG_INFO("The map is increasing in size, size is %i", mapSize);
|
|
continue;
|
|
}
|
|
if (headerInfoPacket.GetMessageType() == MessageType::Snapshot && m_LastReceivedSnapshotGroup > headerInfoPacket.Group()) {
|
|
it = m_PacketSegmentMap.erase(it);
|
|
continue;
|
|
//LOG_INFO("Deleted old entry");
|
|
}
|
|
if (currentVector.size() == groupSize) {
|
|
std::sort(currentVector.begin(), currentVector.end());
|
|
// Add the first packet in vector
|
|
packet.ReconstructFromData(currentVector.at(0).second.get(), packet.HeaderSize());
|
|
// Add the rest of the packets.
|
|
int sizeOfData = 0;
|
|
for (auto& packetSegment : currentVector) {
|
|
memcpy(&sizeOfData, packetSegment.second.get(), sizeof(int));
|
|
packet.WriteData(packetSegment.second.get() + packet.HeaderSize(), sizeOfData - packet.HeaderSize());
|
|
}
|
|
if (headerInfoPacket.GetMessageType() == MessageType::Snapshot) {
|
|
m_LastReceivedSnapshotGroup = packet.Group();
|
|
}
|
|
// No need to get next it as we are returning.
|
|
m_PacketSegmentMap.erase(it);
|
|
return true;
|
|
} else {
|
|
++it;
|
|
}
|
|
}
|
|
return false;
|
|
}
|