📄 transports.cxx
字号:
PIPSocket::InterfaceTable interfaces;
if (!PIPSocket::GetInterfaceTable(interfaces)) {
PTRACE(1, "Listen\tNo interfaces on system!");
return OpenOneSocket(localAddress);
}
for (PINDEX i = 0; i < interfaces.GetSize(); i++) {
PIPSocket::Address addr = interfaces[i].GetAddress();
if (addr != 0 && (localAddress.IsAny() || localAddress == addr)) {
if (OpenOneSocket(addr)) {
#ifndef _WIN32
PIPSocket::Address mask = interfaces[i].GetNetMask();
if (mask != 0 && mask != 0xffffffff)
OpenOneSocket((addr&mask)|(0xffffffff&~mask));
#endif
}
}
}
if (listeners.GetSize() > 0)
return StartThread(theAcceptHandler, TRUE);
PTRACE(1, "Listen\tCould not start any UDP listeners");
return FALSE;
}
BOOL OpalListenerUDP::IsOpen()
{
for (PINDEX i = 0; i < listeners.GetSize(); i++) {
if (!listeners[i].IsOpen())
return FALSE;
}
return TRUE;
}
void OpalListenerUDP::Close()
{
for (PINDEX i = 0; i < listeners.GetSize(); i++)
listeners[i].Close();
}
OpalTransport * OpalListenerUDP::Accept(const PTimeInterval & timeout)
{
if (listeners.IsEmpty())
return NULL;
PSocket::SelectList selection;
PINDEX i;
for (i = 0; i < listeners.GetSize(); i++)
selection += listeners[i];
PTRACE(4, "Listen\tWaiting on UDP packet on " << GetLocalAddress());
PChannel::Errors error = PSocket::Select(selection, timeout);
if (error != PChannel::NoError || selection.IsEmpty()) {
PTRACE(1, "Listen\tUDP select error: " << PSocket::GetErrorText(error));
return NULL;
}
PUDPSocket & socket = (PUDPSocket &)selection[0];
if (singleThread)
return new OpalTransportUDP(endpoint, socket);
PBYTEArray pdu;
PIPSocket::Address addr;
WORD port;
if (socket.ReadFrom(pdu.GetPointer(2000), 2000, addr, port))
return new OpalTransportUDP(endpoint, localAddress, pdu, addr, port);
PTRACE(1, "Listen\tUDP read error: " << socket.GetErrorText());
return NULL;
}
const char * OpalListenerUDP::GetProtoPrefix() const
{
return UdpPrefix;
}
//////////////////////////////////////////////////////////////////////////
OpalTransport::OpalTransport(OpalEndPoint & end)
: endpoint(end)
{
thread = NULL;
}
OpalTransport::~OpalTransport()
{
PAssert(thread == NULL, PLogicError);
}
void OpalTransport::PrintOn(ostream & strm) const
{
strm << GetRemoteAddress() << "<if=" << GetLocalAddress() << '>';
}
void OpalTransport::EndConnect(const OpalTransportAddress &)
{
}
BOOL OpalTransport::Close()
{
PTRACE(4, "Opal\tTransport Close");
/* Do not use PIndirectChannel::Close() as this deletes the sub-channel
member field crashing the background thread. Just close the base
sub-channel so breaks the threads I/O block.
*/
if (IsOpen())
return GetBaseWriteChannel()->Close();
return TRUE;
}
void OpalTransport::CloseWait()
{
PTRACE(3, "Opal\tTransport clean up on termination");
Close();
if (thread != NULL) {
PAssert(thread->WaitForTermination(10000), "Transport thread did not terminate");
if (thread == PThread::Current())
thread->SetAutoDelete();
else
delete thread;
thread = NULL;
}
}
BOOL OpalTransport::IsCompatibleTransport(const OpalTransportAddress &) const
{
PAssertAlways(PUnimplementedFunction);
return FALSE;
}
void OpalTransport::SetPromiscuous(PromisciousModes /*promiscuous*/)
{
}
OpalTransportAddress OpalTransport::GetLastReceivedAddress() const
{
return GetRemoteAddress();
}
BOOL OpalTransport::WriteConnect(WriteConnectCallback function, void * userData)
{
return function(*this, userData);
}
void OpalTransport::AttachThread(PThread * thrd)
{
if (thread != NULL) {
PAssert(thread->WaitForTermination(10000), "Transport not terminated when reattaching thread");
delete thread;
}
thread = thrd;
}
BOOL OpalTransport::IsRunning() const
{
if (thread == NULL)
return FALSE;
return !thread->IsTerminated();
}
/////////////////////////////////////////////////////////////////////////////
OpalTransportIP::OpalTransportIP(OpalEndPoint & end,
PIPSocket::Address binding,
WORD port)
: OpalTransport(end),
localAddress(binding),
remoteAddress(0)
{
localPort = port;
remotePort = 0;
}
OpalTransportAddress OpalTransportIP::GetLocalAddress() const
{
return OpalTransportAddress(localAddress, localPort, GetProtoPrefix());
}
BOOL OpalTransportIP::SetLocalAddress(const OpalTransportAddress & newLocalAddress)
{
if (!IsCompatibleTransport(newLocalAddress))
return FALSE;
if (!IsOpen())
return newLocalAddress.GetIpAndPort(localAddress, localPort);
PIPSocket::Address address;
WORD port = 0;
if (!newLocalAddress.GetIpAndPort(address, port))
return FALSE;
return localAddress == address && localPort == port;
}
OpalTransportAddress OpalTransportIP::GetRemoteAddress() const
{
return OpalTransportAddress(remoteAddress, remotePort, GetProtoPrefix());
}
BOOL OpalTransportIP::SetRemoteAddress(const OpalTransportAddress & address)
{
if (IsCompatibleTransport(address))
return address.GetIpAndPort(remoteAddress, remotePort);
return FALSE;
}
/////////////////////////////////////////////////////////////////////////////
OpalTransportTCP::OpalTransportTCP(OpalEndPoint & ep,
PIPSocket::Address binding,
WORD port,
BOOL reuseAddr)
: OpalTransportIP(ep, binding, port)
{
reuseAddressFlag = reuseAddr;
}
OpalTransportTCP::OpalTransportTCP(OpalEndPoint & ep, PTCPSocket * socket)
: OpalTransportIP(ep, INADDR_ANY, 0)
{
Open(socket);
}
OpalTransportTCP::~OpalTransportTCP()
{
CloseWait();
PTRACE(4,"Opal\tDeleted transport " << *this);
}
BOOL OpalTransportTCP::IsReliable() const
{
return TRUE;
}
BOOL OpalTransportTCP::IsCompatibleTransport(const OpalTransportAddress & address) const
{
return (address.Left(strlen(TcpPrefix)) *= TcpPrefix) ||
(address.Left(sizeof(IpPrefix)-1) *= IpPrefix);
}
BOOL OpalTransportTCP::Connect()
{
if (IsOpen())
return TRUE;
PTCPSocket * socket = new PTCPSocket(remotePort);
Open(socket);
PReadWaitAndSignal mutex(channelPointerMutex);
socket->SetReadTimeout(10000);
OpalManager & manager = endpoint.GetManager();
localPort = manager.GetNextTCPPort();
WORD firstPort = localPort;
for (;;) {
PTRACE(4, "OpalTCP\tConnecting to "
<< remoteAddress << ':' << remotePort
<< " (local port=" << localPort << ')');
if (socket->Connect(localPort, remoteAddress))
break;
int errnum = socket->GetErrorNumber();
if (localPort == 0 || (errnum != EADDRINUSE && errnum != EADDRNOTAVAIL)) {
PTRACE(1, "OpalTCP\tCould not connect to "
<< remoteAddress << ':' << remotePort
<< " (local port=" << localPort << ") - "
<< socket->GetErrorText() << '(' << errnum << ')');
return SetErrorValues(socket->GetErrorCode(), errnum);
}
localPort = manager.GetNextTCPPort();
if (localPort == firstPort) {
PTRACE(1, "OpalTCP\tCould not bind to any port in range " <<
manager.GetTCPPortBase() << " to " << manager.GetTCPPortMax());
return SetErrorValues(socket->GetErrorCode(), errnum);
}
}
socket->SetReadTimeout(PMaxTimeInterval);
return OnOpen();
}
BOOL OpalTransportTCP::ReadPDU(PBYTEArray & pdu)
{
// Make sure is a RFC1006 TPKT
switch (ReadChar()) {
case 3 : // Only support version 3
break;
default : // Unknown version number
SetErrorValues(ProtocolFailure, 0x80000000);
// Do case for read error
case -1 :
return FALSE;
}
// Save timeout
PTimeInterval oldTimeout = GetReadTimeout();
// Should get all of PDU in 5 seconds or something is seriously wrong,
SetReadTimeout(5000);
// Get TPKT length
BYTE header[3];
BOOL ok = ReadBlock(header, sizeof(header));
if (ok) {
PINDEX packetLength = ((header[1] << 8)|header[2]);
if (packetLength < 4) {
PTRACE(1, "H323TCP\tDwarf PDU received (length " << packetLength << ")");
ok = FALSE;
} else {
packetLength -= 4;
ok = ReadBlock(pdu.GetPointer(packetLength), packetLength);
}
}
SetReadTimeout(oldTimeout);
return ok;
}
BOOL OpalTransportTCP::WritePDU(const PBYTEArray & pdu)
{
// We copy the data into a new buffer so we can do a single write call. This
// is necessary as we have disabled the Nagle TCP delay algorithm to improve
// network performance.
int packetLength = pdu.GetSize() + 4;
// Send RFC1006 TPKT length
PBYTEArray tpkt(packetLength);
tpkt[0] = 3;
tpkt[1] = 0;
tpkt[2] = (BYTE)(packetLength >> 8);
tpkt[3] = (BYTE)packetLength;
memcpy(tpkt.GetPointer()+4, (const BYTE *)pdu, pdu.GetSize());
return Write((const BYTE *)tpkt, packetLength);
}
BOOL OpalTransportTCP::OnOpen()
{
PIPSocket * socket = (PIPSocket *)GetReadChannel();
// Get name of the remote computer for information purposes
if (!socket->GetPeerAddress(remoteAddress, remotePort)) {
PTRACE(1, "OpalTCP\tGetPeerAddress() failed: " << socket->GetErrorText());
return FALSE;
}
// get local address of incoming socket to ensure that multi-homed machines
// use a NIC address that is guaranteed to be addressable to destination
if (!socket->GetLocalAddress(localAddress, localPort)) {
PTRACE(1, "OpalTCP\tGetLocalAddress() failed: " << socket->GetErrorText());
return FALSE;
}
#ifndef __BEOS__
if (!socket->SetOption(TCP_NODELAY, 1, IPPROTO_TCP)) {
PTRACE(1, "OpalTCP\tSetOption(TCP_NODELAY) failed: " << socket->GetErrorText());
}
// make sure do not lose outgoing packets on close
const linger ling = { 1, 3 };
if (!socket->SetOption(SO_LINGER, &ling, sizeof(ling))) {
PTRACE(1, "OpalTCP\tSetOption(SO_LINGER) failed: " << socket->GetErrorText());
return FALSE;
}
#endif
PTRACE(1, "OpalTCP\tStarted connection to "
<< remoteAddress << ':' << remotePort
<< " (if=" << localAddress << ':' << localPort << ')');
return TRUE;
}
const char * OpalTransportTCP::GetProtoPrefix() const
{
return TcpPrefix;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -