⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 udptransport.cxx

📁 一个著名的SIP协议栈
💻 CXX
📖 第 1 页 / 共 2 页
字号:
#if defined(HAVE_CONFIG_H)
#include "resip/stack/config.hxx"
#endif

#include <memory>

#include "resip/stack/Helper.hxx"
#include "resip/stack/SendData.hxx"
#include "resip/stack/SipMessage.hxx"
#include "resip/stack/UdpTransport.hxx"
#include "rutil/Data.hxx"
#include "rutil/DnsUtil.hxx"
#include "rutil/Logger.hxx"
#include "rutil/Socket.hxx"
#include "rutil/WinLeakCheck.hxx"
#include "rutil/compat.hxx"
#include "rutil/stun/Stun.hxx"

#ifdef USE_SIGCOMP
#include <osc/Stack.h>
#include <osc/StateChanges.h>
#include <osc/SigcompMessage.h>
#endif

#define RESIPROCATE_SUBSYSTEM Subsystem::TRANSPORT

using namespace std;
using namespace resip;

UdpTransport::UdpTransport(Fifo<TransactionMessage>& fifo,
                           int portNum,  
                           IpVersion version,
                           StunSetting stun,
                           const Data& pinterface,
                           AfterSocketCreationFuncPtr socketFunc,
                           Compression &compression) 
   : InternalTransport(fifo, portNum, version, pinterface, socketFunc, compression),
     mSigcompStack(0)
{
   InfoLog (<< "Creating UDP transport host=" << pinterface 
            << " port=" << portNum
            << " ipv4=" << bool(version==V4) );

   mTuple.setType(transport());
   mFd = InternalTransport::socket(transport(), version);
   bind();
#ifdef USE_SIGCOMP
   if (mCompression.isEnabled())
   {
      DebugLog (<< "Compression enabled for transport: " << *this);
      mSigcompStack = new osc::Stack(mCompression.getStateHandler());
      mCompression.addCompressorsToStack(mSigcompStack);
   }
   else
   {
      DebugLog (<< "Compression disabled for transport: " << *this);
   }
#else
   DebugLog (<< "No compression library available: " << *this);
#endif
}

UdpTransport::~UdpTransport()
{
   DebugLog (<< "Shutting down " << mTuple);
#ifdef USE_SIGCOMP
   delete mSigcompStack;
#endif
}

void 
UdpTransport::process(FdSet& fdset)
{
   // pull buffers to send out of TxFifo
   // receive datagrams from fd
   // preparse and stuff into RxFifo

   if (mTxFifo.messageAvailable() && fdset.readyToWrite(mFd))
   {
      std::auto_ptr<SendData> sendData = std::auto_ptr<SendData>(mTxFifo.getNext());
      //DebugLog (<< "Sent: " <<  sendData->data);
      //DebugLog (<< "Sending message on udp.");

      assert( &(*sendData) );
      assert( sendData->destination.getPort() != 0 );
      
      const sockaddr& addr = sendData->destination.getSockaddr();
      int expected;
      int count;

#ifdef USE_SIGCOMP
      // If message needs to be compressed, compress it here.
      if (mSigcompStack &&
          sendData->sigcompId.size() > 0 &&
          !sendData->isAlreadyCompressed )
      {
          osc::SigcompMessage *sm = mSigcompStack->compressMessage
            (sendData->data.data(), sendData->data.size(),
             sendData->sigcompId.data(), sendData->sigcompId.size(),
             isReliable());

          DebugLog (<< "Compressed message from "
                    << sendData->data.size() << " bytes to " 
                    << sm->getDatagramLength() << " bytes");

          expected = sm->getDatagramLength();

          count = sendto(mFd, 
                         sm->getDatagramMessage(),
                         sm->getDatagramLength(),
                         0, // flags
                         &addr, sendData->destination.length());
          delete sm;
      }
      else
#endif
      {
          expected = sendData->data.size();
          count = sendto(mFd, 
                         sendData->data.data(), sendData->data.size(),  
                         0, // flags
                         &addr, sendData->destination.length());
      }
      
      if ( count == SOCKET_ERROR )
      {
         int e = getErrno();
         error(e);
         InfoLog (<< "Failed (" << e << ") sending to " << sendData->destination);
         fail(sendData->transactionId);
      }
      else
      {
         if (count != expected)
         {
            ErrLog (<< "UDPTransport - send buffer full" );
            fail(sendData->transactionId);
         }
      }
   }
   
   // !jf! this may have to change - when we read a message that is too big
   if ( fdset.readyToRead(mFd) )
   {
      //should this buffer be allocated on the stack and then copied out, as it
      //needs to be deleted every time EWOULDBLOCK is encountered
      // .dlb. can we determine the size of the buffer before we allocate?
      // something about MSG_PEEK|MSG_TRUNC in Stevens..
      // .dlb. RFC3261 18.1.1 MUST accept 65K datagrams. would have to attempt to
      // adjust the UDP buffer as well...
      char* buffer = MsgHeaderScanner::allocateBuffer(MaxBufferSize);      

      // !jf! how do we tell if it discarded bytes 
      // !ah! we use the len-1 trick :-(
      Tuple tuple(mTuple);
      socklen_t slen = tuple.length();
      int len = recvfrom( mFd,
                          buffer,
                          MaxBufferSize,
                          0 /*flags */,
                          &tuple.getMutableSockaddr(), 
                          &slen);
      if ( len == SOCKET_ERROR )
      {
         int err = getErrno();
         if ( err != EWOULDBLOCK  )
         {
            error( err );
         }
      }

      if (len == 0 || len == SOCKET_ERROR)
      {
         delete[] buffer; 
         buffer=0;
         return;
      }

      if (len+1 >= MaxBufferSize)
      {
         InfoLog(<<"Datagram exceeded max length "<<MaxBufferSize);
         delete [] buffer; buffer=0;
         return;
      }

      //handle incoming CRLFCRLF keep-alive packets
      if (len == 4 &&
          strncmp(buffer, Symbols::CRLFCRLF, len) == 0)
      {
         delete[] buffer;
         buffer = 0;
         StackLog(<<"Throwing away incoming firewall keep-alive");
         return;
      }

      // this must be a STUN response (or garbage)
      if (buffer[0] == 1 && buffer[1] == 1 && ipVersion() == V4)
      {
         resip::Lock lock(myMutex);
	     StunMessage resp;
	     memset(&resp, 0, sizeof(StunMessage));
		
	     if (stunParseMessage(buffer, len, resp, false))
		 {
			 in_addr sin_addr;
#if defined(WIN32)
			 sin_addr.S_un.S_addr = htonl(resp.mappedAddress.ipv4.addr);
#else
			 sin_addr.s_addr = htonl(resp.mappedAddress.ipv4.addr);
#endif
			 mStunMappedAddress = Tuple(sin_addr,resp.mappedAddress.ipv4.port, UDP);
			 mStunSuccess = true;
		 }
		 return;
	  }

      // this must be a STUN request (or garbage)
      if (buffer[0] == 0 && buffer[1] == 1 && ipVersion() == V4)
      {
         bool changePort = false;
         bool changeIp = false;
         
         StunAddress4 myAddr;
         const sockaddr_in& bi = (const sockaddr_in&)boundInterface();
         myAddr.addr = ntohl(bi.sin_addr.s_addr);
         myAddr.port = ntohs(bi.sin_port);
         
         StunAddress4 from; // packet source
         const sockaddr_in& fi = (const sockaddr_in&)tuple.getSockaddr();
         from.addr = ntohl(fi.sin_addr.s_addr);
         from.port = ntohs(fi.sin_port);
         
         StunMessage resp;
         StunAddress4 dest;
         StunAtrString hmacPassword;  
         hmacPassword.sizeValue = 0;
         
         StunAddress4 secondary;
         secondary.port = 0;
         secondary.addr = 0;
         
         bool ok = stunServerProcessMsg( buffer, len, // input buffer
                                         from,  // packet source
                                         secondary, // not used
                                         myAddr, // address to fill into response
                                         myAddr, // not used
                                         &resp, // stun response
                                         &dest, // where to send response
                                         &hmacPassword, // not used
                                         &changePort, // not used
                                         &changeIp, // not used
                                         false ); // logging
         
         if (ok)
         {
            char* response = new char[STUN_MAX_MESSAGE_SIZE];
            int rlen = stunEncodeMessage( resp, 
                                          response, 
                                          STUN_MAX_MESSAGE_SIZE, 
                                          hmacPassword,
                                          false );
            SendData* stunResponse = new SendData(tuple, response, rlen);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -