📄 stun.cxx
字号:
tv.tv_usec=150*1000; // 150 ms if ( count == 0 ) tv.tv_usec=0; int err = select(fdSetSize, &fdSet, NULL, NULL, &tv); int e = getErrno(); if ( err == SOCKET_ERROR ) { // error occured cerr << "Error " << e << " " << strerror(e) << " in select" << endl; return StunTypeFailure; } else if ( err == 0 ) { // timeout occured count++; if ( !respTestI ) { stunSendTest( myFd1, dest, username, password, 1 ,verbose ); } if ( (!respTestI2) && respTestI ) { // check the address to send to if valid if ( ( testI2dest.addr != 0 ) && ( testI2dest.port != 0 ) ) { stunSendTest( myFd1, testI2dest, username, password, 10 ,verbose); } } if ( !respTestII ) { stunSendTest( myFd2, dest, username, password, 2 ,verbose ); } if ( !respTestIII ) { stunSendTest( myFd2, dest, username, password, 3 ,verbose ); } if ( respTestI && (!respTestHairpin) ) { if ( ( testImappedAddr.addr != 0 ) && ( testImappedAddr.port != 0 ) ) { stunSendTest( myFd1, testImappedAddr, username, password, 11 ,verbose ); } } } else { //if (verbose) clog << "-----------------------------------------" << endl; assert( err>0 ); // data is avialbe on some fd for ( int i=0; i<2; i++) { Socket myFd; if ( i==0 ) { myFd=myFd1; } else { myFd=myFd2; } if ( myFd!=INVALID_SOCKET ) { if ( FD_ISSET(myFd,&fdSet) ) { char msg[STUN_MAX_MESSAGE_SIZE]; int msgLen = sizeof(msg); StunAddress4 from; getMessage( myFd, msg, &msgLen, &from.addr, &from.port,verbose ); StunMessage resp; memset(&resp, 0, sizeof(StunMessage)); stunParseMessage( msg,msgLen, resp,verbose ); if ( verbose ) { clog << "Received message of type " << resp.msgHdr.msgType << " id=" << (int)(resp.msgHdr.id.octet[0]) << endl; } switch( resp.msgHdr.id.octet[0] ) { case 1: { if ( !respTestI ) { testIchangedAddr.addr = resp.changedAddress.ipv4.addr; testIchangedAddr.port = resp.changedAddress.ipv4.port; testImappedAddr.addr = resp.mappedAddress.ipv4.addr; testImappedAddr.port = resp.mappedAddress.ipv4.port; if ( preservePort ) { *preservePort = ( testImappedAddr.port == port ); } testI2dest.addr = resp.changedAddress.ipv4.addr; if (sAddr) { sAddr->port = testImappedAddr.port; sAddr->addr = testImappedAddr.addr; } count = 0; } respTestI=true; } break; case 2: { respTestII=true; } break; case 3: { respTestIII=true; } break; case 10: { if ( !respTestI2 ) { testI2mappedAddr.addr = resp.mappedAddress.ipv4.addr; testI2mappedAddr.port = resp.mappedAddress.ipv4.port; mappedIpSame = false; if ( (testI2mappedAddr.addr == testImappedAddr.addr ) && (testI2mappedAddr.port == testImappedAddr.port )) { mappedIpSame = true; } } respTestI2=true; } break; case 11: { if ( hairpin ) { *hairpin = true; } respTestHairpin = true; } break; } } } } } } // see if we can bind to this address //cerr << "try binding to " << testImappedAddr << endl; Socket s = openPort( 0/*use ephemeral*/, testImappedAddr.addr, false ); if ( s != INVALID_SOCKET ) { closesocket(s); isNat = false; //cerr << "binding worked" << endl; } else { isNat = true; //cerr << "binding failed" << endl; } if (verbose) { clog << "test I = " << respTestI << endl; clog << "test II = " << respTestII << endl; clog << "test III = " << respTestIII << endl; clog << "test I(2) = " << respTestI2 << endl; clog << "is nat = " << isNat <<endl; clog << "mapped IP same = " << mappedIpSame << endl; } // implement logic flow chart from draft RFC if ( respTestI ) { if ( isNat ) { if (respTestII) { return StunTypeConeNat; } else { if ( mappedIpSame ) { if ( respTestIII ) { return StunTypeRestrictedNat; } else { return StunTypePortRestrictedNat; } } else { return StunTypeSymNat; } } } else { if (respTestII) { return StunTypeOpen; } else { return StunTypeSymFirewall; } } } else { return StunTypeBlocked; } return StunTypeUnknown;}intstunOpenSocket( StunAddress4& dest, StunAddress4* mapAddr, int port, StunAddress4* srcAddr, bool verbose ){ assert( dest.addr != 0 ); assert( dest.port != 0 ); assert( mapAddr ); if ( port == 0 ) { port = randomPort(); } unsigned int interfaceIp = 0; if ( srcAddr ) { interfaceIp = srcAddr->addr; } Socket myFd = openPort(port,interfaceIp,verbose); if (myFd == INVALID_SOCKET) { return myFd; } char msg[STUN_MAX_MESSAGE_SIZE]; int msgLen = sizeof(msg); StunAtrString username; StunAtrString password; username.sizeValue = 0; password.sizeValue = 0; #ifdef USE_TLS stunGetUserNameAndPassword( dest, username, password );#endif stunSendTest(myFd, dest, username, password, 1, 0/*false*/ ); StunAddress4 from; getMessage( myFd, msg, &msgLen, &from.addr, &from.port,verbose ); StunMessage resp; memset(&resp, 0, sizeof(StunMessage)); bool ok = stunParseMessage( msg, msgLen, resp,verbose ); if (!ok) { return -1; } StunAddress4 mappedAddr = resp.mappedAddress.ipv4; StunAddress4 changedAddr = resp.changedAddress.ipv4; //clog << "--- stunOpenSocket --- " << endl; //clog << "\treq id=" << req.id << endl; //clog << "\tresp id=" << id << endl; //clog << "\tmappedAddr=" << mappedAddr << endl; *mapAddr = mappedAddr; return myFd;}boolstunOpenSocketPair( StunAddress4& dest, StunAddress4* mapAddr, int* fd1, int* fd2, int port, StunAddress4* srcAddr, bool verbose ){ assert( dest.addr!= 0 ); assert( dest.port != 0 ); assert( mapAddr ); const int NUM=3; if ( port == 0 ) { port = randomPort(); } *fd1=-1; *fd2=-1; char msg[STUN_MAX_MESSAGE_SIZE]; int msgLen =sizeof(msg); StunAddress4 from; int fd[NUM]; int i; unsigned int interfaceIp = 0; if ( srcAddr ) { interfaceIp = srcAddr->addr; } for( i=0; i<NUM; i++) { fd[i] = openPort( (port == 0) ? 0 : (port + i), interfaceIp, verbose); if (fd[i] < 0) { while (i > 0) { closesocket(fd[--i]); } return false; } } StunAtrString username; StunAtrString password; username.sizeValue = 0; password.sizeValue = 0; #ifdef USE_TLS stunGetUserNameAndPassword( dest, username, password );#endif for( i=0; i<NUM; i++) { stunSendTest(fd[i], dest, username, password, 1/*testNum*/, verbose ); } StunAddress4 mappedAddr[NUM]; for( i=0; i<NUM; i++) { msgLen = sizeof(msg)/sizeof(*msg); getMessage( fd[i], msg, &msgLen, &from.addr, &from.port ,verbose); StunMessage resp; memset(&resp, 0, sizeof(StunMessage)); bool ok = stunParseMessage( msg, msgLen, resp, verbose ); if (!ok) { return false; } mappedAddr[i] = resp.mappedAddress.ipv4; StunAddress4 changedAddr = resp.changedAddress.ipv4; } if (verbose) { clog << "--- stunOpenSocketPair --- " << endl; for( i=0; i<NUM; i++) { clog << "\t mappedAddr=" << mappedAddr[i] << endl; } } if ( mappedAddr[0].port %2 == 0 ) { if ( mappedAddr[0].port+1 == mappedAddr[1].port ) { *mapAddr = mappedAddr[0]; *fd1 = fd[0]; *fd2 = fd[1]; closesocket( fd[2] ); return true; } } else { if (( mappedAddr[1].port %2 == 0 ) && ( mappedAddr[1].port+1 == mappedAddr[2].port )) { *mapAddr = mappedAddr[1]; *fd1 = fd[1]; *fd2 = fd[2]; closesocket( fd[0] ); return true; } } // something failed, close all and return error for( i=0; i<NUM; i++) { closesocket( fd[i] ); } return false;}/* ==================================================================== * The Vovida Software License, Version 1.0 * * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The names "VOCAL", "Vovida Open Communication Application Library", * and "Vovida Open Communication Application Library (VOCAL)" must * not be used to endorse or promote products derived from this * software without prior written permission. For written * permission, please contact vocal@vovida.org. * * 4. Products derived from this software may not be called "VOCAL", nor * may "VOCAL" appear in their name, without prior written * permission of Vovida Networks, Inc. * * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. * * ==================================================================== * * This software consists of voluntary contributions made by Vovida * Networks, Inc. and many individuals on behalf of Vovida Networks, * Inc. For
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -