STUN support

From reSIProcate
Jump to navigation Jump to search

Resiprocate implements STUN client and server support

STUN Server

reSIProcate is able to act as an STUN server on each configured UDP transport. This means that reSIProcate will accept and respond to STUN requests from external clients. Usually STUN is done through a separate STUN server which operates on a different port (or even a different machine). The advantage of using STUN through the SIP port is that this may help traversing even symmetric NATs. Though, this method is not very popular currently and it doesn't really help if RTP streams are involved.

To activate STUN server support you must simply pass the "StunEnabled" value with the "AddTransport" method.

Note: The DialogUsageManager::AddTransport method simply maps through to the SipStack::AddTransport but with fewer parameters. Therefore probably it's best to use the method on the SipStack directly.

STUN Client

The UdpTransport class includes support for sending STUN requests to a STUN server. To use this feature you need to store a pointer to UdpTransport when adding the transport:

m_pUdpTransport = (resip::UdpTransport*)mStack->addTransport(UDP, UDPPort, V4, StunEnabled, IPAddress));

UdpTransport includes two methods for STUN client support:

bool stunSendTest(const Tuple& dest);
bool stunResult(Tuple& mappedAddress); 

The first one sends a STUN request to dest, the second one retrieves the result (if any).

Obviously this implementation is asynchronous. If you need to determine the mapped STUN address in a synchronous way (e.g. in order to make a call) you could use something similar to this:

void SendStunTest()
     if (!m_pUdpTransport) return;

     hostent* h = gethostbyname(STUNServer);
     in_addr sin_addr = *(struct in_addr*)h->h_addr;
     resip::Tuple tStunDest(sin_addr, STUNPort, UDP, Data::Empty);


     mLastStunTestTime = GetTickCount();

..for sending the STUN request and the following to retrieve a result synchronously:

resip::Tuple GetStunAddress()
    resip::Tuple mMappedAddress;


    if (!m_pUdpTransport) return mMappedAddress;

    if (!m_pUdpTransport->stunResult(mMappedAddress))
         // no valid result available, send another request

    else if ((GetTickCount() - mLastStunTestTime) > 1000 * 60 * 3) 
         // don't use a STUN response that is older than 3 minutes

    DWORD dwTmpLastStunTestTime = mLastStunTestTime;

    while ((GetTickCount() - dwTmpLastStunTestTime) < 5 * 1000) // wait 5s for result
         if (m_pUdpTransport->stunResult(mMappedAddress))

    return mMappedAddress;