785 lines
21 KiB
C++
785 lines
21 KiB
C++
#include "cwCommon.h"
|
|
#include "cwLog.h"
|
|
#include "cwCommonImpl.h"
|
|
#include "cwMem.h"
|
|
|
|
#include <sys/socket.h>
|
|
#include <sys/ioctl.h>
|
|
#include <net/if.h>
|
|
#include <netinet/in.h>
|
|
#include <arpa/inet.h>
|
|
#include <fcntl.h>
|
|
#include <unistd.h> // close
|
|
|
|
#include "cwTcpSocket.h"
|
|
|
|
#define cwSOCKET_SYS_ERR (-1)
|
|
#define cwSOCKET_NULL_SOCK (-1)
|
|
|
|
#ifndef HOST_NAME_MAX
|
|
#define HOST_NAME_MAX _POSIX_HOST_NAME_MAX
|
|
#endif
|
|
|
|
|
|
namespace cw
|
|
{
|
|
namespace net
|
|
{
|
|
namespace socket
|
|
{
|
|
enum
|
|
{
|
|
kIsConnectedFl = 0x01,
|
|
kIsBlockingFl = 0x02
|
|
};
|
|
|
|
typedef struct socket_str
|
|
{
|
|
int sockH;
|
|
int fdH;
|
|
unsigned createFlags;
|
|
unsigned flags;
|
|
struct sockaddr_in sockaddr;
|
|
char ntopBuf[ INET_ADDRSTRLEN+1 ]; // use INET6_ADDRSTRLEN for IPv6
|
|
char hnameBuf[ HOST_NAME_MAX+1 ];
|
|
} socket_t;
|
|
|
|
inline socket_t* _handleToPtr( handle_t h )
|
|
{ return handleToPtr<handle_t,socket_t>(h); }
|
|
|
|
rc_t _destroy( socket_t* p )
|
|
{
|
|
|
|
// close the fdH
|
|
if( p->fdH != cwSOCKET_NULL_SOCK )
|
|
{
|
|
errno = 0;
|
|
|
|
if( ::close(p->fdH) != 0 )
|
|
cwLogSysError(kOpFailRC,errno,"The socket fd close failed." );
|
|
|
|
p->fdH = cwSOCKET_NULL_SOCK;
|
|
}
|
|
|
|
// close the socket
|
|
if( p->sockH != cwSOCKET_NULL_SOCK )
|
|
{
|
|
errno = 0;
|
|
|
|
if( ::close(p->sockH) != 0 )
|
|
cwLogSysError(kOpFailRC,errno,"The socket close failed." );
|
|
|
|
p->sockH = cwSOCKET_NULL_SOCK;
|
|
}
|
|
|
|
mem::release(p);
|
|
return kOkRC;
|
|
}
|
|
|
|
|
|
rc_t _initAddr( const char* addrStr, portNumber_t portNumber, struct sockaddr_in* retAddrPtr )
|
|
{
|
|
memset(retAddrPtr,0,sizeof(struct sockaddr_in));
|
|
|
|
//if( portNumber == kInvalidPortNumber )
|
|
// return cwLogError(kInvalidArgRC,"The port number %i cannot be used.",kInvalidPortNumber);
|
|
|
|
if( addrStr == NULL )
|
|
retAddrPtr->sin_addr.s_addr = htonl(INADDR_ANY);
|
|
else
|
|
{
|
|
errno = 0;
|
|
|
|
if(inet_pton(AF_INET,addrStr,&retAddrPtr->sin_addr) == 0 )
|
|
return cwLogSysError(kOpFailRC,errno, "The network address string '%s' could not be converted to a netword address structure.",cwStringNullGuard(addrStr) );
|
|
}
|
|
|
|
//retAddrPtr->sin_len = sizeof(struct sockaddr_in);
|
|
retAddrPtr->sin_family = AF_INET;
|
|
if( portNumber != kInvalidPortNumber )
|
|
retAddrPtr->sin_port = htons(portNumber);
|
|
|
|
return kOkRC;
|
|
}
|
|
|
|
rc_t _connect( socket_t* p, const char* remoteAddr, portNumber_t remotePort )
|
|
{
|
|
struct sockaddr_in addr;
|
|
rc_t rc;
|
|
|
|
// create the remote address
|
|
if((rc = _initAddr( remoteAddr, remotePort, &addr )) != kOkRC )
|
|
return rc;
|
|
|
|
errno = 0;
|
|
|
|
// ... and connect this socket to the remote address/port
|
|
if( connect(p->sockH, (struct sockaddr*)&addr, sizeof(addr)) == cwSOCKET_SYS_ERR )
|
|
return cwLogSysError(kOpFailRC, errno, "Socket connect failed." );
|
|
|
|
p->flags = cwSetFlag(p->flags,kIsConnectedFl);
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
rc_t _setTimeOutMs( socket_t* p, unsigned timeOutMs )
|
|
{
|
|
rc_t rc = kOkRC;
|
|
|
|
struct timeval timeOut;
|
|
|
|
// set the socket time out
|
|
timeOut.tv_sec = timeOutMs/1000;
|
|
timeOut.tv_usec = (timeOutMs - (timeOut.tv_sec * 1000)) * 1000;
|
|
|
|
if( setsockopt( p->sockH, SOL_SOCKET, SO_RCVTIMEO, &timeOut, sizeof(timeOut) ) == cwSOCKET_SYS_ERR )
|
|
{
|
|
rc = cwLogSysError(kOpFailRC,errno, "Attempt to set the socket timeout failed." );
|
|
goto errLabel;
|
|
}
|
|
|
|
errLabel:
|
|
return rc;
|
|
}
|
|
|
|
rc_t _get_info( int sockH, unsigned char outBuf[6], struct sockaddr_in* addr, const char* interfaceName )
|
|
{
|
|
cw::rc_t rc = kOkRC;
|
|
struct ifreq ifr;
|
|
struct ifconf ifc;
|
|
char buf[1024];
|
|
|
|
ifc.ifc_len = sizeof(buf);
|
|
ifc.ifc_buf = buf;
|
|
|
|
if (ioctl(sockH, SIOCGIFCONF, &ifc) == -1)
|
|
{
|
|
rc = cwLogSysError(kOpFailRC,errno,"ioctl(SIOCGIFCONF) failed.");
|
|
return rc;
|
|
}
|
|
|
|
struct ifreq* it = ifc.ifc_req;
|
|
const struct ifreq* const end = it + (ifc.ifc_len / sizeof(struct ifreq));
|
|
|
|
for (; it != end; ++it)
|
|
{
|
|
if( strcmp(it->ifr_name,interfaceName ) == 0 )
|
|
{
|
|
strcpy(ifr.ifr_name, it->ifr_name);
|
|
|
|
if (ioctl(sockH, SIOCGIFFLAGS, &ifr) != 0)
|
|
{
|
|
rc = cwLogSysError(kOpFailRC,errno,"ioctl(SIOCGIFCONF) failed.");
|
|
}
|
|
else
|
|
{
|
|
if (! (ifr.ifr_flags & IFF_LOOPBACK))
|
|
{
|
|
// don't count loopback
|
|
if (ioctl(sockH, SIOCGIFHWADDR, &ifr) == 0)
|
|
{
|
|
memcpy(outBuf, ifr.ifr_hwaddr.sa_data, 6);
|
|
|
|
if( addr != nullptr && ioctl(sockH, SIOCGIFADDR, &ifr) == 0)
|
|
{
|
|
addr->sin_addr = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr;
|
|
}
|
|
|
|
return kOkRC;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return cwLogError(kInvalidArgRC,"The network interface information for '%s' could not be found.", interfaceName);
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
cw::rc_t cw::net::socket::create(
|
|
handle_t& hRef,
|
|
portNumber_t port,
|
|
unsigned flags,
|
|
unsigned timeOutMs,
|
|
const char* remoteAddr,
|
|
portNumber_t remotePort,
|
|
const char* localAddr)
|
|
{
|
|
rc_t rc;
|
|
if((rc = destroy(hRef)) != kOkRC )
|
|
return rc;
|
|
|
|
socket_t* p = mem::allocZ<socket_t>();
|
|
p->sockH = cwSOCKET_NULL_SOCK;
|
|
p->fdH = cwSOCKET_NULL_SOCK;
|
|
p->createFlags = flags;
|
|
|
|
int type = cwIsFlag(flags,kStreamFl) ? SOCK_STREAM : SOCK_DGRAM;
|
|
int protocol = cwIsFlag(flags,kTcpFl) ? 0 : IPPROTO_UDP;
|
|
|
|
// get a handle to the socket
|
|
if(( p->sockH = ::socket( AF_INET, type, protocol ) ) == cwSOCKET_SYS_ERR )
|
|
return cwLogSysError(kOpFailRC, errno, "Socket create failed." );
|
|
|
|
// if this socket should block
|
|
if( cwIsFlag(flags,kBlockingFl))
|
|
{
|
|
if( timeOutMs > 0 )
|
|
{
|
|
_setTimeOutMs(p,timeOutMs);
|
|
}
|
|
|
|
p->flags = cwSetFlag(p->flags,kIsBlockingFl);
|
|
|
|
|
|
}
|
|
else
|
|
{
|
|
int opts;
|
|
|
|
// get the socket options flags
|
|
if( (opts = fcntl(p->sockH,F_GETFL)) < 0 )
|
|
{
|
|
rc = cwLogSysError(kOpFailRC,errno, "Attempt to get the socket options flags failed." );
|
|
goto errLabel;
|
|
}
|
|
|
|
opts = (opts | O_NONBLOCK);
|
|
|
|
// set the socket options flags
|
|
if(fcntl(p->sockH,F_SETFL,opts) < 0)
|
|
{
|
|
rc = cwLogSysError(kOpFailRC,errno, "Attempt to set the socket to non-blocking failed." );
|
|
goto errLabel;
|
|
}
|
|
|
|
}
|
|
|
|
if( cwIsFlag(flags,kReuseAddrFl) )
|
|
{
|
|
unsigned int reuseaddr = 1;
|
|
if( setsockopt(p->sockH, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuseaddr, sizeof(reuseaddr)) == cwSOCKET_SYS_ERR )
|
|
{
|
|
rc = cwLogSysError(kOpFailRC,errno, "Attempt to set the socket 'reuse address' attribute failed." );
|
|
goto errLabel;
|
|
}
|
|
}
|
|
|
|
#ifdef SO_REUSEPORT
|
|
if( cwIsFlag(flags,kReusePortFl) )
|
|
{
|
|
unsigned int reuseaddr = 1;
|
|
if(setsockopt(p->sockH, SOL_SOCKET, SO_REUSEPORT, (const char*)&reuseaddr, sizeof(reuseaddr)) == cwSOCKET_SYS_ERR )
|
|
{
|
|
rc = cwLogSysError(kOpFailRC,errno, "Attempt to set the socket 'reuse port' attribute failed." );
|
|
goto errLabel;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if( cwIsFlag(flags,kMultiCastTtlFl) )
|
|
{
|
|
unsigned char ttl = 1;
|
|
if( setsockopt(p->sockH, IPPROTO_IP, IP_MULTICAST_TTL, (const char*)&ttl, sizeof(ttl)) == cwSOCKET_SYS_ERR )
|
|
{
|
|
rc = cwLogSysError(kOpFailRC,errno, "Attempt to set the socket 'multicast TTL' attribute failed." );
|
|
goto errLabel;
|
|
}
|
|
}
|
|
|
|
if( cwIsFlag(flags,kMultiCastLoopFl) )
|
|
{
|
|
|
|
unsigned char loopback = 1;
|
|
if( setsockopt(p->sockH, IPPROTO_IP, IP_MULTICAST_LOOP, (const char*)&loopback, sizeof(loopback)) == cwSOCKET_SYS_ERR )
|
|
{
|
|
rc = cwLogSysError(kOpFailRC,errno, "Attempt to set the socket 'reuse port' attribute failed." );
|
|
goto errLabel;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
// if broadcast option was requested.
|
|
if( cwIsFlag(flags,kBroadcastFl) )
|
|
{
|
|
int bcastFl = 1;
|
|
if( setsockopt( p->sockH, SOL_SOCKET, SO_BROADCAST, &bcastFl, sizeof(bcastFl) ) == cwSOCKET_SYS_ERR )
|
|
{
|
|
rc = cwLogSysError(kOpFailRC,errno, "Attempt to set the socket broadcast attribute failed." );
|
|
goto errLabel;
|
|
}
|
|
}
|
|
|
|
// create the 32 bit local address
|
|
if((rc = _initAddr( localAddr, port, &p->sockaddr )) != kOkRC )
|
|
goto errLabel;
|
|
|
|
// bind the socket to a local address/port
|
|
if( (bind( p->sockH, (struct sockaddr*)&p->sockaddr, sizeof(p->sockaddr))) == cwSOCKET_SYS_ERR )
|
|
{
|
|
rc = cwLogSysError(kOpFailRC,errno,"Socket bind failed." );
|
|
goto errLabel;
|
|
}
|
|
|
|
// get the local address as a string
|
|
if((rc = addrToString( &p->sockaddr, p->ntopBuf, sizeof(p->ntopBuf) )) != kOkRC )
|
|
goto errLabel;
|
|
|
|
|
|
// if a remote addr was given connect this socket to it
|
|
if( remoteAddr != NULL )
|
|
if((rc = _connect(p,remoteAddr,remotePort)) != kOkRC )
|
|
goto errLabel;
|
|
|
|
// if the socket should be marked for listening
|
|
if( cwIsFlag(flags,kListenFl) )
|
|
{
|
|
if( ::listen(p->sockH, 10) != 0 )
|
|
{
|
|
rc = cwLogSysError(kOpFailRC,errno,"Socket listen() failed.");
|
|
goto errLabel;
|
|
}
|
|
}
|
|
|
|
errLabel:
|
|
if(rc != kOkRC )
|
|
_destroy(p);
|
|
else
|
|
hRef.set(p);
|
|
|
|
return rc;
|
|
}
|
|
|
|
cw::rc_t cw::net::socket::destroy( handle_t& hRef )
|
|
{
|
|
rc_t rc = kOkRC;
|
|
if( !hRef.isValid() )
|
|
return rc;
|
|
|
|
socket_t* p = _handleToPtr(hRef);
|
|
|
|
if((rc = _destroy(p)) != kOkRC )
|
|
return rc;
|
|
|
|
hRef.clear();
|
|
return rc;
|
|
}
|
|
|
|
unsigned cw::net::socket::flags( handle_t h )
|
|
{
|
|
socket_t* p = _handleToPtr(h);
|
|
return p->createFlags;
|
|
}
|
|
|
|
cw::rc_t cw::net::socket::set_multicast_time_to_live( handle_t h, unsigned seconds )
|
|
{
|
|
rc_t rc = kOkRC;
|
|
socket_t* p = _handleToPtr(h);
|
|
|
|
if( setsockopt( p->sockH, IPPROTO_IP, IP_MULTICAST_TTL, &seconds, sizeof(seconds) ) == cwSOCKET_SYS_ERR )
|
|
{
|
|
rc = cwLogSysError(kOpFailRC,errno, "Attempt to set the socket multicast TTLfailed." );
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
cw::rc_t cw::net::socket::join_multicast_group( handle_t h, const char* addrStr )
|
|
{
|
|
rc_t rc = kOkRC;
|
|
socket_t* p = _handleToPtr(h);
|
|
struct ip_mreq req;
|
|
|
|
memset(&req, 0, sizeof(req));
|
|
|
|
if(inet_pton(AF_INET,addrStr,&req.imr_multiaddr.s_addr) == 0 )
|
|
{
|
|
rc = cwLogSysError(kOpFailRC,errno, "The network address string '%s' could not be converted to a netword address structure.",cwStringNullGuard(addrStr) );
|
|
goto errLabel;
|
|
}
|
|
|
|
req.imr_interface.s_addr = INADDR_ANY;
|
|
|
|
if(setsockopt(p->sockH, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&req, sizeof(req)) == cwSOCKET_SYS_ERR )
|
|
{
|
|
rc = cwLogSysError(kOpFailRC,errno, "Attempt to add socket to multicast group on '%s' failed.", cwStringNullGuard(addrStr) );
|
|
goto errLabel;
|
|
}
|
|
|
|
errLabel:
|
|
return rc;
|
|
}
|
|
|
|
cw::rc_t cw::net::socket::setTimeOutMs( handle_t h, unsigned timeOutMs )
|
|
{
|
|
socket_t* p = _handleToPtr(h);
|
|
return _setTimeOutMs(p,timeOutMs);
|
|
}
|
|
|
|
|
|
cw::rc_t cw::net::socket::accept( handle_t h )
|
|
{
|
|
struct sockaddr_storage remoteAddr; // connector's address information
|
|
socklen_t sin_size = sizeof(remoteAddr);
|
|
|
|
rc_t rc = kOkRC;
|
|
int fd = cwSOCKET_NULL_SOCK;
|
|
|
|
socket_t* p = _handleToPtr(h);
|
|
|
|
if((fd = accept(p->sockH, (struct sockaddr*)&remoteAddr, &sin_size)) < 0)
|
|
{
|
|
if( errno == EAGAIN || errno == EWOULDBLOCK )
|
|
rc = kTimeOutRC;
|
|
else
|
|
{
|
|
rc = cwLogSysError(kOpFailRC,errno,"Socket accept() failed.");
|
|
goto errLabel;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
char s[INET_ADDRSTRLEN+1];
|
|
|
|
addrToString( (struct sockaddr_in*)&remoteAddr, s, INET_ADDRSTRLEN );
|
|
|
|
if( p->fdH != cwSOCKET_NULL_SOCK )
|
|
{
|
|
close(p->fdH);
|
|
p->fdH = cwSOCKET_NULL_SOCK;
|
|
}
|
|
|
|
p->fdH = fd;
|
|
|
|
p->flags = cwSetFlag(p->flags,kIsConnectedFl);
|
|
|
|
/*
|
|
if( false )
|
|
{
|
|
struct sockaddr_in addr;
|
|
char aBuf[ INET_ADDRSTRLEN+1 ];
|
|
peername( h, &addr );
|
|
addrToString( &addr, aBuf, INET_ADDRSTRLEN);
|
|
printf("DNS-SD PEER: %i %s\n", addr.sin_port,aBuf );
|
|
|
|
}
|
|
*/
|
|
|
|
cwLogInfo("Connect:%s\n",s);
|
|
}
|
|
|
|
errLabel:
|
|
return rc;
|
|
}
|
|
|
|
|
|
cw::rc_t cw::net::socket::connect( handle_t h, const char* remoteAddr, portNumber_t remotePort )
|
|
{
|
|
socket_t* p = _handleToPtr(h);
|
|
return _connect(p,remoteAddr,remotePort);
|
|
}
|
|
|
|
bool cw::net::socket::isConnected( handle_t h )
|
|
{
|
|
socket_t* p = _handleToPtr(h);
|
|
return cwIsFlag(p->flags,kIsConnectedFl);
|
|
}
|
|
|
|
cw::rc_t cw::net::socket::send( handle_t h, const void* data, unsigned dataByteCnt )
|
|
{
|
|
socket_t* p = _handleToPtr(h);
|
|
errno = 0;
|
|
|
|
if( cwIsFlag(p->flags,kIsConnectedFl) == false )
|
|
return cwLogError(kInvalidOpRC,"socket::send() only works with connected sockets.");
|
|
|
|
int fd = p->fdH != cwSOCKET_NULL_SOCK ? p->fdH : p->sockH;
|
|
|
|
if( ::send( fd, data, dataByteCnt, 0 ) == cwSOCKET_SYS_ERR )
|
|
return cwLogSysError(kOpFailRC,errno,"Send failed.");
|
|
|
|
return kOkRC;
|
|
}
|
|
|
|
cw::rc_t cw::net::socket::send( handle_t h, const void* data, unsigned dataByteCnt, const struct sockaddr_in* remoteAddr )
|
|
{
|
|
socket_t* p = _handleToPtr(h);
|
|
|
|
errno = 0;
|
|
|
|
if( ::sendto(p->sockH, data, dataByteCnt, 0, (struct sockaddr*)remoteAddr, sizeof(*remoteAddr)) == cwSOCKET_SYS_ERR )
|
|
return cwLogSysError(kOpFailRC,errno,"Send to remote addr. failed.");
|
|
|
|
return kOkRC;
|
|
}
|
|
|
|
cw::rc_t cw::net::socket::send( handle_t h, const void* data, unsigned dataByteCnt, const char* remoteAddr, portNumber_t remotePort )
|
|
{
|
|
rc_t rc;
|
|
struct sockaddr_in addr;
|
|
|
|
if((rc = _initAddr(remoteAddr,remotePort,&addr)) != kOkRC )
|
|
return rc;
|
|
|
|
return send( h, data, dataByteCnt, &addr );
|
|
}
|
|
|
|
cw::rc_t cw::net::socket::receive( handle_t h, char* data, unsigned dataByteCnt, unsigned* recvByteCntRef, struct sockaddr_in* fromAddr )
|
|
{
|
|
socket_t* p = _handleToPtr(h);
|
|
rc_t rc = kOkRC;
|
|
ssize_t retVal = 0;
|
|
socklen_t sizeOfRemoteAddr = fromAddr==NULL ? 0 : sizeof(struct sockaddr_in);
|
|
|
|
errno = 0;
|
|
|
|
if( recvByteCntRef != NULL )
|
|
*recvByteCntRef = 0;
|
|
|
|
int fd = p->fdH != cwSOCKET_NULL_SOCK ? p->fdH : p->sockH;
|
|
|
|
if((retVal = recvfrom(fd, data, dataByteCnt, 0, (struct sockaddr*)fromAddr, &sizeOfRemoteAddr )) == cwSOCKET_SYS_ERR )
|
|
{
|
|
switch( errno )
|
|
{
|
|
case EAGAIN:
|
|
return kTimeOutRC;
|
|
|
|
case ENOTCONN:
|
|
if( cwIsFlag(p->flags,kIsConnectedFl ) )
|
|
cwLogWarning("Socket Disconnected.");
|
|
|
|
p->flags = cwClrFlag(p->flags,kIsConnectedFl);
|
|
}
|
|
|
|
return cwLogSysError(kOpFailRC,errno,"recvfrom() failed.");
|
|
}
|
|
|
|
if( recvByteCntRef != NULL )
|
|
*recvByteCntRef = retVal;
|
|
|
|
return rc;
|
|
}
|
|
|
|
cw::rc_t cw::net::socket::select_receive(handle_t h, char* buf, unsigned bufByteCnt, unsigned timeOutMs, unsigned* recvByteCntRef, struct sockaddr_in* fromAddr )
|
|
{
|
|
rc_t rc = kOkRC;
|
|
socket_t* p = _handleToPtr(h);
|
|
fd_set rdSet;
|
|
struct timeval timeOut;
|
|
|
|
int fd = p->fdH != cwSOCKET_NULL_SOCK ? p->fdH : p->sockH;
|
|
|
|
// setup the select() call
|
|
FD_ZERO(&rdSet);
|
|
FD_SET(fd, &rdSet );
|
|
|
|
timeOut.tv_sec = timeOutMs/1000;
|
|
timeOut.tv_usec = (timeOutMs - (timeOut.tv_sec * 1000)) * 1000;
|
|
|
|
if( recvByteCntRef != nullptr )
|
|
*recvByteCntRef = 0;
|
|
|
|
// NOTE; select() takes the highest socket value plus one of all the sockets in all the sets.
|
|
|
|
switch( select(fd+1,&rdSet,NULL,NULL,&timeOut) )
|
|
{
|
|
case -1: // error
|
|
if( errno != EINTR )
|
|
cwLogSysError(kOpFailRC,errno,"Select failed.");
|
|
break;
|
|
|
|
case 0: // select() timed out
|
|
rc = kTimeOutRC;
|
|
break;
|
|
|
|
case 1: // (> 0) count of ready descripters
|
|
if( FD_ISSET(fd,&rdSet) )
|
|
{
|
|
socklen_t addrByteCnt = fromAddr==nullptr ? 0 : sizeof(*fromAddr);
|
|
ssize_t retByteCnt;
|
|
|
|
errno = 0;
|
|
|
|
// recv the incoming msg into buf[]
|
|
if(( retByteCnt = recvfrom( fd, buf, bufByteCnt, 0, (struct sockaddr*)fromAddr, &addrByteCnt )) == cwSOCKET_SYS_ERR )
|
|
{
|
|
switch( errno )
|
|
{
|
|
case ECONNRESET:
|
|
if( cwIsFlag(p->flags,kIsConnectedFl) )
|
|
cwLogWarning("Socket Disconnected.");
|
|
p->flags = cwClrFlag(p->flags,kIsConnectedFl);
|
|
|
|
}
|
|
|
|
rc = cwLogSysError(kOpFailRC,errno,"recvfrom() failed.");
|
|
|
|
}
|
|
else
|
|
{
|
|
// check for overflow
|
|
if( retByteCnt == (ssize_t)bufByteCnt )
|
|
rc = cwLogError(kBufTooSmallRC,"The receive buffer requires more than %i bytes.",bufByteCnt);
|
|
|
|
if( recvByteCntRef != nullptr )
|
|
*recvByteCntRef = retByteCnt;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
{ cwAssert(0); }
|
|
} // switch
|
|
|
|
return rc;
|
|
}
|
|
|
|
cw::rc_t cw::net::socket::recv_from(handle_t h, char* buf, unsigned bufByteCnt, unsigned* recvByteCntRef, struct sockaddr_in* fromAddr )
|
|
{
|
|
rc_t rc = kOkRC;
|
|
socket_t* p = _handleToPtr(h);
|
|
socklen_t addrlen = 0;
|
|
int bytesN = 0;
|
|
|
|
if( recvByteCntRef != nullptr )
|
|
*recvByteCntRef = 0;
|
|
|
|
if( fromAddr != nullptr )
|
|
{
|
|
addrlen = sizeof(*fromAddr);
|
|
memset(fromAddr,0,sizeof(*fromAddr));
|
|
}
|
|
|
|
int fd = p->fdH != cwSOCKET_NULL_SOCK ? p->fdH : p->sockH;
|
|
|
|
if((bytesN = recvfrom(fd, buf, bufByteCnt, 0, (struct sockaddr*)fromAddr, &addrlen)) < 0 )
|
|
{
|
|
// if this is a non-blocking socket then return value -1 indicates that no data is available.
|
|
if( cwIsNotFlag( p->flags, kBlockingFl) && bytesN == -1)
|
|
bytesN = 0;
|
|
else
|
|
{
|
|
rc = cwLogSysError(kReadFailRC,errno,"recvfrom() failed.");
|
|
goto errLabel;
|
|
}
|
|
}
|
|
|
|
if( recvByteCntRef != nullptr )
|
|
*recvByteCntRef = bytesN;
|
|
|
|
errLabel:
|
|
return rc;
|
|
}
|
|
|
|
cw::rc_t cw::net::socket::get_mac( handle_t h, unsigned char outBuf[6], struct sockaddr_in* addr, const char* netInterfaceName )
|
|
{
|
|
socket_t* p = _handleToPtr(h);
|
|
return _get_info(p->sockH, outBuf, addr, netInterfaceName );
|
|
}
|
|
|
|
cw::rc_t cw::net::socket::initAddr( const char* addrStr, portNumber_t portNumber, struct sockaddr_in* retAddrPtr )
|
|
{
|
|
return _initAddr(addrStr,portNumber,retAddrPtr);
|
|
}
|
|
|
|
cw::rc_t cw::net::socket::addrToString( const struct sockaddr_in* addr, char* buf, unsigned bufN )
|
|
{
|
|
rc_t rc = kOkRC;
|
|
|
|
errno = 0;
|
|
|
|
if( inet_ntop(AF_INET, &(addr->sin_addr), buf, bufN) == NULL)
|
|
{
|
|
rc = cwLogSysError(kOpFailRC,errno, "Network address to string conversion failed." );
|
|
goto errLabel;
|
|
}
|
|
|
|
buf[bufN-1]=0;
|
|
errLabel:
|
|
return rc;
|
|
}
|
|
|
|
bool cw::net::socket::addrIsEqual( const struct sockaddr_in* a0, const struct sockaddr_in* a1 )
|
|
{
|
|
return a0->sin_family == a1->sin_family
|
|
&& a0->sin_port == a1->sin_port
|
|
&& memcmp(&a0->sin_addr,&a1->sin_addr,sizeof(a0->sin_addr))==0;
|
|
}
|
|
|
|
const char* cw::net::socket::hostName( handle_t h )
|
|
{
|
|
socket_t* p = _handleToPtr(h);
|
|
|
|
errno = 0;
|
|
|
|
if( gethostname(p->hnameBuf,HOST_NAME_MAX) != 0 )
|
|
{
|
|
cwLogSysError(kOpFailRC,errno, "gethostname() failed." );
|
|
return NULL;
|
|
}
|
|
|
|
p->hnameBuf[HOST_NAME_MAX] = 0;
|
|
return p->hnameBuf;
|
|
}
|
|
|
|
const char* cw::net::socket::ipAddress( handle_t h )
|
|
{
|
|
socket_t* p = _handleToPtr(h);
|
|
return p->ntopBuf;
|
|
}
|
|
|
|
unsigned cw::net::socket::inetAddress( handle_t h )
|
|
{
|
|
socket_t* p = _handleToPtr(h);
|
|
|
|
return p->sockaddr.sin_addr.s_addr;
|
|
}
|
|
|
|
cw::net::socket::portNumber_t cw::net::socket::port( handle_t h )
|
|
{
|
|
socket_t* p = _handleToPtr(h);
|
|
return ntohs(p->sockaddr.sin_port);
|
|
}
|
|
|
|
cw::rc_t cw::net::socket::peername( handle_t h, struct sockaddr_in* addr )
|
|
{
|
|
rc_t rc = kOkRC;
|
|
socklen_t n = sizeof(struct sockaddr_in);
|
|
socket_t* p = _handleToPtr(h);
|
|
|
|
if( getpeername(p->sockH, (struct sockaddr*)addr, &n) == cwSOCKET_SYS_ERR )
|
|
return cwLogSysError(kOpFailRC,errno,"Get peer name failed.");
|
|
|
|
addr->sin_port = ntohs(addr->sin_port);
|
|
|
|
return rc;
|
|
}
|
|
|
|
cw::rc_t cw::net::socket::get_info( const char* netInterfaceName, unsigned char mac[6], char* host, unsigned hostN, struct sockaddr_in* addr )
|
|
{
|
|
rc_t rc = kOkRC;
|
|
int sockH;
|
|
|
|
if( host != nullptr )
|
|
if( gethostname(host,hostN) != 0 )
|
|
return cwLogSysError(kOpFailRC,errno,"Unable to get the local host name.");
|
|
|
|
// get a handle to the socket
|
|
if(( sockH = ::socket( AF_INET, SOCK_DGRAM, 0 ) ) == cwSOCKET_SYS_ERR )
|
|
return cwLogSysError(kOpFailRC,errno,"Unable to create temporary socket.");
|
|
|
|
if((rc = _get_info(sockH,mac,addr,netInterfaceName)) != kOkRC )
|
|
goto errLabel;
|
|
|
|
errLabel:
|
|
close(sockH);
|
|
return rc;
|
|
}
|