Utilise new MergeSym feature to no longer overwrite the source .DEF file when buildin...
[openh323.git] / src / q931.cxx
blob90649e26dac35be07e11f9a66a6c8bd55ba80fe9
1 /*
2 * q931.cxx
4 * Q.931 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 1.66 2006/08/12 03:59:46 csoutheren
31 * Added additional Q.931 message types
32 * Thanks to ii7@bk.ru
34 * Revision 1.65 2004/12/09 23:37:14 csoutheren
35 * Added new Q.931 termination codes
37 * Revision 1.64 2004/11/19 00:14:18 csoutheren
38 * Prevent GetBearerCapabilities from reading invalid memory (array index out of bounds)
39 * Thanks to Michal Zygmuntowicz
41 * Revision 1.63 2004/11/07 12:45:09 rjongbloed
42 * Minor change to parsing of bearer capabilities, thanks Michal Zygmuntowicz
44 * Revision 1.62 2004/07/11 11:37:28 rjongbloed
45 * Added ConnectAck support and fixed bugs in ChannelIdentificationIE, thanks Eize Slange
47 * Revision 1.61 2004/06/06 08:44:26 rjongbloed
48 * Fixed incorrect test for Q.931 calls state information element, thanks Stelios Vaiopoulos
50 * Revision 1.60 2004/05/07 06:44:17 csoutheren
51 * Fixed problem with empty Q>931 DisplayName
53 * Revision 1.59 2003/08/24 23:10:30 rjongbloed
54 * Fixed incorrect mask in bearer caps decoding, thanks Greg Adams
56 * Revision 1.58 2003/03/18 05:54:18 robertj
57 * Added ChannelIdentifier IE support, thanks Eize Slange
59 * Revision 1.57 2003/02/12 02:23:01 robertj
60 * Fixed printing of cause codes that are impossible as opposed to merely
61 * unlikely or unallocated.
63 * Revision 1.56 2003/02/12 00:02:23 robertj
64 * Added more Q.931 cause codes.
65 * Added ability to trace text version of cause codes and IE codes.
67 * Revision 1.55 2002/11/19 06:19:25 robertj
68 * Added extra "congested" Q.931 codes.
70 * Revision 1.54 2002/08/06 02:27:39 robertj
71 * GNU C++ v3 compatibility.
73 * Revision 1.53 2002/08/05 10:03:48 robertj
74 * Cosmetic changes to normalise the usage of pragma interface/implementation.
76 * Revision 1.52 2002/07/25 10:55:44 robertj
77 * Changes to allow more granularity in PDU dumps, hex output increasing
78 * with increasing trace level.
80 * Revision 1.51 2002/07/05 03:13:38 robertj
81 * Added copy constructor for Q.931 so makes duplicate instead of reference to IE's.
83 * Revision 1.50 2002/07/03 10:26:05 robertj
84 * Fixed bearer capabilities for H,450.1 needing non ITU standard, thanks Florian Winterstein
86 * Revision 1.49 2002/05/22 23:12:03 robertj
87 * Enhanced the display of Release-Complete cause codes.
89 * Revision 1.48 2002/05/07 23:49:35 craigs
90 * Changed comment on length of userUserIE field thanks to Paul Long
92 * Revision 1.47 2002/05/03 05:38:19 robertj
93 * Added Q.931 Keypad IE mechanism for user indications (DTMF).
95 * Revision 1.46 2002/04/22 07:32:16 craigs
96 * Changed GetProgressIndicator to be const
98 * Revision 1.45 2002/04/19 04:49:14 robertj
99 * Fixed currect bit shift for CallState IE standard bits.
101 * Revision 1.44 2002/04/19 02:16:47 robertj
102 * Added CallState IE processing.
104 * Revision 1.43 2002/04/18 06:16:32 craigs
105 * Extra robustness in handling of strange UserUserIE lengths
107 * Revision 1.42 2002/01/07 04:25:21 robertj
108 * Added support for Connected-Number Information Element, thanks Hans Verbeek
110 * Revision 1.41 2002/01/06 05:28:41 robertj
111 * Fixed crash if given bad data in number field, thanks Chih-Wei Huang.
113 * Revision 1.40 2001/09/17 02:06:40 robertj
114 * Added Redirecting Number IE to Q.931, thanks Frank Derks
116 * Revision 1.39 2001/09/13 02:41:21 robertj
117 * Fixed call reference generation to use full range and common code, thanks Carlo Kielstra
119 * Revision 1.38 2001/08/27 03:45:59 robertj
120 * Added automatic setting of bearer capability transfer mode from H.323
121 * capabilities on connection at time of SETUP PDU.
123 * Revision 1.37 2001/08/20 06:48:28 robertj
124 * Added Q.931 function for setting bearer capabilities, allowing
125 * applications to set the data rate as they require.
127 * Revision 1.36 2001/08/07 02:57:09 robertj
128 * Fixed incorrect Q.931 bearer capability, thanks Carlo Kielstra.
130 * Revision 1.35 2001/07/24 23:40:15 craigs
131 * Added ability to remove Q931 IE
133 * Revision 1.34 2001/06/14 06:25:16 robertj
134 * Added further H.225 PDU build functions.
135 * Moved some functionality from connection to PDU class.
137 * Revision 1.33 2001/05/30 04:38:40 robertj
138 * Added BuildStatusEnquiry() Q.931 function, thanks Markus Storm
140 * Revision 1.32 2001/04/05 00:06:31 robertj
141 * Fixed some more encoding/decoding problems with little used bits of
142 * the Q.931 protocol, thanks Hans Verbeek.
144 * Revision 1.31 2001/04/03 23:06:15 robertj
145 * Fixed correct encoding and decoding of Q.850 cause field, thanks Hans Verbeek.
147 * Revision 1.30 2001/02/09 05:13:56 craigs
148 * Added pragma implementation to (hopefully) reduce the executable image size
149 * under Linux
151 * Revision 1.29 2001/01/19 06:57:26 robertj
152 * Added Information message type.
154 * Revision 1.28 2000/10/13 02:16:04 robertj
155 * Added support for Progress Indicator Q.931/H.225 message.
157 * Revision 1.27 2000/07/11 11:17:01 robertj
158 * Improved trace log display of Q.931 PDU's (correct order and extra IE fields).
160 * Revision 1.26 2000/07/09 14:54:11 robertj
161 * Added facility IE to facility message.
162 * Changed reference to the word "field" to be more correct IE or "Information Element"
164 * Revision 1.25 2000/06/21 08:07:47 robertj
165 * Added cause/reason to release complete PDU, where relevent.
167 * Revision 1.24 2000/05/09 12:19:31 robertj
168 * Added ability to get and set "distinctive ring" Q.931 functionality.
170 * Revision 1.23 2000/05/08 14:07:35 robertj
171 * Improved the provision and detection of calling and caller numbers, aliases and hostnames.
173 * Revision 1.22 2000/05/06 02:18:26 robertj
174 * Changed the new CallingPartyNumber code so defaults for octet3a are application dependent.
176 * Revision 1.21 2000/05/05 00:44:05 robertj
177 * Added presentation and screening fields to Calling Party Number field, thanks Dean Anderson.
179 * Revision 1.20 2000/05/02 04:32:27 robertj
180 * Fixed copyright notice comment.
182 * Revision 1.19 2000/03/21 01:08:11 robertj
183 * Fixed incorrect call reference code being used in originated call.
185 * Revision 1.18 2000/02/17 12:07:43 robertj
186 * Used ne wPWLib random number generator after finding major problem in MSVC rand().
188 * Revision 1.17 1999/12/23 22:44:06 robertj
189 * Added calling party number field.
191 * Revision 1.16 1999/09/22 04:18:29 robertj
192 * Fixed missing "known" message types in debugging output.
194 * Revision 1.15 1999/09/10 03:36:48 robertj
195 * Added simple Q.931 Status response to Q.931 Status Enquiry
197 * Revision 1.14 1999/08/31 13:54:35 robertj
198 * Fixed problem with memory overrun building PDU's
200 * Revision 1.13 1999/08/31 12:34:19 robertj
201 * Added gatekeeper support.
203 * Revision 1.12 1999/08/13 06:34:38 robertj
204 * Fixed problem in CallPartyNumber Q.931 encoding.
205 * Added field name display to Q.931 protocol.
207 * Revision 1.11 1999/08/10 13:14:15 robertj
208 * Added Q.931 Called Number field if have "phone number" style destination addres.
210 * Revision 1.10 1999/07/16 02:15:30 robertj
211 * Fixed more tunneling problems.
213 * Revision 1.9 1999/07/09 14:59:59 robertj
214 * Fixed GNU C++ compatibility.
216 * Revision 1.8 1999/07/09 06:09:50 robertj
217 * Major implementation. An ENORMOUS amount of stuff added everywhere.
219 * Revision 1.7 1999/06/14 15:19:48 robertj
220 * GNU C compatibility
222 * Revision 1.6 1999/06/13 12:41:14 robertj
223 * Implement logical channel transmitter.
224 * Fixed H245 connect on receiving call.
226 * Revision 1.5 1999/06/09 05:26:20 robertj
227 * Major restructuring of classes.
229 * Revision 1.4 1999/02/23 11:04:29 robertj
230 * Added capability to make outgoing call.
232 * Revision 1.3 1999/01/16 01:31:38 robertj
233 * Major implementation.
235 * Revision 1.2 1999/01/02 04:00:52 robertj
236 * Added higher level protocol negotiations.
238 * Revision 1.1 1998/12/14 09:13:37 robertj
239 * Initial revision
243 #include <ptlib.h>
245 #ifdef __GNUC__
246 #pragma implementation "q931.h"
247 #endif
249 #include "q931.h"
251 #include <ptclib/random.h>
254 #define new PNEW
257 ostream & operator<<(ostream & strm, Q931::InformationElementCodes ie)
259 static POrdinalToString::Initialiser IENamesInit[] = {
260 { Q931::BearerCapabilityIE, "Bearer-Capability" },
261 { Q931::CauseIE, "Cause" },
262 { Q931::FacilityIE, "Facility" },
263 { Q931::ProgressIndicatorIE, "Progress-Indicator" },
264 { Q931::CallStateIE, "Call-State" },
265 { Q931::DisplayIE, "Display" },
266 { Q931::SignalIE, "Signal" },
267 { Q931::KeypadIE, "Keypad" },
268 { Q931::ConnectedNumberIE, "Connected-Number" },
269 { Q931::CallingPartyNumberIE, "Calling-Party-Number" },
270 { Q931::CalledPartyNumberIE, "Called-Party-Number" },
271 { Q931::RedirectingNumberIE, "Redirecting-Number" },
272 { Q931::ChannelIdentificationIE,"Channel-Identification"},
273 { Q931::UserUserIE, "User-User" }
275 static const POrdinalToString IENames(PARRAYSIZE(IENamesInit), IENamesInit);
277 if (IENames.Contains((PINDEX)ie))
278 strm << IENames[ie];
279 else
280 strm << "0x" << hex << (unsigned)ie << dec << " (" << (unsigned)ie << ')';
282 return strm;
286 ostream & operator<<(ostream & strm, Q931::CauseValues cause)
288 static POrdinalToString::Initialiser CauseNamesInit[] = {
289 { Q931::UnallocatedNumber, "Unallocated number" },
290 { Q931::NoRouteToNetwork, "No route to network" },
291 { Q931::NoRouteToDestination, "No route to destination" },
292 { Q931::SendSpecialTone, "Send special tone" },
293 { Q931::MisdialledTrunkPrefix, "Misdialled trunk prefix" },
294 { Q931::ChannelUnacceptable, "Channel unacceptable" },
295 { Q931::NormalCallClearing, "Normal call clearing" },
296 { Q931::UserBusy, "User busy" },
297 { Q931::NoResponse, "No response" },
298 { Q931::NoAnswer, "No answer" },
299 { Q931::SubscriberAbsent, "Subscriber absent" },
300 { Q931::CallRejected, "Call rejected" },
301 { Q931::NumberChanged, "Number changed" },
302 { Q931::Redirection, "Redirection" },
303 { Q931::ExchangeRoutingError, "Exchange routing error" },
304 { Q931::NonSelectedUserClearing, "Non selected user clearing" },
305 { Q931::DestinationOutOfOrder, "Destination out of order" },
306 { Q931::InvalidNumberFormat, "Invalid number format" },
307 { Q931::FacilityRejected, "Facility rejected" },
308 { Q931::StatusEnquiryResponse, "Status enquiry response" },
309 { Q931::NormalUnspecified, "Normal unspecified" },
310 { Q931::NoCircuitChannelAvailable, "No circuit/channel available" },
311 { Q931::NetworkOutOfOrder, "Network out of order" },
312 { Q931::TemporaryFailure, "Temporary failure" },
313 { Q931::Congestion, "Congestion" },
314 { Q931::RequestedCircuitNotAvailable,"RequestedCircuitNotAvailable" },
315 { Q931::ResourceUnavailable, "Resource unavailable" },
316 { Q931::ServiceOptionNotAvailable, "Service or option not available" },
317 { Q931::InvalidCallReference, "Invalid call reference" },
318 { Q931::IncompatibleDestination, "Incompatible destination" },
319 { Q931::IENonExistantOrNotImplemented,"IE non-existent or not implemented" },
320 { Q931::TimerExpiry, "Recovery from timer expiry" },
321 { Q931::ProtocolErrorUnspecified, "Protocol error, unspecified" },
322 { Q931::InterworkingUnspecified, "Interworking, unspecified" },
323 { Q931::CallAwarded, "Call awarded, delivered via established channel" },
324 { Q931::Preemption, "Call is being preempted" },
325 { Q931::PreemptionCircuitReserved, "Preemption - circuit reserved for reuse" },
326 { Q931::CallQueued, "Call queued" },
327 { Q931::FrameModeOOS, "Frame mode out of service" },
328 { Q931::FrameModeOperational, "Frame mode operational" },
329 { Q931::AccessInformationDiscarded, "Access information discarded" },
330 { Q931::PrecedenceCallBlocked, "Precedence Call Blocked" },
331 { Q931::QoSNotAvailable, "QoS not available" },
332 { Q931::RequestedFacilityNotSubscribed, "Requested facility not subscribed" },
333 { Q931::OutgoingCallsBarred, "Outgoing calls barred" },
334 { Q931::OutgoingCallsBarredInCUG, "Outgoing calls barred in CUG" },
335 { Q931::IncomingCallsBarred, "Incoming calls barred" },
336 { Q931::IncomingCallsBarredInCUG, "Incoming calls barred in CUG" },
337 { Q931::BearerCapNotAuthorised, "Bearer cap not authorised" },
338 { Q931::BearerCapNotPresentlyAvailable, "Bearer cap not presently available" },
339 { Q931::InconsistentOutgoingIE, "Inconsistent outgoing information element" },
340 { Q931::BearerCapNotImplemented, "Bearer cap not implemented" },
341 { Q931::ChannelTypeNotImplemented, "Channel type not implemented" },
342 { Q931::RequestedFacilityNotImplemented, "Requested facility not implemented" },
343 { Q931::OnlyRestrictedDigitalBearerCapAvailable, "Only restricted digital bearer cap available" },
344 { Q931::ServiceOrOptionNotImplemented, "Service or option not implemented" },
345 { Q931::IdentifiedChannelNonExistent, "IdentifiedChannelNonExistent" },
346 { Q931::CallIdentifyNotSuspendedCall, "CallIdentifyNotSuspendedCall" },
347 { Q931::CallIdentifyInUse, "CallIdentifyInUse" },
348 { Q931::NoCallSuspended, "NoCallSuspended" },
349 { Q931::ClearedRequestedCallIdentity, "ClearedRequestedCallIdentity" },
350 { Q931::UserNotInCUG, "UserNotInCUG" },
352 static const POrdinalToString CauseNames(PARRAYSIZE(CauseNamesInit), CauseNamesInit);
354 if (CauseNames.Contains((PINDEX)cause))
355 strm << CauseNames[cause];
356 else if (cause < Q931::ErrorInCauseIE)
357 strm << "0x" << hex << (unsigned)cause << dec << " (" << (unsigned)cause << ')';
358 else
359 strm << "N/A";
361 return strm;
365 ///////////////////////////////////////////////////////////////////////////////
367 Q931::Q931()
369 protocolDiscriminator = 8; // Q931 always has 00001000
370 messageType = NationalEscapeMsg;
371 fromDestination = FALSE;
372 callReference = 0;
376 Q931::Q931(const Q931 & other)
378 operator=(other);
382 Q931 & Q931::operator=(const Q931 & other)
384 callReference = other.callReference;
385 fromDestination = other.fromDestination;
386 protocolDiscriminator = other.protocolDiscriminator;
387 messageType = other.messageType;
389 informationElements.RemoveAll();
390 for (PINDEX i = 0; i < other.informationElements.GetSize(); i++)
391 informationElements.SetAt(other.informationElements.GetKeyAt(i), new PBYTEArray(other.informationElements.GetDataAt(i)));
393 return *this;
397 void Q931::BuildFacility(int callRef, BOOL fromDest)
399 messageType = FacilityMsg;
400 callReference = callRef;
401 fromDestination = fromDest;
402 informationElements.RemoveAll();
403 PBYTEArray data;
404 SetIE(FacilityIE, data);
408 void Q931::BuildInformation(int callRef, BOOL fromDest)
410 messageType = InformationMsg;
411 callReference = callRef;
412 fromDestination = fromDest;
413 informationElements.RemoveAll();
417 void Q931::BuildProgress(int callRef,
418 BOOL fromDest,
419 unsigned description,
420 unsigned codingStandard,
421 unsigned location)
423 messageType = ProgressMsg;
424 callReference = callRef;
425 fromDestination = fromDest;
426 informationElements.RemoveAll();
427 SetProgressIndicator(description, codingStandard, location);
431 void Q931::BuildNotify(int callRef, BOOL fromDest)
433 messageType = NotifyMsg;
434 callReference = callRef;
435 fromDestination = fromDest;
436 informationElements.RemoveAll();
440 void Q931::BuildSetupAcknowledge(int callRef)
442 messageType = SetupAckMsg;
443 callReference = callRef;
444 fromDestination = TRUE;
445 informationElements.RemoveAll();
449 void Q931::BuildCallProceeding(int callRef)
451 messageType = CallProceedingMsg;
452 callReference = callRef;
453 fromDestination = TRUE;
454 informationElements.RemoveAll();
458 void Q931::BuildAlerting(int callRef)
460 messageType = AlertingMsg;
461 callReference = callRef;
462 fromDestination = TRUE;
463 informationElements.RemoveAll();
467 void Q931::BuildSetup(int callRef)
469 messageType = SetupMsg;
470 if (callRef < 0)
471 callReference = GenerateCallReference();
472 else
473 callReference = callRef;
474 fromDestination = FALSE;
475 informationElements.RemoveAll();
476 SetBearerCapabilities(TransferSpeech, 1);
480 void Q931::BuildConnect(int callRef)
482 messageType = ConnectMsg;
483 callReference = callRef;
484 fromDestination = TRUE;
485 informationElements.RemoveAll();
486 SetBearerCapabilities(TransferSpeech, 1);
489 void Q931::BuildConnectAck(int callRef, BOOL fromDest)
491 messageType = ConnectAckMsg;
492 callReference = callRef;
493 fromDestination = fromDest;
494 informationElements.RemoveAll();
498 void Q931::BuildStatus(int callRef, BOOL fromDest)
500 messageType = StatusMsg;
501 callReference = callRef;
502 fromDestination = fromDest;
503 informationElements.RemoveAll();
504 SetCallState(CallState_Active);
505 // Cause field as per Q.850
506 SetCause(StatusEnquiryResponse);
510 void Q931::BuildStatusEnquiry(int callRef, BOOL fromDest)
512 messageType = StatusEnquiryMsg;
513 callReference = callRef;
514 fromDestination = fromDest;
515 informationElements.RemoveAll();
519 void Q931::BuildReleaseComplete(int callRef, BOOL fromDest)
521 messageType = ReleaseCompleteMsg;
522 callReference = callRef;
523 fromDestination = fromDest;
524 informationElements.RemoveAll();
528 BOOL Q931::Decode(const PBYTEArray & data)
530 // Clear all existing data before reading new
531 informationElements.RemoveAll();
533 if (data.GetSize() < 5) // Packet too short
534 return FALSE;
536 protocolDiscriminator = data[0];
538 if (data[1] != 2) // Call reference must be 2 bytes long
539 return FALSE;
541 callReference = ((data[2]&0x7f) << 8) | data[3];
542 fromDestination = (data[2]&0x80) != 0;
544 messageType = (MsgTypes)data[4];
546 // Have preamble, start getting the informationElements into buffers
547 PINDEX offset = 5;
548 while (offset < data.GetSize()) {
549 // Get field discriminator
550 int discriminator = data[offset++];
552 PBYTEArray * item = new PBYTEArray;
554 // For discriminator with high bit set there is no data
555 if ((discriminator&0x80) == 0) {
556 int len = data[offset++];
558 if (discriminator == UserUserIE) {
559 // Special case of User-user field. See 7.2.2.31/H.225.0v4.
560 len <<= 8;
561 len |= data[offset++];
563 // we also have a protocol discriminator, which we ignore
564 offset++;
566 // before decrementing the length, make sure it is not zero
567 if (len == 0)
568 return FALSE;
570 // adjust for protocol discriminator
571 len--;
574 if (offset + len > data.GetSize())
575 return FALSE;
577 memcpy(item->GetPointer(len), (const BYTE *)data+offset, len);
578 offset += len;
581 informationElements.SetAt(discriminator, item);
584 return TRUE;
588 BOOL Q931::Encode(PBYTEArray & data) const
590 PINDEX totalBytes = 5;
591 unsigned discriminator;
592 for (discriminator = 0; discriminator < 256; discriminator++) {
593 if (informationElements.Contains(discriminator)) {
594 if (discriminator < 128)
595 totalBytes += informationElements[discriminator].GetSize() +
596 (discriminator != UserUserIE ? 2 : 4);
597 else
598 totalBytes++;
602 if (!data.SetMinSize(totalBytes))
603 return FALSE;
605 // Put in Q931 header
606 PAssert(protocolDiscriminator < 256, PInvalidParameter);
607 data[0] = (BYTE)protocolDiscriminator;
608 data[1] = 2; // Length of call reference
609 data[2] = (BYTE)(callReference >> 8);
610 if (fromDestination)
611 data[2] |= 0x80;
612 data[3] = (BYTE)callReference;
613 PAssert(messageType < 256, PInvalidParameter);
614 data[4] = (BYTE)messageType;
616 // The following assures disciminators are in ascending value order
617 // as required by Q931 specification
618 PINDEX offset = 5;
619 for (discriminator = 0; discriminator < 256; discriminator++) {
620 if (informationElements.Contains(discriminator)) {
621 if (discriminator < 128) {
622 int len = informationElements[discriminator].GetSize();
624 if (discriminator != UserUserIE) {
625 data[offset++] = (BYTE)discriminator;
626 data[offset++] = (BYTE)len;
628 else {
629 len++; // Allow for protocol discriminator
630 data[offset++] = (BYTE)discriminator;
631 data[offset++] = (BYTE)(len >> 8);
632 data[offset++] = (BYTE)len;
633 len--; // Then put the length back again
634 // We shall assume that the user-user field is an ITU protocol block (5)
635 data[offset++] = 5;
638 memcpy(&data[offset], (const BYTE *)informationElements[discriminator], len);
639 offset += len;
641 else
642 data[offset++] = (BYTE)discriminator;
646 return data.SetSize(offset);
650 void Q931::PrintOn(ostream & strm) const
652 int indent = strm.precision() + 2;
653 _Ios_Fmtflags flags = strm.flags();
655 strm << "{\n"
656 << setw(indent+24) << "protocolDiscriminator = " << protocolDiscriminator << '\n'
657 << setw(indent+16) << "callReference = " << callReference << '\n'
658 << setw(indent+7) << "from = " << (fromDestination ? "destination" : "originator") << '\n'
659 << setw(indent+14) << "messageType = " << GetMessageTypeName() << '\n';
661 for (unsigned discriminator = 0; discriminator < 256; discriminator++) {
662 if (informationElements.Contains(discriminator)) {
663 strm << setw(indent+4) << "IE: " << (InformationElementCodes)discriminator;
664 if (discriminator == CauseIE) {
665 if (informationElements[discriminator].GetSize() > 1)
666 strm << " - " << (CauseValues)(informationElements[discriminator][1]&0x7f);
668 strm << " = {\n"
669 << hex << setfill('0') << resetiosflags(ios::floatfield)
670 << setprecision(indent+2) << setw(16);
672 PBYTEArray value = informationElements[discriminator];
673 if (value.GetSize() <= 32 || (flags&ios::floatfield) != ios::fixed)
674 strm << value;
675 else {
676 PBYTEArray truncatedArray(value, 32);
677 strm << truncatedArray << '\n'
678 << setfill(' ')
679 << setw(indent+5) << "...";
682 strm << dec << setfill(' ')
683 << '\n'
684 << setw(indent+2) << "}\n";
688 strm << setw(indent-1) << "}";
690 strm.flags(flags);
694 PString Q931::GetMessageTypeName() const
696 switch (messageType) {
697 case AlertingMsg :
698 return "Alerting";
699 case CallProceedingMsg :
700 return "CallProceeding";
701 case ConnectMsg :
702 return "Connect";
703 case ConnectAckMsg :
704 return "ConnectAck";
705 case ProgressMsg :
706 return "Progress";
707 case SetupMsg :
708 return "Setup";
709 case SetupAckMsg :
710 return "SetupAck";
711 case FacilityMsg :
712 return "Facility";
713 case ReleaseCompleteMsg :
714 return "ReleaseComplete";
715 case StatusEnquiryMsg :
716 return "StatusEnquiry";
717 case StatusMsg :
718 return "Status";
719 case InformationMsg :
720 return "Information";
721 case NationalEscapeMsg :
722 return "Escape";
723 case NotifyMsg :
724 return "NotifyMsg";
725 case ResumeMsg :
726 return "ResumeMsg";
727 case ResumeAckMsg :
728 return "ResumeAckMsg";
729 case ResumeRejectMsg :
730 return "ResumeRejectMsg";
731 case SuspendMsg :
732 return "SuspendMsg";
733 case SuspendAckMsg :
734 return "SuspendAckMsg";
735 case SuspendRejectMsg :
736 return "SuspendRejectMsg";
737 case UserInformationMsg :
738 return "UserInformationMsg";
739 case DisconnectMsg :
740 return "DisconnectMsg";
741 case ReleaseMsg :
742 return "ReleaseMsg";
743 case RestartMsg :
744 return "RestartMsg";
745 case RestartAckMsg :
746 return "RestartAckMsg";
747 case SegmentMsg :
748 return "SegmentMsg";
749 case CongestionCtrlMsg :
750 return "CongestionCtrlMsg";
751 default :
752 break;
755 return psprintf("<%u>", messageType);
759 unsigned Q931::GenerateCallReference()
761 static unsigned LastCallReference;
762 static PMutex mutex;
763 PWaitAndSignal wait(mutex);
765 if (LastCallReference == 0)
766 LastCallReference = PRandom::Number();
767 else
768 LastCallReference++;
770 LastCallReference &= 0x7fff;
772 if (LastCallReference == 0)
773 LastCallReference = 1;
775 return LastCallReference;
779 BOOL Q931::HasIE(InformationElementCodes ie) const
781 return informationElements.Contains(POrdinalKey(ie));
785 PBYTEArray Q931::GetIE(InformationElementCodes ie) const
787 if (informationElements.Contains(POrdinalKey(ie)))
788 return informationElements[ie];
790 return PBYTEArray();
794 void Q931::SetIE(InformationElementCodes ie, const PBYTEArray & userData)
796 informationElements.SetAt(ie, new PBYTEArray(userData));
799 void Q931::RemoveIE(InformationElementCodes ie)
801 informationElements.RemoveAt(ie);
805 void Q931::SetBearerCapabilities(InformationTransferCapability capability,
806 unsigned transferRate,
807 unsigned codingStandard,
808 unsigned userInfoLayer1)
810 BYTE data[4];
811 PINDEX size = 1;
812 data[0] = (BYTE)(0x80 | ((codingStandard&3) << 5) | (capability&31));
814 switch (codingStandard) {
815 case 0 : // ITU-T standardized coding
816 size = 3;
818 // Note this is always "Circuit Mode"
819 switch (transferRate) {
820 case 1 :
821 data[1] = 0x90;
822 break;
823 case 2 :
824 data[1] = 0x91;
825 break;
826 case 6 :
827 data[1] = 0x93;
828 break;
829 case 24 :
830 data[1] = 0x95;
831 break;
832 case 30 :
833 data[1] = 0x97;
834 break;
835 default :
836 PAssert(transferRate > 0 && transferRate < 128, PInvalidParameter);
837 data[1] = 0x18;
838 data[2] = (BYTE)(0x80 | transferRate);
839 size = 4;
842 PAssert(userInfoLayer1 >= 2 && userInfoLayer1 <= 5, PInvalidParameter);
843 data[size-1] = (BYTE)(0x80 | (1<<5) | userInfoLayer1);
844 break;
846 case 1 : // Other international standard
847 size = 2;
848 data[1] = 0x80; // Call independent signalling connection
849 break;
851 default :
852 break;
855 SetIE(BearerCapabilityIE, PBYTEArray(data, size));
859 BOOL Q931::GetBearerCapabilities(InformationTransferCapability & capability,
860 unsigned & transferRate,
861 unsigned * codingStandard,
862 unsigned * userInfoLayer1)
864 if (!HasIE(BearerCapabilityIE))
865 return FALSE;
867 PBYTEArray data = GetIE(BearerCapabilityIE);
868 if (data.GetSize() < 2)
869 return FALSE;
871 capability = (InformationTransferCapability)data[0];
872 if (codingStandard != NULL)
873 *codingStandard = (data[0] >> 5)&3;
875 PINDEX nextByte = 2;
876 switch (data[1]) {
877 case 0x90 :
878 transferRate = 1;
879 break;
880 case 0x91 :
881 transferRate = 2;
882 break;
883 case 0x93 :
884 transferRate = 6;
885 break;
886 case 0x95 :
887 transferRate = 24;
888 break;
889 case 0x97 :
890 transferRate = 30;
891 break;
892 case 0x18 :
893 if (data.GetSize() < 3)
894 return FALSE;
895 transferRate = data[2]&0x7f;
896 nextByte = 3;
897 break;
898 default :
899 return FALSE;
902 if (userInfoLayer1 != NULL)
903 *userInfoLayer1 = data.GetSize() > nextByte && ((data[nextByte]>>5)&3) == 1 ? (data[nextByte]&0x1f) : 0;
905 return TRUE;
909 void Q931::SetCause(CauseValues value, unsigned standard, unsigned location)
911 PBYTEArray data(2);
912 data[0] = (BYTE)(0x80 | ((standard&3) << 5) | (location&15));
913 data[1] = (BYTE)(0x80 | value);
914 SetIE(CauseIE, data);
918 Q931::CauseValues Q931::GetCause(unsigned * standard, unsigned * location) const
920 if (!HasIE(CauseIE))
921 return ErrorInCauseIE;
923 PBYTEArray data = GetIE(CauseIE);
924 if (data.GetSize() < 2)
925 return ErrorInCauseIE;
927 if (standard != NULL)
928 *standard = (data[0] >> 5)&3;
929 if (location != NULL)
930 *location = data[0]&15;
932 if ((data[0]&0x80) != 0)
933 return (CauseValues)(data[1]&0x7f);
935 // Allow for optional octet
936 if (data.GetSize() < 3)
937 return ErrorInCauseIE;
939 return (CauseValues)(data[2]&0x7f);
943 void Q931::SetCallState(CallStates value, unsigned standard)
945 if (value >= CallState_ErrorInIE)
946 return;
948 // Call State as per Q.931 section 4.5.7
949 PBYTEArray data(1);
950 data[0] = (BYTE)(((standard&3) << 6) | value);
951 SetIE(CallStateIE, data);
955 Q931::CallStates Q931::GetCallState(unsigned * standard) const
957 if (!HasIE(CallStateIE))
958 return CallState_ErrorInIE;
960 PBYTEArray data = GetIE(CallStateIE);
961 if (data.IsEmpty())
962 return CallState_ErrorInIE;
964 if (standard != NULL)
965 *standard = (data[0] >> 6)&3;
967 return (CallStates)(data[0]&0x3f);
971 void Q931::SetSignalInfo(SignalInfo value)
973 PBYTEArray data(1);
974 data[0] = (BYTE)value;
975 SetIE(SignalIE, data);
979 Q931::SignalInfo Q931::GetSignalInfo() const
981 if (!HasIE(SignalIE))
982 return SignalErrorInIE;
984 PBYTEArray data = GetIE(SignalIE);
985 if (data.IsEmpty())
986 return SignalErrorInIE;
988 return (SignalInfo)data[0];
992 void Q931::SetKeypad(const PString & digits)
994 PBYTEArray bytes((const BYTE *)(const char *)digits, digits.GetLength()+1);
995 SetIE(KeypadIE, bytes);
999 PString Q931::GetKeypad() const
1001 if (!HasIE(Q931::KeypadIE))
1002 return PString();
1004 PBYTEArray digits = GetIE(Q931::KeypadIE);
1005 if (digits.IsEmpty())
1006 return PString();
1008 return PString((const char *)(const BYTE *)digits, digits.GetSize());
1012 void Q931::SetProgressIndicator(unsigned description,
1013 unsigned codingStandard,
1014 unsigned location)
1016 PBYTEArray data(2);
1017 data[0] = (BYTE)(0x80+((codingStandard&0x03)<<5)+(location&0x0f));
1018 data[1] = (BYTE)(0x80+(description&0x7f));
1019 SetIE(ProgressIndicatorIE, data);
1023 BOOL Q931::GetProgressIndicator(unsigned & description,
1024 unsigned * codingStandard,
1025 unsigned * location) const
1027 if (!HasIE(ProgressIndicatorIE))
1028 return FALSE;
1030 PBYTEArray data = GetIE(ProgressIndicatorIE);
1031 if (data.GetSize() < 2)
1032 return FALSE;
1034 if (codingStandard != NULL)
1035 *codingStandard = (data[0]>>5)&0x03;
1036 if (location != NULL)
1037 *location = data[0]&0x0f;
1038 description = data[1]&0x7f;
1040 return TRUE;
1044 void Q931::SetDisplayName(const PString & name)
1046 PBYTEArray bytes((const BYTE *)(const char *)name, name.GetLength()+1);
1047 if (name.GetLength() == 0)
1048 RemoveIE(DisplayIE);
1049 else
1050 SetIE(DisplayIE, bytes);
1054 PString Q931::GetDisplayName() const
1056 if (!HasIE(Q931::DisplayIE))
1057 return PString();
1059 PBYTEArray display = GetIE(Q931::DisplayIE);
1060 if (display.IsEmpty())
1061 return PString();
1063 return PString((const char *)(const BYTE *)display, display.GetSize());
1067 static PBYTEArray SetNumberIE(const PString & number,
1068 unsigned plan,
1069 unsigned type,
1070 int presentation,
1071 int screening,
1072 int reason)
1074 PBYTEArray bytes;
1076 PINDEX len = number.GetLength();
1078 if (reason == -1) {
1079 if (presentation == -1 || screening == -1) {
1080 bytes.SetSize(len+1);
1081 bytes[0] = (BYTE)(0x80|((type&7)<<4)|(plan&15));
1082 memcpy(bytes.GetPointer()+1, (const char *)number, len);
1084 else {
1085 bytes.SetSize(len+2);
1086 bytes[0] = (BYTE)(((type&7)<<4)|(plan&15));
1087 bytes[1] = (BYTE)(0x80|((presentation&3)<<5)|(screening&3));
1088 memcpy(bytes.GetPointer()+2, (const char *)number, len);
1091 else {
1092 // If octet 3b is present, then octet 3a must also be present!
1093 if (presentation == -1 || screening == -1) {
1094 // This situation should never occur!!!
1095 bytes.SetSize(len+1);
1096 bytes[0] = (BYTE)(0x80|((type&7)<<4)|(plan&15));
1097 memcpy(bytes.GetPointer()+1, (const char *)number, len);
1099 else {
1100 bytes.SetSize(len+3);
1101 bytes[0] = (BYTE)(0x80|((type&7)<<4)|(plan&15));
1102 bytes[1] = (BYTE)(0x80|((presentation&3)<<5)|(screening&3));
1103 bytes[2] = (BYTE)(0x80|(reason&15));
1104 memcpy(bytes.GetPointer()+3, (const char *)number, len);
1108 return bytes;
1112 static BOOL GetNumberIE(const PBYTEArray & bytes,
1113 PString & number,
1114 unsigned * plan,
1115 unsigned * type,
1116 unsigned * presentation,
1117 unsigned * screening,
1118 unsigned * reason,
1119 unsigned defPresentation,
1120 unsigned defScreening,
1121 unsigned defReason)
1123 number = PString();
1125 if (bytes.IsEmpty())
1126 return FALSE;
1128 if (plan != NULL)
1129 *plan = bytes[0]&15;
1131 if (type != NULL)
1132 *type = (bytes[0]>>4)&7;
1134 PINDEX offset;
1135 if ((bytes[0] & 0x80) != 0) { // Octet 3a not provided, set defaults
1136 if (presentation != NULL)
1137 *presentation = defPresentation;
1139 if (screening != NULL)
1140 *screening = defScreening;
1142 offset = 1;
1144 else {
1145 if (bytes.GetSize() < 2)
1146 return FALSE;
1148 if (presentation != NULL)
1149 *presentation = (bytes[1]>>5)&3;
1151 if (screening != NULL)
1152 *screening = bytes[1]&3;
1154 if ((bytes[1] & 0x80) != 0) { // Octet 3b not provided, set defaults
1155 if (reason != NULL)
1156 *reason = defReason;
1158 offset = 2;
1160 else {
1161 if (bytes.GetSize() < 3)
1162 return FALSE;
1164 if (reason != NULL)
1165 *reason = bytes[2]&15;
1167 offset = 3;
1171 if (bytes.GetSize() < offset)
1172 return FALSE;
1174 PINDEX len = bytes.GetSize()-offset;
1176 if (len > 0)
1177 memcpy(number.GetPointer(len+1), ((const BYTE *)bytes)+offset, len);
1179 return !number;
1183 void Q931::SetCallingPartyNumber(const PString & number,
1184 unsigned plan,
1185 unsigned type,
1186 int presentation,
1187 int screening)
1189 SetIE(CallingPartyNumberIE,
1190 SetNumberIE(number, plan, type, presentation, screening, -1));
1194 BOOL Q931::GetCallingPartyNumber(PString & number,
1195 unsigned * plan,
1196 unsigned * type,
1197 unsigned * presentation,
1198 unsigned * screening,
1199 unsigned defPresentation,
1200 unsigned defScreening) const
1202 return GetNumberIE(GetIE(CallingPartyNumberIE), number,
1203 plan, type, presentation, screening, NULL,
1204 defPresentation, defScreening, 0);
1208 void Q931::SetCalledPartyNumber(const PString & number, unsigned plan, unsigned type)
1210 SetIE(CalledPartyNumberIE,
1211 SetNumberIE(number, plan, type, -1, -1, -1));
1215 BOOL Q931::GetCalledPartyNumber(PString & number, unsigned * plan, unsigned * type) const
1217 return GetNumberIE(GetIE(CalledPartyNumberIE),
1218 number, plan, type, NULL, NULL, NULL, 0, 0, 0);
1222 void Q931::SetRedirectingNumber(const PString & number,
1223 unsigned plan,
1224 unsigned type,
1225 int presentation,
1226 int screening,
1227 int reason)
1229 SetIE(RedirectingNumberIE,
1230 SetNumberIE(number, plan, type, presentation, screening, reason));
1234 BOOL Q931::GetRedirectingNumber(PString & number,
1235 unsigned * plan,
1236 unsigned * type,
1237 unsigned * presentation,
1238 unsigned * screening,
1239 unsigned * reason,
1240 unsigned defPresentation,
1241 unsigned defScreening,
1242 unsigned defReason) const
1244 return GetNumberIE(GetIE(RedirectingNumberIE),
1245 number, plan, type, presentation, screening, reason,
1246 defPresentation, defScreening, defReason);
1250 BOOL Q931::GetConnectedNumber(PString & number,
1251 unsigned * plan,
1252 unsigned * type,
1253 unsigned * presentation,
1254 unsigned * screening,
1255 unsigned * reason,
1256 unsigned defPresentation,
1257 unsigned defScreening,
1258 unsigned defReason) const
1260 return GetNumberIE(GetIE(ConnectedNumberIE), number,
1261 plan, type, presentation, screening, reason,
1262 defPresentation, defScreening, defReason);
1266 void Q931::SetConnectedNumber(const PString & number,
1267 unsigned plan,
1268 unsigned type,
1269 int presentation,
1270 int screening,
1271 int reason)
1273 SetIE(ConnectedNumberIE,
1274 SetNumberIE(number, plan, type, presentation, screening, reason));
1278 void Q931::SetChannelIdentification(unsigned interfaceType,
1279 unsigned preferredOrExclusive,
1280 int channelNumber)
1282 // Known limitations:
1283 // - the interface identifier cannot be specified
1284 // - channel in PRI can only be indicated by number and cannot be indicated by map
1285 // - one and only one channel can be indicated
1286 // - the coding standard is always ITU Q.931
1288 PBYTEArray bytes;
1289 bytes.SetSize(1);
1291 PAssert(interfaceType < 2, PInvalidParameter);
1293 if (interfaceType == 0) { // basic rate
1294 if (channelNumber == -1) { // any channel
1295 bytes[0] = 0x80 | 0x03;
1297 if (channelNumber == 0) { // D channel
1298 bytes[0] = 0x80 | 0x04;
1300 if (channelNumber > 0) { // B channel
1301 bytes[0] = (BYTE)(0x80 | ((preferredOrExclusive & 0x01) << 3) | (channelNumber & 0x03));
1305 if (interfaceType == 1) { // primary rate
1306 if (channelNumber == -1) { // any channel
1307 bytes[0] = 0x80 | 0x20 | 0x03;
1308 bytes[1] = 0x80 | 0x03; // dummy octet 3.2
1309 bytes[2] = (BYTE)(0x80 | 1); // dummy octet 3.3
1311 if (channelNumber == 0) { // D channel
1312 bytes[0] = 0x80 | 0x04 | 0x20;
1314 if (channelNumber > 0) { // B channel
1315 bytes.SetSize(3);
1317 bytes[0] = (BYTE)(0x80 | 0x20 | ((preferredOrExclusive & 0x01) << 3) | 0x01);
1318 bytes[1] = 0x80 | 0x03;
1319 bytes[2] = (BYTE)(0x80 | channelNumber);
1323 SetIE(ChannelIdentificationIE, bytes);
1327 BOOL Q931::GetChannelIdentification(unsigned * interfaceType,
1328 unsigned * preferredOrExclusive,
1329 int * channelNumber) const
1331 if (!HasIE(ChannelIdentificationIE))
1332 return FALSE;
1334 PBYTEArray bytes = GetIE(ChannelIdentificationIE);
1335 if (bytes.GetSize() < 1)
1336 return FALSE;
1338 *interfaceType = (bytes[0]>>5) & 0x01;
1339 *preferredOrExclusive = (bytes[0]>>3) & 0x01;
1341 if (*interfaceType == 0) { // basic rate
1342 if ( (bytes[0] & 0x04) == 0x04 ) { // D Channel
1343 *channelNumber = 0;
1345 else {
1346 if ( (bytes[0] & 0x03) == 0x03 ) { // any channel
1347 *channelNumber = -1;
1349 else { // B Channel
1350 *channelNumber = (bytes[0] & 0x03);
1355 if (*interfaceType == 1) { // primary rate
1356 if ( (bytes[0] & 0x04) == 0x04 ) { // D Channel
1357 *channelNumber = 0;
1359 else {
1360 if ( (bytes[0] & 0x03) == 0x03 ) { // any channel
1361 *channelNumber = -1;
1363 else { // B Channel
1364 if (bytes.GetSize() < 3)
1365 return FALSE;
1367 if (bytes[1] != 0x83)
1368 return FALSE;
1370 *channelNumber = bytes[2] & 0x7f;
1375 return TRUE;
1379 /////////////////////////////////////////////////////////////////////////////