简体   繁体   中英

WSARecvFrom target ip address

I use WSARecvFrom function. It looks like this:

addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(listen_port);

bind(s, reinterpret_cast<PSOCKADDR>(&addr), sizeof(addr));

...

WSARecvFrom(s, ..., reinterpret_cast<sockaddr *>(&event->address), &event->addressLength, ...);

I can read From IP address from event->address. But how can I read target IP address UDP packet was sent to (socket was binded to INADDR_ANY - it listens all interfaces) ?

UPDATE . I found solution (for Windows Vista and higher). I wrote 2 functions: WSARecvFromEx allows to get target IP and WSASendToEx allows to send "from" IP:

//copyright (c) 2013 Vitaly. http://blog.coolsoftware.ru/

#if !(_WIN32_WINNT >= 0x0501)    

typedef
INT
(PASCAL FAR * LPFN_WSARECVMSG) (
    __in SOCKET s, 
    __inout LPWSAMSG lpMsg, 
    __out_opt LPDWORD lpdwNumberOfBytesRecvd, 
    __inout_opt LPWSAOVERLAPPED lpOverlapped, 
    __in_opt LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
    );

#define WSAID_WSARECVMSG \
    {0xf689d7c8,0x6f1f,0x436b,{0x8a,0x53,0xe5,0x4f,0xe3,0x51,0xc3,0x22}}

#endif !(_WIN32_WINNT >= 0x0501)

#if !(_WIN32_WINNT >= 0x0600)

typedef
INT
(PASCAL FAR * LPFN_WSASENDMSG) (
    __in SOCKET s,
    __in LPWSAMSG lpMsg,
    __in DWORD dwFlags,
    __out_opt LPDWORD lpNumberOfBytesSent,
    __inout_opt LPWSAOVERLAPPED lpOverlapped OPTIONAL,
    __in_opt LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine OPTIONAL
    );

#define WSAID_WSASENDMSG /* a441e712-754f-43ca-84a7-0dee44cf606d */ \
    {0xa441e712,0x754f,0x43ca,{0x84,0xa7,0x0d,0xee,0x44,0xcf,0x60,0x6d}}

#endif !(_WIN32_WINNT >= 0x0600)

LPFN_WSARECVMSG pfWSARecvMsg = NULL;
LPFN_WSASENDMSG pfWSASendMsg = NULL;

int WSARecvFromEx(
    SOCKET s,
    LPWSABUF lpBuffers,
    DWORD dwBufferCount,
    LPDWORD lpNumberOfBytesRecvd,
    LPDWORD lpFlags,
    struct sockaddr FAR * lpFrom,
    LPINT lpFromlen,
    char * pControlBuffer,
    ULONG nControlBufferLen,
    LPWSAOVERLAPPED lpOverlapped,
    LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
{
    if (pControlBuffer != NULL && 
        nControlBufferLen >= sizeof(WSACMSGHDR))
    {
        memset(pControlBuffer, 0, sizeof(WSACMSGHDR));
    }
    else
    {
        return WSARecvFrom(s, lpBuffers, dwBufferCount, lpNumberOfBytesRecvd, lpFlags, lpFrom, lpFromlen, lpOverlapped, lpCompletionRoutine);
    }

    if (pfWSARecvMsg == NULL)
    {
        return WSARecvFrom(s, lpBuffers, dwBufferCount, lpNumberOfBytesRecvd, lpFlags, lpFrom, lpFromlen, lpOverlapped, lpCompletionRoutine);
    }
    else
    {
        WSAMSG Msg;
        Msg.name = lpFrom;
        Msg.namelen = lpFromlen ? *lpFromlen : 0;
        Msg.lpBuffers = lpBuffers;
        Msg.dwBufferCount = dwBufferCount;
        Msg.Control.buf = pControlBuffer;
        Msg.Control.len = nControlBufferLen;
        Msg.dwFlags = lpFlags ? *lpFlags : 0;
        return pfWSARecvMsg(s, &Msg, lpNumberOfBytesRecvd, lpOverlapped, lpCompletionRoutine);
    }
} //WSARecvFromEx()

int WSASendToEx(
    SOCKET s,
    LPWSABUF lpBuffers,
    DWORD dwBufferCount,
    LPDWORD lpNumberOfBytesSent,
    DWORD dwFlags,
    struct sockaddr FAR * lpTo,
    int iTolen,
    ULONG fromIp4,
    char * pControlBuffer,
    ULONG nControlBufferLen,
    LPWSAOVERLAPPED lpOverlapped,
    LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
{
    int sum = 0;

    if (fromIp4 != INADDR_ANY &&
        pControlBuffer != NULL && 
        nControlBufferLen >= WSA_CMSG_SPACE(sizeof(struct in_pktinfo)))
    {
        memset(pControlBuffer, 0, WSA_CMSG_SPACE(sizeof(struct in_pktinfo)));
        WSACMSGHDR *pCMsgHdr = (WSACMSGHDR *)pControlBuffer;
        pCMsgHdr->cmsg_level = IPPROTO_IP;
        pCMsgHdr->cmsg_type = IP_PKTINFO;
        pCMsgHdr->cmsg_len = WSA_CMSG_LEN(sizeof(struct in_pktinfo));
        struct in_pktinfo *pktinfo = (struct in_pktinfo *)WSA_CMSG_DATA(pCMsgHdr);
        pktinfo->ipi_addr.s_addr = htonl(fromIp4);
        sum += WSA_CMSG_SPACE(sizeof(struct in_pktinfo));
    }
    else
    {
        return WSASendTo(s, lpBuffers, dwBufferCount, lpNumberOfBytesSent, dwFlags, lpTo, iTolen, lpOverlapped, lpCompletionRoutine);
    }

    if (pfWSASendMsg == NULL)
    {
        return WSASendTo(s, lpBuffers, dwBufferCount, lpNumberOfBytesSent, dwFlags, lpTo, iTolen, lpOverlapped, lpCompletionRoutine);
    }
    else
    {
        WSAMSG Msg;
        Msg.name = lpTo;
        Msg.namelen = iTolen;
        Msg.lpBuffers = lpBuffers;
        Msg.dwBufferCount = dwBufferCount;
        Msg.Control.buf = pControlBuffer;
        Msg.Control.len = sum;
        Msg.dwFlags = dwFlags;
        return pfWSASendMsg(s, &Msg, dwFlags, lpNumberOfBytesSent, lpOverlapped, lpCompletionRoutine);
    }
} //WSASendToEx()

Initialization:

    if (dwMajorVersion >= 6)
    {
        if (pfWSARecvMsg == NULL)
        {
            // get WSARecvMsg pointer
            GUID WSARecvMsg_GUID = WSAID_WSARECVMSG;
            DWORD NumberOfBytes = 0;
            if (WSAIoctl(socket_, SIO_GET_EXTENSION_FUNCTION_POINTER,
                    &WSARecvMsg_GUID, sizeof(WSARecvMsg_GUID),
                    &pfWSARecvMsg, sizeof(pfWSARecvMsg),
                    &NumberOfBytes, NULL, NULL) == SOCKET_ERROR)
            {
                printf("Could not get WSARecvMsg. WSAGetLastError returned [%i]", WSAGetLastError());
                pfWSARecvMsg = NULL;
            }
        }

        if (pfWSASendMsg == NULL)
        {
            // get WSASendMsg pointer
            GUID WSASendMsg_GUID = WSAID_WSASENDMSG;
            DWORD NumberOfBytes = 0;
            if (WSAIoctl(socket_, SIO_GET_EXTENSION_FUNCTION_POINTER,
                    &WSASendMsg_GUID, sizeof(WSASendMsg_GUID),
                    &pfWSASendMsg, sizeof(pfWSASendMsg),
                    &NumberOfBytes, NULL, NULL) == SOCKET_ERROR)
            {
                printf("Could not get WSASendMsg. WSAGetLastError returned [%i]", WSAGetLastError());
                pfWSASendMsg = NULL;
            }
        }
    }

Example of usage WSASendToEx:

int result = WSASendToEx(event->socket_, &sendBufferDescriptor, 1, &dwSent, 0,
            reinterpret_cast<sockaddr *>(&event->address), event->addressLength, 
            from, event->controlBuffer, sizeof(event->controlBuffer), 
            &event->overlapped, NULL);

Example of usage WSARecvFromEx:

int result = WSARecvFromEx(event->socket_, &recvBufferDescriptor, 1,
            &numberOfBytes, &recvFlags, 
        reinterpret_cast<sockaddr *>(&event->address), &event->addressLength, 
    event->controlBuffer, sizeof(event->controlBuffer),
    &event->overlapped, NULL);

There is no way to get the target IP from WSARecvFrom() when bound to INADDR_ANY . If you need the target IP, you would have to create and bind a separate socket for each local IP that you want to receive on, then you can use getsockname() to know which local IP a receiving socket is bound to.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM