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