Hi,
I have found an issue with H323EndPoint::InternalMakeCall function for case when it running from H323EndPoint::ForwardConnection function (may be for some others cases too). Take a look: 1.We are trying to connect to some host which uses Gatekeeper. 2.From H323EndPoint::ForwardConnection call H323EndPoint::InternalMakeCall function with some internal token="ip$xxx.xxx.xxx.xxx/port" 3.In the body of H323EndPoint::InternalMakeCall we have the replacement current callToken-connection pair to new one with "ip$xxx.xxx.xxx.xxx/port-replaced-1" string, like connectionsActive.SetAt(adjustedToken, connectionsActive.RemoveAt(newToken)); connectionsToBeCleaned += adjustedToken;
4.But if for some reason our virtual CreateConnection function returns NULL...
connection = CreateConnection(lastReference, userData, transport, NULL);
if (connection == NULL) { PTRACE(1, "H323\tCreateConnection returned NULL"); connectionsMutex.Signal();
return NULL; }
... we cannot clear current Connection because it has not actual callToken "ip$xxx.xxx.xxx.xxx/port" but H323EndPoint::connectionsActive has "ip$xxx.xxx.xxx.xxx/port-replaced-1" and endpoint.ClearCall(callToken, reason) or something similar will be failed because not able to found the Connection by own callToken.
5.Also we have redundant call connectionsMutex.Signal().
if (connection == NULL) { PTRACE(1, "H323\tCreateConnection returned NULL"); connectionsMutex.Signal();
return NULL; }
My proposition - just rename back callToken for H323EndPoint::connectionsActive and remove adjustedToken from H323EndPoint::connectionsToBeCleaned if we have NULL connection. My H323EndPoint::InternalMakeCall function looks like this:
H323Connection * H323EndPoint::InternalMakeCall(const PString & trasferFromToken, const PString & callIdentity, unsigned capabilityLevel, const PString & remoteParty, H323Transport * transport, PString & newToken, void * userData, PBoolean supplimentary ) { PTRACE(2, "H323\tMaking call to: " << remoteParty);
PString alias; H323TransportAddress address; if (!ParsePartyName(remoteParty, alias, address)) { PTRACE(2, "H323\tCould not parse \"" << remoteParty << '"'); return NULL; }
#ifdef H323_H46017 // If H.460.17 use the existing H.460.17 Transport if (transport == NULL && RegisteredWithH46017()) transport = GetH46017Transport(); #endif
if (transport == NULL) { // Restriction: the call must be made on the same transport as the one // that the gatekeeper is using. if (gatekeeper != NULL) transport = gatekeeper->GetTransport().GetRemoteAddress().CreateTransport(*this);
// assume address is an IP address/hostname else transport = address.CreateTransport(*this);
if (transport == NULL) { PTRACE(1, "H323\tInvalid transport in \"" << remoteParty << '"'); return NULL; } }
H323Connection * connection;
connectionsMutex.Wait();
PString adjustedToken; unsigned lastReference; if (newToken.IsEmpty()) { do { lastReference = Q931::GenerateCallReference(); newToken = BuildConnectionToken(*transport, lastReference, FALSE); } while (connectionsActive.Contains(newToken)); } else { lastReference = newToken.Mid(newToken.Find('/')+1).AsUnsigned();
// Move old connection on token to new value and flag for removal unsigned tieBreaker = 0; do { adjustedToken = newToken + "-replaced"; adjustedToken.sprintf("-%u", ++tieBreaker); } while (connectionsActive.Contains(adjustedToken)); connectionsActive.SetAt(adjustedToken, connectionsActive.RemoveAt(newToken)); connectionsToBeCleaned += adjustedToken; PTRACE(3, "H323\tOverwriting call " << newToken << ", renamed to " << adjustedToken); } connectionsMutex.Signal();
connection = CreateConnection(lastReference, userData, transport, NULL); if (connection == NULL) { PTRACE(1, "H323\tCreateConnection returned NULL"); if (!adjustedToken.IsEmpty()) { connectionsMutex.Wait();
connectionsActive.SetAt(newToken, connectionsActive.RemoveAt(adjustedToken)); connectionsToBeCleaned -= adjustedToken;
PTRACE(3, "H323\tOverwriting call " << adjustedToken << ", renamed to " << newToken);
connectionsMutex.Signal(); }
return NULL; } connection->SetRemotePartyName(remoteParty);
if (supplimentary) connection->SetNonCallConnection();
connection->Lock();
connectionsMutex.Wait(); connectionsActive.SetAt(newToken, connection);
connectionsMutex.Signal();
connection->AttachSignalChannel(newToken, transport, FALSE);
#ifdef H323_H450 if (capabilityLevel == UINT_MAX) connection->HandleTransferCall(trasferFromToken, callIdentity); else { connection->HandleIntrudeCall(trasferFromToken, callIdentity); connection->IntrudeCall(capabilityLevel); } #endif
PTRACE(3, "H323\tCreated new connection: " << newToken);
#ifdef H323_H46017 if (RegisteredWithH46017()) { H323Connection::CallEndReason reason = connection->SendSignalSetup(alias, address); if (reason != H323Connection::NumCallEndReasons) connection->ClearCall(reason); } else #endif new H225CallThread(*this, *connection, *transport, alias, address);
return connection; }
Thanks -- Iurii Gordiienko