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

📄 dtlstransport.cxx

📁 一个著名的SIP协议栈
💻 CXX
📖 第 1 页 / 共 2 页
字号:

#ifdef USE_DTLS

#if defined(HAVE_CONFIG_H)
  #include "resip/stack/config.hxx"
#endif

#include <memory>

#ifndef RESIP_COMPAT_HXX
#include "rutil/compat.hxx"
#endif

#ifndef RESIP_DATA_HXX
#include "rutil/Data.hxx"
#endif

#ifndef RESIP_DNSUTIL_HXX
#include "rutil/DnsUtil.hxx"
#endif

#ifndef RESIP_SOCKET_HXX
#include "rutil/Socket.hxx"
#endif

#ifndef RESIP_LOGGER_HXX
#include "rutil/Logger.hxx"
#endif

#ifndef RESIP_SIPMESSAGE_HXX
#include "resip/stack/SipMessage.hxx"
#endif

#ifndef RESIP_HELPER_HXX
#include "resip/stack/Helper.hxx"
#endif

#ifndef RESIP_SECURITY_HXX
#include "resip/stack/Security.hxx"
#endif

#ifndef RESIP_DTLSMESSAGE_HXX
#include "resip/stack/DtlsMessage.hxx"
#endif

#ifndef RESIP_DTLSTRANSPORT_HXX
#include "resip/stack/DtlsTransport.hxx"
#endif

#include "rutil/WinLeakCheck.hxx"

#include <openssl/e_os2.h>
#include <openssl/evp.h>
#include <openssl/crypto.h>
#include <openssl/err.h>
#include <openssl/pem.h>
#include <openssl/pkcs7.h>
#include <openssl/x509v3.h>
#include <openssl/ssl.h>

#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;

DtlsTransport::DtlsTransport(Fifo<TransactionMessage>& fifo,
                             int portNum,
                             IpVersion version,
                             const Data& interfaceObj,
                             Security& security,
                             const Data& sipDomain,
                             Compression& compression)
                             : UdpTransport( fifo, portNum, version, 
                                 StunDisabled, interfaceObj, 0, compression ),
                               mTimer( mHandshakePending ),
                               mSecurity( &security ),
                               mDomain(sipDomain)
{
   setTlsDomain(sipDomain);   
   InfoLog ( << "Creating DTLS transport host=" << interfaceObj 
             << " port=" << portNum
             << " ipv4=" << version ) ;

   mTuple.setType( transport() );

   mClientCtx = SSL_CTX_new( DTLSv1_client_method() ) ;
   mServerCtx = SSL_CTX_new( DTLSv1_server_method() ) ;
   assert( mClientCtx ) ;
   assert( mServerCtx ) ;

   mDummyBio = BIO_new( BIO_s_mem() ) ;
   assert( mDummyBio ) ;

   mSendData = NULL ;

   /* trying to read from this BIO always returns retry */
   BIO_set_mem_eof_return( mDummyBio, -1 ) ;
}

DtlsTransport::~DtlsTransport()
{
   DebugLog (<< "Shutting down " << mTuple);

   while(mDtlsConnections.begin() != mDtlsConnections.end())
   {
       _cleanupConnectionState(mDtlsConnections.begin()->second, mDtlsConnections.begin()->first);
   }       
   SSL_CTX_free(mClientCtx);mClientCtx=0;  
   SSL_CTX_free(mServerCtx);mServerCtx=0;  

   BIO_free( mDummyBio) ;
}

void
DtlsTransport::_read( FdSet& fdset )
{
   //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...
   unsigned int bufferLen = UdpTransport::MaxBufferSize + 5 ;
   char* buffer = new char[ bufferLen ] ;
   unsigned char *pt = new unsigned char[ bufferLen ] ;

   SSL *ssl ;
   BIO *rbio ;
   BIO *wbio ;
   
   // !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,
                       UdpTransport::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 >= UdpTransport::MaxBufferSize )
   {
      InfoLog (<<"Datagram exceeded max length "<<UdpTransport::MaxBufferSize ) ;
      delete [] buffer ; buffer = 0 ;
      return ;
   }

   //DebugLog ( << "UDP Rcv : " << len << " b" );
   //DebugLog ( << Data(buffer, len).escaped().c_str());
   
   /* begin SSL stuff */
   struct sockaddr peer = tuple.getMutableSockaddr() ;

   ssl = mDtlsConnections[ *((struct sockaddr_in *)&peer) ] ;

   /* 
    * If we don't have a binding for this peer,
    * then we're a server.
    */
   if ( ssl == NULL )
   {
      ssl = SSL_new( mServerCtx ) ;
      assert( ssl ) ;

      SSL_set_accept_state( ssl ) ;

      X509 *cert = mSecurity->getDomainCert( mDomain ) ;
      EVP_PKEY *pkey = mSecurity->getDomainKey( mDomain ) ;

      if( !cert )
      {
         Data error = Data("Could not load certifiacte for domain: ") 
             + mDomain;
         throw Security::Exception( error,__FILE__, __LINE__ ) ;
      }

      if( !pkey )
      {
         Data error = Data("Could not load private key for domain: ") 
             + mDomain;
         throw Security::Exception( error,__FILE__, __LINE__ ) ;
      }

      assert( cert ) ;
      assert( pkey ) ;

      if( ! SSL_use_certificate( ssl, cert ) )
      {
         throw Security::Exception( "SSL_use_certificate failed",
                                   __FILE__, __LINE__ ) ;
      }

      if ( ! SSL_use_PrivateKey( ssl, pkey ) )
         throw Security::Exception( "SSL_use_PrivateKey failed.",
                                   __FILE__, __LINE__ ) ;

      wbio = BIO_new_dgram( mFd, BIO_NOCLOSE ) ;
      assert( wbio ) ;

      BIO_dgram_set_peer( wbio, &peer ) ;

      SSL_set_bio( ssl, NULL, wbio ) ;

      /* remember this connection */
      mDtlsConnections[ *((struct sockaddr_in *)&peer) ] = ssl ;
   }

   rbio = BIO_new_mem_buf( buffer, len ) ;
   BIO_set_mem_eof_return( rbio, -1 ) ;

   ssl->rbio = rbio ;

   len = SSL_read( ssl, pt, UdpTransport::MaxBufferSize ) ;
   int err = SSL_get_error( ssl, len ) ;

   /* done with the rbio */
   BIO_free( ssl->rbio ) ;
   ssl->rbio = mDummyBio ;
   delete [] buffer ;
   buffer = 0 ;

   if ( len <= 0 )
   {
      switch( err )
      {
         case SSL_ERROR_NONE:
            break ;
         case SSL_ERROR_SSL:
            break ;
         case SSL_ERROR_WANT_READ:
            break ;
         case SSL_ERROR_WANT_WRITE:
            break ;
         case SSL_ERROR_SYSCALL:
            break ;
            /* connection closed */
         case SSL_ERROR_ZERO_RETURN:
            _cleanupConnectionState( ssl, *((struct sockaddr_in *)&peer) ) ;
            break ;
         case SSL_ERROR_WANT_CONNECT:
            break ;
         case SSL_ERROR_WANT_ACCEPT:
            break ;
         default:
            break ;
      }
   }

   if ( len <= 0 )
       return ;

   if ( SSL_in_init( ssl ) )
      mTimer.add( ssl, DtlsReceiveTimeout ) ;

#ifdef USE_SIGCOMP
   osc::StateChanges *sc = 0;
#endif

   if ((pt[0] & 0xf8) == 0xf8)
   {
      if(!mCompression.isEnabled())
      {
        InfoLog(<< "Discarding unexpected SigComp message");
        delete [] pt;
        return;
      }
#ifdef USE_SIGCOMP
      unsigned char *newPt = new unsigned char[ bufferLen ] ;
      size_t uncompressedLength =
        mSigcompStack->uncompressMessage(pt, len,
                                         newPt, UdpTransport::MaxBufferSize,
                                         sc);

      DebugLog (<< "Unompressed message from "
                << len << " bytes to " 
                << uncompressedLength << " bytes");

      osc::SigcompMessage *nack = mSigcompStack->getNack();

      if (nack)
      {
        mTxFifo.add(new SendData(tuple,
                                 Data(nack->getDatagramMessage(),
                                      nack->getDatagramLength()),
                                 Data::Empty,
                                 Data::Empty,
                                 true)
                   );
        delete nack;
      }

      delete[] buffer;
      buffer = newBuffer;
      len = uncompressedLength;
#endif
   }

   SipMessage* message = new SipMessage(this);
   
   // set the received from information into the received= parameter in the
   // via
   
   // It is presumed that UDP Datagrams are arriving atomically and that
   // each one is a unique SIP message
   
   
   // Save all the info where this message came from
   tuple.transport = this ;
   message->setSource( tuple ) ;
   //DebugLog (<< "Received from: " << tuple);
   
   // Tell the SipMessage about this datagram buffer.
   message->addBuffer( (char *)pt ) ;
   
   mMsgHeaderScanner.prepareForMessage( message ) ;
   
   char *unprocessedCharPtr ;
   if (mMsgHeaderScanner.scanChunk( (char *)pt,
                                    len,
                                    &unprocessedCharPtr ) !=
       MsgHeaderScanner::scrEnd)
   {
      DebugLog( << "Scanner rejecting datagram as unparsable / fragmented from " 
                << tuple ) ;
      DebugLog( << Data( pt, len ) ) ;
      delete message ;
      message = 0 ;
      return ;

⌨️ 快捷键说明

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