Exemplo n.º 1
0
//static
HRESULT CStunSocket::Create(const CSocketAddress& addrlocal, SocketRole role, boost::shared_ptr<CStunSocket>* pStunSocketShared)
{
    int sock = -1;
    int ret;
    CStunSocket* pSocket = NULL;
    sockaddr_storage addrBind = {};
    socklen_t sizeaddrBind;
    HRESULT hr = S_OK;
    
    ChkIfA(pStunSocketShared == NULL, E_INVALIDARG);
    
    sock = socket(addrlocal.GetFamily(), SOCK_DGRAM, 0);
    ChkIf(sock < 0, ERRNOHR);
    
    ret = bind(sock, addrlocal.GetSockAddr(), addrlocal.GetSockAddrLength());
    ChkIf(ret < 0, ERRNOHR);
    
    // call get sockname to find out what port we just binded to.  (Useful for when addrLocal.port is 0)
    sizeaddrBind = sizeof(addrBind);
    ret = ::getsockname(sock, (sockaddr*)&addrBind, &sizeaddrBind);
    ChkIf(ret < 0, ERRNOHR);
    
    pSocket = new CStunSocket();
    pSocket->_sock = sock;
    pSocket->_addrlocal = CSocketAddress(*(sockaddr*)&addrBind);
    pSocket->_role = role;
    sock = -1;
    
    {
        boost::shared_ptr<CStunSocket> spTmp(pSocket);
        pStunSocketShared->swap(spTmp);
    }
    
    
Cleanup:

    if (sock != -1)
    {
        close(sock);
        sock = -1;
    }

    return hr;
}
Exemplo n.º 2
0
// This test validates that the EnablePktInfoOption set on a socket allows us to get at the destination IP address for incoming packets
// This is needed so that we can correctly insert an origin address into responses from the server
// Otherwise, the server doesn't have a way of knowing which interface a packet arrived on when it's listening on INADDR_ANY (all available addresses)
HRESULT CTestRecvFromEx::DoTest(bool fIPV6)
{
    // create a couple of sockets for send/recv
    HRESULT hr = S_OK;
    CSocketAddress addrAny(0,0); // INADDR_ANY, random port
    sockaddr_in6 addrAnyIPV6 = {};
    uint16_t portRecv = 0;
    CRefCountedStunSocket spSocketSend, spSocketRecv;
    fd_set set = {};
    CSocketAddress addrDestForSend;
    CSocketAddress addrDestOnRecv;
    CSocketAddress addrSrcOnRecv;
    
    CSocketAddress addrSrc;
    CSocketAddress addrDst;
    
    char ch = 'x';
    sockaddr_storage addrDummy;
    socklen_t addrlength;
    int ret;
    timeval tv = {};
    
    
    if (fIPV6)
    {
        addrAnyIPV6.sin6_family = AF_INET6;
        addrAny = CSocketAddress(addrAnyIPV6);
    }
    
    
    // create two sockets listening on INADDR_ANY.  One for sending and one for receiving
    ChkA(CStunSocket::Create(addrAny, RolePP, &spSocketSend));
    ChkA(CStunSocket::Create(addrAny, RolePP, &spSocketRecv));
    
    spSocketRecv->EnablePktInfoOption(true);
    
    portRecv = spSocketRecv->GetLocalAddress().GetPort();
    
    // now send to localhost
    if (fIPV6)
    {
        sockaddr_in6 addr6 = {};
        addr6.sin6_family = AF_INET6;
        ::inet_pton(AF_INET6, "::1", &(addr6.sin6_addr));
        addrDestForSend = CSocketAddress(addr6);
    }
    else
    {
        sockaddr_in addr4 = {};
        addr4.sin_family = AF_INET;
        ::inet_pton(AF_INET, "127.0.0.1", &(addr4.sin_addr));
        addrDestForSend = CSocketAddress(addr4);
    }
    addrDestForSend.SetPort(portRecv);
    
    // flush out any residual packets that might be buffered up on recv socket
    ret = -1;
    do
    {
        addrlength = sizeof(addrDummy);
        ret = ::recvfrom(spSocketRecv->GetSocketHandle(), &ch, sizeof(ch), MSG_DONTWAIT, (sockaddr*)&addrDummy, &addrlength);
    } while (ret >= 0);
    
    // now send some data to ourselves
    ret = sendto(spSocketSend->GetSocketHandle(), &ch, sizeof(ch), 0, addrDestForSend.GetSockAddr(), addrDestForSend.GetSockAddrLength());
    ChkIfA(ret <= 0, E_UNEXPECTED);
    
    // now wait for the data to arrive
    FD_ZERO(&set);
    FD_SET(spSocketRecv->GetSocketHandle(), &set);
    tv.tv_sec = 3;
    
    ret = select(spSocketRecv->GetSocketHandle()+1, &set, NULL, NULL, &tv);
    
    ChkIfA(ret <= 0, E_UNEXPECTED);
    
    ret = ::recvfromex(spSocketRecv->GetSocketHandle(), &ch, 1, MSG_DONTWAIT, &addrSrcOnRecv, &addrDestOnRecv);
    
    ChkIfA(ret <= 0, E_UNEXPECTED);    
    
    ChkIfA(addrSrcOnRecv.IsIPAddressZero(), E_UNEXPECTED);
    ChkIfA(addrDestOnRecv.IsIPAddressZero(), E_UNEXPECTED);
    
    
Cleanup:

    return hr;
}
Exemplo n.º 3
0
HRESULT UdpClientLoop(StunClientLogicConfig& config, const ClientSocketConfig& socketconfig)
{
    HRESULT hr = S_OK;
    CRefCountedStunSocket spStunSocket;
    CStunSocket stunSocket;;
    CRefCountedBuffer spMsg(new CBuffer(MAX_STUN_MESSAGE_SIZE));
    int sock = -1;
    CSocketAddress addrDest;   // who we send to
    CSocketAddress addrRemote; // who we
    CSocketAddress addrLocal;
    int ret;
    fd_set set;
    timeval tv = {};
    std::string strAddr;
    std::string strAddrLocal;
    StunClientResults results;

    CStunClientLogic clientlogic;


    hr = clientlogic.Initialize(config);
    
    if (FAILED(hr))
    {
        Logging::LogMsg(LL_ALWAYS, "Unable to initialize client: (error = x%x)", hr);
        Chk(hr);
    }

    hr = stunSocket.UDPInit(socketconfig.addrLocal, RolePP);
    if (FAILED(hr))
    {
        Logging::LogMsg(LL_ALWAYS, "Unable to create local socket: (error = x%x)", hr);
        Chk(hr);
    }
    

    stunSocket.EnablePktInfoOption(true);

    sock = stunSocket.GetSocketHandle();

    // let's get a loop going!

    while (true)
    {
        HRESULT hrRet;
        spMsg->SetSize(0);
        hrRet = clientlogic.GetNextMessage(spMsg, &addrDest, GetMillisecondCounter());

        if (SUCCEEDED(hrRet))
        {
            addrDest.ToString(&strAddr);
            ASSERT(spMsg->GetSize() > 0);
            
            if (Logging::GetLogLevel() >= LL_DEBUG)
            {
                std::string strAddr;
                addrDest.ToString(&strAddr);
                Logging::LogMsg(LL_DEBUG, "Sending message to %s", strAddr.c_str());
            }

            ret = ::sendto(sock, spMsg->GetData(), spMsg->GetSize(), 0, addrDest.GetSockAddr(), addrDest.GetSockAddrLength());

            if (ret <= 0)
            {
                Logging::LogMsg(LL_DEBUG, "ERROR.  sendto failed (errno = %d)", errno);
            }
            // there's not much we can do if "sendto" fails except time out and try again
        }
        else if (hrRet == E_STUNCLIENT_STILL_WAITING)
        {
            Logging::LogMsg(LL_DEBUG, "Continuing to wait for response...");
        }
        else if (hrRet == E_STUNCLIENT_RESULTS_READY)
        {
            break;
        }
        else
        {
            Logging::LogMsg(LL_DEBUG, "Fatal error (hr == %x)", hrRet);
            Chk(hrRet);
        }


        // now wait for a response
        spMsg->SetSize(0);
        FD_ZERO(&set);
        FD_SET(sock, &set);
        tv.tv_usec = 500000; // half-second
        tv.tv_sec = config.timeoutSeconds;

        ret = select(sock+1, &set, NULL, NULL, &tv);
        if (ret > 0)
        {
            ret = ::recvfromex(sock, spMsg->GetData(), spMsg->GetAllocatedSize(), MSG_DONTWAIT, &addrRemote, &addrLocal);
            if (ret > 0)
            {
                addrRemote.ToString(&strAddr);
                addrLocal.ToString(&strAddrLocal);
                Logging::LogMsg(LL_DEBUG, "Got response (%d bytes) from %s on interface %s", ret, strAddr.c_str(), strAddrLocal.c_str());
                spMsg->SetSize(ret);
                clientlogic.ProcessResponse(spMsg, addrRemote, addrLocal);
            }
        }
    }


    results.Init();
    clientlogic.GetResults(&results);

    DumpResults(config, results);


Cleanup:
    return hr;
}