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).
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
4.But if for some reason our virtual CreateConnection function returns 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().
My proposition - just rename back callToken for H323EndPoint::connectionsActive and remove adjustedToken from H323EndPoint::connectionsToBeCleaned if we have NULL connection.
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;
}