#define _CRT_SECURE_NO_DEPRECATE
#include "ofxUDPManager.h"
#include "ofxNetworkUtils.h"
#include "ofxNetwork.h"
#include "ofLog.h"
#include "ofUtils.h"
using namespace std;
bool ofxUDPManager::m_bWinsockInit= false;
ofxUDPManager::ofxUDPManager()
{
#ifdef TARGET_WIN32
if (!m_bWinsockInit) {
unsigned short vr;
WSADATA wsaData;
vr= MAKEWORD(2, 2);
WSAStartup(vr, &wsaData);
m_bWinsockInit= true;
}
#endif
m_hSocket= INVALID_SOCKET;
m_dwTimeoutReceive = OF_UDP_DEFAULT_TIMEOUT;
m_dwTimeoutSend = OF_UDP_DEFAULT_TIMEOUT;
canGetRemoteAddress = false;
nonBlocking = true;
};
bool ofxUDPManager::Close()
{
if (m_hSocket == INVALID_SOCKET)
return(false);
#ifdef TARGET_WIN32
if(closesocket(m_hSocket) == SOCKET_ERROR)
#else
if(close(m_hSocket) == SOCKET_ERROR)
#endif
{
ofxNetworkCheckError();
return(false);
}
m_hSocket= INVALID_SOCKET;
return(true);
}
bool ofxUDPManager::Setup(const ofxUDPSettings & settings)
{
if (!settings.bindPort && !settings.sendPort) {
ofLogError("ofxUDPManager") << "passed settings object was not initialized with .receiveOn or .sendTo";
return false;
}
if (!Create()) {
return false;
}
SetReuseAddress(settings.reuse);
SetEnableBroadcast(settings.broadcast);
SetNonBlocking(!settings.blocking);
SetTimeoutSend(settings.sendTimeout);
SetTimeoutReceive(settings.receiveTimeout);
if (settings.receiveBufferSize) SetReceiveBufferSize(settings.receiveBufferSize);
if (settings.sendBufferSize) SetSendBufferSize(settings.sendBufferSize);
SetTTL(settings.ttl);
if (settings.bindPort) {
if (settings.multicast) {
return BindMcast((char*)settings.bindAddress.c_str(), settings.bindPort);
} else {
return Bind(settings.bindPort);
}
}
if (settings.sendPort) {
if (settings.multicast) {
return ConnectMcast((char*)settings.sendAddress.c_str(), settings.sendPort);
} else {
return Connect((char*)settings.sendAddress.c_str(), settings.sendPort);
}
}
return true;
}
bool ofxUDPManager::Create()
{
if (m_hSocket != INVALID_SOCKET)
return(false);
m_hSocket = socket(AF_INET, SOCK_DGRAM, 0);
if (m_hSocket != INVALID_SOCKET)
{
int unused = true;
setsockopt(m_hSocket, SOL_SOCKET, SO_REUSEADDR, (char*)&unused, sizeof(unused));
#ifdef __APPLE__
setsockopt(m_hSocket, SOL_SOCKET, SO_REUSEPORT, (char*)&unused, sizeof(unused));
#endif
}
bool ret = m_hSocket != INVALID_SOCKET;
if(!ret) ofxNetworkCheckError();
return ret;
}
int ofxUDPManager::WaitReceive(time_t timeoutSeconds, time_t timeoutMicros){
if (m_hSocket == INVALID_SOCKET) return SOCKET_ERROR;
fd_set fd;
FD_ZERO(&fd);
FD_SET(m_hSocket, &fd);
timeval tv;
tv.tv_sec = timeoutSeconds;
tv.tv_usec = timeoutMicros;
auto ret = select(m_hSocket+1,&fd,NULL,NULL,&tv);
if(ret == 0){
return SOCKET_TIMEOUT;
}else if(ret < 0){
return SOCKET_ERROR;
}else{
return 0;
}
}
int ofxUDPManager::WaitSend(time_t timeoutSeconds, time_t timeoutMicros){
if (m_hSocket == INVALID_SOCKET) return SOCKET_ERROR;
fd_set fd;
FD_ZERO(&fd);
FD_SET(m_hSocket, &fd);
timeval tv;
tv.tv_sec = timeoutSeconds;
tv.tv_usec = timeoutMicros;
auto ret = select(m_hSocket+1,NULL,&fd,NULL,&tv);
if(ret == 0){
return SOCKET_TIMEOUT;
}else if(ret < 0){
return SOCKET_ERROR;
}else{
return 0;
}
}
bool ofxUDPManager::SetNonBlocking(bool useNonBlocking)
{
nonBlocking = useNonBlocking;
#ifdef TARGET_WIN32
unsigned long arg = nonBlocking;
int retVal = ioctlsocket(m_hSocket,FIONBIO,&arg);
#else
int arg = nonBlocking;
int retVal = ioctl(m_hSocket,FIONBIO,&arg);
#endif
bool ret=(retVal >= 0);
if(!ret) ofxNetworkCheckError();
return ret;
}
bool ofxUDPManager::Bind(unsigned short usPort)
{
saServer.sin_family = AF_INET;
saServer.sin_addr.s_addr = INADDR_ANY;
saServer.sin_port = htons(usPort);
int ret = ::bind(m_hSocket,(struct sockaddr*)&saServer,sizeof(struct sockaddr));
if(ret == SOCKET_ERROR) ofxNetworkCheckError();
return (ret == 0);
}
bool ofxUDPManager::BindMcast(char *pMcast, unsigned short usPort)
{
if (!Bind(usPort))
{
ofLogWarning("ofxUDPManager") << "BindMcast(): couldn't bind to port " << usPort;
return false;
}
struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr = inet_addr(pMcast);
mreq.imr_interface.s_addr = INADDR_ANY;
if (setsockopt(m_hSocket, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char FAR*) &mreq, sizeof (mreq)) == SOCKET_ERROR)
{
ofxNetworkCheckError();
return false;
}
return true;
}
bool ofxUDPManager::Connect(const char *pHost, unsigned short usPort)
{
memset(&saClient, 0, sizeof(sockaddr_in));
struct hostent *he;
if (m_hSocket == INVALID_SOCKET) return(false);
#include "ofUtils.h"
if ((he = gethostbyname(pHost)) == NULL)
return(false);
saClient.sin_family= AF_INET;
saClient.sin_port = htons(usPort);
memcpy((char *) &saClient.sin_addr.s_addr,
he->h_addr_list[0], he->h_length);
memset(&(saClient.sin_zero), '\0', 8);
return true;
}
bool ofxUDPManager::ConnectMcast(char* pMcast, unsigned short usPort)
{
if (!Bind(usPort))
{
#ifdef _DEBUG
ofLogError("ofxUDPManager") << "ConnectMcast(): couldn't bind to " << usPort;
ofxNetworkCheckError();
#endif
return false;
}
if (!SetTTL(1))
{
#ifdef _DEBUG
ofLogWarning("ofxUDPManager") << "ConnectMcast(): couldn't set TTL; continuing anyway";
ofxNetworkCheckError();
#endif
}
if (!Connect(pMcast, usPort))
{
#ifdef _DEBUG
ofLogError("ofxUDPManager") << " ConnectMcast(): couldn't connect to socket";
ofxNetworkCheckError();
#endif
return false;
}
return true;
}
int ofxUDPManager::Send(const char* pBuff, const int iSize)
{
if (m_hSocket == INVALID_SOCKET) return(SOCKET_ERROR);
if (m_dwTimeoutSend != NO_TIMEOUT){
auto ret = WaitSend(m_dwTimeoutSend,0);
if(ret!=0){
return ret;
}
}
int ret = sendto(m_hSocket, (char*)pBuff, iSize, 0, (sockaddr *)&saClient, sizeof(sockaddr));
if(ret==-1) ofxNetworkCheckError();
return ret;
}
int ofxUDPManager::SendAll(const char* pBuff, const int iSize)
{
if (m_hSocket == INVALID_SOCKET) return(SOCKET_ERROR);
auto timestamp = ofGetElapsedTimeMicros();
auto timeleftSecs = m_dwTimeoutSend;
auto timeleftMicros = 0;
int total= 0;
int bytesleft = iSize;
int ret=-1;
while (total < iSize) {
if (m_dwTimeoutSend != NO_TIMEOUT){
auto ret = WaitSend(timeleftSecs,timeleftMicros);
if(ret!=0){
return ret;
}
}
ret = sendto(m_hSocket, (char*)pBuff, iSize, 0, (sockaddr *)&saClient, sizeof(sockaddr));
if (ret == SOCKET_ERROR) {
return SOCKET_ERROR;
}
total += ret;
bytesleft -=ret;
if (m_dwTimeoutSend != NO_TIMEOUT){
auto now = ofGetElapsedTimeMicros();
auto diff = now - timestamp;
if (diff > m_dwTimeoutSend * 1000000){
return SOCKET_TIMEOUT;
}
float timeFloat = m_dwTimeoutSend - diff/1000000.;
timeleftSecs = timeFloat;
timeleftMicros = (timeFloat - timeleftSecs) * 1000000;
}
}
return total;
}
int ofxUDPManager::PeekReceive()
{
if (m_hSocket == INVALID_SOCKET){
ofLogError("INVALID_SOCKET");
return SOCKET_ERROR;
}
if (m_dwTimeoutReceive != NO_TIMEOUT){
auto ret = WaitReceive(m_dwTimeoutReceive,0);
if(ret!=0){
return ret;
}
}
#ifdef TARGET_WIN32
unsigned long size = 0;
int retVal = ioctlsocket(m_hSocket,FIONREAD,&size);
#else
int size = 0;
int retVal = ioctl(m_hSocket,FIONREAD,&size);
#endif
if ( retVal != 0 )
{
ofxNetworkCheckError();
return SOCKET_ERROR;
}
return size;
}
int ofxUDPManager::Receive(char* pBuff, const int iSize)
{
if (m_hSocket == INVALID_SOCKET){
ofLogError("ofxUDPManager") << "INVALID_SOCKET";
return(SOCKET_ERROR);
}
if (m_dwTimeoutReceive != NO_TIMEOUT){
auto ret = WaitReceive(m_dwTimeoutReceive,0);
if(ret!=0){
return ret;
}
}
#ifndef TARGET_WIN32
socklen_t nLen= sizeof(sockaddr);
#else
int nLen= sizeof(sockaddr);
#endif
int ret=0;
memset(pBuff, 0, iSize);
ret= recvfrom(m_hSocket, pBuff, iSize, 0, (sockaddr *)&saClient, &nLen);
if (ret > 0)
{
canGetRemoteAddress= true;
}
else
{
canGetRemoteAddress = false;
int SocketError = ofxNetworkCheckError();
if ( SocketError == OFXNETWORK_ERROR(WOULDBLOCK) )
return 0;
}
return ret;
}
void ofxUDPManager::SetTimeoutSend(int timeoutInSeconds)
{
m_dwTimeoutSend= timeoutInSeconds;
}
void ofxUDPManager::SetTimeoutReceive(int timeoutInSeconds)
{
m_dwTimeoutReceive= timeoutInSeconds;
}
int ofxUDPManager::GetTimeoutSend()
{
return m_dwTimeoutSend;
}
int ofxUDPManager::GetTimeoutReceive()
{
return m_dwTimeoutReceive;
}
bool ofxUDPManager::GetRemoteAddr(string& address,int& port) const
{
if (m_hSocket == INVALID_SOCKET) return(false);
if ( canGetRemoteAddress == false) return (false);
const char* AddressStr = inet_ntoa((in_addr)saClient.sin_addr);
address = AddressStr;
port = ntohs(saClient.sin_port);
return true;
}
bool ofxUDPManager::GetListenAddr(string& address,int& port) const
{
if (m_hSocket == INVALID_SOCKET) return(false);
const char* AddressStr = inet_ntoa((in_addr)saServer.sin_addr);
address = AddressStr;
port = ntohs(saServer.sin_port);
return true;
}
int ofxUDPManager::GetMaxMsgSize()
{
if (m_hSocket == INVALID_SOCKET) return(false);
int sizeBuffer=0;
#ifndef TARGET_WIN32
socklen_t size = sizeof(int);
#else
int size = sizeof(int);
#endif
int ret = getsockopt(m_hSocket, SOL_SOCKET, SO_MAX_MSG_SIZE, (char*)&sizeBuffer, &size);
if(ret==-1) ofxNetworkCheckError();
return sizeBuffer;
}
int ofxUDPManager::GetReceiveBufferSize()
{
if (m_hSocket == INVALID_SOCKET) return(false);
int sizeBuffer=0;
#ifndef TARGET_WIN32
socklen_t size = sizeof(int);
#else
int size = sizeof(int);
#endif
int ret = getsockopt(m_hSocket, SOL_SOCKET, SO_RCVBUF, (char*)&sizeBuffer, &size);
if(ret==-1) ofxNetworkCheckError();
return sizeBuffer;
}
bool ofxUDPManager::SetReceiveBufferSize(int sizeInByte)
{
if (m_hSocket == INVALID_SOCKET) return(false);
if ( setsockopt(m_hSocket, SOL_SOCKET, SO_RCVBUF, (char*)&sizeInByte, sizeof(sizeInByte)) == 0){
return true;
}else{
ofxNetworkCheckError();
return false;
}
}
int ofxUDPManager::GetSendBufferSize()
{
if (m_hSocket == INVALID_SOCKET) return(false);
int sizeBuffer=0;
#ifndef TARGET_WIN32
socklen_t size = sizeof(int);
#else
int size = sizeof(int);
#endif
int ret = getsockopt(m_hSocket, SOL_SOCKET, SO_SNDBUF, (char*)&sizeBuffer, &size);
if(ret==-1) ofxNetworkCheckError();
return sizeBuffer;
}
bool ofxUDPManager::SetSendBufferSize(int sizeInByte)
{
if (m_hSocket == INVALID_SOCKET) return(false);
if ( setsockopt(m_hSocket, SOL_SOCKET, SO_SNDBUF, (char*)&sizeInByte, sizeof(sizeInByte)) == 0){
return true;
}else{
ofxNetworkCheckError();
return false;
}
}
bool ofxUDPManager::SetReuseAddress(bool allowReuse)
{
if (m_hSocket == INVALID_SOCKET) return(false);
int on;
if (allowReuse) on=1;
else on=0;
if ( setsockopt(m_hSocket, SOL_SOCKET, SO_REUSEADDR, (char*)&on, sizeof(on)) == 0){
return true;
}else{
ofxNetworkCheckError();
return false;
}
}
bool ofxUDPManager::SetEnableBroadcast(bool enableBroadcast)
{
int on;
if (enableBroadcast) on=1;
else on=0;
if ( setsockopt(m_hSocket, SOL_SOCKET, SO_BROADCAST, (char*)&on, sizeof(on)) == 0){
return true;
}else{
ofxNetworkCheckError();
return false;
}
}
int ofxUDPManager::GetTTL()
{
if (m_hSocket == INVALID_SOCKET) return(false);
int nTTL;
#ifndef TARGET_WIN32
socklen_t nSize = sizeof(int);
#else
int nSize = sizeof(int);
#endif
if (getsockopt(m_hSocket, IPPROTO_IP, IP_MULTICAST_TTL, (char FAR *) &nTTL, &nSize) == SOCKET_ERROR)
{
#ifdef _DEBUG
ofLogError("ofxUDPManager") << "GetTTL(): getsockopt failed";
#endif
ofxNetworkCheckError();
return -1;
}
return nTTL;
}
bool ofxUDPManager::SetTTL(int nTTL)
{
if (m_hSocket == INVALID_SOCKET) return(false);
if (setsockopt(m_hSocket, IPPROTO_IP, IP_MULTICAST_TTL, (char FAR *)&nTTL, sizeof (int)) == SOCKET_ERROR)
{
#ifdef _DEBUG
ofLogError("ofxUDPManager") << "SetTTL(): setsockopt failed";
#endif
ofxNetworkCheckError();
return false;
}
return true;
}
Comments