1 /*
2 *
3 * Inter Asterisk Exchange 2
4 *
5 * Implementation of the class that specifies frame construction.
6 *
7 * Open Phone Abstraction Library (OPAL)
8 *
9 * Copyright (c) 2005 Indranet Technologies Ltd.
10 *
11 * The contents of this file are subject to the Mozilla Public License
12 * Version 1.0 (the "License"); you may not use this file except in
13 * compliance with the License. You may obtain a copy of the License at
14 * http://www.mozilla.org/MPL/
15 *
16 * Software distributed under the License is distributed on an "AS IS"
17 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
18 * the License for the specific language governing rights and limitations
19 * under the License.
20 *
21 * The Original Code is Open Phone Abstraction Library.
22 *
23 * The Initial Developer of the Original Code is Indranet Technologies Ltd.
24 *
25 * The author of this code is Derek J Smithies
26 *
27 * $Revision: 24607 $
28 * $Author: dereksmithies $
29 * $Date: 2010-07-28 22:53:29 -0500 (Wed, 28 Jul 2010) $
30 */
31
32 #include <ptlib.h>
33 #include <opal/buildopts.h>
34
35 #if OPAL_IAX2
36
37 #ifdef P_USE_PRAGMA
38 #pragma implementation "frame.h"
39 #endif
40
41 #include <iax2/frame.h>
42
43 #include <iax2/iax2con.h>
44 #include <iax2/iax2ep.h>
45 #include <iax2/ies.h>
46 #include <iax2/receiver.h>
47 #include <iax2/transmit.h>
48
49 #include <ptclib/cypher.h>
50
51 #if OPAL_PTLIB_SSL_AES
52 #include <openssl/aes.h>
53 #ifdef _MSC_VER
54 #pragma comment(lib, P_SSL_LIB1)
55 #pragma comment(lib, P_SSL_LIB2)
56 #endif
57 #endif
58
59
60 #define new PNEW
61
62
IAX2Frame(IAX2EndPoint & _endpoint)63 IAX2Frame::IAX2Frame(IAX2EndPoint &_endpoint)
64 : endpoint(_endpoint)
65 {
66 ZeroAllValues();
67
68 PTRACE(6, "Frame\tConstruct IAX2Frame " << IdString());
69 }
70
~IAX2Frame()71 IAX2Frame::~IAX2Frame()
72 {
73 PTRACE(6, "Frame\tDestructor for IAX2Frame " << *this);
74 }
75
IdString() const76 PString IAX2Frame::IdString() const
77 {
78 PStringStream answer;
79 answer << PString("FR-ID#") << ::hex << this << ::dec;
80 return answer;
81 }
82
ZeroAllValues()83 void IAX2Frame::ZeroAllValues()
84 {
85 data.SetSize(0);
86
87 isFullFrame = PFalse;
88 isVideo = PFalse;
89 isAudio = PFalse;
90
91 currentReadIndex = 0;
92 currentWriteIndex = 0;
93 timeStamp = 0;
94
95 canRetransmitFrame = PFalse;
96 presetTimeStamp = 0;
97
98 frameType = undefType;
99 }
100
101
SetTimeStamp(DWORD newValue)102 void IAX2Frame::SetTimeStamp(DWORD newValue)
103 {
104 timeStamp = newValue;
105 presetTimeStamp = newValue;
106 PTRACE(5, "Frame\tPreset the timestamp to " << newValue);
107 }
108
ReadNetworkPacket(PUDPSocket & sock)109 PBoolean IAX2Frame::ReadNetworkPacket(PUDPSocket &sock)
110 {
111 data.SetSize(4096); //Surely no packets > 4096 bytes in length
112
113 WORD portNo;
114 PIPSocket::Address addr;
115 sock.GetLocalAddress(addr);
116
117 PBoolean res = sock.ReadFrom(data.GetPointer(), 4096, addr, portNo);
118 remote.SetRemoteAddress(addr);
119 remote.SetRemotePort(portNo);
120
121 if (res == PFalse) {
122 PTRACE(3, "Frame\tFailed in reading from socket");
123 return PFalse;
124 }
125
126 data.SetSize(sock.GetLastReadCount());
127
128 if (data.GetSize() < 4) {
129 PTRACE(3, "Frame\tRead a very very small packet from the network - < 4 bytes");
130 return PFalse;
131 }
132
133 return PTrue;
134 }
135
Read1Byte(BYTE & result)136 PBoolean IAX2Frame::Read1Byte(BYTE & result)
137 {
138 if (currentReadIndex >= data.GetSize())
139 return PFalse;
140
141 result = data[currentReadIndex];
142 currentReadIndex++;
143 return PTrue;
144 }
145
Read2Bytes(PINDEX & res)146 PBoolean IAX2Frame::Read2Bytes(PINDEX & res)
147 {
148 BYTE a = 0;
149 BYTE b = 0;
150 if (Read1Byte(a) && Read1Byte(b)) {
151 res = (a << 8) | b;
152 return PTrue;
153 }
154
155 return PFalse;
156 }
157
Read2Bytes(WORD & res)158 PBoolean IAX2Frame::Read2Bytes(WORD & res)
159 {
160 BYTE a = 0, b = 0;
161 if (Read1Byte(a) && Read1Byte(b)) {
162 res = (WORD)((a << 8) | b);
163 return PTrue;
164 }
165
166 return PFalse;
167 }
168
Read4Bytes(DWORD & res)169 PBoolean IAX2Frame::Read4Bytes(DWORD & res)
170 {
171 PINDEX a = 0, b = 0;
172 if (Read2Bytes(a) && Read2Bytes(b)) {
173 res = (a << 16) | b;
174 return PTrue;
175 }
176
177 return PFalse;
178 }
179
Write1Byte(PINDEX newVal)180 void IAX2Frame::Write1Byte(PINDEX newVal)
181 {
182 Write1Byte((BYTE)(newVal & 0xff));
183 }
184
Write1Byte(BYTE newVal)185 void IAX2Frame::Write1Byte(BYTE newVal)
186 {
187 if (currentWriteIndex >= data.GetSize())
188 data.SetSize(currentWriteIndex + 1);
189
190 data[currentWriteIndex] = newVal;
191 currentWriteIndex++;
192 }
193
Write2Bytes(PINDEX newVal)194 void IAX2Frame::Write2Bytes(PINDEX newVal)
195 {
196 BYTE a = (BYTE)(newVal >> 8);
197 BYTE b = (BYTE)(newVal & 0xff);
198
199 Write1Byte(a);
200 Write1Byte(b);
201 }
202
Write4Bytes(unsigned int newVal)203 void IAX2Frame::Write4Bytes(unsigned int newVal)
204 {
205 PINDEX a = newVal >> 16;
206 PINDEX b = newVal & 0xffff;
207
208 Write2Bytes(a);
209 Write2Bytes(b);
210 }
211
212
ProcessNetworkPacket()213 PBoolean IAX2Frame::ProcessNetworkPacket()
214 {
215 /*We are guaranteed to have a packet > 4 bytes in size */
216 PINDEX a = 0;
217 Read2Bytes(a);
218 PINDEX sourceCallNumber = a & 0x7fff;
219 remote.SetSourceCallNumber(sourceCallNumber);
220
221 if (sourceCallNumber > 1)
222 /*Call token frames have a source call number of 1 */
223 BuildConnectionToken();
224
225 if (a & 0x8000) {
226 isFullFrame = PTrue;
227 Read2Bytes(a);
228 remote.SetDestCallNumber(a & 0x7fff);
229 return PTrue;
230 }
231 if (a == 0) { //We have a mini frame here, of video type.
232 isVideo = PTrue;
233 PINDEX b = 0;
234 Read2Bytes(b);
235 remote.SetSourceCallNumber(b);
236 BuildConnectionToken();
237 return PTrue;
238 }
239
240 isAudio = PTrue;
241 return PTrue;
242 }
243
BuildConnectionToken()244 void IAX2Frame::BuildConnectionToken()
245 {
246 connectionToken = remote.BuildConnectionToken();
247 }
248
PrintOn(ostream & strm) const249 void IAX2Frame::PrintOn(ostream & strm) const
250 {
251 strm << IdString() << " " << data.GetSize() << " bytes " << endl;
252 }
253
BuildTimeStamp(const PTimeInterval & callStartTick)254 void IAX2Frame::BuildTimeStamp(const PTimeInterval & callStartTick)
255 {
256 if (presetTimeStamp > 0)
257 timeStamp = presetTimeStamp;
258 else
259 timeStamp = CalcTimeStamp(callStartTick);
260 PTRACE(5, "Frame\tBuild time stamp to " << PString(timeStamp) << " ms");
261 }
262
CalcTimeStamp(const PTimeInterval & callStartTick)263 DWORD IAX2Frame::CalcTimeStamp(const PTimeInterval & callStartTick)
264 {
265 DWORD tVal = (DWORD)(PTimer::Tick() - callStartTick).GetMilliSeconds();
266 PTRACE(6, "Frame\tCalculate timestamp as " << tVal);
267 return tVal;
268 }
269
TransmitPacket(PUDPSocket & sock)270 PBoolean IAX2Frame::TransmitPacket(PUDPSocket &sock)
271 {
272 if (CallMustBeActive()) {
273 if (!endpoint.ConnectionForFrameIsAlive(this)) {
274 PTRACE(3, "Frame\tConnection not found, call has been terminated. "
275 << IdString());
276 return PFalse; //This happens because the call has been terminated.
277 }
278 }
279
280 // if (PIsDescendant(this, FullFrameProtocol))
281 // ((FullFrameProtocol *)this)->SetRetransmissionRequired();
282 // cout << endl;
283
284 PTRACE(6, "Frame\tNow transmit " << endl << *this);
285 PBoolean transmitResult = sock.WriteTo(data.GetPointer(), DataSize(), remote.RemoteAddress(),
286 (unsigned short)remote.RemotePort());
287 PTRACE(6, "Frame\ttransmission of packet gave a " << transmitResult);
288 return transmitResult;
289 }
290
BuildAppropriateFrameType(IAX2Encryption & encryptionInfo)291 IAX2Frame * IAX2Frame::BuildAppropriateFrameType(IAX2Encryption & encryptionInfo)
292 {
293 DecryptContents(encryptionInfo);
294
295 return BuildAppropriateFrameType();
296 }
297
BuildAppropriateFrameType()298 IAX2Frame *IAX2Frame::BuildAppropriateFrameType()
299 {
300 if (isFullFrame) {
301 IAX2FullFrame *ff = new IAX2FullFrame(*this);
302 if (!ff->ProcessNetworkPacket()) {
303 delete ff;
304 return NULL;
305 }
306
307 return ff;
308 }
309
310 IAX2MiniFrame *mf = new IAX2MiniFrame(*this);
311 if (!mf->ProcessNetworkPacket()) {
312 delete mf;
313 return NULL;
314 }
315
316 return mf;
317 }
318
319
DecryptContents(IAX2Encryption & encryption)320 PBoolean IAX2Frame::DecryptContents(IAX2Encryption &encryption)
321 {
322 if (!encryption.IsEncrypted())
323 return PTrue;
324
325 #if OPAL_PTLIB_SSL_AES
326 PINDEX headerSize = GetEncryptionOffset();
327 PTRACE(4, "Frame\tUnEncrypted headerSize for " << IdString() << " is " << headerSize);
328
329 if ((headerSize + 32) > data.GetSize()) //Make certain packet larger than minimum size.
330 return PFalse;
331
332 PTRACE(6, "Decryption\tDATA Raw is " << endl << ::hex << data << ::dec);
333 PINDEX encDataSize = data.GetSize() - headerSize;
334 PTRACE(4, "Decryption\tEncoded data size is " << encDataSize);
335 if ((encDataSize % 16) != 0) {
336 PTRACE(2, "Decryption\tData size is not a multiple of 16.. Error. ");
337 return PFalse;
338 }
339
340 unsigned char lastblock[16];
341 memset(lastblock, 0, 16);
342 PBYTEArray working(encDataSize);
343
344 for (PINDEX i = 0; i < encDataSize; i+= 16) {
345 AES_decrypt(data.GetPointer() + headerSize + i, working.GetPointer() + i, encryption.AesDecryptKey());
346 for (int x = 0; x < 16; x++)
347 working[x + i] ^= lastblock[x];
348 memcpy(lastblock, data.GetPointer() + headerSize + i, 16);
349 }
350
351 PINDEX padding = 16 + (working[15] & 0x0f);
352 PTRACE(6, "padding is " << padding);
353
354 PINDEX encryptedSize = encDataSize - padding;
355 data.SetSize(encryptedSize + headerSize);
356
357 PTRACE(6, "Decryption\tDATA should have a size of " << data.GetSize());
358 PTRACE(6, "Decryption\tUNENCRYPTED DATA is " << endl << ::hex << working << ::dec);
359
360 memcpy(data.GetPointer() + headerSize, working.GetPointer() + padding, encryptedSize);
361 PTRACE(6, "Decryption\tEntire frame unencrypted is " << endl << ::hex << data << ::dec);
362 return PTrue;
363 #else
364 return PFalse;
365 #endif
366 }
367
EncryptContents(IAX2Encryption & encryption)368 PBoolean IAX2Frame::EncryptContents(IAX2Encryption &encryption)
369 {
370 if (!encryption.IsEncrypted())
371 return PTrue;
372
373 #if OPAL_PTLIB_SSL_AES
374 PINDEX headerSize = GetEncryptionOffset();
375 PINDEX eDataSize = data.GetSize() - headerSize;
376 PINDEX padding = 16 + ((16 - (eDataSize % 16)) & 0x0f);
377 PTRACE(6, "Frame\tEncryption, Size of encrypted region is changed from "
378 << eDataSize << " to " << (padding + eDataSize));
379
380 PBYTEArray working(eDataSize + padding);
381 memset(working.GetPointer(), 0, 16);
382 working[15] = (BYTE)(0x0f & padding);
383 memcpy(working.GetPointer() + padding, data.GetPointer() + headerSize, eDataSize);
384
385 PBYTEArray result(headerSize + eDataSize + padding);
386 memcpy(result.GetPointer(), data.GetPointer(), headerSize);
387
388 unsigned char curblock[16];
389 memset(curblock, 0, 16);
390 for (PINDEX i = 0; i < (eDataSize + padding); i+= 16) {
391 for (int x = 0; x < 16; x++)
392 curblock[x] ^= working[x + i];
393 AES_encrypt(curblock, result.GetPointer() + i + headerSize, encryption.AesEncryptKey());
394 memcpy(curblock, result.GetPointer() + i + headerSize, 16);
395 }
396
397 data = result;
398 return PTrue;
399 #else
400 PTRACE(1, "Frame\tEncryption is Flagged on, but AES routines in openssl are not available");
401 return PFalse;
402 #endif
403 }
404
GetEncryptionOffset()405 PINDEX IAX2Frame::GetEncryptionOffset()
406 {
407 if (isFullFrame)
408 return 4;
409
410 return 2;
411 }
412
413 ////////////////////////////////////////////////////////////////////////////////
414
IAX2MiniFrame(const IAX2Frame & srcFrame)415 IAX2MiniFrame::IAX2MiniFrame(const IAX2Frame & srcFrame)
416 : IAX2Frame(srcFrame)
417 {
418 ZeroAllValues();
419 isAudio = (data[0] != 0) || (data[1] != 0);
420 isVideo = !isAudio;
421 PTRACE(6, "Build this IAX2MiniFrame " << IdString());
422 }
423
IAX2MiniFrame(IAX2EndPoint & _endpoint)424 IAX2MiniFrame::IAX2MiniFrame(IAX2EndPoint &_endpoint)
425 : IAX2Frame(_endpoint)
426 {
427 ZeroAllValues();
428 PTRACE(6, "Build this IAX2MiniFrame " << IdString());
429 }
430
IAX2MiniFrame(IAX2Processor * iax2Processor,PBYTEArray & sound,PBoolean _isAudio,DWORD usersTimeStamp)431 IAX2MiniFrame::IAX2MiniFrame(IAX2Processor * iax2Processor, PBYTEArray &sound,
432 PBoolean _isAudio, DWORD usersTimeStamp)
433 : IAX2Frame(iax2Processor->GetEndPoint())
434 {
435 isAudio = _isAudio;
436 presetTimeStamp = usersTimeStamp;
437 InitialiseHeader(iax2Processor);
438
439 PINDEX headerSize = data.GetSize();
440 data.SetSize(sound.GetSize() + headerSize);
441 memcpy(data.GetPointer() + headerSize, sound.GetPointer(), sound.GetSize());
442 PTRACE(6, "Build this IAX2MiniFrame " << IdString());
443 }
444
~IAX2MiniFrame()445 IAX2MiniFrame::~IAX2MiniFrame()
446 {
447 PTRACE(6, "Destroy this IAX2MiniFrame " << IdString());
448 }
449
InitialiseHeader(IAX2Processor * iax2Processor)450 void IAX2MiniFrame::InitialiseHeader(IAX2Processor *iax2Processor)
451 {
452 if (iax2Processor != NULL) {
453 remote = iax2Processor->GetRemoteInfo();
454 BuildTimeStamp(iax2Processor->GetCallStartTick());
455 SetConnectionToken(iax2Processor->GetCallToken());
456 }
457 WriteHeader();
458 }
459
ProcessNetworkPacket()460 PBoolean IAX2MiniFrame::ProcessNetworkPacket()
461 {
462 WORD dataWord;
463 Read2Bytes(dataWord);
464 timeStamp = dataWord;
465
466 PTRACE(5, "Mini frame, header processed. frame is "
467 << PString(isAudio ? " audio" : "video"));
468 return PTrue;
469 }
470
ZeroAllValues()471 void IAX2MiniFrame::ZeroAllValues()
472 {
473 }
474
AlterTimeStamp(PINDEX newValue)475 void IAX2MiniFrame::AlterTimeStamp(PINDEX newValue)
476 {
477 timeStamp = (newValue & (0xffff << 16)) | (timeStamp & 0xffff);
478 }
479
WriteHeader()480 PBoolean IAX2MiniFrame::WriteHeader()
481 {
482 currentWriteIndex = 0; //Probably not needed, but this makes everything "obvious"
483
484 if(IsVideo()) {
485 data.SetSize(6);
486 Write2Bytes(0);
487 } else
488 data.SetSize(4);
489
490 Write2Bytes(remote.SourceCallNumber() & 0x7fff);
491 Write2Bytes(timeStamp & 0xffff);
492
493 return PTrue;
494 }
495
PrintOn(ostream & strm) const496 void IAX2MiniFrame::PrintOn(ostream & strm) const
497 {
498 strm << "IAX2MiniFrame of " << PString(IsVideo() ? "video" : "audio") << " "
499 << IdString() << " \"" << GetConnectionToken() << "\" " << endl;
500
501 IAX2Frame::PrintOn(strm);
502 }
503
GetMediaDataPointer()504 BYTE *IAX2MiniFrame::GetMediaDataPointer()
505 {
506 if (IsVideo())
507 return data.GetPointer() + 6;
508 else
509 return data.GetPointer() + 4;
510 }
511
GetMediaDataSize()512 PINDEX IAX2MiniFrame::GetMediaDataSize()
513 {
514 int thisSize;
515 if (IsVideo())
516 thisSize = data.GetSize() - 6;
517 else
518 thisSize = data.GetSize() - 4;
519
520 if (thisSize < 0)
521 return 0;
522 else
523 return thisSize;
524 }
525
GetEncryptionOffset()526 PINDEX IAX2MiniFrame::GetEncryptionOffset()
527 {
528 if (IsAudio())
529 return 2;
530
531 return 4;
532 }
533
534 ////////////////////////////////////////////////////////////////////////////////
535
IAX2FullFrame(IAX2EndPoint & _newEndpoint)536 IAX2FullFrame::IAX2FullFrame(IAX2EndPoint &_newEndpoint)
537 : IAX2Frame(_newEndpoint)
538 {
539 ZeroAllValues();
540 }
541
542 /*This is built from an incoming frame (from the network*/
IAX2FullFrame(const IAX2Frame & srcFrame)543 IAX2FullFrame::IAX2FullFrame(const IAX2Frame & srcFrame)
544 : IAX2Frame(srcFrame)
545 {
546 PTRACE(6, "Frame\tConstructor for a full frame");
547 ZeroAllValues();
548 }
549
~IAX2FullFrame()550 IAX2FullFrame::~IAX2FullFrame()
551 {
552 PTRACE(6, "Frame\tDestructor IAX2FullFrame:: " << IdString());
553 }
554
operator *=(IAX2FullFrame &)555 PBoolean IAX2FullFrame::operator*=(IAX2FullFrame & /*other*/)
556 {
557 PAssertAlways("Sorry, IAX2FullFrame comparison operator is Not implemented");
558 return PTrue;
559 }
560
MarkAsResent()561 void IAX2FullFrame::MarkAsResent()
562 {
563 if (data.GetSize() > 2)
564 data[2] |= 0x80;
565 }
566
ZeroAllValues()567 void IAX2FullFrame::ZeroAllValues()
568 {
569 subClass = 0;
570 timeStamp = 0;
571 sequence.ZeroAllValues();
572 canRetransmitFrame = PTrue;
573
574 transmissionTimer.SetNotifier(PCREATE_NOTIFIER(OnTransmissionTimeout));
575
576 retryDelta = PTimeInterval(minRetryTime);
577 retries = maxRetries;
578
579 callMustBeActive = PTrue;
580 packetResent = PFalse;
581 ClearListFlags();
582
583 isFullFrame = PTrue;
584 isAckFrame = PFalse;
585 }
586
ClearListFlags()587 void IAX2FullFrame::ClearListFlags()
588 {
589 deleteFrameNow = PFalse;
590 sendFrameNow = PFalse;
591 }
592
TransmitPacket(PUDPSocket & sock)593 PBoolean IAX2FullFrame::TransmitPacket(PUDPSocket &sock)
594 {
595 PTRACE(6, "Send network packet on " << IdString() << " " << connectionToken);
596 if (packetResent) {
597 MarkAsResent(); /* Set Retry flag.*/
598 }
599
600 if (retries == P_MAX_INDEX) {
601 PTRACE(4, "Retries count is now negative on. " << IdString());
602 return PFalse; //Give up on this packet, it has exceeded the allowed number of retries.
603 }
604
605 PTRACE(6, "Start timer running for " << IdString() << connectionToken);
606 transmissionTimer.SetInterval(retryDelta.GetMilliSeconds());
607 transmissionTimer.Reset(); //*This causes the timer to start running.
608 ClearListFlags();
609
610 return IAX2Frame::TransmitPacket(sock);
611 }
612
ProcessNetworkPacket()613 PBoolean IAX2FullFrame::ProcessNetworkPacket()
614 {
615 PTRACE(5, "ProcessNetworkPacket - read the frame header");
616 if (data.GetSize() < 12) {
617 PTRACE(2, "Incoming full frame is undersize - should have 12 bytes, but only read " << data.GetSize());
618 return PFalse;
619 }
620
621 Read4Bytes(timeStamp);
622 PTRACE(5, "Remote timestamp is " << timeStamp << " milliseconds");
623
624 BYTE a = 0;
625 Read1Byte(a);
626 sequence.SetOutSeqNo(a);
627 Read1Byte(a);
628 sequence.SetInSeqNo(a);
629 PTRACE(6, "Sequence is " << sequence.AsString());
630
631 Read1Byte(a);
632
633 if ((a >= numFrameTypes) || (a == undefType)) {
634 PTRACE(3, "Incoming packet has invalid frame type of " << a);
635 return PFalse;
636 }
637
638 frameType = (IAX2FrameType)a;
639 isAudio = frameType == voiceType;
640 isVideo = frameType == videoType;
641
642 /*Do subclass value (which might be compressed) */
643 Read1Byte(a);
644
645 UnCompressSubClass(a);
646 isAckFrame = (subClass == IAX2FullFrameProtocol::cmdAck) &&
647 (frameType == iax2ProtocolType);
648 return PTrue;
649 }
650
IsPingFrame()651 PBoolean IAX2FullFrame::IsPingFrame()
652 {
653 return (subClass == IAX2FullFrameProtocol::cmdPing) &&
654 (frameType == iax2ProtocolType);
655 }
656
IsNewFrame()657 PBoolean IAX2FullFrame::IsNewFrame()
658 {
659 return (subClass == IAX2FullFrameProtocol::cmdNew) &&
660 (frameType == iax2ProtocolType);
661 }
662
IsLagRqFrame()663 PBoolean IAX2FullFrame::IsLagRqFrame()
664 {
665 return (subClass == IAX2FullFrameProtocol::cmdLagRq) &&
666 (frameType == iax2ProtocolType);
667 }
668
IsLagRpFrame()669 PBoolean IAX2FullFrame::IsLagRpFrame()
670 {
671 return (subClass == IAX2FullFrameProtocol::cmdLagRp) &&
672 (frameType == iax2ProtocolType);
673 }
674
IsPongFrame()675 PBoolean IAX2FullFrame::IsPongFrame()
676 {
677 return (subClass == IAX2FullFrameProtocol::cmdPong) &&
678 (frameType == iax2ProtocolType);
679 }
680
IsAuthReqFrame()681 PBoolean IAX2FullFrame::IsAuthReqFrame()
682 {
683 return (subClass == IAX2FullFrameProtocol::cmdAuthReq) &&
684 (frameType == iax2ProtocolType);
685 }
686
IsVnakFrame()687 PBoolean IAX2FullFrame::IsVnakFrame()
688 {
689 return (subClass == IAX2FullFrameProtocol::cmdVnak) &&
690 (frameType == iax2ProtocolType);
691 }
692
IsRegReqFrame()693 PBoolean IAX2FullFrame::IsRegReqFrame()
694 {
695 return (subClass == IAX2FullFrameProtocol::cmdRegReq) &&
696 (frameType == iax2ProtocolType);
697 }
698
IsRegAuthFrame()699 PBoolean IAX2FullFrame::IsRegAuthFrame()
700 {
701 return (subClass == IAX2FullFrameProtocol::cmdRegAuth) &&
702 (frameType == iax2ProtocolType);
703 }
704
IsRegAckFrame()705 PBoolean IAX2FullFrame::IsRegAckFrame()
706 {
707 return (subClass == IAX2FullFrameProtocol::cmdRegAck) &&
708 (frameType == iax2ProtocolType);
709 }
710
IsRegRelFrame()711 PBoolean IAX2FullFrame::IsRegRelFrame()
712 {
713 return (subClass == IAX2FullFrameProtocol::cmdRegRel) &&
714 (frameType == iax2ProtocolType);
715 }
716
IsRegRejFrame()717 PBoolean IAX2FullFrame::IsRegRejFrame()
718 {
719 return (subClass == IAX2FullFrameProtocol::cmdRegRej) &&
720 (frameType == iax2ProtocolType);
721 }
722
IsHangupFrame()723 PBoolean IAX2FullFrame::IsHangupFrame()
724 {
725 return (subClass == IAX2FullFrameProtocol::cmdHangup) &&
726 (frameType == iax2ProtocolType);
727 }
728
IsCallTokenFrame()729 PBoolean IAX2FullFrame::IsCallTokenFrame()
730 {
731 return (subClass == IAX2FullFrameProtocol::cmdCallToken) &&
732 (frameType == iax2ProtocolType);
733 }
734
FrameIncrementsInSeqNo()735 PBoolean IAX2FullFrame::FrameIncrementsInSeqNo()
736 {
737 if (frameType != iax2ProtocolType) {
738 PTRACE(5, "SeqNos\tFrameType is not iaxProtocol, so we do increment inseqno. FrameType is " << frameType);
739 return PTrue;
740 }
741
742 IAX2FullFrameProtocol::ProtocolSc cmdType = (IAX2FullFrameProtocol::ProtocolSc)subClass;
743 PTRACE(5, "SeqNos\tThe cmd type (or subclass of IAX2FullFrameProtocol) is " << cmdType);
744 if ((cmdType == IAX2FullFrameProtocol::cmdAck) ||
745 // (cmdType == IAX2FullFrameProtocol::cmdLagRq) ||
746 // (cmdType == IAX2FullFrameProtocol::cmdLagRp) ||
747 // (cmdType == IAX2FullFrameProtocol::cmdAuthReq) ||
748 // (cmdType == IAX2FullFrameProtocol::cmdAuthRep) ||
749 (cmdType == IAX2FullFrameProtocol::cmdVnak)) {
750 PTRACE(3, "SeqNos\tThis is a iaxProtocol cmd type that does not increment inseqno");
751 return PFalse;
752 } else {
753 PTRACE(5, "SeqNos\tThis is a iaxProtocol cmd type that increments inseqno");
754 }
755 return PTrue;
756 }
757
UnCompressSubClass(BYTE a)758 void IAX2FullFrame::UnCompressSubClass(BYTE a)
759 {
760 if (a & 0x80) {
761 if (a == 0xff)
762 subClass = -1;
763 else
764 subClass = 1 << (a & 0x1f);
765 } else
766 subClass = a;
767 }
768
CompressSubClass()769 int IAX2FullFrame::CompressSubClass()
770 {
771 if (subClass < 0x80)
772 return subClass;
773
774 for(PINDEX i = 0; i < 0x1f; i++) {
775 if (subClass & (1 << i))
776 return i | 0x80;
777 }
778
779 return -1;
780 }
781
WriteHeader()782 PBoolean IAX2FullFrame::WriteHeader()
783 {
784 data.SetSize(12);
785 PTRACE(6, "Write a source call number of " << remote.SourceCallNumber());
786 Write2Bytes(remote.SourceCallNumber() + 0x8000);
787 PTRACE(6, "Write a dest call number of " << remote.DestCallNumber());
788 Write2Bytes(remote.DestCallNumber() + (packetResent ? 0x8000 : 0));
789
790 PTRACE(6, "Write a timestamp of " << timeStamp);
791 Write4Bytes(timeStamp);
792
793 PTRACE(6, "Write in seq no " << sequence.InSeqNo() << " and out seq no of " << sequence.OutSeqNo());
794 Write1Byte(sequence.OutSeqNo());
795 Write1Byte(sequence.InSeqNo());
796
797 PTRACE(6, "FrameType is " << ((int)GetFullFrameType()));
798 Write1Byte(GetFullFrameType());
799
800 int a = CompressSubClass();
801 if (a < 0)
802 Write1Byte(0xff);
803 else
804 Write1Byte((BYTE)a);
805 PTRACE(6, "Comppressed sub class is " << a << " from " << subClass);
806
807 return PTrue;
808 }
809
MarkVnakSendNow()810 void IAX2FullFrame::MarkVnakSendNow()
811 {
812 transmissionTimer.Stop();
813 sendFrameNow = PTrue;
814 deleteFrameNow = PFalse;
815 retryDelta = PTimeInterval(minRetryTime);
816 retries = maxRetries;
817 }
818
MarkDeleteNow()819 void IAX2FullFrame::MarkDeleteNow()
820 {
821 PTRACE(5, "MarkDeleteNow() method on " << IdString());
822 transmissionTimer.Stop();
823 deleteFrameNow = PTrue;
824 retries = P_MAX_INDEX;
825 }
826
OnTransmissionTimeout(PTimer &,INT)827 void IAX2FullFrame::OnTransmissionTimeout(PTimer &, INT)
828 {
829 PTRACE(4, "Has had a TX timeout " << IdString() << " " << connectionToken);
830 retryDelta = 4 * retryDelta.GetMilliSeconds();
831 if (retryDelta > maxRetryTime)
832 retryDelta = maxRetryTime;
833
834 packetResent = PTrue;
835 if ((retries == P_MAX_INDEX) || (retries == 0)) {
836 retries = P_MAX_INDEX;
837 PTRACE(5, "Retries are " << PString(retries)
838 << " NowMarkDeleteNow " << IdString());
839 MarkDeleteNow();
840 } else {
841 retries--;
842 sendFrameNow = PTrue;
843 PTRACE(5, "Tx timeout, so Mark as Send now " << IdString() << " " << connectionToken);
844 }
845
846 endpoint.transmitter->ProcessLists();
847 }
848
GetFullFrameName() const849 PString IAX2FullFrame::GetFullFrameName() const
850 {
851 switch(frameType) {
852 case undefType : return PString("(0?) ");
853 case dtmfType : return PString("Dtmf ");
854 case voiceType : return PString("Voice ");
855 case videoType : return PString("Video ");
856 case controlType : return PString("Session ");
857 case nullType : return PString("Null ");
858 case iax2ProtocolType: return PString("Protocol ");
859 case textType : return PString("Text ");
860 case imageType : return PString("Image ");
861 case htmlType : return PString("Html ");
862 case cngType : return PString("Cng ");
863 case numFrameTypes : return PString("# F types ");
864 }
865
866 return PString("Frame name is undefined for value of ") + PString(frameType);
867 }
868
GetMediaDataPointer()869 BYTE *IAX2FullFrame::GetMediaDataPointer()
870 {
871 return data.GetPointer() + 12;
872 }
873
GetMediaDataSize()874 PINDEX IAX2FullFrame::GetMediaDataSize()
875 {
876 return data.GetSize() - 12;
877 }
878
InitialiseHeader(IAX2Processor * iax2Processor)879 void IAX2FullFrame::InitialiseHeader(IAX2Processor *iax2Processor)
880 {
881 if (iax2Processor != NULL) {
882 SetConnectionToken(iax2Processor->GetCallToken());
883 BuildTimeStamp(iax2Processor->GetCallStartTick());
884 remote = iax2Processor->GetRemoteInfo();
885 }
886 PTRACE(5, "source timestamp is " << timeStamp);
887 frameType = (IAX2FrameType)GetFullFrameType();
888 WriteHeader();
889 }
890
PrintOn(ostream & strm) const891 void IAX2FullFrame::PrintOn(ostream & strm) const
892 {
893 strm << IdString() << " ++ " << GetFullFrameName() << " -- "
894 << GetSubClassName() << " \"" << connectionToken << "\"" << endl
895 << remote << endl;
896 }
897
ModifyFrameHeaderSequenceNumbers(PINDEX inNo,PINDEX outNo)898 void IAX2FullFrame::ModifyFrameHeaderSequenceNumbers(PINDEX inNo, PINDEX outNo)
899 {
900 data[8] = (BYTE) (outNo & 0xff);
901 data[9] = (BYTE) (inNo & 0xff);
902 GetSequenceInfo().SetInOutSeqNo(inNo, outNo);
903 }
904
ModifyFrameTimeStamp(PINDEX newTimeStamp)905 void IAX2FullFrame::ModifyFrameTimeStamp(PINDEX newTimeStamp)
906 {
907 timeStamp = newTimeStamp;
908 PINDEX oldWriteIndex = currentWriteIndex;
909 currentWriteIndex = 4;
910 Write4Bytes(timeStamp);
911 currentWriteIndex = oldWriteIndex;
912 }
913 ////////////////////////////////////////////////////////////////////////////////
914
IAX2FullFrameDtmf(const IAX2Frame & srcFrame)915 IAX2FullFrameDtmf::IAX2FullFrameDtmf(const IAX2Frame & srcFrame)
916 : IAX2FullFrame(srcFrame)
917 {
918 }
919
IAX2FullFrameDtmf(const IAX2FullFrame & srcFrame)920 IAX2FullFrameDtmf::IAX2FullFrameDtmf(const IAX2FullFrame & srcFrame)
921 : IAX2FullFrame(srcFrame)
922 {
923 }
924
IAX2FullFrameDtmf(IAX2Processor * iax2Processor,PString subClassValue)925 IAX2FullFrameDtmf::IAX2FullFrameDtmf(IAX2Processor *iax2Processor, PString subClassValue)
926 : IAX2FullFrame(iax2Processor->GetEndPoint())
927 {
928 SetSubClass(subClassValue.ToUpper()[0]);
929 InitialiseHeader(iax2Processor);
930 }
931
IAX2FullFrameDtmf(IAX2Processor * iax2Processor,char subClassValue)932 IAX2FullFrameDtmf::IAX2FullFrameDtmf(IAX2Processor *iax2Processor, char subClassValue)
933 : IAX2FullFrame(iax2Processor->GetEndPoint())
934 {
935 SetSubClass(toupper(subClassValue));
936 InitialiseHeader(iax2Processor);
937 }
938
GetSubClassName() const939 PString IAX2FullFrameDtmf::GetSubClassName() const {
940 switch (GetSubClass()) {
941 case dtmf0: return PString("0");
942 case dtmf1: return PString("1");
943 case dtmf2: return PString("2");
944 case dtmf3: return PString("3");
945 case dtmf4: return PString("4");
946 case dtmf5: return PString("5");
947 case dtmf6: return PString("6");
948 case dtmf7: return PString("7");
949 case dtmf8: return PString("8");
950 case dtmf9: return PString("9");
951 case dtmfA: return PString("A");
952 case dtmfB: return PString("B");
953 case dtmfC: return PString("C");
954 case dtmfD: return PString("D");
955 case dtmfStar: return PString("*");
956 case dtmfHash: return PString("#");
957 };
958 return PString("Undefined dtmf subclass value of ") + PString(GetSubClass());
959 }
960
961 ////////////////////////////////////////////////////////////////////////////////
IAX2FullFrameVoice(const IAX2Frame & srcFrame)962 IAX2FullFrameVoice::IAX2FullFrameVoice(const IAX2Frame & srcFrame)
963 : IAX2FullFrame(srcFrame)
964 {
965 PTRACE(6, "Construct a full frame voice from a Frame" << IdString());
966 }
967
IAX2FullFrameVoice(const IAX2FullFrame & srcFrame)968 IAX2FullFrameVoice::IAX2FullFrameVoice(const IAX2FullFrame & srcFrame)
969 : IAX2FullFrame(srcFrame)
970 {
971 PTRACE(6, "Construct a full frame voice from a IAX2FullFrame" << IdString());
972 }
973
IAX2FullFrameVoice(IAX2CallProcessor * iax2Processor,PBYTEArray & sound,PINDEX usersTimeStamp)974 IAX2FullFrameVoice::IAX2FullFrameVoice(IAX2CallProcessor *iax2Processor, PBYTEArray & sound, PINDEX usersTimeStamp)
975 : IAX2FullFrame(iax2Processor->GetEndPoint())
976 {
977 if (iax2Processor != NULL) {
978 SetSubClass((PINDEX)iax2Processor->GetSelectedCodec());
979 }
980
981 presetTimeStamp = usersTimeStamp;
982 InitialiseHeader(iax2Processor);
983
984 PINDEX headerSize = data.GetSize();
985 data.SetSize(sound.GetSize() + headerSize);
986 memcpy(data.GetPointer() + headerSize, sound.GetPointer(), sound.GetSize());
987 PTRACE(6, "Construct a full frame voice from a processor, sound, and codec" << IdString());
988 }
989
990
~IAX2FullFrameVoice()991 IAX2FullFrameVoice::~IAX2FullFrameVoice()
992 {
993 PTRACE(6, "Destroy this IAX2FullFrameVoice" << IdString());
994 }
995
GetSubClassName(unsigned int testValue)996 PString IAX2FullFrameVoice::GetSubClassName(unsigned int testValue)
997 {
998 switch (testValue) {
999 case g7231: return PString("G.723.1");
1000 case gsm: return PString("GSM-06.10");
1001 case g711ulaw: return PString("G.711-uLaw-64k");
1002 case g711alaw: return PString("G.711-ALaw-64k");
1003 case mp3: return PString("mp3");
1004 case adpcm: return PString("adpcm");
1005 case pcm: return PString("pcm");
1006 case lpc10: return PString("LPC-10");
1007 case g729: return PString("G.729");
1008 case speex: return PString("speex");
1009 case ilbc: return PString("iLBC-13k3");
1010 default: ;
1011 };
1012
1013 PStringStream res;
1014 res << "The value 0x" << ::hex << testValue << ::dec << " could not be identified as a codec";
1015 return res;
1016 }
1017
OpalNameToIax2Value(const PString opalName)1018 unsigned short IAX2FullFrameVoice::OpalNameToIax2Value(const PString opalName)
1019 {
1020 if (opalName.Find("uLaw") != P_MAX_INDEX) {
1021 return g711ulaw;
1022 }
1023
1024 if (opalName.Find("ALaw") != P_MAX_INDEX) {
1025 return g711alaw;
1026 }
1027
1028 if (opalName.Find("GSM-06.10") != P_MAX_INDEX) {
1029 return gsm;
1030 }
1031
1032 if (opalName.Find("iLBC-13k3") != P_MAX_INDEX) {
1033 return ilbc;
1034 }
1035 PTRACE(6, "Codec " << opalName << " is not supported in IAX2");
1036 return 0;
1037 }
1038
GetSubClassName() const1039 PString IAX2FullFrameVoice::GetSubClassName() const
1040 {
1041 return GetSubClassName(GetSubClass());
1042 }
1043
GetOpalNameOfCodec(PINDEX testValue)1044 PString IAX2FullFrameVoice::GetOpalNameOfCodec(PINDEX testValue)
1045 {
1046 switch (testValue) {
1047 case g7231: return PString("G.723.1");
1048 case gsm: return PString("GSM-06.10");
1049 case g711ulaw: return PString("G.711-uLaw-64k");
1050 case g711alaw: return PString("G.711-ALaw-64k");
1051 case mp3: return PString("mp3");
1052 case adpcm: return PString("adpcm");
1053 case pcm: return PString("Linear-16-Mono-8kHz");
1054 case lpc10: return PString("LPC10");
1055 case g729: return PString("G.729");
1056 case speex: return PString("speex");
1057 case ilbc: return PString("ilbc");
1058 default: ;
1059 };
1060
1061 PStringStream res;
1062 res << "The value 0x" << ::hex << testValue << ::dec << " could not be identified as a codec";
1063 return res;
1064 }
1065
1066 ////////////////////////////////////////////////////////////////////////////////
1067
IAX2FullFrameVideo(const IAX2Frame & srcFrame)1068 IAX2FullFrameVideo::IAX2FullFrameVideo(const IAX2Frame & srcFrame)
1069 : IAX2FullFrame(srcFrame)
1070 {
1071 }
1072
IAX2FullFrameVideo(const IAX2FullFrame & srcFrame)1073 IAX2FullFrameVideo::IAX2FullFrameVideo(const IAX2FullFrame & srcFrame)
1074 : IAX2FullFrame(srcFrame)
1075 {
1076 }
1077
GetSubClassName() const1078 PString IAX2FullFrameVideo::GetSubClassName() const
1079 {
1080 switch (GetSubClass()) {
1081 case jpeg: return PString("jpeg");
1082 case png: return PString("png");
1083 case h261: return PString("H.261");
1084 case h263: return PString("H.263");
1085 };
1086 return PString("Undefined IAX2FullFrameVideo subclass value of ") + PString(GetSubClass());
1087 }
1088 ////////////////////////////////////////////////////////////////////////////////
1089
IAX2FullFrameSessionControl(const IAX2Frame & srcFrame)1090 IAX2FullFrameSessionControl::IAX2FullFrameSessionControl(const IAX2Frame & srcFrame)
1091 : IAX2FullFrame(srcFrame)
1092 {
1093 }
1094
IAX2FullFrameSessionControl(const IAX2FullFrame & srcFrame)1095 IAX2FullFrameSessionControl::IAX2FullFrameSessionControl(const IAX2FullFrame & srcFrame)
1096 : IAX2FullFrame(srcFrame)
1097 {
1098 }
1099
IAX2FullFrameSessionControl(IAX2Processor * iax2Processor,SessionSc session)1100 IAX2FullFrameSessionControl::IAX2FullFrameSessionControl(IAX2Processor *iax2Processor,
1101 SessionSc session)
1102 : IAX2FullFrame(iax2Processor->GetEndPoint())
1103 {
1104 SetSubClass((PINDEX)session);
1105 isAckFrame = PFalse;
1106 InitialiseHeader(iax2Processor);
1107 callMustBeActive = PTrue;
1108 }
1109
IAX2FullFrameSessionControl(IAX2Processor * iax2Processor,PINDEX subClassValue)1110 IAX2FullFrameSessionControl::IAX2FullFrameSessionControl(IAX2Processor *iax2Processor,
1111 PINDEX subClassValue)
1112 : IAX2FullFrame(iax2Processor->GetEndPoint())
1113 {
1114 SetSubClass(subClassValue);
1115 isAckFrame = PFalse;
1116 InitialiseHeader(iax2Processor);
1117 callMustBeActive = PTrue;
1118 }
1119
GetSubClassName() const1120 PString IAX2FullFrameSessionControl::GetSubClassName() const {
1121 switch (GetSubClass()) {
1122 case hangup: return PString("hangup");
1123 case ring: return PString("ring");
1124 case ringing: return PString("ringing");
1125 case answer: return PString("answer");
1126 case busy: return PString("busy");
1127 case tkoffhk: return PString("tkoffhk");
1128 case offhook: return PString("offhook");
1129 case congestion: return PString("congestion");
1130 case flashhook: return PString("flashhook");
1131 case wink: return PString("wink");
1132 case option: return PString("option");
1133 case keyRadio: return PString("keyRadio");
1134 case unkeyRadio: return PString("unkeyRadio");
1135 case callProgress: return PString("callProgress");
1136 case callProceeding: return PString("callProceeding");
1137 };
1138
1139 return PString("Undefined IAX2FullFrameSessionControl subclass value of ")
1140 + PString(GetSubClass());
1141 }
1142 ////////////////////////////////////////////////////////////////////////////////
1143
IAX2FullFrameNull(const IAX2Frame & srcFrame)1144 IAX2FullFrameNull::IAX2FullFrameNull(const IAX2Frame & srcFrame)
1145 : IAX2FullFrame(srcFrame)
1146 {
1147 }
1148
IAX2FullFrameNull(const IAX2FullFrame & srcFrame)1149 IAX2FullFrameNull::IAX2FullFrameNull(const IAX2FullFrame & srcFrame)
1150 : IAX2FullFrame(srcFrame)
1151 {
1152 }
1153
1154 ////////////////////////////////////////////////////////////////////////////////
1155
IAX2FullFrameProtocol(IAX2Processor * iax2Processor,PINDEX subClassValue,ConnectionRequired needCon)1156 IAX2FullFrameProtocol::IAX2FullFrameProtocol(IAX2Processor *iax2Processor, PINDEX subClassValue, ConnectionRequired needCon)
1157 : IAX2FullFrame(iax2Processor->GetEndPoint())
1158 {
1159 SetSubClass(subClassValue);
1160 isAckFrame = (subClassValue == cmdAck);
1161 if (isAckFrame) {
1162 PTRACE(5, "Sending an ack frame now");
1163 }
1164 InitialiseHeader(iax2Processor);
1165 callMustBeActive = (needCon == callActive);
1166 PTRACE(5, "Construct a fullframeprotocol from a processor, subclass value and a connectionrequired. " << IdString());
1167
1168 }
1169
IAX2FullFrameProtocol(IAX2Processor * iax2Processor,ProtocolSc subClassValue,ConnectionRequired needCon)1170 IAX2FullFrameProtocol::IAX2FullFrameProtocol(IAX2Processor *iax2Processor, ProtocolSc subClassValue, ConnectionRequired needCon)
1171 : IAX2FullFrame(iax2Processor->GetEndPoint())
1172 {
1173 SetSubClass(subClassValue);
1174 isAckFrame = (subClassValue == cmdAck);
1175 InitialiseHeader(iax2Processor);
1176 callMustBeActive = (needCon == callActive);
1177
1178 PTRACE(5, "Construct a fullframeprotocol from a processor subclass value and connection required " << IdString());
1179 }
1180
IAX2FullFrameProtocol(IAX2Processor * iax2Processor,ProtocolSc subClassValue,IAX2FullFrame * inReplyTo,ConnectionRequired needCon)1181 IAX2FullFrameProtocol::IAX2FullFrameProtocol(IAX2Processor *iax2Processor, ProtocolSc subClassValue, IAX2FullFrame *inReplyTo, ConnectionRequired needCon)
1182 : IAX2FullFrame(iax2Processor->GetEndPoint())
1183 {
1184 SetSubClass(subClassValue);
1185 timeStamp = inReplyTo->GetTimeStamp();
1186 isAckFrame = (subClassValue == cmdAck);
1187 if (isAckFrame) {
1188 sequence.SetAckSequenceInfo(inReplyTo->GetSequenceInfo());
1189 }
1190 if (iax2Processor == NULL) {
1191 IAX2Remote rem = inReplyTo->GetRemoteInfo();
1192 remote = rem;
1193 } else {
1194 remote = iax2Processor->GetRemoteInfo();
1195 SetConnectionToken(iax2Processor->GetCallToken());
1196 }
1197 frameType = iax2ProtocolType;
1198 callMustBeActive = (needCon == callActive);
1199 WriteHeader();
1200 PTRACE(5, "Construct a fullframeprotocol from a processor, subclass value and a connection required" << IdString());
1201 }
1202
IAX2FullFrameProtocol(const IAX2Frame & srcFrame)1203 IAX2FullFrameProtocol::IAX2FullFrameProtocol(const IAX2Frame & srcFrame)
1204 : IAX2FullFrame(srcFrame)
1205 {
1206 ReadInformationElements();
1207 PTRACE(5, "Construct a fullframeprotocol from a Frame" << IdString());
1208 }
1209
IAX2FullFrameProtocol(const IAX2FullFrame & srcFrame)1210 IAX2FullFrameProtocol::IAX2FullFrameProtocol(const IAX2FullFrame & srcFrame)
1211 : IAX2FullFrame(srcFrame)
1212 {
1213 ReadInformationElements();
1214 PTRACE(5, "Construct a fullframeprotocol from a Full Frame" << IdString());
1215 }
1216
~IAX2FullFrameProtocol()1217 IAX2FullFrameProtocol::~IAX2FullFrameProtocol()
1218 {
1219 ieElements.AllowDeleteObjects(PTrue);
1220 PTRACE(6, "Destroy this IAX2FullFrameProtocol(" << GetSubClassName() << ") " << IdString());
1221 }
1222
SetRetransmissionRequired()1223 void IAX2FullFrameProtocol::SetRetransmissionRequired()
1224 {
1225 if (GetSubClass() == IAX2FullFrameProtocol::cmdAck)
1226 canRetransmitFrame = PFalse;
1227
1228 if (GetSubClass() == IAX2FullFrameProtocol::cmdLagRp)
1229 canRetransmitFrame = PFalse;
1230
1231 if (GetSubClass() == IAX2FullFrameProtocol::cmdPong)
1232 canRetransmitFrame = PFalse;
1233 }
1234
WriteIeAsBinaryData()1235 void IAX2FullFrameProtocol::WriteIeAsBinaryData()
1236 {
1237 PTRACE(6, "Frame\tWrite the IE data (" << ieElements.GetSize()
1238 << " elements) as binary data to frame " << IdString());
1239 PINDEX headerSize = data.GetSize();
1240 data.SetSize(headerSize + ieElements.GetBinaryDataSize());
1241
1242 PINDEX i;
1243 for(i = 0; i < ieElements.GetSize(); i++) {
1244 PTRACE(6, "Frame\tAppend to outgoing frame " << *ieElements.GetIeAt(i));
1245 ieElements.GetIeAt(i)->WriteBinary(data.GetPointer(), headerSize);
1246 }
1247 }
1248
GetCallTokenIe(IAX2IeCallToken & callToken)1249 PBoolean IAX2FullFrameProtocol::GetCallTokenIe(IAX2IeCallToken & callToken)
1250 {
1251 PINDEX i;
1252 for (i = 0; i < ieElements.GetSize(); i++) {
1253 IAX2Ie *elem = ieElements.GetIeAt(i);
1254 if (elem->GetKeyValue() == IAX2Ie::ie_callToken) {
1255 IAX2IeCallToken *src = (IAX2IeCallToken *)elem;
1256 callToken.CopyData(src);
1257 return PTrue;
1258 }
1259 }
1260 return PFalse;
1261 }
1262
ReadInformationElements()1263 PBoolean IAX2FullFrameProtocol::ReadInformationElements()
1264 {
1265 IAX2Ie *elem = NULL;
1266
1267 while (GetUnReadBytes() >= 2) {
1268 BYTE thisType = 0, thisLength = 0;
1269 Read1Byte(thisType);
1270 Read1Byte(thisLength);
1271 if (thisLength <= GetUnReadBytes()){
1272 elem = IAX2Ie::BuildInformationElement(thisType, thisLength, data.GetPointer() + currentReadIndex);
1273 currentReadIndex += thisLength;
1274 if (elem != NULL)
1275 if (elem->IsValid()) {
1276 ieElements.Append(elem);
1277 // PTRACE(3, "Read information element " << *elem);
1278 }
1279 } else {
1280 PTRACE(6, "Unread bytes is " << GetUnReadBytes() << " This length is " << thisLength);
1281 break;
1282 }
1283 }
1284
1285 if (elem == NULL)
1286 return PFalse;
1287
1288 if (!elem->IsValid())
1289 return PFalse;
1290
1291 return GetUnReadBytes() == 0;
1292 }
1293
GetRemoteCapability(unsigned int & capability,unsigned int & preferred)1294 void IAX2FullFrameProtocol::GetRemoteCapability(unsigned int & capability, unsigned int & preferred)
1295 {
1296 capability = 0;
1297 preferred = 0;
1298 IAX2Ie * p;
1299 PINDEX i = 0;
1300 for(;;) {
1301 p = GetIeAt(i);
1302 if (p == NULL)
1303 break;
1304
1305 i++;
1306 if (p->IsValid()) {
1307 if (PIsDescendant(p, IAX2IeCapability)) {
1308 capability = ((IAX2IeCapability *)p)->ReadData();
1309 PTRACE(5, "IAX2FullFrameProtocol\tCapability codecs are " << capability);
1310 }
1311 if (PIsDescendant(p, IAX2IeFormat)) {
1312 preferred = ((IAX2IeFormat *)p)->ReadData();
1313 PTRACE(4, "IAX2FullFrameProtocol\tPreferred codec is " << preferred);
1314 }
1315 } else {
1316 PTRACE(3, "Invalid data in IE. ");
1317 }
1318 }
1319 }
1320
CopyDataFromIeListTo(IAX2IeData & res)1321 void IAX2FullFrameProtocol::CopyDataFromIeListTo(IAX2IeData &res)
1322 {
1323 IAX2Ie * p;
1324 PINDEX i = 0;
1325 for(;;) {
1326 p = GetIeAt(i);
1327 if (p == NULL)
1328 break;
1329
1330 i++;
1331 PTRACE(4, "From IAX2FullFrameProtocol, handle IAX2Ie of type " << *p);
1332 if (p->IsValid())
1333 p->StoreDataIn(res);
1334 else {
1335 PTRACE(3, "Invalid data in IE. " << *p);
1336 }
1337 }
1338 }
1339
GetSubClassName() const1340 PString IAX2FullFrameProtocol::GetSubClassName() const
1341 {
1342 return GetSubClassName(GetSubClass());
1343 }
1344
GetSubClassName(PINDEX t)1345 PString IAX2FullFrameProtocol::GetSubClassName(PINDEX t)
1346 {
1347 switch (t) {
1348 case cmdNew: return PString("new");
1349 case cmdPing: return PString("ping");
1350 case cmdPong: return PString("pong");
1351 case cmdAck: return PString("ack");
1352 case cmdHangup: return PString("hangup");
1353 case cmdReject: return PString("reject");
1354 case cmdAccept: return PString("accept");
1355 case cmdAuthReq: return PString("authreq");
1356 case cmdAuthRep: return PString("authrep");
1357 case cmdInval: return PString("inval");
1358 case cmdLagRq: return PString("lagrq");
1359 case cmdLagRp: return PString("lagrp");
1360 case cmdRegReq: return PString("regreq");
1361 case cmdRegAuth: return PString("regauth");
1362 case cmdRegAck: return PString("regack");
1363 case cmdRegRej: return PString("regrej");
1364 case cmdRegRel: return PString("regrel");
1365 case cmdVnak: return PString("vnak");
1366 case cmdDpReq: return PString("dpreq");
1367 case cmdDpRep: return PString("dprep");
1368 case cmdDial: return PString("dial");
1369 case cmdTxreq: return PString("txreq");
1370 case cmdTxcnt: return PString("txcnt");
1371 case cmdTxacc: return PString("txacc");
1372 case cmdTxready: return PString("txready");
1373 case cmdTxrel: return PString("txrel");
1374 case cmdTxrej: return PString("txrej");
1375 case cmdQuelch: return PString("quelch");
1376 case cmdUnquelch: return PString("unquelch");
1377 case cmdPoke: return PString("poke");
1378 case cmdPage: return PString("page");
1379 case cmdMwi: return PString("mwi");
1380 case cmdUnsupport: return PString("unsupport");
1381 case cmdTransfer: return PString("transfer");
1382 case cmdProvision: return PString("provision");
1383 case cmdFwDownl: return PString("fwDownl");
1384 case cmdFwData: return PString("fwData");
1385 };
1386 return PString("Undefined FullFrameProtocol subclass value of ") + PString(t);
1387 }
1388
1389 #if PTRACING
operator <<(ostream & o,IAX2FullFrameProtocol::ProtocolSc t)1390 ostream & operator << (ostream & o, IAX2FullFrameProtocol::ProtocolSc t)
1391 {
1392 PString answer = IAX2FullFrameProtocol::GetSubClassName(t);
1393 o << answer;
1394 return o;
1395 }
1396 #endif
1397
PrintOn(ostream & strm) const1398 void IAX2FullFrameProtocol::PrintOn(ostream & strm) const
1399 {
1400 strm << "IAX2FullFrameProtocol(" << GetSubClassName() << ") "
1401 << IdString() << " -- "
1402 << " \"" << connectionToken << "\"" << endl
1403 << remote << endl;
1404 }
1405 ////////////////////////////////////////////////////////////////////////////////
1406
IAX2FullFrameText(const IAX2Frame & srcFrame)1407 IAX2FullFrameText::IAX2FullFrameText(const IAX2Frame & srcFrame)
1408 : IAX2FullFrame(srcFrame)
1409 {
1410 if (GetMediaDataSize() > 0)
1411 internalText = PString((const char *)GetMediaDataPointer(),
1412 GetMediaDataSize());
1413
1414 }
1415
IAX2FullFrameText(const IAX2FullFrame & srcFrame)1416 IAX2FullFrameText::IAX2FullFrameText(const IAX2FullFrame & srcFrame)
1417 : IAX2FullFrame(srcFrame)
1418 {
1419 if (GetMediaDataSize() > 0)
1420 internalText = PString((const char *)GetMediaDataPointer(),
1421 GetMediaDataSize());
1422
1423 }
1424
GetSubClassName() const1425 PString IAX2FullFrameText::GetSubClassName() const
1426 {
1427 return PString("IAX2FullFrameText never has a valid sub class");
1428 }
1429
IAX2FullFrameText(IAX2Processor * iaxProcessor,const PString & text)1430 IAX2FullFrameText::IAX2FullFrameText(IAX2Processor *iaxProcessor, const PString& text )
1431 : IAX2FullFrame(iaxProcessor->GetEndPoint())
1432 {
1433 // presetTimeStamp = usersTimeStamp;
1434 InitialiseHeader(iaxProcessor);
1435
1436 internalText = text;
1437
1438 PINDEX headerSize = data.GetSize();
1439 data.SetSize(text.GetLength() + headerSize);
1440 memcpy(data.GetPointer() + headerSize,
1441 internalText.GetPointer(), internalText.GetLength());
1442
1443 PTRACE(4, "Construct a full frame text" << IdString() << " for text " << text);
1444 }
1445
GetTextString() const1446 PString IAX2FullFrameText::GetTextString() const
1447 {
1448 return internalText;
1449 }
1450
1451 ////////////////////////////////////////////////////////////////////////////////
1452
IAX2FullFrameImage(const IAX2Frame & srcFrame)1453 IAX2FullFrameImage::IAX2FullFrameImage(const IAX2Frame & srcFrame)
1454 : IAX2FullFrame(srcFrame)
1455 {
1456 }
1457
IAX2FullFrameImage(const IAX2FullFrame & srcFrame)1458 IAX2FullFrameImage::IAX2FullFrameImage(const IAX2FullFrame & srcFrame)
1459 : IAX2FullFrame(srcFrame)
1460 {
1461 }
1462
GetSubClassName() const1463 PString IAX2FullFrameImage::GetSubClassName() const
1464 {
1465 return PString("IAX2FullFrameImage never has a valid sub class");
1466 }
1467 ////////////////////////////////////////////////////////////////////////////////
1468
IAX2FullFrameHtml(const IAX2Frame & srcFrame)1469 IAX2FullFrameHtml::IAX2FullFrameHtml(const IAX2Frame & srcFrame)
1470 : IAX2FullFrame(srcFrame)
1471 {
1472 }
1473
IAX2FullFrameHtml(const IAX2FullFrame & srcFrame)1474 IAX2FullFrameHtml::IAX2FullFrameHtml(const IAX2FullFrame & srcFrame)
1475 : IAX2FullFrame(srcFrame)
1476 {
1477 }
1478
GetSubClassName() const1479 PString IAX2FullFrameHtml::GetSubClassName() const
1480 {
1481 return PString("IAX2FullFrameHtml has a sub class of ") + PString(GetSubClass());
1482 }
1483
1484 ////////////////////////////////////////////////////////////////////////////////
1485
IAX2FullFrameCng(const IAX2Frame & srcFrame)1486 IAX2FullFrameCng::IAX2FullFrameCng(const IAX2Frame & srcFrame)
1487 : IAX2FullFrame(srcFrame)
1488 {
1489 }
1490
IAX2FullFrameCng(const IAX2FullFrame & srcFrame)1491 IAX2FullFrameCng::IAX2FullFrameCng(const IAX2FullFrame & srcFrame)
1492 : IAX2FullFrame(srcFrame)
1493 {
1494 }
1495
GetSubClassName() const1496 PString IAX2FullFrameCng::GetSubClassName() const
1497 {
1498 return PString("IAX2FullFrameCng has a sub class of ") + PString(GetSubClass());
1499 }
1500
1501
1502 ////////////////////////////////////////////////////////////////////////////////
1503
~IAX2FrameList()1504 IAX2FrameList::~IAX2FrameList()
1505 {
1506 }
1507
ReportList(PString & answer)1508 void IAX2FrameList::ReportList(PString & answer)
1509 {
1510 PStringStream reply;
1511 {
1512 PWaitAndSignal m(mutex);
1513
1514 for(PINDEX i = 0; i < PAbstractList::GetSize(); i++) {
1515 IAX2Frame *frame = (IAX2Frame *)GetAt(i);
1516 reply << " #" << (i + 1) << " of "
1517 << PAbstractList::GetSize() << " "
1518 << frame->GetConnectionToken() << " "
1519 << frame->GetTimeStamp();
1520 if (frame->IsFullFrame()) {
1521 IAX2FullFrame *ff = (IAX2FullFrame *)frame;
1522 reply << " " << ff->GetSequenceInfo().AsString() << " "
1523 << ff->GetFullFrameName() << endl;
1524 }
1525 }
1526 }
1527 answer = reply;
1528 }
1529
AddNewFrame(IAX2Frame * newFrame)1530 void IAX2FrameList::AddNewFrame(IAX2Frame *newFrame)
1531 {
1532 if (newFrame == NULL)
1533 return;
1534 PTRACE(5, "Frame\tAdd " << newFrame->IdString()
1535 << " " << newFrame->GetRemoteInfo());
1536 PWaitAndSignal m(mutex);
1537 PAbstractList::Append(newFrame);
1538 }
1539
GrabContents(IAX2FrameList & src)1540 void IAX2FrameList::GrabContents(IAX2FrameList &src)
1541 {
1542 IAX2Frame *current;
1543 do {
1544 current = src.GetLastFrame();
1545 AddNewFrame(current);
1546 } while (current != NULL);
1547 }
1548
GetLastFrame()1549 IAX2Frame *IAX2FrameList::GetLastFrame()
1550 {
1551 PWaitAndSignal m(mutex);
1552 PINDEX elems = GetEntries();
1553 if (elems == 0) {
1554 return NULL;
1555 }
1556
1557 return (IAX2Frame *)PAbstractList::RemoveAt(0);
1558 }
1559
DeleteMatchingSendFrame(IAX2FullFrame * reply)1560 void IAX2FrameList::DeleteMatchingSendFrame(IAX2FullFrame *reply)
1561 {
1562 PINDEX currentIndex;
1563 IAX2FullFrame *sent;
1564
1565 PWaitAndSignal m(mutex);
1566 //Look for a frame that has been sent, which is waiting for a reply/ack.
1567 PTRACE(5, "Frame\tID# Delete matchingSendFrame start, test on "
1568 << reply->IdString());
1569
1570 for (PINDEX i = 0; i < GetEntries(); i++) {
1571 sent = NULL;
1572 IAX2Frame *frame = (IAX2Frame *)GetAt(i);
1573 if (frame == NULL)
1574 continue;
1575
1576 PTRACE(5, "ID#DeleteMatching " << frame->IdString());
1577 if (!frame->IsFullFrame())
1578 continue;
1579
1580 sent = (IAX2FullFrame *)frame;
1581 currentIndex = i; /* If a match is found, we delete this one */
1582
1583 if (sent->DeleteFrameNow()) {
1584 // Skip this frame, as it is marked, delete now
1585 continue;
1586 }
1587
1588 if (sent->IsNewFrame() &&
1589 reply->IsCallTokenFrame()) {
1590 if(sent->GetRemoteInfo().SourceCallNumber() ==
1591 reply->GetRemoteInfo().DestCallNumber())
1592 goto foundMatch;
1593 }
1594
1595 if (!(sent->GetRemoteInfo() *= reply->GetRemoteInfo())) {
1596 PTRACE(5, "mismatch in remote info");
1597 continue;
1598 }
1599
1600 if (sent->IsNewFrame() &&
1601 reply->GetSequenceInfo().IsFirstReplyFrame()) {
1602 PTRACE(5, "Frame\tHave a match on a new frame we sent out");
1603 goto foundMatch;
1604 }
1605
1606 if (sent->IsRegReqFrame() &&
1607 (reply->IsRegAckFrame() || reply->IsRegAuthFrame() || reply->IsRegRejFrame())) {
1608 PTRACE(5, "have read a RegAck, RegAuth or RegRej packet for a RegReq frame we have sent, delete this RegReq");
1609 PTRACE(5, "reg type frame, so MarkDeleteNow on " << sent->IdString());
1610 goto foundMatch;
1611 }
1612
1613 if (sent->IsRegRelFrame() &&
1614 (reply->IsRegAckFrame() || reply->IsRegAuthFrame() || reply->IsRegRejFrame())) {
1615 PTRACE(5, "have read a RegAck, RegAuth or RegRej packet for a RegRel frame we have sent, delete this RegRel");
1616 PTRACE(5, "reg rel/authoframe, so MarkDeleteNow on " << sent->IdString());
1617 goto foundMatch;
1618 }
1619
1620 if (sent->GetTimeStamp() != reply->GetTimeStamp()) {
1621 PTRACE(5, "Time stamps differ, so give up on the test" << sent->IdString());
1622 continue;
1623 } else {
1624 PTRACE(5, "Time stamps are the same, so check in seqno vs oseqno " << sent->IdString());
1625 }
1626
1627 PTRACE(5, "SeqNos\tSent is " << sent->GetSequenceInfo().OutSeqNo()
1628 << " " << sent->GetSequenceInfo().InSeqNo());
1629 PTRACE(5, "SeqNos\tRepl is " << reply->GetSequenceInfo().OutSeqNo()
1630 << " " << reply->GetSequenceInfo().InSeqNo());
1631
1632 if (reply->IsLagRpFrame() && sent->IsLagRqFrame()) {
1633 PTRACE(5, "have read a LagRp packet for a LagRq frame we have sent, delete this LagRq "
1634 << sent->IdString());
1635 PTRACE(5, "LAG frame, so MarkDeleteNow on " << sent->IdString());
1636 goto foundMatch;
1637 }
1638
1639 if (reply->IsPongFrame() && sent->IsPingFrame()) {
1640 PTRACE(5, "have read a Pong packet for a PING frame we have sent: delete the Pong "
1641 << sent->IdString());
1642 PTRACE(5, "PONG frame, so MarkDeleteNow on " << sent->IdString());
1643 goto foundMatch;
1644 }
1645
1646 if (sent->GetSequenceInfo().InSeqNo() == reply->GetSequenceInfo().OutSeqNo()) {
1647 PTRACE(5, "Timestamp, and inseqno matches oseqno " << sent->IdString());
1648 if (reply->IsAckFrame()) {
1649 PTRACE(5, "have read an ack packet for one we have sent, so delete this one " << sent->IdString());
1650 PTRACE(5, "ack for existing frame, MarkDeleteNow " << sent->IdString());
1651 goto foundMatch;
1652 }
1653 } else {
1654 PTRACE(5, "No match:: sent=" << sent->IdString() << " and reply=" << reply->IdString()
1655 << PString(reply->IsAckFrame() ? "reply is ack frame " : "reply is not ack frame ")
1656 << PString("Sequence numbers are:: sentIn" )
1657 << sent->GetSequenceInfo().InSeqNo() << " rcvdOut" << reply->GetSequenceInfo().OutSeqNo());
1658 }
1659
1660 PTRACE(5, " sequence " << sent->GetSequenceInfo().OutSeqNo()
1661 << " and " << reply->GetSequenceInfo().InSeqNo() << " are different");
1662
1663 }
1664 // No match found, so no sent frame will be deleted
1665 return;
1666
1667 foundMatch:
1668
1669 delete sent;
1670 RemoveAt(currentIndex);
1671 return;
1672 }
1673
SendVnakRequestedFrames(IAX2FullFrameProtocol & src)1674 void IAX2FrameList::SendVnakRequestedFrames(IAX2FullFrameProtocol &src)
1675 {
1676 PINDEX srcOutSeqNo = src.GetSequenceInfo().OutSeqNo();
1677 PWaitAndSignal m(mutex);
1678 PTRACE(4, "Look for a frame that has been sent, waiting to be acked etc, that matches the supplied Vnak frame");
1679
1680 for (PINDEX i = 0; i < GetEntries(); i++) {
1681 IAX2Frame *frame = (IAX2Frame *)GetAt(i);
1682 if (frame == NULL)
1683 continue;
1684
1685 if (!frame->IsFullFrame())
1686 continue;
1687
1688 IAX2FullFrame *sent = (IAX2FullFrame *)frame;
1689
1690 if (sent->DeleteFrameNow()) {
1691 PTRACE(4, "Skip this frame, as it is marked, delete now" << sent->IdString());
1692 continue;
1693 }
1694
1695 if (!(sent->GetRemoteInfo() *= src.GetRemoteInfo())) {
1696 PTRACE(5, "mismatch in remote info");
1697 continue;
1698 }
1699
1700 if (sent->GetSequenceInfo().OutSeqNo() <= srcOutSeqNo) {
1701 sent->MarkVnakSendNow();
1702 }
1703 }
1704 }
1705
Initialise()1706 void IAX2FrameList::Initialise()
1707 {
1708 PWaitAndSignal m(mutex);
1709 DisallowDeleteObjects();
1710 }
1711
GetResendFramesDeleteOldFrames(IAX2FrameList & framesToSend)1712 void IAX2FrameList::GetResendFramesDeleteOldFrames(IAX2FrameList &framesToSend)
1713 {
1714 PWaitAndSignal m(mutex);
1715 PTRACE(5, "ID# GetResendFramesDeleteOldFrames start");
1716
1717 if (GetSize() == 0) {
1718 PTRACE(5, "No frames to be resent.");
1719 PTRACE(5, "ID# GetResendFramesDeleteOldFrames end cause empty");
1720 return;
1721 }
1722
1723 for (PINDEX i = GetEntries(); i > 0; i--) {
1724 IAX2FullFrame *active = (IAX2FullFrame *)PAbstractList::GetAt(i - 1);
1725 if (active == NULL)
1726 continue;
1727
1728 if (active->DeleteFrameNow()) {
1729 PTRACE(5, "marked as delete now, so delete" << *active);
1730 delete active;
1731 active = NULL;
1732 PAbstractList::RemoveAt(i - 1);
1733 continue;
1734 }
1735
1736 if (active->SendFrameNow()) {
1737 PAbstractList::RemoveAt(i - 1);
1738 framesToSend.AddNewFrame(active);
1739 }
1740 }
1741 PTRACE(4, "Have collected " << framesToSend.GetSize() << " frames to onsend");
1742 PTRACE(5, "ID# GetResendFramesDeleteOldFrames end ");
1743 return;
1744 }
1745
MarkAllAsResent()1746 void IAX2FrameList::MarkAllAsResent()
1747 {
1748 PWaitAndSignal m(mutex);
1749
1750 for (PINDEX i = 0; i < GetEntries(); i++) {
1751 IAX2FullFrame *active = (IAX2FullFrame *)PAbstractList::GetAt(i);
1752 active->MarkAsResent();
1753 }
1754 }
1755
1756
1757 #endif // OPAL_IAX2
1758
1759
1760 ////////////////////////////////////////////////////////////////////////////////
1761 /* The comment below is magic for those who use emacs to edit this file.
1762 * With the comment below, the tab key does auto indent to 2 spaces.
1763 *
1764 * Local Variables:
1765 * mode:c
1766 * c-basic-offset:2
1767 * End:
1768 */
1769
1770