Reviewed and adjusted PTRACE log levels
[opal.git] / src / h323 / h323ep.cxx
blobdd63130c3976bd0742aba9322c0223fb6539d95d
1 /*
2 * h323ep.cxx
4 * H.323 protocol handler
6 * Open H323 Library
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
18 * under the License.
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): ______________________________________.
29 * $Log$
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
141 #include <ptlib.h>
143 #ifdef __GNUC__
144 #pragma implementation "h323ep.h"
145 #endif
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>
158 #define new PNEW
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
192 #if OPAL_H450
193 ,nextH450CallIdentity(0)
194 #endif
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;
213 #if OPAL_H450
214 callIntrusionProtectionLevel = 3; //H45011_CIProtectionLevel::e_fullProtection;
215 #endif
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;
227 sendGRQ = TRUE;
229 gatekeeper = NULL;
231 secondaryConnectionsActive.DisallowDeleteObjects();
233 #ifdef H323_H460
234 features.AttachEndPoint(this);
235 features.LoadFeatureSet(H460_Feature::FeatureBase);
236 #endif
238 PTRACE(4, "H323\tCreated endpoint.");
242 H323EndPoint::~H323EndPoint()
244 // And shut down the gatekeeper (if there was one)
245 RemoveGatekeeper();
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);
263 break;
264 case e_GatewayOnly :
265 case e_GatewayAndMC :
266 case e_GatewayAndMCWithDataMP :
267 case e_GatewayAndMCWithAudioMP :
268 case e_GatewayAndMCWithAVMP :
269 info.IncludeOptionalField(H225_EndpointType::e_gateway);
270 break;
271 case e_GatekeeperOnly :
272 case e_GatekeeperWithDataMP :
273 case e_GatekeeperWithAudioMP :
274 case e_GatekeeperWithAVMP :
275 info.IncludeOptionalField(H225_EndpointType::e_gatekeeper);
276 break;
277 case e_MCUOnly :
278 case e_MCUWithDataMP :
279 case e_MCUWithAudioMP :
280 case e_MCUWithAVMP :
281 info.IncludeOptionalField(H225_EndpointType::e_mcu);
282 info.m_mc = TRUE;
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,
343 PINDEX simultaneous,
344 const PString & name)
346 return capabilities.AddAllCapabilities(*this, descriptorNum, simultaneous, name);
350 void H323EndPoint::AddAllUserInputCapabilities(PINDEX descriptorNum,
351 PINDEX simultaneous)
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);
376 return capabilities;
380 BOOL H323EndPoint::UseGatekeeper(const PString & address,
381 const PString & identifier,
382 const PString & localAddress)
384 if (gatekeeper != NULL) {
385 BOOL same = TRUE;
387 if (!address)
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);
396 if (same) {
397 PTRACE(3, "H323\tUsing existing gatekeeper " << *gatekeeper);
398 return TRUE;
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);
414 else
415 return LocateGatekeeper(identifier, transport);
417 else {
418 if (identifier.IsEmpty())
419 return SetGatekeeper(address, transport);
420 else
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);
470 return gk;
474 BOOL H323EndPoint::InternalRegisterGatekeeper(H323Gatekeeper * gk, BOOL discovered)
476 if (discovered) {
477 if (gk->RegistrationRequest()) {
478 gatekeeper = gk;
479 return TRUE;
482 // RRQ was rejected continue trying
483 gatekeeper = gk;
485 else // Only stop listening if the GRQ was rejected
486 delete gk;
488 return FALSE;
492 H323Gatekeeper * H323EndPoint::CreateGatekeeper(H323Transport * transport)
494 return new H323Gatekeeper(*this, transport);
498 BOOL H323EndPoint::IsRegisteredWithGatekeeper() const
500 if (gatekeeper == NULL)
501 return FALSE;
503 return gatekeeper->IsRegistered();
507 BOOL H323EndPoint::RemoveGatekeeper(int reason)
509 BOOL ok = TRUE;
511 if (gatekeeper == NULL)
512 return ok;
514 ClearAllCalls();
516 if (gatekeeper->IsRegistered()) // If we are registered send a URQ
517 ok = gatekeeper->UnregistrationRequest(reason);
519 delete gatekeeper;
520 gatekeeper = NULL;
522 return ok;
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,
572 void * userData,
573 unsigned int options,
574 OpalConnection::StringOptions * stringOptions)
576 PTRACE(3, "H323\tMaking call to: " << remoteParty);
577 return InternalMakeCall(call,
578 PString::Empty(),
579 PString::Empty(),
580 UINT_MAX,
581 remoteParty,
582 userData,
583 options,
584 stringOptions);
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
598 H323SignalPDU pdu;
599 if (!pdu.Read(*transport)) {
600 PTRACE(1, "H225\tFailed to get initial Q.931 PDU, connection not started.");
601 return TRUE;
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);
637 // Send the PDU
638 releaseComplete.Write(*transport);
640 return TRUE;
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();
652 else {
653 connection->ClearCall(H323Connection::EndedByTransportFail);
654 PTRACE(1, "H225\tSignal channel stopped on first PDU.");
657 return FALSE;
661 H323Connection * H323EndPoint::CreateConnection(OpalCall & call,
662 const PString & token,
663 void * /*userData*/,
664 OpalTransport & /*transport*/,
665 const PString & alias,
666 const H323TransportAddress & address,
667 H323SignalPDU * /*setupPDU*/,
668 unsigned options,
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,
678 void * userData)
680 // Make a new connection
681 PSafePtr<OpalConnection> otherConnection =
682 GetConnectionWithLock(oldToken, PSafeReference);
683 if (otherConnection == NULL) {
684 return FALSE;
687 OpalCall & call = otherConnection->GetCall();
689 call.RemoveMediaStreams();
691 PTRACE(3, "H323\tTransferring call to: " << remoteParty);
692 BOOL ok = InternalMakeCall(call,
693 oldToken,
694 callIdentity,
695 UINT_MAX,
696 remoteParty,
697 userData);
698 call.OnReleased(*otherConnection);
699 otherConnection->Release(OpalConnection::EndedByCallForwarded);
701 return ok;
705 BOOL H323EndPoint::InternalMakeCall(OpalCall & call,
706 const PString & existingToken,
707 #if OPAL_H450
708 const PString & callIdentity,
709 unsigned capabilityLevel,
710 #else
711 const PString & ,
712 unsigned ,
713 #endif
714 const PString & remoteParty,
715 void * userData,
716 unsigned int options,
717 OpalConnection::StringOptions * stringOptions)
719 PString alias;
720 H323TransportAddress address;
721 if (!ParsePartyName(remoteParty, alias, address)) {
722 PTRACE(2, "H323\tCould not parse \"" << remoteParty << '"');
723 return FALSE;
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);
732 else
733 transport = address.CreateTransport(*this, OpalTransportAddress::NoBinding);
735 if (transport == NULL) {
736 PTRACE(1, "H323\tInvalid transport in \"" << remoteParty << '"');
737 return FALSE;
740 inUseFlag.Wait();
742 PString newToken;
743 if (existingToken.IsEmpty()) {
744 do {
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.");
752 return FALSE;
755 inUseFlag.Signal();
757 connection->AttachSignalChannel(newToken, transport, FALSE);
759 #if OPAL_H450
760 if (!callIdentity) {
761 if (capabilityLevel == UINT_MAX)
762 connection->HandleTransferCall(existingToken, callIdentity);
763 else {
764 connection->HandleIntrudeCall(existingToken, callIdentity);
765 connection->IntrudeCall(capabilityLevel);
768 #endif
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();
776 return TRUE;
780 #if OPAL_H450
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,
811 void * userData)
813 return InternalMakeCall(*manager.CreateCall(NULL),
814 PString::Empty(),
815 PString::Empty(),
816 capabilityLevel,
817 remoteParty,
818 userData);
821 #endif
823 BOOL H323EndPoint::OnSendConnect(H323Connection & /*connection*/,
824 H323SignalPDU & /*connectPDU*/
827 return TRUE;
830 BOOL H323EndPoint::OnSendSignalSetup(H323Connection & /*connection*/,
831 H323SignalPDU & /*setupPDU*/)
833 return TRUE;
836 BOOL H323EndPoint::OnSendCallProceeding(H323Connection & /*connection*/,
837 H323SignalPDU & /*callProceedingPDU*/)
839 return TRUE;
842 void H323EndPoint::OnReceivedInitiateReturnError()
846 BOOL H323EndPoint::ParsePartyName(const PString & _remoteParty,
847 PString & alias,
848 H323TransportAddress & address)
850 PString remoteParty = _remoteParty;
852 #if P_DNS
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:")
859 e164 = e164.Mid(4);
860 PINDEX i;
861 for (i = 0; i < e164.GetLength(); ++i)
862 if (!isdigit(e164[i]) && (i != 0 || e164[0] != '+'))
863 break;
864 if (i >= e164.GetLength()) {
865 PString str;
866 if (PDNS::ENUMLookup(e164, "E2U+h323", str)) {
867 PTRACE(4, "H323\tENUM converted remote party " << _remoteParty << " to " << str);
868 remoteParty = str;
870 else
871 return FALSE;
874 #endif
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);
883 else
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 << '"');
895 return FALSE;
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") {
906 #if P_LDAP
907 PString server = url.GetHostName();
908 if (server.IsEmpty())
909 server = GetDefaultILSServer();
910 if (server.IsEmpty())
911 return FALSE;
913 PILSSession ils;
914 if (!ils.Open(server, url.GetPort())) {
915 PTRACE(1, "H323\tCould not open ILS server at \"" << server
916 << "\" - " << ils.GetErrorText());
917 return FALSE;
920 PILSSession::RTPerson person;
921 if (!ils.SearchPerson(alias, person)) {
922 PTRACE(1, "H323\tCould not find "
923 << server << '/' << alias << ": " << ils.GetErrorText());
924 return FALSE;
927 if (!person.sipAddress.IsValid()) {
928 PTRACE(1, "H323\tILS user " << server << '/' << alias
929 << " does not have a valid IP address");
930 return FALSE;
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]);
940 break;
944 alias = PString::Empty(); // No alias for ILS lookup, only host
945 return TRUE;
946 #else
947 return FALSE;
948 #endif
951 if (url.GetParamVars().Contains("gateway"))
952 gatewaySpecified = TRUE;
954 else if (url.GetScheme() == "h323") {
955 if (type == "gw")
956 gatewaySpecified = TRUE;
957 else if (type == "gk")
958 gatekeeperSpecified = TRUE;
959 else if (!type) {
960 PTRACE(1, "H323\tUnsupported host type \"" << type << "\" in h323 URL");
961 return FALSE;
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!");
969 return FALSE;
972 if (address.IsEmpty()) {
973 PTRACE(1, "H323\tAttempt to use explict gatekeeper without address!");
974 return FALSE;
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);
983 if (ok) {
984 ok = gk->LocationRequest(alias, address);
985 if (ok) {
986 PTRACE(3, "H323\tLocation Request of \"" << alias << "\" on gk " << gkAddr << " found " << address);
988 else {
989 PTRACE(1, "H323\tLocation Request failed for \"" << alias << "\" on gk " << gkAddr);
992 else {
993 PTRACE(1, "H323\tLocation Request discovery failed for gk " << gkAddr);
996 delete gk;
998 return ok;
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();
1009 return TRUE;
1012 // We have a gatekeeper and user provided a host, all done
1013 if (!address)
1014 return TRUE;
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);
1026 if (ip.IsValid()) {
1027 alias = PString::Empty();
1028 address = H323TransportAddress(ip, port);
1032 return TRUE;
1036 PSafePtr<H323Connection> H323EndPoint::FindConnectionWithLock(const PString & token, PSafetyMode mode)
1038 PSafePtr<H323Connection> connnection = PSafePtrCast<OpalConnection, H323Connection>(GetConnectionWithLock(token, mode));
1039 if (connnection != NULL)
1040 return connnection;
1042 for (connnection = PSafePtrCast<OpalConnection, H323Connection>(connectionsActive.GetAt(0)); connnection != NULL; ++connnection) {
1043 if (connnection->GetCallIdentifier().AsString() == token)
1044 return connnection;
1045 if (connnection->GetConferenceIdentifier().AsString() == token)
1046 return connnection;
1049 return NULL;
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*/)
1064 return TRUE;
1068 BOOL H323EndPoint::OnCallTransferIdentify(H323Connection & /*connection*/)
1070 return TRUE;
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();
1103 return TRUE;
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);
1113 return TRUE;
1116 BOOL H323EndPoint::OnSentAlerting(H323Connection & PTRACE_PARAM(connection))
1118 PTRACE(3, "H225\tOnSentAlerting conn = " << connection);
1119 return TRUE;
1122 BOOL H323EndPoint::OnConnectionForwarded(H323Connection & /*connection*/,
1123 const PString & /*forwardParty*/,
1124 const H323SignalPDU & /*pdu*/)
1126 return FALSE;
1130 BOOL H323EndPoint::ForwardConnection(H323Connection & connection,
1131 const PString & forwardParty,
1132 const H323SignalPDU & /*pdu*/)
1134 if (!InternalMakeCall(connection.GetCall(),
1135 connection.GetCallToken(),
1136 PString::Empty(),
1137 UINT_MAX,
1138 forwardParty,
1139 NULL))
1140 return FALSE;
1142 connection.SetCallEndReason(H323Connection::EndedByCallForwarded);
1144 return TRUE;
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.");
1165 return TRUE;
1169 void H323EndPoint::OnConnectionCleared(H323Connection & /*connection*/,
1170 const PString & /*token*/)
1175 #if PTRACING
1176 static void OnStartStopChannel(const char * startstop, const H323Channel & channel)
1178 const char * dir;
1179 switch (channel.GetDirection()) {
1180 case H323Channel::IsTransmitter :
1181 dir = "send";
1182 break;
1184 case H323Channel::IsReceiver :
1185 dir = "receiv";
1186 break;
1188 default :
1189 dir = "us";
1190 break;
1193 PTRACE(3, "H323\t" << startstop << "ed "
1194 << dir << "ing logical channel: "
1195 << channel.GetCapability());
1197 #endif
1200 BOOL H323EndPoint::OnStartLogicalChannel(H323Connection & /*connection*/,
1201 H323Channel & PTRACE_PARAM(channel))
1203 #if PTRACING
1204 OnStartStopChannel("Start", channel);
1205 #endif
1206 return TRUE;
1210 void H323EndPoint::OnClosedLogicalChannel(H323Connection & /*connection*/,
1211 const H323Channel & PTRACE_PARAM(channel))
1213 #if PTRACING
1214 OnStartStopChannel("Stopp", channel);
1215 #endif
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,
1245 unsigned sessionId,
1246 const H323ServiceControlSession & session,
1247 H323Connection * connection)
1249 session.OnChange(type, sessionId, *this, connection);
1252 BOOL H323EndPoint::OnConferenceInvite(const H323SignalPDU & /*setupPDU */)
1254 return FALSE;
1257 BOOL H323EndPoint::OnCallIndependentSupplementaryService(const H323SignalPDU & /* setupPDU */)
1259 return FALSE;
1262 BOOL H323EndPoint::OnNegotiateConferenceCapabilities(const H323SignalPDU & /* setupPDU */)
1264 return FALSE;
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);
1277 return NULL;
1281 void H323EndPoint::SetLocalUserName(const PString & name)
1283 PAssert(!name, "Must have non-empty string in AliasAddress!");
1284 if (name.IsEmpty())
1285 return;
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)
1297 return FALSE;
1299 localAliasNames.AppendString(name);
1300 return TRUE;
1304 BOOL H323EndPoint::RemoveAliasName(const PString & name)
1306 PINDEX pos = localAliasNames.GetValuesIndex(name);
1307 if (pos == P_MAX_INDEX)
1308 return FALSE;
1310 PAssert(localAliasNames.GetSize() > 1, "Must have at least one AliasAddress!");
1311 if (localAliasNames.GetSize() < 2)
1312 return FALSE;
1314 localAliasNames.RemoveAt(pos);
1315 return TRUE;
1319 BOOL H323EndPoint::IsTerminal() const
1321 switch (terminalType) {
1322 case e_TerminalOnly :
1323 case e_TerminalAndMC :
1324 return TRUE;
1326 default :
1327 return FALSE;
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 :
1340 return TRUE;
1342 default :
1343 return FALSE;
1348 BOOL H323EndPoint::IsGatekeeper() const
1350 switch (terminalType) {
1351 case e_GatekeeperOnly :
1352 case e_GatekeeperWithDataMP :
1353 case e_GatekeeperWithAudioMP :
1354 case e_GatekeeperWithAVMP :
1355 return TRUE;
1357 default :
1358 return FALSE;
1363 BOOL H323EndPoint::IsMCU() const
1365 switch (terminalType) {
1366 case e_MCUOnly :
1367 case e_MCUWithDataMP :
1368 case e_MCUWithAudioMP :
1369 case e_MCUWithAVMP :
1370 return TRUE;
1372 default :
1373 return FALSE;
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*/)
1386 return FALSE;
1389 void H323EndPoint::OnReceiveFeatureSet(unsigned, const H225_FeatureSet & /*features*/)
1393 /////////////////////////////////////////////////////////////////////////////