1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144 |
- /*
- ** Copyright 2003-2009, Ernest Laurentin (http://www.ernzo.com/)
- **
- ** Licensed under the Apache License, Version 2.0 (the "License");
- ** you may not use this file except in compliance with the License.
- ** You may obtain a copy of the License at
- **
- ** http://www.apache.org/licenses/LICENSE-2.0
- **
- ** Unless required by applicable law or agreed to in writing, software
- ** distributed under the License is distributed on an "AS IS" BASIS,
- ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ** See the License for the specific language governing permissions and
- ** limitations under the License.
- **
- ** File: SocketHandle.cpp
- ** Version: 1.4 - IPv6 support
- ** 1.3 - Update for Asynchronous mode / Linux port
- ** 1.2 - Update interface for TCP remote connection
- ** 1.1 - Added multicast support
- */
- #include "stdafx.h"
- #ifdef WIN32
- #include <stdlib.h>
- #ifndef UNDER_CE
- #include <crtdbg.h>
- #endif
- #include <strsafe.h>
- #endif
- #include "SocketHandle.h"
- // Jeff.add.
- //#include "Wspiapi.h"
- //#include "Ws2tcpip.h"
- #ifndef BUFFER_SIZE
- #define BUFFER_SIZE 64*1024
- #endif
- #ifndef SOCKHANDLE_TTL
- #define SOCKHANDLE_TTL 5
- #endif
- #ifndef SOCKHANDLE_HOPS
- #define SOCKHANDLE_HOPS 10
- #endif
- #define HOSTNAME_SIZE MAX_PATH
- #define STRING_LENGTH 40
- #if !defined(PLATFORM_HAS_INETFUNC)
- const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt);
- int inet_pton(int af, const char *src, void *dst);
- #endif
- #ifdef WIN32
- #ifndef UNDER_CE
- #pragma comment(lib, "ws2_32.lib")
- #else
- #pragma comment(lib, "Ws2.lib")
- #endif
- #endif
- ///////////////////////////////////////////////////////////////////////////////
- // SockAddrIn Struct
- SockAddrIn SockAddrIn::NULLAddr;
- ///////////////////////////////////////////////////////////////////////////////
- // Constructs
- SockAddrIn::SockAddrIn()
- {
- Clear();
- }
- SockAddrIn::SockAddrIn(const SockAddrIn& sin)
- {
- Copy( sin );
- }
- SockAddrIn::~SockAddrIn()
- {
- }
- ///////////////////////////////////////////////////////////////////////////////
- // Clear
- void SockAddrIn::Clear()
- {
- memset(this, 0, sizeof(sockaddr_storage));
- }
- ///////////////////////////////////////////////////////////////////////////////
- // Copy
- SockAddrIn& SockAddrIn::Copy(const SockAddrIn& sin)
- {
- ss_family = sin.ss_family;
- memcpy(this, &sin, Size());
- return *this;
- }
- ///////////////////////////////////////////////////////////////////////////////
- // IsEqual
- bool SockAddrIn::IsEqual(const SockAddrIn& sin) const
- {
- // Is it Equal? - ignore 'sin_zero'
- if ( ss_family == AF_INET ) {
- return (memcmp(this, &sin, Size()-8) == 0);
- }
- return (memcmp(this, &sin, Size()) == 0);
- }
- ///////////////////////////////////////////////////////////////////////////////
- // CreateFrom
- bool SockAddrIn::CreateFrom(LPCTSTR pszAddr, LPCTSTR pszService, int nFamily /*=AF_INET*/)
- {
- Clear();
- CSocketHandle::GetAddressInfo(pszAddr, pszService, nFamily, *this);
- return !IsNull();
- }
- ///////////////////////////////////////////////////////////////////////////////
- // CreateFrom
- bool SockAddrIn::CreateFrom(ULONG lIPAddr, USHORT nPort, int nFamily /*= AF_INET*/, bool bFmtHost /*= true*/)
- {
- Clear();
- _ASSERTE( nFamily == AF_INET ); // supports IPv4 only
- SOCKADDR_IN* psin = reinterpret_cast<SOCKADDR_IN*>(this);
- psin->sin_family = static_cast<short>(nFamily);
- if ( bFmtHost )
- {
- psin->sin_addr.s_addr = htonl( lIPAddr );
- psin->sin_port = htons( nPort );
- }
- else
- {
- psin->sin_addr.s_addr = lIPAddr;
- psin->sin_port = nPort;
- }
- return !IsNull();
- }
- ///////////////////////////////////////////////////////////////////////////////
- // CSocketHandle
- CSocketHandle::CSocketHandle()
- : m_hSocket(INVALID_SOCKET)
- {
- m_npendingSize = 0;
- memset(m_szpendingbuf,0,SOCKET_BUFFSIZE);
- }
- CSocketHandle::~CSocketHandle()
- {
- Close();
- }
- ///////////////////////////////////////////////////////////////////////////////
- // IsOpen
- bool CSocketHandle::IsOpen() const
- {
- return ( INVALID_SOCKET != m_hSocket );
- }
- ///////////////////////////////////////////////////////////////////////////////
- // GetSocket
- SOCKET CSocketHandle::GetSocket() const
- {
- return m_hSocket;
- }
- ///////////////////////////////////////////////////////////////////////////////
- // GetSocketType
- int CSocketHandle::GetSocketType() const
- {
- int type = -1;
- if ( INVALID_SOCKET != m_hSocket ) {
- socklen_t optlen = sizeof(int);
- if ( getsockopt(GetSocket(), SOL_SOCKET, SO_TYPE, reinterpret_cast<char*>(&type),
- &optlen) == SOCKET_ERROR)
- {
- SetLastError( WSAGetLastError() );
- }
- }
- return type;
- }
- ///////////////////////////////////////////////////////////////////////////////
- // Attach
- bool CSocketHandle::Attach(SOCKET sock)
- {
- if ( INVALID_SOCKET == m_hSocket )
- {
- m_hSocket = sock;
- return true;
- }
- return false;
- }
- ///////////////////////////////////////////////////////////////////////////////
- // Detach
- SOCKET CSocketHandle::Detach()
- {
- SOCKET sock = m_hSocket;
- ::InterlockedExchange(reinterpret_cast<long*>(&m_hSocket), INVALID_SOCKET);
- return sock;
- }
- ///////////////////////////////////////////////////////////////////////////////
- // GetSockName
- bool CSocketHandle::GetSockName(SockAddrIn& saddr_in) const
- {
- _ASSERTE( IsOpen() );
- if (IsOpen()) {
- socklen_t namelen = (socklen_t)saddr_in.Size();
- if (SOCKET_ERROR != getsockname(GetSocket(), saddr_in, &namelen))
- {
- return true;
- }
- SetLastError( WSAGetLastError() );
- }
- return false;
- }
- ///////////////////////////////////////////////////////////////////////////////
- // GetPeerName
- bool CSocketHandle::GetPeerName(SockAddrIn& saddr_in) const
- {
- _ASSERTE( IsOpen() );
- if (IsOpen()) {
- socklen_t namelen = (socklen_t)saddr_in.Size();
- if (SOCKET_ERROR != getpeername(GetSocket(), saddr_in, &namelen))
- {
- return true;
- }
- SetLastError( WSAGetLastError() );
- }
- return false;
- }
- ///////////////////////////////////////////////////////////////////////////////
- // Close
- void CSocketHandle::Close()
- {
- if ( IsOpen() )
- {
- ShutdownConnection(static_cast<SOCKET>(
- ::InterlockedExchange((LONG*)&m_hSocket, INVALID_SOCKET)
- ));
- }
- }
- ///////////////////////////////////////////////////////////////////////////////
- // AddMembership
- bool CSocketHandle::AddMembership(LPCTSTR pszIPAddr, LPCTSTR pszNIC)
- {
- _ASSERTE( IsOpen() );
- if ( IsOpen() )
- {
- int nType = 0;
- socklen_t nOptLen = sizeof(int);
- if ( SOCKET_ERROR != getsockopt(m_hSocket, SOL_SOCKET, SO_TYPE, (char*)&nType, &nOptLen))
- {
- if ( nType == SOCK_DGRAM )
- {
- // Setup interface for multicast traffic
- SockAddrIn mcastAddr;
- if (GetAddressInfo(pszIPAddr, NULL, AF_UNSPEC, mcastAddr))
- {
- SockAddrIn interfAddr;
- GetAddressInfo(pszNIC, NULL, mcastAddr.ss_family, interfAddr);
- if ( mcastAddr.ss_family == AF_INET )
- {
- int nTTL = SOCKHANDLE_TTL;
- if ( SOCKET_ERROR != setsockopt(m_hSocket, IPPROTO_IP, IP_MULTICAST_TTL, (const char*)&nTTL, sizeof(nTTL)))
- {
- ULONG ulNIC = interfAddr.GetIPAddr();
- if ( SOCKET_ERROR != setsockopt(m_hSocket, IPPROTO_IP, IP_MULTICAST_IF,(char *) &ulNIC, sizeof(ulNIC)))
- {
- ip_mreq mreq = { 0 };
- mreq.imr_multiaddr.s_addr = mcastAddr.GetIPAddr();
- mreq.imr_interface.s_addr = ulNIC;
- if ( SOCKET_ERROR != setsockopt(m_hSocket, IPPROTO_IP, IP_ADD_MEMBERSHIP, (const char*)&mreq, sizeof(mreq)))
- {
- return true;
- }
- }
- }
- }
- else if ( mcastAddr.ss_family == AF_INET6 )
- {
- int nTTL = SOCKHANDLE_HOPS;
- if ( SOCKET_ERROR != setsockopt(m_hSocket, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (const char*)&nTTL, sizeof(nTTL)))
- {
- ipv6_mreq mreq6 = { 0 };
- IN6_ADDR mcin6 = ((sockaddr_in6*)&mcastAddr)->sin6_addr;
- memcpy(&(mreq6.ipv6mr_multiaddr), &mcin6, sizeof(IN6_ADDR));
- if ( SOCKET_ERROR != setsockopt(m_hSocket, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (const char*)&mreq6, sizeof(mreq6)))
- {
- return true;
- }
- }
- }
- else
- {
- // invalid socket option
- WSASetLastError(WSAENOPROTOOPT);
- }
- }
- }
- else
- {
- // invalid socket option
- WSASetLastError(WSAENOPROTOOPT);
- }
- }
- SetLastError( WSAGetLastError() );
- }
- return false;
- }
- ///////////////////////////////////////////////////////////////////////////////
- // DropMembership
- bool CSocketHandle::DropMembership(LPCTSTR pszIPAddr, LPCTSTR pszNIC)
- {
- _ASSERTE( IsOpen() );
- if ( IsOpen() )
- {
- int nType = 0;
- socklen_t nOptLen = sizeof(int);
- if ( SOCKET_ERROR != getsockopt(m_hSocket, SOL_SOCKET, SO_TYPE, (char*)&nType, &nOptLen))
- {
- if ( nType == SOCK_DGRAM )
- {
- SockAddrIn mcastAddr;
- if (GetAddressInfo(pszIPAddr, NULL, AF_UNSPEC, mcastAddr))
- {
- SockAddrIn interfAddr;
- GetAddressInfo(pszNIC, NULL, mcastAddr.ss_family, interfAddr);
- if ( mcastAddr.ss_family == AF_INET )
- {
- ip_mreq mreq;
- mreq.imr_multiaddr.s_addr = mcastAddr.GetIPAddr();
- mreq.imr_interface.s_addr = interfAddr.GetIPAddr();;
- if ( SOCKET_ERROR != setsockopt(m_hSocket, IPPROTO_IP, IP_DROP_MEMBERSHIP, (const char*)&mreq, sizeof(mreq)))
- {
- return true;
- }
- }
- else if ( mcastAddr.ss_family == AF_INET6 )
- {
- ipv6_mreq mreq6 = { 0 };
- IN6_ADDR mcin6 = ((sockaddr_in6*)&mcastAddr)->sin6_addr;
- memcpy(&(mreq6.ipv6mr_multiaddr), &mcin6, sizeof(IN6_ADDR));
- if ( SOCKET_ERROR != setsockopt(m_hSocket, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, (const char*)&mreq6, sizeof(mreq6)))
- {
- return true;
- }
- }
- else
- {
- // invalid socket option
- WSASetLastError(WSAENOPROTOOPT);
- }
- }
- }
- else
- {
- // invalid socket option
- WSASetLastError(WSAENOPROTOOPT);
- }
- }
- SetLastError( WSAGetLastError() );
- }
- return false;
- }
- ///////////////////////////////////////////////////////////////////////////////
- // CreateSocket
- bool CSocketHandle::CreateSocket(LPCTSTR pszHostName, LPCTSTR pszServiceName,
- int nFamily, int nType, UINT uOptions /* = 0 */)
- {
- // Socket is already opened
- if ( IsOpen() ) {
- SetLastError(ERROR_ACCESS_DENIED);
- return false;
- }
- // Create a Socket that is bound to a specific service provider
- // nFamily: (AF_INET, AF_INET6)
- // nType: (SOCK_STREAM, SOCK_DGRAM)
- #ifdef SOCKHANDLE_USE_OVERLAPPED
- SOCKET sock = WSASocket(nFamily, nType, IPPROTO_IP, NULL, 0, WSA_FLAG_OVERLAPPED);
- #else
- SOCKET sock = socket(nFamily, nType, IPPROTO_IP);
- #endif
- if (INVALID_SOCKET != sock)
- {
- if (uOptions & SO_REUSEADDR)
- {
- // Inform Windows Sockets provider that a bind on a socket should not be disallowed
- // because the desired address is already in use by another socket
- BOOL optval = TRUE;
- if ( SOCKET_ERROR == setsockopt( sock, SOL_SOCKET, SO_REUSEADDR, (char *) &optval, sizeof( BOOL ) ) )
- {
- SetLastError( WSAGetLastError() );
- closesocket( sock );
- return false;
- }
- }
- if (nType == SOCK_DGRAM)
- {
- if ((uOptions & SO_BROADCAST) && (nFamily == AF_INET))
- {
- // Inform Windows Sockets provider that broadcast messages are allowed
- BOOL optval = TRUE;
- if ( SOCKET_ERROR == setsockopt( sock, SOL_SOCKET, SO_BROADCAST, (char *) &optval, sizeof( BOOL ) ) )
- {
- SetLastError( WSAGetLastError() );
- closesocket( sock );
- return false;
- }
- }
- #ifdef SOCKHANDLE_CONFIGBUF
- // configure buffer size
- socklen_t rcvbuf = BUFFER_SIZE;
- if ( SOCKET_ERROR == setsockopt( sock, SOL_SOCKET, SO_RCVBUF, (char *) &rcvbuf, sizeof( int ) ) )
- {
- SetLastError( WSAGetLastError() );
- closesocket( sock );
- return false;
- }
- #endif
- }
- // Associate a local address with the socket
- SockAddrIn sockAddr;
- sockAddr.CreateFrom(pszHostName, pszServiceName, nFamily);
- if ( SOCKET_ERROR == bind(sock, sockAddr, (int)sockAddr.Size()))
- {
- SetLastError( WSAGetLastError() );
- closesocket( sock );
- return false;
- }
- // Listen to the socket, only valid for connection socket (TCP)
- if (SOCK_STREAM == nType)
- {
- if ( SOCKET_ERROR == listen(sock, SOMAXCONN))
- {
- SetLastError( WSAGetLastError() );
- closesocket( sock );
- return false;
- }
- }
- // Success, now we may save this socket
- m_hSocket = sock;
- }
- return (INVALID_SOCKET != sock);
- }
- ///////////////////////////////////////////////////////////////////////////////
- // ConnectTo
- bool CSocketHandle::ConnectTo(LPCTSTR pszHostName, LPCTSTR pszRemote,
- LPCTSTR pszServiceName, int nFamily, int nType)
- {
- // Socket is already opened
- if ( IsOpen() ) {
- SetLastError(ERROR_ACCESS_DENIED);
- return false;
- }
- // Create a Socket that is bound to a specific service provider
- // nFamily: (AF_INET, AF_INET6)
- // nType: (SOCK_STREAM, SOCK_DGRAM)
- #ifdef SOCKHANDLE_USE_OVERLAPPED
- SOCKET sock = WSASocket(nFamily, nType, IPPROTO_IP, NULL, 0, WSA_FLAG_OVERLAPPED);
- #else
- SOCKET sock = socket(nFamily, nType, IPPROTO_IP);
- #endif
- if (INVALID_SOCKET != sock)
- {
- // Associate a local address with the socket but let provider assign a port number
- SockAddrIn sockAddr;
- if (false == sockAddr.CreateFrom(pszHostName, TEXT("0"), nFamily))
- {
- SetLastError( WSAGetLastError() );
- closesocket( sock );
- return false;
- }
- if ( SOCKET_ERROR == bind(sock, sockAddr, (int)sockAddr.Size()))
- {
- SetLastError( WSAGetLastError() );
- closesocket( sock );
- return false;
- }
- #ifdef SOCKHANDLE_CONFIGBUF
- if (nType == SOCK_DGRAM)
- {
- // configure buffer size
- socklen_t rcvbuf = BUFFER_SIZE;
- if ( SOCKET_ERROR == setsockopt( sock, SOL_SOCKET, SO_RCVBUF, (char *) &rcvbuf, sizeof( int ) ) )
- {
- SetLastError( WSAGetLastError() );
- closesocket( sock );
- return false;
- }
- }
- #endif
- // Now get destination address & port
- sockAddr.CreateFrom( pszRemote, pszServiceName, nFamily );
- // try to connect - if fail, server not ready
- if (SOCKET_ERROR == connect( sock, sockAddr, (int)sockAddr.Size()))
- {
- SetLastError( WSAGetLastError() );
- closesocket( sock );
- return false;
- }
- // Success, now we may save this socket
- m_hSocket = sock;
- }
- return (INVALID_SOCKET != sock);
- }
- ///////////////////////////////////////////////////////////////////////////////
- // Read
- DWORD CSocketHandle::Read(LPBYTE lpBuffer, DWORD dwSize, LPSOCKADDR lpAddrIn,
- DWORD dwTimeout)
- {
- _ASSERTE( IsOpen() );
- _ASSERTE( lpBuffer != NULL );
- if (!IsOpen() || lpBuffer == NULL || dwSize < 1L)
- return (DWORD)-1L;
- fd_set fdRead = { 0 };
- TIMEVAL stTime;
- TIMEVAL *pstTime = NULL;
- if ( INFINITE != dwTimeout ) {
- stTime.tv_sec = dwTimeout/1000;
- stTime.tv_usec = (dwTimeout%1000)*1000;
- pstTime = &stTime;
- }
- SOCKET s = GetSocket();
- // Set Descriptor
- FD_SET( s, &fdRead );
- // Select function set read timeout
- DWORD dwBytesRead = 0L;
- int res = 1;
- if ( pstTime != NULL )
- res = select((int)s, &fdRead, NULL, NULL, pstTime );
- if ( res > 0)
- {
- if (lpAddrIn)
- {
- // UDP
- socklen_t fromlen = sizeof(SOCKADDR_STORAGE);
- res = recvfrom(s, reinterpret_cast<LPSTR>(lpBuffer), dwSize, 0, lpAddrIn, &fromlen);
- }
- else
- {
- // TCP
- res = recv(s, reinterpret_cast<LPSTR>(lpBuffer), dwSize, 0);
- }
- if ( res == 0 ) {
- WSASetLastError(WSAECONNRESET);
- res = SOCKET_ERROR;
- }
- }
- if ( res == SOCKET_ERROR )
- {
- SetLastError( WSAGetLastError() );
- }
- dwBytesRead = (DWORD)((res >= 0)?(res) : (-1));
- return dwBytesRead;
- }
- #ifdef WIN32
- ///////////////////////////////////////////////////////////////////////////////
- // ReadEx
- DWORD CSocketHandle::ReadEx(LPBYTE lpBuffer, DWORD dwSize, LPSOCKADDR lpAddrIn,
- LPWSAOVERLAPPED lpOverlapped, LPWSACOMPLETIONROUTINE lpCompletionRoutine)
- {
- _ASSERTE( IsOpen() );
- _ASSERTE( lpBuffer != NULL );
- if (!IsOpen() || lpBuffer == NULL || dwSize < 1L)
- return (DWORD)-1L;
- SOCKET s = GetSocket();
- // Send message to peer
- WSABUF wsabuf;
- wsabuf.buf = (char FAR*)lpBuffer;
- wsabuf.len = dwSize;
- // Select function set read timeout
- DWORD dwBytesRead = 0L;
- DWORD dwFlags = 0L;
- int res = 0;
- if (lpAddrIn)
- {
- // UDP
- socklen_t fromlen = sizeof(SOCKADDR_STORAGE);
- res = WSARecvFrom( s, &wsabuf, 1, &dwBytesRead, &dwFlags, lpAddrIn, &fromlen, lpOverlapped, lpCompletionRoutine);
- }
- else
- {
- // TCP
- res = WSARecv( s, &wsabuf, 1, &dwBytesRead, &dwFlags, lpOverlapped, lpCompletionRoutine);
- }
- if ( res == SOCKET_ERROR )
- {
- res = WSAGetLastError();
- if ( res != WSA_IO_PENDING )
- {
- dwBytesRead = (DWORD)-1L;
- SetLastError( res );
- }
- }
- return dwBytesRead;
- }
- #endif
- ///////////////////////////////////////////////////////////////////////////////
- // Write
- DWORD CSocketHandle::Write(const LPBYTE lpBuffer, DWORD dwCount,
- const LPSOCKADDR lpAddrIn, DWORD dwTimeout)
- {
- _ASSERTE( IsOpen() );
- _ASSERTE( NULL != lpBuffer );
- // validate params
- if (!IsOpen() || NULL == lpBuffer)
- return (DWORD)-1L;
- fd_set fdWrite = { 0 };
- TIMEVAL stTime;
- TIMEVAL *pstTime = NULL;
- if ( INFINITE != dwTimeout ) {
- stTime.tv_sec = dwTimeout/1000;
- stTime.tv_usec = (dwTimeout%1000)*1000;
- pstTime = &stTime;
- }
- SOCKET s = GetSocket();
- // Set Descriptor
- FD_SET( s, &fdWrite );
- // Select function set write timeout
- DWORD dwBytesWritten = 0L;
- int res = 1;
- if ( pstTime != NULL )
- res = select((int)s, NULL, &fdWrite, NULL, pstTime );
- if ( res > 0)
- {
- // Send message to peer
- if (lpAddrIn)
- {
- // UDP
- res = sendto( s, reinterpret_cast<LPCSTR>(lpBuffer), dwCount, 0, lpAddrIn, sizeof(SOCKADDR_STORAGE));
- }
- else
- {
- // TCP
- res = send( s, reinterpret_cast<LPCSTR>(lpBuffer), dwCount, 0);
- }
- }
- if ( res == SOCKET_ERROR )
- {
- SetLastError( WSAGetLastError() );
- }
- dwBytesWritten = (DWORD)((res >= 0)?(res) : (-1));
- return dwBytesWritten;
- }
- #ifdef WIN32
- ///////////////////////////////////////////////////////////////////////////////
- // WriteEx
- DWORD CSocketHandle::WriteEx(const LPBYTE lpBuffer, DWORD dwCount,
- const LPSOCKADDR lpAddrIn,
- LPWSAOVERLAPPED lpOverlapped, LPWSACOMPLETIONROUTINE lpCompletionRoutine)
- {
- _ASSERTE( IsOpen() );
- _ASSERTE( NULL != lpBuffer );
- // validate params
- if (!IsOpen() || NULL == lpBuffer)
- return (DWORD)-1L;
- SOCKET s = GetSocket();
- // Select function set write timeout
- DWORD dwBytesWritten = 0L;
- int res = 0;
- // Send message to peer
- WSABUF wsabuf;
- wsabuf.buf = (char FAR*) lpBuffer;
- wsabuf.len = dwCount;
- if (lpAddrIn)
- {
- // UDP
- res = WSASendTo( s, &wsabuf, 1, &dwBytesWritten, 0, lpAddrIn, sizeof(SOCKADDR_STORAGE),
- lpOverlapped, lpCompletionRoutine);
- }
- else // TCP
- res = WSASend( s, &wsabuf, 1, &dwBytesWritten, 0, lpOverlapped, lpCompletionRoutine);
- if ( res == SOCKET_ERROR )
- {
- res = WSAGetLastError();
- if ( res != WSA_IO_PENDING )
- {
- dwBytesWritten = (DWORD)-1L;
- SetLastError( res );
- }
- }
- return dwBytesWritten;
- }
- #endif
- #ifdef WIN32
- ///////////////////////////////////////////////////////////////////////////////
- // IOControl
- bool CSocketHandle::IOControl(DWORD dwIoCode, LPBYTE lpInBuffer, DWORD cbInBuffer,
- LPBYTE lpOutBuffer, DWORD cbOutBuffer,
- LPDWORD lpcbBytesReturned, LPWSAOVERLAPPED lpOverlapped,
- LPWSACOMPLETIONROUTINE lpCompletionRoutine)
- {
- _ASSERTE( IsOpen() );
- // validate params
- if ( !IsOpen() ) {
- SetLastError(ERROR_INVALID_HANDLE);
- return false;
- }
- int res;
- SOCKET s = GetSocket();
- res = WSAIoctl(s, dwIoCode, lpInBuffer, cbInBuffer, lpOutBuffer, cbOutBuffer,
- lpcbBytesReturned, lpOverlapped, lpCompletionRoutine);
- if ( res == SOCKET_ERROR )
- {
- SetLastError( WSAGetLastError() );
- }
- return ( res != SOCKET_ERROR );
- }
- ///////////////////////////////////////////////////////////////////////////////
- // GetTransferOverlappedResult
- bool CSocketHandle::GetTransferOverlappedResult(LPWSAOVERLAPPED lpOverlapped, LPDWORD lpcbTransfer,
- bool bWait /*= true*/, LPDWORD lpdwFlags /*= NULL*/)
- {
- _ASSERTE( IsOpen() );
- _ASSERTE( NULL != lpOverlapped );
- // validate params
- if (!IsOpen() || NULL == lpOverlapped) {
- SetLastError(ERROR_INVALID_HANDLE);
- return false;
- }
- SOCKET s = GetSocket();
- DWORD dwFlags = 0;
- if ( lpdwFlags == NULL )
- lpdwFlags = &dwFlags;
- BOOL bRet = WSAGetOverlappedResult( s, lpOverlapped, lpcbTransfer, bWait, lpdwFlags );
- if ( !bRet )
- {
- SetLastError( WSAGetLastError() );
- }
- return (bRet != FALSE);
- }
- #endif
- ///////////////////////////////////////////////////////////////////////////////
- // Utility functions
- ///////////////////////////////////////////////////////////////////////////////
- // InitLibrary
- bool CSocketHandle::InitLibrary(WORD wVersion)
- {
- #ifdef WIN32
- WSADATA WSAData = { 0 };
- return ( 0 == WSAStartup( wVersion, &WSAData ) );
- #else
- return true;
- #endif
- }
- ///////////////////////////////////////////////////////////////////////////////
- // ReleaseLibrary
- bool CSocketHandle::ReleaseLibrary()
- {
- #ifdef WIN32
- return ( 0 == WSACleanup() );
- #else
- return true;
- #endif
- }
- ///////////////////////////////////////////////////////////////////////////////
- // WaitForConnection
- SOCKET CSocketHandle::WaitForConnection(SOCKET sock)
- {
- return accept(sock, 0, 0);
- }
- ///////////////////////////////////////////////////////////////////////////////
- // ShutdownConnection
- bool CSocketHandle::ShutdownConnection(SOCKET sock)
- {
- shutdown(sock, SD_BOTH);
- return ( 0 == closesocket( sock ));
- }
- static unsigned char chMinClassA_IP [] = { 1, 0, 0, 0 } ;
- static unsigned char chMinClassD_IP [] = { 224, 0, 0, 0 } ;
- static unsigned char chMaxClassD_IP [] = { 239, 255, 255, 255 } ;
- ///////////////////////////////////////////////////////////////////////////////
- // IsUnicastIP
- bool CSocketHandle::IsUnicastIP( ULONG ulAddr )
- {
- return (((unsigned char *) & ulAddr) [0] >= chMinClassA_IP [0] &&
- ((unsigned char *) & ulAddr) [0] < chMinClassD_IP [0]) ;
- }
- ///////////////////////////////////////////////////////////////////////////////
- // IsMulticastIP
- bool CSocketHandle::IsMulticastIP( ULONG ulAddr )
- {
- return (((unsigned char *) & ulAddr) [0] >= chMinClassD_IP [0] &&
- ((unsigned char *) & ulAddr) [0] <= chMaxClassD_IP [0]) ;
- }
- ///////////////////////////////////////////////////////////////////////////////
- // FormatIP
- bool CSocketHandle::FormatIP(LPTSTR pszIPAddr, UINT nSize, ULONG ulAddr, bool bFmtHost)
- {
- if ( pszIPAddr && nSize > 8)
- {
- if ( bFmtHost )
- ulAddr = htonl( ulAddr );
- // Create Address string
- return (SUCCEEDED(StringCchPrintf(pszIPAddr, nSize, TEXT("%u.%u.%u.%u"),
- (UINT)(((PBYTE) &ulAddr)[0]),
- (UINT)(((PBYTE) &ulAddr)[1]),
- (UINT)(((PBYTE) &ulAddr)[2]),
- (UINT)(((PBYTE) &ulAddr)[3]))));
- }
- SetLastError(ERROR_INSUFFICIENT_BUFFER);
- return false;
- }
- ///////////////////////////////////////////////////////////////////////////////
- // FormatIP
- bool CSocketHandle::FormatIP(LPTSTR pszIPAddr, UINT nSize, const SockAddrIn& addrIn)
- {
- if ( pszIPAddr && nSize > 8)
- {
- const void* addr;
- char szIPAddr[MAX_PATH] = { 0 };
- if (addrIn.ss_family == AF_INET) {
- addr = &((const sockaddr_in*)&addrIn)->sin_addr;
- } else {
- addr = &((const sockaddr_in6*)&addrIn)->sin6_addr;
- }
- if (inet_ntop(addrIn.ss_family, addr, szIPAddr, MAX_PATH) != NULL)
- {
- #ifdef _UNICODE
- return (0 != MultiByteToWideChar(CP_UTF8, 0, szIPAddr, -1, pszIPAddr, nSize ));
- #else
- ::StringCbCopyA(pszIPAddr, nSize, szIPAddr);
- return true;
- #endif
- }
- }
- SetLastError(ERROR_INSUFFICIENT_BUFFER);
- return false;
- }
- ///////////////////////////////////////////////////////////////////////////////
- // GetPortNumber
- USHORT CSocketHandle::GetPortNumber( LPCTSTR pszServiceName )
- {
- LPSERVENT lpservent;
- USHORT nPort = 0;
- if ( _istdigit( pszServiceName[0] ) ) {
- nPort = (USHORT) _ttoi( pszServiceName );
- }
- else {
- #ifdef _UNICODE
- char pstrService[HOSTNAME_SIZE] = { 0 };
- WideCharToMultiByte(CP_UTF8, 0, pszServiceName, -1, pstrService, sizeof(pstrService), NULL, NULL );
- #else
- LPCTSTR pstrService = pszServiceName;
- #endif
- // Convert network byte order to host byte order
- if ( (lpservent = getservbyname( pstrService, NULL )) != NULL )
- nPort = ntohs( lpservent->s_port );
- }
- return nPort;
- }
- ///////////////////////////////////////////////////////////////////////////////
- // GetIPAddress
- ULONG CSocketHandle::GetIPAddress( LPCTSTR pszHostName )
- {
- LPHOSTENT lphostent;
- ULONG uAddr = INADDR_NONE;
- TCHAR szLocal[HOSTNAME_SIZE] = { 0 };
- // if no name specified, get local
- if ( NULL == pszHostName || !pszHostName[0])
- {
- GetLocalName(szLocal, HOSTNAME_SIZE);
- pszHostName = szLocal;
- }
- #ifdef _UNICODE
- char pstrHost[HOSTNAME_SIZE] = { 0 };
- WideCharToMultiByte(CP_UTF8, 0, pszHostName, -1, pstrHost, sizeof(pstrHost), NULL, NULL );
- #else
- LPCTSTR pstrHost = pszHostName;
- #endif
- // Check for an Internet Protocol dotted address string
- uAddr = inet_addr( pstrHost );
- if ( (INADDR_NONE == uAddr) && (strcmp( pstrHost, "255.255.255.255" )) )
- {
- // It's not an address, then try to resolve it as a hostname
- if ( (lphostent = gethostbyname( pstrHost )) != NULL )
- uAddr = *((ULONG *) lphostent->h_addr_list[0]);
- }
-
- return ntohl( uAddr );
- }
- ///////////////////////////////////////////////////////////////////////////////
- // GetLocalName
- bool CSocketHandle::GetLocalName(LPTSTR pszName, UINT nSize)
- {
- if (pszName != NULL && nSize > 0)
- {
- char szHost[HOSTNAME_SIZE] = { 0 };
- // get host name, if fail, SetLastError is set
- if (SOCKET_ERROR != gethostname(szHost, sizeof(szHost)))
- {
- struct hostent* hp;
- hp = gethostbyname(szHost);
- if (hp != NULL) {
- ::StringCbCopyA(szHost, HOSTNAME_SIZE, hp->h_name);
- }
- // check if user provide enough buffer
- size_t cbLength = 0;
- ::StringCbLengthA(szHost, HOSTNAME_SIZE, &cbLength);
- if ( cbLength > nSize )
- {
- SetLastError(ERROR_INSUFFICIENT_BUFFER);
- return false;
- }
- // Unicode conversion
- #ifdef _UNICODE
- return (0 != MultiByteToWideChar(CP_UTF8, 0, szHost, -1, pszName, nSize ));
- #else
- ::StringCbCopyA(pszName, nSize, szHost);
- return true;
- #endif
- }
- else
- SetLastError( WSAGetLastError() );
- }
- else
- SetLastError(ERROR_INVALID_PARAMETER);
- return false;
- }
- ///////////////////////////////////////////////////////////////////////////////
- // GetLocalAddress
- bool CSocketHandle::GetLocalAddress(LPTSTR pszAddress, UINT nSize, int nFamily /*= AF_INET*/)
- {
- if (pszAddress != NULL && nSize > 0)
- {
- TCHAR szHost[HOSTNAME_SIZE] = { 0 };
- // Get computer local address
- // get host name, if fail, SetLastError is set
- if (GetLocalName(szHost, HOSTNAME_SIZE))
- {
- char szAddress[MAX_PATH] = { 0 };
- #ifdef _UNICODE
- char pstrHost[HOSTNAME_SIZE] = { 0 };
- WideCharToMultiByte(CP_UTF8, 0, szHost, -1, pstrHost, sizeof(pstrHost), NULL, NULL );
- #else
- LPCTSTR pstrHost = szHost;
- #endif
- // get address info
- sockaddr_storage addr_store = { 0 };
- addr_store.ss_family = static_cast<short>(nFamily);
- inet_pton(nFamily, pstrHost, &addr_store);
- const void* addr;
- if (addr_store.ss_family == AF_INET) {
- addr = &((const sockaddr_in*)&addr_store)->sin_addr;
- } else {
- addr = &((const sockaddr_in6*)&addr_store)->sin6_addr;
- }
- if (inet_ntop(addr_store.ss_family, addr, szAddress, MAX_PATH) != NULL)
- {
- // Unicode conversion
- #ifdef _UNICODE
- return (0 != MultiByteToWideChar(CP_UTF8, 0, szAddress, -1, pszAddress, nSize ));
- #else
- ::StringCbCopyA(pszAddress, nSize, szAddress);
- return true;
- #endif
- }
- else
- SetLastError( WSAGetLastError() );
- }
- }
- else
- SetLastError(ERROR_INVALID_PARAMETER);
- return false;
- }
- ///////////////////////////////////////////////////////////////////////////////
- // GetAddressInfo
- bool CSocketHandle::GetAddressInfo(LPCTSTR pszHostName, LPCTSTR pszServiceName,
- int nFamily, SockAddrIn& sockAddr)
- {
- const TCHAR szZERO[] = TEXT("0");
- ADDRINFO aiHints;
- ADDRINFO *aiList = NULL;
- memset(&aiHints, 0, sizeof(aiHints));
- aiHints.ai_flags = AI_ADDRCONFIG; // Jeff.ÔÝʱ½ûµô;
- aiHints.ai_family = static_cast<short>(nFamily);
- TCHAR szLocal[HOSTNAME_SIZE] = { 0 };
- // if no name specified, get local
- if ( NULL == pszHostName || !pszHostName[0])
- {
- GetLocalName(szLocal, HOSTNAME_SIZE);
- pszHostName = szLocal;
- }
- if ( NULL == pszServiceName || !pszServiceName[0])
- {
- pszServiceName = szZERO;
- }
- #ifdef _UNICODE
- char pstrHost[HOSTNAME_SIZE] = { 0 };
- WideCharToMultiByte(CP_UTF8, 0, pszHostName, -1, pstrHost, sizeof(pstrHost), NULL, NULL );
- char pstrService[HOSTNAME_SIZE] = { 0 };
- WideCharToMultiByte(CP_UTF8, 0, pszServiceName, -1, pstrService, sizeof(pstrService), NULL, NULL );
- #else
- LPCTSTR pstrHost = pszHostName;
- LPCTSTR pstrService = pszServiceName;
- #endif
- if ( SOCKET_ERROR != getaddrinfo(pstrHost, pstrService, &aiHints, &aiList) && ( aiList != 0 ))
- {
- ADDRINFO ai = { 0 };
- ai.ai_addr = sockAddr;
- memcpy(ai.ai_addr, aiList->ai_addr, aiList->ai_addrlen);
- freeaddrinfo( aiList );
- return true;
- }
- SetLastError( WSAGetLastError() );
- return false;
- }
- ///////////////////////////////////////////////////////////////////////////////
- // Globals
- ///////////////////////////////////////////////////////////////////////////////
- #if !defined(PLATFORM_HAS_INETFUNC)
- ///////////////////////////////////////////////////////////////////////////////
- // inet_ntop
- const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt)
- {
- if ( dst != NULL)
- {
- dst[0] = 0;
- if (af == AF_INET)
- {
- sockaddr_in in;
- memset(&in, 0, sizeof(in));
- in.sin_family = AF_INET;
- memcpy(&in.sin_addr, src, sizeof(in_addr));
- getnameinfo((sockaddr *)&in, sizeof(sockaddr_in), dst, cnt, NULL, 0, NI_NUMERICHOST);
- return dst;
- }
- else if (af == AF_INET6)
- {
- sockaddr_in6 in;
- memset(&in, 0, sizeof(in));
- in.sin6_family = AF_INET6;
- memcpy(&in.sin6_addr, src, sizeof(in6_addr));
- getnameinfo((sockaddr *)&in, sizeof(sockaddr_in6), dst, cnt, NULL, 0, NI_NUMERICHOST);
- return dst;
- }
- }
- WSASetLastError(WSA_INVALID_PARAMETER);
- return dst;
- }
- ///////////////////////////////////////////////////////////////////////////////
- // inet_pton
- int inet_pton(int af, const char *src, void *dst)
- {
- int result = SOCKET_ERROR;
- addrinfo aiHints, *aiList = NULL;
- memset(&aiHints, 0, sizeof(aiHints));
- aiHints.ai_family = af;
- if ( SOCKET_ERROR != getaddrinfo(src, NULL, &aiHints, &aiList) && (aiList != NULL))
- {
- memcpy(dst, aiList->ai_addr, aiList->ai_addrlen);
- freeaddrinfo(aiList);
- result = 0;
- }
- return result;
- }
- #endif
|