4 * H.323 protocol handler
8 * Copyright (c) 1998-2000 Equivalence Pty. Ltd.
10 * The contents of this file are subject to the Mozilla Public License
11 * Version 1.0 (the "License"); you may not use this file except in
12 * compliance with the License. You may obtain a copy of the License at
13 * http://www.mozilla.org/MPL/
15 * Software distributed under the License is distributed on an "AS IS"
16 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
17 * the License for the specific language governing rights and limitations
20 * The Original Code is Open H323 Library.
22 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
24 * Portions of this code were written with the assisance of funding from
25 * Vovida Networks, Inc. http://www.vovida.com.
27 * Contributor(s): ______________________________________.
30 * Revision 2.68 2007/04/04 02:12:00 rjongbloed
31 * Reviewed and adjusted PTRACE log levels
32 * Now follows 1=error,2=warn,3=info,4+=debug
34 * Revision 2.67 2007/04/03 07:40:24 rjongbloed
35 * Fixed CreateCall usage so correct function (with userData) is called on
36 * incoming connections.
38 * Revision 2.66 2007/04/02 05:51:33 rjongbloed
39 * Tidied some trace logs to assure all have a category (bit before a tab character) set.
41 * Revision 2.65 2007/03/29 23:55:46 rjongbloed
42 * Tidied some code when a new connection is created by an endpoint. Now
43 * if someone needs to derive a connection class they can create it without
44 * needing to remember to do any more than the new.
46 * Revision 2.64 2007/03/13 02:17:46 csoutheren
47 * Remove warnings/errors when compiling with various turned off
49 * Revision 2.63 2007/03/12 23:22:17 csoutheren
50 * Add ability to remove H.450
52 * Revision 2.62 2007/03/01 05:51:04 rjongbloed
53 * Fixed backward compatibility of OnIncomingConnection() virtual
54 * functions on various classes. If an old override returned FALSE
55 * then it will now abort the call as it used to.
57 * Revision 2.61 2007/01/24 04:00:56 csoutheren
58 * Arrrghh. Changing OnIncomingConnection turned out to have a lot of side-effects
59 * Added some pure viritual functions to prevent old code from breaking silently
60 * New OpalEndpoint and OpalConnection descendants will need to re-implement
61 * OnIncomingConnection. Sorry :)
63 * Revision 2.60 2007/01/18 04:45:16 csoutheren
64 * Messy, but simple change to add additional options argument to OpalConnection constructor
65 * This allows the provision of non-trivial arguments for connections
67 * Revision 2.59 2006/12/18 03:18:42 csoutheren
68 * Messy but simple fixes
69 * - Add access to SIP REGISTER timeout
70 * - Ensure OpalConnection options are correctly progagated
72 * Revision 2.58 2006/09/28 07:42:17 csoutheren
73 * Merge of useful SRTP implementation
75 * Revision 2.57 2006/09/19 01:52:17 csoutheren
76 * Fixed parsing for explicit address and ports when using a GK
78 * Revision 2.56 2006/08/29 00:55:51 csoutheren
79 * Fixed problem with parsing aliases when using GKs
81 * Revision 2.55 2006/08/21 05:29:25 csoutheren
82 * Messy but relatively simple change to add support for secure (SSL/TLS) TCP transport
83 * and secure H.323 signalling via the sh323 URL scheme
85 * Revision 2.54 2006/06/28 11:21:09 csoutheren
86 * Removed warning on gcc
88 * Revision 2.53 2006/06/27 13:07:37 csoutheren
89 * Patch 1374533 - add h323 Progress handling
90 * Thanks to Frederich Heem
92 * Revision 2.52 2006/06/27 12:54:35 csoutheren
93 * Patch 1374489 - h450.7 message center support
94 * Thanks to Frederich Heem
96 * Revision 2.51 2006/05/30 11:33:02 hfriederich
97 * Porting support for H.460 from OpenH323
99 * Revision 2.50 2006/05/30 04:58:06 csoutheren
100 * Added suport for SIP INFO message (untested as yet)
101 * Fixed some issues with SIP state machine on answering calls
102 * Fixed some formatting issues
104 * Revision 2.49 2006/04/20 16:52:22 hfriederich
105 * Adding support for H.224/H.281
107 * Revision 2.48 2006/03/12 06:36:57 rjongbloed
108 * Fixed DevStudio warning
110 * Revision 2.47 2006/03/07 11:23:46 csoutheren
111 * Add ability to disable GRQ on GK registration
113 * Revision 2.46 2006/02/22 10:40:10 csoutheren
114 * Added patch #1374583 from Frederic Heem
115 * Added additional H.323 virtual function
117 * Revision 2.45 2006/02/22 10:37:48 csoutheren
118 * Fixed warning on Linux
120 * Revision 2.44 2006/02/22 10:29:09 csoutheren
121 * Applied patch #1374470 from Frederic Heem
122 * Add ability to disable H.245 negotiation
124 * Revision 2.43 2006/02/13 11:09:56 csoutheren
125 * Multiple fixes for H235 authenticators
127 * Revision 2.42 2006/01/14 10:43:06 dsandras
128 * Applied patch from Brian Lu <Brian.Lu _AT_____ sun.com> to allow compilation
129 * with OpenSolaris compiler. Many thanks !!!
131 * Revision 2.41 2006/01/02 15:52:39 dsandras
132 * Added what was required to merge changes from OpenH323 Altas_devel_2 in gkclient.cxx, gkserver.cxx and channels.cxx.
134 * Revision 2.40 2005/11/28 19:08:26 dsandras
135 * Added E.164 support.
137 * History trimmed CRS 7 Sep 2006
144 #pragma implementation "h323ep.h"
147 #include <h323/h323ep.h>
149 #include <ptclib/random.h>
150 #include <opal/call.h>
151 #include <h323/h323pdu.h>
152 #include <h323/gkclient.h>
153 #include <ptclib/url.h>
154 #include <ptclib/enum.h>
155 #include <ptclib/pils.h>
161 BYTE
H323EndPoint::defaultT35CountryCode
= 9; // Country code for Australia
162 BYTE
H323EndPoint::defaultT35Extension
= 0;
163 WORD
H323EndPoint::defaultManufacturerCode
= 61; // Allocated by Australian Communications Authority, Oct 2000;
166 /////////////////////////////////////////////////////////////////////////////
168 H323EndPoint::H323EndPoint(OpalManager
& manager
, const char * _prefix
, WORD _defaultSignalPort
)
169 : OpalEndPoint(manager
, _prefix
, CanTerminateCall
),
170 m_bH245Disabled(FALSE
),
171 signallingChannelCallTimeout(0, 0, 1), // Minutes
172 controlChannelStartTimeout(0, 0, 2), // Minutes
173 endSessionTimeout(0, 10), // Seconds
174 masterSlaveDeterminationTimeout(0, 30), // Seconds
175 capabilityExchangeTimeout(0, 30), // Seconds
176 logicalChannelTimeout(0, 30), // Seconds
177 requestModeTimeout(0, 30), // Seconds
178 roundTripDelayTimeout(0, 10), // Seconds
179 roundTripDelayRate(0, 0, 1), // Minutes
180 gatekeeperRequestTimeout(0, 5), // Seconds
181 rasRequestTimeout(0, 3), // Seconds
182 callTransferT1(0,10), // Seconds
183 callTransferT2(0,10), // Seconds
184 callTransferT3(0,10), // Seconds
185 callTransferT4(0,10), // Seconds
186 callIntrusionT1(0,30), // Seconds
187 callIntrusionT2(0,30), // Seconds
188 callIntrusionT3(0,30), // Seconds
189 callIntrusionT4(0,30), // Seconds
190 callIntrusionT5(0,10), // Seconds
191 callIntrusionT6(0,10) // Seconds
193 ,nextH450CallIdentity(0)
196 // Set port in OpalEndPoint class
197 defaultSignalPort
= _defaultSignalPort
;
199 localAliasNames
.AppendString(defaultLocalPartyName
);
201 autoStartReceiveFax
= autoStartTransmitFax
= FALSE
;
203 isH224Enabled
= FALSE
;
205 m_bH245Disabled
= FALSE
;
206 autoCallForward
= TRUE
;
207 disableFastStart
= FALSE
;
208 disableH245Tunneling
= FALSE
;
209 disableH245inSetup
= FALSE
;
210 canDisplayAmountString
= FALSE
;
211 canEnforceDurationLimit
= TRUE
;
214 callIntrusionProtectionLevel
= 3; //H45011_CIProtectionLevel::e_fullProtection;
217 terminalType
= e_TerminalOnly
;
218 clearCallOnRoundTripFail
= FALSE
;
220 t35CountryCode
= defaultT35CountryCode
; // Country code for Australia
221 t35Extension
= defaultT35Extension
;
222 manufacturerCode
= defaultManufacturerCode
; // Allocated by Australian Communications Authority, Oct 2000
224 masterSlaveDeterminationRetries
= 10;
225 gatekeeperRequestRetries
= 2;
226 rasRequestRetries
= 2;
231 secondaryConnectionsActive
.DisallowDeleteObjects();
234 features
.AttachEndPoint(this);
235 features
.LoadFeatureSet(H460_Feature::FeatureBase
);
238 PTRACE(4, "H323\tCreated endpoint.");
242 H323EndPoint::~H323EndPoint()
244 // And shut down the gatekeeper (if there was one)
247 // Shut down the listeners as soon as possible to avoid race conditions
248 listeners
.RemoveAll();
250 PTRACE(4, "H323\tDeleted endpoint.");
254 void H323EndPoint::SetEndpointTypeInfo(H225_EndpointType
& info
) const
256 info
.IncludeOptionalField(H225_EndpointType::e_vendor
);
257 SetVendorIdentifierInfo(info
.m_vendor
);
259 switch (terminalType
) {
260 case e_TerminalOnly
:
261 case e_TerminalAndMC
:
262 info
.IncludeOptionalField(H225_EndpointType::e_terminal
);
265 case e_GatewayAndMC
:
266 case e_GatewayAndMCWithDataMP
:
267 case e_GatewayAndMCWithAudioMP
:
268 case e_GatewayAndMCWithAVMP
:
269 info
.IncludeOptionalField(H225_EndpointType::e_gateway
);
271 case e_GatekeeperOnly
:
272 case e_GatekeeperWithDataMP
:
273 case e_GatekeeperWithAudioMP
:
274 case e_GatekeeperWithAVMP
:
275 info
.IncludeOptionalField(H225_EndpointType::e_gatekeeper
);
278 case e_MCUWithDataMP
:
279 case e_MCUWithAudioMP
:
281 info
.IncludeOptionalField(H225_EndpointType::e_mcu
);
287 void H323EndPoint::SetVendorIdentifierInfo(H225_VendorIdentifier
& info
) const
289 SetH221NonStandardInfo(info
.m_vendor
);
291 info
.IncludeOptionalField(H225_VendorIdentifier::e_productId
);
292 info
.m_productId
= PProcess::Current().GetManufacturer() & PProcess::Current().GetName();
293 info
.m_productId
.SetSize(info
.m_productId
.GetSize()+2);
295 info
.IncludeOptionalField(H225_VendorIdentifier::e_versionId
);
296 info
.m_versionId
= PProcess::Current().GetVersion(TRUE
) + " (OPAL v" + OpalGetVersion() + ')';
297 info
.m_versionId
.SetSize(info
.m_versionId
.GetSize()+2);
301 void H323EndPoint::SetH221NonStandardInfo(H225_H221NonStandard
& info
) const
303 info
.m_t35CountryCode
= t35CountryCode
;
304 info
.m_t35Extension
= t35Extension
;
305 info
.m_manufacturerCode
= manufacturerCode
;
309 H323Capability
* H323EndPoint::FindCapability(const H245_Capability
& cap
) const
311 return GetCapabilities().FindCapability(cap
);
315 H323Capability
* H323EndPoint::FindCapability(const H245_DataType
& dataType
) const
317 return GetCapabilities().FindCapability(dataType
);
321 H323Capability
* H323EndPoint::FindCapability(H323Capability::MainTypes mainType
,
322 unsigned subType
) const
324 return GetCapabilities().FindCapability(mainType
, subType
);
328 void H323EndPoint::AddCapability(H323Capability
* capability
)
330 capabilities
.Add(capability
);
334 PINDEX
H323EndPoint::SetCapability(PINDEX descriptorNum
,
335 PINDEX simultaneousNum
,
336 H323Capability
* capability
)
338 return capabilities
.SetCapability(descriptorNum
, simultaneousNum
, capability
);
342 PINDEX
H323EndPoint::AddAllCapabilities(PINDEX descriptorNum
,
344 const PString
& name
)
346 return capabilities
.AddAllCapabilities(*this, descriptorNum
, simultaneous
, name
);
350 void H323EndPoint::AddAllUserInputCapabilities(PINDEX descriptorNum
,
353 H323_UserInputCapability::AddAllCapabilities(capabilities
, descriptorNum
, simultaneous
);
357 void H323EndPoint::RemoveCapabilities(const PStringArray
& codecNames
)
359 capabilities
.Remove(codecNames
);
363 void H323EndPoint::ReorderCapabilities(const PStringArray
& preferenceOrder
)
365 capabilities
.Reorder(preferenceOrder
);
369 const H323Capabilities
& H323EndPoint::GetCapabilities() const
371 if (capabilities
.GetSize() == 0) {
372 capabilities
.AddAllCapabilities(*this, P_MAX_INDEX
, P_MAX_INDEX
, "*");
373 H323_UserInputCapability::AddAllCapabilities(capabilities
, P_MAX_INDEX
, P_MAX_INDEX
);
380 BOOL
H323EndPoint::UseGatekeeper(const PString
& address
,
381 const PString
& identifier
,
382 const PString
& localAddress
)
384 if (gatekeeper
!= NULL
) {
388 same
= gatekeeper
->GetTransport().GetRemoteAddress().IsEquivalent(address
);
390 if (!same
&& !identifier
)
391 same
= gatekeeper
->GetIdentifier() == identifier
;
393 if (!same
&& !localAddress
)
394 same
= gatekeeper
->GetTransport().GetLocalAddress().IsEquivalent(localAddress
);
397 PTRACE(3, "H323\tUsing existing gatekeeper " << *gatekeeper
);
402 H323Transport
* transport
= NULL
;
403 if (!localAddress
.IsEmpty()) {
404 H323TransportAddress
iface(localAddress
);
405 PIPSocket::Address ip
;
406 WORD port
= H225_RAS::DefaultRasUdpPort
;
407 if (iface
.GetIpAndPort(ip
, port
))
408 transport
= new H323TransportUDP(*this, ip
, port
);
411 if (address
.IsEmpty()) {
412 if (identifier
.IsEmpty())
413 return DiscoverGatekeeper(transport
);
415 return LocateGatekeeper(identifier
, transport
);
418 if (identifier
.IsEmpty())
419 return SetGatekeeper(address
, transport
);
421 return SetGatekeeperZone(address
, identifier
, transport
);
426 BOOL
H323EndPoint::SetGatekeeper(const PString
& address
, H323Transport
* transport
)
428 H323Gatekeeper
* gk
= InternalCreateGatekeeper(transport
);
429 H323TransportAddress
h323addr(address
, H225_RAS::DefaultRasUdpPort
, "udp");
430 return InternalRegisterGatekeeper(gk
, gk
->DiscoverByAddress(h323addr
));
434 BOOL
H323EndPoint::SetGatekeeperZone(const PString
& address
,
435 const PString
& identifier
,
436 H323Transport
* transport
)
438 H323Gatekeeper
* gk
= InternalCreateGatekeeper(transport
);
439 H323TransportAddress
h323addr(address
, H225_RAS::DefaultRasUdpPort
, "udp");
440 return InternalRegisterGatekeeper(gk
, gk
->DiscoverByNameAndAddress(identifier
, h323addr
));
444 BOOL
H323EndPoint::LocateGatekeeper(const PString
& identifier
, H323Transport
* transport
)
446 H323Gatekeeper
* gk
= InternalCreateGatekeeper(transport
);
447 return InternalRegisterGatekeeper(gk
, gk
->DiscoverByName(identifier
));
451 BOOL
H323EndPoint::DiscoverGatekeeper(H323Transport
* transport
)
453 H323Gatekeeper
* gk
= InternalCreateGatekeeper(transport
);
454 return InternalRegisterGatekeeper(gk
, gk
->DiscoverAny());
458 H323Gatekeeper
* H323EndPoint::InternalCreateGatekeeper(H323Transport
* transport
)
460 RemoveGatekeeper(H225_UnregRequestReason::e_reregistrationRequired
);
462 if (transport
== NULL
)
463 transport
= new H323TransportUDP(*this);
466 H323Gatekeeper
* gk
= CreateGatekeeper(transport
);
468 gk
->SetPassword(gatekeeperPassword
, gatekeeperUsername
);
474 BOOL
H323EndPoint::InternalRegisterGatekeeper(H323Gatekeeper
* gk
, BOOL discovered
)
477 if (gk
->RegistrationRequest()) {
482 // RRQ was rejected continue trying
485 else // Only stop listening if the GRQ was rejected
492 H323Gatekeeper
* H323EndPoint::CreateGatekeeper(H323Transport
* transport
)
494 return new H323Gatekeeper(*this, transport
);
498 BOOL
H323EndPoint::IsRegisteredWithGatekeeper() const
500 if (gatekeeper
== NULL
)
503 return gatekeeper
->IsRegistered();
507 BOOL
H323EndPoint::RemoveGatekeeper(int reason
)
511 if (gatekeeper
== NULL
)
516 if (gatekeeper
->IsRegistered()) // If we are registered send a URQ
517 ok
= gatekeeper
->UnregistrationRequest(reason
);
526 void H323EndPoint::SetGatekeeperPassword(const PString
& password
, const PString
& username
)
528 gatekeeperUsername
= username
;
529 gatekeeperPassword
= password
;
531 if (gatekeeper
!= NULL
) {
532 gatekeeper
->SetPassword(gatekeeperPassword
, gatekeeperUsername
);
533 if (gatekeeper
->IsRegistered()) // If we are registered send a URQ
534 gatekeeper
->UnregistrationRequest(H225_UnregRequestReason::e_reregistrationRequired
);
535 InternalRegisterGatekeeper(gatekeeper
, TRUE
);
539 void H323EndPoint::OnGatekeeperConfirm()
543 void H323EndPoint::OnGatekeeperReject()
547 void H323EndPoint::OnRegistrationConfirm()
551 void H323EndPoint::OnRegistrationReject()
555 H235Authenticators
H323EndPoint::CreateAuthenticators()
557 H235Authenticators authenticators
;
559 PFactory
<H235Authenticator
>::KeyList_T keyList
= PFactory
<H235Authenticator
>::GetKeyList();
560 PFactory
<H235Authenticator
>::KeyList_T::const_iterator r
;
561 for (r
= keyList
.begin(); r
!= keyList
.end(); ++r
)
562 authenticators
.Append(PFactory
<H235Authenticator
>::CreateInstance(*r
));
564 PTRACE(3, "H323\tAuthenticator list is size " << (int)authenticators
.GetSize());
566 return authenticators
;
570 BOOL
H323EndPoint::MakeConnection(OpalCall
& call
,
571 const PString
& remoteParty
,
573 unsigned int options
,
574 OpalConnection::StringOptions
* stringOptions
)
576 PTRACE(3, "H323\tMaking call to: " << remoteParty
);
577 return InternalMakeCall(call
,
588 OpalMediaFormatList
H323EndPoint::GetMediaFormats() const
590 return OpalMediaFormat::GetAllRegisteredMediaFormats();
594 BOOL
H323EndPoint::NewIncomingConnection(OpalTransport
* transport
)
596 PTRACE(3, "H225\tAwaiting first PDU");
597 transport
->SetReadTimeout(15000); // Await 15 seconds after connect for first byte
599 if (!pdu
.Read(*transport
)) {
600 PTRACE(1, "H225\tFailed to get initial Q.931 PDU, connection not started.");
604 unsigned callReference
= pdu
.GetQ931().GetCallReference();
605 PTRACE(3, "H225\tIncoming call, first PDU: callReference=" << callReference
);
607 // Get a new (or old) connection from the endpoint, calculate token
608 PString token
= transport
->GetRemoteAddress();
609 token
.sprintf("/%u", callReference
);
611 PSafePtr
<H323Connection
> connection
= FindConnectionWithLock(token
);
613 if (connection
== NULL
) {
614 connection
= CreateConnection(*manager
.CreateCall(NULL
), token
, NULL
,
615 *transport
, PString::Empty(), PString::Empty(), &pdu
);
616 if (!AddConnection(connection
)) {
617 PTRACE(1, "H225\tEndpoint could not create connection, "
618 "sending release complete PDU: callRef=" << callReference
);
620 H323SignalPDU releaseComplete
;
621 Q931
&q931PDU
= releaseComplete
.GetQ931();
622 q931PDU
.BuildReleaseComplete(callReference
, TRUE
);
623 releaseComplete
.m_h323_uu_pdu
.m_h323_message_body
.SetTag(H225_H323_UU_PDU_h323_message_body::e_releaseComplete
);
625 H225_ReleaseComplete_UUIE
&release
= releaseComplete
.m_h323_uu_pdu
.m_h323_message_body
;
626 release
.m_protocolIdentifier
.SetValue(psprintf("0.0.8.2250.0.%u", H225_PROTOCOL_VERSION
));
628 H225_Setup_UUIE
&setup
= pdu
.m_h323_uu_pdu
.m_h323_message_body
;
629 if (setup
.HasOptionalField(H225_Setup_UUIE::e_callIdentifier
)) {
630 release
.IncludeOptionalField(H225_Setup_UUIE::e_callIdentifier
);
631 release
.m_callIdentifier
= setup
.m_callIdentifier
;
634 // Set the cause value
635 q931PDU
.SetCause(Q931::TemporaryFailure
);
638 releaseComplete
.Write(*transport
);
644 PTRACE(3, "H323\tCreated new connection: " << token
);
645 connection
->AttachSignalChannel(token
, transport
, TRUE
);
647 if (connection
->HandleSignalPDU(pdu
)) {
648 // All subsequent PDU's should wait forever
649 transport
->SetReadTimeout(PMaxTimeInterval
);
650 connection
->HandleSignallingChannel();
653 connection
->ClearCall(H323Connection::EndedByTransportFail
);
654 PTRACE(1, "H225\tSignal channel stopped on first PDU.");
661 H323Connection
* H323EndPoint::CreateConnection(OpalCall
& call
,
662 const PString
& token
,
664 OpalTransport
& /*transport*/,
665 const PString
& alias
,
666 const H323TransportAddress
& address
,
667 H323SignalPDU
* /*setupPDU*/,
669 OpalConnection::StringOptions
* stringOptions
)
671 return new H323Connection(call
, *this, token
, alias
, address
, options
, stringOptions
);
675 BOOL
H323EndPoint::SetupTransfer(const PString
& oldToken
,
676 const PString
& callIdentity
,
677 const PString
& remoteParty
,
680 // Make a new connection
681 PSafePtr
<OpalConnection
> otherConnection
=
682 GetConnectionWithLock(oldToken
, PSafeReference
);
683 if (otherConnection
== NULL
) {
687 OpalCall
& call
= otherConnection
->GetCall();
689 call
.RemoveMediaStreams();
691 PTRACE(3, "H323\tTransferring call to: " << remoteParty
);
692 BOOL ok
= InternalMakeCall(call
,
698 call
.OnReleased(*otherConnection
);
699 otherConnection
->Release(OpalConnection::EndedByCallForwarded
);
705 BOOL
H323EndPoint::InternalMakeCall(OpalCall
& call
,
706 const PString
& existingToken
,
708 const PString
& callIdentity
,
709 unsigned capabilityLevel
,
714 const PString
& remoteParty
,
716 unsigned int options
,
717 OpalConnection::StringOptions
* stringOptions
)
720 H323TransportAddress address
;
721 if (!ParsePartyName(remoteParty
, alias
, address
)) {
722 PTRACE(2, "H323\tCould not parse \"" << remoteParty
<< '"');
726 // Restriction: the call must be made on the same transport as the one
727 // that the gatekeeper is using.
728 H323Transport
* transport
;
729 if (gatekeeper
!= NULL
)
730 transport
= gatekeeper
->GetTransport().GetLocalAddress().CreateTransport(
731 *this, OpalTransportAddress::Streamed
);
733 transport
= address
.CreateTransport(*this, OpalTransportAddress::NoBinding
);
735 if (transport
== NULL
) {
736 PTRACE(1, "H323\tInvalid transport in \"" << remoteParty
<< '"');
743 if (existingToken
.IsEmpty()) {
745 newToken
= psprintf("localhost/%u", Q931::GenerateCallReference());
746 } while (connectionsActive
.Contains(newToken
));
749 H323Connection
* connection
= CreateConnection(call
, newToken
, userData
, *transport
, alias
, address
, NULL
, options
, stringOptions
);
750 if (!AddConnection(connection
)) {
751 PTRACE(1, "H225\tEndpoint could not create connection, aborting setup.");
757 connection
->AttachSignalChannel(newToken
, transport
, FALSE
);
761 if (capabilityLevel
== UINT_MAX
)
762 connection
->HandleTransferCall(existingToken
, callIdentity
);
764 connection
->HandleIntrudeCall(existingToken
, callIdentity
);
765 connection
->IntrudeCall(capabilityLevel
);
770 PTRACE(3, "H323\tCreated new connection: " << newToken
);
772 // See if we are starting an outgoing connection as first in a call
773 if (call
.GetConnection(0) == (OpalConnection
*)connection
|| !existingToken
.IsEmpty())
774 connection
->SetUpConnection();
782 void H323EndPoint::TransferCall(const PString
& token
,
783 const PString
& remoteParty
,
784 const PString
& callIdentity
)
786 PSafePtr
<H323Connection
> connection
= FindConnectionWithLock(token
);
787 if (connection
!= NULL
)
788 connection
->TransferCall(remoteParty
, callIdentity
);
792 void H323EndPoint::ConsultationTransfer(const PString
& primaryCallToken
,
793 const PString
& secondaryCallToken
)
795 PSafePtr
<H323Connection
> secondaryCall
= FindConnectionWithLock(secondaryCallToken
);
796 if (secondaryCall
!= NULL
)
797 secondaryCall
->ConsultationTransfer(primaryCallToken
);
801 void H323EndPoint::HoldCall(const PString
& token
, BOOL localHold
)
803 PSafePtr
<H323Connection
> connection
= FindConnectionWithLock(token
);
804 if (connection
!= NULL
)
805 connection
->HoldCall(localHold
);
809 BOOL
H323EndPoint::IntrudeCall(const PString
& remoteParty
,
810 unsigned capabilityLevel
,
813 return InternalMakeCall(*manager
.CreateCall(NULL
),
823 BOOL
H323EndPoint::OnSendConnect(H323Connection
& /*connection*/,
824 H323SignalPDU
& /*connectPDU*/
830 BOOL
H323EndPoint::OnSendSignalSetup(H323Connection
& /*connection*/,
831 H323SignalPDU
& /*setupPDU*/)
836 BOOL
H323EndPoint::OnSendCallProceeding(H323Connection
& /*connection*/,
837 H323SignalPDU
& /*callProceedingPDU*/)
842 void H323EndPoint::OnReceivedInitiateReturnError()
846 BOOL
H323EndPoint::ParsePartyName(const PString
& _remoteParty
,
848 H323TransportAddress
& address
)
850 PString remoteParty
= _remoteParty
;
853 // if there is no gatekeeper, and there is no '@', and there is no URL scheme, then attempt to use ENUM
854 if ((remoteParty
.Find('@') == P_MAX_INDEX
) && (gatekeeper
== NULL
)) {
856 // make sure the number has only digits
857 PString e164
= remoteParty
;
858 if (e164
.Left(4) *= "h323:")
861 for (i
= 0; i
< e164
.GetLength(); ++i
)
862 if (!isdigit(e164
[i
]) && (i
!= 0 || e164
[0] != '+'))
864 if (i
>= e164
.GetLength()) {
866 if (PDNS::ENUMLookup(e164
, "E2U+h323", str
)) {
867 PTRACE(4, "H323\tENUM converted remote party " << _remoteParty
<< " to " << str
);
876 PURL
url(remoteParty
, GetPrefixName());
878 // Special adjustment if
879 if (remoteParty
.Find('@') == P_MAX_INDEX
&&
880 remoteParty
.NumCompare(url
.GetScheme()) != EqualTo
) {
881 if (gatekeeper
== NULL
)
882 url
.Parse(GetPrefixName() + ":@" + remoteParty
);
884 url
.Parse(GetPrefixName() + ":" + remoteParty
);
887 alias
= url
.GetUserName();
889 address
= url
.GetHostName();
890 if (!address
&& url
.GetPort() != 0)
891 address
.sprintf(":%u", url
.GetPort());
893 if (alias
.IsEmpty() && address
.IsEmpty()) {
894 PTRACE(1, "H323\tAttempt to use invalid URL \"" << remoteParty
<< '"');
898 BOOL gatekeeperSpecified
= FALSE
;
899 BOOL gatewaySpecified
= FALSE
;
901 PCaselessString type
= url
.GetParamVars()("type");
903 if (url
.GetScheme() == "callto") {
904 // Do not yet support ILS
905 if (type
== "directory") {
907 PString server
= url
.GetHostName();
908 if (server
.IsEmpty())
909 server
= GetDefaultILSServer();
910 if (server
.IsEmpty())
914 if (!ils
.Open(server
, url
.GetPort())) {
915 PTRACE(1, "H323\tCould not open ILS server at \"" << server
916 << "\" - " << ils
.GetErrorText());
920 PILSSession::RTPerson person
;
921 if (!ils
.SearchPerson(alias
, person
)) {
922 PTRACE(1, "H323\tCould not find "
923 << server
<< '/' << alias
<< ": " << ils
.GetErrorText());
927 if (!person
.sipAddress
.IsValid()) {
928 PTRACE(1, "H323\tILS user " << server
<< '/' << alias
929 << " does not have a valid IP address");
933 // Get the IP address
934 address
= H323TransportAddress(person
.sipAddress
);
936 // Get the port if provided
937 for (PINDEX i
= 0; i
< person
.sport
.GetSize(); i
++) {
938 if (person
.sport
[i
] != 1503) { // Dont use the T.120 port
939 address
= H323TransportAddress(person
.sipAddress
, person
.sport
[i
]);
944 alias
= PString::Empty(); // No alias for ILS lookup, only host
951 if (url
.GetParamVars().Contains("gateway"))
952 gatewaySpecified
= TRUE
;
954 else if (url
.GetScheme() == "h323") {
956 gatewaySpecified
= TRUE
;
957 else if (type
== "gk")
958 gatekeeperSpecified
= TRUE
;
960 PTRACE(1, "H323\tUnsupported host type \"" << type
<< "\" in h323 URL");
965 // User explicitly asked fo a look up to a gk
966 if (gatekeeperSpecified
) {
967 if (alias
.IsEmpty()) {
968 PTRACE(1, "H323\tAttempt to use explict gatekeeper without alias!");
972 if (address
.IsEmpty()) {
973 PTRACE(1, "H323\tAttempt to use explict gatekeeper without address!");
977 H323TransportAddress gkAddr
= address
;
978 PTRACE(3, "H323\tLooking for \"" << alias
<< "\" on gatekeeper at " << gkAddr
);
980 H323Gatekeeper
* gk
= CreateGatekeeper(new H323TransportUDP(*this));
982 BOOL ok
= gk
->DiscoverByAddress(gkAddr
);
984 ok
= gk
->LocationRequest(alias
, address
);
986 PTRACE(3, "H323\tLocation Request of \"" << alias
<< "\" on gk " << gkAddr
<< " found " << address
);
989 PTRACE(1, "H323\tLocation Request failed for \"" << alias
<< "\" on gk " << gkAddr
);
993 PTRACE(1, "H323\tLocation Request discovery failed for gk " << gkAddr
);
1001 // User explicitly said to use a gw, or we do not have a gk to do look up
1002 if (gatekeeper
== NULL
|| gatewaySpecified
) {
1003 // If URL did not have a host, but user said to use gw, or we do not have
1004 // a gk to do a lookup so we MUST have a host, use alias must be host
1005 if (address
.IsEmpty()) {
1006 address
= H323TransportAddress(alias
, GetDefaultSignalPort(), GetDefaultTransport());
1007 alias
= PString::Empty();
1012 // We have a gatekeeper and user provided a host, all done
1016 // We have a gk and user did not explicitly supply a host, so lets
1017 // do a check to see if it is an IP address
1018 if (alias
.FindRegEx("^[0-9][0-9]*\\.[0-9][0-9]*\\.[0-9][0-9]*\\.[0-9][0-9]*") != P_MAX_INDEX
) {
1019 PINDEX colon
= alias
.Find(':');
1020 WORD port
= GetDefaultSignalPort();
1021 if (colon
!= P_MAX_INDEX
) {
1022 port
= (WORD
)alias
.Mid(colon
+1).AsInteger();
1023 alias
= alias
.Left(colon
);
1025 PIPSocket::Address
ip(alias
);
1027 alias
= PString::Empty();
1028 address
= H323TransportAddress(ip
, port
);
1036 PSafePtr
<H323Connection
> H323EndPoint::FindConnectionWithLock(const PString
& token
, PSafetyMode mode
)
1038 PSafePtr
<H323Connection
> connnection
= PSafePtrCast
<OpalConnection
, H323Connection
>(GetConnectionWithLock(token
, mode
));
1039 if (connnection
!= NULL
)
1042 for (connnection
= PSafePtrCast
<OpalConnection
, H323Connection
>(connectionsActive
.GetAt(0)); connnection
!= NULL
; ++connnection
) {
1043 if (connnection
->GetCallIdentifier().AsString() == token
)
1045 if (connnection
->GetConferenceIdentifier().AsString() == token
)
1053 BOOL
H323EndPoint::OnIncomingCall(H323Connection
& connection
,
1054 const H323SignalPDU
& /*setupPDU*/,
1055 H323SignalPDU
& /*alertingPDU*/)
1057 return connection
.OnIncomingConnection(0, NULL
);
1061 BOOL
H323EndPoint::OnCallTransferInitiate(H323Connection
& /*connection*/,
1062 const PString
& /*remoteParty*/)
1068 BOOL
H323EndPoint::OnCallTransferIdentify(H323Connection
& /*connection*/)
1074 void H323EndPoint::OnSendARQ(H323Connection
& /*conn*/, H225_AdmissionRequest
& /*arq*/)
1079 OpalConnection::AnswerCallResponse
1080 H323EndPoint::OnAnswerCall(H323Connection
& connection
,
1081 const PString
& caller
,
1082 const H323SignalPDU
& /*setupPDU*/,
1083 H323SignalPDU
& /*connectPDU*/,
1084 H323SignalPDU
& /*progressPDU*/)
1086 return connection
.OnAnswerCall(caller
);
1089 OpalConnection::AnswerCallResponse
1090 H323EndPoint::OnAnswerCall(OpalConnection
& connection
,
1091 const PString
& caller
1094 return OpalEndPoint::OnAnswerCall(connection
, caller
);
1097 BOOL
H323EndPoint::OnAlerting(H323Connection
& connection
,
1098 const H323SignalPDU
& /*alertingPDU*/,
1099 const PString
& /*username*/)
1101 PTRACE(3, "H225\tReceived alerting PDU.");
1102 ((OpalConnection
&)connection
).OnAlerting();
1106 BOOL
H323EndPoint::OnSendAlerting(H323Connection
& PTRACE_PARAM(connection
),
1107 H323SignalPDU
& /*alerting*/,
1108 const PString
& /*calleeName*/, /// Name of endpoint being alerted.
1109 BOOL
/*withMedia*/ /// Open media with alerting
1112 PTRACE(3, "H225\tOnSendAlerting conn = " << connection
);
1116 BOOL
H323EndPoint::OnSentAlerting(H323Connection
& PTRACE_PARAM(connection
))
1118 PTRACE(3, "H225\tOnSentAlerting conn = " << connection
);
1122 BOOL
H323EndPoint::OnConnectionForwarded(H323Connection
& /*connection*/,
1123 const PString
& /*forwardParty*/,
1124 const H323SignalPDU
& /*pdu*/)
1130 BOOL
H323EndPoint::ForwardConnection(H323Connection
& connection
,
1131 const PString
& forwardParty
,
1132 const H323SignalPDU
& /*pdu*/)
1134 if (!InternalMakeCall(connection
.GetCall(),
1135 connection
.GetCallToken(),
1142 connection
.SetCallEndReason(H323Connection::EndedByCallForwarded
);
1148 void H323EndPoint::OnConnectionEstablished(H323Connection
& /*connection*/,
1149 const PString
& /*token*/)
1154 BOOL
H323EndPoint::IsConnectionEstablished(const PString
& token
)
1156 PSafePtr
<H323Connection
> connection
= FindConnectionWithLock(token
);
1157 return connection
!= NULL
&& connection
->IsEstablished();
1161 BOOL
H323EndPoint::OnOutgoingCall(H323Connection
& /*connection*/,
1162 const H323SignalPDU
& /*connectPDU*/)
1164 PTRACE(3, "H225\tReceived connect PDU.");
1169 void H323EndPoint::OnConnectionCleared(H323Connection
& /*connection*/,
1170 const PString
& /*token*/)
1176 static void OnStartStopChannel(const char * startstop
, const H323Channel
& channel
)
1179 switch (channel
.GetDirection()) {
1180 case H323Channel::IsTransmitter
:
1184 case H323Channel::IsReceiver
:
1193 PTRACE(3, "H323\t" << startstop
<< "ed "
1194 << dir
<< "ing logical channel: "
1195 << channel
.GetCapability());
1200 BOOL
H323EndPoint::OnStartLogicalChannel(H323Connection
& /*connection*/,
1201 H323Channel
& PTRACE_PARAM(channel
))
1204 OnStartStopChannel("Start", channel
);
1210 void H323EndPoint::OnClosedLogicalChannel(H323Connection
& /*connection*/,
1211 const H323Channel
& PTRACE_PARAM(channel
))
1214 OnStartStopChannel("Stopp", channel
);
1219 void H323EndPoint::OnRTPStatistics(const H323Connection
& /*connection*/,
1220 const RTP_Session
& /*session*/) const
1225 void H323EndPoint::OnGatekeeperNATDetect(PIPSocket::Address
/* publicAddr*/,
1226 PString
& /*gkIdentifier*/,
1227 H323TransportAddress
& /*gkRouteAddress*/)
1232 void H323EndPoint::OnHTTPServiceControl(unsigned /*opeartion*/,
1233 unsigned /*sessionId*/,
1234 const PString
& /*url*/)
1239 void H323EndPoint::OnCallCreditServiceControl(const PString
& /*amount*/, BOOL
/*mode*/)
1244 void H323EndPoint::OnServiceControlSession(unsigned type
,
1246 const H323ServiceControlSession
& session
,
1247 H323Connection
* connection
)
1249 session
.OnChange(type
, sessionId
, *this, connection
);
1252 BOOL
H323EndPoint::OnConferenceInvite(const H323SignalPDU
& /*setupPDU */)
1257 BOOL
H323EndPoint::OnCallIndependentSupplementaryService(const H323SignalPDU
& /* setupPDU */)
1262 BOOL
H323EndPoint::OnNegotiateConferenceCapabilities(const H323SignalPDU
& /* setupPDU */)
1267 H323ServiceControlSession
* H323EndPoint::CreateServiceControlSession(const H225_ServiceControlDescriptor
& contents
)
1269 switch (contents
.GetTag()) {
1270 case H225_ServiceControlDescriptor::e_url
:
1271 return new H323HTTPServiceControl(contents
);
1273 case H225_ServiceControlDescriptor::e_callCreditServiceControl
:
1274 return new H323CallCreditServiceControl(contents
);
1281 void H323EndPoint::SetLocalUserName(const PString
& name
)
1283 PAssert(!name
, "Must have non-empty string in AliasAddress!");
1287 localAliasNames
.RemoveAll();
1288 localAliasNames
.AppendString(name
);
1292 BOOL
H323EndPoint::AddAliasName(const PString
& name
)
1294 PAssert(!name
, "Must have non-empty string in AliasAddress!");
1296 if (localAliasNames
.GetValuesIndex(name
) != P_MAX_INDEX
)
1299 localAliasNames
.AppendString(name
);
1304 BOOL
H323EndPoint::RemoveAliasName(const PString
& name
)
1306 PINDEX pos
= localAliasNames
.GetValuesIndex(name
);
1307 if (pos
== P_MAX_INDEX
)
1310 PAssert(localAliasNames
.GetSize() > 1, "Must have at least one AliasAddress!");
1311 if (localAliasNames
.GetSize() < 2)
1314 localAliasNames
.RemoveAt(pos
);
1319 BOOL
H323EndPoint::IsTerminal() const
1321 switch (terminalType
) {
1322 case e_TerminalOnly
:
1323 case e_TerminalAndMC
:
1332 BOOL
H323EndPoint::IsGateway() const
1334 switch (terminalType
) {
1335 case e_GatewayOnly
:
1336 case e_GatewayAndMC
:
1337 case e_GatewayAndMCWithDataMP
:
1338 case e_GatewayAndMCWithAudioMP
:
1339 case e_GatewayAndMCWithAVMP
:
1348 BOOL
H323EndPoint::IsGatekeeper() const
1350 switch (terminalType
) {
1351 case e_GatekeeperOnly
:
1352 case e_GatekeeperWithDataMP
:
1353 case e_GatekeeperWithAudioMP
:
1354 case e_GatekeeperWithAVMP
:
1363 BOOL
H323EndPoint::IsMCU() const
1365 switch (terminalType
) {
1367 case e_MCUWithDataMP
:
1368 case e_MCUWithAudioMP
:
1369 case e_MCUWithAVMP
:
1378 void H323EndPoint::TranslateTCPAddress(PIPSocket::Address
& localAddr
,
1379 const PIPSocket::Address
& remoteAddr
)
1381 manager
.TranslateIPAddress(localAddr
, remoteAddr
);
1384 BOOL
H323EndPoint::OnSendFeatureSet(unsigned, H225_FeatureSet
& /*features*/)
1389 void H323EndPoint::OnReceiveFeatureSet(unsigned, const H225_FeatureSet
& /*features*/)
1393 /////////////////////////////////////////////////////////////////////////////