1 /*
2  * h224.cxx
3  *
4  * H.224 implementation for the OpenH323 Project.
5  *
6  * Copyright (c) 2006 Network for Educational Technology, ETH Zurich.
7  * Written by Hannes Friederich.
8  *
9  * The contents of this file are subject to the Mozilla Public License
10  * Version 1.0 (the "License"); you may not use this file except in
11  * compliance with the License. You may obtain a copy of the License at
12  * http://www.mozilla.org/MPL/
13  *
14  * Software distributed under the License is distributed on an "AS IS"
15  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
16  * the License for the specific language governing rights and limitations
17  * under the License.
18  *
19  * Contributor(s): ______________________________________.
20  *
21  * $Revision: 27149 $
22  * $Author: rjongbloed $
23  * $Date: 2012-03-07 18:32:36 -0600 (Wed, 07 Mar 2012) $
24  */
25 
26 /*
27   This file implements H.224 as part of H.323, as well as RFC 4573 for H.224 over SIP
28  */
29 
30 #include <ptlib.h>
31 
32 #include <opal/buildopts.h>
33 
34 #ifdef __GNUC__
35 #pragma implementation "h224.h"
36 #pragma implementation "h224handler.h"
37 #endif
38 
39 #if OPAL_HAS_H224
40 
41 #include <h224/h224.h>
42 #include <h224/h224handler.h>
43 
44 #if OPAL_SIP
45 #include <sip/sdp.h>
46 #endif
47 
48 #define H224_MAX_HEADER_SIZE 6+5
49 
50 /////////////////////////////////////////////////////////////////////////
51 
52 OPAL_INSTANTIATE_MEDIATYPE(h224, OpalH224MediaType);
53 
OpalH224MediaType()54 OpalH224MediaType::OpalH224MediaType()
55   : OpalRTPAVPMediaType("h224", "application")
56 {
57 }
58 
MediaType()59 const OpalMediaType & OpalH224MediaType::MediaType()
60 {
61   static const OpalMediaType type = "h224";
62   return type;
63 }
64 
65 #if OPAL_SIP
66 
67 class SDPH224MediaDescription : public SDPRTPAVPMediaDescription
68 {
69   PCLASSINFO(SDPH224MediaDescription, SDPRTPAVPMediaDescription);
70   public:
SDPH224MediaDescription(const OpalTransportAddress & address)71     SDPH224MediaDescription(const OpalTransportAddress & address)
72       : SDPRTPAVPMediaDescription(address, OpalH224MediaType::MediaType())
73     {
74     }
75 
CreateEmpty() const76     virtual SDPMediaDescription * CreateEmpty() const
77     {
78       return new SDPH224MediaDescription(OpalTransportAddress());
79     }
80 
GetSDPMediaType() const81     virtual PString GetSDPMediaType() const
82     {
83       return "application";
84     }
85 };
86 
CreateSDPMediaDescription(const OpalTransportAddress & localAddress)87 SDPMediaDescription * OpalH224MediaType::CreateSDPMediaDescription(const OpalTransportAddress & localAddress)
88 {
89   return new SDPH224MediaDescription(localAddress);
90 }
91 
92 #endif
93 
94 /////////////////////////////////////////////////////////////////////////
95 
GetOpalH224_H323AnnexQ()96 const OpalMediaFormat & GetOpalH224_H323AnnexQ()
97 {
98   static class H224_AnnexQ_MediaFormat : public OpalH224MediaFormat {
99     public:
100       H224_AnnexQ_MediaFormat()
101         : OpalH224MediaFormat("H.224/H323AnnexQ", RTP_DataFrame::DynamicBase)
102       {
103         OpalMediaOption * option = new OpalMediaOptionBoolean("HDLC Tunneling", true, OpalMediaOption::MinMerge, false);
104         AddOption(option);
105       }
106   } const h224q;
107   return h224q;
108 };
109 
GetOpalH224_HDLCTunneling()110 const OpalMediaFormat & GetOpalH224_HDLCTunneling()
111 {
112   static class H224_HDLCTunneling_MediaFormat : public OpalH224MediaFormat {
113     public:
114       H224_HDLCTunneling_MediaFormat()
115         : OpalH224MediaFormat("H.224/HDLCTunneling", RTP_DataFrame::MaxPayloadType)    // HDLC tunnelled is not sent over RTP
116       {
117         OpalMediaOption * option = new OpalMediaOptionBoolean("HDLC Tunneling", true, OpalMediaOption::MinMerge, true);
118         AddOption(option);
119       }
120   } const h224h;
121   return h224h;
122 }
123 
OpalH224MediaFormat(const char * fullName,RTP_DataFrame::PayloadTypes rtpPayloadType)124 OpalH224MediaFormat::OpalH224MediaFormat(
125       const char * fullName,                      ///<  Full name of media format
126       RTP_DataFrame::PayloadTypes rtpPayloadType  ///<  RTP payload type code
127   )
128   : OpalMediaFormat(fullName,
129                     "h224",
130                     rtpPayloadType,
131                     "h224",
132                     PFalse,
133                     6400,  // 6.4kbit/s as defined in RFC 4573
134                     0,
135                     0,
136                     4800,  // As defined in RFC 4573
137                     0)
138 {
139 }
140 
Clone() const141 PObject * OpalH224MediaFormat::Clone() const
142 {
143   return new OpalH224MediaFormat(*this);
144 }
145 
IsValidForProtocol(const PString & protocol) const146 PBoolean OpalH224MediaFormat::IsValidForProtocol(const PString & protocol) const
147 {
148   // HDLC tunnelling only makes sense for H.323. Everything else uses RTP;
149   return !GetOptionBoolean("HDLC Tunneling") || (protocol == "h323");
150 }
151 
152 /////////////////////////////////////////////////////////////////////////
153 
H224_Frame(PINDEX size)154 H224_Frame::H224_Frame(PINDEX size)
155 : Q922_Frame(H224_MAX_HEADER_SIZE + size)
156 {
157   SetHighPriority(PFalse);
158   SetControlFieldOctet(0x03); // UI-Mode
159   SetDestinationTerminalAddress(OpalH224Handler::Broadcast);
160   SetSourceTerminalAddress(OpalH224Handler::Broadcast);
161 
162   // setting Client ID to CME
163   SetClientID(OpalH224Client::CMEClientID);
164 
165   // Setting ES / BS / C1 / C0 / Segment number to zero
166   SetBS(PFalse);
167   SetES(PFalse);
168   SetC1(PFalse);
169   SetC0(PFalse);
170   SetSegmentNumber(0x00);
171 
172   SetClientDataSize(size);
173 }
174 
H224_Frame(const OpalH224Client & h224Client,PINDEX size)175 H224_Frame::H224_Frame(const OpalH224Client & h224Client, PINDEX size)
176 : Q922_Frame(H224_MAX_HEADER_SIZE + size)
177 {
178   SetHighPriority(PFalse);
179   SetControlFieldOctet(0x03); // UI-Mode
180   SetDestinationTerminalAddress(OpalH224Handler::Broadcast);
181   SetSourceTerminalAddress(OpalH224Handler::Broadcast);
182 
183   SetClient(h224Client);
184 
185   // Setting ES / BS / C1 / C0 / Segment number to zero
186   SetBS(PFalse);
187   SetES(PFalse);
188   SetC1(PFalse);
189   SetC0(PFalse);
190   SetSegmentNumber(0x00);
191 
192   SetClientDataSize(size);
193 }
194 
~H224_Frame()195 H224_Frame::~H224_Frame()
196 {
197 }
198 
SetHighPriority(PBoolean flag)199 void H224_Frame::SetHighPriority(PBoolean flag)
200 {
201   SetHighOrderAddressOctet(0x00);
202 
203   if (flag) {
204     SetLowOrderAddressOctet(0x71);
205   } else {
206     SetLowOrderAddressOctet(0x061);
207   }
208 }
209 
GetDestinationTerminalAddress() const210 WORD H224_Frame::GetDestinationTerminalAddress() const
211 {
212   BYTE *data = GetInformationFieldPtr();
213   return (WORD)((data[0] << 8) | data[1]);
214 }
215 
SetDestinationTerminalAddress(WORD address)216 void H224_Frame::SetDestinationTerminalAddress(WORD address)
217 {
218   BYTE *data = GetInformationFieldPtr();
219   data[0] = (BYTE)(address >> 8);
220   data[1] = (BYTE) address;
221 }
222 
GetSourceTerminalAddress() const223 WORD H224_Frame::GetSourceTerminalAddress() const
224 {
225   BYTE *data = GetInformationFieldPtr();
226   return (WORD)((data[2] << 8) | data[3]);
227 }
228 
SetSourceTerminalAddress(WORD address)229 void H224_Frame::SetSourceTerminalAddress(WORD address)
230 {
231   BYTE *data = GetInformationFieldPtr();
232   data[2] = (BYTE)(address >> 8);
233   data[3] = (BYTE) address;
234 }
235 
SetClient(const OpalH224Client & h224Client)236 void H224_Frame::SetClient(const OpalH224Client & h224Client)
237 {
238   BYTE clientID = h224Client.GetClientID();
239 
240   SetClientID(clientID);
241 
242   if (clientID == OpalH224Client::ExtendedClientID) {
243     SetExtendedClientID(h224Client.GetExtendedClientID());
244 
245   } else if (clientID == OpalH224Client::NonStandardClientID) {
246     SetNonStandardClientInformation(h224Client.GetCountryCode(),
247                                     h224Client.GetCountryCodeExtension(),
248                                     h224Client.GetManufacturerCode(),
249                                     h224Client.GetManufacturerClientID());
250   }
251 }
252 
GetClientID() const253 BYTE H224_Frame::GetClientID() const
254 {
255   BYTE *data = GetInformationFieldPtr();
256   return data[4] & 0x7f;
257 }
258 
SetClientID(BYTE clientID)259 void H224_Frame::SetClientID(BYTE clientID)
260 {
261 	BYTE *data = GetInformationFieldPtr();
262   data[4] = (clientID & 0x7f);
263 }
264 
GetExtendedClientID() const265 BYTE H224_Frame::GetExtendedClientID() const
266 {
267   if (GetClientID() != OpalH224Client::ExtendedClientID) {
268     return 0x00;
269   }
270 
271   BYTE *data = GetInformationFieldPtr();
272   return data[5];
273 }
274 
SetExtendedClientID(BYTE extendedClientID)275 void H224_Frame::SetExtendedClientID(BYTE extendedClientID)
276 {
277   if (GetClientID() != OpalH224Client::ExtendedClientID) {
278     return;
279   }
280 
281   BYTE *data = GetInformationFieldPtr();
282   data[5] = extendedClientID;
283 }
284 
GetCountryCode() const285 BYTE H224_Frame::GetCountryCode() const
286 {
287   if (GetClientID() != OpalH224Client::NonStandardClientID) {
288     return 0x00;
289   }
290 
291   BYTE *data = GetInformationFieldPtr();
292   return data[5];
293 }
294 
GetCountryCodeExtension() const295 BYTE H224_Frame::GetCountryCodeExtension() const
296 {
297   if (GetClientID() != OpalH224Client::NonStandardClientID) {
298     return 0x00;
299   }
300 
301   BYTE *data = GetInformationFieldPtr();
302   return data[6];
303 }
304 
GetManufacturerCode() const305 WORD H224_Frame::GetManufacturerCode() const
306 {
307   if (GetClientID() != OpalH224Client::NonStandardClientID) {
308     return 0x0000;
309   }
310 
311   BYTE *data = GetInformationFieldPtr();
312   return (((WORD)data[7] << 8) | (WORD)data[8]);
313 }
314 
GetManufacturerClientID() const315 BYTE H224_Frame::GetManufacturerClientID() const
316 {
317   if (GetClientID() != OpalH224Client::NonStandardClientID) {
318     return 0x00;
319   }
320 
321   BYTE *data = GetInformationFieldPtr();
322   return data[9];
323 }
324 
SetNonStandardClientInformation(BYTE countryCode,BYTE countryCodeExtension,WORD manufacturerCode,BYTE manufacturerClientID)325 void H224_Frame::SetNonStandardClientInformation(BYTE countryCode,
326                                                  BYTE countryCodeExtension,
327                                                  WORD manufacturerCode,
328                                                  BYTE manufacturerClientID)
329 {
330   if (GetClientID() != OpalH224Client::NonStandardClientID) {
331     return;
332   }
333 
334   BYTE *data = GetInformationFieldPtr();
335 
336   data[5] = countryCode;
337   data[6] = countryCodeExtension;
338   data[7] = (BYTE)(manufacturerCode << 8);
339   data[8] = (BYTE) manufacturerCode;
340   data[9] = manufacturerClientID;
341 }
342 
GetBS() const343 PBoolean H224_Frame::GetBS() const
344 {
345   BYTE *data = GetInformationFieldPtr();
346 
347   return (data[5] & 0x80) != 0;
348 }
349 
SetBS(PBoolean flag)350 void H224_Frame::SetBS(PBoolean flag)
351 {
352   BYTE *data = GetInformationFieldPtr();
353 
354   if (flag) {
355     data[5] |= 0x80;
356   }	else {
357     data[5] &= 0x7f;
358   }
359 }
360 
GetES() const361 PBoolean H224_Frame::GetES() const
362 {
363   BYTE *data = GetInformationFieldPtr();
364 
365   return (data[5] & 0x40) != 0;
366 }
367 
SetES(PBoolean flag)368 void H224_Frame::SetES(PBoolean flag)
369 {
370   BYTE *data = GetInformationFieldPtr();
371 
372   if (flag) {
373     data[5] |= 0x40;
374   } else {
375     data[5] &= 0xbf;
376   }
377 }
378 
GetC1() const379 PBoolean H224_Frame::GetC1() const
380 {
381   BYTE *data = GetInformationFieldPtr();
382 
383   return (data[5] & 0x20) != 0;
384 }
385 
SetC1(PBoolean flag)386 void H224_Frame::SetC1(PBoolean flag)
387 {
388   BYTE *data = GetInformationFieldPtr();
389 
390   if (flag) {
391     data[5] |= 0x20;
392   } else {
393     data[5] &= 0xdf;
394   }
395 }
396 
GetC0() const397 PBoolean H224_Frame::GetC0() const
398 {
399   BYTE *data = GetInformationFieldPtr();
400 
401   return (data[5] & 0x10) != 0;
402 }
403 
SetC0(PBoolean flag)404 void H224_Frame::SetC0(PBoolean flag)
405 {
406   BYTE *data = GetInformationFieldPtr();
407 
408   if (flag) {
409     data[5] |= 0x10;
410   }	else {
411     data[5] &= 0xef;
412   }
413 }
414 
GetSegmentNumber() const415 BYTE H224_Frame::GetSegmentNumber() const
416 {
417   BYTE *data = GetInformationFieldPtr();
418 
419   return (data[5] & 0x0f);
420 }
421 
SetSegmentNumber(BYTE segmentNumber)422 void H224_Frame::SetSegmentNumber(BYTE segmentNumber)
423 {
424   BYTE *data = GetInformationFieldPtr();
425 
426   data[5] &= 0xf0;
427   data[5] |= (segmentNumber & 0x0f);
428 }
429 
GetClientDataPtr() const430 BYTE * H224_Frame::GetClientDataPtr() const
431 {
432   BYTE * data = GetInformationFieldPtr();
433   return (data + GetHeaderSize());
434 }
435 
GetClientDataSize() const436 PINDEX H224_Frame::GetClientDataSize() const
437 {
438   PINDEX size = GetInformationFieldSize();
439   return (size - GetHeaderSize());
440 }
441 
SetClientDataSize(PINDEX size)442 void H224_Frame::SetClientDataSize(PINDEX size)
443 {
444   SetInformationFieldSize(size + GetHeaderSize());
445 }
446 
DecodeAnnexQ(const BYTE * data,PINDEX size)447 PBoolean H224_Frame::DecodeAnnexQ(const BYTE *data, PINDEX size)
448 {
449   PBoolean result = Q922_Frame::DecodeAnnexQ(data, size);
450 
451   if (result == PFalse) {
452     return PFalse;
453   }
454 
455   // doing some validity checks for H.224 frames
456   BYTE highOrderAddressOctet = GetHighOrderAddressOctet();
457   BYTE lowOrderAddressOctet = GetLowOrderAddressOctet();
458   BYTE controlFieldOctet = GetControlFieldOctet();
459 
460   if ((highOrderAddressOctet != 0x00) ||
461       (!(lowOrderAddressOctet == 0x61 || lowOrderAddressOctet == 0x71)) ||
462       (controlFieldOctet != 0x03)) {
463 	  return PFalse;
464   }
465 
466   return PTrue;
467 
468 }
469 
DecodeHDLC(const BYTE * data,PINDEX size)470 PBoolean H224_Frame::DecodeHDLC(const BYTE *data, PINDEX size)
471 {
472   PBoolean result = Q922_Frame::DecodeHDLC(data, size);
473 
474   if (result == PFalse) {
475     return PFalse;
476   }
477 
478   // doing some validity checks for H.224 frames
479   BYTE highOrderAddressOctet = GetHighOrderAddressOctet();
480   BYTE lowOrderAddressOctet = GetLowOrderAddressOctet();
481   BYTE controlFieldOctet = GetControlFieldOctet();
482 
483   if ((highOrderAddressOctet != 0x00) ||
484      (!(lowOrderAddressOctet == 0x61 || lowOrderAddressOctet == 0x71)) ||
485      (controlFieldOctet != 0x03)) {
486 	  return PFalse;
487   }
488 
489   return PTrue;
490 }
491 
GetHeaderSize() const492 PINDEX H224_Frame::GetHeaderSize() const
493 {
494   BYTE clientID = GetClientID();
495 
496   if (clientID < OpalH224Client::ExtendedClientID) {
497     return 6;
498   } else if (clientID == OpalH224Client::ExtendedClientID) {
499     return 7; // one extra octet
500   } else {
501     return 11; // 5 extra octets
502   }
503 }
504 
505 ////////////////////////////////////
506 
OpalH224Handler()507 OpalH224Handler::OpalH224Handler()
508 : transmitMutex(),
509   transmitFrame(300),
510   receiveFrame()
511 {
512   canTransmit = PFalse;
513   transmitBitIndex = 7;
514   transmitStartTime = NULL;
515   transmitMediaStream = NULL;
516 
517   transmitHDLCTunneling = PFalse;
518   receiveHDLCTunneling = PFalse;
519 
520   clients.DisallowDeleteObjects();
521 }
522 
~OpalH224Handler()523 OpalH224Handler::~OpalH224Handler()
524 {
525 }
526 
AddClient(OpalH224Client & client)527 PBoolean OpalH224Handler::AddClient(OpalH224Client & client)
528 {
529   if (client.GetClientID() == OpalH224Client::CMEClientID) {
530     return PFalse; // No client may have CMEClientID
531   }
532 
533   if (clients.GetObjectsIndex(&client) != P_MAX_INDEX) {
534     return PFalse; // Only allow one instance of a client
535   }
536 
537   clients.Append(&client);
538   client.SetH224Handler(this);
539   return PTrue;
540 }
541 
RemoveClient(OpalH224Client & client)542 PBoolean OpalH224Handler::RemoveClient(OpalH224Client & client)
543 {
544   PBoolean result = clients.Remove(&client);
545   if (result == PTrue) {
546     client.SetH224Handler(NULL);
547   }
548   return result;
549 }
550 
SetTransmitMediaFormat(const OpalMediaFormat & mediaFormat)551 void OpalH224Handler::SetTransmitMediaFormat(const OpalMediaFormat & mediaFormat)
552 {
553   PAssert(mediaFormat.GetMediaType() == "h224", "H.224 handler passed incorrect media format");
554   transmitHDLCTunneling = mediaFormat.GetOptionBoolean("HDLC Tunneling");
555 }
556 
SetReceiveMediaFormat(const OpalMediaFormat & mediaFormat)557 void OpalH224Handler::SetReceiveMediaFormat(const OpalMediaFormat & mediaFormat)
558 {
559   PAssert(mediaFormat.GetMediaType() == "h224", "H.224 handler passed incorrect media format");
560   receiveHDLCTunneling = mediaFormat.GetOptionBoolean("HDLC Tunneling");
561 }
562 
SetTransmitMediaStream(OpalH224MediaStream * mediaStream)563 void OpalH224Handler::SetTransmitMediaStream(OpalH224MediaStream * mediaStream)
564 {
565   PWaitAndSignal m(transmitMutex);
566 
567   transmitMediaStream = mediaStream;
568 
569   if (transmitMediaStream != NULL) {
570     transmitFrame.SetPayloadType(transmitMediaStream->GetMediaFormat().GetPayloadType());
571   }
572 }
573 
StartTransmit()574 void OpalH224Handler::StartTransmit()
575 {
576   PWaitAndSignal m(transmitMutex);
577 
578   if (canTransmit == PTrue) {
579     return;
580   }
581 
582   canTransmit = PTrue;
583 
584   transmitBitIndex = 7;
585   transmitStartTime = new PTime();
586 
587   SendClientList();
588   SendExtraCapabilities();
589 }
590 
StopTransmit()591 void OpalH224Handler::StopTransmit()
592 {
593   PWaitAndSignal m(transmitMutex);
594 
595   if (canTransmit == PFalse) {
596     return;
597   }
598 
599   delete transmitStartTime;
600   transmitStartTime = NULL;
601 
602   canTransmit = PFalse;
603 }
604 
SendClientList()605 PBoolean OpalH224Handler::SendClientList()
606 {
607   PWaitAndSignal m(transmitMutex);
608 
609   if (canTransmit == PFalse) {
610     return PFalse;
611   }
612 
613   // If all clients are non-standard, 5 octets per clients + 3 octets header information
614   H224_Frame h224Frame = H224_Frame(5*clients.GetSize() + 3);
615 
616   h224Frame.SetHighPriority(PTrue);
617   h224Frame.SetDestinationTerminalAddress(Broadcast);
618   h224Frame.SetSourceTerminalAddress(Broadcast);
619 
620   // CME frame
621   h224Frame.SetClientID(OpalH224Client::CMEClientID);
622 
623   // Begin and end of sequence
624   h224Frame.SetBS(PTrue);
625   h224Frame.SetES(PTrue);
626   h224Frame.SetC1(PFalse);
627   h224Frame.SetC0(PFalse);
628   h224Frame.SetSegmentNumber(0);
629 
630   BYTE *ptr = h224Frame.GetClientDataPtr();
631 
632   ptr[0] = OpalH224Handler::CMEClientListCode;
633   ptr[1] = OpalH224Handler::CMEMessage;
634   ptr[2] = (BYTE)clients.GetSize();
635 
636   PINDEX dataIndex = 3;
637   for (PINDEX i = 0; i < clients.GetSize(); i++) {
638     OpalH224Client & client = clients[i];
639 
640     BYTE clientID = client.GetClientID();
641 
642     if (client.HasExtraCapabilities()) {
643       ptr[dataIndex] = (0x80 | clientID);
644     } else {
645       ptr[dataIndex] = (0x7f & clientID);
646     }
647     dataIndex++;
648 
649     if (clientID == OpalH224Client::ExtendedClientID) {
650       ptr[dataIndex] = client.GetExtendedClientID();
651       dataIndex++;
652 
653     } else if (clientID == OpalH224Client::NonStandardClientID) {
654 
655       ptr[dataIndex] = client.GetCountryCode();
656       dataIndex++;
657       ptr[dataIndex] = client.GetCountryCodeExtension();
658       dataIndex++;
659 
660       WORD manufacturerCode = client.GetManufacturerCode();
661       ptr[dataIndex] = (BYTE)(manufacturerCode >> 8);
662       dataIndex++;
663       ptr[dataIndex] = (BYTE) manufacturerCode;
664       dataIndex++;
665 
666       ptr[dataIndex] = client.GetManufacturerClientID();
667       dataIndex++;
668     }
669   }
670 
671   h224Frame.SetClientDataSize(dataIndex);
672 
673   TransmitFrame(h224Frame);
674 
675   return PTrue;
676 }
677 
SendExtraCapabilities()678 PBoolean OpalH224Handler::SendExtraCapabilities()
679 {
680   for (PINDEX i = 0; i < clients.GetSize(); i++) {
681     OpalH224Client & client = clients[i];
682     client.SendExtraCapabilities();
683   }
684 
685   return PTrue;
686 }
687 
SendClientListCommand()688 PBoolean OpalH224Handler::SendClientListCommand()
689 {
690   PWaitAndSignal m(transmitMutex);
691 
692   if (canTransmit == PFalse) {
693     return PFalse;
694   }
695 
696   H224_Frame h224Frame = H224_Frame(2);
697   h224Frame.SetHighPriority(PTrue);
698   h224Frame.SetDestinationTerminalAddress(OpalH224Handler::Broadcast);
699   h224Frame.SetSourceTerminalAddress(OpalH224Handler::Broadcast);
700 
701   // CME frame
702   h224Frame.SetClientID(OpalH224Client::CMEClientID);
703 
704   // Begin and end of sequence
705   h224Frame.SetBS(PTrue);
706   h224Frame.SetES(PTrue);
707   h224Frame.SetC1(PFalse);
708   h224Frame.SetC0(PFalse);
709   h224Frame.SetSegmentNumber(0);
710 
711   BYTE *ptr = h224Frame.GetClientDataPtr();
712 
713   ptr[0] = OpalH224Handler::CMEClientListCode;
714   ptr[1] = OpalH224Handler::CMECommand;
715 
716   TransmitFrame(h224Frame);
717 
718   return PTrue;
719 }
720 
SendExtraCapabilitiesCommand(const OpalH224Client & client)721 PBoolean OpalH224Handler::SendExtraCapabilitiesCommand(const OpalH224Client & client)
722 {
723   PWaitAndSignal m(transmitMutex);
724 
725   if (canTransmit == PFalse) {
726     return PFalse;
727   }
728 
729   if (clients.GetObjectsIndex(&client) == P_MAX_INDEX) {
730     return PFalse; // only allow if the client is really registered
731   }
732 
733   H224_Frame h224Frame = H224_Frame(8);
734   h224Frame.SetHighPriority(PTrue);
735   h224Frame.SetDestinationTerminalAddress(OpalH224Handler::Broadcast);
736   h224Frame.SetSourceTerminalAddress(OpalH224Handler::Broadcast);
737 
738   // CME frame
739   h224Frame.SetClientID(OpalH224Client::CMEClientID);
740 
741   // Begin and end of sequence
742   h224Frame.SetBS(PTrue);
743   h224Frame.SetES(PTrue);
744   h224Frame.SetC1(PFalse);
745   h224Frame.SetC0(PFalse);
746   h224Frame.SetSegmentNumber(0);
747 
748   BYTE *ptr = h224Frame.GetClientDataPtr();
749 
750   ptr[0] = OpalH224Handler::CMEExtraCapabilitiesCode;
751   ptr[1] = OpalH224Handler::CMECommand;
752 
753   PINDEX dataSize;
754 
755   BYTE extendedCapabilitiesFlag = client.HasExtraCapabilities() ? 0x80 : 0x00;
756   BYTE clientID = client.GetClientID();
757   ptr[2] = (extendedCapabilitiesFlag | (clientID & 0x7f));
758 
759   if (clientID < OpalH224Client::ExtendedClientID) {
760     dataSize = 3;
761   } else if (clientID == OpalH224Client::ExtendedClientID) {
762     ptr[3] = client.GetExtendedClientID();
763     dataSize = 4;
764   } else {
765     ptr[3] = client.GetCountryCode();
766     ptr[4] = client.GetCountryCodeExtension();
767 
768     WORD manufacturerCode = client.GetManufacturerCode();
769     ptr[5] = (BYTE)(manufacturerCode >> 8);
770     ptr[6] = (BYTE) manufacturerCode;
771 
772     ptr[7] = client.GetManufacturerClientID();
773     dataSize = 8;
774   }
775   h224Frame.SetClientDataSize(dataSize);
776 
777   TransmitFrame(h224Frame);
778 
779   return PTrue;
780 }
781 
SendExtraCapabilitiesMessage(const OpalH224Client & client,BYTE * data,PINDEX length)782 PBoolean OpalH224Handler::SendExtraCapabilitiesMessage(const OpalH224Client & client,
783                                                        BYTE *data, PINDEX length)
784 {
785   PWaitAndSignal m(transmitMutex);
786 
787   if (clients.GetObjectsIndex(&client) == P_MAX_INDEX) {
788     return PFalse; // Only allow if the client is really registered
789   }
790 
791   H224_Frame h224Frame = H224_Frame(length+3);
792   h224Frame.SetHighPriority(PTrue);
793   h224Frame.SetDestinationTerminalAddress(OpalH224Handler::Broadcast);
794   h224Frame.SetSourceTerminalAddress(OpalH224Handler::Broadcast);
795 
796   // use clientID zero to indicate a CME frame
797   h224Frame.SetClientID(OpalH224Client::CMEClientID);
798 
799   // Begin and end of sequence, rest is zero
800   h224Frame.SetBS(PTrue);
801   h224Frame.SetES(PTrue);
802   h224Frame.SetC1(PFalse);
803   h224Frame.SetC0(PFalse);
804   h224Frame.SetSegmentNumber(0);
805 
806   BYTE *ptr = h224Frame.GetClientDataPtr();
807 
808   ptr[0] = CMEExtraCapabilitiesCode;
809   ptr[1] = CMEMessage;
810 
811   PINDEX headerSize;
812   BYTE clientID = client.GetClientID();
813   BYTE extendedCapabilitiesFlag = client.HasExtraCapabilities() ? 0x80 : 0x00;
814 
815   ptr[2] = (extendedCapabilitiesFlag | (clientID & 0x7f));
816 
817   if (clientID < OpalH224Client::ExtendedClientID) {
818     headerSize = 3;
819   } else if (clientID == OpalH224Client::ExtendedClientID) {
820     ptr[3] = client.GetExtendedClientID();
821     headerSize = 4;
822   } else {
823     ptr[3] = client.GetCountryCode();
824     ptr[4] = client.GetCountryCodeExtension();
825 
826     WORD manufacturerCode = client.GetManufacturerCode();
827     ptr[5] = (BYTE) (manufacturerCode >> 8);
828     ptr[6] = (BYTE) manufacturerCode;
829 
830     ptr[7] = client.GetManufacturerClientID();
831     headerSize = 8;
832   }
833 
834   h224Frame.SetClientDataSize(length+headerSize);
835   memcpy(ptr+headerSize, data, length);
836 
837   TransmitFrame(h224Frame);
838 
839   return PTrue;
840 }
841 
TransmitClientFrame(const OpalH224Client & client,H224_Frame & frame)842 PBoolean OpalH224Handler::TransmitClientFrame(const OpalH224Client & client, H224_Frame & frame)
843 {
844   PWaitAndSignal m(transmitMutex);
845 
846   if (canTransmit == PFalse) {
847     return PFalse;
848   }
849 
850   if (clients.GetObjectsIndex(&client) == P_MAX_INDEX) {
851     return PFalse; // Only allow if the client is really registered
852   }
853 
854   TransmitFrame(frame);
855 
856   return PTrue;
857 }
858 
OnReceivedFrame(H224_Frame & frame)859 PBoolean OpalH224Handler::OnReceivedFrame(H224_Frame & frame)
860 {
861   if (frame.GetDestinationTerminalAddress() != OpalH224Handler::Broadcast) {
862     // only broadcast frames are handled at the moment
863     PTRACE(3, "H.224\tReceived frame with non-broadcast address");
864     return PTrue;
865   }
866   BYTE clientID = frame.GetClientID();
867 
868   if (clientID == OpalH224Client::CMEClientID) {
869     return OnReceivedCMEMessage(frame);
870   }
871 
872   for (PINDEX i = 0; i < clients.GetSize(); i++) {
873     OpalH224Client & client = clients[i];
874     if (client.GetClientID() == clientID) {
875       PBoolean found = PFalse;
876       if (clientID < OpalH224Client::ExtendedClientID) {
877         found = PTrue;
878       } else if (clientID == OpalH224Client::ExtendedClientID) {
879         if (client.GetExtendedClientID() == frame.GetExtendedClientID()) {
880           found = PTrue;
881         }
882       } else {
883         if (client.GetCountryCode() == frame.GetCountryCode() &&
884            client.GetCountryCodeExtension() == frame.GetCountryCodeExtension() &&
885            client.GetManufacturerCode() == frame.GetManufacturerCode() &&
886            client.GetManufacturerClientID() == frame.GetManufacturerClientID()) {
887           found = PTrue;
888         }
889       }
890       if (found == PTrue) {
891         client.OnReceivedMessage(frame);
892         return PTrue;
893       }
894     }
895   }
896 
897   // ignore if no client found
898 
899   return PTrue;
900 }
901 
OnReceivedCMEMessage(H224_Frame & frame)902 PBoolean OpalH224Handler::OnReceivedCMEMessage(H224_Frame & frame)
903 {
904   BYTE *data = frame.GetClientDataPtr();
905 
906   if (data[0] == CMEClientListCode) {
907 
908     if (data[1] == CMEMessage) {
909       return OnReceivedClientList(frame);
910 
911     } else if (data[1] == CMECommand) {
912       return OnReceivedClientListCommand();
913     }
914 
915   } else if (data[0] == CMEExtraCapabilitiesCode) {
916 
917     if (data[1] == CMEMessage) {
918       return OnReceivedExtraCapabilities(frame);
919 
920     } else if (data[1] == CMECommand) {
921       return OnReceivedExtraCapabilitiesCommand();
922     }
923   }
924 
925   // incorrect frames are simply ignored
926   return PTrue;
927 }
928 
OnReceivedClientList(H224_Frame & frame)929 PBoolean OpalH224Handler::OnReceivedClientList(H224_Frame & frame)
930 {
931   // First, reset all clients
932   for (PINDEX i = 0; i < clients.GetSize(); i++)
933   {
934     OpalH224Client & client = clients[i];
935     client.SetRemoteClientAvailable(PFalse, PFalse);
936   }
937 
938   BYTE *data = frame.GetClientDataPtr();
939 
940   BYTE numberOfClients = data[2];
941 
942   PINDEX dataIndex = 3;
943 
944   while (numberOfClients > 0) {
945 
946     BYTE clientID = (data[dataIndex] & 0x7f);
947     PBoolean hasExtraCapabilities = (data[dataIndex] & 0x80) != 0 ? PTrue: PFalse;
948     dataIndex++;
949     BYTE extendedClientID = 0x00;
950     BYTE countryCode = CountryCodeEscape;
951     BYTE countryCodeExtension = 0x00;
952     WORD manufacturerCode = 0x0000;
953     BYTE manufacturerClientID = 0x00;
954 
955     if (clientID == OpalH224Client::ExtendedClientID) {
956       extendedClientID = data[dataIndex];
957       dataIndex++;
958     } else if (clientID == OpalH224Client::NonStandardClientID) {
959       countryCode = data[dataIndex];
960       dataIndex++;
961       countryCodeExtension = data[dataIndex];
962       dataIndex++;
963       manufacturerCode = (((WORD)data[dataIndex] << 8) | (WORD)data[dataIndex+1]);
964       dataIndex += 2;
965       manufacturerClientID = data[dataIndex];
966       dataIndex++;
967     }
968 
969     for (PINDEX i = 0; i < clients.GetSize(); i++) {
970       OpalH224Client & client = clients[i];
971       PBoolean found = PFalse;
972       if (client.GetClientID() == clientID) {
973         if (clientID < OpalH224Client::ExtendedClientID) {
974           found = PTrue;
975         } else if (clientID == OpalH224Client::ExtendedClientID) {
976           if (client.GetExtendedClientID() == extendedClientID) {
977             found = PTrue;
978           }
979         } else {
980           if (client.GetCountryCode() == countryCode &&
981              client.GetCountryCodeExtension() == countryCodeExtension &&
982              client.GetManufacturerCode() == manufacturerCode &&
983              client.GetManufacturerClientID() == manufacturerClientID) {
984             found = PTrue;
985           }
986         }
987       }
988       if (found == PTrue) {
989         client.SetRemoteClientAvailable(PTrue, hasExtraCapabilities);
990         break;
991       }
992     }
993     numberOfClients--;
994   }
995 
996 
997   return PTrue;
998 }
999 
OnReceivedClientListCommand()1000 PBoolean OpalH224Handler::OnReceivedClientListCommand()
1001 {
1002   SendClientList();
1003   return PTrue;
1004 }
1005 
OnReceivedExtraCapabilities(H224_Frame & frame)1006 PBoolean OpalH224Handler::OnReceivedExtraCapabilities(H224_Frame & frame)
1007 {
1008   BYTE *data = frame.GetClientDataPtr();
1009 
1010   BYTE clientID = (data[2] & 0x7f);
1011   PINDEX dataIndex = 0;
1012   BYTE extendedClientID = 0x00;
1013   BYTE countryCode = CountryCodeEscape;
1014   BYTE countryCodeExtension = 0x00;
1015   WORD manufacturerCode = 0x0000;
1016   BYTE manufacturerClientID = 0x00;
1017 
1018   if (clientID < OpalH224Client::ExtendedClientID) {
1019     dataIndex = 3;
1020   } else if (clientID == OpalH224Client::ExtendedClientID) {
1021     extendedClientID = data[3];
1022     dataIndex = 4;
1023   } else if (clientID == OpalH224Client::NonStandardClientID) {
1024     countryCode = data[3];
1025     countryCodeExtension = data[4];
1026     manufacturerCode = (((WORD)data[5] << 8) | (WORD)data[6]);
1027     manufacturerClientID = data[7];
1028     dataIndex = 8;
1029   }
1030 
1031   for (PINDEX i = 0; i < clients.GetSize(); i++) {
1032     OpalH224Client & client = clients[i];
1033     PBoolean found = PFalse;
1034     if (client.GetClientID() == clientID) {
1035       if (clientID < OpalH224Client::ExtendedClientID) {
1036         found = PTrue;
1037       } else if (clientID == OpalH224Client::ExtendedClientID) {
1038         if (client.GetExtendedClientID() == extendedClientID) {
1039           found = PTrue;
1040         }
1041       } else {
1042         if (client.GetCountryCode() == countryCode &&
1043            client.GetCountryCodeExtension() == countryCodeExtension &&
1044            client.GetManufacturerCode() == manufacturerCode &&
1045            client.GetManufacturerClientID() == manufacturerClientID) {
1046           found = PTrue;
1047         }
1048       }
1049     }
1050     if (found) {
1051       PINDEX size = frame.GetClientDataSize() - dataIndex;
1052       client.SetRemoteClientAvailable(PTrue, PTrue);
1053       client.OnReceivedExtraCapabilities((data + dataIndex), size);
1054       return PTrue;
1055     }
1056   }
1057 
1058   // Simply ignore if no client is available for this clientID
1059 
1060   return PTrue;
1061 }
1062 
OnReceivedExtraCapabilitiesCommand()1063 PBoolean OpalH224Handler::OnReceivedExtraCapabilitiesCommand()
1064 {
1065   SendExtraCapabilities();
1066   return PTrue;
1067 }
1068 
HandleFrame(const RTP_DataFrame & dataFrame)1069 PBoolean OpalH224Handler::HandleFrame(const RTP_DataFrame & dataFrame)
1070 {
1071   if (receiveHDLCTunneling) {
1072     if (receiveFrame.DecodeHDLC(dataFrame.GetPayloadPtr(), dataFrame.GetPayloadSize())) {
1073       PBoolean result = OnReceivedFrame(receiveFrame);
1074       return result;
1075     } else {
1076       PTRACE(1, "H224\tDecoding of the frame failed");
1077       return PFalse;
1078     }
1079   } else {
1080     if (receiveFrame.DecodeAnnexQ(dataFrame.GetPayloadPtr(), dataFrame.GetPayloadSize())) {
1081       PBoolean result = OnReceivedFrame(receiveFrame);
1082       return result;
1083     } else {
1084       PTRACE(1, "H224\tDecoding of the frame failed");
1085       return PFalse;
1086     }
1087   }
1088 }
1089 
TransmitFrame(H224_Frame & frame)1090 void OpalH224Handler::TransmitFrame(H224_Frame & frame)
1091 {
1092   PINDEX size;
1093   if (transmitHDLCTunneling) {
1094     size = frame.GetHDLCEncodedSize();
1095     transmitFrame.SetMinSize(size);
1096     if (!frame.EncodeHDLC(transmitFrame.GetPayloadPtr(), size, transmitBitIndex)) {
1097       PTRACE(1, "H224\tFailed to encode the frame");
1098       return;
1099     }
1100   } else {
1101     size = frame.GetAnnexQEncodedSize();
1102     transmitFrame.SetMinSize(size);
1103     if (!frame.EncodeAnnexQ(transmitFrame.GetPayloadPtr(), size)) {
1104       PTRACE(1, "H224\tFailed to encode the frame");
1105       return;
1106     }
1107   }
1108 
1109   // determining correct timestamp
1110   PTime currentTime = PTime();
1111   PTimeInterval timePassed = currentTime - *transmitStartTime;
1112   transmitFrame.SetTimestamp((DWORD)timePassed.GetMilliSeconds() * 8);
1113 
1114   transmitFrame.SetPayloadSize(size);
1115   transmitFrame.SetMarker(PTrue);
1116 
1117   if (transmitMediaStream != NULL) {
1118     transmitMediaStream->PushPacket(transmitFrame);
1119   }
1120 }
1121 
1122 ////////////////////////////////////
1123 
OpalH224MediaStream(OpalConnection & connection,OpalH224Handler & handler,const OpalMediaFormat & mediaFormat,unsigned sessionID,PBoolean isSource)1124 OpalH224MediaStream::OpalH224MediaStream(OpalConnection & connection,
1125                                          OpalH224Handler & handler,
1126                                          const OpalMediaFormat & mediaFormat,
1127                                          unsigned sessionID,
1128                                          PBoolean isSource)
1129 : OpalMediaStream(connection, mediaFormat, sessionID, isSource),
1130   h224Handler(handler)
1131 {
1132   if (isSource == PTrue) {
1133     h224Handler.SetTransmitMediaFormat(mediaFormat);
1134     h224Handler.SetTransmitMediaStream(this);
1135   } else {
1136     h224Handler.SetReceiveMediaFormat(mediaFormat);
1137   }
1138 }
1139 
~OpalH224MediaStream()1140 OpalH224MediaStream::~OpalH224MediaStream()
1141 {
1142   Close();
1143 }
1144 
OnStartMediaPatch()1145 void OpalH224MediaStream::OnStartMediaPatch()
1146 {
1147   h224Handler.StartTransmit();
1148   OpalMediaStream::OnStartMediaPatch();
1149 }
1150 
1151 
InternalClose()1152 void OpalH224MediaStream::InternalClose()
1153 {
1154   if (IsSource()) {
1155     h224Handler.StopTransmit();
1156     h224Handler.SetTransmitMediaStream(NULL);
1157   }
1158 }
1159 
1160 
ReadPacket(RTP_DataFrame &)1161 PBoolean OpalH224MediaStream::ReadPacket(RTP_DataFrame & /*packet*/)
1162 {
1163   return PFalse;
1164 }
1165 
WritePacket(RTP_DataFrame & packet)1166 PBoolean OpalH224MediaStream::WritePacket(RTP_DataFrame & packet)
1167 {
1168   return h224Handler.HandleFrame(packet);
1169 }
1170 
1171 ////////////////////////////////////
1172 
OpalH224Client()1173 OpalH224Client::OpalH224Client()
1174 {
1175   remoteClientAvailable = PFalse;
1176   remoteClientHasExtraCapabilities = PFalse;
1177   h224Handler = NULL;
1178 }
1179 
~OpalH224Client()1180 OpalH224Client::~OpalH224Client()
1181 {
1182 }
1183 
Compare(const PObject & obj)1184 PObject::Comparison OpalH224Client::Compare(const PObject & obj)
1185 {
1186   if (!PIsDescendant(&obj, OpalH224Client)) {
1187     return LessThan;
1188   }
1189 
1190   const OpalH224Client & otherClient = (const OpalH224Client &) obj;
1191 
1192   BYTE clientID = GetClientID();
1193   BYTE otherClientID = otherClient.GetClientID();
1194 
1195   if (clientID < otherClientID) {
1196     return LessThan;
1197   } else if (clientID > otherClientID) {
1198     return GreaterThan;
1199   }
1200 
1201   if (clientID < ExtendedClientID) {
1202     return EqualTo;
1203   }
1204 
1205   if (clientID == ExtendedClientID) {
1206     BYTE extendedClientID = GetExtendedClientID();
1207     BYTE otherExtendedClientID = otherClient.GetExtendedClientID();
1208 
1209     if (extendedClientID < otherExtendedClientID) {
1210       return LessThan;
1211     } else if (extendedClientID > otherExtendedClientID) {
1212       return GreaterThan;
1213     } else {
1214       return EqualTo;
1215     }
1216   }
1217 
1218   // Non-standard client.
1219   // Compare country code, extended country code, manufacturer code, manufacturer client ID
1220   BYTE countryCode = GetCountryCode();
1221   BYTE otherCountryCode = otherClient.GetCountryCode();
1222   if (countryCode < otherCountryCode) {
1223     return LessThan;
1224   } else if (countryCode > otherCountryCode) {
1225     return GreaterThan;
1226   }
1227 
1228   BYTE countryCodeExtension = GetCountryCodeExtension();
1229   BYTE otherCountryCodeExtension = otherClient.GetCountryCodeExtension();
1230   if (countryCodeExtension < otherCountryCodeExtension) {
1231     return LessThan;
1232   } else if (countryCodeExtension > otherCountryCodeExtension) {
1233     return GreaterThan;
1234   }
1235 
1236   WORD manufacturerCode = GetManufacturerCode();
1237   WORD otherManufacturerCode = otherClient.GetManufacturerCode();
1238   if (manufacturerCode < otherManufacturerCode) {
1239     return LessThan;
1240   } else if (manufacturerCode > otherManufacturerCode) {
1241     return GreaterThan;
1242   }
1243 
1244   BYTE manufacturerClientID = GetManufacturerClientID();
1245   BYTE otherManufacturerClientID = otherClient.GetManufacturerClientID();
1246 
1247   if (manufacturerClientID < otherManufacturerClientID) {
1248     return LessThan;
1249   } else if (manufacturerClientID > otherManufacturerClientID) {
1250     return GreaterThan;
1251   }
1252 
1253   return EqualTo;
1254 }
1255 
SetRemoteClientAvailable(PBoolean available,PBoolean hasExtraCapabilities)1256 void OpalH224Client::SetRemoteClientAvailable(PBoolean available, PBoolean hasExtraCapabilities)
1257 {
1258   remoteClientAvailable = available;
1259   remoteClientHasExtraCapabilities = hasExtraCapabilities;
1260 }
1261 
1262 #endif // OPAL_HAS_H224
1263