stun.h File Reference

#include <iostream>
#include <time.h>

Classes

struct  UInt128
struct  StunMsgHdr
struct  StunAtrHdr
struct  StunAddress4
struct  StunAtrAddress4
struct  StunAtrChangeRequest
struct  StunAtrError
struct  StunAtrUnknown
struct  StunAtrString
struct  StunAtrIntegrity
struct  StunMessage
struct  StunMediaRelay
struct  StunServerInfo

Defines

#define STUN_VERSION   "0.96"
#define STUN_MAX_STRING   256
#define STUN_MAX_UNKNOWN_ATTRIBUTES   8
#define STUN_MAX_MESSAGE_SIZE   2048
#define STUN_PORT   3478
#define MAX_MEDIA_RELAYS   500
#define MAX_RTP_MSG_SIZE   1500
#define MEDIA_RELAY_TIMEOUT   3*60

Typedefs

typedef unsigned char UInt8
typedef unsigned short UInt16
typedef unsigned int UInt32
typedef unsigned long long UInt64
typedef int Socket

Enumerations

enum  StunHmacStatus {
  HmacUnkown = 0, HmacOK, HmacBadUserName, HmacUnkownUserName,
  HmacFailed
}
enum  NatType {
  StunTypeUnknown = 0, StunTypeFailure, StunTypeOpen, StunTypeBlocked,
  StunTypeIndependentFilter, StunTypeDependentFilter, StunTypePortDependedFilter, StunTypeDependentMapping,
  StunTypeFirewall
}

Functions

bool stunParseMessage (char *buf, unsigned int bufLen, StunMessage &message, bool verbose)
void stunBuildReqSimple (StunMessage *msg, const StunAtrString &username, bool changePort, bool changeIp, unsigned int id=0)
unsigned int stunEncodeMessage (const StunMessage &message, char *buf, unsigned int bufLen, const StunAtrString &password, bool verbose)
void stunCreateUserName (const StunAddress4 &addr, StunAtrString *username)
void stunGetUserNameAndPassword (const StunAddress4 &dest, StunAtrString *username, StunAtrString *password)
void stunCreatePassword (const StunAtrString &username, StunAtrString *password)
int stunRand ()
UInt64 stunGetSystemTimeSecs ()
bool stunParseServerName (char *serverName, StunAddress4 &stunServerAddr)
 find the IP address of a the specified stun server - return false is fails parse
bool stunParseHostName (char *peerName, UInt32 &ip, UInt16 &portVal, UInt16 defaultPort)
bool stunInitServer (StunServerInfo &info, const StunAddress4 &myAddr, const StunAddress4 &altAddr, int startMediaPort, bool verbose)
 return true if all is OK Create a media relay and do the STERN thing if startMediaPort is non-zero
void stunStopServer (StunServerInfo &info)
bool stunServerProcess (StunServerInfo &info, bool verbose)
 return true if all is OK
int stunFindLocalInterfaces (UInt32 *addresses, int maxSize)
 returns number of address found - take array or addres
void stunTest (StunAddress4 &dest, int testNum, bool verbose, StunAddress4 *srcAddr=0)
NatType stunNatType (StunAddress4 &dest, bool verbose, bool *preservePort=0, bool *hairpin=0, int port=0, StunAddress4 *sAddr=0)
std::ostream & operator<< (std::ostream &strm, const StunAddress4 &addr)
 prints a StunAddress
std::ostream & operator<< (std::ostream &strm, const UInt128 &)
bool stunServerProcessMsg (char *buf, unsigned int bufLen, StunAddress4 &from, StunAddress4 &myAddr, StunAddress4 &altAddr, StunMessage *resp, StunAddress4 *destination, StunAtrString *hmacPassword, bool *changePort, bool *changeIp, bool verbose)
int stunOpenSocket (StunAddress4 &dest, StunAddress4 *mappedAddr, int port=0, StunAddress4 *srcAddr=0, bool verbose=false)
bool stunOpenSocketPair (StunAddress4 &dest, StunAddress4 *mappedAddr, int *fd1, int *fd2, int srcPort=0, StunAddress4 *srcAddr=0, bool verbose=false)
int stunRandomPort ()
 return a random number to use as a port

Variables

const UInt8 IPv4Family = 0x01
 define a structure to hold a stun address
const UInt8 IPv6Family = 0x02
const UInt32 ChangeIpFlag = 0x04
const UInt32 ChangePortFlag = 0x02
const UInt16 MappedAddress = 0x0001
const UInt16 ResponseAddress = 0x0002
const UInt16 ChangeRequest = 0x0003
const UInt16 SourceAddress = 0x0004
const UInt16 ChangedAddress = 0x0005
const UInt16 Username = 0x0006
const UInt16 Password = 0x0007
const UInt16 MessageIntegrity = 0x0008
const UInt16 ErrorCode = 0x0009
const UInt16 UnknownAttribute = 0x000A
const UInt16 ReflectedFrom = 0x000B
const UInt16 XorMappedAddress = 0x8020
const UInt16 XorOnly = 0x0021
const UInt16 ServerName = 0x8022
const UInt16 SecondaryAddress = 0x8050
const UInt16 BindRequestMsg = 0x0001
const UInt16 BindResponseMsg = 0x0101
const UInt16 BindErrorResponseMsg = 0x0111
const UInt16 SharedSecretRequestMsg = 0x0002
const UInt16 SharedSecretResponseMsg = 0x0102
const UInt16 SharedSecretErrorResponseMsg = 0x0112


Define Documentation

#define MAX_MEDIA_RELAYS   500

#define MAX_RTP_MSG_SIZE   1500

Referenced by stunServerProcess().

#define MEDIA_RELAY_TIMEOUT   3*60

Referenced by stunServerProcess().

#define STUN_MAX_MESSAGE_SIZE   2048

#define STUN_MAX_STRING   256

#define STUN_MAX_UNKNOWN_ATTRIBUTES   8

#define STUN_PORT   3478

#define STUN_VERSION   "0.96"

Referenced by stunServerProcessMsg().


Typedef Documentation

typedef int Socket

typedef unsigned short UInt16

typedef unsigned int UInt32

typedef unsigned long long UInt64

typedef unsigned char UInt8


Enumeration Type Documentation

enum NatType

Enumerator:
StunTypeUnknown 
StunTypeFailure 
StunTypeOpen 
StunTypeBlocked 
StunTypeIndependentFilter 
StunTypeDependentFilter 
StunTypePortDependedFilter 
StunTypeDependentMapping 
StunTypeFirewall 
00179 {
00180    StunTypeUnknown=0,
00181    StunTypeFailure,
00182    StunTypeOpen,
00183    StunTypeBlocked,
00184 
00185    StunTypeIndependentFilter,
00186    StunTypeDependentFilter,
00187    StunTypePortDependedFilter,
00188    StunTypeDependentMapping,
00189 
00190    //StunTypeConeNat,
00191    //StunTypeRestrictedNat,
00192    //StunTypePortRestrictedNat,
00193    //StunTypeSymNat,
00194    
00195    StunTypeFirewall,
00196 } NatType;

Enumerator:
HmacUnkown 
HmacOK 
HmacBadUserName 
HmacUnkownUserName 
HmacFailed 
00119 {
00120    HmacUnkown=0,
00121    HmacOK,
00122    HmacBadUserName,
00123    HmacUnkownUserName,
00124    HmacFailed,
00125 } StunHmacStatus;


Function Documentation

std::ostream& operator<< ( std::ostream &  strm,
const UInt128  
)

std::ostream& operator<< ( std::ostream &  strm,
const StunAddress4 addr 
)

prints a StunAddress

void stunBuildReqSimple ( StunMessage msg,
const StunAtrString username,
bool  changePort,
bool  changeIp,
unsigned int  id = 0 
)

Referenced by stunSendTest().

01699 {
01700    assert( msg );
01701    memset( msg , 0 , sizeof(*msg) );
01702         
01703    msg->msgHdr.msgType = BindRequestMsg;
01704         
01705    for ( int i=0; i<16; i=i+4 )
01706    {
01707       assert(i+3<16);
01708       int r = stunRand();
01709       msg->msgHdr.id.octet[i+0]= r>>0;
01710       msg->msgHdr.id.octet[i+1]= r>>8;
01711       msg->msgHdr.id.octet[i+2]= r>>16;
01712       msg->msgHdr.id.octet[i+3]= r>>24;
01713    }
01714         
01715    if ( id != 0 )
01716    {
01717       msg->msgHdr.id.octet[0] = id; 
01718    }
01719         
01720    msg->hasChangeRequest = true;
01721    msg->changeRequest.value =(changeIp?ChangeIpFlag:0) | 
01722       (changePort?ChangePortFlag:0);
01723         
01724    if ( username.sizeValue > 0 )
01725    {
01726       msg->hasUsername = true;
01727       msg->username = username;
01728    }
01729 }

void stunCreatePassword ( const StunAtrString username,
StunAtrString password 
)

Referenced by stunCreateSharedSecretResponse(), stunGetUserNameAndPassword(), and stunServerProcessMsg().

00802 {
00803    char hmac[20];
00804    char key[] = "Fluffy";
00805    //char buffer[STUN_MAX_STRING];
00806    computeHmac(hmac, username.value, strlen(username.value), key, strlen(key));
00807    toHex(hmac, 20, password->value);
00808    password->sizeValue = 40;
00809    password->value[40]=0;
00810         
00811    //clog << "password=" << password->value << endl;
00812 }

void stunCreateUserName ( const StunAddress4 addr,
StunAtrString username 
)

Referenced by stunCreateSharedSecretResponse(), and stunGetUserNameAndPassword().

00764 {
00765    UInt64 time = stunGetSystemTimeSecs();
00766    time -= (time % 20*60);
00767    //UInt64 hitime = time >> 32;
00768    UInt64 lotime = time & 0xFFFFFFFF;
00769         
00770    char buffer[1024];
00771    sprintf(buffer,
00772            "%08x:%08x:%08x:", 
00773            UInt32(source.addr),
00774            UInt32(stunRand()),
00775            UInt32(lotime));
00776    assert( strlen(buffer) < 1024 );
00777         
00778    assert(strlen(buffer) + 41 < STUN_MAX_STRING);
00779         
00780    char hmac[20];
00781    char key[] = "Jason";
00782    computeHmac(hmac, buffer, strlen(buffer), key, strlen(key) );
00783    char hmacHex[41];
00784    toHex(hmac, 20, hmacHex );
00785    hmacHex[40] =0;
00786         
00787    strcat(buffer,hmacHex);
00788         
00789    int l = strlen(buffer);
00790    assert( l+1 < STUN_MAX_STRING );
00791    assert( l%4 == 0 );
00792    
00793    username->sizeValue = l;
00794    memcpy(username->value,buffer,l);
00795    username->value[l]=0;
00796         
00797    //if (verbose) clog << "computed username=" << username.value << endl;
00798 }

unsigned int stunEncodeMessage ( const StunMessage message,
char *  buf,
unsigned int  bufLen,
const StunAtrString password,
bool  verbose 
)

Referenced by stunSendTest(), and stunServerProcess().

00548 {
00549    assert(bufLen >= sizeof(StunMsgHdr));
00550    char* ptr = buf;
00551         
00552    ptr = encode16(ptr, msg.msgHdr.msgType);
00553    char* lengthp = ptr;
00554    ptr = encode16(ptr, 0);
00555    ptr = encode(ptr, reinterpret_cast<const char*>(msg.msgHdr.id.octet), sizeof(msg.msgHdr.id));
00556         
00557    if (verbose) clog << "Encoding stun message: " << endl;
00558    if (msg.hasMappedAddress)
00559    {
00560       if (verbose) clog << "Encoding MappedAddress: " << msg.mappedAddress.ipv4 << endl;
00561       ptr = encodeAtrAddress4 (ptr, MappedAddress, msg.mappedAddress);
00562    }
00563    if (msg.hasResponseAddress)
00564    {
00565       if (verbose) clog << "Encoding ResponseAddress: " << msg.responseAddress.ipv4 << endl;
00566       ptr = encodeAtrAddress4(ptr, ResponseAddress, msg.responseAddress);
00567    }
00568    if (msg.hasChangeRequest)
00569    {
00570       if (verbose) clog << "Encoding ChangeRequest: " << msg.changeRequest.value << endl;
00571       ptr = encodeAtrChangeRequest(ptr, msg.changeRequest);
00572    }
00573    if (msg.hasSourceAddress)
00574    {
00575       if (verbose) clog << "Encoding SourceAddress: " << msg.sourceAddress.ipv4 << endl;
00576       ptr = encodeAtrAddress4(ptr, SourceAddress, msg.sourceAddress);
00577    }
00578    if (msg.hasChangedAddress)
00579    {
00580       if (verbose) clog << "Encoding ChangedAddress: " << msg.changedAddress.ipv4 << endl;
00581       ptr = encodeAtrAddress4(ptr, ChangedAddress, msg.changedAddress);
00582    }
00583    if (msg.hasUsername)
00584    {
00585       if (verbose) clog << "Encoding Username: " << msg.username.value << endl;
00586       ptr = encodeAtrString(ptr, Username, msg.username);
00587    }
00588    if (msg.hasPassword)
00589    {
00590       if (verbose) clog << "Encoding Password: " << msg.password.value << endl;
00591       ptr = encodeAtrString(ptr, Password, msg.password);
00592    }
00593    if (msg.hasErrorCode)
00594    {
00595       if (verbose) clog << "Encoding ErrorCode: class=" 
00596                         << int(msg.errorCode.errorClass)  
00597                         << " number=" << int(msg.errorCode.number) 
00598                         << " reason=" 
00599                         << msg.errorCode.reason 
00600                         << endl;
00601                 
00602       ptr = encodeAtrError(ptr, msg.errorCode);
00603    }
00604    if (msg.hasUnknownAttributes)
00605    {
00606       if (verbose) clog << "Encoding UnknownAttribute: ???" << endl;
00607       ptr = encodeAtrUnknown(ptr, msg.unknownAttributes);
00608    }
00609    if (msg.hasReflectedFrom)
00610    {
00611       if (verbose) clog << "Encoding ReflectedFrom: " << msg.reflectedFrom.ipv4 << endl;
00612       ptr = encodeAtrAddress4(ptr, ReflectedFrom, msg.reflectedFrom);
00613    }
00614    if (msg.hasXorMappedAddress)
00615    {
00616       if (verbose) clog << "Encoding XorMappedAddress: " << msg.xorMappedAddress.ipv4 << endl;
00617       ptr = encodeAtrAddress4 (ptr, XorMappedAddress, msg.xorMappedAddress);
00618    }
00619    if (msg.xorOnly)
00620    {
00621       if (verbose) clog << "Encoding xorOnly: " << endl;
00622       ptr = encodeXorOnly( ptr );
00623    }
00624    if (msg.hasServerName)
00625    {
00626       if (verbose) clog << "Encoding ServerName: " << msg.serverName.value << endl;
00627       ptr = encodeAtrString(ptr, ServerName, msg.serverName);
00628    }
00629    if (msg.hasSecondaryAddress)
00630    {
00631       if (verbose) clog << "Encoding SecondaryAddress: " << msg.secondaryAddress.ipv4 << endl;
00632       ptr = encodeAtrAddress4 (ptr, SecondaryAddress, msg.secondaryAddress);
00633    }
00634 
00635    if (password.sizeValue > 0)
00636    {
00637       if (verbose) clog << "HMAC with password: " << password.value << endl;
00638                 
00639       StunAtrIntegrity integrity;
00640       computeHmac(integrity.hash, buf, int(ptr-buf) , password.value, password.sizeValue);
00641       ptr = encodeAtrIntegrity(ptr, integrity);
00642    }
00643    if (verbose) clog << endl;
00644         
00645    encode16(lengthp, UInt16(ptr - buf - sizeof(StunMsgHdr)));
00646    return int(ptr - buf);
00647 }

int stunFindLocalInterfaces ( UInt32 addresses,
int  maxSize 
)

returns number of address found - take array or addres

01630 {
01631 #if defined(WIN32) || defined(__sparc__)
01632    return 0;
01633 #else
01634    struct ifconf ifc;
01635         
01636    int s = socket( AF_INET, SOCK_DGRAM, 0 );
01637    int len = 100 * sizeof(struct ifreq);
01638         
01639    char buf[ len ];
01640         
01641    ifc.ifc_len = len;
01642    ifc.ifc_buf = buf;
01643         
01644    int e = ioctl(s,SIOCGIFCONF,&ifc);
01645    char *ptr = buf;
01646    int tl = ifc.ifc_len;
01647    int count=0;
01648         
01649    while ( (tl > 0) && ( count < maxRet) )
01650    {
01651       struct ifreq* ifr = (struct ifreq *)ptr;
01652                 
01653       int si = sizeof(ifr->ifr_name) + sizeof(struct sockaddr);
01654       tl -= si;
01655       ptr += si;
01656       //char* name = ifr->ifr_ifrn.ifrn_name;
01657       //cerr << "name = " << name << endl;
01658                 
01659       struct ifreq ifr2;
01660       ifr2 = *ifr;
01661                 
01662       e = ioctl(s,SIOCGIFADDR,&ifr2);
01663       if ( e == -1 )
01664       {
01665          break;
01666       }
01667                 
01668       //cerr << "ioctl addr e = " << e << endl;
01669                 
01670       struct sockaddr a = ifr2.ifr_addr;
01671       struct sockaddr_in* addr = (struct sockaddr_in*) &a;
01672                 
01673       UInt32 ai = ntohl( addr->sin_addr.s_addr );
01674       if (int((ai>>24)&0xFF) != 127)
01675       {
01676          addresses[count++] = ai;
01677       }
01678                 
01679 #if 0
01680       cerr << "Detected interface "
01681            << int((ai>>24)&0xFF) << "." 
01682            << int((ai>>16)&0xFF) << "." 
01683            << int((ai>> 8)&0xFF) << "." 
01684            << int((ai    )&0xFF) << endl;
01685 #endif
01686    }
01687         
01688    closesocket(s);
01689         
01690    return count;
01691 #endif
01692 }

UInt64 stunGetSystemTimeSecs (  ) 

Referenced by stunCreateUserName().

00817 {
00818    UInt64 time=0;
00819 #if defined(WIN32)  
00820    SYSTEMTIME t;
00821    // CJ TODO - this probably has bug on wrap around every 24 hours
00822    GetSystemTime( &t );
00823    time = (t.wHour*60+t.wMinute)*60+t.wSecond; 
00824 #else
00825    struct timeval now;
00826    gettimeofday( &now , NULL );
00827    //assert( now );
00828    time = now.tv_sec;
00829 #endif
00830    return time;
00831 }

void stunGetUserNameAndPassword ( const StunAddress4 dest,
StunAtrString username,
StunAtrString password 
)

Referenced by stunNatType(), stunOpenSocket(), stunOpenSocketPair(), and stunTest().

01803 { 
01804    // !cj! This is totally bogus - need to make TLS connection to dest and get a
01805    // username and password to use 
01806    stunCreateUserName(dest, username);
01807    stunCreatePassword(*username, password);
01808 }

bool stunInitServer ( StunServerInfo info,
const StunAddress4 myAddr,
const StunAddress4 altAddr,
int  startMediaPort,
bool  verbose 
)

return true if all is OK Create a media relay and do the STERN thing if startMediaPort is non-zero

01250 {
01251    assert( myAddr.port != 0 );
01252    assert( altAddr.port!= 0 );
01253    assert( myAddr.addr  != 0 );
01254    //assert( altAddr.addr != 0 );
01255         
01256    info.myAddr = myAddr;
01257    info.altAddr = altAddr;
01258         
01259    info.myFd = INVALID_SOCKET;
01260    info.altPortFd = INVALID_SOCKET;
01261    info.altIpFd = INVALID_SOCKET;
01262    info.altIpPortFd = INVALID_SOCKET;
01263 
01264    memset(info.relays, 0, sizeof(info.relays));
01265    if (startMediaPort > 0)
01266    {
01267       info.relay = true;
01268 
01269       for (int i=0; i<MAX_MEDIA_RELAYS; ++i)
01270       {
01271          StunMediaRelay* relay = &info.relays[i];
01272          relay->relayPort = startMediaPort+i;
01273          relay->fd = 0;
01274          relay->expireTime = 0;
01275       }
01276    }
01277    else
01278    {
01279       info.relay = false;
01280    }
01281    
01282    if ((info.myFd = openPort(myAddr.port, myAddr.addr,verbose)) == INVALID_SOCKET)
01283    {
01284       clog << "Can't open " << myAddr << endl;
01285       stunStopServer(info);
01286 
01287       return false;
01288    }
01289    //if (verbose) clog << "Opened " << myAddr.addr << ":" << myAddr.port << " --> " << info.myFd << endl;
01290 
01291    if ((info.altPortFd = openPort(altAddr.port,myAddr.addr,verbose)) == INVALID_SOCKET)
01292    {
01293       clog << "Can't open " << myAddr << endl;
01294       stunStopServer(info);
01295       return false;
01296    }
01297    //if (verbose) clog << "Opened " << myAddr.addr << ":" << altAddr.port << " --> " << info.altPortFd << endl;
01298    
01299    
01300    info.altIpFd = INVALID_SOCKET;
01301    if (  altAddr.addr != 0 )
01302    {
01303       if ((info.altIpFd = openPort( myAddr.port, altAddr.addr,verbose)) == INVALID_SOCKET)
01304       {
01305          clog << "Can't open " << altAddr << endl;
01306          stunStopServer(info);
01307          return false;
01308       }
01309       //if (verbose) clog << "Opened " << altAddr.addr << ":" << myAddr.port << " --> " << info.altIpFd << endl;;
01310    }
01311    
01312    info.altIpPortFd = INVALID_SOCKET;
01313    if (  altAddr.addr != 0 )
01314    {  if ((info.altIpPortFd = openPort(altAddr.port, altAddr.addr,verbose)) == INVALID_SOCKET)
01315       {
01316          clog << "Can't open " << altAddr << endl;
01317          stunStopServer(info);
01318          return false;
01319       }
01320       //if (verbose) clog << "Opened " << altAddr.addr << ":" << altAddr.port << " --> " << info.altIpPortFd << endl;;
01321    }
01322    
01323    return true;
01324 }

NatType stunNatType ( StunAddress4 dest,
bool  verbose,
bool *  preservePort = 0,
bool *  hairpin = 0,
int  port = 0,
StunAddress4 sAddr = 0 
)

Referenced by SingleHostConfigurator::initializeUnderlay().

01882 { 
01883    assert( dest.addr != 0 );
01884    assert( dest.port != 0 );
01885         
01886    if ( hairpin ) 
01887    {
01888       *hairpin = false;
01889    }
01890         
01891    if ( port == 0 )
01892    {
01893       port = stunRandomPort();
01894    }
01895    UInt32 interfaceIp=0;
01896    if (sAddr)
01897    {
01898       interfaceIp = sAddr->addr;
01899    }
01900    Socket myFd1 = openPort(port,interfaceIp,verbose);
01901    Socket myFd2 = openPort(port+1,interfaceIp,verbose);
01902 
01903    if ( ( myFd1 == INVALID_SOCKET) || ( myFd2 == INVALID_SOCKET) )
01904    {
01905         cerr << "Some problem opening port/interface to send on" << endl;
01906        return StunTypeFailure; 
01907    }
01908 
01909    assert( myFd1 != INVALID_SOCKET );
01910    assert( myFd2 != INVALID_SOCKET );
01911     
01912    bool respTestI=false;
01913    bool isNat=true;
01914    StunAddress4 testIchangedAddr;
01915    StunAddress4 testImappedAddr;
01916    bool respTestI2=false; 
01917    bool mappedIpSame = true;
01918    StunAddress4 testI2mappedAddr;
01919    StunAddress4 testI2dest=dest;
01920    bool respTestII=false;
01921    bool respTestIII=false;
01922 
01923    bool respTestHairpin=false;
01924    bool respTestPreservePort=false;
01925         
01926    memset(&testImappedAddr,0,sizeof(testImappedAddr));
01927         
01928    StunAtrString username;
01929    StunAtrString password;
01930         
01931    username.sizeValue = 0;
01932    password.sizeValue = 0;
01933         
01934 #ifdef USE_TLS 
01935    stunGetUserNameAndPassword( dest, username, password );
01936 #endif
01937         
01938    int count=0;
01939    while ( count < 7 )
01940    {
01941       struct timeval tv;
01942       fd_set fdSet; 
01943 #ifdef WIN32
01944       unsigned int fdSetSize;
01945 #else
01946       int fdSetSize;
01947 #endif
01948       FD_ZERO(&fdSet); fdSetSize=0;
01949       FD_SET(myFd1,&fdSet); fdSetSize = (myFd1+1>fdSetSize) ? myFd1+1 : fdSetSize;
01950       FD_SET(myFd2,&fdSet); fdSetSize = (myFd2+1>fdSetSize) ? myFd2+1 : fdSetSize;
01951       tv.tv_sec=0;
01952       tv.tv_usec=150*1000; // 150 ms 
01953       if ( count == 0 ) tv.tv_usec=0;
01954                 
01955       int  err = select(fdSetSize, &fdSet, NULL, NULL, &tv);
01956       int e = getErrno();
01957       if ( err == SOCKET_ERROR )
01958       {
01959          // error occured
01960          cerr << "Error " << e << " " << strerror(e) << " in select" << endl;
01961         return StunTypeFailure; 
01962      }
01963       else if ( err == 0 )
01964       {
01965          // timeout occured 
01966          count++;
01967                         
01968          if ( !respTestI ) 
01969          {
01970             stunSendTest( myFd1, dest, username, password, 1 ,verbose );
01971          }         
01972                         
01973          if ( (!respTestI2) && respTestI ) 
01974          {
01975             // check the address to send to if valid 
01976             if (  ( testI2dest.addr != 0 ) &&
01977                   ( testI2dest.port != 0 ) )
01978             {
01979                stunSendTest( myFd1, testI2dest, username, password, 10  ,verbose);
01980             }
01981          }
01982                         
01983          if ( !respTestII )
01984          {
01985             stunSendTest( myFd2, dest, username, password, 2 ,verbose );
01986          }
01987                         
01988          if ( !respTestIII )
01989          {
01990             stunSendTest( myFd2, dest, username, password, 3 ,verbose );
01991          }
01992                         
01993          if ( respTestI && (!respTestHairpin) )
01994          {
01995             if (  ( testImappedAddr.addr != 0 ) &&
01996                   ( testImappedAddr.port != 0 ) )
01997             {
01998                stunSendTest( myFd1, testImappedAddr, username, password, 11 ,verbose );
01999             }
02000          }
02001       }
02002       else
02003       {
02004          //if (verbose) clog << "-----------------------------------------" << endl;
02005          assert( err>0 );
02006          // data is avialbe on some fd 
02007                         
02008          for ( int i=0; i<2; i++)
02009          {
02010             Socket myFd;
02011             if ( i==0 ) 
02012             {
02013                myFd=myFd1;
02014             }
02015             else
02016             {
02017                myFd=myFd2;
02018             }
02019                                 
02020             if ( myFd!=INVALID_SOCKET ) 
02021             {                                   
02022                if ( FD_ISSET(myFd,&fdSet) )
02023                {
02024                   char msg[STUN_MAX_MESSAGE_SIZE];
02025                   int msgLen = sizeof(msg);
02026                                                                 
02027                   StunAddress4 from;
02028                                                 
02029                   getMessage( myFd,
02030                               msg,
02031                               &msgLen,
02032                               &from.addr,
02033                               &from.port,verbose );
02034                                                 
02035                   StunMessage resp;
02036                   memset(&resp, 0, sizeof(StunMessage));
02037                                                 
02038                   stunParseMessage( msg,msgLen, resp,verbose );
02039                                                 
02040                   if ( verbose )
02041                   {
02042                      clog << "Received message of type " << resp.msgHdr.msgType 
02043                           << "  id=" << (int)(resp.msgHdr.id.octet[0]) << endl;
02044                   }
02045                                                 
02046                   switch( resp.msgHdr.id.octet[0] )
02047                   {
02048                      case 1:
02049                      {
02050                         if ( !respTestI )
02051                         {
02052                                                                         
02053                            testIchangedAddr.addr = resp.changedAddress.ipv4.addr;
02054                            testIchangedAddr.port = resp.changedAddress.ipv4.port;
02055                            testImappedAddr.addr = resp.mappedAddress.ipv4.addr;
02056                            testImappedAddr.port = resp.mappedAddress.ipv4.port;
02057                         
02058                            respTestPreservePort = ( testImappedAddr.port == port ); 
02059                            if ( preservePort )
02060                            {
02061                               *preservePort = respTestPreservePort;
02062                            }                                                            
02063                                                                         
02064                            testI2dest.addr = resp.changedAddress.ipv4.addr;
02065                                                                         
02066                            if (sAddr)
02067                            {
02068                               sAddr->port = testImappedAddr.port;
02069                               sAddr->addr = testImappedAddr.addr;
02070                            }
02071                                                                         
02072                            count = 0;
02073                         }               
02074                         respTestI=true;
02075                      }
02076                      break;
02077                      case 2:
02078                      {  
02079                         respTestII=true;
02080                      }
02081                      break;
02082                      case 3:
02083                      {
02084                         respTestIII=true;
02085                      }
02086                      break;
02087                      case 10:
02088                      {
02089                         if ( !respTestI2 )
02090                         {
02091                            testI2mappedAddr.addr = resp.mappedAddress.ipv4.addr;
02092                            testI2mappedAddr.port = resp.mappedAddress.ipv4.port;
02093                                                                 
02094                            mappedIpSame = false;
02095                            if ( (testI2mappedAddr.addr  == testImappedAddr.addr ) &&
02096                                 (testI2mappedAddr.port == testImappedAddr.port ))
02097                            { 
02098                               mappedIpSame = true;
02099                            }
02100                                                                 
02101                                                         
02102                         }
02103                         respTestI2=true;
02104                      }
02105                      break;
02106                      case 11:
02107                      {
02108                                                         
02109                         if ( hairpin ) 
02110                         {
02111                            *hairpin = true;
02112                         }
02113                         respTestHairpin = true;
02114                      }
02115                      break;
02116                   }
02117                }
02118             }
02119          }
02120       }
02121    }
02122         
02123    // see if we can bind to this address 
02124    //cerr << "try binding to " << testImappedAddr << endl;
02125    Socket s = openPort( 0/*use ephemeral*/, testImappedAddr.addr, false );
02126    if ( s != INVALID_SOCKET )
02127    {
02128       closesocket(s);
02129       isNat = false;
02130       //cerr << "binding worked" << endl;
02131    }
02132    else
02133    {
02134       isNat = true;
02135       //cerr << "binding failed" << endl;
02136    }
02137         
02138    if (verbose)
02139    {
02140       clog << "test I = " << respTestI << endl;
02141       clog << "test II = " << respTestII << endl;
02142       clog << "test III = " << respTestIII << endl;
02143       clog << "test I(2) = " << respTestI2 << endl;
02144       clog << "is nat  = " << isNat <<endl;
02145       clog << "mapped IP same = " << mappedIpSame << endl;
02146       clog << "hairpin = " << respTestHairpin << endl;
02147       clog << "preserver port = " << respTestPreservePort << endl;
02148    }
02149         
02150 #if 0
02151    // implement logic flow chart from draft RFC
02152    if ( respTestI )
02153    {
02154       if ( isNat )
02155       {
02156          if (respTestII)
02157          {
02158             return StunTypeConeNat;
02159          }
02160          else
02161          {
02162             if ( mappedIpSame )
02163             {
02164                if ( respTestIII )
02165                {
02166                   return StunTypeRestrictedNat;
02167                }
02168                else
02169                {
02170                   return StunTypePortRestrictedNat;
02171                }
02172             }
02173             else
02174             {
02175                return StunTypeSymNat;
02176             }
02177          }
02178       }
02179       else
02180       {
02181          if (respTestII)
02182          {
02183             return StunTypeOpen;
02184          }
02185          else
02186          {
02187             return StunTypeSymFirewall;
02188          }
02189       }
02190    }
02191    else
02192    {
02193       return StunTypeBlocked;
02194    }
02195 #else
02196    if ( respTestI ) // not blocked 
02197    {
02198       if ( isNat )
02199       {
02200          if ( mappedIpSame )
02201          {
02202             if (respTestII)
02203             {
02204                return StunTypeIndependentFilter;
02205             }
02206             else
02207             {
02208                if ( respTestIII )
02209                {
02210                   return StunTypeDependentFilter;
02211                }
02212                else
02213                {
02214                   return StunTypePortDependedFilter;
02215                }
02216             }
02217          }
02218          else // mappedIp is not same 
02219          {
02220             return StunTypeDependentMapping;
02221          }
02222       }
02223       else  // isNat is false
02224       {
02225          if (respTestII)
02226          {
02227             return StunTypeOpen;
02228          }
02229          else
02230          {
02231             return StunTypeFirewall;
02232          }
02233       }
02234    }
02235    else
02236    {
02237       return StunTypeBlocked;
02238    }
02239 #endif
02240         
02241    return StunTypeUnknown;
02242 }

int stunOpenSocket ( StunAddress4 dest,
StunAddress4 mappedAddr,
int  port = 0,
StunAddress4 srcAddr = 0,
bool  verbose = false 
)

02249 {
02250    assert( dest.addr != 0 );
02251    assert( dest.port != 0 );
02252    assert( mapAddr );
02253    
02254    if ( port == 0 )
02255    {
02256       port = stunRandomPort();
02257    }
02258    unsigned int interfaceIp = 0;
02259    if ( srcAddr )
02260    {
02261       interfaceIp = srcAddr->addr;
02262    }
02263    
02264    Socket myFd = openPort(port,interfaceIp,verbose);
02265    if (myFd == INVALID_SOCKET)
02266    {
02267       return myFd;
02268    }
02269    
02270    char msg[STUN_MAX_MESSAGE_SIZE];
02271    int msgLen = sizeof(msg);
02272         
02273    StunAtrString username;
02274    StunAtrString password;
02275         
02276    username.sizeValue = 0;
02277    password.sizeValue = 0;
02278         
02279 #ifdef USE_TLS
02280    stunGetUserNameAndPassword( dest, username, password );
02281 #endif
02282         
02283    stunSendTest(myFd, dest, username, password, 1, 0/*false*/ );
02284         
02285    StunAddress4 from;
02286         
02287    getMessage( myFd, msg, &msgLen, &from.addr, &from.port,verbose );
02288         
02289    StunMessage resp;
02290    memset(&resp, 0, sizeof(StunMessage));
02291         
02292    bool ok = stunParseMessage( msg, msgLen, resp,verbose );
02293    if (!ok)
02294    {
02295       return -1;
02296    }
02297         
02298    StunAddress4 mappedAddr = resp.mappedAddress.ipv4;
02299    StunAddress4 changedAddr = resp.changedAddress.ipv4;
02300         
02301    //clog << "--- stunOpenSocket --- " << endl;
02302    //clog << "\treq  id=" << req.id << endl;
02303    //clog << "\tresp id=" << id << endl;
02304    //clog << "\tmappedAddr=" << mappedAddr << endl;
02305         
02306    *mapAddr = mappedAddr;
02307         
02308    return myFd;
02309 }

bool stunOpenSocketPair ( StunAddress4 dest,
StunAddress4 mappedAddr,
int *  fd1,
int *  fd2,
int  srcPort = 0,
StunAddress4 srcAddr = 0,
bool  verbose = false 
)

02317 {
02318    assert( dest.addr!= 0 );
02319    assert( dest.port != 0 );
02320    assert( mapAddr );
02321    
02322    const int NUM=3;
02323         
02324    if ( port == 0 )
02325    {
02326       port = stunRandomPort();
02327    }
02328         
02329    *fd1=-1;
02330    *fd2=-1;
02331         
02332    char msg[STUN_MAX_MESSAGE_SIZE];
02333    int msgLen =sizeof(msg);
02334         
02335    StunAddress4 from;
02336    int fd[NUM];
02337    int i;
02338         
02339    unsigned int interfaceIp = 0;
02340    if ( srcAddr )
02341    {
02342       interfaceIp = srcAddr->addr;
02343    }
02344 
02345    for( i=0; i<NUM; i++)
02346    {
02347       fd[i] = openPort( (port == 0) ? 0 : (port + i), 
02348                         interfaceIp, verbose);
02349       if (fd[i] < 0) 
02350       {
02351          while (i > 0)
02352          {
02353             closesocket(fd[--i]);
02354          }
02355          return false;
02356       }
02357    }
02358         
02359    StunAtrString username;
02360    StunAtrString password;
02361         
02362    username.sizeValue = 0;
02363    password.sizeValue = 0;
02364         
02365 #ifdef USE_TLS
02366    stunGetUserNameAndPassword( dest, username, password );
02367 #endif
02368         
02369    for( i=0; i<NUM; i++)
02370    {
02371       stunSendTest(fd[i], dest, username, password, 1/*testNum*/, verbose );
02372    }
02373         
02374    StunAddress4 mappedAddr[NUM];
02375    for( i=0; i<NUM; i++)
02376    {
02377       msgLen = sizeof(msg)/sizeof(*msg);
02378       getMessage( fd[i],
02379                   msg,
02380                   &msgLen,
02381                   &from.addr,
02382                   &from.port ,verbose);
02383                 
02384       StunMessage resp;
02385       memset(&resp, 0, sizeof(StunMessage));
02386                 
02387       bool ok = stunParseMessage( msg, msgLen, resp, verbose );
02388       if (!ok) 
02389       {
02390          return false;
02391       }
02392                 
02393       mappedAddr[i] = resp.mappedAddress.ipv4;
02394       StunAddress4 changedAddr = resp.changedAddress.ipv4;
02395    }
02396         
02397    if (verbose)
02398    {               
02399       clog << "--- stunOpenSocketPair --- " << endl;
02400       for( i=0; i<NUM; i++)
02401       {
02402          clog << "\t mappedAddr=" << mappedAddr[i] << endl;
02403       }
02404    }
02405         
02406    if ( mappedAddr[0].port %2 == 0 )
02407    {
02408       if (  mappedAddr[0].port+1 ==  mappedAddr[1].port )
02409       {
02410          *mapAddr = mappedAddr[0];
02411          *fd1 = fd[0];
02412          *fd2 = fd[1];
02413          closesocket( fd[2] );
02414          return true;
02415       }
02416    }
02417    else
02418    {
02419       if (( mappedAddr[1].port %2 == 0 )
02420           && (  mappedAddr[1].port+1 ==  mappedAddr[2].port ))
02421       {
02422          *mapAddr = mappedAddr[1];
02423          *fd1 = fd[1];
02424          *fd2 = fd[2];
02425          closesocket( fd[0] );
02426          return true;
02427       }
02428    }
02429 
02430    // something failed, close all and return error
02431    for( i=0; i<NUM; i++)
02432    {
02433       closesocket( fd[i] );
02434    }
02435         
02436    return false;
02437 }

bool stunParseHostName ( char *  peerName,
UInt32 ip,
UInt16 portVal,
UInt16  defaultPort 
)

Referenced by stunParseServerName().

00866 {
00867    in_addr sin_addr;
00868     
00869    char host[512];
00870    strncpy(host,peerName,512);
00871    host[512-1]='\0';
00872    char* port = NULL;
00873         
00874    int portNum = defaultPort;
00875         
00876    // pull out the port part if present.
00877    char* sep = strchr(host,':');
00878         
00879    if ( sep == NULL )
00880    {
00881       portNum = defaultPort;
00882    }
00883    else
00884    {
00885       *sep = '\0';
00886       port = sep + 1;
00887       // set port part
00888                 
00889       char* endPtr=NULL;
00890                 
00891       portNum = strtol(port,&endPtr,10);
00892                 
00893       if ( endPtr != NULL )
00894       {
00895          if ( *endPtr != '\0' )
00896          {
00897             portNum = defaultPort;
00898          }
00899       }
00900    }
00901     
00902    if ( portNum < 1024 ) return false;
00903    if ( portNum >= 0xFFFF ) return false;
00904         
00905    // figure out the host part 
00906    struct hostent* h;
00907         
00908 #ifdef WIN32
00909    assert( strlen(host) >= 1 );
00910    if ( isdigit( host[0] ) )
00911    {
00912       // assume it is a ip address 
00913       unsigned long a = inet_addr(host);
00914       //cerr << "a=0x" << hex << a << dec << endl;
00915                 
00916       ip = ntohl( a );
00917    }
00918    else
00919    {
00920       // assume it is a host name 
00921       h = gethostbyname( host );
00922                 
00923       if ( h == NULL )
00924       {
00925          int err = getErrno();
00926          std::cerr << "error was " << err << std::endl;
00927          assert( err != WSANOTINITIALISED );
00928                         
00929          ip = ntohl( 0x7F000001L );
00930                         
00931          return false;
00932       }
00933       else
00934       {
00935          sin_addr = *(struct in_addr*)h->h_addr;
00936          ip = ntohl( sin_addr.s_addr );
00937       }
00938    }
00939         
00940 #else
00941    h = gethostbyname( host );
00942    if ( h == NULL )
00943    {
00944       int err = getErrno();
00945       std::cerr << "error was " << err << std::endl;
00946       ip = ntohl( 0x7F000001L );
00947       return false;
00948    }
00949    else
00950    {
00951       sin_addr = *(struct in_addr*)h->h_addr;
00952       ip = ntohl( sin_addr.s_addr );
00953    }
00954 #endif
00955         
00956    portVal = portNum;
00957         
00958    return true;
00959 }

bool stunParseMessage ( char *  buf,
unsigned int  bufLen,
StunMessage message,
bool  verbose 
)

Referenced by stunNatType(), stunOpenSocket(), stunOpenSocketPair(), stunServerProcessMsg(), and stunTest().

00183 {
00184    if (verbose) clog << "Received stun message: " << bufLen << " bytes" << endl;
00185    memset(&msg, 0, sizeof(msg));
00186         
00187    if (sizeof(StunMsgHdr) > bufLen)
00188    {
00189       clog << "Bad message" << endl;
00190       return false;
00191    }
00192         
00193    memcpy(&msg.msgHdr, buf, sizeof(StunMsgHdr));
00194    msg.msgHdr.msgType = ntohs(msg.msgHdr.msgType);
00195    msg.msgHdr.msgLength = ntohs(msg.msgHdr.msgLength);
00196         
00197    if (msg.msgHdr.msgLength + sizeof(StunMsgHdr) != bufLen)
00198    {
00199       clog << "Message header length doesn't match message size: "
00200            << msg.msgHdr.msgLength << " - " << bufLen << endl;
00201       return false;
00202    }
00203         
00204    char* body = buf + sizeof(StunMsgHdr);
00205    unsigned int size = msg.msgHdr.msgLength;
00206         
00207    //clog << "bytes after header = " << size << endl;
00208         
00209    while ( size > 0 )
00210    {
00211       // !jf! should check that there are enough bytes left in the buffer
00212                 
00213       StunAtrHdr* attr = reinterpret_cast<StunAtrHdr*>(body);
00214                 
00215       unsigned int attrLen = ntohs(attr->length);
00216       int atrType = ntohs(attr->type);
00217                 
00218       //if (verbose) clog << "Found attribute type=" << AttrNames[atrType] << " length=" << attrLen << endl;
00219       if ( attrLen+4 > size ) 
00220       {
00221          clog << "claims attribute is larger than size of message " 
00222               <<"(attribute type="<<atrType<<")"<< endl;
00223          return false;
00224       }
00225                 
00226       body += 4; // skip the length and type in attribute header
00227       size -= 4;
00228                 
00229       switch ( atrType )
00230       {
00231          case MappedAddress:
00232             msg.hasMappedAddress = true;
00233             if ( stunParseAtrAddress(  body,  attrLen,  msg.mappedAddress )== false )
00234             {
00235                clog << "problem parsing MappedAddress" << endl;
00236                return false;
00237             }
00238             else
00239             {
00240                if (verbose) clog << "MappedAddress = " << msg.mappedAddress.ipv4 << endl;
00241             }
00242                                         
00243             break;  
00244 
00245          case ResponseAddress:
00246             msg.hasResponseAddress = true;
00247             if ( stunParseAtrAddress(  body,  attrLen,  msg.responseAddress )== false )
00248             {
00249                clog << "problem parsing ResponseAddress" << endl;
00250                return false;
00251             }
00252             else
00253             {
00254                if (verbose) clog << "ResponseAddress = " << msg.responseAddress.ipv4 << endl;
00255             }
00256             break;  
00257                                 
00258          case ChangeRequest:
00259             msg.hasChangeRequest = true;
00260             if (stunParseAtrChangeRequest( body, attrLen, msg.changeRequest) == false)
00261             {
00262                clog << "problem parsing ChangeRequest" << endl;
00263                return false;
00264             }
00265             else
00266             {
00267                if (verbose) clog << "ChangeRequest = " << msg.changeRequest.value << endl;
00268             }
00269             break;
00270                                 
00271          case SourceAddress:
00272             msg.hasSourceAddress = true;
00273             if ( stunParseAtrAddress(  body,  attrLen,  msg.sourceAddress )== false )
00274             {
00275                clog << "problem parsing SourceAddress" << endl;
00276                return false;
00277             }
00278             else
00279             {
00280                if (verbose) clog << "SourceAddress = " << msg.sourceAddress.ipv4 << endl;
00281             }
00282             break;  
00283                                 
00284          case ChangedAddress:
00285             msg.hasChangedAddress = true;
00286             if ( stunParseAtrAddress(  body,  attrLen,  msg.changedAddress )== false )
00287             {
00288                clog << "problem parsing ChangedAddress" << endl;
00289                return false;
00290             }
00291             else
00292             {
00293                if (verbose) clog << "ChangedAddress = " << msg.changedAddress.ipv4 << endl;
00294             }
00295             break;  
00296                                 
00297          case Username: 
00298             msg.hasUsername = true;
00299             if (stunParseAtrString( body, attrLen, msg.username) == false)
00300             {
00301                clog << "problem parsing Username" << endl;
00302                return false;
00303             }
00304             else
00305             {
00306                if (verbose) clog << "Username = " << msg.username.value << endl;
00307             }
00308                                         
00309             break;
00310                                 
00311          case Password: 
00312             msg.hasPassword = true;
00313             if (stunParseAtrString( body, attrLen, msg.password) == false)
00314             {
00315                clog << "problem parsing Password" << endl;
00316                return false;
00317             }
00318             else
00319             {
00320                if (verbose) clog << "Password = " << msg.password.value << endl;
00321             }
00322             break;
00323                                 
00324          case MessageIntegrity:
00325             msg.hasMessageIntegrity = true;
00326             if (stunParseAtrIntegrity( body, attrLen, msg.messageIntegrity) == false)
00327             {
00328                clog << "problem parsing MessageIntegrity" << endl;
00329                return false;
00330             }
00331             else
00332             {
00333                //if (verbose) clog << "MessageIntegrity = " << msg.messageIntegrity.hash << endl;
00334             }
00335                                         
00336             // read the current HMAC
00337             // look up the password given the user of given the transaction id 
00338             // compute the HMAC on the buffer
00339             // decide if they match or not
00340             break;
00341                                 
00342          case ErrorCode:
00343             msg.hasErrorCode = true;
00344             if (stunParseAtrError(body, attrLen, msg.errorCode) == false)
00345             {
00346                clog << "problem parsing ErrorCode" << endl;
00347                return false;
00348             }
00349             else
00350             {
00351                if (verbose) clog << "ErrorCode = " << int(msg.errorCode.errorClass) 
00352                                  << " " << int(msg.errorCode.number) 
00353                                  << " " << msg.errorCode.reason << endl;
00354             }
00355                                         
00356             break;
00357                                 
00358          case UnknownAttribute:
00359             msg.hasUnknownAttributes = true;
00360             if (stunParseAtrUnknown(body, attrLen, msg.unknownAttributes) == false)
00361             {
00362                clog << "problem parsing UnknownAttribute" << endl;
00363                return false;
00364             }
00365             break;
00366                                 
00367          case ReflectedFrom:
00368             msg.hasReflectedFrom = true;
00369             if ( stunParseAtrAddress(  body,  attrLen,  msg.reflectedFrom ) == false )
00370             {
00371                clog << "problem parsing ReflectedFrom" << endl;
00372                return false;
00373             }
00374             break;  
00375                                 
00376          case XorMappedAddress:
00377             msg.hasXorMappedAddress = true;
00378             if ( stunParseAtrAddress(  body,  attrLen,  msg.xorMappedAddress ) == false )
00379             {
00380                clog << "problem parsing XorMappedAddress" << endl;
00381                return false;
00382             }
00383             else
00384             {
00385                if (verbose) clog << "XorMappedAddress = " << msg.mappedAddress.ipv4 << endl;
00386             }
00387             break;  
00388 
00389          case XorOnly:
00390             msg.xorOnly = true;
00391             if (verbose) 
00392             {
00393                clog << "xorOnly = true" << endl;
00394             }
00395             break;  
00396                                 
00397          case ServerName: 
00398             msg.hasServerName = true;
00399             if (stunParseAtrString( body, attrLen, msg.serverName) == false)
00400             {
00401                clog << "problem parsing ServerName" << endl;
00402                return false;
00403             }
00404             else
00405             {
00406                if (verbose) clog << "ServerName = " << msg.serverName.value << endl;
00407             }
00408             break;
00409                                 
00410          case SecondaryAddress:
00411             msg.hasSecondaryAddress = true;
00412             if ( stunParseAtrAddress(  body,  attrLen,  msg.secondaryAddress ) == false )
00413             {
00414                clog << "problem parsing secondaryAddress" << endl;
00415                return false;
00416             }
00417             else
00418             {
00419                if (verbose) clog << "SecondaryAddress = " << msg.secondaryAddress.ipv4 << endl;
00420             }
00421             break;  
00422                                         
00423          default:
00424             if (verbose) clog << "Unknown attribute: " << atrType << endl;
00425             if ( atrType <= 0x7FFF ) 
00426             {
00427                return false;
00428             }
00429       }
00430                 
00431       body += attrLen;
00432       size -= attrLen;
00433    }
00434     
00435    return true;
00436 }

bool stunParseServerName ( char *  serverName,
StunAddress4 stunServerAddr 
)

find the IP address of a the specified stun server - return false is fails parse

Referenced by SingleHostConfigurator::initializeUnderlay().

00964 {
00965    assert(name);
00966         
00967    // TODO - put in DNS SRV stuff.
00968         
00969    bool ret = stunParseHostName( name, addr.addr, addr.port, 3478); 
00970    if ( ret != true ) 
00971    {
00972        addr.port=0xFFFF;
00973    }    
00974    return ret;
00975 }

int stunRand (  ) 

Referenced by stunBuildReqSimple(), stunCreateUserName(), and stunRandomPort().

00651 {
00652    // return 32 bits of random stuff
00653    assert( sizeof(int) == 4 );
00654    static bool init=false;
00655    if ( !init )
00656    { 
00657       init = true;
00658                 
00659       UInt64 tick;
00660                 
00661 #if defined(WIN32) 
00662       volatile unsigned int lowtick=0,hightick=0;
00663       __asm
00664          {
00665             rdtsc 
00666                mov lowtick, eax
00667                mov hightick, edx
00668                }
00669       tick = hightick;
00670       tick <<= 32;
00671       tick |= lowtick;
00672 #elif defined(__GNUC__) && ( defined(__i686__) || defined(__i386__) || defined(__x86_64__) )
00673       asm("rdtsc" : "=A" (tick));
00674 #elif defined (__SUNPRO_CC) || defined( __sparc__ )     
00675       tick = gethrtime();
00676 #elif defined(__MACH__) 
00677       int fd=open("/dev/random",O_RDONLY);
00678       read(fd,&tick,sizeof(tick));
00679       closesocket(fd);
00680 #else
00681 #     error Need some way to seed the random number generator 
00682 #endif 
00683       int seed = int(tick);
00684 #ifdef WIN32
00685       srand(seed);
00686 #else
00687       srandom(seed);
00688 #endif
00689    }
00690         
00691 #ifdef WIN32
00692    assert( RAND_MAX == 0x7fff );
00693    int r1 = rand();
00694    int r2 = rand();
00695         
00696    int ret = (r1<<16) + r2;
00697         
00698    return ret;
00699 #else
00700    return random(); 
00701 #endif
00702 }

int stunRandomPort (  ) 

return a random number to use as a port

Referenced by stunNatType(), stunOpenSocket(), stunOpenSocketPair(), and stunTest().

00708 {
00709    int min=0x4000;
00710    int max=0x7FFF;
00711         
00712    int ret = stunRand();
00713    ret = ret|min;
00714    ret = ret&max;
00715         
00716    return ret;
00717 }

bool stunServerProcess ( StunServerInfo info,
bool  verbose 
)

return true if all is OK

01351 {
01352    char msg[STUN_MAX_MESSAGE_SIZE];
01353    int msgLen = sizeof(msg);
01354         
01355    bool ok = false;
01356    bool recvAltIp =false;
01357    bool recvAltPort = false;
01358         
01359    fd_set fdSet; 
01360    Socket maxFd=0;
01361 
01362    FD_ZERO(&fdSet); 
01363    FD_SET(info.myFd,&fdSet); 
01364    if ( info.myFd >= maxFd ) maxFd=info.myFd+1;
01365    FD_SET(info.altPortFd,&fdSet); 
01366    if ( info.altPortFd >= maxFd ) maxFd=info.altPortFd+1;
01367 
01368    if ( info.altIpFd != INVALID_SOCKET )
01369    {
01370       FD_SET(info.altIpFd,&fdSet);
01371       if (info.altIpFd>=maxFd) maxFd=info.altIpFd+1;
01372    }
01373    if ( info.altIpPortFd != INVALID_SOCKET )
01374    {
01375       FD_SET(info.altIpPortFd,&fdSet);
01376       if (info.altIpPortFd>=maxFd) maxFd=info.altIpPortFd+1;
01377    }
01378 
01379    if (info.relay)
01380    {
01381       for (int i=0; i<MAX_MEDIA_RELAYS; ++i)
01382       {
01383          StunMediaRelay* relay = &info.relays[i];
01384          if (relay->fd)
01385          {
01386             FD_SET(relay->fd, &fdSet);
01387             if (relay->fd >= maxFd) 
01388                         {
01389                                 maxFd=relay->fd+1;
01390                         }
01391          }
01392       }
01393    }
01394    
01395    if ( info.altIpFd != INVALID_SOCKET )
01396    {
01397       FD_SET(info.altIpFd,&fdSet);
01398       if (info.altIpFd>=maxFd) maxFd=info.altIpFd+1;
01399    }
01400    if ( info.altIpPortFd != INVALID_SOCKET )
01401    {
01402       FD_SET(info.altIpPortFd,&fdSet);
01403       if (info.altIpPortFd>=maxFd) maxFd=info.altIpPortFd+1;
01404    }
01405    
01406    struct timeval tv;
01407    tv.tv_sec = 0;
01408    tv.tv_usec = 1000;
01409         
01410    int e = select( maxFd, &fdSet, NULL,NULL, &tv );
01411    if (e < 0)
01412    {
01413       int err = getErrno();
01414       clog << "Error on select: " << strerror(err) << endl;
01415    }
01416    else if (e >= 0)
01417    {
01418       StunAddress4 from;
01419 
01420       // do the media relaying
01421       if (info.relay)
01422       {
01423          time_t now = time(0);
01424          for (int i=0; i<MAX_MEDIA_RELAYS; ++i)
01425          {
01426             StunMediaRelay* relay = &info.relays[i];
01427             if (relay->fd)
01428             {
01429                if (FD_ISSET(relay->fd, &fdSet))
01430                {
01431                   char msg[MAX_RTP_MSG_SIZE];
01432                   int msgLen = sizeof(msg);
01433                   
01434                   StunAddress4 rtpFrom;
01435                   ok = getMessage( relay->fd, msg, &msgLen, &rtpFrom.addr, &rtpFrom.port ,verbose);
01436                   if (ok)
01437                   {
01438                      sendMessage(info.myFd, msg, msgLen, relay->destination.addr, relay->destination.port, verbose);
01439                      relay->expireTime = now + MEDIA_RELAY_TIMEOUT;
01440                      if ( verbose ) clog << "Relay packet on " 
01441                                          << relay->fd 
01442                                          << " from " << rtpFrom 
01443                                          << " -> " << relay->destination 
01444                                          << endl;
01445                   }
01446                }
01447                else if (now > relay->expireTime)
01448                {
01449                   closesocket(relay->fd);
01450                   relay->fd = 0;
01451                }
01452             }
01453          }
01454       }
01455       
01456      
01457       if (FD_ISSET(info.myFd,&fdSet))
01458       {
01459          if (verbose) clog << "received on A1:P1" << endl;
01460          recvAltIp = false;
01461          recvAltPort = false;
01462          ok = getMessage( info.myFd, msg, &msgLen, &from.addr, &from.port,verbose );
01463       }
01464       else if (FD_ISSET(info.altPortFd, &fdSet))
01465       {
01466          if (verbose) clog << "received on A1:P2" << endl;
01467          recvAltIp = false;
01468          recvAltPort = true;
01469          ok = getMessage( info.altPortFd, msg, &msgLen, &from.addr, &from.port,verbose );
01470       }
01471       else if ( (info.altIpFd!=INVALID_SOCKET) && FD_ISSET(info.altIpFd,&fdSet))
01472       {
01473          if (verbose) clog << "received on A2:P1" << endl;
01474          recvAltIp = true;
01475          recvAltPort = false;
01476          ok = getMessage( info.altIpFd, msg, &msgLen, &from.addr, &from.port ,verbose);
01477       }
01478       else if ( (info.altIpPortFd!=INVALID_SOCKET) && FD_ISSET(info.altIpPortFd, &fdSet))
01479       {
01480          if (verbose) clog << "received on A2:P2" << endl;
01481          recvAltIp = true;
01482          recvAltPort = true;
01483          ok = getMessage( info.altIpPortFd, msg, &msgLen, &from.addr, &from.port,verbose );
01484       }
01485       else
01486       {
01487          return true;
01488       }
01489 
01490       int relayPort = 0;
01491       if (info.relay)
01492       {
01493          for (int i=0; i<MAX_MEDIA_RELAYS; ++i)
01494          {
01495             StunMediaRelay* relay = &info.relays[i];
01496             if (relay->destination.addr == from.addr && 
01497                 relay->destination.port == from.port)
01498             {
01499                relayPort = relay->relayPort;
01500                relay->expireTime = time(0) + MEDIA_RELAY_TIMEOUT;
01501                break;
01502             }
01503          }
01504 
01505          if (relayPort == 0)
01506          {
01507             for (int i=0; i<MAX_MEDIA_RELAYS; ++i)
01508             {
01509                StunMediaRelay* relay = &info.relays[i];
01510                if (relay->fd == 0)
01511                {
01512                   if ( verbose ) clog << "Open relay port " << relay->relayPort << endl;
01513                   
01514                   relay->fd = openPort(relay->relayPort, info.myAddr.addr, verbose);
01515                   relay->destination.addr = from.addr;
01516                   relay->destination.port = from.port;
01517                   relay->expireTime = time(0) + MEDIA_RELAY_TIMEOUT;
01518                   relayPort = relay->relayPort;
01519                   break;
01520                }
01521             }
01522          }
01523       }
01524          
01525       if ( !ok ) 
01526       {
01527          if ( verbose ) clog << "Get message did not return a valid message" <<endl;
01528          return true;
01529       }
01530                 
01531       if ( verbose ) clog << "Got a request (len=" << msgLen << ") from " << from << endl;
01532                 
01533       if ( msgLen <= 0 )
01534       {
01535          return true;
01536       }
01537                 
01538       bool changePort = false;
01539       bool changeIp = false;
01540                 
01541       StunMessage resp;
01542       StunAddress4 dest;
01543       StunAtrString hmacPassword;  
01544       hmacPassword.sizeValue = 0;
01545 
01546       StunAddress4 secondary;
01547       secondary.port = 0;
01548       secondary.addr = 0;
01549                
01550       if (info.relay && relayPort)
01551       {
01552          secondary = from;
01553          
01554          from.addr = info.myAddr.addr;
01555          from.port = relayPort;
01556       }
01557       
01558       ok = stunServerProcessMsg( msg, msgLen, from, secondary,
01559                                  recvAltIp ? info.altAddr : info.myAddr,
01560                                  recvAltIp ? info.myAddr : info.altAddr, 
01561                                  &resp,
01562                                  &dest,
01563                                  &hmacPassword,
01564                                  &changePort,
01565                                  &changeIp,
01566                                  verbose );
01567                 
01568       if ( !ok )
01569       {
01570          if ( verbose ) clog << "Failed to parse message" << endl;
01571          return true;
01572       }
01573                 
01574       char buf[STUN_MAX_MESSAGE_SIZE];
01575       int len = sizeof(buf);
01576                 
01577       len = stunEncodeMessage( resp, buf, len, hmacPassword,verbose );
01578                 
01579       if ( dest.addr == 0 )  ok=false;
01580       if ( dest.port == 0 ) ok=false;
01581                 
01582       if ( ok )
01583       {
01584          assert( dest.addr != 0 );
01585          assert( dest.port != 0 );
01586                         
01587          Socket sendFd;
01588                         
01589          bool sendAltIp   = recvAltIp;   // send on the received IP address 
01590          bool sendAltPort = recvAltPort; // send on the received port
01591                         
01592          if ( changeIp )   sendAltIp   = !sendAltIp;   // if need to change IP, then flip logic 
01593          if ( changePort ) sendAltPort = !sendAltPort; // if need to change port, then flip logic 
01594                         
01595          if ( !sendAltPort )
01596          {
01597             if ( !sendAltIp )
01598             {
01599                sendFd = info.myFd;
01600             }
01601             else
01602             {
01603                sendFd = info.altIpFd;
01604             }
01605          }
01606          else
01607          {
01608             if ( !sendAltIp )
01609             {
01610                sendFd = info.altPortFd;
01611             }
01612             else
01613             {
01614                sendFd = info.altIpPortFd;
01615             }
01616          }
01617         
01618          if ( sendFd != INVALID_SOCKET )
01619          {
01620             sendMessage( sendFd, buf, len, dest.addr, dest.port, verbose );
01621          }
01622       }
01623    }
01624         
01625    return true;
01626 }

bool stunServerProcessMsg ( char *  buf,
unsigned int  bufLen,
StunAddress4 from,
StunAddress4 myAddr,
StunAddress4 altAddr,
StunMessage resp,
StunAddress4 destination,
StunAtrString hmacPassword,
bool *  changePort,
bool *  changeIp,
bool  verbose 
)

void stunStopServer ( StunServerInfo info  ) 

Referenced by stunInitServer().

01328 {
01329    if (info.myFd > 0) closesocket(info.myFd);
01330    if (info.altPortFd > 0) closesocket(info.altPortFd);
01331    if (info.altIpFd > 0) closesocket(info.altIpFd);
01332    if (info.altIpPortFd > 0) closesocket(info.altIpPortFd);
01333    
01334    if (info.relay)
01335    {
01336       for (int i=0; i<MAX_MEDIA_RELAYS; ++i)
01337       {
01338          StunMediaRelay* relay = &info.relays[i];
01339          if (relay->fd)
01340          {
01341             closesocket(relay->fd);
01342             relay->fd = 0;
01343          }
01344       }
01345    }
01346 }

void stunTest ( StunAddress4 dest,
int  testNum,
bool  verbose,
StunAddress4 srcAddr = 0 
)

01813 { 
01814    assert( dest.addr != 0 );
01815    assert( dest.port != 0 );
01816         
01817    int port = stunRandomPort();
01818    UInt32 interfaceIp=0;
01819    if (sAddr)
01820    {
01821       interfaceIp = sAddr->addr;
01822       if ( sAddr->port != 0 )
01823       {
01824         port = sAddr->port;
01825       }
01826    }
01827    Socket myFd = openPort(port,interfaceIp,verbose);
01828         
01829    StunAtrString username;
01830    StunAtrString password;
01831         
01832    username.sizeValue = 0;
01833    password.sizeValue = 0;
01834         
01835 #ifdef USE_TLS
01836    stunGetUserNameAndPassword( dest, username, password );
01837 #endif
01838         
01839    stunSendTest( myFd, dest, username, password, testNum, verbose );
01840     
01841    char msg[STUN_MAX_MESSAGE_SIZE];
01842    int msgLen = STUN_MAX_MESSAGE_SIZE;
01843         
01844    StunAddress4 from;
01845    getMessage( myFd,
01846                msg,
01847                &msgLen,
01848                &from.addr,
01849                &from.port,verbose );
01850         
01851    StunMessage resp;
01852    memset(&resp, 0, sizeof(StunMessage));
01853         
01854    if ( verbose ) clog << "Got a response" << endl;
01855    bool ok = stunParseMessage( msg,msgLen, resp,verbose );
01856         
01857    if ( verbose )
01858    {
01859       clog << "\t ok=" << ok << endl;
01860       clog << "\t id=" << resp.msgHdr.id << endl;
01861       clog << "\t mappedAddr=" << resp.mappedAddress.ipv4 << endl;
01862       clog << "\t changedAddr=" << resp.changedAddress.ipv4 << endl;
01863       clog << endl;
01864    }
01865         
01866    if (sAddr)
01867    {
01868       sAddr->port = resp.mappedAddress.ipv4.port;
01869       sAddr->addr = resp.mappedAddress.ipv4.addr;
01870    }
01871 }


Variable Documentation

const UInt16 BindErrorResponseMsg = 0x0111

Referenced by stunCreateErrorResponse().

const UInt16 BindRequestMsg = 0x0001

const UInt16 BindResponseMsg = 0x0101

Referenced by stunServerProcessMsg().

const UInt16 ChangedAddress = 0x0005

const UInt32 ChangeIpFlag = 0x04

const UInt32 ChangePortFlag = 0x02

const UInt16 ChangeRequest = 0x0003

const UInt16 ErrorCode = 0x0009

Referenced by encodeAtrError(), and stunParseMessage().

const UInt8 IPv4Family = 0x01

define a structure to hold a stun address

Referenced by encodeAtrAddress4(), and stunParseAtrAddress().

const UInt8 IPv6Family = 0x02

Referenced by stunParseAtrAddress().

const UInt16 MappedAddress = 0x0001

const UInt16 MessageIntegrity = 0x0008

const UInt16 Password = 0x0007

const UInt16 ReflectedFrom = 0x000B

const UInt16 ResponseAddress = 0x0002

const UInt16 SecondaryAddress = 0x8050

const UInt16 ServerName = 0x8022

Referenced by stunServerProcessMsg().

const UInt16 SourceAddress = 0x0004

const UInt16 UnknownAttribute = 0x000A

const UInt16 Username = 0x0006

const UInt16 XorMappedAddress = 0x8020

const UInt16 XorOnly = 0x0021

Referenced by encodeXorOnly(), and stunParseMessage().


Generated on Fri Sep 19 13:05:05 2008 for ITM OverSim by  doxygen 1.5.5