Files
rtphone/src/engine/helper/HL_NetworkSocket.cpp
T

207 lines
4.9 KiB
C++

/* Copyright(C) 2007-2026 VoIP objects (voipobjects.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#if defined(TARGET_LINUX) || defined(TARGET_ANDROID)
#include <asm/ioctls.h>
#endif
#include "../engine_config.h"
#include "HL_NetworkSocket.h"
#include "HL_Log.h"
#if defined(TARGET_OSX) || defined(TARGET_LINUX)
#include <fcntl.h>
#endif
#if !defined(TARGET_WIN)
#include <unistd.h>
#endif
#include <assert.h>
#define LOG_SUBSYSTEM "network"
DatagramSocket::DatagramSocket() : mFamily(AF_INET), mHandle(INVALID_SOCKET), mLocalPort(0) {}
DatagramSocket::~DatagramSocket()
{
internalClose();
}
void DatagramSocket::open(int family)
{
if (mHandle != INVALID_SOCKET || mFamily != family)
closeSocket();
assert(family == AF_INET || family == AF_INET6);
mFamily = family;
mHandle = ::socket(mFamily, SOCK_DGRAM, IPPROTO_UDP);
if (mHandle != INVALID_SOCKET)
{
sockaddr_in addr4;
sockaddr_in6 addr6;
memset(&addr4, 0, sizeof(addr4));
memset(&addr6, 0, sizeof(addr6));
socklen_t l = mFamily == AF_INET ? sizeof(addr4) : sizeof(addr6);
int retcode = getsockname(mHandle, (mFamily == AF_INET ? (sockaddr*)&addr4 : (sockaddr*)&addr6), &l);
if (!retcode)
{
mLocalPort = ntohs(mFamily == AF_INET ? addr4.sin_port : addr6.sin6_port);
}
}
}
int DatagramSocket::localport()
{
return mLocalPort;
}
void DatagramSocket::sendDatagram(InternetAddress& dest, const void* packetData, unsigned int packetSize)
{
if (mHandle == INVALID_SOCKET)
return;
/*int sent = */ ::sendto(mHandle, (const char*)packetData, packetSize, 0, dest.genericsockaddr(),
dest.sockaddrLen());
}
unsigned DatagramSocket::recvDatagram(InternetAddress& src, void* packetBuffer, unsigned packetCapacity)
{
if (mHandle == INVALID_SOCKET)
return 0;
sockaddr* addr = nullptr;
socklen_t addrLen = 0;
sockaddr_in addr_4 = {AF_INET, 0, {0}, {0}};
sockaddr_in6 addr_6 = {AF_INET6, 0, 0, {0}, 0};
switch (mFamily)
{
case AF_INET:
addr = (sockaddr*)&addr_4;
addrLen = sizeof(addr_4);
break;
case AF_INET6:
addr = (sockaddr*)&addr_6;
addrLen = sizeof(addr_6);
break;
default:
assert(0);
}
if (!addr || !addrLen)
return 0;
int received = ::recvfrom(mHandle, (char*)packetBuffer, packetCapacity, 0, addr, &addrLen);
if (received > 0)
{
src = InternetAddress((sockaddr&)*addr, addrLen);
return received;
}
return 0;
}
void DatagramSocket::internalClose()
{
if (mHandle != INVALID_SOCKET)
{
#ifdef WIN32
::closesocket(mHandle);
#else
close(mHandle);
#endif
mHandle = INVALID_SOCKET;
}
}
void DatagramSocket::closeSocket()
{
internalClose();
}
bool DatagramSocket::isValid() const
{
return mHandle != INVALID_SOCKET;
}
int DatagramSocket::family() const
{
return mFamily;
}
bool DatagramSocket::setBlocking(bool blocking)
{
#if defined(TARGET_WIN)
unsigned long mode = blocking ? 0 : 1;
return (ioctlsocket(mHandle, FIONBIO, &mode) == 0) ? true : false;
#endif
#if defined(TARGET_OSX) || defined(TARGET_LINUX)
int flags = fcntl(mHandle, F_GETFL, 0);
if (flags < 0)
return false;
flags = blocking ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK);
return (fcntl(mHandle, F_SETFL, flags) == 0) ? true : false;
#endif
#if defined(TARGET_ANDROID)
unsigned long mode = blocking ? 0 : 1;
return (ioctl(mHandle, FIONBIO, &mode) == 0) ? true : false;
#endif
return false;
}
SOCKET DatagramSocket::socket() const
{
return mHandle;
}
DatagramAgreggator::DatagramAgreggator()
{
FD_ZERO(&mReadSet);
mMaxHandle = 0;
}
DatagramAgreggator::~DatagramAgreggator() {}
void DatagramAgreggator::addSocket(PDatagramSocket socket)
{
if (socket->mHandle == INVALID_SOCKET)
return;
if (mSocketVector.size() >= 62)
{
ICELogError(<< "fd_set overflow; too much sockets");
return;
}
FD_SET(socket->mHandle, &mReadSet);
if (socket->mHandle > mMaxHandle)
mMaxHandle = socket->mHandle;
mSocketVector.push_back(socket);
}
unsigned DatagramAgreggator::count()
{
return mSocketVector.size();
}
bool DatagramAgreggator::hasDataAtIndex(unsigned index)
{
PDatagramSocket socket = mSocketVector[index];
return FD_ISSET(socket->mHandle, &mReadSet);
}
PDatagramSocket DatagramAgreggator::socketAt(unsigned index)
{
return mSocketVector[index];
}
bool DatagramAgreggator::waitForData(std::chrono::milliseconds timeout)
{
timeval tv;
tv.tv_sec = timeout.count() / 1000;
tv.tv_usec = (timeout.count() % 1000) * 1000;
int rescode = ::select(mMaxHandle + 1, &mReadSet, nullptr, nullptr, &tv);
return rescode > 0;
}