/*
* Copyright (C) 2012 Yee Young Han (http://blog.naver.com/websearch)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "SipPlatformDefine.h"
#include
#include "SipUdp.h"
#include "Log.h"
#ifndef WIN32
#include
#include
#endif
#include "MemoryDebug.h"
/**
* @ingroup SipPlatform
* @brief UDP ¼ÒÄÏÀ» »ý¼ºÇÑ´Ù.
* @param bIpv6 IPv6 ¼ÒÄÏÀ» »ý¼ºÇÒ °ÍÀΰ¡?
* @return ¼º°øÇϸé socket handle À» ¸®ÅÏÇÑ´Ù. ±×·¸Áö ¾ÊÀ¸¸é INVALID_SOCKET ¸¦ ¸®ÅÏÇÑ´Ù.
*/
Socket UdpSocket( bool bIpv6 )
{
Socket iFd;
iFd = socket( bIpv6 ? AF_INET6 : AF_INET, SOCK_DGRAM, IPPROTO_UDP );
if( iFd == INVALID_SOCKET )
{
return INVALID_SOCKET;
}
return iFd;
}
/**
* @ingroup SipPlatform
* @brief UDP listen ¼ÒÄÏÀ» »ý¼ºÇÑ´Ù.
* @param iPort UDP Æ÷Æ®
* @param pszIp UDP IP ÁÖ¼Ò. NULL À» ÀÔ·ÂÇϸé any ip ÁÖ¼Ò¸¦ »ç¿ëÇÑ´Ù.
* @param bIpv6 IPv6 ¼ÒÄÏÀ» »ý¼ºÇÒ °ÍÀΰ¡?
* @return ¼º°øÇϸé socket handle À» ¸®ÅÏÇÑ´Ù. ±×·¸Áö ¾ÊÀ¸¸é INVALID_SOCKET ¸¦ ¸®ÅÏÇÑ´Ù.
*/
Socket UdpListen( unsigned short iPort, const char * pszIp, bool bIpv6 )
{
if( iPort == 0 )
{
return INVALID_SOCKET;
}
Socket iFd;
int n;
iFd = socket( bIpv6 ? AF_INET6 : AF_INET, SOCK_DGRAM, IPPROTO_UDP );
if( iFd == INVALID_SOCKET )
{
return INVALID_SOCKET;
}
#ifndef WINXP
if( bIpv6 )
{
struct sockaddr_in6 addr;
memset((char*) &(addr),0, sizeof((addr)));
addr.sin6_family = AF_INET6;
addr.sin6_port = htons(iPort);
if( pszIp )
{
inet_pton( AF_INET6, pszIp, &addr.sin6_addr );
}
else
{
addr.sin6_addr = in6addr_any;
}
n = bind( iFd,(struct sockaddr*)&addr, sizeof(addr));
}
else
#endif
{
struct sockaddr_in addr;
memset((char*) &(addr),0, sizeof((addr)));
addr.sin_family = AF_INET;
addr.sin_port = htons(iPort);
if( pszIp )
{
#ifdef WINXP
addr.sin_addr.s_addr = inet_addr(pszIp);
#else
inet_pton( AF_INET, pszIp, &addr.sin_addr.s_addr );
#endif
}
else
{
addr.sin_addr.s_addr = htonl(INADDR_ANY);
}
n = bind( iFd,(struct sockaddr*)&addr, sizeof(addr));
}
if( n != 0 )
{
closesocket( iFd );
return INVALID_SOCKET;
}
return iFd;
}
/**
* @ingroup SipPlatform
* @brief UDP ¸Þ½ÃÁö¸¦ ¼ö½ÅÇÑ´Ù.
* @param iFd ¼ÒÄÏ ÇÚµé
* @param pszBuf ¼ö½Å ¹öÆÛ
* @param piLen ¼ö½Å ÆÐŶ Å©±â¸¦ ÀúÀåÇÒ º¯¼ö
* @param pszIp IP ÁÖ¼Ò
* @param iIpSize IP ÁÖ¼Ò º¯¼ö Å©±â
* @param piPort Æ÷Æ® ¹øÈ£
* @param bIpv6 IPv6 ¼ÒÄÏÀΰ¡?
* @returns ¼º°øÇϸé true ¸¦ ¸®ÅÏÇÏ°í ½ÇÆÐÇϸé false ¸¦ ¸®ÅÏÇÑ´Ù.
*/
bool UdpRecv( Socket iFd, char * pszBuf, int * piLen, char * pszIp, int iIpSize, unsigned short* piPort, bool bIpv6 )
{
if( iFd == INVALID_SOCKET ) return false;
int iBufSize = *piLen;
if( iBufSize <= 0 ) return false;
#ifndef WINXP
if( bIpv6 )
{
struct sockaddr_in6 sttAddr;
int iAddrSize = sizeof(sttAddr);
*piLen = recvfrom( iFd, pszBuf, iBufSize, 0, (struct sockaddr *)&sttAddr, (socklen_t*)&iAddrSize );
if( *piLen <= 0 )
{
return false;
}
if( piPort ) *piPort = ntohs( sttAddr.sin6_port );
if( pszIp )
{
inet_ntop( AF_INET6, &sttAddr.sin6_addr, pszIp, iIpSize );
}
}
else
#endif
{
struct sockaddr_in sttAddr;
int iAddrSize = sizeof(sttAddr);
*piLen = recvfrom( iFd, pszBuf, iBufSize, 0, (struct sockaddr *)&sttAddr, (socklen_t*)&iAddrSize );
if( *piLen <= 0 )
{
return false;
}
if( piPort ) *piPort = ntohs( sttAddr.sin_port );
if( pszIp )
{
#ifdef WINXP
snprintf( pszIp, iIpSize, "%s", inet_ntoa( sttAddr.sin_addr ) );
#else
inet_ntop( AF_INET, &sttAddr.sin_addr, pszIp, iIpSize );
#endif
}
}
if( (*piLen)+1 >= iBufSize )
{
return false;
}
pszBuf[*piLen] = 0;
return true;
}
/**
* @ingroup SipPlatform
* @brief IPv4 ·Î UDP ¸Þ½ÃÁö¸¦ ¼ö½ÅÇÑ´Ù.
* @param iFd ¼ÒÄÏ ÇÚµé
* @param pszBuf ¼ö½Å ¹öÆÛ
* @param piLen ¼ö½Å ÆÐŶ Å©±â
* @param piIp IP ÁÖ¼Ò
* @param piPort Æ÷Æ® ¹øÈ£
* @returns ¼º°øÇϸé true ¸¦ ¸®ÅÏÇÏ°í ½ÇÆÐÇϸé false ¸¦ ¸®ÅÏÇÑ´Ù.
*/
bool UdpRecv( Socket iFd, char * pszBuf, int * piLen, unsigned int * piIp, unsigned short* piPort )
{
if( iFd == INVALID_SOCKET ) return false;
int iBufSize = *piLen;
if( iBufSize <= 0 ) return false;
struct sockaddr_in sttAddr;
int iAddrSize = sizeof(sttAddr);
*piLen = recvfrom( iFd, pszBuf, iBufSize-1, 0, (struct sockaddr *)&sttAddr, (socklen_t*)&iAddrSize );
if( *piLen <= 0 )
{
return false;
}
if( piPort ) *piPort = sttAddr.sin_port;
if( piIp ) *piIp = sttAddr.sin_addr.s_addr;
if( (*piLen)+1 > iBufSize )
{
return false;
}
pszBuf[*piLen] = 0;
return true;
}
/**
* @ingroup SipPlatform
* @brief IPv6 ·Î UDP ¸Þ½ÃÁö¸¦ ¼ö½ÅÇÑ´Ù.
* @param iFd ¼ÒÄÏ ÇÚµé
* @param pszBuf ¼ö½Å ¹öÆÛ
* @param piLen ¼ö½Å ÆÐŶ Å©±â
* @param psttIp IP ÁÖ¼Ò
* @param piPort Æ÷Æ® ¹øÈ£
* @returns ¼º°øÇϸé true ¸¦ ¸®ÅÏÇÏ°í ½ÇÆÐÇϸé false ¸¦ ¸®ÅÏÇÑ´Ù.
*/
bool UdpRecv( Socket iFd, char * pszBuf, int * piLen, IN6_ADDR * psttIp, unsigned short* piPort )
{
if( iFd == INVALID_SOCKET ) return false;
int iBufSize = *piLen;
if( iBufSize <= 0 ) return false;
struct sockaddr_in6 sttAddr;
int iAddrSize = sizeof(sttAddr);
*piLen = recvfrom( iFd, pszBuf, iBufSize-1, 0, (struct sockaddr *)&sttAddr, (socklen_t*)&iAddrSize );
if( *piLen <= 0 )
{
return false;
}
if( piPort ) *piPort = sttAddr.sin6_port;
if( psttIp ) memcpy( psttIp, &sttAddr.sin6_addr, sizeof(IN6_ADDR) );
if( (*piLen)+1 > iBufSize )
{
return false;
}
pszBuf[*piLen] = 0;
return true;
}
/**
* @ingroup SipPlatform
* @brief UDP ¸Þ½ÃÁö¸¦ Àü¼ÛÇÑ´Ù.
* @param iFd ¼ÒĹ ÇÚµé
* @param pszBuf Àü¼Û ¹öÆÛ
* @param iBufLen Àü¼Û ¹öÆÛ ±æÀÌ
* @param pszIp ¸ñÀûÁö IP ÁÖ¼Ò
* @param iPort ¸ñÀûÁö Æ÷Æ® ¹øÈ£
* @returns ¼º°øÇϸé true ¸¦ ¸®ÅÏÇÏ°í ½ÇÆÐÇϸé false ¸¦ ¸®ÅÏÇÑ´Ù.
*/
bool UdpSend( Socket iFd, const char * pszBuf, int iBufLen, const char * pszIp, unsigned short iPort )
{
if( iFd == INVALID_SOCKET || pszBuf == NULL || iBufLen <= 0 || pszIp == NULL || iPort == 0 ) return false;
int n;
#ifndef WINXP
if( strstr( pszIp, ":" ) )
{
struct sockaddr_in6 sttAddr;
memset( &sttAddr, 0, sizeof(sttAddr) );
sttAddr.sin6_family = AF_INET6;
sttAddr.sin6_port = htons( iPort );
inet_pton( AF_INET6, pszIp, &sttAddr.sin6_addr );
n = sendto( iFd, pszBuf, iBufLen, 0, (sockaddr*)&sttAddr, sizeof(sttAddr) );
}
else
#endif
{
struct sockaddr_in sttAddr;
memset( &sttAddr, 0, sizeof(sttAddr) );
sttAddr.sin_family = AF_INET;
sttAddr.sin_port = htons( iPort );
#ifdef WINXP
sttAddr.sin_addr.s_addr = inet_addr( pszIp );
#else
inet_pton( AF_INET, pszIp, &sttAddr.sin_addr.s_addr );
#endif
n = sendto( iFd, pszBuf, iBufLen, 0, (sockaddr*)&sttAddr, sizeof(sttAddr) );
}
if( n != iBufLen )
{
CLog::Print( LOG_ERROR, "%s sendto error(%d)", __FUNCTION__, GetError() );
return false;
}
return true;
}
/**
* @ingroup SipPlatform
* @brief IPv4 ·Î UDP ¸Þ½ÃÁö¸¦ Àü¼ÛÇÑ´Ù.
* @param iFd ¼ÒĹ ÇÚµé
* @param pszBuf ¹ß½Å ¹öÆÛ
* @param iBufLen ¹ß½Å ¹öÆÛ ±æÀÌ
* @param iIp ¸ñÀûÁö IP ÁÖ¼Ò
* @param iPort ¸ñÀûÁö Æ÷Æ® ¹øÈ£
* @returns ¼º°øÇϸé true ¸¦ ¸®ÅÏÇÏ°í ½ÇÆÐÇϸé false ¸¦ ¸®ÅÏÇÑ´Ù.
*/
bool UdpSend( Socket iFd, const char * pszBuf, int iBufLen, unsigned int iIp, unsigned short iPort )
{
if( iFd == INVALID_SOCKET || pszBuf == NULL || iBufLen <= 0 || iPort == 0 ) return false;
struct sockaddr_in sttAddr;
memset( &sttAddr, 0, sizeof(sttAddr) );
sttAddr.sin_family = AF_INET;
sttAddr.sin_port = iPort;
sttAddr.sin_addr.s_addr = iIp;
if( sendto( iFd, pszBuf, iBufLen, 0,(sockaddr*)&sttAddr, sizeof(sttAddr) ) != iBufLen )
{
return false;
}
return true;
}
/**
* @ingroup SipPlatform
* @brief IPv6 ·Î UDP ¸Þ½ÃÁö¸¦ Àü¼ÛÇÑ´Ù.
* @param iFd ¼ÒĹ ÇÚµé
* @param pszBuf ¹ß½Å ¹öÆÛ
* @param iBufLen ¹ß½Å ¹öÆÛ ±æÀÌ
* @param psttIp ¸ñÀûÁö IP ÁÖ¼Ò
* @param iPort ¸ñÀûÁö Æ÷Æ® ¹øÈ£
* @returns ¼º°øÇϸé true ¸¦ ¸®ÅÏÇÏ°í ½ÇÆÐÇϸé false ¸¦ ¸®ÅÏÇÑ´Ù.
*/
bool UdpSend( Socket iFd, const char * pszBuf, int iBufLen, IN6_ADDR * psttIp, unsigned short iPort )
{
if( iFd == INVALID_SOCKET || pszBuf == NULL || iBufLen <= 0 || iPort == 0 ) return false;
struct sockaddr_in6 sttAddr;
memset( &sttAddr, 0, sizeof(sttAddr) );
sttAddr.sin6_family = AF_INET6;
sttAddr.sin6_port = iPort;
memcpy( &sttAddr.sin6_addr, psttIp, sizeof(sttAddr.sin6_addr) );
if( sendto( iFd, pszBuf, iBufLen, 0,(sockaddr*)&sttAddr, sizeof(sttAddr) ) != iBufLen )
{
return false;
}
return true;
}
/**
* @ingroup SipPlatform
* @brief ³×Æ®¿öÅ© API ¸¦ ÃʱâȽÃŲ´Ù.
*/
void InitNetwork()
{
#ifdef WIN32
static bool bInitNetwork = false;
if( bInitNetwork == false )
{
WORD wVersionRequested = MAKEWORD( 2, 2 );
WSADATA wsaData;
if( WSAStartup( wVersionRequested, &wsaData ) != 0 )
{
return;
}
bInitNetwork = true;
}
#endif
}
/**
* @brief pollfd ±¸Á¶Ã¼¿¡ ¼ö½ÅÇÒ ÇÚµéÀ» ÀúÀåÇÑ´Ù.
* @param sttPollFd pollfd ±¸Á¶Ã¼
* @param hSocket ¼ö½Å À̺¥Æ®¸¦ À§ÇÑ ¼ÒÄÏ
*/
void TcpSetPollIn( struct pollfd & sttPollFd, Socket hSocket )
{
sttPollFd.fd = hSocket;
sttPollFd.events = POLLIN;
sttPollFd.revents = 0;
}
#ifdef WIN32
/**
* @ingroup SipPlatform
* @brief À©µµ¿ì¿ë poll ¸Þ¼Òµå
* - ÇöÀç´Â read event ¸¸ ó¸®ÇÒ ¼ö ÀÖ´Ù.
*/
int poll( struct pollfd *fds, unsigned int nfds, int timeout )
{
fd_set rset;
unsigned int i;
int n, iCount = 0;
struct timeval sttTimeout;
sttTimeout.tv_sec = timeout / 1000;
sttTimeout.tv_usec = ( timeout % 1000 ) * 1000;
FD_ZERO(&rset);
for( i = 0; i < nfds; ++i )
{
if( fds[i].fd != -1 ) FD_SET( fds[i].fd, &rset );
}
n = select( 0, &rset, NULL, NULL, &sttTimeout );
if( n <= 0 )
{
return n;
}
for( i = 0; i < nfds; ++i )
{
if( FD_ISSET( fds[i].fd, &rset ) )
{
fds[i].revents = POLLIN;
++iCount;
}
else
{
fds[i].revents = 0;
}
}
return iCount;
}
#endif
/**
* @ingroup SipPlatform
* @brief localhost IP ÁÖ¼Ò¸¦ Á¦¿ÜÇÑ È£½ºÆ®¿¡ ¿¬°áµÈ IP ÁÖ¼Ò¸¦ °¡Á®¿Â´Ù.
* @param strIp IP ÁÖ¼Ò¸¦ ÀúÀåÇÒ º¯¼ö
* @return ¼º°øÇϸé true ¸¦ ¸®ÅÏÇÑ´Ù. ½ÇÆÐÇϸé false ¸¦ ¸®ÅÏÇÑ´Ù.
*/
bool GetLocalIp( std::string & strIp )
{
#ifdef WIN32
char szHostName[128], szIpAddr[INET6_ADDRSTRLEN];
struct sockaddr_in sttAddr;
struct hostent *psttHost = NULL;
InitNetwork();
memset( szHostName, 0, sizeof(szHostName) );
if( gethostname(szHostName, sizeof(szHostName)) ) return false;
psttHost = gethostbyname( szHostName );
if( !psttHost ) return false;
for( int i = 0; psttHost->h_addr_list[i]; i++ )
{
memcpy( &sttAddr.sin_addr, psttHost->h_addr_list[i], psttHost->h_length );
#ifdef WINXP
snprintf( szIpAddr, sizeof(szIpAddr), "%s", inet_ntoa(sttAddr.sin_addr) );
#else
inet_ntop( AF_INET, &sttAddr.sin_addr, szIpAddr, sizeof(szIpAddr) );
#endif
if( strcmp( szIpAddr, "127.0.0.1" ) )
{
strIp = szIpAddr;
break;
}
}
#else
struct ifconf ifc;
int hSocket = socket( AF_INET, SOCK_DGRAM, 0 );
int len = 100 * sizeof(struct ifreq);
char buf[ len ];
char szError[255];
ifc.ifc_len = len;
ifc.ifc_buf = buf;
int e = ioctl( hSocket, SIOCGIFCONF, &ifc );
if( e == -1 ) return false;
char *ptr = buf;
int tl = ifc.ifc_len;
char szIpAddr[INET6_ADDRSTRLEN];
while ( tl > 0 )
{
struct ifreq * ifr = (struct ifreq *)ptr;
int si;
#ifdef __APPLE__
si = sizeof(ifr->ifr_name) + sizeof(ifr->ifr_addr);
#else
si = sizeof(ifr->ifr_name) + sizeof(ifr->ifr_map);
#endif
tl -= si;
ptr += si;
struct ifreq ifr2;
ifr2 = *ifr;
e = ioctl( hSocket, SIOCGIFADDR, &ifr2 );
if( e == -1 )
{
printf( "ioctl error(%d) - %s\n", errno, strerror_r( errno, szError, sizeof(szError) ) );
continue;
}
struct sockaddr a = ifr2.ifr_addr;
struct sockaddr_in* addr = (struct sockaddr_in*) &a;
unsigned int ai = ntohl( addr->sin_addr.s_addr );
// 127.0.0.1 ÁÖ¼Ò´Â Ãâ·ÂÇÏÁö ¾Ê´Â´Ù.
if( int((ai>>24)&0xFF) == 127 ) continue;
snprintf( szIpAddr, sizeof(szIpAddr), "%d.%d.%d.%d", int((ai>>24)&0xFF)
, int((ai>>16)&0xFF)
, int((ai>> 8)&0xFF)
, int((ai )&0xFF) );
strIp = szIpAddr;
break;
}
close(hSocket);
#endif
return true;
}