2#if defined(HAVE_CONFIG_H)
11#ifndef RESIP_COMPAT_HXX
19#ifndef RESIP_DNSUTIL_HXX
23#ifndef RESIP_SOCKET_HXX
27#ifndef RESIP_LOGGER_HXX
31#ifndef RESIP_SIPMESSAGE_HXX
35#ifndef RESIP_HELPER_HXX
39#ifndef RESIP_SECURITY_HXX
43#ifndef RESIP_DTLSMESSAGE_HXX
47#ifndef RESIP_DTLSTRANSPORT_HXX
53#include <openssl/opensslv.h>
54#if !defined(LIBRESSL_VERSION_NUMBER)
55#include <openssl/e_os2.h>
57#include <openssl/evp.h>
58#include <openssl/crypto.h>
59#include <openssl/err.h>
60#include <openssl/pem.h>
61#include <openssl/pkcs7.h>
62#include <openssl/x509v3.h>
63#include <openssl/ssl.h>
67#include <osc/StateChanges.h>
68#include <osc/SigcompMessage.h>
71#define RESIPROCATE_SUBSYSTEM Subsystem::TRANSPORT
82 const Data& interfaceObj,
84 const Data& sipDomain,
87 const Data& certificateFilename,
88 const Data& privateKeyFilename,
89 const Data& privateKeyPassPhrase)
91 mTimer(mHandshakePending),
101 InfoLog(<<
"Creating DTLS transport host=" << interfaceObj
103 <<
" ipv4=" << version);
105 mTxFifo.setDescription(
"DtlsTransport::mTxFifo");
109 mClientCtx = mSecurity->
createDomainCtx(DTLS_client_method(),
Data::Empty, certificateFilename, privateKeyFilename, privateKeyPassPhrase);
110 mServerCtx = mSecurity->
createDomainCtx(DTLS_server_method(), sipDomain, certificateFilename, privateKeyFilename, privateKeyPassPhrase);
114 mDummyBio = BIO_new(BIO_s_mem());
123 SSL_CTX_set_read_ahead(mClientCtx, 1);
124 SSL_CTX_set_read_ahead(mServerCtx, 1);
127 BIO_set_mem_eof_return(mDummyBio, -1);
134 while (mDtlsConnections.begin() != mDtlsConnections.end())
136 _cleanupConnectionState(mDtlsConnections.begin()->second, mDtlsConnections.begin()->first);
138 SSL_CTX_free(mClientCtx); mClientCtx =
nullptr;
139 SSL_CTX_free(mServerCtx); mServerCtx =
nullptr;
145DtlsTransport::_read()
159 struct sockaddr peer = sender.getMutableSockaddr();
161 ssl = mDtlsConnections[*((
struct sockaddr_in*)&peer)];
169 ssl = SSL_new(mServerCtx);
173 SSL_set_verify(ssl, 0,
nullptr);
175 InfoLog(<<
"DTLS handshake starting (Server mode)");
177 SSL_set_accept_state(ssl);
179 wbio = BIO_new_dgram((
int)
mFd, BIO_NOCLOSE);
182 BIO_dgram_set_peer(wbio, &peer);
184 SSL_set_bio(ssl,
nullptr, wbio);
187 mDtlsConnections[*((
struct sockaddr_in*)&peer)] = ssl;
190 rbio = BIO_new_mem_buf(
mRxBuffer.data(), len);
191 BIO_set_mem_eof_return(rbio, -1);
193 SSL_set0_rbio(ssl, rbio);
199 len = SSL_read(ssl, mRxSslBuffer.data(),
static_cast<int>(mRxSslBuffer.size()));
200 int err = SSL_get_error(ssl, len);
203 SSL_set0_rbio(ssl, mDummyBio);
207 char errorString[1024];
215 ERR_error_string_n(ERR_get_error(), errorString,
sizeof(errorString));
216 DebugLog(<<
"Got DTLS read condition SSL_ERROR_SSL on"
218 <<
" port = " << ntohs(((
struct sockaddr_in*)&peer)->sin_port)
219 <<
" error = " << errorString);
222 case SSL_ERROR_WANT_READ:
224 case SSL_ERROR_WANT_WRITE:
226 case SSL_ERROR_SYSCALL:
228 ERR_error_string_n(ERR_get_error(), errorString,
sizeof(errorString));
229 DebugLog(<<
"Got DTLS read condition SSL_ERROR_SYSCALL on"
231 <<
" port = " << ntohs(((
struct sockaddr_in*)&peer)->sin_port)
232 <<
" error = " << errorString);
236 case SSL_ERROR_ZERO_RETURN:
238 ERR_error_string_n(ERR_get_error(), errorString,
sizeof(errorString));
239 DebugLog(<<
"Got DTLS read condition SSL_ERROR_ZERO_RETURN on"
241 <<
" port = " << ntohs(((
struct sockaddr_in*)&peer)->sin_port)
242 <<
" error = " << errorString);
244 _cleanupConnectionState(ssl, *((
struct sockaddr_in*)&peer));
247 case SSL_ERROR_WANT_CONNECT:
249 case SSL_ERROR_WANT_ACCEPT:
261 if (SSL_in_init(ssl))
269void DtlsTransport::_write(
FdSet& fdset)
276 if (mSendData !=
nullptr)
277 sendData = mSendData;
289 ssl = mDtlsConnections[*((
struct sockaddr_in*)&peer)];
294 ssl = SSL_new(mClientCtx);
297 InfoLog(<<
"DTLS handshake starting (client mode)");
299 SSL_set_connect_state(ssl);
301 wBio = BIO_new_dgram((
int)
mFd, BIO_NOCLOSE);
304 BIO_dgram_set_peer(wBio, &peer);
307 SSL_set_bio(ssl, mDummyBio, wBio);
311 mDtlsConnections[*((
struct sockaddr_in*)&peer)] = ssl;
330 DebugLog(<<
"Compressed message from "
331 << sendData->
data.
size() <<
" bytes to "
332 << sm->getDatagramLength() <<
" bytes");
334 expected = sm->getDatagramLength();
336 count = SSL_write(ssl,
337 sm->getDatagramMessage(),
338 sm->getDatagramLength());
344 expected = (int)sendData->
data.
size();
346 count = SSL_write(ssl, sendData->
data.
data(),
349 if (count < expected)
351 WarningLog(<<
"expected = " << expected <<
" but SSL_write only sent " << count);
363 mSendData = sendData;
365 int err = SSL_get_error(ssl, count);
367 char errorString[1024];
375 ERR_error_string_n(ERR_get_error(), errorString,
sizeof(errorString));
376 DebugLog(<<
"Got DTLS write condition SSL_ERROR_SSL on "
378 <<
" error = " << errorString);
381 case SSL_ERROR_WANT_READ:
384 case SSL_ERROR_WANT_WRITE:
388 case SSL_ERROR_SYSCALL:
393 ERR_error_string_n(ERR_get_error(), errorString,
sizeof(errorString));
394 DebugLog(<<
"Got DTLS write condition SSL_ERROR_SYSCALL "
395 <<
"Failed (" << e <<
") sending to "
397 <<
" error = " << errorString);
402 case SSL_ERROR_ZERO_RETURN:
404 ERR_error_string_n(ERR_get_error(), errorString,
sizeof(errorString));
405 DebugLog(<<
"Got DTLS write condition SSL_ERROR_ZERO_RETURN on "
407 <<
" error = " << errorString);
409 _cleanupConnectionState(ssl, *((
struct sockaddr_in*)&peer));
412 case SSL_ERROR_WANT_CONNECT:
414 case SSL_ERROR_WANT_ACCEPT:
430 if (!retry && count !=
int(sendData->
data.
size()))
432 ErrLog(<<
"UDPTransport - send buffer full");
438DtlsTransport::_doHandshake(
void)
447 int ret = SSL_do_handshake(ssl);
450 int err = SSL_get_error(ssl, ret);
452 char errorString[1024];
460 ERR_error_string_n(ERR_get_error(), errorString,
sizeof(errorString));
461 DebugLog(<<
"Got DTLS handshake code SSL_ERROR_SSL"
462 <<
" error = " << errorString);
465 case SSL_ERROR_WANT_READ:
467 case SSL_ERROR_WANT_WRITE:
469 case SSL_ERROR_SYSCALL:
471 ERR_error_string_n(ERR_get_error(), errorString,
sizeof(errorString));
472 DebugLog(<<
"Got DTLS handshake code SSL_ERROR_SYSCALL"
473 <<
" error = " << errorString);
476 case SSL_ERROR_ZERO_RETURN:
478 ERR_error_string_n(ERR_get_error(), errorString,
sizeof(errorString));
479 DebugLog(<<
"Got DTLS handshake code SSL_ERROR_ZERO_RETURN"
480 <<
" error = " << errorString);
483 case SSL_ERROR_WANT_CONNECT:
485 case SSL_ERROR_WANT_ACCEPT:
504 while (mHandshakePending.messageAvailable())
507 if ((mSendData !=
nullptr ||
mTxFifo.messageAvailable())
523 if (mSendData !=
nullptr ||
mTxFifo.messageAvailable())
530DtlsTransport::_cleanupConnectionState(
SSL* ssl,
struct sockaddr_in peer)
536 BIO_up_ref(mDummyBio);
539 mDtlsConnections.erase(peer);
543DtlsTransport::_mapDebug(
const char* where,
const char* action,
SSL* ssl)
545 fprintf(stderr,
"%s: %s\t%p\n", where, action, ssl);
546 fprintf(stderr,
"map sizet = %d\n", (
unsigned int)mDtlsConnections.size());
550DtlsTransport::_printSock(
const struct sockaddr_in* sock)
553 ntohs(sock->sin_port));
#define WarningLog(args_)
#define resip_assert(x)
This file needs to work for both C and C++ code.
Handles cross-platform sockets compatibility.
An alternative to std::string, encapsulates an arbitrary buffer of bytes.
static const Data Empty
Constant that represents a zero-length data.
const char * c_str() const
Returns a null-terminated string representing.
size_type size() const noexcept
Returns the number of bytes in this Data.
const char * data() const noexcept
Returns a pointer to the contents of this Data.
static Data inet_ntop(const struct in_addr &addr)
Converts from the network format to presentation format.
uint64_t add(SSL *, unsigned long msOffset)
static const unsigned long DtlsReceiveTimeout
virtual void buildFdSet(FdSet &fdset)
Adds the Transport's socket FD to the appropriate read or write sets as applicable.
DtlsTransport(Fifo< TransactionMessage > &fifo, int portNum, IpVersion version, const Data &interfaceObj, Security &security, const Data &sipDomain, AfterSocketCreationFuncPtr socketFunc=0, Compression &compression=Compression::Disabled, const Data &certificateFilename="", const Data &privateKeyFilename="", const Data &privateKeyPassPhrase="")
Object-oriented wrapper for your platform's file-descriptor set.
bool readyToWrite(Socket fd)
bool readyToRead(Socket fd)
A templated, threadsafe message-queue class.
virtual SSL_CTX * createDomainCtx(const SSL_METHOD *method, const Data &domain, const Data &certificateFilename, const Data &privateKeyFilename, const Data &privateKeyPassPhrase)
Throws BaseSecurity::Exception if the certificate or private key can't be loaded; nothing is left all...
virtual uint64_t process()
gets the set of timers that have fired, and inserts TimerMsg into the state machine fifo and applicat...
void drainDscpRefresh()
Serves a pending refresh and a pending report.
void setTlsDomain(const Data &domain)
void fail(const Data &tid, TransportFailure::FailureReason reason=TransportFailure::Failure, int subCode=0)
Posts a TransportFailure to the TransactionMessage Fifo.
virtual void process()=0
Version of process to be invoked periodically when using callback-based IO (via FdPollGrp).
static void error(int e)
Generates a generic log for the platform specific socket error number.
Represents a network address.
void setType(TransportType type)
const sockaddr & getSockaddr() const
Retrieve a const binary representation of the socket address for this tuple.
A Transport based on UDP.
osc::Stack * mSigcompStack
int processRxRecv(Tuple &sender)
std::array< char, MaxMessageSize > mRxBuffer
void processRxParseSip(char *buffer, int len, const Tuple &sender)
This file is used to handle compatibility fixes/tweaks so reSIProcate can function on multiple platfo...
dcm! – add UnusedChecking(_enum) below;
void(* AfterSocketCreationFuncPtr)(Socket s, int transportType, const char *file, int line)
IpVersion
An enumeration of IP versions.