1 /*
2 *
3 * Inter Asterisk Exchange 2
4 *
5 * Implementation of the IAX2 extensions to the OpalEndpoint class.
6 * There is one instance of this class in the Opal environemnt.
7 *
8 * Open Phone Abstraction Library (OPAL)
9 *
10 * Copyright (c) 2005 Indranet Technologies Ltd.
11 *
12 * The contents of this file are subject to the Mozilla Public License
13 * Version 1.0 (the "License"); you may not use this file except in
14 * compliance with the License. You may obtain a copy of the License at
15 * http://www.mozilla.org/MPL/
16 *
17 * Software distributed under the License is distributed on an "AS IS"
18 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
19 * the License for the specific language governing rights and limitations
20 * under the License.
21 *
22 * The Original Code is Open Phone Abstraction Library.
23 *
24 * The Initial Developer of the Original Code is Indranet Technologies Ltd.
25 *
26 * The author of this code is Derek J Smithies
27 *
28 * $Revision: 25368 $
29 * $Author: rjongbloed $
30 * $Date: 2011-03-21 01:34:07 -0500 (Mon, 21 Mar 2011) $
31 */
32
33 #include <ptlib.h>
34 #include <opal/buildopts.h>
35
36 #if OPAL_IAX2
37
38 #ifdef P_USE_PRAGMA
39 #pragma implementation "iax2ep.h"
40 #endif
41
42 #include <iax2/iax2ep.h>
43 #include <iax2/receiver.h>
44 #include <iax2/transmit.h>
45 #include <iax2/specialprocessor.h>
46
47 #include <ptclib/random.h>
48
49 #define new PNEW
50
51
52 ////////////////////////////////////////////////////////////////////////////////
53
IAX2EndPoint(OpalManager & mgr,unsigned short port)54 IAX2EndPoint::IAX2EndPoint(OpalManager & mgr, unsigned short port)
55 : OpalEndPoint(mgr, "iax2", CanTerminateCall|SupportsE164)
56 , localPort(port)
57 {
58
59 localUserName = mgr.GetDefaultUserName();
60 localNumber = "1234";
61
62 statusQueryCounter = 1;
63 specialPacketHandler = new IAX2SpecialProcessor(*this);
64
65 transmitter = NULL;
66 receiver = NULL;
67 sock = NULL;
68 callsEstablished.SetValue(0);
69
70 IAX2IeCallToken::InitialiseKey();
71 //We handle the deletion of regProcessor objects.
72 regProcessors.AllowDeleteObjects(PFalse);
73
74 Initialise();
75 PTRACE(5, "Iax2Ep\tCreated endpoint.");
76 }
77
~IAX2EndPoint()78 IAX2EndPoint::~IAX2EndPoint()
79 {
80 PTRACE(5, "Iax2Ep\tIaxEndPoint destructor. Terminate the transmitter, receiver, and incoming frame handler.");
81
82 //contents of this array are automatically shifted when removed
83 //so we only need to loop through the first element until all
84 //elements are removed
85 while (regProcessors.GetSize()) {
86 IAX2RegProcessor *regProcessor = (IAX2RegProcessor*)regProcessors.GetAt(0);
87 regProcessor->Unregister();
88 regProcessors.RemoveAt(0);
89 delete regProcessor;
90 }
91
92 PTRACE(6, "Iax2Ep\tDestructor - cleaned up the different registration processeors");
93
94 incomingFrameHandler.Terminate();
95 incomingFrameHandler.WaitForTermination();
96 packetsReadFromEthernet.AllowDeleteObjects();
97 PTRACE(6, "Iax2Ep\tDestructor - cleaned up the incoming frame handler");
98
99 if (receiver != NULL && transmitter != NULL) {
100 transmitter->Terminate();
101 receiver->Terminate();
102 transmitter->WaitForTermination();
103 PTRACE(6, "Iax2Ep\tDestructor - cleaned up the iax2 transmitter");
104 receiver->WaitForTermination();
105 PTRACE(6, "Iax2Ep\tDestructor - cleaned up the iax2 receiver");
106 }
107
108 if (specialPacketHandler != NULL) {
109 specialPacketHandler->Terminate();
110 specialPacketHandler->WaitForTermination();
111 delete specialPacketHandler;
112 PTRACE(6, "Iax2Ep\tDestructor - cleaned up the iax2 special packet handler");
113 }
114 specialPacketHandler = NULL;
115
116 if (transmitter != NULL)
117 delete transmitter;
118 if (receiver != NULL)
119 delete receiver;
120
121 if (sock != NULL)
122 delete sock;
123
124 PTRACE(6, "Iax2Ep\tDESTRUCTOR of IAX2 endpoint has Finished.");
125 }
126
ReportTransmitterLists(PString & answer,bool getFullReport)127 void IAX2EndPoint::ReportTransmitterLists(PString & answer, bool getFullReport)
128 {
129 transmitter->ReportLists(answer, getFullReport);
130 }
131
NewIncomingConnection(OpalTransport *)132 PBoolean IAX2EndPoint::NewIncomingConnection(OpalTransport * /*transport*/)
133 {
134 return PTrue;
135 }
136
NewIncomingConnection(IAX2Frame * f)137 void IAX2EndPoint::NewIncomingConnection(IAX2Frame *f)
138 {
139 PTRACE(3, "IAX2\tWe have received a NEW request from " << f->GetConnectionToken());
140
141 if (connectionsActive.Contains(f->GetConnectionToken())) {
142 /*Have received a duplicate new packet */
143 PTRACE(3, "IAX2\thave received a duplicate new packet from "
144 << f->GetConnectionToken());
145 delete f;
146 return;
147 }
148
149 /* We need to extract the username from the incoming frame. We have to
150 do this now, before establishing the connection. */
151 IAX2FullFrameProtocol ffp(*f);
152
153 PString userName;
154 PString host = f->GetRemoteInfo().RemoteAddress();
155
156 {
157 IAX2RegProcessor *regProcessor = NULL;
158
159 PWaitAndSignal m(regProcessorsMutex);
160
161 PINDEX size = regProcessors.GetSize();
162 for (PINDEX i = 0; i < size; i++) {
163 regProcessor = (IAX2RegProcessor*)regProcessors.GetAt(i);
164
165 if (regProcessor->GetHost() == host) {
166 userName = regProcessor->GetUserName();
167 break;
168 }
169 }
170 }
171
172 /* take the info in the NEW packet and use it to build information about the
173 person who is calling us */
174 IAX2IeData ieData;
175 ffp.CopyDataFromIeListTo(ieData);
176 PString url = BuildUrl(host, userName, ieData.callingNumber);
177
178 // Get new instance of a call, abort if none created
179 OpalCall * call = manager.InternalCreateCall();
180 if (call == NULL)
181 return;
182
183 /* We have completed the extraction of information process. Now we can
184 build the matching connection */
185 IAX2Connection *connection = CreateConnection(*call, f->GetConnectionToken(), NULL, url, ieData.callingName);
186 if (!AddConnection(connection)) {
187 PTRACE(2, "IAX2\tFailed to create IAX2Connection for NEW request from "
188 << f->GetConnectionToken());
189 delete f;
190 delete connection;
191
192 return;
193 }
194
195 /*Now activate the connection and start processing packets */
196 connection->StartOperation();
197 connection->IncomingEthernetFrame(f);
198 }
199
200
OnEstablished(OpalConnection & con)201 void IAX2EndPoint::OnEstablished(OpalConnection & con)
202 {
203 PTRACE(3, "Iax2Ep\tOnEstablished for " << con);
204
205 OpalEndPoint::OnEstablished(con);
206 }
207
NextSrcCallNumber(IAX2Processor *)208 PINDEX IAX2EndPoint::NextSrcCallNumber(IAX2Processor * /*processor*/)
209 {
210 PWaitAndSignal m(callNumbLock);
211
212 PINDEX callno = callnumbs++;
213
214 if (callnumbs > 32766)
215 callnumbs = 1;
216
217 return callno;
218 }
219
220
ConnectionForFrameIsAlive(IAX2Frame * f)221 PBoolean IAX2EndPoint::ConnectionForFrameIsAlive(IAX2Frame *f)
222 {
223 PString frameToken = f->GetConnectionToken();
224
225 // ReportStoredConnections();
226
227 PBoolean res = connectionsActive.Contains(frameToken);
228 if (res) {
229 return PTrue;
230 }
231
232 mutexTokenTable.StartRead();
233 PString tokenTranslated = tokenTable(frameToken);
234 mutexTokenTable.EndRead();
235
236 if (tokenTranslated.IsEmpty()) {
237 PTRACE(4, "No matching translation table entry token for \"" << frameToken << "\"");
238 return PFalse;
239 }
240
241 res = connectionsActive.Contains(tokenTranslated);
242 if (res) {
243 PTRACE(5, "Found \"" << tokenTranslated << "\" in the connectionsActive table");
244 return PTrue;
245 }
246
247 PTRACE(6, "ERR Could not find matching connection for \"" << tokenTranslated
248 << "\" or \"" << frameToken << "\"");
249 return PFalse;
250 }
251
ReportStoredConnections()252 void IAX2EndPoint::ReportStoredConnections()
253 {
254 PStringArray cons = GetAllConnections();
255 PTRACE(5, " There are " << cons.GetSize() << " stored connections in connectionsActive");
256 PINDEX i;
257 for(i = 0; i < cons.GetSize(); i++) {
258 PTRACE(5, " #" << (i + 1) << " \"" << cons[i] << "\"");
259 }
260
261 mutexTokenTable.StartRead();
262 PTRACE(5, " There are " << tokenTable.GetSize()
263 << " stored connections in the token translation table.");
264 for (i = 0; i < tokenTable.GetSize(); i++) {
265 PTRACE(5, " token table at " << i << " is "
266 << tokenTable.GetKeyAt(i) << " " << tokenTable.GetDataAt(i));
267 }
268 mutexTokenTable.EndRead();
269 }
270
DissectRemoteParty(const PString & other)271 PStringArray IAX2EndPoint::DissectRemoteParty(const PString & other)
272 {
273 PStringArray res(maximumIndex);
274
275 res[protoIndex] = PString("iax2");
276 res[transportIndex] = PString("UDP");
277
278 PString working;
279 if (other.Find("iax2:") != P_MAX_INDEX) //Remove iax2: from "other"
280 working = other.Mid(5);
281 else
282 working = other;
283
284 PStringArray halfs = working.Tokenise("@");
285 if (halfs.GetSize() == 2) {
286 res[userIndex] = halfs[0];
287 working = halfs[1];
288 } else
289 working = halfs[0];
290
291 halfs = working.Tokenise("$");
292 if (halfs.GetSize() == 2) {
293 res[transportIndex] = halfs[0];
294 working = halfs[1];
295 } else
296 working = halfs[0];
297
298 halfs = working.Tokenise("/");
299 res[addressIndex] = halfs[0];
300 if (halfs.GetSize() == 2) {
301 working = halfs[1];
302 halfs = working.Tokenise("+");
303 res[extensionIndex] = halfs[0];
304 if (halfs.GetSize() == 2)
305 res[contextIndex] = halfs[1];
306 }
307
308 halfs = res[addressIndex].Tokenise(":");
309 if (halfs.GetSize() == 2) {
310 res[addressIndex] = halfs[0];
311 res[portIndex] = halfs[1];
312 }
313
314 PTRACE(4, "Opal\t call protocol " << res[protoIndex]);
315 PTRACE(4, "Opal\t destination user " << res[userIndex]);
316 PTRACE(4, "Opal\t transport to use " << res[transportIndex]);
317 PTRACE(4, "Opal\t destination address " << res[addressIndex]);
318 PTRACE(4, "Opal\t destination port " << res[portIndex]);
319 PTRACE(4, "Opal\t destination extension " << res[extensionIndex]);
320 PTRACE(4, "Opal\t destination context " << res[contextIndex]);
321
322 return res;
323 }
324
BuildUrl(const PString & host,const PString & userName,const PString & extension,const PString & context,const PString & transport)325 PString IAX2EndPoint::BuildUrl(
326 const PString & host,
327 const PString & userName,
328 const PString & extension,
329 const PString & context,
330 const PString & transport
331 )
332 {
333 PString url;
334
335 url = host;
336
337 if (!extension.IsEmpty())
338 url = url + "/" + extension;
339
340 if (!context.IsEmpty() && context != "Default")
341 url = url + "+" + context;
342
343 if (!transport.IsEmpty())
344 url = transport + "$" + url;
345
346 if (!userName.IsEmpty())
347 url = userName + "@" + url;
348
349 return url;
350 }
351
OnReleased(OpalConnection & opalCon)352 void IAX2EndPoint::OnReleased(OpalConnection & opalCon)
353 {
354 IAX2Connection &con((IAX2Connection &)opalCon);
355
356 PString token(con.GetRemoteInfo().BuildOurConnectionToken());
357 mutexTokenTable.StartWrite();
358 tokenTable.RemoveAt(token);
359 mutexTokenTable.EndWrite();
360 OpalEndPoint::OnReleased(opalCon);
361 }
362
MakeConnection(OpalCall & call,const PString & rParty,void * userData,unsigned int,OpalConnection::StringOptions *)363 PSafePtr<OpalConnection> IAX2EndPoint::MakeConnection(OpalCall & call,
364 const PString & rParty,
365 void * userData,
366 unsigned int /*options*/,
367 OpalConnection::StringOptions * /*stringOptions*/)
368 {
369 /* This method is called as Step 1 of making an IAX call to some remote destination
370 this method is invoked by the OpalManager, who controls everything, in response by a
371 users desire to talk to someone else */
372
373 PTRACE(3, "IaxEp\tTry to make iax2 call to " << rParty);
374 PTRACE(5, "IaxEp\tParty A=\"" << call.GetPartyA()
375 << "\" and party B=\"" << call.GetPartyB() << "\"");
376 PStringArray remoteInfo = DissectRemoteParty(rParty);
377 if(remoteInfo[protoIndex] != PString("iax2"))
378 return NULL;
379
380 PString remotePartyName = rParty.Mid(5);
381
382 PIPSocket::Address ip;
383 if (!PIPSocket::GetHostAddress(remoteInfo[addressIndex], ip)) {
384 PTRACE(3, "Could not make a iax2 call to " << remoteInfo[addressIndex]
385 << " as IP resolution failed");
386 return NULL;
387 }
388
389 PStringStream callId;
390 callId << "iax2:" << ip.AsString() << "Out" << PString(++callsEstablished);
391 IAX2Connection * connection = CreateConnection(call, callId, userData, remotePartyName);
392 if (AddConnection(connection) == NULL)
393 return NULL;
394
395 connection->StartOperation();
396 //search through the register srcProcessors to see if there is a relevant userName
397 //and password we can use for authentication. If there isn't then the default
398 //userName and password of this endpoint will be used instead.
399 {
400 PWaitAndSignal m(regProcessorsMutex);
401 PINDEX size = regProcessors.GetSize();
402
403 for (PINDEX i = 0; i < size; i++) {
404 IAX2RegProcessor *regProcessor = (IAX2RegProcessor*)regProcessors.GetAt(i);
405
406 if (regProcessor->GetHost() == remoteInfo[addressIndex]) {
407 PString userName = regProcessor->GetUserName();
408 PString password = regProcessor->GetPassword();
409
410 connection->SetUserName(userName);
411 connection->SetPassword(password);
412 break;
413 }
414 }
415 }
416
417 return connection;
418 }
419
CreateConnection(OpalCall & call,const PString & token,void * userData,const PString & remoteParty,const PString & remotePartyName)420 IAX2Connection * IAX2EndPoint::CreateConnection(
421 OpalCall & call,
422 const PString & token,
423 void * userData,
424 const PString & remoteParty,
425 const PString & remotePartyName)
426 {
427 return new IAX2Connection(call, *this, token, userData, remoteParty, remotePartyName);
428 }
429
GetMediaFormats() const430 OpalMediaFormatList IAX2EndPoint::GetMediaFormats() const
431 {
432 return localMediaFormats;
433 }
434
Initialise()435 PBoolean IAX2EndPoint::Initialise()
436 {
437 transmitter = NULL;
438 receiver = NULL;
439
440 localMediaFormats = OpalMediaFormat::GetAllRegisteredMediaFormats();
441 OpalMediaFormatList::iterator iterFormat = localMediaFormats.begin();
442 while (iterFormat != localMediaFormats.end()) {
443 if (IAX2FullFrameVoice::OpalNameToIax2Value(*iterFormat) != 0)
444 ++iterFormat;
445 else
446 localMediaFormats.erase(iterFormat++);
447 }
448
449 incomingFrameHandler.Assign(this);
450 packetsReadFromEthernet.Initialise();
451
452 PTRACE(6, "IAX2EndPoint\tInitialise()");
453 PRandom rand;
454 rand.SetSeed((DWORD)(PTime().GetTimeInSeconds() + 1));
455 callnumbs = PRandom::Number() % 32000;
456
457 sock = new PUDPSocket(localPort);
458 PTRACE(4, "IAX2EndPoint\tCreate Socket " << sock->GetPort());
459
460 if (!sock->Listen(INADDR_ANY, 0, localPort)) {
461 PTRACE(3, "Receiver\tFailed to listen for incoming connections on " << localPort);
462 PTRACE(3, "Receiver\tFailed because the socket:::" << sock->GetErrorText());
463 return PFalse;
464 }
465
466 PTRACE(6, "Receiver\tYES.. Ready for incoming connections on " << localPort);
467
468 transmitter = new IAX2Transmit(*this, *sock);
469 receiver = new IAX2Receiver(*this, *sock);
470
471 return PTrue;
472 }
473
GetOutSequenceNumberForStatusQuery()474 PINDEX IAX2EndPoint::GetOutSequenceNumberForStatusQuery()
475 {
476 PWaitAndSignal m(statusQueryMutex);
477
478 if (statusQueryCounter > 240)
479 statusQueryCounter = 1;
480
481 return statusQueryCounter++;
482 }
483
484
ProcessInConnectionTestAll(IAX2Frame * frame)485 PBoolean IAX2EndPoint::ProcessInConnectionTestAll(IAX2Frame *frame)
486 {
487 if (!frame->IsFullFrame()) {
488 // Do Not have a FullFrame, so dont add a translation entry.
489 // Only process miniframes when the call is setup, when we have a
490 // translation table in place and working...
491 return PFalse;
492 }
493
494 PINDEX destCallNo = frame->GetRemoteInfo().DestCallNumber();
495 /*destCallNo is the call number at our end. We do not know if the
496 frame is encrypted, so examination of anything other than the
497 source call number/dest call number is unwise */
498
499 PString callToken;
500 {
501 PSafePtr<IAX2Connection> connection;
502 for (connection = PSafePtrCast<OpalConnection, IAX2Connection>
503 (connectionsActive.GetAt(0));
504 connection != NULL;
505 ++connection) {
506 if (connection->GetRemoteInfo().SourceCallNumber() == destCallNo) {
507 PString token(frame->GetConnectionToken());
508 callToken = connection->GetCallToken();
509 if (!token.IsEmpty()) /* token available, modify token table */ {
510 mutexTokenTable.StartWrite();
511 tokenTable.SetAt(token, callToken);
512 mutexTokenTable.EndWrite();
513 }
514 }
515 }
516 }
517
518 if (callToken.IsEmpty()) {
519 PTRACE(3, "Iax2Ep\tFail to find home for the frame " << *frame);
520 return PFalse;
521 }
522
523 PTRACE(5, "Iax2Ep\tProcess " << *frame << " in connection" << callToken);
524 return ProcessFrameInConnection(frame, callToken);
525 }
526
527
ProcessInMatchingConnection(IAX2Frame * f)528 PBoolean IAX2EndPoint::ProcessInMatchingConnection(IAX2Frame *f)
529 {
530 ReportStoredConnections();
531
532 PString tokenTranslated;
533 mutexTokenTable.StartRead();
534 tokenTranslated = tokenTable(f->GetConnectionToken());
535 mutexTokenTable.EndRead();
536
537 if (tokenTranslated.IsEmpty())
538 tokenTranslated = f->GetConnectionToken();
539
540 if (tokenTranslated.IsEmpty()) {
541 PTRACE(3, "Distribution\tERR Could not find matching connection "
542 << "for incoming frame of " << f->GetRemoteInfo());
543 return PFalse;
544 }
545
546 return ProcessFrameInConnection(f, tokenTranslated);
547 }
548
ProcessFrameInConnection(IAX2Frame * f,const PString & token)549 PBoolean IAX2EndPoint::ProcessFrameInConnection(IAX2Frame *f,
550 const PString & token)
551 {
552 IAX2Connection *connection;
553 connection = PSafePtrCast<OpalConnection, IAX2Connection>
554 (connectionsActive.FindWithLock(token));
555 if (connection != NULL) {
556 PTRACE(5, "Distribution\tHave a connection for " << f->GetRemoteInfo());
557 connection->IncomingEthernetFrame(f);
558 return PTrue;
559 }
560
561 PTRACE(3, "Distribution\tERR Could not find matching connection for \""
562 << token << "\" or \"" << f->GetConnectionToken() << "\"");
563 return PFalse;
564 }
565
566 //The receiving thread has finished reading a frame, and has droppped it here.
567 //At this stage, we do not know the frame type. We just know the frame is
568 // of type full or mini.
569 //The frame has not been acknowledged, or replied to.
IncomingEthernetFrame(IAX2Frame * frame)570 void IAX2EndPoint::IncomingEthernetFrame(IAX2Frame *frame)
571 {
572 PTRACE(5, "IAXEp\tEthernet Frame received from Receiver " << frame->IdString());
573
574 packetsReadFromEthernet.AddNewFrame(frame);
575 incomingFrameHandler.ProcessList();
576 }
577
ProcessReceivedEthernetFrames()578 void IAX2EndPoint::ProcessReceivedEthernetFrames()
579 {
580 IAX2Frame *f;
581 do {
582 f = packetsReadFromEthernet.GetLastFrame();
583 if (f == NULL) {
584 continue;
585 }
586
587 PString idString = f->IdString();
588 PTRACE(5, "Distribution\tNow try to find a home for " << idString);
589 if (ProcessInMatchingConnection(f)) {
590 continue;
591 }
592
593 if (ProcessInConnectionTestAll(f))
594 continue;
595
596 /**These packets cannot be encrypted, as they are not going to a phone call */
597 IAX2Frame *af = f->BuildAppropriateFrameType();
598 delete f;
599 if (af == NULL)
600 continue;
601 f = af;
602
603 if (specialPacketHandler->IsStatusQueryEthernetFrame(f)) {
604 PTRACE(3, "Distribution\tthis frame is a Status Query with no destination call" << idString);
605 specialPacketHandler->IncomingEthernetFrame(f);
606 continue;
607 }
608
609 if (!PIsDescendant(f, IAX2FullFrame)) {
610 PTRACE(3, "Distribution\tNo matching connection for network frame."
611 << " Deleting " << idString);
612 delete f;
613 continue;
614 }
615
616 IAX2FullFrame *ff = (IAX2FullFrame *)f;
617 if (ff->IsAckFrame()) {// snuck in here after termination. may be an ack for hangup ?
618 PTRACE(3, "Distribution\t***** it's an ACK " << idString);
619 /* purge will check for remote, call id, etc */
620 transmitter->PurgeMatchingFullFrames(ff);
621 delete ff;
622 continue;
623 }
624
625 if (ff->GetFrameType() != IAX2FullFrame::iax2ProtocolType) {
626 PTRACE(3, "Distribution\tNO matching connection for incoming ethernet frame Sorry" << idString);
627 delete ff;
628 continue;
629 }
630
631 if (ff->GetSubClass() != IAX2FullFrameProtocol::cmdNew) {
632 PTRACE(3, "Distribution\tNO matching connection for incoming ethernet frame Sorry" << idString);
633 delete ff;
634 continue;
635 }
636
637 NewIncomingConnection(f);
638
639 } while (f != NULL);
640 }
641
GetPreferredCodec(OpalMediaFormatList & list)642 PINDEX IAX2EndPoint::GetPreferredCodec(OpalMediaFormatList & list)
643 {
644 PTRACE(4, "Iax2Ep\tPreferred codecs are " << list);
645
646 for (OpalMediaFormatList::iterator iterFormat = list.begin(); iterFormat != list.end(); ++iterFormat) {
647 unsigned short val = IAX2FullFrameVoice::OpalNameToIax2Value(*iterFormat);
648 if (val != 0) {
649 PTRACE(4, "Iax2Ep\tPreferred codec is " << *iterFormat);
650 return val;
651 }
652 }
653
654 PTRACE(4, "Preferred codec is empty");
655 return 0;
656 }
657
GetCodecLengths(PINDEX codec,PINDEX & compressedBytes,PINDEX & duration)658 void IAX2EndPoint::GetCodecLengths(PINDEX codec, PINDEX &compressedBytes, PINDEX &duration)
659 {
660 switch (codec) {
661 case IAX2FullFrameVoice::g7231:
662 compressedBytes = 24;
663 duration = 30;
664 return;
665 case IAX2FullFrameVoice::gsm:
666 compressedBytes = 33;
667 duration = 20;
668 return;
669 case IAX2FullFrameVoice::g711ulaw:
670 case IAX2FullFrameVoice::g711alaw:
671 compressedBytes = 160;
672 duration = 20;
673 return;
674 case IAX2FullFrameVoice::pcm:
675 compressedBytes = 16;
676 duration = 1;
677 case IAX2FullFrameVoice::mp3:
678 case IAX2FullFrameVoice::adpcm:
679 case IAX2FullFrameVoice::lpc10:
680 case IAX2FullFrameVoice::g729:
681 case IAX2FullFrameVoice::speex:
682 case IAX2FullFrameVoice::ilbc:
683
684 default: ;
685
686 }
687
688 PTRACE(1, "ERROR - could not find format " << IAX2FullFrameVoice::GetOpalNameOfCodec(codec) << " so use 20ms");
689 duration = 20;
690 compressedBytes = 33;
691 }
692
GetSupportedCodecs(OpalMediaFormatList & list)693 PINDEX IAX2EndPoint::GetSupportedCodecs(OpalMediaFormatList & list)
694 {
695 PTRACE(4, "Iax2Ep\tSupported codecs are " << list);
696
697 PINDEX returnValue = 0;
698 for (OpalMediaFormatList::iterator iterFormat = list.begin(); iterFormat != list.end(); ++iterFormat)
699 returnValue += IAX2FullFrameVoice::OpalNameToIax2Value(*iterFormat);
700
701 PTRACE(5, "Iax2Ep\tBitmask of codecs we support is 0x" << ::hex << returnValue << ::dec);
702
703 return returnValue;
704 }
705
CopyLocalMediaFormats(OpalMediaFormatList & list)706 void IAX2EndPoint::CopyLocalMediaFormats(OpalMediaFormatList & list)
707 {
708 list = localMediaFormats;
709 }
710
SetPassword(PString newValue)711 void IAX2EndPoint::SetPassword(PString newValue)
712 {
713 password = newValue;
714 }
715
SetLocalUserName(PString newValue)716 void IAX2EndPoint::SetLocalUserName(PString newValue)
717 {
718 localUserName = newValue;
719 }
720
SetLocalNumber(PString newValue)721 void IAX2EndPoint::SetLocalNumber(PString newValue)
722 {
723 localNumber = newValue;
724 }
725
Register(const PString & host,const PString & username,const PString & password,PINDEX requestedRefreshTime)726 void IAX2EndPoint::Register(
727 const PString & host,
728 const PString & username,
729 const PString & password,
730 PINDEX requestedRefreshTime)
731 {
732 PWaitAndSignal m(regProcessorsMutex);
733
734 IAX2RegProcessor *regProcessor =
735 new IAX2RegProcessor(*this, host, username, password, requestedRefreshTime);
736 regProcessors.Append(regProcessor);
737 }
738
OnRegistered(const PString &,const PString &,PBoolean,RegisteredError)739 void IAX2EndPoint::OnRegistered(
740 const PString & /*host*/,
741 const PString & /*username*/,
742 PBoolean /*isFailure*/,
743 RegisteredError /*reason*/)
744 {
745 PTRACE(2, "registration event occured");
746 }
747
OnUnregistered(const PString &,const PString &,PBoolean,UnregisteredError)748 void IAX2EndPoint::OnUnregistered(
749 const PString & /*host*/,
750 const PString & /*username*/,
751 PBoolean /*isFailure*/,
752 UnregisteredError /*reason*/)
753 {
754 PTRACE(2, "unregistration event occured");
755 }
756
Unregister(const PString & host,const PString & username)757 void IAX2EndPoint::Unregister(
758 const PString & host,
759 const PString & username)
760 {
761 IAX2RegProcessor *removeRegProcesser = NULL;
762
763 //this section and loop is optimized to remove
764 //the time the lock will be held.
765 {
766 PWaitAndSignal m(regProcessorsMutex);
767 PINDEX size = regProcessors.GetSize();
768
769 for (PINDEX i = 0; i < size; i++) {
770 IAX2RegProcessor *regProcessor = (IAX2RegProcessor*)regProcessors.GetAt(i);
771
772 if (regProcessor->GetHost() == host &&
773 regProcessor->GetUserName() == username) {
774 regProcessors.RemoveAt(i);
775 removeRegProcesser = regProcessor;
776 break;
777 }
778 }
779 }
780
781 if (removeRegProcesser != NULL) {
782 removeRegProcesser->Unregister();
783 delete removeRegProcesser;
784 }
785 }
786
IsRegistered(const PString & host,const PString & username)787 PBoolean IAX2EndPoint::IsRegistered(const PString & host, const PString & username)
788 {
789 PWaitAndSignal m(regProcessorsMutex);
790
791 PINDEX size = regProcessors.GetSize();
792
793 for (PINDEX i = 0; i < size; i++) {
794 IAX2RegProcessor *regProcessor = (IAX2RegProcessor*)regProcessors.GetAt(i);
795
796 if (regProcessor->GetHost() == host &&
797 regProcessor->GetUserName() == username) {
798 return PTrue;
799 }
800 }
801
802 return PFalse;
803 }
804
GetRegistrationsCount()805 PINDEX IAX2EndPoint::GetRegistrationsCount() {
806 PWaitAndSignal m(regProcessorsMutex);
807 return regProcessors.GetSize();
808 }
809
810 ////////////////////////////////////////////////////////////////////////////////
811
IAX2IncomingEthernetFrames()812 IAX2IncomingEthernetFrames::IAX2IncomingEthernetFrames()
813 : PThread(1000, NoAutoDeleteThread, NormalPriority, "IAX Incoming")
814 {
815 keepGoing = PTrue;
816 }
817
Assign(IAX2EndPoint * ep)818 void IAX2IncomingEthernetFrames::Assign(IAX2EndPoint *ep)
819 {
820 endpoint = ep;
821 Resume();
822 }
823
Terminate()824 void IAX2IncomingEthernetFrames::Terminate()
825 {
826 PTRACE(3, "Distribute\tEnd of thread - have received a terminate signal");
827 keepGoing = PFalse;
828 ProcessList();
829 }
830
Main()831 void IAX2IncomingEthernetFrames::Main()
832 {
833 SetThreadName("Distribute to Cons");
834 while (keepGoing) {
835 if (!endpoint->EthernetFramesToBeProcessed())
836 activate.Wait();
837 endpoint->ProcessReceivedEthernetFrames();
838 }
839
840 PTRACE(3, "Distribute\tEnd of thread - Do no more work now");
841 return;
842 }
843
844 #endif // OPAL_IAX2
845
846 /* The comment below is magic for those who use emacs to edit this file.
847 * With the comment below, the tab key does auto indent to 2 spaces.
848 *
849 * Local Variables:
850 * mode:c
851 * c-basic-offset:2
852 * End:
853 */
854
855
856
857