#include "stdafx.h" #ifdef WIN32 #include #ifndef UNDER_CE #include #endif #include #endif #include "SocketHandle.h" #include #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, size_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 #if 1 typedef struct STcpKeepAlive2 { DWORD onoff; DWORD keepalivetime; DWORD keepaliveinterval; }TCP_KEEP_ALIVE2; /************************************************************************/ /* 函数:SetKeepLive[2/29/2016 IT]; /* 描述:设置TCP连接鲜活时间; /* 参数:; /* [IN] Socket:要设置的客户端SOCKET; /* 返回:设置成功返回TRUE; /* 注意:; /* 示例:; /* /* 修改:; /* 日期:; /* 内容:; /************************************************************************/ BOOL SetKeepLive(IN SOCKET &Socket) { const BYTE chOpt = 1; // True; // Set KeepAlive 开启保活机制, 防止服务端产生死连接; if (setsockopt(Socket, SOL_SOCKET, SO_KEEPALIVE, (char *)&chOpt, sizeof(chOpt)) == SOCKET_ERROR) { printf("设置客户端鲜活机制失败1\n\n"); return FALSE; } // 设置超时详细信息; BYTE byRet[5] = {0}; TCP_KEEP_ALIVE2 klive; klive.onoff = 1; // 启用保活; klive.keepalivetime = 1000 * 15; // 3分钟超时 Keep Alive; klive.keepaliveinterval = 1000 * 5; // 重试间隔为5秒 Resend if No-Reply; INT nResult = WSAIoctl ( Socket, SIO_KEEPALIVE_VALS, &klive, sizeof(TCP_KEEP_ALIVE2), NULL, 0, (unsigned long *)&byRet, 0, NULL ); if ( nResult == SOCKET_ERROR ) { printf("设置客户端鲜活机制失败2\n\n"); return FALSE; } return TRUE; } #endif CSocketHandle::CSocketHandle(): m_hSocket(INVALID_SOCKET) { } CSocketHandle::~CSocketHandle() { Close(); } bool CSocketHandle::IsOpen() const { return ( INVALID_SOCKET != m_hSocket ); } SOCKET CSocketHandle::GetSocket() const { return m_hSocket; } /************************************************************************/ /* 函数:GetSocketType[2/29/2016 IT]; /* 描述:获取套接字类型; /* 参数:; /* 返回:返回-1表示不是一个有效的套接字; /* 注意:; /* 示例:; /* /* 修改:; /* 日期:; /* 内容:; /************************************************************************/ 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(&type),&optlen) == SOCKET_ERROR) { SetLastError( WSAGetLastError() ); } } return type; } /************************************************************************/ /* 函数:Attach[2/29/2016 IT]; /* 描述:附加一个SOCKET句柄,使用Detach函数或Close函数来释放句柄; /* 参数:; /* [IN] sock:要附加到类中的套接字句柄; /* 返回:成功返回TRUE; /* 注意:函数有可能失败,当要附加的套接字是一个无效值或该值已在使用时; /* 示例:; /* /* 修改:; /* 日期:; /* 内容:; /************************************************************************/ bool CSocketHandle::Attach(IN SOCKET sock) { if ( INVALID_SOCKET == m_hSocket ) { m_hSocket = sock; return true; } return false; } /************************************************************************/ /* 函数:Detach[2/29/2016 IT]; /* 描述:把套接字从类对象中分离出来; /* 参数:无; /* 返回:返回前面附加的套接字句柄或INVALID_SOCKET; /* 注意:; /* 示例:; /* /* 修改:; /* 日期:; /* 内容:; /************************************************************************/ SOCKET CSocketHandle::Detach() { SOCKET sock = m_hSocket; ::InterlockedExchange(reinterpret_cast(&m_hSocket), INVALID_SOCKET); return sock; } /************************************************************************/ /* 函数:GetSockName[2/29/2016 IT]; /* 描述:获取套接字名(本地地址); /* 参数:; /* [OUT] saddr_in:连接成功时返回的当前本地地址和端口号; /* 返回:成功返回TRUE; /* 注意:使用前必须调用InitLibrary函数; /* 示例:; /* /* 修改:; /* 日期:; /* 内容:; /************************************************************************/ bool CSocketHandle::GetSockName(OUT 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[2/29/2016 IT]; /* 描述:获取点对点的套接接名(获取Peer地址);; /* 参数:; /* [OUT] saddr_in: peer address and port (use only with TCP or client mode UDP); /* 返回:成功返回TRUE; /* 注意:使用前必须调用InitLibrary函数; /* 示例:; /* /* 修改:; /* 日期:; /* 内容:; /************************************************************************/ bool CSocketHandle::GetPeerName(OUT 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[2/29/2016 IT]; /* 描述:关闭套接字; /* 参数:; /* 返回:void; /* 注意:关联函数InitLibrary, CreateSocket, ConnectTo, IsOpen; /* 示例:; /* /* 修改:; /* 日期:; /* 内容:; /************************************************************************/ void CSocketHandle::Close() { if ( IsOpen() ) { ShutdownConnection(static_cast(::InterlockedExchange((LONG*)&m_hSocket, INVALID_SOCKET))); } } /************************************************************************/ /* 函数:AddMembership[2/29/2016 IT]; /* 描述:添加多播地址; /* 参数:; /* [IN] pszIPAddr:多播IP组; /* [IN] pszNIC:IP地址接口(多张网卡时,某一网卡序列号); /* 返回:成功返回TRUE; /* 注意:关联InitLibrary函数; /* 示例:; /* /* 修改:; /* 日期:; /* 内容:; /************************************************************************/ bool CSocketHandle::AddMembership(IN LPCTSTR pszIPAddr, IN 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[2/29/2016 IT]; /* 描述:移除多播地址; /* 参数:; /* [IN] pszIPAddr:多播IP组; /* [IN] pszNIC:IP地址接口(多张网卡时,某一网卡序列号); /* 返回:成功返回TRUE; /* 注意:关联InitLibrary函数; /* 示例:; /* /* 修改:; /* 日期:; /* 内容:; /************************************************************************/ 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[2/29/2016 IT]; /* 描述:创建服务端套接字; /* 参数:; /* [IN] pszHostName:主机名或网卡适配器地址; /* [IN] pszServiceName:网络服务名或者IP端口号; /* [IN] nFamily:要用的地址协议簇类型(IPV4或IPV6); /* [IN] nType:要创建的套接字类型(SOCK_STREAM 或 SOCK_DGRAM); /* [IN] uOptions:附加选项(SO_BROADCAST,SO_REUSEADDR) ; /* 返回:成功返回TRUE; /* 注意:使用WSAGetLastError()函数获取最后的错误,关联函数InitLibrary, ConnectTo, IsOpen; /* 示例:; /* /* 修改:; /* 日期:; /* 内容:; /************************************************************************/ bool CSocketHandle::CreateSocket(IN LPCTSTR pszHostName, IN LPCTSTR pszServiceName, IN int nFamily, IN int nType, IN 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[2/29/2016 IT]; /* 描述:客户端连接服务端; /* 参数:; /* [IN] pszHostName:Hostname or NIC address; /* [IN] pszRemote:Remote network address; /* [IN] pszServiceName:Network service name or port number; /* [IN] nFamily:address family to use (AF_INET, AF_INET6); /* [IN] nType:type of socket to create (SOCK_STREAM, SOCK_DGRAM); /* 返回:return true if successful, otherwise false (call WSAGetLastError() to retrieve latest error); /* 注意:关联函数InitLibrary, CreateSocket, IsOpen; /* 示例:; /* /* 修改:; /* 日期:; /* 内容:; /************************************************************************/ bool CSocketHandle::ConnectTo(IN LPCTSTR pszHostName, IN LPCTSTR pszRemote, IN LPCTSTR pszServiceName, IN int nFamily, IN 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[2/29/2016 IT]; /* 描述:从套接字中读取内容; /* 参数:; /* [OUT] lpBuffer:Buffer to receive data; /* [IN] dwSize:Size of buffer in bytes; /* [IN] lpAddrIn:Peer address for UDP - this must be NULL for TCP; /* [IN] dwTimeout:Read timeout in milliseconds; /* 返回:return number of bytes read or (-1L) if fail; /* 注意:关联函数InitLibrary, CreateSocket, ConnectTo, IsOpen, ReadEx, Write, WriteEx; /* 示例:; /* /* 修改:; /* 日期:; /* 内容:; /************************************************************************/ DWORD CSocketHandle::Read(OUT LPBYTE lpBuffer, IN DWORD dwSize, IN LPSOCKADDR lpAddrIn /* = NULL */, IN DWORD dwTimeout /* = INFINITE */) { _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(lpBuffer), dwSize, 0, lpAddrIn, &fromlen); } else { // TCP res = recv(s, reinterpret_cast(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[2/29/2016 IT]; /* 描述:从套接字读取内容,异步模式(asynchronous mode); /* 参数:; /* [OUT] lpBuffer:Buffer to receive data; /* [IN] dwSize:Size of buffer in bytes; /* [IN] lpAddrIn:SockAddrIn for UDP - this must be NULL for TCP; /* [IN] lpOverlapped:Windows Overlapped structure (required); /* [IN] lpCompletionRoutine:Winsock Completion routine (required); /* 返回:return number of bytes read, overlapped operation is pending or (-1L) if fail; /* 注意:关联函数 InitLibrary, CreateSocket, ConnectTo, IsOpen, Read, Write, WriteEx, IOControl, GetTransferOverlappedResult; /* 示例:; /* /* 修改:; /* 日期:; /* 内容:; /************************************************************************/ DWORD CSocketHandle::ReadEx(OUT LPBYTE lpBuffer, IN DWORD dwSize, IN LPSOCKADDR lpAddrIn, IN LPWSAOVERLAPPED lpOverlapped, IN 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[2/29/2016 IT]; /* 描述:向目标套接字发送内容; /* 参数:; /* [IN] lpBuffer:Buffer to send; /* [IN] dwCount:Number of bytes to send; /* [IN] lpAddrIn:Peer address for UDP - this must be NULL for TCP; /* [IN] dwTimeout:Write timeout in milliseconds; /* 返回:return number of bytes sent or (-1L) if fail; /* 注意:关联函数InitLibrary, CreateSocket, ConnectTo, IsOpen, Read, ReadEx, WriteEx; /* 示例:; /* /* 修改:; /* 日期:; /* 内容:; /************************************************************************/ DWORD CSocketHandle::Write(IN const LPBYTE lpBuffer, IN DWORD dwCount, IN const LPSOCKADDR lpAddrIn /* = NULL */, IN DWORD dwTimeout /* = INFINITE */) { _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(lpBuffer), dwCount, 0, lpAddrIn, sizeof(SOCKADDR_STORAGE)); } else { // TCP res = send( s, reinterpret_cast(lpBuffer), dwCount, 0); } } if ( res == SOCKET_ERROR ) { SetLastError( WSAGetLastError() ); } dwBytesWritten = (DWORD)((res >= 0)?(res) : (-1)); return dwBytesWritten; } #ifdef WIN32 /************************************************************************/ /* 函数:WriteEx[2/29/2016 IT]; /* 描述:向目标套接字发送内容,异步模式(asynchronous mode); /* 参数:; /* [IN] lpBuffer:Buffer to send; /* [IN] dwCount:Number of bytes to send; /* [IN] lpAddrIn:SockAddrIn for UDP - this must be NULL for TCP; /* [IN] lpOverlapped:Windows Overlapped structure (required); /* [IN] lpCompletionRoutine:Winsock Completion routine (required); /* 返回:return number of bytes read, overlapped operation is pending or (-1L) if fail; /* 注意:关联函数InitLibrary, CreateSocket, ConnectTo, IsOpen, Read, ReadEx, Write, IOControl, GetTransferOverlappedResult; /* 示例:; /* /* 修改:; /* 日期:; /* 内容:; /************************************************************************/ DWORD CSocketHandle::WriteEx(IN const LPBYTE lpBuffer, IN DWORD dwCount, IN const LPSOCKADDR lpAddrIn, IN LPWSAOVERLAPPED lpOverlapped, IN 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[2/29/2016 IT]; /* 描述:Control the mode of a socket (asynchronous mode); /* 参数:; /* [IN] dwIoCode:Control code of operation to perform; /* [IN] lpInBuffer:Pointer to the input buffer; /* [IN] cbInBuffer:Size of the input buffer, in bytes; /* [IN] lpOutBuffer:Pointer to the output buffer; /* [IN] cbOutBuffer:Size of the output buffer, in bytes; /* [IN] lpcbBytesReturned:Pointer to actual number of bytes of output; /* [IN] lpOverlapped:Winsock Overlapped structure; /* [IN] lpCompletionRoutine:Winsock Completion routine; /* 返回:return true if successful, otherwise false (call WSAGetLastError() to retrieve latest error); /* 注意:关联函数InitLibrary, CreateSocket, ConnectTo, IsOpen, ReadEx, WriteEx, GetTransferOverlappedResult; /* 示例:; /* /* 修改:; /* 日期:; /* 内容:; /************************************************************************/ bool CSocketHandle::IOControl( IN DWORD dwIoCode, IN LPBYTE lpInBuffer, IN DWORD cbInBuffer, IN LPBYTE lpOutBuffer, IN DWORD cbOutBuffer, IN LPDWORD lpcbBytesReturned, IN LPWSAOVERLAPPED lpOverlapped, IN 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[2/29/2016 IT]; /* 描述:Get Overlapped result (asynchronous mode); /* 参数:; /* [IN] lpOverlapped:Windows Overlapped structure (required); /* [IN] lpcbTransfer:Pointer to get number of bytes transferred; /* [IN] bWait:Force wait for overlapped operation to complete; /* [IN] lpdwFlags:Optional flags (see MSDN on WSARecv API); /* [OUT] :; /* [IN/OUT] :; /* 返回:成功返回TRUE; /* 注意:关联函数InitLibrary, CreateSocket, ConnectTo, IsOpen, ReadEx, WriteEx, IOControl; /* 示例:; /* /* 修改:; /* 日期:; /* 内容:; /************************************************************************/ bool CSocketHandle::GetTransferOverlappedResult(IN LPWSAOVERLAPPED lpOverlapped, IN LPDWORD lpcbTransfer, IN bool bWait /* = true */, IN LPDWORD lpdwFlags /* = 0 */) { _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[2/29/2016 IT]; /* 描述:Initialize Winsock library. This function calls WSAStartup; /* 参数:; /* [IN] wVersion:Winsock version use MAKEWORD macro if possible (e.g.: MAKEWORD(2,2)); /* 返回:return true if successful; /* 注意:关联ReleaseLibrary; /* 示例:; /* /* 修改:; /* 日期:; /* 内容:; /************************************************************************/ bool CSocketHandle::InitLibrary(IN WORD wVersion) { #ifdef WIN32 WSADATA WSAData = { 0 }; return ( 0 == WSAStartup( wVersion, &WSAData ) ); #else return true; #endif } /************************************************************************/ /* 函数:ReleaseLibrary[2/29/2016 IT]; /* 描述:Release Winsock library; /* 参数:; /* 返回:return true if successful; /* 注意:关联InitLibrary; /* 示例:; /* /* 修改:; /* 日期:; /* 内容:; /************************************************************************/ bool CSocketHandle::ReleaseLibrary() { #ifdef WIN32 return ( 0 == WSACleanup() ); #else return true; #endif } /************************************************************************/ /* 函数:WaitForConnection[2/29/2016 IT]; /* 描述:Wait for a new connection; /* 参数:; /* [IN] sock:A TCP socket handle. A new socket is return returned; /* 返回:return A new socket when a new client connects; /* 注意:关联GetSocket, CreateSocket; /* 示例:; /* /* 修改:; /* 日期:; /* 内容:; /************************************************************************/ SOCKET CSocketHandle::WaitForConnection(IN SOCKET sock) { #if 0 return accept(sock, 0, 0); #else SOCKET ncs = accept(sock, 0, 0); SetKeepLive(ncs); return ncs; #endif } /************************************************************************/ /* 函数:ShutdownConnection[2/29/2016 IT]; /* 描述:Shutdown a connection; /* 参数:; /* [IN] sock:Socket to shutdown communication; /* 返回:return true if successful; /* 注意:; /* 示例:; /* /* 修改:; /* 日期:; /* 内容:; /************************************************************************/ bool CSocketHandle::ShutdownConnection(IN 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[2/29/2016 IT]; /* 描述:Check if IP address is unicast (network order); /* 参数:; /* [IN] ulAddr:IP address (expected valid unicast address); /* 返回:return true if successful; /* 注意:; /* 示例:; /* /* 修改:; /* 日期:; /* 内容:; /************************************************************************/ bool CSocketHandle::IsUnicastIP( ULONG ulAddr ) { return (((unsigned char *) & ulAddr) [0] >= chMinClassA_IP [0] && ((unsigned char *) & ulAddr) [0] < chMinClassD_IP [0]) ; } /************************************************************************/ /* 函数:IsMulticastIP[2/29/2016 IT]; /* 描述:Check if IP address is multicast (network order); /* 参数:; /* [IN] ulAddr:IP address (expected valid multicast address); /* 返回:return true if successful; /* 注意:; /* 示例:; /* /* 修改:; /* 日期:; /* 内容:; /************************************************************************/ bool CSocketHandle::IsMulticastIP( ULONG ulAddr ) { return (((unsigned char *) & ulAddr) [0] >= chMinClassD_IP [0] && ((unsigned char *) & ulAddr) [0] <= chMaxClassD_IP [0]) ; } /************************************************************************/ /* 函数:FormatIP[2/29/2016 IT]; /* 描述:Format IP address to string; /* 参数:; /* [IN] pszIPAddr:Buffer to hold string; /* [IN] nSize:Size of buffer in characters; /* [IN] ulAddr:IP Address to format; /* [IN] bFmtHost:Specify if address (ulAddr) is in host (true) or network format (false); /* 返回:return true if successful. Possible error could be INSUFFICIENT_BUFFER; /* 注意:; /* 示例:; /* /* 修改:; /* 日期:; /* 内容:; /************************************************************************/ 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[2/29/2016 IT]; /* 描述:Format IP address to string; /* 参数:; /* [IN] pszIPAddr:Buffer to hold string; /* [IN] nSize:Size of buffer in characters; /* [IN] addrIn:IP Address to format; /* 返回:return true if successful. Possible error could be INSUFFICIENT_BUFFER; /* 注意:; /* 示例:; /* /* 修改:; /* 日期:; /* 内容:; /************************************************************************/ 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, const_cast(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[2/29/2016 IT]; /* 描述:Get service port number; /* 参数:; /* [IN] pszServiceName:Network service name (e.g.: "ftp", "telnet") or port number; /* 返回:return port number; /* 注意:; /* 示例:; /* /* 修改:; /* 日期:; /* 内容:; /************************************************************************/ 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[2/29/2016 IT]; /* 描述:Get IP address of a host; /* 参数:; /* [IN] pszHostName:host name or IP address; /* 返回:return Host IP address in host format; /* 注意:关联GetAddressInfo; /* 示例:; /* /* 修改:; /* 日期:; /* 内容:; /************************************************************************/ 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[2/29/2016 IT]; /* 描述:Get current localname for this machine; /* 参数:; /* [IN] pszName:Buffer to receive host name; /* [IN] nSize:Size of this buffer in character; /* 返回:return true if successful; /* 注意:; /* 示例:; /* /* 修改:; /* 日期:; /* 内容:; /************************************************************************/ 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[2/29/2016 IT]; /* 描述:Get current (default) IP address for this machine; /* 参数:; /* [IN] pszAddress:Buffer to receive IP address (IPv4, IPv6 format); /* [IN] nSize:Size of this buffer in character; /* [IN] nFamily:address family to use (AF_INET, AF_INET6); /* 返回:return true if successful; /* 注意:; /* 示例:; /* /* 修改:; /* 日期:; /* 内容:; /************************************************************************/ 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(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, const_cast(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[2/29/2016 IT]; /* 描述:Get IP address info of a host (Supports: IPv4 and IPv6); /* 参数:; /* [IN] pszHostName:host name or IP address; /* [IN] pszServiceName:pszServiceName Network service name (e.g.: "ftp", "telnet") or port number; /* [IN] nFamily:address family to use (AF_INET, AF_INET6); /* [IN] sockAddr:Socket address to fill in; /* 返回:return true if successful; /* 注意:; /* 示例:; /* /* 修改:; /* 日期:; /* 内容:; /************************************************************************/ 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(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) #if 0 /////////////////////////////////////////////////////////////////////////////// // inet_ntop const char *inet_ntop(int af, const void *src, char *dst, size_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; } #else ////////////////////////////////////////////////////////////////////////// static const char * inet_ntop_v4 (const void *src, char *dst, size_t size) { const char digits[] = "0123456789"; int i; struct in_addr *addr = (struct in_addr *)src; u_long a = ntohl(addr->s_addr); const char *orig_dst = dst; if (size < INET_ADDRSTRLEN) { errno = ENOSPC; return NULL; } for (i = 0; i < 4; ++i) { int n = (a >> (24 - i * 8)) & 0xFF; int non_zerop = 0; if (non_zerop || n / 100 > 0) { *dst++ = digits[n / 100]; n %= 100; non_zerop = 1; } if (non_zerop || n / 10 > 0) { *dst++ = digits[n / 10]; n %= 10; non_zerop = 1; } *dst++ = digits[n]; if (i != 3) *dst++ = '.'; } *dst++ = '\0'; return orig_dst; } #ifdef HAVE_IPV6 static const char * inet_ntop_v6 (const void *src, char *dst, size_t size) { const char xdigits[] = "0123456789abcdef"; int i; const struct in6_addr *addr = (struct in6_addr *)src; const u_char *ptr = addr->s6_addr; const char *orig_dst = dst; int compressed = 0; if (size < INET6_ADDRSTRLEN) { errno = ENOSPC; return NULL; } for (i = 0; i < 8; ++i) { int non_zerop = 0; if (compressed == 0 && ptr[0] == 0 && ptr[1] == 0 && i <= 5 && ptr[2] == 0 && ptr[3] == 0 && ptr[4] == 0 && ptr[5] == 0) { compressed = 1; if (i == 0) *dst++ = ':'; *dst++ = ':'; for (ptr += 6, i += 3; i < 8 && ptr[0] == 0 && ptr[1] == 0; ++i, ptr += 2); if (i >= 8) break; } if (non_zerop || (ptr[0] >> 4)) { *dst++ = xdigits[ptr[0] >> 4]; non_zerop = 1; } if (non_zerop || (ptr[0] & 0x0F)) { *dst++ = xdigits[ptr[0] & 0x0F]; non_zerop = 1; } if (non_zerop || (ptr[1] >> 4)) { *dst++ = xdigits[ptr[1] >> 4]; non_zerop = 1; } *dst++ = xdigits[ptr[1] & 0x0F]; if (i != 7) *dst++ = ':'; ptr += 2; } *dst++ = '\0'; return orig_dst; } #endif /* HAVE_IPV6 */ const char * inet_ntop(int af, const void *src, char *dst, size_t size) { switch (af) { case AF_INET : return inet_ntop_v4 (src, dst, size); #ifdef HAVE_IPV6 case AF_INET6 : return inet_ntop_v6 (src, dst, size); #endif default : //errno = EAFNOSUPPORT; return NULL; } } int inet_pton(int af, const char *csrc, void *dst) { char * src; if (csrc == NULL || (src = strdup(csrc)) == NULL) { _set_errno( ENOMEM ); return 0; } switch (af) { case AF_INET: { struct sockaddr_in si4; INT r; INT s = sizeof(si4); si4.sin_family = AF_INET; r = WSAStringToAddress(src, AF_INET, NULL, (LPSOCKADDR) &si4, &s); free(src); src = NULL; if (r == 0) { memcpy(dst, &si4.sin_addr, sizeof(si4.sin_addr)); return 1; } } break; case AF_INET6: { struct sockaddr_in6 si6; INT r; INT s = sizeof(si6); si6.sin6_family = AF_INET6; r = WSAStringToAddress(src, AF_INET6, NULL, (LPSOCKADDR) &si6, &s); free(src); src = NULL; if (r == 0) { memcpy(dst, &si6.sin6_addr, sizeof(si6.sin6_addr)); return 1; } } break; default: _set_errno( ENOSYS/*EAFNOSUPPORT*/ ); return -1; } /* the call failed */ { int le = WSAGetLastError(); if (le == WSAEINVAL) return 0; _set_errno(le); return -1; } } #endif #endif