stun.cc

Go to the documentation of this file.
00001 #include <cassert>
00002 #include <cstring>
00003 #include <iostream>
00004 #include <cstdlib>
00005 #include <errno.h>
00006 
00007 #ifdef WIN32
00008 #include <winsock2.h>
00009 #include <stdlib.h>
00010 #include <stdio.h>
00011 #include <io.h>
00012 #include <time.h>
00013 #else
00014 
00015 #include <stdlib.h>
00016 #include <unistd.h>
00017 #include <string.h>
00018 #include <sys/ioctl.h>
00019 #include <sys/socket.h>
00020 #include <sys/time.h>
00021 #include <sys/types.h>
00022 #include <arpa/inet.h>
00023 #include <fcntl.h>
00024 #include <netdb.h>
00025 #include <netinet/in.h>
00026 #include <arpa/nameser.h>
00027 #include <resolv.h>
00028 #include <net/if.h>
00029 
00030 #endif
00031 
00032 
00033 #if defined(__sparc__) || defined(WIN32)
00034 #define NOSSL
00035 #endif
00036 #define NOSSL
00037 
00038 #include "stun_udp.h"
00039 #include "stun.h"
00040 
00041 
00042 using namespace std;
00043 
00044 
00045 static void
00046 computeHmac(char* hmac, const char* input, int length, const char* key, int keySize);
00047 
00048 static bool
00049 stunParseAtrAddress( char* body, unsigned int hdrLen,  StunAtrAddress4& result )
00050 {
00051    if ( hdrLen != 8 )
00052    {
00053       clog << "hdrLen wrong for Address" <<endl;
00054       return false;
00055    }
00056    result.pad = *body++;
00057    result.family = *body++;
00058    if (result.family == IPv4Family)
00059    {
00060       UInt16 nport;
00061       memcpy(&nport, body, 2); body+=2;
00062       result.ipv4.port = ntohs(nport);
00063 
00064       UInt32 naddr;
00065       memcpy(&naddr, body, 4); body+=4;
00066       result.ipv4.addr = ntohl(naddr);
00067       return true;
00068    }
00069    else if (result.family == IPv6Family)
00070    {
00071       clog << "ipv6 not supported" << endl;
00072    }
00073    else
00074    {
00075       clog << "bad address family: " << result.family << endl;
00076    }
00077 
00078    return false;
00079 }
00080 
00081 static bool
00082 stunParseAtrChangeRequest( char* body, unsigned int hdrLen,  StunAtrChangeRequest& result )
00083 {
00084    if ( hdrLen != 4 )
00085    {
00086       clog << "hdr length = " << hdrLen << " expecting " << sizeof(result) << endl;
00087 
00088       clog << "Incorrect size for ChangeRequest" << endl;
00089       return false;
00090    }
00091    else
00092    {
00093       memcpy(&result.value, body, 4);
00094       result.value = ntohl(result.value);
00095       return true;
00096    }
00097 }
00098 
00099 static bool
00100 stunParseAtrError( char* body, unsigned int hdrLen,  StunAtrError& result )
00101 {
00102    if ( hdrLen >= sizeof(result) )
00103    {
00104       clog << "head on Error too large" << endl;
00105       return false;
00106    }
00107    else
00108    {
00109       memcpy(&result.pad, body, 2); body+=2;
00110       result.pad = ntohs(result.pad);
00111       result.errorClass = *body++;
00112       result.number = *body++;
00113 
00114       result.sizeReason = hdrLen - 4;
00115       memcpy(&result.reason, body, result.sizeReason);
00116       result.reason[result.sizeReason] = 0;
00117       return true;
00118    }
00119 }
00120 
00121 static bool
00122 stunParseAtrUnknown( char* body, unsigned int hdrLen,  StunAtrUnknown& result )
00123 {
00124    if ( hdrLen >= sizeof(result) )
00125    {
00126       return false;
00127    }
00128    else
00129    {
00130       if (hdrLen % 4 != 0) return false;
00131       result.numAttributes = hdrLen / 4;
00132       for (int i=0; i<result.numAttributes; i++)
00133       {
00134          memcpy(&result.attrType[i], body, 2); body+=2;
00135          result.attrType[i] = ntohs(result.attrType[i]);
00136       }
00137       return true;
00138    }
00139 }
00140 
00141 
00142 static bool
00143 stunParseAtrString( char* body, unsigned int hdrLen,  StunAtrString& result )
00144 {
00145    if ( hdrLen >= STUN_MAX_STRING )
00146    {
00147       clog << "String is too large" << endl;
00148       return false;
00149    }
00150    else
00151    {
00152       if (hdrLen % 4 != 0)
00153       {
00154          clog << "Bad length string " << hdrLen << endl;
00155          return false;
00156       }
00157 
00158       result.sizeValue = hdrLen;
00159       memcpy(&result.value, body, hdrLen);
00160       result.value[hdrLen] = 0;
00161       return true;
00162    }
00163 }
00164 
00165 
00166 static bool
00167 stunParseAtrIntegrity( char* body, unsigned int hdrLen,  StunAtrIntegrity& result )
00168 {
00169    if ( hdrLen != 20)
00170    {
00171       clog << "MessageIntegrity must be 20 bytes" << endl;
00172       return false;
00173    }
00174    else
00175    {
00176       memcpy(&result.hash, body, hdrLen);
00177       return true;
00178    }
00179 }
00180 
00181 
00182 bool
00183 stunParseMessage( char* buf, unsigned int bufLen, StunMessage& msg, bool verbose)
00184 {
00185    if (verbose) clog << "Received stun message: " << bufLen << " bytes" << endl;
00186    memset(&msg, 0, sizeof(msg));
00187 
00188    if (sizeof(StunMsgHdr) > bufLen)
00189    {
00190       clog << "Bad message" << endl;
00191       return false;
00192    }
00193 
00194    memcpy(&msg.msgHdr, buf, sizeof(StunMsgHdr));
00195    msg.msgHdr.msgType = ntohs(msg.msgHdr.msgType);
00196    msg.msgHdr.msgLength = ntohs(msg.msgHdr.msgLength);
00197 
00198    if (msg.msgHdr.msgLength + sizeof(StunMsgHdr) != bufLen)
00199    {
00200       clog << "Message header length doesn't match message size: "
00201            << msg.msgHdr.msgLength << " - " << bufLen << endl;
00202       return false;
00203    }
00204 
00205    char* body = buf + sizeof(StunMsgHdr);
00206    unsigned int size = msg.msgHdr.msgLength;
00207 
00208    //clog << "bytes after header = " << size << endl;
00209 
00210    while ( size > 0 )
00211    {
00212       // !jf! should check that there are enough bytes left in the buffer
00213 
00214       StunAtrHdr* attr = reinterpret_cast<StunAtrHdr*>(body);
00215 
00216       unsigned int attrLen = ntohs(attr->length);
00217       int atrType = ntohs(attr->type);
00218 
00219       //if (verbose) clog << "Found attribute type=" << AttrNames[atrType] << " length=" << attrLen << endl;
00220       if ( attrLen+4 > size )
00221       {
00222          clog << "claims attribute is larger than size of message "
00223               <<"(attribute type="<<atrType<<")"<< endl;
00224          return false;
00225       }
00226 
00227       body += 4; // skip the length and type in attribute header
00228       size -= 4;
00229 
00230       switch ( atrType )
00231       {
00232          case MappedAddress:
00233             msg.hasMappedAddress = true;
00234             if ( stunParseAtrAddress(  body,  attrLen,  msg.mappedAddress )== false )
00235             {
00236                clog << "problem parsing MappedAddress" << endl;
00237                return false;
00238             }
00239             else
00240             {
00241                if (verbose) clog << "MappedAddress = " << msg.mappedAddress.ipv4 << endl;
00242             }
00243 
00244             break;
00245 
00246          case ResponseAddress:
00247             msg.hasResponseAddress = true;
00248             if ( stunParseAtrAddress(  body,  attrLen,  msg.responseAddress )== false )
00249             {
00250                clog << "problem parsing ResponseAddress" << endl;
00251                return false;
00252             }
00253             else
00254             {
00255                if (verbose) clog << "ResponseAddress = " << msg.responseAddress.ipv4 << endl;
00256             }
00257             break;
00258 
00259          case ChangeRequest:
00260             msg.hasChangeRequest = true;
00261             if (stunParseAtrChangeRequest( body, attrLen, msg.changeRequest) == false)
00262             {
00263                clog << "problem parsing ChangeRequest" << endl;
00264                return false;
00265             }
00266             else
00267             {
00268                if (verbose) clog << "ChangeRequest = " << msg.changeRequest.value << endl;
00269             }
00270             break;
00271 
00272          case SourceAddress:
00273             msg.hasSourceAddress = true;
00274             if ( stunParseAtrAddress(  body,  attrLen,  msg.sourceAddress )== false )
00275             {
00276                clog << "problem parsing SourceAddress" << endl;
00277                return false;
00278             }
00279             else
00280             {
00281                if (verbose) clog << "SourceAddress = " << msg.sourceAddress.ipv4 << endl;
00282             }
00283             break;
00284 
00285          case ChangedAddress:
00286             msg.hasChangedAddress = true;
00287             if ( stunParseAtrAddress(  body,  attrLen,  msg.changedAddress )== false )
00288             {
00289                clog << "problem parsing ChangedAddress" << endl;
00290                return false;
00291             }
00292             else
00293             {
00294                if (verbose) clog << "ChangedAddress = " << msg.changedAddress.ipv4 << endl;
00295             }
00296             break;
00297 
00298          case Username:
00299             msg.hasUsername = true;
00300             if (stunParseAtrString( body, attrLen, msg.username) == false)
00301             {
00302                clog << "problem parsing Username" << endl;
00303                return false;
00304             }
00305             else
00306             {
00307                if (verbose) clog << "Username = " << msg.username.value << endl;
00308             }
00309 
00310             break;
00311 
00312          case Password:
00313             msg.hasPassword = true;
00314             if (stunParseAtrString( body, attrLen, msg.password) == false)
00315             {
00316                clog << "problem parsing Password" << endl;
00317                return false;
00318             }
00319             else
00320             {
00321                if (verbose) clog << "Password = " << msg.password.value << endl;
00322             }
00323             break;
00324 
00325          case MessageIntegrity:
00326             msg.hasMessageIntegrity = true;
00327             if (stunParseAtrIntegrity( body, attrLen, msg.messageIntegrity) == false)
00328             {
00329                clog << "problem parsing MessageIntegrity" << endl;
00330                return false;
00331             }
00332             else
00333             {
00334                //if (verbose) clog << "MessageIntegrity = " << msg.messageIntegrity.hash << endl;
00335             }
00336 
00337             // read the current HMAC
00338             // look up the password given the user of given the transaction id
00339             // compute the HMAC on the buffer
00340             // decide if they match or not
00341             break;
00342 
00343          case ErrorCode:
00344             msg.hasErrorCode = true;
00345             if (stunParseAtrError(body, attrLen, msg.errorCode) == false)
00346             {
00347                clog << "problem parsing ErrorCode" << endl;
00348                return false;
00349             }
00350             else
00351             {
00352                if (verbose) clog << "ErrorCode = " << int(msg.errorCode.errorClass)
00353                                  << " " << int(msg.errorCode.number)
00354                                  << " " << msg.errorCode.reason << endl;
00355             }
00356 
00357             break;
00358 
00359          case UnknownAttribute:
00360             msg.hasUnknownAttributes = true;
00361             if (stunParseAtrUnknown(body, attrLen, msg.unknownAttributes) == false)
00362             {
00363                clog << "problem parsing UnknownAttribute" << endl;
00364                return false;
00365             }
00366             break;
00367 
00368          case ReflectedFrom:
00369             msg.hasReflectedFrom = true;
00370             if ( stunParseAtrAddress(  body,  attrLen,  msg.reflectedFrom ) == false )
00371             {
00372                clog << "problem parsing ReflectedFrom" << endl;
00373                return false;
00374             }
00375             break;
00376 
00377          case XorMappedAddress:
00378             msg.hasXorMappedAddress = true;
00379             if ( stunParseAtrAddress(  body,  attrLen,  msg.xorMappedAddress ) == false )
00380             {
00381                clog << "problem parsing XorMappedAddress" << endl;
00382                return false;
00383             }
00384             else
00385             {
00386                if (verbose) clog << "XorMappedAddress = " << msg.mappedAddress.ipv4 << endl;
00387             }
00388             break;
00389 
00390          case XorOnly:
00391             msg.xorOnly = true;
00392             if (verbose)
00393             {
00394                clog << "xorOnly = true" << endl;
00395             }
00396             break;
00397 
00398          case ServerName:
00399             msg.hasServerName = true;
00400             if (stunParseAtrString( body, attrLen, msg.serverName) == false)
00401             {
00402                clog << "problem parsing ServerName" << endl;
00403                return false;
00404             }
00405             else
00406             {
00407                if (verbose) clog << "ServerName = " << msg.serverName.value << endl;
00408             }
00409             break;
00410 
00411          case SecondaryAddress:
00412             msg.hasSecondaryAddress = true;
00413             if ( stunParseAtrAddress(  body,  attrLen,  msg.secondaryAddress ) == false )
00414             {
00415                clog << "problem parsing secondaryAddress" << endl;
00416                return false;
00417             }
00418             else
00419             {
00420                if (verbose) clog << "SecondaryAddress = " << msg.secondaryAddress.ipv4 << endl;
00421             }
00422             break;
00423 
00424          default:
00425             if (verbose) clog << "Unknown attribute: " << atrType << endl;
00426             if ( atrType <= 0x7FFF )
00427             {
00428                return false;
00429             }
00430       }
00431 
00432       body += attrLen;
00433       size -= attrLen;
00434    }
00435 
00436    return true;
00437 }
00438 
00439 
00440 static char*
00441 encode16(char* buf, UInt16 data)
00442 {
00443    UInt16 ndata = htons(data);
00444    memcpy(buf, reinterpret_cast<void*>(&ndata), sizeof(UInt16));
00445    return buf + sizeof(UInt16);
00446 }
00447 
00448 static char*
00449 encode32(char* buf, UInt32 data)
00450 {
00451    UInt32 ndata = htonl(data);
00452    memcpy(buf, reinterpret_cast<void*>(&ndata), sizeof(UInt32));
00453    return buf + sizeof(UInt32);
00454 }
00455 
00456 
00457 static char*
00458 encode(char* buf, const char* data, unsigned int length)
00459 {
00460    memcpy(buf, data, length);
00461    return buf + length;
00462 }
00463 
00464 
00465 static char*
00466 encodeAtrAddress4(char* ptr, UInt16 type, const StunAtrAddress4& atr)
00467 {
00468    ptr = encode16(ptr, type);
00469    ptr = encode16(ptr, 8);
00470    *ptr++ = atr.pad;
00471    *ptr++ = IPv4Family;
00472    ptr = encode16(ptr, atr.ipv4.port);
00473    ptr = encode32(ptr, atr.ipv4.addr);
00474 
00475    return ptr;
00476 }
00477 
00478 static char*
00479 encodeAtrChangeRequest(char* ptr, const StunAtrChangeRequest& atr)
00480 {
00481    ptr = encode16(ptr, ChangeRequest);
00482    ptr = encode16(ptr, 4);
00483    ptr = encode32(ptr, atr.value);
00484    return ptr;
00485 }
00486 
00487 static char*
00488 encodeAtrError(char* ptr, const StunAtrError& atr)
00489 {
00490    ptr = encode16(ptr, ErrorCode);
00491    ptr = encode16(ptr, 6 + atr.sizeReason);
00492    ptr = encode16(ptr, atr.pad);
00493    *ptr++ = atr.errorClass;
00494    *ptr++ = atr.number;
00495    ptr = encode(ptr, atr.reason, atr.sizeReason);
00496    return ptr;
00497 }
00498 
00499 
00500 static char*
00501 encodeAtrUnknown(char* ptr, const StunAtrUnknown& atr)
00502 {
00503    ptr = encode16(ptr, UnknownAttribute);
00504    ptr = encode16(ptr, 2+2*atr.numAttributes);
00505    for (int i=0; i<atr.numAttributes; i++)
00506    {
00507       ptr = encode16(ptr, atr.attrType[i]);
00508    }
00509    return ptr;
00510 }
00511 
00512 
00513 static char*
00514 encodeXorOnly(char* ptr)
00515 {
00516    ptr = encode16(ptr, XorOnly );
00517    return ptr;
00518 }
00519 
00520 
00521 static char*
00522 encodeAtrString(char* ptr, UInt16 type, const StunAtrString& atr)
00523 {
00524    assert(atr.sizeValue % 4 == 0);
00525 
00526    ptr = encode16(ptr, type);
00527    ptr = encode16(ptr, atr.sizeValue);
00528    ptr = encode(ptr, atr.value, atr.sizeValue);
00529    return ptr;
00530 }
00531 
00532 
00533 static char*
00534 encodeAtrIntegrity(char* ptr, const StunAtrIntegrity& atr)
00535 {
00536    ptr = encode16(ptr, MessageIntegrity);
00537    ptr = encode16(ptr, 20);
00538    ptr = encode(ptr, atr.hash, sizeof(atr.hash));
00539    return ptr;
00540 }
00541 
00542 
00543 unsigned int
00544 stunEncodeMessage( const StunMessage& msg,
00545                    char* buf,
00546                    unsigned int bufLen,
00547                    const StunAtrString& password,
00548                    bool verbose)
00549 {
00550    assert(bufLen >= sizeof(StunMsgHdr));
00551    char* ptr = buf;
00552 
00553    ptr = encode16(ptr, msg.msgHdr.msgType);
00554    char* lengthp = ptr;
00555    ptr = encode16(ptr, 0);
00556    ptr = encode(ptr, reinterpret_cast<const char*>(msg.msgHdr.id.octet), sizeof(msg.msgHdr.id));
00557 
00558    if (verbose) clog << "Encoding stun message: " << endl;
00559    if (msg.hasMappedAddress)
00560    {
00561       if (verbose) clog << "Encoding MappedAddress: " << msg.mappedAddress.ipv4 << endl;
00562       ptr = encodeAtrAddress4 (ptr, MappedAddress, msg.mappedAddress);
00563    }
00564    if (msg.hasResponseAddress)
00565    {
00566       if (verbose) clog << "Encoding ResponseAddress: " << msg.responseAddress.ipv4 << endl;
00567       ptr = encodeAtrAddress4(ptr, ResponseAddress, msg.responseAddress);
00568    }
00569    if (msg.hasChangeRequest)
00570    {
00571       if (verbose) clog << "Encoding ChangeRequest: " << msg.changeRequest.value << endl;
00572       ptr = encodeAtrChangeRequest(ptr, msg.changeRequest);
00573    }
00574    if (msg.hasSourceAddress)
00575    {
00576       if (verbose) clog << "Encoding SourceAddress: " << msg.sourceAddress.ipv4 << endl;
00577       ptr = encodeAtrAddress4(ptr, SourceAddress, msg.sourceAddress);
00578    }
00579    if (msg.hasChangedAddress)
00580    {
00581       if (verbose) clog << "Encoding ChangedAddress: " << msg.changedAddress.ipv4 << endl;
00582       ptr = encodeAtrAddress4(ptr, ChangedAddress, msg.changedAddress);
00583    }
00584    if (msg.hasUsername)
00585    {
00586       if (verbose) clog << "Encoding Username: " << msg.username.value << endl;
00587       ptr = encodeAtrString(ptr, Username, msg.username);
00588    }
00589    if (msg.hasPassword)
00590    {
00591       if (verbose) clog << "Encoding Password: " << msg.password.value << endl;
00592       ptr = encodeAtrString(ptr, Password, msg.password);
00593    }
00594    if (msg.hasErrorCode)
00595    {
00596       if (verbose) clog << "Encoding ErrorCode: class="
00597                         << int(msg.errorCode.errorClass)
00598                         << " number=" << int(msg.errorCode.number)
00599                         << " reason="
00600                         << msg.errorCode.reason
00601                         << endl;
00602 
00603       ptr = encodeAtrError(ptr, msg.errorCode);
00604    }
00605    if (msg.hasUnknownAttributes)
00606    {
00607       if (verbose) clog << "Encoding UnknownAttribute: ???" << endl;
00608       ptr = encodeAtrUnknown(ptr, msg.unknownAttributes);
00609    }
00610    if (msg.hasReflectedFrom)
00611    {
00612       if (verbose) clog << "Encoding ReflectedFrom: " << msg.reflectedFrom.ipv4 << endl;
00613       ptr = encodeAtrAddress4(ptr, ReflectedFrom, msg.reflectedFrom);
00614    }
00615    if (msg.hasXorMappedAddress)
00616    {
00617       if (verbose) clog << "Encoding XorMappedAddress: " << msg.xorMappedAddress.ipv4 << endl;
00618       ptr = encodeAtrAddress4 (ptr, XorMappedAddress, msg.xorMappedAddress);
00619    }
00620    if (msg.xorOnly)
00621    {
00622       if (verbose) clog << "Encoding xorOnly: " << endl;
00623       ptr = encodeXorOnly( ptr );
00624    }
00625    if (msg.hasServerName)
00626    {
00627       if (verbose) clog << "Encoding ServerName: " << msg.serverName.value << endl;
00628       ptr = encodeAtrString(ptr, ServerName, msg.serverName);
00629    }
00630    if (msg.hasSecondaryAddress)
00631    {
00632       if (verbose) clog << "Encoding SecondaryAddress: " << msg.secondaryAddress.ipv4 << endl;
00633       ptr = encodeAtrAddress4 (ptr, SecondaryAddress, msg.secondaryAddress);
00634    }
00635 
00636    if (password.sizeValue > 0)
00637    {
00638       if (verbose) clog << "HMAC with password: " << password.value << endl;
00639 
00640       StunAtrIntegrity integrity;
00641       computeHmac(integrity.hash, buf, int(ptr-buf) , password.value, password.sizeValue);
00642       ptr = encodeAtrIntegrity(ptr, integrity);
00643    }
00644    if (verbose) clog << endl;
00645 
00646    encode16(lengthp, UInt16(ptr - buf - sizeof(StunMsgHdr)));
00647    return int(ptr - buf);
00648 }
00649 
00650 int
00651 stunRand()
00652 {
00653    // return 32 bits of random stuff
00654    assert( sizeof(int) == 4 );
00655    static bool init=false;
00656    if ( !init )
00657    {
00658       init = true;
00659 
00660       UInt64 tick;
00661 
00662 #if defined(MSVC_WIN32)
00663       volatile unsigned int lowtick=0,hightick=0;
00664       __asm
00665          {
00666             rdtsc
00667                mov lowtick, eax
00668                mov hightick, edx
00669                }
00670       tick = hightick;
00671       tick <<= 32;
00672       tick |= lowtick;
00673 #elif (defined(WIN32) || defined(__GNUC__)) && ( defined(__i686__) || defined(__i386__) || defined(__x86_64__) )
00674       asm("rdtsc" : "=A" (tick));
00675 #elif defined (__SUNPRO_CC) || defined( __sparc__ )
00676       tick = gethrtime();
00677 #elif defined(__MACH__)
00678       int fd=open("/dev/random",O_RDONLY);
00679       read(fd,&tick,sizeof(tick));
00680       stunclosesocket(fd);
00681 #else
00682 #     error Need some way to seed the random number generator
00683 #endif
00684       int seed = int(tick);
00685 #ifdef WIN32
00686       srand(seed);
00687 #else
00688       srandom(seed);
00689 #endif
00690    }
00691 
00692 #ifdef WIN32
00693    assert( RAND_MAX == 0x7fff );
00694    int r1 = rand();
00695    int r2 = rand();
00696 
00697    int ret = (r1<<16) + r2;
00698 
00699    return ret;
00700 #else
00701    return random();
00702 #endif
00703 }
00704 
00705 
00707 int
00708 stunRandomPort()
00709 {
00710    int min=0x4000;
00711    int max=0x7FFF;
00712 
00713    int ret = stunRand();
00714    ret = ret|min;
00715    ret = ret&max;
00716 
00717    return ret;
00718 }
00719 
00720 
00721 #ifdef NOSSL
00722 static void
00723 computeHmac(char* hmac, const char* input, int length, const char* key, int sizeKey)
00724 {
00725    strncpy(hmac,"hmac-not-implemented",20);
00726 }
00727 #else
00728 #include <openssl/hmac.h>
00729 
00730 static void
00731 computeHmac(char* hmac, const char* input, int length, const char* key, int sizeKey)
00732 {
00733    unsigned int resultSize=0;
00734    HMAC(EVP_sha1(),
00735         key, sizeKey,
00736         reinterpret_cast<const unsigned char*>(input), length,
00737         reinterpret_cast<unsigned char*>(hmac), &resultSize);
00738    assert(resultSize == 20);
00739 }
00740 #endif
00741 
00742 
00743 static void
00744 toHex(const char* buffer, int bufferSize, char* output)
00745 {
00746    static char hexmap[] = "0123456789abcdef";
00747 
00748    const char* p = buffer;
00749    char* r = output;
00750    for (int i=0; i < bufferSize; i++)
00751    {
00752       unsigned char temp = *p++;
00753 
00754       int hi = (temp & 0xf0)>>4;
00755       int low = (temp & 0xf);
00756 
00757       *r++ = hexmap[hi];
00758       *r++ = hexmap[low];
00759    }
00760    *r = 0;
00761 }
00762 
00763 void
00764 stunCreateUserName(const StunAddress4& source, StunAtrString* username)
00765 {
00766    UInt64 time = stunGetSystemTimeSecs();
00767    time -= (time % 20*60);
00768    //UInt64 hitime = time >> 32;
00769    UInt64 lotime = time & 0xFFFFFFFF;
00770 
00771    char buffer[1024];
00772    sprintf(buffer,
00773            "%08x:%08x:%08x:",
00774            UInt32(source.addr),
00775            UInt32(stunRand()),
00776            UInt32(lotime));
00777    assert( strlen(buffer) < 1024 );
00778 
00779    assert(strlen(buffer) + 41 < STUN_MAX_STRING);
00780 
00781    char hmac[20];
00782    char key[] = "Jason";
00783    computeHmac(hmac, buffer, strlen(buffer), key, strlen(key) );
00784    char hmacHex[41];
00785    toHex(hmac, 20, hmacHex );
00786    hmacHex[40] =0;
00787 
00788    strcat(buffer,hmacHex);
00789 
00790    int l = strlen(buffer);
00791    assert( l+1 < STUN_MAX_STRING );
00792    assert( l%4 == 0 );
00793 
00794    username->sizeValue = l;
00795    memcpy(username->value,buffer,l);
00796    username->value[l]=0;
00797 
00798    //if (verbose) clog << "computed username=" << username.value << endl;
00799 }
00800 
00801 void
00802 stunCreatePassword(const StunAtrString& username, StunAtrString* password)
00803 {
00804    char hmac[20];
00805    char key[] = "Fluffy";
00806    //char buffer[STUN_MAX_STRING];
00807    computeHmac(hmac, username.value, strlen(username.value), key, strlen(key));
00808    toHex(hmac, 20, password->value);
00809    password->sizeValue = 40;
00810    password->value[40]=0;
00811 
00812    //clog << "password=" << password->value << endl;
00813 }
00814 
00815 
00816 UInt64
00817 stunGetSystemTimeSecs()
00818 {
00819    UInt64 time=0;
00820 #if defined(WIN32)
00821    SYSTEMTIME t;
00822    // CJ TODO - this probably has bug on wrap around every 24 hours
00823    GetSystemTime( &t );
00824    time = (t.wHour*60+t.wMinute)*60+t.wSecond;
00825 #else
00826    struct timeval now;
00827    gettimeofday( &now , NULL );
00828    //assert( now );
00829    time = now.tv_sec;
00830 #endif
00831    return time;
00832 }
00833 
00834 
00835 ostream& operator<< ( ostream& strm, const UInt128& r )
00836 {
00837    strm << int(r.octet[0]);
00838    for ( int i=1; i<16; i++ )
00839    {
00840       strm << ':' << int(r.octet[i]);
00841    }
00842 
00843    return strm;
00844 }
00845 
00846 ostream&
00847 operator<<( ostream& strm, const StunAddress4& addr)
00848 {
00849    UInt32 ip = addr.addr;
00850    strm << ((int)(ip>>24)&0xFF) << ".";
00851    strm << ((int)(ip>>16)&0xFF) << ".";
00852    strm << ((int)(ip>> 8)&0xFF) << ".";
00853    strm << ((int)(ip>> 0)&0xFF) ;
00854 
00855    strm << ":" << addr.port;
00856 
00857    return strm;
00858 }
00859 
00860 
00861 // returns true if it scucceeded
00862 bool
00863 stunParseHostName( char* peerName,
00864                UInt32& ip,
00865                UInt16& portVal,
00866                UInt16 defaultPort )
00867 {
00868    in_addr sin_addr;
00869 
00870    char host[512];
00871    strncpy(host,peerName,512);
00872    host[512-1]='\0';
00873    char* port = NULL;
00874 
00875    int portNum = defaultPort;
00876 
00877    // pull out the port part if present.
00878    char* sep = strchr(host,':');
00879 
00880    if ( sep == NULL )
00881    {
00882       portNum = defaultPort;
00883    }
00884    else
00885    {
00886       *sep = '\0';
00887       port = sep + 1;
00888       // set port part
00889 
00890       char* endPtr=NULL;
00891 
00892       portNum = strtol(port,&endPtr,10);
00893 
00894       if ( endPtr != NULL )
00895       {
00896          if ( *endPtr != '\0' )
00897          {
00898             portNum = defaultPort;
00899          }
00900       }
00901    }
00902 
00903    if ( portNum < 1024 ) return false;
00904    if ( portNum >= 0xFFFF ) return false;
00905 
00906    // figure out the host part
00907    struct hostent* h;
00908 
00909 #ifdef WIN32
00910    assert( strlen(host) >= 1 );
00911    if ( isdigit( host[0] ) )
00912    {
00913       // assume it is a ip address
00914       unsigned long a = inet_addr(host);
00915       //cerr << "a=0x" << hex << a << dec << endl;
00916 
00917       ip = ntohl( a );
00918    }
00919    else
00920    {
00921       // assume it is a host name
00922       h = gethostbyname( host );
00923 
00924       if ( h == NULL )
00925       {
00926          int err = getErrno();
00927          std::cerr << "error was " << err << std::endl;
00928          assert( err != WSANOTINITIALISED );
00929 
00930          ip = ntohl( 0x7F000001L );
00931 
00932          return false;
00933       }
00934       else
00935       {
00936          sin_addr = *(struct in_addr*)h->h_addr;
00937          ip = ntohl( sin_addr.s_addr );
00938       }
00939    }
00940 
00941 #else
00942    h = gethostbyname( host );
00943    if ( h == NULL )
00944    {
00945       int err = getErrno();
00946       std::cerr << "error was " << err << std::endl;
00947       ip = ntohl( 0x7F000001L );
00948       return false;
00949    }
00950    else
00951    {
00952       sin_addr = *(struct in_addr*)h->h_addr;
00953       ip = ntohl( sin_addr.s_addr );
00954    }
00955 #endif
00956 
00957    portVal = portNum;
00958 
00959    return true;
00960 }
00961 
00962 
00963 bool
00964 stunParseServerName( char* name, StunAddress4& addr)
00965 {
00966    assert(name);
00967 
00968    // TODO - put in DNS SRV stuff.
00969 
00970    bool ret = stunParseHostName( name, addr.addr, addr.port, 3478);
00971    if ( ret != true )
00972    {
00973        addr.port=0xFFFF;
00974    }
00975    return ret;
00976 }
00977 
00978 
00979 static void
00980 stunCreateErrorResponse(StunMessage& response, int cl, int number, const char* msg)
00981 {
00982    response.msgHdr.msgType = BindErrorResponseMsg;
00983    response.hasErrorCode = true;
00984    response.errorCode.errorClass = cl;
00985    response.errorCode.number = number;
00986    strcpy(response.errorCode.reason, msg);
00987 }
00988 
00989 #if 0
00990 static void
00991 stunCreateSharedSecretErrorResponse(StunMessage& response, int cl, int number, const char* msg)
00992 {
00993    response.msgHdr.msgType = SharedSecretErrorResponseMsg;
00994    response.hasErrorCode = true;
00995    response.errorCode.errorClass = cl;
00996    response.errorCode.number = number;
00997    strcpy(response.errorCode.reason, msg);
00998 }
00999 #endif
01000 
01001 static void
01002 stunCreateSharedSecretResponse(const StunMessage& request, const StunAddress4& source, StunMessage& response)
01003 {
01004    response.msgHdr.msgType = SharedSecretResponseMsg;
01005    response.msgHdr.id = request.msgHdr.id;
01006 
01007    response.hasUsername = true;
01008    stunCreateUserName( source, &response.username);
01009 
01010    response.hasPassword = true;
01011    stunCreatePassword( response.username, &response.password);
01012 }
01013 
01014 
01015 // This funtion takes a single message sent to a stun server, parses
01016 // and constructs an apropriate repsonse - returns true if message is
01017 // valid
01018 bool
01019 stunServerProcessMsg( char* buf,
01020                       unsigned int bufLen,
01021                       StunAddress4& from,
01022                       StunAddress4& secondary,
01023                       StunAddress4& myAddr,
01024                       StunAddress4& altAddr,
01025                       StunMessage* resp,
01026                       StunAddress4* destination,
01027                       StunAtrString* hmacPassword,
01028                       bool* changePort,
01029                       bool* changeIp,
01030                       bool verbose)
01031 {
01032 
01033    // set up information for default response
01034 
01035    memset( resp, 0 , sizeof(*resp) );
01036 
01037    *changeIp = false;
01038    *changePort = false;
01039 
01040    StunMessage req;
01041    bool ok = stunParseMessage( buf,bufLen, req, verbose);
01042 
01043    if (!ok)      // Complete garbage, drop it on the floor
01044    {
01045       if (verbose) clog << "Request did not parse" << endl;
01046       return false;
01047    }
01048    if (verbose) clog << "Request parsed ok" << endl;
01049 
01050    StunAddress4 mapped = req.mappedAddress.ipv4;
01051    StunAddress4 respondTo = req.responseAddress.ipv4;
01052    UInt32 flags = req.changeRequest.value;
01053 
01054    switch (req.msgHdr.msgType)
01055    {
01056       case SharedSecretRequestMsg:
01057          if(verbose) clog << "Received SharedSecretRequestMsg on udp. send error 433." << endl;
01058          // !cj! - should fix so you know if this came over TLS or UDP
01059          stunCreateSharedSecretResponse(req, from, *resp);
01060          //stunCreateSharedSecretErrorResponse(*resp, 4, 33, "this request must be over TLS");
01061          return true;
01062 
01063       case BindRequestMsg:
01064          if (!req.hasMessageIntegrity)
01065          {
01066             if (verbose) clog << "BindRequest does not contain MessageIntegrity" << endl;
01067 
01068             if (0) // !jf! mustAuthenticate
01069             {
01070                if(verbose) clog << "Received BindRequest with no MessageIntegrity. Sending 401." << endl;
01071                stunCreateErrorResponse(*resp, 4, 1, "Missing MessageIntegrity");
01072                return true;
01073             }
01074          }
01075          else
01076          {
01077             if (!req.hasUsername)
01078             {
01079                if (verbose) clog << "No UserName. Send 432." << endl;
01080                stunCreateErrorResponse(*resp, 4, 32, "No UserName and contains MessageIntegrity");
01081                return true;
01082             }
01083             else
01084             {
01085                if (verbose) clog << "Validating username: " << req.username.value << endl;
01086                // !jf! could retrieve associated password from provisioning here
01087                if (strcmp(req.username.value, "test") == 0)
01088                {
01089                   if (0)
01090                   {
01091                      // !jf! if the credentials are stale
01092                      stunCreateErrorResponse(*resp, 4, 30, "Stale credentials on BindRequest");
01093                      return true;
01094                   }
01095                   else
01096                   {
01097                      if (verbose) clog << "Validating MessageIntegrity" << endl;
01098                      // need access to shared secret
01099 
01100                      unsigned char hmac[20];
01101 #ifndef NOSSL
01102                      unsigned int hmacSize=20;
01103 
01104                      HMAC(EVP_sha1(),
01105                           "1234", 4,
01106                           reinterpret_cast<const unsigned char*>(buf), bufLen-20-4,
01107                           hmac, &hmacSize);
01108                      assert(hmacSize == 20);
01109 #endif
01110 
01111                      if (memcmp(buf, hmac, 20) != 0)
01112                      {
01113                         if (verbose) clog << "MessageIntegrity is bad. Sending " << endl;
01114                         stunCreateErrorResponse(*resp, 4, 3, "Unknown username. Try test with password 1234");
01115                         return true;
01116                      }
01117 
01118                      // need to compute this later after message is filled in
01119                      resp->hasMessageIntegrity = true;
01120                      assert(req.hasUsername);
01121                      resp->hasUsername = true;
01122                      resp->username = req.username; // copy username in
01123                   }
01124                }
01125                else
01126                {
01127                   if (verbose) clog << "Invalid username: " << req.username.value << "Send 430." << endl;
01128                }
01129             }
01130          }
01131 
01132          // TODO !jf! should check for unknown attributes here and send 420 listing the
01133          // unknown attributes.
01134 
01135          if ( respondTo.port == 0 ) respondTo = from;
01136          if ( mapped.port == 0 ) mapped = from;
01137 
01138          *changeIp   = ( flags & ChangeIpFlag )?true:false;
01139          *changePort = ( flags & ChangePortFlag )?true:false;
01140 
01141          if (verbose)
01142          {
01143             clog << "Request is valid:" << endl;
01144             clog << "\t flags=" << flags << endl;
01145             clog << "\t changeIp=" << *changeIp << endl;
01146             clog << "\t changePort=" << *changePort << endl;
01147             clog << "\t from = " << from << endl;
01148             clog << "\t respond to = " << respondTo << endl;
01149             clog << "\t mapped = " << mapped << endl;
01150          }
01151 
01152          // form the outgoing message
01153          resp->msgHdr.msgType = BindResponseMsg;
01154          for ( int i=0; i<16; i++ )
01155          {
01156             resp->msgHdr.id.octet[i] = req.msgHdr.id.octet[i];
01157          }
01158 
01159          if ( req.xorOnly == false )
01160          {
01161             resp->hasMappedAddress = true;
01162             resp->mappedAddress.ipv4.port = mapped.port;
01163             resp->mappedAddress.ipv4.addr = mapped.addr;
01164          }
01165 
01166          if (1) // do xorMapped address or not
01167          {
01168             resp->hasXorMappedAddress = true;
01169             UInt16 id16 = req.msgHdr.id.octet[0]<<8
01170                | req.msgHdr.id.octet[1];
01171             UInt32 id32 = req.msgHdr.id.octet[0]<<24
01172                | req.msgHdr.id.octet[1]<<16
01173                | req.msgHdr.id.octet[2]<<8
01174                | req.msgHdr.id.octet[3];
01175             resp->xorMappedAddress.ipv4.port = mapped.port^id16;
01176             resp->xorMappedAddress.ipv4.addr = mapped.addr^id32;
01177          }
01178 
01179          resp->hasSourceAddress = true;
01180          resp->sourceAddress.ipv4.port = (*changePort) ? altAddr.port : myAddr.port;
01181          resp->sourceAddress.ipv4.addr = (*changeIp)   ? altAddr.addr : myAddr.addr;
01182 
01183          resp->hasChangedAddress = true;
01184          resp->changedAddress.ipv4.port = altAddr.port;
01185          resp->changedAddress.ipv4.addr = altAddr.addr;
01186 
01187          if ( secondary.port != 0 )
01188          {
01189             resp->hasSecondaryAddress = true;
01190             resp->secondaryAddress.ipv4.port = secondary.port;
01191             resp->secondaryAddress.ipv4.addr = secondary.addr;
01192          }
01193 
01194          if ( req.hasUsername && req.username.sizeValue > 0 )
01195          {
01196             // copy username in
01197             resp->hasUsername = true;
01198             assert( req.username.sizeValue % 4 == 0 );
01199             assert( req.username.sizeValue < STUN_MAX_STRING );
01200             memcpy( resp->username.value, req.username.value, req.username.sizeValue );
01201             resp->username.sizeValue = req.username.sizeValue;
01202          }
01203 
01204          if (1) // add ServerName
01205          {
01206             resp->hasServerName = true;
01207             const char serverName[] = "Vovida.org " STUN_VERSION; // must pad to mult of 4
01208 
01209             assert( sizeof(serverName) < STUN_MAX_STRING );
01210             //cerr << "sizeof serverName is "  << sizeof(serverName) << endl;
01211             assert( sizeof(serverName)%4 == 0 );
01212             memcpy( resp->serverName.value, serverName, sizeof(serverName));
01213             resp->serverName.sizeValue = sizeof(serverName);
01214          }
01215 
01216          if ( req.hasMessageIntegrity & req.hasUsername )
01217          {
01218             // this creates the password that will be used in the HMAC when then
01219             // messages is sent
01220             stunCreatePassword( req.username, hmacPassword );
01221          }
01222 
01223          if (req.hasUsername && (req.username.sizeValue > 64 ) )
01224          {
01225             UInt32 source;
01226             assert( sizeof(int) == sizeof(UInt32) );
01227 
01228             sscanf(req.username.value, "%x", &source);
01229             resp->hasReflectedFrom = true;
01230             resp->reflectedFrom.ipv4.port = 0;
01231             resp->reflectedFrom.ipv4.addr = source;
01232          }
01233 
01234          destination->port = respondTo.port;
01235          destination->addr = respondTo.addr;
01236 
01237          return true;
01238 
01239       default:
01240          if (verbose) clog << "Unknown or unsupported request " << endl;
01241          return false;
01242    }
01243 
01244    assert(0);
01245    return false;
01246 }
01247 
01248 bool
01249 stunInitServer(StunServerInfo& info, const StunAddress4& myAddr,
01250                const StunAddress4& altAddr, int startMediaPort, bool verbose )
01251 {
01252    assert( myAddr.port != 0 );
01253    assert( altAddr.port!= 0 );
01254    assert( myAddr.addr  != 0 );
01255    //assert( altAddr.addr != 0 );
01256 
01257    info.myAddr = myAddr;
01258    info.altAddr = altAddr;
01259 
01260    info.myFd = STUN_INVALID_SOCKET;
01261    info.altPortFd = STUN_INVALID_SOCKET;
01262    info.altIpFd = STUN_INVALID_SOCKET;
01263    info.altIpPortFd = STUN_INVALID_SOCKET;
01264 
01265    memset(info.relays, 0, sizeof(info.relays));
01266    if (startMediaPort > 0)
01267    {
01268       info.relay = true;
01269 
01270       for (int i=0; i<MAX_MEDIA_RELAYS; ++i)
01271       {
01272          StunMediaRelay* relay = &info.relays[i];
01273          relay->relayPort = startMediaPort+i;
01274          relay->fd = 0;
01275          relay->expireTime = 0;
01276       }
01277    }
01278    else
01279    {
01280       info.relay = false;
01281    }
01282 
01283    if ((info.myFd = openPort(myAddr.port, myAddr.addr,verbose)) == STUN_INVALID_SOCKET)
01284    {
01285       clog << "Can't open " << myAddr << endl;
01286       stunStopServer(info);
01287 
01288       return false;
01289    }
01290    //if (verbose) clog << "Opened " << myAddr.addr << ":" << myAddr.port << " --> " << info.myFd << endl;
01291 
01292    if ((info.altPortFd = openPort(altAddr.port,myAddr.addr,verbose)) == STUN_INVALID_SOCKET)
01293    {
01294       clog << "Can't open " << myAddr << endl;
01295       stunStopServer(info);
01296       return false;
01297    }
01298    //if (verbose) clog << "Opened " << myAddr.addr << ":" << altAddr.port << " --> " << info.altPortFd << endl;
01299 
01300 
01301    info.altIpFd = STUN_INVALID_SOCKET;
01302    if (  altAddr.addr != 0 )
01303    {
01304       if ((info.altIpFd = openPort( myAddr.port, altAddr.addr,verbose)) == STUN_INVALID_SOCKET)
01305       {
01306          clog << "Can't open " << altAddr << endl;
01307          stunStopServer(info);
01308          return false;
01309       }
01310       //if (verbose) clog << "Opened " << altAddr.addr << ":" << myAddr.port << " --> " << info.altIpFd << endl;;
01311    }
01312 
01313    info.altIpPortFd = STUN_INVALID_SOCKET;
01314    if (  altAddr.addr != 0 )
01315    {  if ((info.altIpPortFd = openPort(altAddr.port, altAddr.addr,verbose)) == STUN_INVALID_SOCKET)
01316       {
01317          clog << "Can't open " << altAddr << endl;
01318          stunStopServer(info);
01319          return false;
01320       }
01321       //if (verbose) clog << "Opened " << altAddr.addr << ":" << altAddr.port << " --> " << info.altIpPortFd << endl;;
01322    }
01323 
01324    return true;
01325 }
01326 
01327 void
01328 stunStopServer(StunServerInfo& info)
01329 {
01330    if (info.myFd > 0) stunclosesocket(info.myFd);
01331    if (info.altPortFd > 0) stunclosesocket(info.altPortFd);
01332    if (info.altIpFd > 0) stunclosesocket(info.altIpFd);
01333    if (info.altIpPortFd > 0) stunclosesocket(info.altIpPortFd);
01334 
01335    if (info.relay)
01336    {
01337       for (int i=0; i<MAX_MEDIA_RELAYS; ++i)
01338       {
01339          StunMediaRelay* relay = &info.relays[i];
01340          if (relay->fd)
01341          {
01342             stunclosesocket(relay->fd);
01343             relay->fd = 0;
01344          }
01345       }
01346    }
01347 }
01348 
01349 
01350 bool
01351 stunServerProcess(StunServerInfo& info, bool verbose)
01352 {
01353    char msg[STUN_MAX_MESSAGE_SIZE];
01354    int msgLen = sizeof(msg);
01355 
01356    bool ok = false;
01357    bool recvAltIp =false;
01358    bool recvAltPort = false;
01359 
01360    fd_set fdSet;
01361    Socket maxFd=0;
01362 
01363    FD_ZERO(&fdSet);
01364    FD_SET(info.myFd,&fdSet);
01365    if ( info.myFd >= maxFd ) maxFd=info.myFd+1;
01366    FD_SET(info.altPortFd,&fdSet);
01367    if ( info.altPortFd >= maxFd ) maxFd=info.altPortFd+1;
01368 
01369    if ( info.altIpFd != STUN_INVALID_SOCKET )
01370    {
01371       FD_SET(info.altIpFd,&fdSet);
01372       if (info.altIpFd>=maxFd) maxFd=info.altIpFd+1;
01373    }
01374    if ( info.altIpPortFd != STUN_INVALID_SOCKET )
01375    {
01376       FD_SET(info.altIpPortFd,&fdSet);
01377       if (info.altIpPortFd>=maxFd) maxFd=info.altIpPortFd+1;
01378    }
01379 
01380    if (info.relay)
01381    {
01382       for (int i=0; i<MAX_MEDIA_RELAYS; ++i)
01383       {
01384          StunMediaRelay* relay = &info.relays[i];
01385          if (relay->fd)
01386          {
01387             FD_SET(relay->fd, &fdSet);
01388             if (relay->fd >= maxFd)
01389                         {
01390                                 maxFd=relay->fd+1;
01391                         }
01392          }
01393       }
01394    }
01395 
01396    if ( info.altIpFd != STUN_INVALID_SOCKET )
01397    {
01398       FD_SET(info.altIpFd,&fdSet);
01399       if (info.altIpFd>=maxFd) maxFd=info.altIpFd+1;
01400    }
01401    if ( info.altIpPortFd != STUN_INVALID_SOCKET )
01402    {
01403       FD_SET(info.altIpPortFd,&fdSet);
01404       if (info.altIpPortFd>=maxFd) maxFd=info.altIpPortFd+1;
01405    }
01406 
01407    struct timeval tv;
01408    tv.tv_sec = 0;
01409    tv.tv_usec = 1000;
01410 
01411    int e = select( maxFd, &fdSet, NULL,NULL, &tv );
01412    if (e < 0)
01413    {
01414       int err = getErrno();
01415       clog << "Error on select: " << strerror(err) << endl;
01416    }
01417    else if (e >= 0)
01418    {
01419       StunAddress4 from;
01420 
01421       // do the media relaying
01422       if (info.relay)
01423       {
01424          time_t now = time(0);
01425          for (int i=0; i<MAX_MEDIA_RELAYS; ++i)
01426          {
01427             StunMediaRelay* relay = &info.relays[i];
01428             if (relay->fd)
01429             {
01430                if (FD_ISSET(relay->fd, &fdSet))
01431                {
01432                   char msg[MAX_RTP_MSG_SIZE];
01433                   int msgLen = sizeof(msg);
01434 
01435                   StunAddress4 rtpFrom;
01436                   ok = getMessage( relay->fd, msg, &msgLen, &rtpFrom.addr, &rtpFrom.port ,verbose);
01437                   if (ok)
01438                   {
01439                      sendMessage(info.myFd, msg, msgLen, relay->destination.addr, relay->destination.port, verbose);
01440                      relay->expireTime = now + MEDIA_RELAY_TIMEOUT;
01441                      if ( verbose ) clog << "Relay packet on "
01442                                          << relay->fd
01443                                          << " from " << rtpFrom
01444                                          << " -> " << relay->destination
01445                                          << endl;
01446                   }
01447                }
01448                else if (now > relay->expireTime)
01449                {
01450                   stunclosesocket(relay->fd);
01451                   relay->fd = 0;
01452                }
01453             }
01454          }
01455       }
01456 
01457 
01458       if (FD_ISSET(info.myFd,&fdSet))
01459       {
01460          if (verbose) clog << "received on A1:P1" << endl;
01461          recvAltIp = false;
01462          recvAltPort = false;
01463          ok = getMessage( info.myFd, msg, &msgLen, &from.addr, &from.port,verbose );
01464       }
01465       else if (FD_ISSET(info.altPortFd, &fdSet))
01466       {
01467          if (verbose) clog << "received on A1:P2" << endl;
01468          recvAltIp = false;
01469          recvAltPort = true;
01470          ok = getMessage( info.altPortFd, msg, &msgLen, &from.addr, &from.port,verbose );
01471       }
01472       else if ( (info.altIpFd!=STUN_INVALID_SOCKET) && FD_ISSET(info.altIpFd,&fdSet))
01473       {
01474          if (verbose) clog << "received on A2:P1" << endl;
01475          recvAltIp = true;
01476          recvAltPort = false;
01477          ok = getMessage( info.altIpFd, msg, &msgLen, &from.addr, &from.port ,verbose);
01478       }
01479       else if ( (info.altIpPortFd!=STUN_INVALID_SOCKET) && FD_ISSET(info.altIpPortFd, &fdSet))
01480       {
01481          if (verbose) clog << "received on A2:P2" << endl;
01482          recvAltIp = true;
01483          recvAltPort = true;
01484          ok = getMessage( info.altIpPortFd, msg, &msgLen, &from.addr, &from.port,verbose );
01485       }
01486       else
01487       {
01488          return true;
01489       }
01490 
01491       int relayPort = 0;
01492       if (info.relay)
01493       {
01494          for (int i=0; i<MAX_MEDIA_RELAYS; ++i)
01495          {
01496             StunMediaRelay* relay = &info.relays[i];
01497             if (relay->destination.addr == from.addr &&
01498                 relay->destination.port == from.port)
01499             {
01500                relayPort = relay->relayPort;
01501                relay->expireTime = time(0) + MEDIA_RELAY_TIMEOUT;
01502                break;
01503             }
01504          }
01505 
01506          if (relayPort == 0)
01507          {
01508             for (int i=0; i<MAX_MEDIA_RELAYS; ++i)
01509             {
01510                StunMediaRelay* relay = &info.relays[i];
01511                if (relay->fd == 0)
01512                {
01513                   if ( verbose ) clog << "Open relay port " << relay->relayPort << endl;
01514 
01515                   relay->fd = openPort(relay->relayPort, info.myAddr.addr, verbose);
01516                   relay->destination.addr = from.addr;
01517                   relay->destination.port = from.port;
01518                   relay->expireTime = time(0) + MEDIA_RELAY_TIMEOUT;
01519                   relayPort = relay->relayPort;
01520                   break;
01521                }
01522             }
01523          }
01524       }
01525 
01526       if ( !ok )
01527       {
01528          if ( verbose ) clog << "Get message did not return a valid message" <<endl;
01529          return true;
01530       }
01531 
01532       if ( verbose ) clog << "Got a request (len=" << msgLen << ") from " << from << endl;
01533 
01534       if ( msgLen <= 0 )
01535       {
01536          return true;
01537       }
01538 
01539       bool changePort = false;
01540       bool changeIp = false;
01541 
01542       StunMessage resp;
01543       StunAddress4 dest;
01544       StunAtrString hmacPassword;
01545       hmacPassword.sizeValue = 0;
01546 
01547       StunAddress4 secondary;
01548       secondary.port = 0;
01549       secondary.addr = 0;
01550 
01551       if (info.relay && relayPort)
01552       {
01553          secondary = from;
01554 
01555          from.addr = info.myAddr.addr;
01556          from.port = relayPort;
01557       }
01558 
01559       ok = stunServerProcessMsg( msg, msgLen, from, secondary,
01560                                  recvAltIp ? info.altAddr : info.myAddr,
01561                                  recvAltIp ? info.myAddr : info.altAddr,
01562                                  &resp,
01563                                  &dest,
01564                                  &hmacPassword,
01565                                  &changePort,
01566                                  &changeIp,
01567                                  verbose );
01568 
01569       if ( !ok )
01570       {
01571          if ( verbose ) clog << "Failed to parse message" << endl;
01572          return true;
01573       }
01574 
01575       char buf[STUN_MAX_MESSAGE_SIZE];
01576       int len = sizeof(buf);
01577 
01578       len = stunEncodeMessage( resp, buf, len, hmacPassword,verbose );
01579 
01580       if ( dest.addr == 0 )  ok=false;
01581       if ( dest.port == 0 ) ok=false;
01582 
01583       if ( ok )
01584       {
01585          assert( dest.addr != 0 );
01586          assert( dest.port != 0 );
01587 
01588          Socket sendFd;
01589 
01590          bool sendAltIp   = recvAltIp;   // send on the received IP address
01591          bool sendAltPort = recvAltPort; // send on the received port
01592 
01593          if ( changeIp )   sendAltIp   = !sendAltIp;   // if need to change IP, then flip logic
01594          if ( changePort ) sendAltPort = !sendAltPort; // if need to change port, then flip logic
01595 
01596          if ( !sendAltPort )
01597          {
01598             if ( !sendAltIp )
01599             {
01600                sendFd = info.myFd;
01601             }
01602             else
01603             {
01604                sendFd = info.altIpFd;
01605             }
01606          }
01607          else
01608          {
01609             if ( !sendAltIp )
01610             {
01611                sendFd = info.altPortFd;
01612             }
01613             else
01614             {
01615                sendFd = info.altIpPortFd;
01616             }
01617          }
01618 
01619          if ( sendFd != STUN_INVALID_SOCKET )
01620          {
01621             sendMessage( sendFd, buf, len, dest.addr, dest.port, verbose );
01622          }
01623       }
01624    }
01625 
01626    return true;
01627 }
01628 
01629 int
01630 stunFindLocalInterfaces(UInt32* addresses,int maxRet)
01631 {
01632 #if defined(WIN32) || defined(__sparc__)
01633    return 0;
01634 #else
01635    struct ifconf ifc;
01636 
01637    int s = socket( AF_INET, SOCK_DGRAM, 0 );
01638    int len = 100 * sizeof(struct ifreq);
01639 
01640    char buf[ len ];
01641 
01642    ifc.ifc_len = len;
01643    ifc.ifc_buf = buf;
01644 
01645    int e = ioctl(s,SIOCGIFCONF,&ifc);
01646    char *ptr = buf;
01647    int tl = ifc.ifc_len;
01648    int count=0;
01649 
01650    while ( (tl > 0) && ( count < maxRet) )
01651    {
01652       struct ifreq* ifr = (struct ifreq *)ptr;
01653 
01654       int si = sizeof(ifr->ifr_name) + sizeof(struct sockaddr);
01655       tl -= si;
01656       ptr += si;
01657       //char* name = ifr->ifr_ifrn.ifrn_name;
01658       //cerr << "name = " << name << endl;
01659 
01660       struct ifreq ifr2;
01661       ifr2 = *ifr;
01662 
01663       e = ioctl(s,SIOCGIFADDR,&ifr2);
01664       if ( e == -1 )
01665       {
01666          break;
01667       }
01668 
01669       //cerr << "ioctl addr e = " << e << endl;
01670 
01671       struct sockaddr a = ifr2.ifr_addr;
01672       struct sockaddr_in* addr = (struct sockaddr_in*) &a;
01673 
01674       UInt32 ai = ntohl( addr->sin_addr.s_addr );
01675       if (int((ai>>24)&0xFF) != 127)
01676       {
01677          addresses[count++] = ai;
01678       }
01679 
01680 #if 0
01681       cerr << "Detected interface "
01682            << int((ai>>24)&0xFF) << "."
01683            << int((ai>>16)&0xFF) << "."
01684            << int((ai>> 8)&0xFF) << "."
01685            << int((ai    )&0xFF) << endl;
01686 #endif
01687    }
01688 
01689    stunclosesocket(s);
01690 
01691    return count;
01692 #endif
01693 }
01694 
01695 
01696 void
01697 stunBuildReqSimple( StunMessage* msg,
01698                     const StunAtrString& username,
01699                     bool changePort, bool changeIp, unsigned int id )
01700 {
01701    assert( msg );
01702    memset( msg , 0 , sizeof(*msg) );
01703 
01704    msg->msgHdr.msgType = BindRequestMsg;
01705 
01706    for ( int i=0; i<16; i=i+4 )
01707    {
01708       assert(i+3<16);
01709       int r = stunRand();
01710       msg->msgHdr.id.octet[i+0]= r>>0;
01711       msg->msgHdr.id.octet[i+1]= r>>8;
01712       msg->msgHdr.id.octet[i+2]= r>>16;
01713       msg->msgHdr.id.octet[i+3]= r>>24;
01714    }
01715 
01716    if ( id != 0 )
01717    {
01718       msg->msgHdr.id.octet[0] = id;
01719    }
01720 
01721    msg->hasChangeRequest = true;
01722    msg->changeRequest.value =(changeIp?ChangeIpFlag:0) |
01723       (changePort?ChangePortFlag:0);
01724 
01725    if ( username.sizeValue > 0 )
01726    {
01727       msg->hasUsername = true;
01728       msg->username = username;
01729    }
01730 }
01731 
01732 
01733 static void
01734 stunSendTest( Socket myFd, StunAddress4& dest,
01735               const StunAtrString& username, const StunAtrString& password,
01736               int testNum, bool verbose )
01737 {
01738    assert( dest.addr != 0 );
01739    assert( dest.port != 0 );
01740 
01741    bool changePort=false;
01742    bool changeIP=false;
01743    bool discard=false;
01744 
01745    switch (testNum)
01746    {
01747       case 1:
01748       case 10:
01749       case 11:
01750          break;
01751       case 2:
01752          //changePort=true;
01753          changeIP=true;
01754          break;
01755       case 3:
01756          changePort=true;
01757          break;
01758       case 4:
01759          changeIP=true;
01760          break;
01761       case 5:
01762          discard=true;
01763          break;
01764       default:
01765          cerr << "Test " << testNum <<" is unkown\n";
01766          assert(0);
01767    }
01768 
01769    StunMessage req;
01770    memset(&req, 0, sizeof(StunMessage));
01771 
01772    stunBuildReqSimple( &req, username,
01773                        changePort , changeIP ,
01774                        testNum );
01775 
01776    char buf[STUN_MAX_MESSAGE_SIZE];
01777    int len = STUN_MAX_MESSAGE_SIZE;
01778 
01779    len = stunEncodeMessage( req, buf, len, password,verbose );
01780 
01781    if ( verbose )
01782    {
01783       clog << "About to send msg of len " << len << " to " << dest << endl;
01784    }
01785 
01786    sendMessage( myFd, buf, len, dest.addr, dest.port, verbose );
01787 
01788    // add some delay so the packets don't get sent too quickly
01789 #ifdef WIN32 // !cj! TODO - should fix this up in windows
01790                  clock_t now = clock();
01791                  assert( CLOCKS_PER_SEC == 1000 );
01792                  while ( clock() <= now+10 ) { };
01793 #else
01794                  usleep(10*1000);
01795 #endif
01796 
01797 }
01798 
01799 
01800 void
01801 stunGetUserNameAndPassword(  const StunAddress4& dest,
01802                              StunAtrString* username,
01803                              StunAtrString* password)
01804 {
01805    // !cj! This is totally bogus - need to make TLS connection to dest and get a
01806    // username and password to use
01807    stunCreateUserName(dest, username);
01808    stunCreatePassword(*username, password);
01809 }
01810 
01811 
01812 void
01813 stunTest( StunAddress4& dest, int testNum, bool verbose, StunAddress4* sAddr )
01814 {
01815    assert( dest.addr != 0 );
01816    assert( dest.port != 0 );
01817 
01818    int port = stunRandomPort();
01819    UInt32 interfaceIp=0;
01820    if (sAddr)
01821    {
01822       interfaceIp = sAddr->addr;
01823       if ( sAddr->port != 0 )
01824       {
01825         port = sAddr->port;
01826       }
01827    }
01828    Socket myFd = openPort(port,interfaceIp,verbose);
01829 
01830    StunAtrString username;
01831    StunAtrString password;
01832 
01833    username.sizeValue = 0;
01834    password.sizeValue = 0;
01835 
01836 #ifdef USE_TLS
01837    stunGetUserNameAndPassword( dest, username, password );
01838 #endif
01839 
01840    stunSendTest( myFd, dest, username, password, testNum, verbose );
01841 
01842    char msg[STUN_MAX_MESSAGE_SIZE];
01843    int msgLen = STUN_MAX_MESSAGE_SIZE;
01844 
01845    StunAddress4 from;
01846    getMessage( myFd,
01847                msg,
01848                &msgLen,
01849                &from.addr,
01850                &from.port,verbose );
01851 
01852    StunMessage resp;
01853    memset(&resp, 0, sizeof(StunMessage));
01854 
01855    if ( verbose ) clog << "Got a response" << endl;
01856    bool ok = stunParseMessage( msg,msgLen, resp,verbose );
01857 
01858    if ( verbose )
01859    {
01860       clog << "\t ok=" << ok << endl;
01861       clog << "\t id=" << resp.msgHdr.id << endl;
01862       clog << "\t mappedAddr=" << resp.mappedAddress.ipv4 << endl;
01863       clog << "\t changedAddr=" << resp.changedAddress.ipv4 << endl;
01864       clog << endl;
01865    }
01866 
01867    if (sAddr)
01868    {
01869       sAddr->port = resp.mappedAddress.ipv4.port;
01870       sAddr->addr = resp.mappedAddress.ipv4.addr;
01871    }
01872 }
01873 
01874 
01875 NatType
01876 stunNatType( StunAddress4& dest,
01877              bool verbose,
01878              bool* preservePort, // if set, is return for if NAT preservers ports or not
01879              bool* hairpin,  // if set, is the return for if NAT will hairpin packets
01880              int port, // port to use for the test, 0 to choose random port
01881              StunAddress4* sAddr // NIC to use
01882    )
01883 {
01884    assert( dest.addr != 0 );
01885    assert( dest.port != 0 );
01886 
01887    if ( hairpin )
01888    {
01889       *hairpin = false;
01890    }
01891 
01892    if ( port == 0 )
01893    {
01894       port = stunRandomPort();
01895    }
01896    UInt32 interfaceIp=0;
01897    if (sAddr)
01898    {
01899       interfaceIp = sAddr->addr;
01900    }
01901    Socket myFd1 = openPort(port,interfaceIp,verbose);
01902    Socket myFd2 = openPort(port+1,interfaceIp,verbose);
01903 
01904    if ( ( myFd1 == STUN_INVALID_SOCKET) || ( myFd2 == STUN_INVALID_SOCKET) )
01905    {
01906         cerr << "Some problem opening port/interface to send on" << endl;
01907        return StunTypeFailure;
01908    }
01909 
01910    assert( myFd1 != STUN_INVALID_SOCKET );
01911    assert( myFd2 != STUN_INVALID_SOCKET );
01912 
01913    bool respTestI=false;
01914    bool isNat=true;
01915    StunAddress4 testIchangedAddr;
01916    StunAddress4 testImappedAddr;
01917    bool respTestI2=false;
01918    bool mappedIpSame = true;
01919    StunAddress4 testI2mappedAddr;
01920    StunAddress4 testI2dest=dest;
01921    bool respTestII=false;
01922    bool respTestIII=false;
01923 
01924    bool respTestHairpin=false;
01925    bool respTestPreservePort=false;
01926 
01927    memset(&testImappedAddr,0,sizeof(testImappedAddr));
01928 
01929    StunAtrString username;
01930    StunAtrString password;
01931 
01932    username.sizeValue = 0;
01933    password.sizeValue = 0;
01934 
01935 #ifdef USE_TLS
01936    stunGetUserNameAndPassword( dest, username, password );
01937 #endif
01938 
01939    int count=0;
01940    while ( count < 7 )
01941    {
01942       struct timeval tv;
01943       fd_set fdSet;
01944 #ifdef WIN32
01945       unsigned int fdSetSize;
01946 #else
01947       int fdSetSize;
01948 #endif
01949       FD_ZERO(&fdSet); fdSetSize=0;
01950       FD_SET(myFd1,&fdSet); fdSetSize = (myFd1+1>fdSetSize) ? myFd1+1 : fdSetSize;
01951       FD_SET(myFd2,&fdSet); fdSetSize = (myFd2+1>fdSetSize) ? myFd2+1 : fdSetSize;
01952       tv.tv_sec=0;
01953       tv.tv_usec=150*1000; // 150 ms
01954       if ( count == 0 ) tv.tv_usec=0;
01955 
01956       int  err = select(fdSetSize, &fdSet, NULL, NULL, &tv);
01957       int e = getErrno();
01958       if ( err == STUN_SOCKET_ERROR )
01959       {
01960          // error occured
01961          cerr << "Error " << e << " " << strerror(e) << " in select" << endl;
01962         return StunTypeFailure;
01963      }
01964       else if ( err == 0 )
01965       {
01966          // timeout occured
01967          count++;
01968 
01969          if ( !respTestI )
01970          {
01971             stunSendTest( myFd1, dest, username, password, 1 ,verbose );
01972          }
01973 
01974          if ( (!respTestI2) && respTestI )
01975          {
01976             // check the address to send to if valid
01977             if (  ( testI2dest.addr != 0 ) &&
01978                   ( testI2dest.port != 0 ) )
01979             {
01980                stunSendTest( myFd1, testI2dest, username, password, 10  ,verbose);
01981             }
01982          }
01983 
01984          if ( !respTestII )
01985          {
01986             stunSendTest( myFd2, dest, username, password, 2 ,verbose );
01987          }
01988 
01989          if ( !respTestIII )
01990          {
01991             stunSendTest( myFd2, dest, username, password, 3 ,verbose );
01992          }
01993 
01994          if ( respTestI && (!respTestHairpin) )
01995          {
01996             if (  ( testImappedAddr.addr != 0 ) &&
01997                   ( testImappedAddr.port != 0 ) )
01998             {
01999                stunSendTest( myFd1, testImappedAddr, username, password, 11 ,verbose );
02000             }
02001          }
02002       }
02003       else
02004       {
02005          //if (verbose) clog << "-----------------------------------------" << endl;
02006          assert( err>0 );
02007          // data is avialbe on some fd
02008 
02009          for ( int i=0; i<2; i++)
02010          {
02011             Socket myFd;
02012             if ( i==0 )
02013             {
02014                myFd=myFd1;
02015             }
02016             else
02017             {
02018                myFd=myFd2;
02019             }
02020 
02021             if ( myFd!=STUN_INVALID_SOCKET )
02022             {
02023                if ( FD_ISSET(myFd,&fdSet) )
02024                {
02025                   char msg[STUN_MAX_MESSAGE_SIZE];
02026                   int msgLen = sizeof(msg);
02027 
02028                   StunAddress4 from;
02029 
02030                   getMessage( myFd,
02031                               msg,
02032                               &msgLen,
02033                               &from.addr,
02034                               &from.port,verbose );
02035 
02036                   StunMessage resp;
02037                   memset(&resp, 0, sizeof(StunMessage));
02038 
02039                   stunParseMessage( msg,msgLen, resp,verbose );
02040 
02041                   if ( verbose )
02042                   {
02043                      clog << "Received message of type " << resp.msgHdr.msgType
02044                           << "  id=" << (int)(resp.msgHdr.id.octet[0]) << endl;
02045                   }
02046 
02047                   switch( resp.msgHdr.id.octet[0] )
02048                   {
02049                      case 1:
02050                      {
02051                         if ( !respTestI )
02052                         {
02053 
02054                            testIchangedAddr.addr = resp.changedAddress.ipv4.addr;
02055                            testIchangedAddr.port = resp.changedAddress.ipv4.port;
02056                            testImappedAddr.addr = resp.mappedAddress.ipv4.addr;
02057                            testImappedAddr.port = resp.mappedAddress.ipv4.port;
02058 
02059                            respTestPreservePort = ( testImappedAddr.port == port );
02060                            if ( preservePort )
02061                            {
02062                               *preservePort = respTestPreservePort;
02063                            }
02064 
02065                            testI2dest.addr = resp.changedAddress.ipv4.addr;
02066 
02067                            if (sAddr)
02068                            {
02069                               sAddr->port = testImappedAddr.port;
02070                               sAddr->addr = testImappedAddr.addr;
02071                            }
02072 
02073                            count = 0;
02074                         }
02075                         respTestI=true;
02076                      }
02077                      break;
02078                      case 2:
02079                      {
02080                         respTestII=true;
02081                      }
02082                      break;
02083                      case 3:
02084                      {
02085                         respTestIII=true;
02086                      }
02087                      break;
02088                      case 10:
02089                      {
02090                         if ( !respTestI2 )
02091                         {
02092                            testI2mappedAddr.addr = resp.mappedAddress.ipv4.addr;
02093                            testI2mappedAddr.port = resp.mappedAddress.ipv4.port;
02094 
02095                            mappedIpSame = false;
02096                            if ( (testI2mappedAddr.addr  == testImappedAddr.addr ) &&
02097                                 (testI2mappedAddr.port == testImappedAddr.port ))
02098                            {
02099                               mappedIpSame = true;
02100                            }
02101 
02102 
02103                         }
02104                         respTestI2=true;
02105                      }
02106                      break;
02107                      case 11:
02108                      {
02109 
02110                         if ( hairpin )
02111                         {
02112                            *hairpin = true;
02113                         }
02114                         respTestHairpin = true;
02115                      }
02116                      break;
02117                   }
02118                }
02119             }
02120          }
02121       }
02122    }
02123 
02124    // see if we can bind to this address
02125    //cerr << "try binding to " << testImappedAddr << endl;
02126    Socket s = openPort( 0/*use ephemeral*/, testImappedAddr.addr, false );
02127    if ( s != STUN_INVALID_SOCKET )
02128    {
02129       stunclosesocket(s);
02130       isNat = false;
02131       //cerr << "binding worked" << endl;
02132    }
02133    else
02134    {
02135       isNat = true;
02136       //cerr << "binding failed" << endl;
02137    }
02138 
02139    if (verbose)
02140    {
02141       clog << "test I = " << respTestI << endl;
02142       clog << "test II = " << respTestII << endl;
02143       clog << "test III = " << respTestIII << endl;
02144       clog << "test I(2) = " << respTestI2 << endl;
02145       clog << "is nat  = " << isNat <<endl;
02146       clog << "mapped IP same = " << mappedIpSame << endl;
02147       clog << "hairpin = " << respTestHairpin << endl;
02148       clog << "preserver port = " << respTestPreservePort << endl;
02149    }
02150 
02151 #if 0
02152    // implement logic flow chart from draft RFC
02153    if ( respTestI )
02154    {
02155       if ( isNat )
02156       {
02157          if (respTestII)
02158          {
02159             return StunTypeConeNat;
02160          }
02161          else
02162          {
02163             if ( mappedIpSame )
02164             {
02165                if ( respTestIII )
02166                {
02167                   return StunTypeRestrictedNat;
02168                }
02169                else
02170                {
02171                   return StunTypePortRestrictedNat;
02172                }
02173             }
02174             else
02175             {
02176                return StunTypeSymNat;
02177             }
02178          }
02179       }
02180       else
02181       {
02182          if (respTestII)
02183          {
02184             return StunTypeOpen;
02185          }
02186          else
02187          {
02188             return StunTypeSymFirewall;
02189          }
02190       }
02191    }
02192    else
02193    {
02194       return StunTypeBlocked;
02195    }
02196 #else
02197    if ( respTestI ) // not blocked
02198    {
02199       if ( isNat )
02200       {
02201          if ( mappedIpSame )
02202          {
02203             if (respTestII)
02204             {
02205                return StunTypeIndependentFilter;
02206             }
02207             else
02208             {
02209                if ( respTestIII )
02210                {
02211                   return StunTypeDependentFilter;
02212                }
02213                else
02214                {
02215                   return StunTypePortDependedFilter;
02216                }
02217             }
02218          }
02219          else // mappedIp is not same
02220          {
02221             return StunTypeDependentMapping;
02222          }
02223       }
02224       else  // isNat is false
02225       {
02226          if (respTestII)
02227          {
02228             return StunTypeOpen;
02229          }
02230          else
02231          {
02232             return StunTypeFirewall;
02233          }
02234       }
02235    }
02236    else
02237    {
02238       return StunTypeBlocked;
02239    }
02240 #endif
02241 
02242    return StunTypeUnknown;
02243 }
02244 
02245 
02246 int
02247 stunOpenSocket( StunAddress4& dest, StunAddress4* mapAddr,
02248                 int port, StunAddress4* srcAddr,
02249                 bool verbose )
02250 {
02251    assert( dest.addr != 0 );
02252    assert( dest.port != 0 );
02253    assert( mapAddr );
02254 
02255    if ( port == 0 )
02256    {
02257       port = stunRandomPort();
02258    }
02259    unsigned int interfaceIp = 0;
02260    if ( srcAddr )
02261    {
02262       interfaceIp = srcAddr->addr;
02263    }
02264 
02265    Socket myFd = openPort(port,interfaceIp,verbose);
02266    if (myFd == STUN_INVALID_SOCKET)
02267    {
02268       return myFd;
02269    }
02270 
02271    char msg[STUN_MAX_MESSAGE_SIZE];
02272    int msgLen = sizeof(msg);
02273 
02274    StunAtrString username;
02275    StunAtrString password;
02276 
02277    username.sizeValue = 0;
02278    password.sizeValue = 0;
02279 
02280 #ifdef USE_TLS
02281    stunGetUserNameAndPassword( dest, username, password );
02282 #endif
02283 
02284    stunSendTest(myFd, dest, username, password, 1, 0/*false*/ );
02285 
02286    StunAddress4 from;
02287 
02288    getMessage( myFd, msg, &msgLen, &from.addr, &from.port,verbose );
02289 
02290    StunMessage resp;
02291    memset(&resp, 0, sizeof(StunMessage));
02292 
02293    bool ok = stunParseMessage( msg, msgLen, resp,verbose );
02294    if (!ok)
02295    {
02296       return -1;
02297    }
02298 
02299    StunAddress4 mappedAddr = resp.mappedAddress.ipv4;
02300    StunAddress4 changedAddr = resp.changedAddress.ipv4;
02301 
02302    //clog << "--- stunOpenSocket --- " << endl;
02303    //clog << "\treq  id=" << req.id << endl;
02304    //clog << "\tresp id=" << id << endl;
02305    //clog << "\tmappedAddr=" << mappedAddr << endl;
02306 
02307    *mapAddr = mappedAddr;
02308 
02309    return myFd;
02310 }
02311 
02312 
02313 bool
02314 stunOpenSocketPair( StunAddress4& dest, StunAddress4* mapAddr,
02315                     int* fd1, int* fd2,
02316                     int port, StunAddress4* srcAddr,
02317                     bool verbose )
02318 {
02319    assert( dest.addr!= 0 );
02320    assert( dest.port != 0 );
02321    assert( mapAddr );
02322 
02323    const int NUM=3;
02324 
02325    if ( port == 0 )
02326    {
02327       port = stunRandomPort();
02328    }
02329 
02330    *fd1=-1;
02331    *fd2=-1;
02332 
02333    char msg[STUN_MAX_MESSAGE_SIZE];
02334    int msgLen =sizeof(msg);
02335 
02336    StunAddress4 from;
02337    int fd[NUM];
02338    int i;
02339 
02340    unsigned int interfaceIp = 0;
02341    if ( srcAddr )
02342    {
02343       interfaceIp = srcAddr->addr;
02344    }
02345 
02346    for( i=0; i<NUM; i++)
02347    {
02348       fd[i] = openPort( (port == 0) ? 0 : (port + i),
02349                         interfaceIp, verbose);
02350       if (fd[i] < 0)
02351       {
02352          while (i > 0)
02353          {
02354             stunclosesocket(fd[--i]);
02355          }
02356          return false;
02357       }
02358    }
02359 
02360    StunAtrString username;
02361    StunAtrString password;
02362 
02363    username.sizeValue = 0;
02364    password.sizeValue = 0;
02365 
02366 #ifdef USE_TLS
02367    stunGetUserNameAndPassword( dest, username, password );
02368 #endif
02369 
02370    for( i=0; i<NUM; i++)
02371    {
02372       stunSendTest(fd[i], dest, username, password, 1/*testNum*/, verbose );
02373    }
02374 
02375    StunAddress4 mappedAddr[NUM];
02376    for( i=0; i<NUM; i++)
02377    {
02378       msgLen = sizeof(msg)/sizeof(*msg);
02379       getMessage( fd[i],
02380                   msg,
02381                   &msgLen,
02382                   &from.addr,
02383                   &from.port ,verbose);
02384 
02385       StunMessage resp;
02386       memset(&resp, 0, sizeof(StunMessage));
02387 
02388       bool ok = stunParseMessage( msg, msgLen, resp, verbose );
02389       if (!ok)
02390       {
02391          return false;
02392       }
02393 
02394       mappedAddr[i] = resp.mappedAddress.ipv4;
02395       StunAddress4 changedAddr = resp.changedAddress.ipv4;
02396    }
02397 
02398    if (verbose)
02399    {
02400       clog << "--- stunOpenSocketPair --- " << endl;
02401       for( i=0; i<NUM; i++)
02402       {
02403          clog << "\t mappedAddr=" << mappedAddr[i] << endl;
02404       }
02405    }
02406 
02407    if ( mappedAddr[0].port %2 == 0 )
02408    {
02409       if (  mappedAddr[0].port+1 ==  mappedAddr[1].port )
02410       {
02411          *mapAddr = mappedAddr[0];
02412          *fd1 = fd[0];
02413          *fd2 = fd[1];
02414          stunclosesocket( fd[2] );
02415          return true;
02416       }
02417    }
02418    else
02419    {
02420       if (( mappedAddr[1].port %2 == 0 )
02421           && (  mappedAddr[1].port+1 ==  mappedAddr[2].port ))
02422       {
02423          *mapAddr = mappedAddr[1];
02424          *fd1 = fd[1];
02425          *fd2 = fd[2];
02426          stunclosesocket( fd[0] );
02427          return true;
02428       }
02429    }
02430 
02431    // something failed, close all and return error
02432    for( i=0; i<NUM; i++)
02433    {
02434       stunclosesocket( fd[i] );
02435    }
02436 
02437    return false;
02438 }
02439 
02440 /* ====================================================================
02441  * The Vovida Software License, Version 1.0
02442  *
02443  * Copyright (c) 2000 Vovida Networks, Inc.  All rights reserved.
02444  *
02445  * Redistribution and use in source and binary forms, with or without
02446  * modification, are permitted provided that the following conditions
02447  * are met:
02448  *
02449  * 1. Redistributions of source code must retain the above copyright
02450  *    notice, this list of conditions and the following disclaimer.
02451  *
02452  * 2. Redistributions in binary form must reproduce the above copyright
02453  *    notice, this list of conditions and the following disclaimer in
02454  *    the documentation and/or other materials provided with the
02455  *    distribution.
02456  *
02457  * 3. The names "VOCAL", "Vovida Open Communication Application Library",
02458  *    and "Vovida Open Communication Application Library (VOCAL)" must
02459  *    not be used to endorse or promote products derived from this
02460  *    software without prior written permission. For written
02461  *    permission, please contact vocal@vovida.org.
02462  *
02463  * 4. Products derived from this software may not be called "VOCAL", nor
02464  *    may "VOCAL" appear in their name, without prior written
02465  *    permission of Vovida Networks, Inc.
02466  *
02467  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
02468  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
02469  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
02470  * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL VOVIDA
02471  * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
02472  * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
02473  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
02474  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
02475  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
02476  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
02477  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
02478  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
02479  * DAMAGE.
02480  *
02481  * ====================================================================
02482  *
02483  * This software consists of voluntary contributions made by Vovida
02484  * Networks, Inc. and many individuals on behalf of Vovida Networks,
02485  * Inc.  For more information on Vovida Networks, Inc., please see
02486  * <http://www.vovida.org/>.
02487  *
02488  */
02489 
02490 // Local Variables:
02491 // mode:c++
02492 // c-file-style:"ellemtel"
02493 // c-file-offsets:((case-label . +))
02494 // indent-tabs-mode:nil
02495 // End:
02496 
02497