|
|
|
@ -905,7 +905,7 @@ static BOOL EmbedCiscoTunneledInfo(H323SignalPDU &pdu)
|
|
|
|
|
} codes[] = {
|
|
|
|
|
{ Q931::RedirectingNumberIE, },
|
|
|
|
|
{ Q931::FacilityIE, },
|
|
|
|
|
{ Q931::CallingPartyNumberIE, TRUE },
|
|
|
|
|
// { Q931::CallingPartyNumberIE, TRUE },
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
BOOL res = FALSE;
|
|
|
|
@ -1213,6 +1213,7 @@ BOOL MyH323Connection::OnSendSignalSetup(H323SignalPDU & setupPDU)
|
|
|
|
|
by embedding routines */
|
|
|
|
|
setupPDU.GetQ931().SetCallingPartyNumber(GetLocalPartyName(), (cid_ton >> 4) & 0x07,
|
|
|
|
|
cid_ton & 0x0f, (cid_presentation >> 5) & 0x03, cid_presentation & 0x1f);
|
|
|
|
|
setupPDU.GetQ931().SetDisplayName(GetDisplayName());
|
|
|
|
|
|
|
|
|
|
#ifdef TUNNELLING
|
|
|
|
|
EmbedTunneledInfo(setupPDU);
|
|
|
|
@ -1221,6 +1222,311 @@ BOOL MyH323Connection::OnSendSignalSetup(H323SignalPDU & setupPDU)
|
|
|
|
|
return H323Connection::OnSendSignalSetup(setupPDU);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static BOOL BuildFastStartList(const H323Channel & channel,
|
|
|
|
|
H225_ArrayOf_PASN_OctetString & array,
|
|
|
|
|
H323Channel::Directions reverseDirection)
|
|
|
|
|
{
|
|
|
|
|
H245_OpenLogicalChannel open;
|
|
|
|
|
const H323Capability & capability = channel.GetCapability();
|
|
|
|
|
|
|
|
|
|
if (channel.GetDirection() != reverseDirection) {
|
|
|
|
|
if (!capability.OnSendingPDU(open.m_forwardLogicalChannelParameters.m_dataType))
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
if (!capability.OnSendingPDU(open.m_reverseLogicalChannelParameters.m_dataType))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
open.m_forwardLogicalChannelParameters.m_multiplexParameters.SetTag(
|
|
|
|
|
H245_OpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters::e_none);
|
|
|
|
|
open.m_forwardLogicalChannelParameters.m_dataType.SetTag(H245_DataType::e_nullData);
|
|
|
|
|
open.IncludeOptionalField(H245_OpenLogicalChannel::e_reverseLogicalChannelParameters);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!channel.OnSendingPDU(open))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
PTRACE(4, "H225\tBuild fastStart:\n " << setprecision(2) << open);
|
|
|
|
|
PINDEX last = array.GetSize();
|
|
|
|
|
array.SetSize(last+1);
|
|
|
|
|
array[last].EncodeSubType(open);
|
|
|
|
|
|
|
|
|
|
PTRACE(3, "H225\tBuilt fastStart for " << capability);
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
H323Connection::CallEndReason MyH323Connection::SendSignalSetup(const PString & alias,
|
|
|
|
|
const H323TransportAddress & address)
|
|
|
|
|
{
|
|
|
|
|
// Start the call, first state is asking gatekeeper
|
|
|
|
|
connectionState = AwaitingGatekeeperAdmission;
|
|
|
|
|
|
|
|
|
|
// Indicate the direction of call.
|
|
|
|
|
if (alias.IsEmpty())
|
|
|
|
|
remotePartyName = remotePartyAddress = address;
|
|
|
|
|
else {
|
|
|
|
|
remotePartyName = alias;
|
|
|
|
|
remotePartyAddress = alias + '@' + address;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Start building the setup PDU to get various ID's
|
|
|
|
|
H323SignalPDU setupPDU;
|
|
|
|
|
H225_Setup_UUIE & setup = setupPDU.BuildSetup(*this, address);
|
|
|
|
|
|
|
|
|
|
#ifdef H323_H450
|
|
|
|
|
h450dispatcher->AttachToSetup(setupPDU);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// Save the identifiers generated by BuildSetup
|
|
|
|
|
setupPDU.GetQ931().GetCalledPartyNumber(remotePartyNumber);
|
|
|
|
|
|
|
|
|
|
H323TransportAddress gatekeeperRoute = address;
|
|
|
|
|
|
|
|
|
|
// Check for gatekeeper and do admission check if have one
|
|
|
|
|
H323Gatekeeper * gatekeeper = endpoint.GetGatekeeper();
|
|
|
|
|
H225_ArrayOf_AliasAddress newAliasAddresses;
|
|
|
|
|
if (gatekeeper != NULL) {
|
|
|
|
|
H323Gatekeeper::AdmissionResponse response;
|
|
|
|
|
response.transportAddress = &gatekeeperRoute;
|
|
|
|
|
response.aliasAddresses = &newAliasAddresses;
|
|
|
|
|
if (!gkAccessTokenOID)
|
|
|
|
|
response.accessTokenData = &gkAccessTokenData;
|
|
|
|
|
while (!gatekeeper->AdmissionRequest(*this, response, alias.IsEmpty())) {
|
|
|
|
|
PTRACE(1, "H225\tGatekeeper refused admission: "
|
|
|
|
|
<< (response.rejectReason == UINT_MAX
|
|
|
|
|
? PString("Transport error")
|
|
|
|
|
: H225_AdmissionRejectReason(response.rejectReason).GetTagName()));
|
|
|
|
|
#ifdef H323_H450
|
|
|
|
|
h4502handler->onReceivedAdmissionReject(H4501_GeneralErrorList::e_notAvailable);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
switch (response.rejectReason) {
|
|
|
|
|
case H225_AdmissionRejectReason::e_calledPartyNotRegistered:
|
|
|
|
|
return EndedByNoUser;
|
|
|
|
|
case H225_AdmissionRejectReason::e_requestDenied:
|
|
|
|
|
return EndedByNoBandwidth;
|
|
|
|
|
case H225_AdmissionRejectReason::e_invalidPermission:
|
|
|
|
|
case H225_AdmissionRejectReason::e_securityDenial:
|
|
|
|
|
return EndedBySecurityDenial;
|
|
|
|
|
case H225_AdmissionRejectReason::e_resourceUnavailable:
|
|
|
|
|
return EndedByRemoteBusy;
|
|
|
|
|
case H225_AdmissionRejectReason::e_incompleteAddress:
|
|
|
|
|
if (OnInsufficientDigits())
|
|
|
|
|
break;
|
|
|
|
|
// Then default case
|
|
|
|
|
default:
|
|
|
|
|
return EndedByGatekeeper;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PString lastRemotePartyName = remotePartyName;
|
|
|
|
|
while (lastRemotePartyName == remotePartyName) {
|
|
|
|
|
Unlock(); // Release the mutex as can deadlock trying to clear call during connect.
|
|
|
|
|
digitsWaitFlag.Wait();
|
|
|
|
|
if (!Lock()) // Lock while checking for shutting down.
|
|
|
|
|
return EndedByCallerAbort;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
mustSendDRQ = TRUE;
|
|
|
|
|
if (response.gatekeeperRouted) {
|
|
|
|
|
setup.IncludeOptionalField(H225_Setup_UUIE::e_endpointIdentifier);
|
|
|
|
|
setup.m_endpointIdentifier = gatekeeper->GetEndpointIdentifier();
|
|
|
|
|
gatekeeperRouted = TRUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef H323_TRANSNEXUS_OSP
|
|
|
|
|
// check for OSP server (if not using GK)
|
|
|
|
|
if (gatekeeper == NULL) {
|
|
|
|
|
OpalOSP::Provider * ospProvider = endpoint.GetOSPProvider();
|
|
|
|
|
if (ospProvider != NULL) {
|
|
|
|
|
OpalOSP::Transaction * transaction = new OpalOSP::Transaction();
|
|
|
|
|
if (transaction->Open(*ospProvider) != 0) {
|
|
|
|
|
PTRACE(1, "H225\tCannot create OSP transaction");
|
|
|
|
|
return EndedByOSPRefusal;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
OpalOSP::Transaction::DestinationInfo destInfo;
|
|
|
|
|
if (!AuthoriseOSPTransaction(*transaction, destInfo)) {
|
|
|
|
|
delete transaction;
|
|
|
|
|
return EndedByOSPRefusal;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// save the transaction for use by the call
|
|
|
|
|
ospTransaction = transaction;
|
|
|
|
|
|
|
|
|
|
// retreive the call information
|
|
|
|
|
gatekeeperRoute = destInfo.destinationAddress;
|
|
|
|
|
newAliasAddresses.Append(new H225_AliasAddress(destInfo.calledNumber));
|
|
|
|
|
|
|
|
|
|
// insert the token
|
|
|
|
|
setup.IncludeOptionalField(H225_Setup_UUIE::e_tokens);
|
|
|
|
|
destInfo.InsertToken(setup.m_tokens);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// Update the field e_destinationAddress in the SETUP PDU to reflect the new
|
|
|
|
|
// alias received in the ACF (m_destinationInfo).
|
|
|
|
|
if (newAliasAddresses.GetSize() > 0) {
|
|
|
|
|
setup.IncludeOptionalField(H225_Setup_UUIE::e_destinationAddress);
|
|
|
|
|
setup.m_destinationAddress = newAliasAddresses;
|
|
|
|
|
|
|
|
|
|
// Update the Q.931 Information Element (if is an E.164 address)
|
|
|
|
|
PString e164 = H323GetAliasAddressE164(newAliasAddresses);
|
|
|
|
|
if (!e164)
|
|
|
|
|
remotePartyNumber = e164;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (addAccessTokenToSetup && !gkAccessTokenOID && !gkAccessTokenData.IsEmpty()) {
|
|
|
|
|
PString oid1, oid2;
|
|
|
|
|
PINDEX comma = gkAccessTokenOID.Find(',');
|
|
|
|
|
if (comma == P_MAX_INDEX)
|
|
|
|
|
oid1 = oid2 = gkAccessTokenOID;
|
|
|
|
|
else {
|
|
|
|
|
oid1 = gkAccessTokenOID.Left(comma);
|
|
|
|
|
oid2 = gkAccessTokenOID.Mid(comma+1);
|
|
|
|
|
}
|
|
|
|
|
setup.IncludeOptionalField(H225_Setup_UUIE::e_tokens);
|
|
|
|
|
PINDEX last = setup.m_tokens.GetSize();
|
|
|
|
|
setup.m_tokens.SetSize(last+1);
|
|
|
|
|
setup.m_tokens[last].m_tokenOID = oid1;
|
|
|
|
|
setup.m_tokens[last].IncludeOptionalField(H235_ClearToken::e_nonStandard);
|
|
|
|
|
setup.m_tokens[last].m_nonStandard.m_nonStandardIdentifier = oid2;
|
|
|
|
|
setup.m_tokens[last].m_nonStandard.m_data = gkAccessTokenData;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!signallingChannel->SetRemoteAddress(gatekeeperRoute)) {
|
|
|
|
|
PTRACE(1, "H225\tInvalid "
|
|
|
|
|
<< (gatekeeperRoute != address ? "gatekeeper" : "user")
|
|
|
|
|
<< " supplied address: \"" << gatekeeperRoute << '"');
|
|
|
|
|
connectionState = AwaitingTransportConnect;
|
|
|
|
|
return EndedByConnectFail;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Do the transport connect
|
|
|
|
|
connectionState = AwaitingTransportConnect;
|
|
|
|
|
|
|
|
|
|
// Release the mutex as can deadlock trying to clear call during connect.
|
|
|
|
|
Unlock();
|
|
|
|
|
|
|
|
|
|
signallingChannel->SetWriteTimeout(100);
|
|
|
|
|
|
|
|
|
|
BOOL connectFailed = !signallingChannel->Connect();
|
|
|
|
|
|
|
|
|
|
// Lock while checking for shutting down.
|
|
|
|
|
if (!Lock())
|
|
|
|
|
return EndedByCallerAbort;
|
|
|
|
|
|
|
|
|
|
// See if transport connect failed, abort if so.
|
|
|
|
|
if (connectFailed) {
|
|
|
|
|
connectionState = NoConnectionActive;
|
|
|
|
|
switch (signallingChannel->GetErrorNumber()) {
|
|
|
|
|
case ENETUNREACH :
|
|
|
|
|
return EndedByUnreachable;
|
|
|
|
|
case ECONNREFUSED :
|
|
|
|
|
return EndedByNoEndPoint;
|
|
|
|
|
case ETIMEDOUT :
|
|
|
|
|
return EndedByHostOffline;
|
|
|
|
|
}
|
|
|
|
|
return EndedByConnectFail;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PTRACE(3, "H225\tSending Setup PDU");
|
|
|
|
|
connectionState = AwaitingSignalConnect;
|
|
|
|
|
|
|
|
|
|
// Put in all the signalling addresses for link
|
|
|
|
|
setup.IncludeOptionalField(H225_Setup_UUIE::e_sourceCallSignalAddress);
|
|
|
|
|
signallingChannel->SetUpTransportPDU(setup.m_sourceCallSignalAddress, TRUE);
|
|
|
|
|
if (!setup.HasOptionalField(H225_Setup_UUIE::e_destCallSignalAddress)) {
|
|
|
|
|
setup.IncludeOptionalField(H225_Setup_UUIE::e_destCallSignalAddress);
|
|
|
|
|
signallingChannel->SetUpTransportPDU(setup.m_destCallSignalAddress, FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If a standard call do Fast Start (if required)
|
|
|
|
|
if (setup.m_conferenceGoal.GetTag() == H225_Setup_UUIE_conferenceGoal::e_create) {
|
|
|
|
|
|
|
|
|
|
// Get the local capabilities before fast start is handled
|
|
|
|
|
OnSetLocalCapabilities();
|
|
|
|
|
|
|
|
|
|
// Ask the application what channels to open
|
|
|
|
|
PTRACE(3, "H225\tCheck for Fast start by local endpoint");
|
|
|
|
|
fastStartChannels.RemoveAll();
|
|
|
|
|
OnSelectLogicalChannels();
|
|
|
|
|
|
|
|
|
|
// If application called OpenLogicalChannel, put in the fastStart field
|
|
|
|
|
if (!fastStartChannels.IsEmpty()) {
|
|
|
|
|
PTRACE(3, "H225\tFast start begun by local endpoint");
|
|
|
|
|
for (PINDEX i = 0; i < fastStartChannels.GetSize(); i++)
|
|
|
|
|
BuildFastStartList(fastStartChannels[i], setup.m_fastStart, H323Channel::IsReceiver);
|
|
|
|
|
if (setup.m_fastStart.GetSize() > 0)
|
|
|
|
|
setup.IncludeOptionalField(H225_Setup_UUIE::e_fastStart);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Search the capability set and see if we have video capability
|
|
|
|
|
for (PINDEX i = 0; i < localCapabilities.GetSize(); i++) {
|
|
|
|
|
switch (localCapabilities[i].GetMainType()) {
|
|
|
|
|
case H323Capability::e_Audio:
|
|
|
|
|
case H323Capability::e_UserInput:
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default: // Is video or other data (eg T.120)
|
|
|
|
|
setupPDU.GetQ931().SetBearerCapabilities(Q931::TransferUnrestrictedDigital, 6);
|
|
|
|
|
i = localCapabilities.GetSize(); // Break out of the for loop
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!OnSendSignalSetup(setupPDU))
|
|
|
|
|
return EndedByNoAccept;
|
|
|
|
|
|
|
|
|
|
// Do this again (was done when PDU was constructed) in case
|
|
|
|
|
// OnSendSignalSetup() changed something.
|
|
|
|
|
// setupPDU.SetQ931Fields(*this, TRUE);
|
|
|
|
|
setupPDU.GetQ931().GetCalledPartyNumber(remotePartyNumber);
|
|
|
|
|
|
|
|
|
|
fastStartState = FastStartDisabled;
|
|
|
|
|
BOOL set_lastPDUWasH245inSETUP = FALSE;
|
|
|
|
|
|
|
|
|
|
if (h245Tunneling && doH245inSETUP) {
|
|
|
|
|
h245TunnelTxPDU = &setupPDU;
|
|
|
|
|
|
|
|
|
|
// Try and start the master/slave and capability exchange through the tunnel
|
|
|
|
|
// Note: this used to be disallowed but is now allowed as of H323v4
|
|
|
|
|
BOOL ok = StartControlNegotiations();
|
|
|
|
|
|
|
|
|
|
h245TunnelTxPDU = NULL;
|
|
|
|
|
|
|
|
|
|
if (!ok)
|
|
|
|
|
return EndedByTransportFail;
|
|
|
|
|
|
|
|
|
|
if (setup.m_fastStart.GetSize() > 0) {
|
|
|
|
|
// Now if fast start as well need to put this in setup specific field
|
|
|
|
|
// and not the generic H.245 tunneling field
|
|
|
|
|
setup.IncludeOptionalField(H225_Setup_UUIE::e_parallelH245Control);
|
|
|
|
|
setup.m_parallelH245Control = setupPDU.m_h323_uu_pdu.m_h245Control;
|
|
|
|
|
setupPDU.m_h323_uu_pdu.RemoveOptionalField(H225_H323_UU_PDU::e_h245Control);
|
|
|
|
|
set_lastPDUWasH245inSETUP = TRUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Send the initial PDU
|
|
|
|
|
setupTime = PTime();
|
|
|
|
|
if (!WriteSignalPDU(setupPDU))
|
|
|
|
|
return EndedByTransportFail;
|
|
|
|
|
|
|
|
|
|
// WriteSignalPDU always resets lastPDUWasH245inSETUP.
|
|
|
|
|
// So set it here if required
|
|
|
|
|
if (set_lastPDUWasH245inSETUP)
|
|
|
|
|
lastPDUWasH245inSETUP = TRUE;
|
|
|
|
|
|
|
|
|
|
// Set timeout for remote party to answer the call
|
|
|
|
|
signallingChannel->SetReadTimeout(endpoint.GetSignallingChannelCallTimeout());
|
|
|
|
|
|
|
|
|
|
return NumCallEndReasons;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
BOOL MyH323Connection::OnSendReleaseComplete(H323SignalPDU & releaseCompletePDU)
|
|
|
|
|
{
|
|
|
|
|
if (h323debug) {
|
|
|
|
|