1 /*
2  * h323trans.cxx
3  *
4  * H.323 Transactor handler
5  *
6  * Open H323 Library
7  *
8  * Copyright (c) 2003 Equivalence Pty. Ltd.
9  *
10  * The contents of this file are subject to the Mozilla Public License
11  * Version 1.0 (the "License"); you may not use this file except in
12  * compliance with the License. You may obtain a copy of the License at
13  * http://www.mozilla.org/MPL/
14  *
15  * Software distributed under the License is distributed on an "AS IS"
16  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
17  * the License for the specific language governing rights and limitations
18  * under the License.
19  *
20  * The Original Code is Open H323 Library.
21  *
22  * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
23  *
24  * Contributor(s): ______________________________________.
25  *
26  * $Revision: 22170 $
27  * $Author: rjongbloed $
28  * $Date: 2009-03-08 21:48:51 -0500 (Sun, 08 Mar 2009) $
29  */
30 
31 #include <ptlib.h>
32 
33 #include <opal/buildopts.h>
34 #if OPAL_H323
35 
36 #ifdef __GNUC__
37 #pragma implementation "h323trans.h"
38 #endif
39 
40 #include <h323/h323trans.h>
41 
42 #include <h323/h323ep.h>
43 #include <h323/h323pdu.h>
44 
45 #include <ptclib/random.h>
46 
47 
48 static PTimeInterval ResponseRetirementAge(0, 30); // Seconds
49 
50 
51 #define new PNEW
52 
53 
54 static struct AuthenticatorString {
55   int code;
56   const char * desc;
57 } authenticatorStrings[] = {
58   { H235Authenticator::e_OK,          "Security parameters and Msg are ok, no security attacks" },
59   { H235Authenticator::e_Absent,      "Security parameters are expected but absent" },
60   { H235Authenticator::e_Error,       "Security parameters are present but incorrect" },
61   { H235Authenticator::e_InvalidTime, "Security parameters indicate peer has bad real time clock" },
62   { H235Authenticator::e_BadPassword, "Security parameters indicate bad password in token" },
63   { H235Authenticator::e_ReplyAttack, "Security parameters indicate an attack was made" },
64   { H235Authenticator::e_Disabled,    "Security is disabled by local system" },
65   { -1, NULL }
66 };
67 
68 /////////////////////////////////////////////////////////////////////////////////
69 
H323TransactionPDU()70 H323TransactionPDU::H323TransactionPDU()
71 {
72 }
73 
74 
H323TransactionPDU(const H235Authenticators & auth)75 H323TransactionPDU::H323TransactionPDU(const H235Authenticators & auth)
76   : authenticators(auth)
77 {
78 }
79 
80 
operator <<(ostream & strm,const H323TransactionPDU & pdu)81 ostream & operator<<(ostream & strm, const H323TransactionPDU & pdu)
82 {
83   pdu.GetPDU().PrintOn(strm);
84   return strm;
85 }
86 
87 
Read(H323Transport & transport)88 PBoolean H323TransactionPDU::Read(H323Transport & transport)
89 {
90   if (!transport.ReadPDU(rawPDU)) {
91     PTRACE(1, GetProtocolName() << "\tRead error ("
92            << transport.GetErrorNumber(PChannel::LastReadError)
93            << "): " << transport.GetErrorText(PChannel::LastReadError));
94     return PFalse;
95   }
96 
97   rawPDU.ResetDecoder();
98   PBoolean ok = GetPDU().Decode(rawPDU);
99   if (!ok) {
100     PTRACE(1, GetProtocolName() << "\tRead error: PER decode failure:\n  "
101            << setprecision(2) << rawPDU << "\n "  << setprecision(2) << *this);
102     GetChoice().SetTag(UINT_MAX);
103     return PTrue;
104   }
105 
106   H323TraceDumpPDU(GetProtocolName(), PFalse, rawPDU, GetPDU(), GetChoice(), GetSequenceNumber());
107 
108   return PTrue;
109 }
110 
111 
Write(H323Transport & transport)112 PBoolean H323TransactionPDU::Write(H323Transport & transport)
113 {
114   PPER_Stream strm;
115   GetPDU().Encode(strm);
116   strm.CompleteEncoding();
117 
118   // Finalise the security if present
119   for (H235Authenticators::iterator iterAuth = authenticators.begin(); iterAuth != authenticators.end(); ++iterAuth)
120     iterAuth->Finalise(strm);
121 
122   H323TraceDumpPDU("Trans", PTrue, strm, GetPDU(), GetChoice(), GetSequenceNumber());
123 
124   if (transport.WritePDU(strm))
125     return PTrue;
126 
127   PTRACE(1, GetProtocolName() << "\tWrite PDU failed ("
128          << transport.GetErrorNumber(PChannel::LastWriteError)
129          << "): " << transport.GetErrorText(PChannel::LastWriteError));
130   return PFalse;
131 }
132 
133 
134 /////////////////////////////////////////////////////////////////////////////////
135 
H323Transactor(H323EndPoint & ep,H323Transport * trans,WORD local_port,WORD remote_port)136 H323Transactor::H323Transactor(H323EndPoint & ep,
137                                H323Transport * trans,
138                                WORD local_port,
139                                WORD remote_port)
140   : endpoint(ep),
141     defaultLocalPort(local_port),
142     defaultRemotePort(remote_port)
143 {
144   if (trans != NULL)
145     transport = trans;
146   else
147     transport = new H323TransportUDP(ep, PIPSocket::GetDefaultIpAny(), local_port);
148 
149   Construct();
150 }
151 
152 
H323Transactor(H323EndPoint & ep,const H323TransportAddress & iface,WORD local_port,WORD remote_port)153 H323Transactor::H323Transactor(H323EndPoint & ep,
154                                const H323TransportAddress & iface,
155                                WORD local_port,
156                                WORD remote_port)
157   : endpoint(ep),
158     defaultLocalPort(local_port),
159     defaultRemotePort(remote_port)
160 {
161   if (iface.IsEmpty())
162     transport = NULL;
163   else {
164     PIPSocket::Address addr;
165     PAssert(iface.GetIpAndPort(addr, local_port), "Cannot parse address");
166     transport = new H323TransportUDP(ep, addr, local_port);
167   }
168 
169   Construct();
170 }
171 
172 
Construct()173 void H323Transactor::Construct()
174 {
175   nextSequenceNumber = PRandom::Number()%65536;
176   checkResponseCryptoTokens = PTrue;
177   lastRequest = NULL;
178 
179   requests.DisallowDeleteObjects();
180 }
181 
182 
~H323Transactor()183 H323Transactor::~H323Transactor()
184 {
185   StopChannel();
186 }
187 
188 
PrintOn(ostream & strm) const189 void H323Transactor::PrintOn(ostream & strm) const
190 {
191   if (transport == NULL)
192     strm << "<<no-transport>>";
193   else {
194     H323TransportAddress addr = transport->GetRemoteAddress();
195 
196     PIPSocket::Address ip;
197     WORD port;
198     if (addr.GetIpAndPort(ip, port)) {
199       strm << PIPSocket::GetHostName(ip);
200       if (port != defaultRemotePort)
201         strm << ':' << port;
202     }
203     else
204       strm << addr;
205   }
206 }
207 
208 
SetTransport(const H323TransportAddress & iface)209 PBoolean H323Transactor::SetTransport(const H323TransportAddress & iface)
210 {
211   PWaitAndSignal mutex(pduWriteMutex);
212 
213   if (transport != NULL && transport->GetLocalAddress().IsEquivalent(iface)) {
214     PTRACE(2, "Trans\tAlready have listener for " << iface);
215     return PTrue;
216   }
217 
218   PIPSocket::Address addr;
219   WORD port = defaultLocalPort;
220   if (!iface.GetIpAndPort(addr, port)) {
221     PTRACE(1, "Trans\tCannot create listener for " << iface);
222     return PFalse;
223   }
224 
225   if (transport != NULL) {
226     transport->CleanUpOnTermination();
227     delete transport;
228   }
229 
230   transport = new H323TransportUDP(endpoint, addr, port);
231   transport->SetPromiscuous(H323Transport::AcceptFromAny);
232   return StartChannel();;
233 }
234 
235 
GetInterfaceAddresses(bool excludeLocalHost)236 H323TransportAddressArray H323Transactor::GetInterfaceAddresses(bool excludeLocalHost)
237 {
238   if (transport == NULL)
239     return H323TransportAddressArray();
240   else
241     return endpoint.GetInterfaceAddresses(excludeLocalHost, transport);
242 }
243 
244 
StartChannel()245 PBoolean H323Transactor::StartChannel()
246 {
247   if (transport == NULL)
248     return PFalse;
249 
250   transport->AttachThread(PThread::Create(PCREATE_NOTIFIER(HandleTransactions), "Transactor"));
251   return PTrue;
252 }
253 
254 
StopChannel()255 void H323Transactor::StopChannel()
256 {
257   if (transport != NULL) {
258     transport->CleanUpOnTermination();
259     delete transport;
260     transport = NULL;
261   }
262 }
263 
264 
HandleTransactions(PThread &,INT)265 void H323Transactor::HandleTransactions(PThread &, INT)
266 {
267   if (PAssertNULL(transport) == NULL)
268     return;
269 
270   PTRACE(3, "Trans\tStarting listener thread on " << *transport);
271 
272   transport->SetReadTimeout(PMaxTimeInterval);
273 
274   PINDEX consecutiveErrors = 0;
275 
276   PBoolean ok = PTrue;
277   while (ok) {
278     PTRACE(5, "Trans\tReading PDU");
279     H323TransactionPDU * response = CreateTransactionPDU();
280     if (response->Read(*transport)) {
281       consecutiveErrors = 0;
282       lastRequest = NULL;
283       if (HandleTransaction(response->GetPDU()))
284         lastRequest->responseHandled.Signal();
285       if (lastRequest != NULL)
286         lastRequest->responseMutex.Signal();
287     }
288     else {
289       switch (transport->GetErrorCode(PChannel::LastReadError)) {
290         case PChannel::Interrupted :
291           if (transport->IsOpen())
292             break;
293           // Do NotOpen case
294 
295         case PChannel::NotOpen :
296           ok = PFalse;
297           break;
298 
299         default :
300           switch (transport->GetErrorNumber(PChannel::LastReadError)) {
301             case ECONNRESET:
302             case ECONNREFUSED:
303               PTRACE(2, "Trans\tCannot access remote " << transport->GetRemoteAddress());
304               break;
305 
306             default:
307               PTRACE(1, "Trans\tRead error: " << transport->GetErrorText(PChannel::LastReadError));
308               if (++consecutiveErrors > 10)
309                 ok = PFalse;
310           }
311       }
312     }
313 
314     delete response;
315     AgeResponses();
316   }
317 
318   PTRACE(3, "Trans\tEnded listener thread on " << *transport);
319 }
320 
321 
SetUpCallSignalAddresses(H225_ArrayOf_TransportAddress & addresses)322 PBoolean H323Transactor::SetUpCallSignalAddresses(H225_ArrayOf_TransportAddress & addresses)
323 {
324   if (PAssertNULL(transport) == NULL)
325     return PFalse;
326 
327   H323SetTransportAddresses(*transport,
328                             endpoint.GetInterfaceAddresses(PFalse, transport),
329                             addresses);
330 
331   return addresses.GetSize() > 0;
332 }
333 
334 
GetNextSequenceNumber()335 unsigned H323Transactor::GetNextSequenceNumber()
336 {
337   PWaitAndSignal mutex(nextSequenceNumberMutex);
338   nextSequenceNumber++;
339   if (nextSequenceNumber >= 65536)
340     nextSequenceNumber = 1;
341   return nextSequenceNumber;
342 }
343 
344 
AgeResponses()345 void H323Transactor::AgeResponses()
346 {
347   PTime now;
348 
349   PWaitAndSignal mutex(pduWriteMutex);
350 
351   for (PINDEX i = 0; i < responses.GetSize(); i++) {
352     const Response & response = responses[i];
353     if ((now - response.lastUsedTime) > response.retirementAge) {
354       PTRACE(4, "Trans\tRemoving cached response: " << response);
355       responses.RemoveAt(i--);
356     }
357   }
358 }
359 
360 
SendCachedResponse(const H323TransactionPDU & pdu)361 PBoolean H323Transactor::SendCachedResponse(const H323TransactionPDU & pdu)
362 {
363   if (PAssertNULL(transport) == NULL)
364     return PFalse;
365 
366   Response key(transport->GetLastReceivedAddress(), pdu.GetSequenceNumber());
367 
368   PWaitAndSignal mutex(pduWriteMutex);
369 
370   PINDEX idx = responses.GetValuesIndex(key);
371   if (idx != P_MAX_INDEX)
372     return responses[idx].SendCachedResponse(*transport);
373 
374   responses.Append(new Response(key));
375   return PFalse;
376 }
377 
378 
WritePDU(H323TransactionPDU & pdu)379 PBoolean H323Transactor::WritePDU(H323TransactionPDU & pdu)
380 {
381   if (PAssertNULL(transport) == NULL)
382     return PFalse;
383 
384   OnSendingPDU(pdu.GetPDU());
385 
386   PWaitAndSignal mutex(pduWriteMutex);
387 
388   Response key(transport->GetLastReceivedAddress(), pdu.GetSequenceNumber());
389   PINDEX idx = responses.GetValuesIndex(key);
390   if (idx != P_MAX_INDEX)
391     responses[idx].SetPDU(pdu);
392 
393   return pdu.Write(*transport);
394 }
395 
396 
WriteTo(H323TransactionPDU & pdu,const H323TransportAddressArray & addresses,PBoolean callback)397 PBoolean H323Transactor::WriteTo(H323TransactionPDU & pdu,
398                              const H323TransportAddressArray & addresses,
399                              PBoolean callback)
400 {
401   if (PAssertNULL(transport) == NULL)
402     return PFalse;
403 
404   if (addresses.IsEmpty()) {
405     if (callback)
406       return WritePDU(pdu);
407 
408     return pdu.Write(*transport);
409   }
410 
411   pduWriteMutex.Wait();
412 
413   H323TransportAddress oldAddress = transport->GetRemoteAddress();
414 
415   PBoolean ok = PFalse;
416   for (PINDEX i = 0; i < addresses.GetSize(); i++) {
417     if (transport->SetRemoteAddress(addresses[i])) {
418       PTRACE(3, "Trans\tWrite address set to " << addresses[i]);
419       if (callback)
420         ok = WritePDU(pdu);
421       else
422         ok = pdu.Write(*transport);
423     }
424   }
425 
426   transport->SetRemoteAddress(oldAddress);
427 
428   pduWriteMutex.Signal();
429 
430   return ok;
431 }
432 
433 
MakeRequest(Request & request)434 PBoolean H323Transactor::MakeRequest(Request & request)
435 {
436   PTRACE(3, "Trans\tMaking request: " << request.requestPDU.GetChoice().GetTagName());
437 
438   OnSendingPDU(request.requestPDU.GetPDU());
439 
440   requestsMutex.Wait();
441   requests.SetAt(request.sequenceNumber, &request);
442   requestsMutex.Signal();
443 
444   PBoolean ok = request.Poll(*this);
445 
446   requestsMutex.Wait();
447   requests.SetAt(request.sequenceNumber, NULL);
448   requestsMutex.Signal();
449 
450   return ok;
451 }
452 
453 
CheckForResponse(unsigned reqTag,unsigned seqNum,const PASN_Choice * reason)454 PBoolean H323Transactor::CheckForResponse(unsigned reqTag, unsigned seqNum, const PASN_Choice * reason)
455 {
456   requestsMutex.Wait();
457   lastRequest = requests.GetAt(seqNum);
458   requestsMutex.Signal();
459 
460   if (lastRequest == NULL) {
461     PTRACE(2, "Trans\tTimed out or received sequence number (" << seqNum << ") for PDU we never requested");
462     return PFalse;
463   }
464 
465   lastRequest->responseMutex.Wait();
466   lastRequest->CheckResponse(reqTag, reason);
467   return PTrue;
468 }
469 
470 
HandleRequestInProgress(const H323TransactionPDU & pdu,unsigned delay)471 PBoolean H323Transactor::HandleRequestInProgress(const H323TransactionPDU & pdu,
472                                              unsigned delay)
473 {
474   unsigned seqNum = pdu.GetSequenceNumber();
475 
476   requestsMutex.Wait();
477   lastRequest = requests.GetAt(seqNum);
478   requestsMutex.Signal();
479 
480   if (lastRequest == NULL) {
481     PTRACE(2, "Trans\tTimed out or received sequence number (" << seqNum << ") for PDU we never requested");
482     return PFalse;
483   }
484 
485   lastRequest->responseMutex.Wait();
486 
487   PTRACE(3, "Trans\tReceived RIP on sequence number " << seqNum);
488   lastRequest->OnReceiveRIP(delay);
489   return PTrue;
490 }
491 
492 
CheckCryptoTokens(const H323TransactionPDU & pdu,const PASN_Array & clearTokens,unsigned clearOptionalField,const PASN_Array & cryptoTokens,unsigned cryptoOptionalField)493 PBoolean H323Transactor::CheckCryptoTokens(const H323TransactionPDU & pdu,
494                                        const PASN_Array & clearTokens,
495                                        unsigned clearOptionalField,
496                                        const PASN_Array & cryptoTokens,
497                                        unsigned cryptoOptionalField)
498 {
499   // If cypto token checking disabled, just return PTrue.
500   if (!GetCheckResponseCryptoTokens())
501     return PTrue;
502 
503   if (lastRequest != NULL && pdu.GetAuthenticators().IsEmpty()) {
504     ((H323TransactionPDU &)pdu).SetAuthenticators(lastRequest->requestPDU.GetAuthenticators());
505     PTRACE(4, "Trans\tUsing credentials from request: "
506            << setfill(',') << pdu.GetAuthenticators() << setfill(' '));
507   }
508 
509   if (pdu.Validate(clearTokens, clearOptionalField,
510                    cryptoTokens, cryptoOptionalField) == H235Authenticator::e_OK)
511     return PTrue;
512 
513   /* Note that a crypto tokens error is flagged to the requestor in the
514      responseResult field but the other thread is NOT signalled. This is so
515      it can wait for the full timeout for any other packets that might have
516      the correct tokens, preventing a possible DOS attack.
517    */
518   if (lastRequest != NULL) {
519     lastRequest->responseResult = Request::BadCryptoTokens;
520     lastRequest->responseHandled.Signal();
521     lastRequest->responseMutex.Signal();
522     lastRequest = NULL;
523   }
524 
525   return PFalse;
526 }
527 
528 
529 /////////////////////////////////////////////////////////////////////////////
530 
Request(unsigned seqNum,H323TransactionPDU & pdu)531 H323Transactor::Request::Request(unsigned seqNum, H323TransactionPDU & pdu)
532   : requestPDU(pdu)
533 {
534   sequenceNumber = seqNum;
535   responseInfo   = NULL;
536 }
537 
538 
Request(unsigned seqNum,H323TransactionPDU & pdu,const H323TransportAddressArray & addresses)539 H323Transactor::Request::Request(unsigned seqNum,
540                                  H323TransactionPDU & pdu,
541                                  const H323TransportAddressArray & addresses)
542   : requestAddresses(addresses),
543     requestPDU(pdu)
544 {
545   sequenceNumber = seqNum;
546   responseInfo   = NULL;
547 }
548 
549 
Poll(H323Transactor & rasChannel,unsigned numRetries,PTimeInterval timeout)550 PBoolean H323Transactor::Request::Poll(H323Transactor & rasChannel, unsigned numRetries, PTimeInterval timeout)
551 {
552   H323EndPoint & endpoint = rasChannel.GetEndPoint();
553 
554   responseResult = AwaitingResponse;
555 
556   if (numRetries == 0)
557     numRetries = endpoint.GetRasRequestRetries();
558 
559   if (timeout == 0)
560     timeout = endpoint.GetRasRequestTimeout();
561 
562   for (unsigned retry = 1; retry <= numRetries; retry++) {
563     // To avoid race condition with RIP must set timeout before sending the packet
564     whenResponseExpected = PTimer::Tick() + timeout;
565 
566     if (!rasChannel.WriteTo(requestPDU, requestAddresses, PFalse))
567       break;
568 
569     PTRACE(3, "Trans\tWaiting on response to seqnum=" << requestPDU.GetSequenceNumber()
570            << " for " << setprecision(1) << timeout << " seconds");
571 
572     do {
573       // Wait for a response
574       responseHandled.Wait(whenResponseExpected - PTimer::Tick());
575 
576       PWaitAndSignal mutex(responseMutex); // Wait till lastRequest goes out of scope
577 
578       switch (responseResult) {
579         case AwaitingResponse :  // Was a timeout
580           responseResult = NoResponseReceived;
581           break;
582 
583         case ConfirmReceived :
584           return PTrue;
585 
586         case RejectReceived :
587         case TryAlternate :
588           return PFalse;
589 
590         case BadCryptoTokens :
591           PTRACE(1, "Trans\tResponse to seqnum=" << requestPDU.GetSequenceNumber()
592                  << " had invalid crypto tokens.");
593           return PFalse;
594 
595         default : // RequestInProgress
596           responseResult = AwaitingResponse; // Keep waiting
597       }
598 
599       PTRACE_IF(3, responseResult == AwaitingResponse,
600                 "Trans\tWaiting again on response to seqnum=" << requestPDU.GetSequenceNumber() <<
601                 " for " << setprecision(1) << (whenResponseExpected - PTimer::Tick()) << " seconds");
602     } while (responseResult == AwaitingResponse);
603 
604     PTRACE(1, "Trans\tTimeout on request seqnum=" << requestPDU.GetSequenceNumber()
605            << ", try #" << retry << " of " << numRetries);
606   }
607 
608   return PFalse;
609 }
610 
611 
CheckResponse(unsigned reqTag,const PASN_Choice * reason)612 void H323Transactor::Request::CheckResponse(unsigned reqTag, const PASN_Choice * reason)
613 {
614   if (requestPDU.GetChoice().GetTag() != reqTag) {
615     PTRACE(2, "Trans\tReceived reply for incorrect PDU tag.");
616     responseResult = RejectReceived;
617     rejectReason = UINT_MAX;
618     return;
619   }
620 
621   if (reason == NULL) {
622     responseResult = ConfirmReceived;
623     return;
624   }
625 
626   PTRACE(2, "Trans\t" << requestPDU.GetChoice().GetTagName()
627          << " rejected: " << reason->GetTagName());
628   responseResult = RejectReceived;
629   rejectReason = reason->GetTag();
630 
631   switch(reqTag) {
632     case H225_RasMessage::e_admissionRequest:
633       if (rejectReason == H225_AdmissionRejectReason::e_callerNotRegistered)
634         responseResult = TryAlternate;
635       break;
636 
637     case H225_RasMessage::e_gatekeeperRequest:
638       if (rejectReason == H225_GatekeeperRejectReason::e_resourceUnavailable)
639         responseResult = TryAlternate;
640       break;
641 
642     case H225_RasMessage::e_disengageRequest:
643       if (rejectReason == H225_DisengageRejectReason::e_notRegistered)
644         responseResult = TryAlternate;
645       break;
646 
647     case H225_RasMessage::e_registrationRequest:
648       if (rejectReason == H225_RegistrationRejectReason::e_resourceUnavailable)
649         responseResult = TryAlternate;
650       break;
651 
652     case H225_RasMessage::e_infoRequestResponse:
653       if (rejectReason == H225_InfoRequestNakReason::e_notRegistered)
654         responseResult = TryAlternate;
655       break;
656   }
657 }
658 
659 
OnReceiveRIP(unsigned milliseconds)660 void H323Transactor::Request::OnReceiveRIP(unsigned milliseconds)
661 {
662   responseResult = RequestInProgress;
663   whenResponseExpected = PTimer::Tick() + PTimeInterval(milliseconds);
664 }
665 
666 
667 /////////////////////////////////////////////////////////////////////////////
668 
Response(const H323TransportAddress & addr,unsigned seqNum)669 H323Transactor::Response::Response(const H323TransportAddress & addr, unsigned seqNum)
670   : PString(addr),
671     retirementAge(ResponseRetirementAge)
672 {
673   sprintf("#%u", seqNum);
674   replyPDU = NULL;
675 }
676 
677 
~Response()678 H323Transactor::Response::~Response()
679 {
680   if (replyPDU != NULL)
681     replyPDU->DeletePDU();
682 }
683 
684 
SetPDU(const H323TransactionPDU & pdu)685 void H323Transactor::Response::SetPDU(const H323TransactionPDU & pdu)
686 {
687   PTRACE(4, "Trans\tAdding cached response: " << *this);
688 
689   if (replyPDU != NULL)
690     replyPDU->DeletePDU();
691   replyPDU = pdu.ClonePDU();
692   lastUsedTime = PTime();
693 
694   unsigned delay = pdu.GetRequestInProgressDelay();
695   if (delay > 0)
696     retirementAge = ResponseRetirementAge + delay;
697 }
698 
699 
SendCachedResponse(H323Transport & transport)700 PBoolean H323Transactor::Response::SendCachedResponse(H323Transport & transport)
701 {
702   PTRACE(3, "Trans\tSending cached response: " << *this);
703 
704   if (replyPDU != NULL) {
705     H323TransportAddress oldAddress = transport.GetRemoteAddress();
706     transport.ConnectTo(Left(FindLast('#')));
707     replyPDU->Write(transport);
708     transport.ConnectTo(oldAddress);
709   }
710   else {
711     PTRACE(2, "Trans\tRetry made by remote before sending response: " << *this);
712   }
713 
714   lastUsedTime = PTime();
715   return PTrue;
716 }
717 
718 
719 /////////////////////////////////////////////////////////////////////////////////
720 
H323Transaction(H323Transactor & trans,const H323TransactionPDU & requestToCopy,H323TransactionPDU * conf,H323TransactionPDU * rej)721 H323Transaction::H323Transaction(H323Transactor & trans,
722                                  const H323TransactionPDU & requestToCopy,
723                                  H323TransactionPDU * conf,
724                                  H323TransactionPDU * rej)
725   : transactor(trans),
726     replyAddresses(trans.GetTransport().GetLastReceivedAddress()),
727     request(requestToCopy.ClonePDU())
728 {
729   confirm = conf;
730   reject = rej;
731   authenticatorResult = H235Authenticator::e_Disabled;
732   fastResponseRequired = PTrue;
733   isBehindNAT = PFalse;
734   canSendRIP  = PFalse;
735 }
736 
737 
~H323Transaction()738 H323Transaction::~H323Transaction()
739 {
740   delete request;
741   delete confirm;
742   delete reject;
743 }
744 
745 
HandlePDU()746 PBoolean H323Transaction::HandlePDU()
747 {
748   int response = OnHandlePDU();
749   switch (response) {
750     case Ignore :
751       return PFalse;
752 
753     case Confirm :
754       if (confirm != NULL)
755         WritePDU(*confirm);
756       return PFalse;
757 
758     case Reject :
759       if (reject != NULL)
760         WritePDU(*reject);
761       return PFalse;
762   }
763 
764   H323TransactionPDU * rip = CreateRIP(request->GetSequenceNumber(), response);
765   PBoolean ok = WritePDU(*rip);
766   delete rip;
767 
768   if (!ok)
769     return PFalse;
770 
771   if (fastResponseRequired) {
772     fastResponseRequired = PFalse;
773     PThread::Create(PCREATE_NOTIFIER(SlowHandler), 0,
774                                      PThread::AutoDeleteThread,
775                                      PThread::NormalPriority,
776                                      "Transaction");
777   }
778 
779   return PTrue;
780 }
781 
782 
SlowHandler(PThread &,INT)783 void H323Transaction::SlowHandler(PThread &, INT)
784 {
785   PTRACE(4, "Trans\tStarted slow PDU handler thread.");
786 
787   while (HandlePDU())
788     ;
789 
790   delete this;
791 
792   PTRACE(4, "Trans\tEnded slow PDU handler thread.");
793 }
794 
795 
WritePDU(H323TransactionPDU & pdu)796 PBoolean H323Transaction::WritePDU(H323TransactionPDU & pdu)
797 {
798   pdu.SetAuthenticators(authenticators);
799   return transactor.WriteTo(pdu, replyAddresses, PTrue);
800 }
801 
802 
CheckCryptoTokens(const H235Authenticators & auth)803 PBoolean H323Transaction::CheckCryptoTokens(const H235Authenticators & auth)
804 {
805   authenticators = auth;
806 
807   request->SetAuthenticators(authenticators);
808 
809   authenticatorResult = ValidatePDU();
810 
811   if (authenticatorResult == H235Authenticator::e_OK)
812     return PTrue;
813 
814   PINDEX i;
815   for (i = 0; (authenticatorStrings[i].code >= 0) && (authenticatorStrings[i].code != authenticatorResult); ++i)
816     ;
817 
818   const char * desc = "Unknown error";
819   if (authenticatorStrings[i].code >= 0)
820     desc = authenticatorStrings[i].desc;
821 
822   PTRACE(2, "Trans\t" << GetName() << " rejected - " << desc);
823   return PFalse;
824 }
825 
826 
827 /////////////////////////////////////////////////////////////////////////////////
828 
H323TransactionServer(H323EndPoint & ep)829 H323TransactionServer::H323TransactionServer(H323EndPoint & ep)
830   : ownerEndPoint(ep)
831 {
832 }
833 
834 
~H323TransactionServer()835 H323TransactionServer::~H323TransactionServer()
836 {
837 }
838 
839 
AddListeners(const H323TransportAddressArray & ifaces)840 PBoolean H323TransactionServer::AddListeners(const H323TransportAddressArray & ifaces)
841 {
842   if (ifaces.IsEmpty())
843     return AddListener("udp$*");
844 
845   PINDEX i;
846 
847   mutex.Wait();
848   ListenerList::iterator iterListener = listeners.begin();
849   while (iterListener != listeners.end()) {
850     PBoolean remove = PTrue;
851     for (PINDEX j = 0; j < ifaces.GetSize(); j++) {
852       if (iterListener->GetTransport().GetLocalAddress().IsEquivalent(ifaces[j], true)) {
853         remove = PFalse;
854        break;
855       }
856     }
857     if (remove) {
858       PTRACE(3, "Trans\tRemoving listener " << *iterListener);
859       listeners.erase(iterListener++);
860     }
861     else
862       ++iterListener;
863   }
864   mutex.Signal();
865 
866   for (i = 0; i < ifaces.GetSize(); i++) {
867     if (!ifaces[i])
868       AddListener(ifaces[i]);
869   }
870 
871   return listeners.GetSize() > 0;
872 }
873 
874 
AddListener(const H323TransportAddress & interfaceName)875 PBoolean H323TransactionServer::AddListener(const H323TransportAddress & interfaceName)
876 {
877   PWaitAndSignal wait(mutex);
878 
879   PINDEX i;
880   for (ListenerList::iterator iterListener = listeners.begin(); iterListener != listeners.end(); ++iterListener) {
881     if (iterListener->GetTransport().GetLocalAddress().IsEquivalent(interfaceName, true)) {
882       PTRACE(2, "H323\tAlready have listener for " << interfaceName);
883       return PTrue;
884     }
885   }
886 
887   PIPSocket::Address addr;
888   WORD port = GetDefaultUdpPort();
889   if (!interfaceName.GetIpAndPort(addr, port))
890     return AddListener(interfaceName.CreateTransport(ownerEndPoint));
891 
892   if (!addr.IsAny())
893     return AddListener(new H323TransportUDP(ownerEndPoint, addr, port));
894 
895   PIPSocket::InterfaceTable interfaces;
896   if (!PIPSocket::GetInterfaceTable(interfaces)) {
897     PTRACE(1, "Trans\tNo interfaces on system!");
898     if (!PIPSocket::GetHostAddress(addr))
899       return PFalse;
900     return AddListener(new H323TransportUDP(ownerEndPoint, addr, port));
901   }
902 
903   PTRACE(4, "Trans\tAdding interfaces:\n" << setfill('\n') << interfaces << setfill(' '));
904 
905   PBoolean atLeastOne = PFalse;
906 
907   for (i = 0; i < interfaces.GetSize(); i++) {
908     addr = interfaces[i].GetAddress();
909     if (addr != 0) {
910       if (AddListener(new H323TransportUDP(ownerEndPoint, addr, port, false, true)))
911         atLeastOne = PTrue;
912     }
913   }
914 
915   return atLeastOne;
916 }
917 
918 
AddListener(H323Transport * transport)919 PBoolean H323TransactionServer::AddListener(H323Transport * transport)
920 {
921   if (transport == NULL)
922     return PFalse;
923 
924   if (!transport->IsOpen()) {
925     delete transport;
926     return PFalse;
927   }
928 
929   return AddListener(CreateListener(transport));
930 }
931 
932 
AddListener(H323Transactor * listener)933 PBoolean H323TransactionServer::AddListener(H323Transactor * listener)
934 {
935   if (listener == NULL)
936     return PFalse;
937 
938   PTRACE(3, "Trans\tStarted listener " << *listener);
939 
940   mutex.Wait();
941   listeners.Append(listener);
942   mutex.Signal();
943 
944   listener->StartChannel();
945 
946   return PTrue;
947 }
948 
949 
RemoveListener(H323Transactor * listener)950 PBoolean H323TransactionServer::RemoveListener(H323Transactor * listener)
951 {
952   PBoolean ok = PTrue;
953 
954   mutex.Wait();
955   if (listener != NULL) {
956     PTRACE(3, "Trans\tRemoving listener " << *listener);
957     ok = listeners.Remove(listener);
958   }
959   else {
960     PTRACE(3, "Trans\tRemoving all listeners");
961     listeners.RemoveAll();
962   }
963   mutex.Signal();
964 
965   return ok;
966 }
967 
968 
969 #endif // OPAL_H323
970 
971 /////////////////////////////////////////////////////////////////////////////////
972