📄 dtlstransport.cxx
字号:
#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::TRANSPORTusing 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) ;}voidDtlsTransport::_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 + -