📄 transports.cxx
字号:
/////////////////////////////////////////////////////////////////////////////
OpalTransportUDP::OpalTransportUDP(OpalEndPoint & ep,
PIPSocket::Address binding,
WORD port,
BOOL reuseAddr)
: OpalTransportIP(ep, binding, port)
{
promiscuousReads = AcceptFromRemoteOnly;
socketOwnedByListener = FALSE;
reuseAddressFlag = reuseAddr;
PUDPSocket * udp = new PUDPSocket;
udp->Listen(binding, 0, port,
reuseAddr ? PSocket::CanReuseAddress : PSocket::AddressIsExclusive);
localPort = udp->GetPort();
Open(udp);
PTRACE(3, "OpalUDP\tBinding to interface: " << localAddress << ':' << localPort);
}
OpalTransportUDP::OpalTransportUDP(OpalEndPoint & ep, PUDPSocket & udp)
: OpalTransportIP(ep, PIPSocket::GetDefaultIpAny(), 0)
{
promiscuousReads = AcceptFromAnyAutoSet;
socketOwnedByListener = TRUE;
reuseAddressFlag = FALSE;
udp.GetLocalAddress(localAddress, localPort);
Open(udp);
PTRACE(3, "OpalUDP\tPre-bound to interface: " << localAddress << ':' << localPort);
}
OpalTransportUDP::OpalTransportUDP(OpalEndPoint & ep,
PIPSocket::Address binding,
const PBYTEArray & packet,
PIPSocket::Address remAddr,
WORD remPort)
: OpalTransportIP(ep, binding, 0),
preReadPacket(packet)
{
promiscuousReads = AcceptFromAnyAutoSet;
socketOwnedByListener = FALSE;
remoteAddress = remAddr;
remotePort = remPort;
PUDPSocket * udp = new PUDPSocket;
udp->Listen(binding);
localPort = udp->GetPort();
Open(udp);
PTRACE(3, "OpalUDP\tBinding to interface: " << localAddress << ':' << localPort);
}
OpalTransportUDP::~OpalTransportUDP()
{
CloseWait();
PTRACE(4,"Opal\tDeleted transport " << *this);
}
BOOL OpalTransportUDP::Close()
{
PTRACE(4, "OpalUDP\tClose");
PReadWaitAndSignal mutex(channelPointerMutex);
if (socketOwnedByListener) {
channelPointerMutex.StartWrite();
readChannel = writeChannel = NULL;
// Thread also owned by listener as well, don't wait on or delete it!
thread = NULL;
channelPointerMutex.EndWrite();
return TRUE;
}
if (connectSockets.IsEmpty())
return OpalTransport::Close();
channelPointerMutex.StartWrite();
readChannel = writeChannel = NULL;
// Still in connection on multiple interface phase. Close all of the
// sockets we have open.
for (PINDEX i = 0; i < connectSockets.GetSize(); i++)
connectSockets[i].Close();
channelPointerMutex.EndWrite();
return TRUE;
}
BOOL OpalTransportUDP::IsReliable() const
{
return FALSE;
}
BOOL OpalTransportUDP::IsCompatibleTransport(const OpalTransportAddress & address) const
{
return address.Left(strlen(UdpPrefix)).ToLower () == UdpPrefix ||
address.Left(sizeof(IpPrefix)-1).ToLower () == IpPrefix;
}
BOOL OpalTransportUDP::Connect()
{
if (remotePort == 0)
return FALSE;
if (remoteAddress == 0) {
remoteAddress = INADDR_BROADCAST;
PTRACE(2, "OpalUDP\tBroadcast connect to port " << remotePort);
}
else {
PTRACE(2, "OpalUDP\tStarted connect to " << remoteAddress << ':' << remotePort);
}
OpalManager & manager = endpoint.GetManager();
PSTUNClient * stun = manager.GetSTUN(remoteAddress);
if (stun != NULL) {
PUDPSocket * socket;
if (stun->CreateSocket(socket)) {
PIndirectChannel::Close(); //closing the channel and opening it with the new socket
readAutoDelete = writeAutoDelete = FALSE;
Open(socket);
socket->GetLocalAddress(localAddress, localPort);
socket->SetSendAddress(remoteAddress, remotePort);
PTRACE(4, "OpalUDP\tSTUN created socket: " << localAddress << ':' << localPort);
connectSockets.Append(socket);
return true;
}
PTRACE(4, "OpalUDP\tSTUN could not create socket!");
}
// See if prebound to interface, only use that if so
PIPSocket::InterfaceTable interfaces;
if (localAddress != INADDR_ANY) {
PTRACE(3, "OpalUDP\tConnect on pre-bound interface: " << localAddress);
interfaces.Append(new PIPSocket::InterfaceEntry("", localAddress, PIPSocket::Address(0xffffffff), ""));
}
else if (!PIPSocket::GetInterfaceTable(interfaces)) {
PTRACE(1, "OpalUDP\tNo interfaces on system!");
interfaces.Append(new PIPSocket::InterfaceEntry("", localAddress, PIPSocket::Address(0xffffffff), ""));
}
else {
PTRACE(4, "OpalUDP\tConnecting to interfaces:\n" << setfill('\n') << interfaces << setfill(' '));
}
PIndirectChannel::Close(); //closing the channel and opening it with the new socket
PINDEX i;
for (i = 0; i < interfaces.GetSize(); i++) {
PIPSocket::Address interfaceAddress = interfaces[i].GetAddress();
if (interfaceAddress == 0 || interfaceAddress == PIPSocket::Address())
continue;
// Check for already have had that IP address.
PINDEX j;
for (j = 0; j < i; j++) {
if (interfaceAddress == interfaces[j].GetAddress())
break;
}
if (j < i)
continue;
// Not explicitly multicast
PUDPSocket * socket = new PUDPSocket;
localPort = manager.GetNextUDPPort();
WORD firstPort = localPort;
while (!socket->Listen(interfaceAddress, 0, localPort, reuseAddressFlag?PIPSocket::CanReuseAddress:PIPSocket::AddressIsExclusive)) {
localPort = manager.GetNextUDPPort();
if (localPort == firstPort) {
PTRACE(1, "OpalUDP\tCould not bind to any port in range " <<
manager.GetUDPPortBase() << " to " << manager.GetUDPPortMax());
return FALSE;
}
}
readAutoDelete = writeAutoDelete = FALSE;
if (!PIndirectChannel::IsOpen())
Open(socket);
#ifndef __BEOS__
if (remoteAddress == INADDR_BROADCAST) {
if (!socket->SetOption(SO_BROADCAST, 1)) {
PTRACE(2, "OpalUDP\tError allowing broadcast: " << socket->GetErrorText());
return FALSE;
}
}
#else
PTRACE(3, "RAS\tBroadcast option under BeOS is not implemented yet");
#endif
socket->GetLocalAddress(localAddress, localPort);
socket->SetSendAddress(remoteAddress, remotePort);
connectSockets.Append(socket);
}
readAutoDelete = writeAutoDelete = FALSE;
if (connectSockets.IsEmpty())
return FALSE;
promiscuousReads = AcceptFromAnyAutoSet;
return TRUE;
}
void OpalTransportUDP::EndConnect(const OpalTransportAddress & theLocalAddress)
{
PAssert(theLocalAddress.GetIpAndPort(localAddress, localPort), PInvalidParameter);
for (PINDEX i = 0; i < connectSockets.GetSize(); i++) {
PUDPSocket * socket = (PUDPSocket *)connectSockets.GetAt(i);
PIPSocket::Address addr;
WORD port;
if (socket->GetLocalAddress(addr, port) && addr == localAddress && port == localPort) {
PTRACE(3, "OpalUDP\tEnded connect, selecting " << localAddress << ':' << localPort);
connectSockets.DisallowDeleteObjects();
connectSockets.RemoveAt(i);
connectSockets.AllowDeleteObjects();
readChannel = NULL;
writeChannel = NULL;
socket->SetOption(SO_BROADCAST, 0);
PAssert(Open(socket), PLogicError);
break;
}
}
connectSockets.RemoveAll();
OpalTransport::EndConnect(theLocalAddress);
}
BOOL OpalTransportUDP::SetLocalAddress(const OpalTransportAddress & newLocalAddress)
{
if (connectSockets.IsEmpty())
return OpalTransportIP::SetLocalAddress(newLocalAddress);
if (!IsCompatibleTransport(newLocalAddress))
return FALSE;
if (!newLocalAddress.GetIpAndPort(localAddress, localPort))
return FALSE;
for (PINDEX i = 0; i < connectSockets.GetSize(); i++) {
PUDPSocket * socket = (PUDPSocket *)connectSockets.GetAt(i);
PIPSocket::Address ip;
WORD port = 0;
if (socket->GetLocalAddress(ip, port) && ip == localAddress && port == localPort) {
writeChannel = &connectSockets[i];
return TRUE;
}
}
return FALSE;
}
BOOL OpalTransportUDP::SetRemoteAddress(const OpalTransportAddress & address)
{
if (!OpalTransportIP::SetRemoteAddress(address))
return FALSE;
PUDPSocket * socket = (PUDPSocket *)GetReadChannel();
if (socket != NULL)
socket->SetSendAddress(remoteAddress, remotePort);
return TRUE;
}
void OpalTransportUDP::SetPromiscuous(PromisciousModes promiscuous)
{
promiscuousReads = promiscuous;
}
OpalTransportAddress OpalTransportUDP::GetLastReceivedAddress() const
{
if (!lastReceivedAddress)
return lastReceivedAddress;
return OpalTransport::GetLastReceivedAddress();
}
BOOL OpalTransportUDP::Read(void * buffer, PINDEX length)
{
if (!connectSockets.IsEmpty()) {
PSocket::SelectList selection;
PINDEX i;
for (i = 0; i < connectSockets.GetSize(); i++)
selection += connectSockets[i];
if (PSocket::Select(selection, GetReadTimeout()) != PChannel::NoError) {
PTRACE(1, "OpalUDP\tError on connection read select.");
return FALSE;
}
if (selection.IsEmpty()) {
PTRACE(2, "OpalUDP\tTimeout on connection read select.");
return FALSE;
}
PUDPSocket & socket = (PUDPSocket &)selection[0];
channelPointerMutex.StartWrite();
if (!socket.IsOpen()) {
channelPointerMutex.EndWrite();
PTRACE(2, "OpalUDP\tSocket closed in connection read select.");
return FALSE;
}
socket.GetLocalAddress(localAddress, localPort);
readChannel = &socket;
channelPointerMutex.EndWrite();
}
for (;;) {
if (!OpalTransportIP::Read(buffer, length))
return FALSE;
PUDPSocket * socket = (PUDPSocket *)GetReadChannel();
PIPSocket::Address address;
WORD port;
socket->GetLastReceiveAddress(address, port);
lastReceivedAddress = OpalTransportAddress(address, port);
switch (promiscuousReads) {
case AcceptFromRemoteOnly :
if (remoteAddress == address)
return TRUE;
break;
case AcceptFromAnyAutoSet :
remoteAddress = address;
remotePort = port;
socket->SetSendAddress(remoteAddress, remotePort);
// fall into next case
default : //AcceptFromAny
return TRUE;
}
if (remoteAddress *= address)
return TRUE;
PTRACE(1, "UDP\tReceived PDU from incorrect host: " << address << ':' << port);
}
}
BOOL OpalTransportUDP::ReadPDU(PBYTEArray & packet)
{
if (preReadPacket.GetSize() > 0) {
packet = preReadPacket;
preReadPacket.SetSize(0);
return TRUE;
}
if (!Read(packet.GetPointer(10000), 10000)) {
packet.SetSize(0);
return FALSE;
}
packet.SetSize(GetLastReadCount());
return TRUE;
}
BOOL OpalTransportUDP::WritePDU(const PBYTEArray & packet)
{
return Write((const BYTE *)packet, packet.GetSize());
}
BOOL OpalTransportUDP::WriteConnect(WriteConnectCallback function, void * userData)
{
if (connectSockets.IsEmpty())
return OpalTransport::WriteConnect(function, userData);
BOOL ok = FALSE;
PINDEX i;
for (i = 0; i < connectSockets.GetSize(); i++) {
PUDPSocket & socket = (PUDPSocket &)connectSockets[i];
socket.GetLocalAddress(localAddress, localPort);
writeChannel = &socket;
if (function(*this, userData))
ok = TRUE;
}
return ok;
}
const char * OpalTransportUDP::GetProtoPrefix() const
{
return UdpPrefix;
}
//////////////////////////////////////////////////////////////////////////
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -