Utilise new MergeSym feature to no longer overwrite the source .DEF file when buildin...
[openh323.git] / src / opalosp.cxx
blobdd052c1b6eb979650b1b6e94567c28b6074d4ee1
1 /*
2 * opalosp.cxx
4 * OSP protocol handler
6 * OpenH323 Library
8 * Copyright (C) 2004 Post Increment
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 Post Increment
24 * This code was written with assistance from TransNexus, Inc.
25 * http://www.transnexus.com
27 * Contributor(s): ______________________________________.
29 * $Log$
30 * Revision 1.24 2006/06/09 07:15:34 csoutheren
31 * Fixed warning when using old OSP toolkit
33 * Revision 1.23 2006/03/26 23:49:20 csoutheren
34 * Added extra logging for OSP release codes
36 * Revision 1.22 2006/03/09 23:43:23 csoutheren
37 * Change OSP call duration
39 * Revision 1.21 2006/02/27 07:04:18 csoutheren
40 * Ensure call ID allocated by the OSP toolkit is freed by the toolkit
42 * Revision 1.20 2006/02/24 04:53:01 csoutheren
43 * Fixed problem with incorrect flag in OSP population
45 * Revision 1.19 2006/02/21 23:50:21 csoutheren
46 * Remove requirement for destination call signaling address in SETUP for OSP validation
48 * Revision 1.18 2006/02/09 03:17:01 csoutheren
49 * Use OSP toolkit routines for allocating call IDs rather than automatic variables
51 * Revision 1.17 2006/01/30 06:11:04 csoutheren
52 * Added extra logging for OSP report usage call
54 * Revision 1.16 2005/12/20 02:08:02 csoutheren
55 * Look for called and calling number information in Q.931 header for OSP validation
57 * Revision 1.15 2005/12/08 06:31:13 csoutheren
58 * Look for called number information in Q.931 header
60 * Revision 1.14 2005/12/02 00:07:12 csoutheren
61 * Look for calling number information in Q.931 header
63 * Revision 1.13 2005/09/16 08:08:36 csoutheren
64 * Split ReportUsage from CallEnd function
66 * Revision 1.12 2005/08/30 08:30:14 csoutheren
67 * Added support for setting connection count on OSP server
69 * Revision 1.11 2005/08/30 01:12:38 csoutheren
70 * Added automatic detection of OSP toolkit version on Unix
72 * Revision 1.10 2005/08/27 02:11:58 csoutheren
73 * Added support for different pthread library required by new OSP toolkit on Windows
74 * Added support for new parameters to GetFirst and GetNext
75 * Fixed incorrect usage of destination address and destination device
77 * Revision 1.9 2005/08/15 01:58:13 csoutheren
78 * Adde support for version 3.3.2 of the OSP Toolkit
80 * Revision 1.8 2005/07/25 01:23:28 csoutheren
81 * Added ability to select token algorithm when validating OSP tokens
83 * Revision 1.7 2005/01/03 14:03:42 csoutheren
84 * Added new configure options and ability to disable/enable modules
86 * Revision 1.6 2004/12/20 02:32:36 csoutheren
87 * Cleeaned up OSP functions
89 * Revision 1.5 2004/12/16 00:34:36 csoutheren
90 * Fixed reporting of call end time and code
91 * Added GetNextDestination
93 * Revision 1.4 2004/12/14 06:22:22 csoutheren
94 * More OSP implementation
96 * Revision 1.3 2004/12/09 23:38:41 csoutheren
97 * More OSP implementation
99 * Revision 1.2 2004/12/08 05:16:14 csoutheren
100 * Fixed OSP compilation on Linux
102 * Revision 1.1 2004/12/08 01:59:23 csoutheren
103 * initial support for Transnexus OSP toolkit
107 #ifdef __GNUC__
108 #pragma implementation "opalosp.h"
109 #endif
111 #include <ptlib.h>
112 #include <ptlib/sockets.h>
113 #include <ptclib/url.h>
115 #include <h323.h>
116 #include "opalosp.h"
117 #include <h225.h>
118 #include <h323pdu.h>
119 #include <h323ep.h>
121 #ifdef H323_TRANSNEXUS_OSP
124 // Windows has no way to determine which version of the OSP API is being used,
125 // while Unix systems will use a configure test.
126 // On Windows, set the default to the most recent version. This will need manual
127 // configuration if older versions of the toolkit are used
129 #ifdef _MSC_VER
130 #define H323_NEW_OSP_API 1
132 #pragma comment(lib, H323_TRANSNEXUS_OSP_DIR_LIBRARY1)
134 #ifdef H323_NEW_OSP_API
135 #pragma comment(lib, H323_TRANSNEXUS_OSP_DIR_LIBRARY2b)
136 #else
137 #pragma comment(lib, H323_TRANSNEXUS_OSP_DIR_LIBRARY2a)
138 #endif
139 #endif
141 #define DEFAULT_SSL_LIFETIME 3600 // SSL lifetime
142 #define DEFAULT_MAX_SIMULT_CONN 32 // maximum simultaneous connections
143 #define DEFAULT_HTTP_PERSIST 60 // HTTP persistence of 1 minute
144 #define DEFAULT_HTTP_RETRY_DELAY 600 // HTTP retry delay of 10 minutes
145 #define DEFAULT_HTTP_RETRY 3 // HTTP retry count of 3
146 #define DEFAULT_HTTP_TIMEOUT 10000 // HTTP timeout of 10 secs
147 #define DEFAULT_DELETE_TIMEOUT 4 // delete timeout
149 #define CALLID_SIZE 20 // size of call ID
150 #define CALLED_NUMBER_SIZE 100 // size of storage for called number
151 #define CALLING_NUMBER_SIZE 100 // size of storage for calling number
152 #define DESTINATION_SIZE 100 // size of storage for destination
153 #define DEVICE_SIZE 100 // size of storage for device
154 #define TOKEN_SIZE 16384 // size of OSP token
156 ////////////////////////////////////////////////////////////////////////////////////////////////////////
158 class OSPShutDown : public PProcessStartup
160 PCLASSINFO(OSPShutDown, PProcessStartup);
161 public:
162 void OnShutdown()
163 { OpalOSP::Initialise(FALSE); }
166 PFactory<PProcessStartup>::Worker<OSPShutDown> ospPluginLoaderStartupFactory("OSPShutDown", true);
168 void OpalOSP::Initialise(BOOL shutdown)
170 static BOOL initialised = FALSE;
172 if (!initialised && !shutdown) {
173 ::OSPPInit(FALSE);
174 initialised = TRUE;
176 else if (initialised && shutdown) {
177 ::OSPPCleanup();
181 PString OpalOSP::TransportAddressToOSPString(const H323TransportAddress & taddr)
183 PIPSocket::Address addr;
184 WORD port;
185 taddr.GetIpAndPort(addr, port);
186 return IpAddressPortToOSPString(addr, port);
189 PString OpalOSP::AddressToOSPString(const PString & str)
191 int b1, b2, b3, b4, port;
192 if (sscanf((const char *)str, "%d.%d.%d.%d:%d", &b1, &b2, &b3, &b4, &port) == 5)
193 return psprintf("[%d.%d.%d.%d]:%d", b1, b2, b3, b4, port);
194 else if (sscanf((const char *)str, "%d.%d.%d.%d", &b1, &b2, &b3, &b4) == 4)
195 return psprintf("[%d.%d.%d.%d]", b1, b2, b3, b4);
196 else
197 return str;
200 H323TransportAddress OpalOSP::OSPStringToAddress(const PString & str, WORD defaultPort)
202 int b1, b2, b3, b4, port;
203 if (sscanf((const char *)str, "[%d.%d.%d.%d]:%d", &b1, &b2, &b3, &b4, &port) == 5)
204 return H323TransportAddress(PIPSocket::Address((BYTE)b1, (BYTE)b2, (BYTE)b3, (BYTE)b4), (WORD)port);
205 else if (sscanf((const char *)str, "[%d.%d.%d.%d]", &b1, &b2, &b3, &b4) == 4)
206 return H323TransportAddress(PIPSocket::Address((BYTE)b1, (BYTE)b2, (BYTE)b3, (BYTE)b4), defaultPort);
207 else
208 return H323TransportAddress(str);;
211 BOOL OpalOSP::ConvertAliasToOSPString(const H225_AliasAddress & alias, int & format, PString & str)
213 str = H323GetAliasAddressString(alias);
214 switch (alias.GetTag()) {
215 case H225_AliasAddress::e_dialedDigits:
216 format = ::OSPC_E164;
217 return TRUE;
218 break;
220 case H225_AliasAddress::e_url_ID:
221 format = ::OSPC_URL;
222 return TRUE;
223 break;
225 case H225_AliasAddress::e_email_ID:
226 case H225_AliasAddress::e_h323_ID:
227 case H225_AliasAddress::e_transportID:
228 case H225_AliasAddress::e_partyNumber:
229 case H225_AliasAddress::e_mobileUIM:
230 break;
232 return FALSE;
235 ////////////////////////////////////////////////////////////////////////////////////////////////////////
237 // provider functions
240 OpalOSP::Provider::Provider()
242 Initialise();
244 handle = IllegalHandle;
246 sslLifeTime = DEFAULT_SSL_LIFETIME;
247 maxSimultConn = DEFAULT_MAX_SIMULT_CONN;
248 httpPersist = DEFAULT_HTTP_PERSIST;
249 httpRetryDelay = DEFAULT_HTTP_RETRY_DELAY;
250 httpRetry = DEFAULT_HTTP_RETRY;
251 httpTimeout = DEFAULT_HTTP_TIMEOUT;
252 deleteTimeout = DEFAULT_DELETE_TIMEOUT;
253 messageCount = 0;
256 OpalOSP::Provider::~Provider()
258 Close();
261 int OpalOSP::Provider::Open(const PString & servicePoint, const PDirectory & certDir)
263 PURL url(servicePoint, "http");
264 PString hostName = url.GetHostName();
265 if (!PIPSocket::GetHostAddress(hostName, hostAddress)) {
266 PTRACE(2, "OSP\tCannot resolve address of OSP server " << hostName);
267 return -1;
270 PFilePath privateKeyFilename = certDir + (hostName + "_priv.pem");
271 PFilePath publicKeyFilename = certDir + (hostName + "_cert.pem");
272 PFilePath serverCAFilename = certDir + (hostName + "_cacert.pem");
274 return Open(servicePoint, privateKeyFilename, publicKeyFilename, serverCAFilename);
277 int OpalOSP::Provider::Open(const PString & servicePoint,
278 const PFilePath & localPrivateKeyName,
279 const PFilePath & localPublicCertName,
280 const PFilePath & localAuthCertName)
282 PSSLPrivateKey privateKey;
283 if (!privateKey.Load(localPrivateKeyName)) {
284 PTRACE(2, "OSP\tCannot load public cert " << localPrivateKeyName);
285 return -1;
288 PSSLCertificate publicCert;
289 if (!publicCert.Load(localPublicCertName)) {
290 PTRACE(2, "OSP\tCannot load public cert " << localPublicCertName);
291 return -1;
294 PSSLCertificate authCert;
295 if (!authCert.Load(localAuthCertName)) {
296 PTRACE(2, "OSP\tCannot load auth cert " << localAuthCertName);
297 return -1;
300 return Open(servicePoint, privateKey, publicCert, authCert);
303 int OpalOSP::Provider::Open(const PString & servicePoint,
304 PSSLPrivateKey & localPrivateKey,
305 PSSLCertificate & localPublicCert,
306 PSSLCertificate & localAuthCert)
308 const char * ospvServicePoint = (const char *)servicePoint;
310 OSPTPRIVATEKEY localKey;
311 PBYTEArray localKeyData = localPrivateKey.GetData();
312 localKey.PrivateKeyData = localKeyData.GetPointer();
313 localKey.PrivateKeyLength = localKeyData.GetSize();
315 OSPTCERT localCert;
316 PBYTEArray localCertData = localPublicCert.GetData();
317 localCert.CertData = localCertData.GetPointer();
318 localCert.CertDataLength = localCertData.GetSize();
320 OSPTCERT authCert;
321 PBYTEArray authCertData = localAuthCert.GetData();
322 authCert.CertData = authCertData.GetPointer();
323 authCert.CertDataLength = authCertData.GetSize();
324 const OSPTCERT * authCerts = &authCert;
326 unsigned long * ospvMessageCount = NULL;
327 if (messageCount > 0) {
328 ospvMessageCount = new unsigned long[1];
329 *ospvMessageCount = messageCount;
332 // create the provider handle
333 int stat = ::OSPPProviderNew(
334 1, // number of service points
335 &ospvServicePoint, // service point data
336 ospvMessageCount, // max mesages per service point
337 "", // audit URL
338 &localKey, // private key
339 &localCert, // public cert
340 1, // number of public certs
341 &authCerts, // public cert
342 0, // use local validation
343 sslLifeTime, // SSL lifetime of one hour
344 maxSimultConn, // maximum simultaneous connections
345 httpPersist, // HTTP persistence of 1 minute
346 httpRetryDelay, // HTTP retry delay of 10 minutes
347 httpRetry, // HTTP retry count of 3
348 httpTimeout, // HTTP timeout of 3.5 secs
349 (const char *)customerID, // customer ID
350 (const char *)deviceID, // device ID
351 &handle);
353 delete[](ospvMessageCount);
355 PTRACE_IF(1, stat != 0, "OSP\tOSPPProviderNew returned status " << stat);
357 if (stat != 0)
358 handle = IllegalHandle;
359 else
360 PTRACE(2, "OSP\tOSPPProviderNew succeeded ");
362 return stat;
365 int OpalOSP::Provider::Close()
367 int stat = 0;
369 if (IsOpen()) {
370 stat = ::OSPPProviderDelete(handle, deleteTimeout);
371 PTRACE(2, "OSP\tOSPPProviderDelete returned status " << stat);
372 handle = IllegalHandle;
375 return stat;
379 ////////////////////////////////////////////////////////////////////////////////////////////////////////
381 // transaction functions
384 OpalOSP::Transaction::Transaction()
385 : provider(NULL)
387 handle = IllegalHandle;
388 // endReason = H323Connection::NumCallEndReasons;
391 OpalOSP::Transaction::~Transaction()
393 Close();
396 BOOL OpalOSP::Transaction::CheckOpenedAndNotEnded(const char * str)
398 if (!IsOpen()) {
399 PTRACE(1, "OSP\tAttempt to " << str << " unopened transaction");
400 return FALSE;
402 if (ended) {
403 PTRACE(1, "OSP\tAttempt to " << str << " ended transaction");
404 return FALSE;
406 return TRUE;
410 int OpalOSP::Transaction::Open(Provider & _provider, const PString & _user)
412 // make sure the transaction is not already open
413 if (IsOpen()) {
414 PTRACE(1, "OSP\tAttempt to open transaction that is already open");
415 return -1;
418 // make sure the provider is open
419 if (!_provider.IsOpen())
420 return -1;
421 provider = &_provider;
423 // reset the call information
424 user = _user;
425 ended = FALSE;
426 lostSentPackets = lostReceivedPackets = 0;
427 lostFractionSent = lostFractionReceived = -1;
429 // create the transaction
430 int stat = ::OSPPTransactionNew(*provider, &handle);
432 if (stat != 0) {
433 handle = IllegalHandle;
436 return stat;
439 void OpalOSP::Transaction::CallStatistics(unsigned _lostSentPackets,
440 signed _lostFractionSent,
441 unsigned _lostReceivedPackets,
442 signed _lostFractionReceived,
443 const PTime & _firstRTPTime)
445 if (CheckOpenedAndNotEnded("set call statistics")) {
446 lostSentPackets = _lostSentPackets;
447 lostFractionSent = _lostFractionSent;
448 lostReceivedPackets = _lostReceivedPackets;
449 lostFractionReceived = _lostFractionReceived;
450 firstRTPTime = _firstRTPTime;
454 static OSPTTIME ValidateOSPTime(const PTime & time)
456 if (time.IsValid())
457 return (OSPTTIME)time.GetTimeInSeconds();
459 return 0;
462 void OpalOSP::Transaction::CallEnd(H323Connection & conn)
464 if (!CheckOpenedAndNotEnded("end"))
465 return;
467 int result;
469 // convert end reason to the correct code
470 // note that OSP codes are Q.931 codes, except for the UnknownCauseIE and normal call clearing
471 H323Connection::CallEndReason endReason= conn.GetCallEndReason();
472 if (endReason != H323Connection::NumCallEndReasons) {
473 H225_ReleaseCompleteReason h225Reason;
474 int ospReason = (int)H323TranslateFromCallEndReason((H323Connection::CallEndReason)endReason, h225Reason);
475 if (ospReason == Q931::NormalCallClearing)
476 ospReason = OSPC_FAIL_NORMAL_CALL_CLEARING;
477 else if (ospReason == Q931::UnknownCauseIE)
478 ospReason = OSPC_FAIL_GENERAL;
479 if (ospReason != OSPC_FAIL_NORMAL_CALL_CLEARING) {
480 PTRACE(4, "OSP\tH323 call end reason " << endReason << " converted to OSP/Q.931 release code " << ospReason);
481 result = ::OSPPTransactionRecordFailure(*this, (OSPEFAILREASON)ospReason);
482 PTRACE_IF(1, result != 0, "OSP\tSetting result code failed");
486 ReportUsage(conn);
489 void OpalOSP::Transaction::ReportUsage(H323Connection & conn)
491 if (!CheckOpenedAndNotEnded("end")) {
492 PTRACE(4, "OSP\tReportUsage skipped as transaction not opened or already reported");
493 return;
496 // calculate duration of the call, in seconds
497 unsigned ospvCallDuration = 0;
498 if (conn.GetConnectionStartTime().IsValid())
499 ospvCallDuration = ((unsigned)(PTime() - conn.GetConnectionStartTime()).GetMilliSeconds() + 500) / 1000 ;
501 #ifdef H323_NEW_OSP_API
503 // get start time of call, in 1970 epoch
504 OSPTTIME ospvStartTime = ValidateOSPTime(conn.GetSetupUpTime());
506 // get end time of call, in 1970 epoch
507 OSPTTIME ospvEndTime = ValidateOSPTime(conn.GetConnectionEndTime());
509 // get alerting time of call, in 1970 epoch
510 OSPTTIME ospvAlertTime = ValidateOSPTime(conn.GetAlertingTime());
512 // get flag indicating whether local endpoint released the call
513 BOOL localRelease = conn.GetReleaseSequence() == H323Connection::ReleaseSequence_Local;
515 // get flag for whether originator released the call
516 int ospvReleaseSource = (conn.HadAnsweredCall() ? !localRelease : localRelease) ? 0 : 1;
518 #endif
520 // get connection time of call, in 1970 epoch
521 OSPTTIME ospvConnectionTime = ValidateOSPTime(conn.GetConnectionStartTime());
523 // get post dial delay time (time from SETUP to media)
524 #ifdef H323_NEW_OSP_API
525 unsigned ospvPostDialDelay = conn.GetReverseMediaOpenTime().IsValid() ? (((unsigned)(conn.GetReverseMediaOpenTime() - conn.GetSetupUpTime()).GetMilliSeconds() + 500) / 1000) : 0;
526 #endif
528 ended = TRUE;
530 int result = ::OSPPTransactionReportUsage(
531 *this, /* In - Transaction handle */
532 ospvCallDuration, /* In - Length of call */
533 #ifdef H323_NEW_OSP_API
534 ospvStartTime, /* In - Call start time */
535 ospvEndTime, /* In - Call end time */
536 ospvAlertTime, /* In - Call alert time */
537 #endif
538 ospvConnectionTime, /* In - Call connect time */
539 #ifdef H323_NEW_OSP_API
540 ospvPostDialDelay > 0, /* In - Is PDD Info present */
541 ospvPostDialDelay, /* In - Post Dial Delay */
542 ospvReleaseSource, /* In - EP that released the call */
543 (unsigned char *)"", /* In - conference Id. Max 100 char long */
544 #endif
545 lostSentPackets, /* In - Packets not received by peer */
546 lostFractionSent, /* In - Fraction of packets not received by peer */
547 lostReceivedPackets, /* In - Packets not received that were expected */
548 lostFractionReceived, /* In - Fraction of packets expected but not received */
549 0, /* In/Out - Max size of detail log \ Actual size of detail log */
550 NULL /* Out - Pointer to detail log storage */
553 PTRACE_IF(2, result != 0, "OSP\tOSPPTransactionReportUsage returned status " << result);
554 PTRACE_IF(4, result == 0, "OSP\tOSPPTransactionReportUsage call with duration " << ospvCallDuration);
557 int OpalOSP::Transaction::Close()
559 int stat = 0;
560 if (IsOpen()) {
562 // make sure the transaction is ended
563 //if (!ended)
564 // CallEnd();
566 // close the transaction
567 stat = ::OSPPTransactionDelete(handle);
568 PTRACE_IF(2, stat != 0, "OSP\tOSPPTransactionDelete returned status " << stat);
569 handle = IllegalHandle;
572 return stat;
575 ////////////////////////////////////////////////////////////////////////////////////
577 // transaction authorisation functions
579 int OpalOSP::Transaction::Authorise(AuthorisationInfo & info, unsigned & numberOfDestinations)
581 return Authorise(
582 info.ospvSource,
583 info.ospvSourceDevice,
584 info.callingNumber,
585 info.calledNumber,
586 info.callID,
587 numberOfDestinations
592 int OpalOSP::Transaction::Authorise(const PString & ospvSource,
593 const PString & ospvSourceDevice,
594 const H225_AliasAddress & callingNumber,
595 const H225_AliasAddress & calledNumber,
596 const PBYTEArray & callID,
597 unsigned & numberOfDestinations)
599 int ospvCallingNumberFormat;
600 PString ospvCallingNumber;
601 if (!ConvertAliasToOSPString(callingNumber, ospvCallingNumberFormat, ospvCallingNumber)) {
602 PTRACE(1, "OSP\tUnknown alias address type for calling number " << callingNumber);
603 return -1;;
606 PString ospvCalledNumber;
607 int ospvCalledNumberFormat;
608 if (!ConvertAliasToOSPString(calledNumber, ospvCalledNumberFormat, ospvCalledNumber)) {
609 PTRACE(1, "OSP\tUnknown alias address type for called number " << callingNumber);
610 return -1;;
613 return Authorise(ospvSource,
614 ospvSourceDevice,
615 ospvCallingNumber,
616 ospvCallingNumberFormat,
617 ospvCalledNumber,
618 ospvCalledNumberFormat,
619 callID,
620 numberOfDestinations);
623 int OpalOSP::Transaction::Authorise(const PString & ospvSource,
624 const PString & _ospvSourceDevice,
625 const PString & ospvCallingNumber,
626 int ospvCallingNumberFormat,
627 const PString & ospvCalledNumber,
628 int ospvCalledNumberFormat,
629 const PBYTEArray & callID,
630 unsigned & numberOfDestinations)
632 // make sure the provider is open
633 if (!provider->IsOpen())
634 return -1;
636 // make sure the transaction is open
637 if (!IsOpen()) {
638 return -1 ;
641 PString ospvSourceDevice = _ospvSourceDevice;
642 if (ospvSourceDevice.IsEmpty())
643 ospvSourceDevice = ospvSource;
645 ::OSPTCALLID * ospvCallID = OSPPCallIdNew(callID.GetSize(), (const BYTE *)callID);
647 unsigned logSize = 0;
649 PTRACE(4, "OSP\tMaking OSP Authorise request: src=" << ospvSource << ",srcDev=" << ospvSourceDevice << ",callingDn=" << ospvCallingNumber << ",calledDn=" << ospvCalledNumber);
651 // perform the authorisation
652 int stat = ::OSPPTransactionRequestAuthorisation(
653 *this,
654 (const char *)ospvSource, // source
655 (const char *)ospvSourceDevice, // source device
656 (const char *)ospvCallingNumber, // calling number
657 (OSPE_NUMBERING_FORMAT)ospvCallingNumberFormat, // calling number format
658 (const char *)ospvCalledNumber, // called number
659 (OSPE_NUMBERING_FORMAT)ospvCalledNumberFormat, // called number format
660 user.IsEmpty() ? "" : (const char *)user, // user identifier
661 1, // number of call IDs
662 &ospvCallID, // call ID
663 NULL, // preferred destinations,
664 &numberOfDestinations, // number of destinations,
665 &logSize, // detail log size,
666 NULL // detail log
669 ::OSPPCallIdDelete(&ospvCallID);
671 PTRACE_IF(1, stat != 0, "OSP\tOSPPTransactionRequestAuthorisation returned " << stat);
673 return stat;
676 static BOOL ValidateAddress(const H225_ArrayOf_AliasAddress & addresses, H225_AliasAddress & alias)
678 PINDEX i;
679 for (i = 0; i < addresses.GetSize(); ++i) {
680 int fmt;
681 PString str;
682 if (OpalOSP::ConvertAliasToOSPString(addresses[i], fmt, str)) {
683 alias = addresses[i];
684 return TRUE;
687 return FALSE;
691 BOOL OpalOSP::Transaction::AuthorisationInfo::Extract(const H323SignalPDU & setupPDU)
693 if (setupPDU.m_h323_uu_pdu.m_h323_message_body.GetTag() != H225_H323_UU_PDU_h323_message_body::e_setup)
694 return FALSE;
696 const H225_Setup_UUIE & setup = setupPDU.m_h323_uu_pdu.m_h323_message_body;
698 // must have a source call signalling address
699 if (!setup.HasOptionalField(H225_Setup_UUIE::e_sourceCallSignalAddress))
700 return FALSE;
701 ospvSourceDevice = ospvSource = TransportAddressToOSPString(setup.m_sourceCallSignalAddress);
703 // must have one or more source addresses
704 // Use the Q.931 calling party number otherwise find a H.323 alias
705 // that is a valid OSP target
706 PString str;
707 if (setupPDU.GetQ931().GetCallingPartyNumber(str))
708 H323SetAliasAddress(str, callingNumber, H225_AliasAddress::e_dialedDigits);
709 else if (!setup.HasOptionalField(H225_Setup_UUIE::e_sourceAddress) ||
710 !ValidateAddress(setup.m_sourceAddress, callingNumber))
711 return FALSE;
713 // must have one or more destination addresses
714 // Use the Q.931 called party number otherwise find a H.323 destination alias
715 // that is a valid OSP target
716 if (setupPDU.GetQ931().GetCalledPartyNumber(str))
717 H323SetAliasAddress(str, calledNumber, H225_AliasAddress::e_dialedDigits);
718 else if (!setup.HasOptionalField(H225_Setup_UUIE::e_destinationAddress) ||
719 !ValidateAddress(setup.m_destinationAddress, calledNumber))
720 return FALSE;
722 // get the call identifier (make sure it has non-zero length)
723 if (setup.m_callIdentifier.m_guid.GetSize() == 0)
724 return FALSE;
725 callID = setup.m_callIdentifier.m_guid;
727 return TRUE;
730 BOOL OpalOSP::Transaction::AuthorisationInfo::Extract(const H225_AdmissionRequest & arq)
732 // must have a source call signalling address
733 if (!arq.HasOptionalField(H225_AdmissionRequest::e_srcCallSignalAddress))
734 return FALSE;
735 ospvSourceDevice = ospvSource = TransportAddressToOSPString(arq.m_srcCallSignalAddress);
737 // must have one or more source addresses
738 // pick the first one that is a valid OSP target
739 if (!ValidateAddress(arq.m_srcInfo, callingNumber))
740 return FALSE;
742 // must have one or more destination addresses
743 // pick the first one that is a valid OSP target
744 if (!arq.HasOptionalField(H225_AdmissionRequest::e_destinationInfo) ||
745 !ValidateAddress(arq.m_destinationInfo, calledNumber))
746 return FALSE;
748 // get the call identifier (make sure it has non-zero length)
749 if (arq.m_callIdentifier.m_guid.GetSize() == 0)
750 return FALSE;
751 callID = arq.m_callIdentifier.m_guid;
753 return TRUE;
757 ////////////////////////////////////////////////////////////////////////////////////
759 // transaction validation functions
762 int OpalOSP::Transaction::Validate(const ValidationInfo & info, BOOL & authorised, unsigned & timeLimit)
764 return Validate(
765 info.ospvSource,
766 info.ospvDest,
767 info.ospvSourceDevice,
768 info.ospvDestDevice,
769 info.callingNumber,
770 info.calledNumber,
771 info.callID,
772 info.token,
773 info.tokenAlgo,
774 authorised,
775 timeLimit
779 int OpalOSP::Transaction::Validate(
780 const PString & ospvSource,
781 const PString & ospvDest,
782 const PString & ospvSourceDevice,
783 const PString & ospvDestDevice,
784 const H225_AliasAddress & callingNumber,
785 const H225_AliasAddress & calledNumber,
786 const PBYTEArray & callID,
787 const PBYTEArray & token,
788 unsigned int tokenAlgo,
789 BOOL & authorised,
790 unsigned & timeLimit
793 PString calling;
794 int callingFormat;
795 ConvertAliasToOSPString(callingNumber, callingFormat, calling);
797 PString called;
798 int calledFormat;
799 ConvertAliasToOSPString(calledNumber, calledFormat, called);
801 return Validate(ospvSource, ospvDest, ospvSourceDevice, ospvDestDevice,
802 callingFormat, calling,
803 calledFormat, called,
804 callID, token, tokenAlgo, authorised, timeLimit);
807 int OpalOSP::Transaction::Validate(
808 const PString & ospvSource,
809 const PString & ospvDest,
810 const PString & ospvSourceDevice,
811 const PString & ospvDestDevice,
812 int ospvCallingNumberFormat,
813 const PString & ospvCallingNumber,
814 int ospvCalledNumberFormat,
815 const PString & ospvCalledNumber,
816 const PBYTEArray & callID,
817 const PBYTEArray & token,
818 unsigned int tokenAlgo,
819 BOOL & isAuthorised,
820 unsigned & timeLimit
823 // make sure the provider is open
824 if (!provider->IsOpen())
825 return -1;
827 // make sure the transaction is open
828 int stat = 0;
829 if (!IsOpen()) {
830 return -1 ;
833 unsigned int authorised = 0;
834 unsigned int logSize = 0;
836 stat = ::OSPPTransactionValidateAuthorisation(
837 *this,
838 (const char *)ospvSource,
839 (const char *)ospvDest,
840 (const char *)ospvSourceDevice,
841 (const char *)ospvDestDevice,
842 (const char *)ospvCallingNumber,
843 (OSPE_NUMBERING_FORMAT)ospvCallingNumberFormat,
844 (const char *)ospvCalledNumber,
845 (OSPE_NUMBERING_FORMAT)ospvCalledNumberFormat,
846 callID.GetSize(), (const BYTE *)callID,
847 token.GetSize(), (const BYTE *)token,
848 &authorised,
849 &timeLimit,
850 &logSize,
851 NULL,
852 tokenAlgo);
854 isAuthorised = authorised != 0;
855 return stat;
858 BOOL OpalOSP::Transaction::ValidationInfo::ExtractToken(const H225_ArrayOf_ClearToken & clearTokens)
860 PINDEX tokenCount = clearTokens.GetSize();
861 PINDEX i;
862 for (i = 0; i < tokenCount; ++i) {
863 H235_ClearToken & clearToken = clearTokens[i];
864 if (clearToken.m_tokenOID == ETSIXMLTokenOID &&
865 clearToken.HasOptionalField(H235_ClearToken::e_nonStandard) &&
866 clearToken.m_nonStandard.m_nonStandardIdentifier == ETSIXMLTokenOID)
868 token = clearToken.m_nonStandard.m_data;
869 return TRUE;
872 return FALSE;
875 BOOL OpalOSP::Transaction::ValidationInfo::Extract(const H323SignalPDU & setupPDU)
877 if (setupPDU.m_h323_uu_pdu.m_h323_message_body.GetTag() != H225_H323_UU_PDU_h323_message_body::e_setup)
878 return FALSE;
880 const H225_Setup_UUIE & setup = setupPDU.m_h323_uu_pdu.m_h323_message_body;
882 // must have a source call signalling address
883 if (!setup.HasOptionalField(H225_Setup_UUIE::e_sourceCallSignalAddress))
884 return FALSE;
885 ospvSourceDevice = ospvSource = TransportAddressToOSPString(setup.m_sourceCallSignalAddress);
887 // must have one or more source addresses
888 // Use the Q.931 calling party number otherwise find a H.323 alias
889 // that is a valid OSP target
890 PString str;
891 if (setupPDU.GetQ931().GetCallingPartyNumber(str))
892 H323SetAliasAddress(str, callingNumber, H225_AliasAddress::e_dialedDigits);
893 else if (!setup.HasOptionalField(H225_Setup_UUIE::e_sourceAddress) ||
894 !ValidateAddress(setup.m_sourceAddress, callingNumber))
895 return FALSE;
897 // use destination call signalling address if present
898 if (setup.HasOptionalField(H225_Setup_UUIE::e_destCallSignalAddress))
899 ospvDestDevice = ospvDest = TransportAddressToOSPString(setup.m_destCallSignalAddress);
901 // must have one or more destination addresses
902 // Use the Q.931 called party number otherwise find a H.323 destination alias
903 // that is a valid OSP target
904 if (setupPDU.GetQ931().GetCalledPartyNumber(str))
905 H323SetAliasAddress(str, calledNumber, H225_AliasAddress::e_dialedDigits);
906 else if (!setup.HasOptionalField(H225_Setup_UUIE::e_destinationAddress) ||
907 !ValidateAddress(setup.m_destinationAddress, calledNumber))
908 return FALSE;
910 // get the call identifier (make sure it has non-zero length)
911 if (setup.m_callIdentifier.m_guid.GetSize() == 0)
912 return FALSE;
913 callID = setup.m_callIdentifier.m_guid;
915 // get the token
916 return setup.HasOptionalField(H225_Setup_UUIE::e_tokens) && ExtractToken(setup.m_tokens);
919 BOOL OpalOSP::Transaction::ValidationInfo::Extract(const H225_AdmissionRequest & arq)
921 // must have a source call signalling address
922 if (!arq.HasOptionalField(H225_AdmissionRequest::e_srcCallSignalAddress))
923 return FALSE;
924 PIPSocket::Address addr;
925 WORD port;
926 H323TransportAddress taddr(arq.m_srcCallSignalAddress);
927 if (!taddr.GetIpAndPort(addr, port))
928 return FALSE;
929 ospvSourceDevice = ospvSource = IpAddressPortToOSPString(addr, port);
931 // must have one or more source addresses
932 // pick the first one that is a valid OSP target
933 if (!ValidateAddress(arq.m_srcInfo, callingNumber))
934 return FALSE;
936 // must have one or more destination addresses
937 // pick the first one that is a valid OSP target
938 if (!arq.HasOptionalField(H225_AdmissionRequest::e_destinationInfo) ||
939 !ValidateAddress(arq.m_destinationInfo, calledNumber))
940 return FALSE;
942 // get the call identifier (make sure it has non-zero length)
943 if (arq.m_callIdentifier.m_guid.GetSize() == 0)
944 return FALSE;
945 callID = arq.m_callIdentifier.m_guid;
947 return TRUE;
951 ////////////////////////////////////////////////////////////////////////////////////
953 // transaction destination functions
956 int OpalOSP::Transaction::GetFirstDestination(DestinationInfo & info)
958 PString destAddress;
959 PString calledNumber;
960 PString callingNumber;
962 int result = GetFirstDestination(
963 info.timeLimit,
964 info.callID,
965 calledNumber,
966 callingNumber,
967 destAddress,
968 info.destination,
969 info.token
972 if (result != 0)
973 return result;
975 info.destinationAddress = OSPStringToAddress(destAddress, H323EndPoint::DefaultTcpPort);
976 H323SetAliasAddress(calledNumber, info.calledNumber, H225_AliasAddress::e_dialedDigits);
978 info.hasCallingNumber = !callingNumber.IsEmpty();
979 if (info.hasCallingNumber)
980 H323SetAliasAddress(callingNumber, info.callingNumber, H225_AliasAddress::e_dialedDigits);
982 return 0;
985 int OpalOSP::Transaction::GetFirstDestination(unsigned & timeLimit,
986 PBYTEArray & callID,
987 PString & calledNumber,
988 PString & callingNumber,
989 PString & destAddress,
990 PString & destDevice,
991 PBYTEArray & token)
993 if (!CheckOpenedAndNotEnded("get first destination"))
994 return -1;
996 callID.SetSize(CALLID_SIZE);
997 unsigned callIDSize = callID.GetSize();
999 calledNumber.SetSize(CALLED_NUMBER_SIZE+1);
1000 callingNumber.SetSize(CALLING_NUMBER_SIZE+1);
1001 destAddress.SetSize(DESTINATION_SIZE+1);
1002 destDevice.SetSize(DEVICE_SIZE+1);
1004 token.SetSize(TOKEN_SIZE);
1005 unsigned tokenSize = token.GetSize();
1007 int stat = ::OSPPTransactionGetFirstDestination(
1008 *this, /* In - Transaction handle */
1009 0, /* In - Max size for timestamp string */
1010 NULL, /* Out - Valid After time in string format */
1011 NULL, /* Out - Valid Until time in string format */
1012 &timeLimit, /* Out - Number of seconds call is authorised for */
1013 &callIDSize, /* In/Out - Max size for CallId string Actual size of CallId string */
1014 callID.GetPointer(), /* Out - Call Id string */
1015 calledNumber.GetSize(), /* In - Max size of called number */
1016 calledNumber.GetPointer(), /* Out - Called number string */
1017 #ifdef H323_NEW_OSP_API
1018 callingNumber.GetSize(), /* In - Max size of calling number */
1019 callingNumber.GetPointer(), /* Out - Calling number string */
1020 #endif
1021 destAddress.GetSize(), /* In - Max size of destination string */
1022 destAddress.GetPointer(), /* Out - Destination string */
1023 destDevice.GetSize(), /* In - Max size of dest device string */
1024 destDevice.GetPointer(), /* Out - Dest device string */
1025 &tokenSize, /* In/Out - Max size of token string Actual size of token string */
1026 token.GetPointer() /* Out - Token string */
1029 callID.SetSize(callIDSize);
1030 calledNumber.MakeMinimumSize();
1031 callingNumber.MakeMinimumSize();
1032 destAddress.MakeMinimumSize();
1033 destDevice.MakeMinimumSize();
1034 token.SetSize(tokenSize);
1036 return stat;
1039 int OpalOSP::Transaction::GetNextDestination(int reason, DestinationInfo & info)
1041 PString destAddress;
1042 PString calledNumber;
1043 PString callingNumber;
1045 int result = GetNextDestination(
1046 reason,
1047 info.timeLimit,
1048 info.callID,
1049 calledNumber,
1050 callingNumber,
1051 destAddress,
1052 info.destination,
1053 info.token
1056 if (result != 0)
1057 return result;
1059 info.destinationAddress = OSPStringToAddress(destAddress, H323EndPoint::DefaultTcpPort);
1060 H323SetAliasAddress(calledNumber, info.calledNumber, H225_AliasAddress::e_dialedDigits);
1062 info.hasCallingNumber = !callingNumber.IsEmpty();
1063 if (info.hasCallingNumber)
1064 H323SetAliasAddress(callingNumber, info.callingNumber, H225_AliasAddress::e_dialedDigits);
1066 return 0;
1069 int OpalOSP::Transaction::GetNextDestination(int reason,
1070 unsigned & timeLimit,
1071 PBYTEArray & callID,
1072 PString & calledNumber,
1073 PString & callingNumber,
1074 PString & destAddress,
1075 PString & destDevice,
1076 PBYTEArray & token)
1078 if (!CheckOpenedAndNotEnded("get first destination"))
1079 return -1;
1081 callID.SetSize(CALLID_SIZE);
1082 unsigned callIDSize = callID.GetSize();
1084 calledNumber.SetSize(CALLED_NUMBER_SIZE+1);
1085 callingNumber.SetSize(CALLING_NUMBER_SIZE+1);
1086 destAddress.SetSize(DESTINATION_SIZE+1);
1087 destDevice.SetSize(DEVICE_SIZE+1);
1089 token.SetSize(TOKEN_SIZE);
1090 unsigned tokenSize = token.GetSize();
1092 int stat = ::OSPPTransactionGetNextDestination(
1093 *this, /* In - Transaction handle */
1094 (OSPEFAILREASON)reason, /* In - Failure code */
1095 0, /* In - Max size of timestamp string */
1096 NULL, /* Out - Valid after time string */
1097 NULL, /* Out - Valid until time string */
1098 &timeLimit, /* Out - Number of seconds call is authorised for */
1099 &callIDSize, /* In - Max size of call id string */
1100 callID.GetPointer(), /* Out - Call Id string */
1101 calledNumber.GetSize(), /* In - Max size of called number */
1102 calledNumber.GetPointer(), /* Out - Called number string */
1103 #ifdef H323_NEW_OSP_API
1104 callingNumber.GetSize(), /* In - Max size of calling number */
1105 callingNumber.GetPointer(), /* Out - Calling number string */
1106 #endif
1107 destAddress.GetSize(), /* In - Max size of destination string */
1108 destAddress.GetPointer(), /* Out - Destination string */
1109 destDevice.GetSize(), /* In - Max size of dest device string */
1110 destDevice.GetPointer(), /* Out - Dest device string */
1111 &tokenSize, /* In/Out - Max size of token string Actual size of token string */
1112 token.GetPointer() /* Out - Token string */
1115 callID.SetSize(callIDSize);
1116 calledNumber.MakeMinimumSize();
1117 callingNumber.MakeMinimumSize();
1118 destAddress.MakeMinimumSize();
1119 destDevice.MakeMinimumSize();
1120 token.SetSize(tokenSize);
1122 return stat;
1125 void OpalOSP::Transaction::DestinationInfo::InsertToken(H225_ArrayOf_ClearToken & clearTokens, BOOL useCiscoBug)
1127 PINDEX tokenCount = clearTokens.GetSize();
1128 clearTokens.SetSize(tokenCount+1);
1129 H235_ClearToken & clearToken = clearTokens[tokenCount];
1130 clearToken.m_tokenOID = ETSIXMLTokenOID;
1131 clearToken.IncludeOptionalField(H235_ClearToken::e_nonStandard);
1132 clearToken.m_nonStandard.m_nonStandardIdentifier = ETSIXMLTokenOID;
1134 if (!useCiscoBug) {
1135 clearToken.m_nonStandard.m_data = token;
1136 } else {
1137 PASN_OctetString & destToken = clearToken.m_nonStandard.m_data;
1138 PINDEX tokenSize = token.GetSize();
1139 destToken.SetSize(token.GetSize()+3);
1140 destToken[0] = 0;
1141 destToken[1] = (BYTE)(0x80+(tokenSize>>8));
1142 destToken[2] = (BYTE)tokenSize;
1143 memcpy(&destToken[3], &token[0], tokenSize);
1147 BOOL OpalOSP::Transaction::DestinationInfo::Insert(H323SignalPDU & setupPDU, BOOL useCiscoBug)
1149 if (setupPDU.m_h323_uu_pdu.m_h323_message_body.GetTag() != H225_H323_UU_PDU_h323_message_body::e_setup)
1150 return FALSE;
1152 H225_Setup_UUIE & setup = setupPDU.m_h323_uu_pdu.m_h323_message_body;
1154 return Insert(setup, useCiscoBug);
1157 BOOL OpalOSP::Transaction::DestinationInfo::Insert(H225_Setup_UUIE & setup, BOOL useCiscoBug)
1159 // insert the OSP token into the PDU
1160 setup.IncludeOptionalField(H225_Setup_UUIE::e_tokens);
1161 InsertToken(setup.m_tokens, useCiscoBug);
1163 // set the destination address array to the called number
1164 setup.IncludeOptionalField(H225_Setup_UUIE::e_destinationAddress);
1165 setup.m_destinationAddress.SetSize(1);
1166 setup.m_destinationAddress[0] = calledNumber;
1168 return TRUE;
1171 BOOL OpalOSP::Transaction::DestinationInfo::Insert(H225_AdmissionConfirm & acf, BOOL useCiscoBug)
1173 // insert the OSP token into the PDU
1174 acf.IncludeOptionalField(H225_AdmissionConfirm::e_tokens);
1175 InsertToken(acf.m_tokens, useCiscoBug);
1177 // set the destinationInfo field to the called number
1178 destinationAddress.SetPDU(acf.m_destCallSignalAddress);
1180 // set the destCallSignalAddress field to the destination address
1181 acf.IncludeOptionalField(H225_AdmissionConfirm::e_destinationInfo);
1182 acf.m_destinationInfo.SetSize(1);
1183 acf.m_destinationInfo[0] = calledNumber;
1185 return TRUE;
1188 ////////////////////////////////////////////////////////////////////////////////////////////////////////
1190 #endif // H323_TRANSNEXUS_OSP
1192 // end of file