📄 udptransport.cxx
字号:
#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 + -