Iurii Gordiienko | 22 Jan 14:08 2016
Picon

H323Connection concurrent access issue

Hi all,

I found an issue with concurrent access during work with H323Connection.
Take a look on H46018Transport::HandleH46018SignallingChannelPDU(PThread * thread)

Simplest schema of this function running:

thread1:
H46018Transport::HandleH46018SignallingChannelPDU(PThread * thread)
{
...
H323Connection * connection = endpoint.CreateConnection(callReference, NULL, this, &pdu);
...
connection->AttachSignalChannel(token, this, true); 
...
connection->HandleSignallingChannel();
...
return connection->HadAnsweredCall();
}

The function connection->HandleSignallingChannel() in really working with "this" (H46018Transport object) all time in the while-loop.

! iv>
thread2:
H323EndPoint::CleanUpConnections() running. In this thread we are running:
1.connection.CleanUpOnCallEnd() - this function will call CleanUpOnTermination() for signallingChannel (H46018Transport object) which running in connection->HandleSignallingChannel() function.
2.delete current H323Connection (which will delete our signallingChannel object also)

The concurrent access issue - in time when we are running connection->HandleSignallingChannel() function from  thread1, the H323Connection object can be deleted and signallingChannel will points to dead object - we have a crash in result. Also it is possible to run the connection->HadAnsweredCall() function for dead "connection" object.

I have had the crash several times for this situation.


Thanks
--
Iurii Gordiienko
Iurii Gordiienko | 21 Jan 18:10 2016
Picon

Bug inH323Capabilities::Remove(H323Capability*)

Hi,

I found a bug - H323Capabilities::Remove function will skip item when doing .RemoveAt operation. In result I have had a crash (in line if (set[outer][middle][inner].GetCapabilityNumber() == capabilityNumber)) for some sets of capabilities.
I can't understand why the crash is occurs but in any way...


Original code:

void H323Capabilities::Remove(H323Capability * capability)
{
  if (capability == NULL)
    return;

  PTRACE(3, "H323\tRemoving capability: " << *capability);

  unsigned capabilityNumber = capability->GetCapabilityNumber();

  for (PINDEX outer = 0; outer < set.GetSize(); outer++) {
    for (PINDEX middle = 0; middle < set[outer].GetSize(); middle++) {! div>
      for (PINDEX inner = 0; inner < set[outer][middle].GetSize(); inner++) {
        if (set[outer][middle][inner].GetCapabilityNumber() == capabilityNumber) {
          set[outer][middle].RemoveAt(inner);
          break;
        }
      }
      if (set[outer][middle].GetSize() == 0)
        set[outer].RemoveAt(middle);

    }
    if (set[outer].GetSize() == 0)
        set.RemoveAt(outer);
  }


My fi x:

void H323Capabilities::Remove(H323Capability * capability)
{
  if (capability == NULL)
    return;
  PTRACE(3, "H323\tRemoving capability: " << *capability);

  unsigned capabilityNumber = capability->GetCapabilityNumber();

  for (PINDEX outer = 0; outer < set.GetSize(); ) {
    for (PINDEX middle = 0; middle < set[outer].GetSize(); ) {
      for (PINDEX inner = 0; inner < set[outer][middle].GetSize(); inner++) {
        if (set[outer][middle][inner].GetCapabilityNumber() == capabilityNumber) {
          set[outer][middle].RemoveAt(inner);
          break;
        }
      }
  & nbsp;   if (set[outer][middle].GetSize())
        ++middle;
      else
        set[outer].RemoveAt(middle);

    }
  &nb! sp; if (set[outer].GetSize())
        ++outer;
    else
        set.RemoveAt(outer);
  }

Thanks
--
Iurii Gordiienko
!
Iurii Gordiienko | 15 Jan 16:08 2016
Picon

H323EndPoint::ParsePartyName issue

Hi,

I'm working with ForwardCall functional and have found a bug if we have forward URL which contains PORT number.
For example, for h323: <at> 192.168.1.1:1726 input string H323EndPoint::ParsePartyName will make address string like ip$192.168.1.1:1726:1726.

The fix is trivial (may be I've not covered all cases):

  // get the various parts of the name
  PString hostOnly = PString();
  PINDEX userPos = remoteParty.Find(' <at> ');
  if (userPos != P_MAX_INDEX) {
    if (gatekeeper != NULL)
      alias = url.AsString();
    else {
      alias = remoteParty.Left(userPos);
      PINDEX portPos = remoteParty.FindLast(':', portPos + 1);
      PINDEX len = (portPos != P_MAX_IND! EX) ? (portPos - userPos - 1) : P_MAX_INDEX;
      hostOnly = remoteParty.Mid(userPos+1, len);
    }
  } else {
     alias = url.GetUserName();
     hostOnly = url.GetHostName();
  } 
  address = hostOnly;



Also we have similar issue for input string without ' <at> ' character. In this case PTLIB::PURL class wrong parse the string (uses 192.168.1.1:1726:1726 as USER).

To fix this issue we need look PTLIB::PURL class futher.

Thanks
--
Iurii Gordiienko
Iurii Gordiienko | 11 Jan 12:46 2016
Picon

Issue with H.263 codecs set

Hi all,

I need an advice - how to work with set of H.263 codecs.
Basically, I have all H.263 codec types capability implemented: H.263, H.263-1998 and H.263-2000. All these capabilities uses same H245_VideoCapability::e_h263VideoCapability value for GetSubType function. In result my localCapabilities variable has all these 3 capabilities as well.

When I receiving remote capabilities the remoteCapabilities variable is loading by H323Capabilities::H323Capabilities(const H323Connection & connection, const H245_TerminalCapabilitySet & pdu) constructor and the function uses code like this (simplified):

H323Capability * capability = localCapabilities.FindCapabil ity(pdu.m_capabilityTable[i].m_capability, capabilityNo, pdu);
if (capability != NULL) 
{
          H323Capability * copy = (H323! Capability *)capability->Clone();
          copy->SetCapabilityNumber(capabilityNo);
          if (copy->OnReceivedPDU(pdu.m_capabilityTable[i].m_capability))
            table.Append(copy);
          else
            delete copy;
}

The main issue -  localCapabilities.FindCapability function returns any first H.263 Capability from it's table, no matter which particular H.263 remote Capability was used, it only checks MainType and SubType... In result if remote side send me, for example, H.263-1998, but I have H.263 and H.263-1998 - I will have H.263 in result... 

Now I'm trying to override Connection::OnReceivedCapabilitySet(const H245_TerminalCapabilitySet & pdu) function, extract H.263 codecs manually, st! ore all these capabilities and update remoteCapabilities after, but may be exists a proper solution for this case?


Thanks
--
Iurii Gordiienko
!
Iurii Gordiienko | 8 Jan 17:03 2016
Picon

Double-delete Capability bug

Hi,

I have found something...
For H323ExtendedVideoCapability::AddAllCapabilities function we are using H323CodecExtendedVideoCapability::AddCapability function for extCapability->AddCapability(*r).
H323CodecExtendedVideoCapability::AddCapability function uses extCapabilities.Add(H323ExtendedVideoFactory::CreateInstance(cap)) function. The function H323ExtendedVideoFactory::CreateInstance(cap) will call "new" if any same "cap" does not is exists for now< for other case it will return the pointer to current actual Capability. But H323CodecExtendedVideoCapability::extCapabilities will delete all items in time of execution 
extCapabilities.RemoveAll() function from H323CodecExtendedVideoCa pability::~H323CodecExtendedVideoCapability(). In result we have "double delete" and undefined behavior (crash for worst case).

------------------------------! --

void H323ExtendedVideoCapability::AddAllCapabilities(
      H323Capabilities & basecapabilities, PINDEX descriptorNum,PINDEX simultaneous)
{
  H323ExtendedVideoFactory::KeyList_T extCaps = H323ExtendedVideoFactory::GetKeyList();
  if (extCaps.size() > 0) {
    H323CodecExtendedVideoCapability * capability = new H323CodecExtendedVideoCapability();
    H323ExtendedVideoFactory::KeyList_T::const_iterator r;
        PINDEX num = P_MAX_INDEX;
        for (r = extCaps.begin(); r != extCaps.end(); ++r) {
           H323CodecExtendedVideoCapability * extCapab ility = (H323CodecExtendedVideoCapability *)capability->Clone();
           extCapability->AddCapability(*r);
      &n! bsp;    num = basecapabilities.SetCapability(descriptorNum, simultaneous,extCapability);
           simultaneous = num;
        }
    simultaneous = P_MAX_INDEX;
    basecapabilities.SetCapability(descriptorNum, simultaneous,new H323ControlExtendedVideoCapability());
    delete capability;
  } 
}

void H323CodecExtendedVideoCapability::AddCapability(const PString & cap)
{
    extCapabilities.Add(H323ExtendedVideoFactory::CreateInstance(cap));
}


-------------------------------------------------

I propose to replace the "void H323CodecExtendedVideoCapability::AddCapability(const PString & cap)" to this one:

void H323CodecExtendedVideoCapability::AddCapability(const PString & cap)
{
! >
    extCapabilities.Add(H323ExtendedVideoFactory::CreateInstance(cap)->clone());
}




Thanks
--
Iurii Gordiienko
!
Iurii Gordiienko | 31 Dec 11:40 2015
Picon

H323EndPoint::InternalMakeCall bug

Hi,

I have found an issue with H323EndPoint::InternalMakeCall function for case when it running from H323EndPoint::ForwardConnection function (may be for some others cases too).
Take a look:
1.We are trying to connect to some host which uses Gatekeeper.
2.From H323EndPoint::ForwardConnection call H323EndPoint::InternalMakeCall function with some internal token="ip$xxx.xxx.xxx.xxx/port"
3.In the body of H323EndPoint::InternalMakeCall we have the replacement current callToken-connection pair to new one with "ip$xxx.xxx.xxx.xxx/port-replaced-1" string, like
    
    connectionsActive.SetAt(adjustedToken, connectionsActive.RemoveAt(newToken)) ;
    connectionsToBeCleaned += adjustedToken;

4.But if for some reason our virtual CreateConnection function returns NULL...
  connection = CreateConnection(lastReference, userData, transport, NULL);
  if (connection == NULL) {
    PTRACE(1, "H323\tCreateConnection returned NULL");
    connectionsMutex.Signal();

    return NULL;
  }

 ... we cannot clear current Connection because it has not actual callToken "ip$xxx.xxx.xxx.xxx/port" but H323EndPoint::connectionsActive has "ip$xxx.xxx.xxx.xxx/port-replaced-1" and endpoint.ClearCall(callToken, reason) or something similar will be failed because not able to found the Connection by own callToken.

5.Also we have redundant call connectionsMutex.Signal().

if (connection == NULL) {
    PTRACE(1, "H323\tCreateConnection returned NULL");
    connectionsMutex.Signal();

    return NULL;
  }


My proposition - just rename back callToken for H323EndPoint::connectionsActive and remove adjustedToken from H323EndPoint::connectionsToBeCleaned if we have NULL connection.
My H323EndPoint::InternalMakeCall function looks like this:

H323Connection * H323EndPoint::InternalMakeCall(const PString & trasferFromToken,
                                                const PString & callIdentity,
                                &nbs p;               unsigned capabilityLevel,
                                                cons! t PString & remoteParty,
                                                H323Transport * transport,
                                                PString & newToken,
                                                void * userData,
                                              &nbsp ; PBoolean supplimentary
                                            !     )
{
  PTRACE(2, "H323\tMaking call to: " << remoteParty);

  PString alias;
  H323TransportAddress address;
  if (!ParsePartyName(remoteParty, alias, address)) {
    PTRACE(2, "H323\tCould not parse \"" << remoteParty << '"');
    return NULL;
  }

#ifdef H323_H46017
  // If H.460.17 use the existing H.460.17 Transport
  if (transport == NULL && RegisteredWithH46017())
      transport = GetH46017Transport();
#endif

  if (transport == NULL) {
    // Restriction: the call must be mad e on the same transport as the one
    // that the gatekeeper is using.
    if (gatekeeper != NULL)
      transport = gatekeeper->GetTransport().GetRemoteAddress().CreateTransport(*this);
! >

    // assume address is an IP address/hostname
    else
      transport = address.CreateTransport(*this);

    if (transport == NULL) {
      PTRACE(1, "H323\tInvalid transport in \"" << remoteParty << '"');
      return NULL;
    }
  }

  H323Connection * connection;

  connectionsMutex.Wait();

  PString adjustedToken;
  unsigned lastReference;
  if (newToken.IsEmpty()) {
    do {
      lastReference = Q931::GenerateCa llReference();
      newToken = BuildConnectionToken(*transport, lastReference, FALSE);
    } while (connectionsActive.Contains(newToken));
! >
  }
  else {
    lastReference = newToken.Mid(newToken.Find('/')+1).AsUnsigned();

    // Move old connection on token to new value and flag for removal
    unsigned tieBreaker = 0;
    do {
      adjustedToken = newToken + "-replaced";
      adjustedToken.sprintf("-%u", ++tieBreaker);
    } while (connectionsActive.Contains(adjustedToken));
    connectionsActive.SetAt(adjustedToken, connectionsActive.RemoveAt(newToken));
    connectionsToBeCleaned += adjustedToken;
    PTRACE(3, "H323\tOverwriting call " << newToken << ", renamed to " << adjustedToken);
  }
  connectionsMutex.Signal();

  connection = CreateConnection(lastReference, userData, transport, NULL);
  if (connection == NULL) {
  !   PTRACE(1, "H323\tCreateConnection returned NULL");
    
    if (!adjustedToken.IsEmpty())
    {
        connectionsMutex.Wait();

        connectionsActive.SetAt(newToken, connectionsActive.RemoveAt(adjustedToken));
        connectionsToBeCleaned -= adjustedToken;

        PTRACE(3, "H323\tOverwriting call " << adjustedToken << ", renamed to " << newToken);

        connectionsMutex.Signal();
    }

    return NULL;
  }
  con nection->SetRemotePartyName(remoteParty);

  if (supplimentary) 
      connection->SetNonCallConnection();    &nb! sp;

  connection->Lock();

  connectionsMutex.Wait();
  connectionsActive.SetAt(newToken, connection);

  connectionsMutex.Signal();

  connection->AttachSignalChannel(newToken, transport, FALSE);

#ifdef H323_H450
  if (capabilityLevel == UINT_MAX)
    connection->HandleTransferCall(trasferFromToken, callIdentity);
  else {
    connection->HandleIntrudeCall(trasferFromToken, callIdentity);
    connection->IntrudeCall(capabilityLevel);
  }
#endif

  PTRACE(3, "H323\tCreated new connection: " << newToken);

#ifdef H323_H46017
  if (RegisteredWithH46017()) {
    H323Connection::CallEndReason reason = connection->SendSignalSetup(alias, address);
  &! nbsp; if (reason != H323Connection::NumCallEndReasons)
      connection->ClearCall(reason);
  } else
#endif
      new H225CallThread(*this, *connection, *transport, alias, address);

  return connection;
}




Thanks
--
Iurii Gordiienko
!
Iurii Gordiienko | 28 Dec 12:30 2015
Picon

H323CodecExtendedVideoCapability::OnSendingPDUstrange behavior

Hi,

Take a look on the H323CodecExtendedVideoCapability::OnSendingPDU function.
I have had some issues with Extended capabilities and have fixed the issue only after change the view order - we need to look the .table first and only if it empty - work with extCapabilities.
For current implementation we always work the extCapabilities only because it always has GetSize()>0 (otherwise we return FALSE at the beginning of this function).

PBoolean H323CodecExtendedVideoCapability::OnSendingPDU(H245_VideoCapability & pdu, CommandType ctype) const 
    if (extCapabilities.GetSize() == 0)
        return FALSE;

   // bla-bla-bla
    
    if (extCapabilities.GetSize() > 0) {
      caps.SetSize(extCapabilities.GetSize());
      for (PINDEX i=0; i< extCapabilities.GetSize(); i++) {
         H245_VideoCapability vidcap;
         ((H323VideoCapability &)extCapabilities[i]).OnSendingPDU(vidcap,ctype);
         caps[i] = vidcap;
      }
    } else {
      caps.SetSize(table.GetSize());
      for (PINDEX i=0; i< table.GetSize(); i++) {
         H245_VideoCapability vidcap;
        ((H323VideoCapability &)table[i]).OnSendingPDU(vidcap,ctype);
        caps[i] = vidcap;
      }
    }

  return TRUE;
}


Thanks
--
Iurii Gordiienko
!
Iurii Gordiienko | 25 Dec 14:59 2015
Picon

Twice H323Connection::Unlock() call issue

Hi,

I have found a bug with twice H323Connection::Unlock() call if we have an connection issue.

Take a look:

1.We are running connection.SendSignalSetup function from H225CallThread::Main() and if it returns any reason!=H323Connection::EndedByCallerAbort we will Unlock the connection.


void H225CallThread::Main()
{
  PTRACE(3, "H225\tStarted call thread");

  if (connection.Lock()) {
    H323Connection::CallEndReason reason = connection.SendSignalSetup(alias, address);

    // Special case, if we aborted the call then already w ill be unlocked
    if (reason != H323Connection::EndedByCallerAbort)
      connection.Unlock();

    // bla-! bla-bla
}

2.But we have case when connection.SendSignalSetup returns non H323Connection::EndedByCallerAbort reason but has own unlocked state - for this case PTLIB will unlock the mutex twice with assert (as minimum) message.

H323Connection::SendSignalSetup(const PString & alias,
                                                              const H323TransportAddress & address)
{
//bla-bla-bla

      // Release the mutex as can deadlock trying to clear call during connect.iv>
      Unlock();

      PBoolean connectFailed = false;
      if (!signallingChannel->IsOpen()) {! div>
        signallingChannel->SetWriteTimeout(100);
        connectFailed = !signallingChannel->Connect();
      }

      // See if transport connect failed, abort if so.
      if (connectFailed) {
        connectionState = NoConnectionActive;
        switch (signallingChannel->GetErrorNumber()) {
          case ENETUNREACH :
            return EndedByUnreachable;
          case ECONNREFUSED :
            return EndedByNoEndPoint;
          case ETIMEDOUT :
            return EndedByHostOffline;
        }
        return EndedByConnectFail;
&nb! sp;     }

}

Thanks
--
Iurii Gordiienko
!
Jan Willamowius | 3 Dec 10:01 2015
Picon

GNU Gatekeeper 4.0 released


I am pleased to announce the release of GNU Gatekeeper 4.0.
It is now available from http://www.gnugk.org/h323download.html.

This release includes source code suitable for Linux, Windows, MacOS X,
FreeBSD, NetBSD, OpenBSD and Solaris and executables for Linux.

GnuGk 4.0 includes many new features as well as some important bug
fixes, but remains fully compatible with your previous configuration
files.

Whats new ?

- rewrite of the H.235 password authentication - much better
  interoperability and much more secure (it is high time to get ride of
  MD5 based authentication!)

- IP authentication for all RAS and Q.931 messages

- important IPv6 updates and fixes

- support for TCS0 call transfers ("reroute") that can be initiated from
  applications

- better NAT traversal support for unregistered endpoints

- better blocking of spam calls using SQLAuth

- per endpoint codec filtering

- DisplayIE rewriting

- more secure handling of status port passwords (only hash stored)

- important fix for ODBC database driver

- CalledPartyNumber IE rewriting for better Polycom interoperability

- bug fixes

Some of the new 4.0 features are discussed in more detail this blog
post:
http://blog.gnugk.org/2015/11/gnu-gatekeeper-40-features.html

The full change log is appended below.

Regards,
Jan

-- 
Jan Willamowius, Founder of the GNU Gatekeeper Project
EMail  : jan <at> willamowius.de
Website: http://www.gnugk.org
Support: http://www.willamowius.com/gnugk-support.html

Relaxed Communications GmbH
Frahmredder 91
22393 Hamburg
Geschäftsführer: Jan Willamowius
HRB 125261 (Amtsgericht Hamburg)
USt-IdNr: DE286003584

Changes from 3.9 to 4.0
=======================
- [...PasswordAuth] CheckID switch is now deprecated, use [H235] CheckSendersID instead
- provide vendor informations from ARQ or Setup as %{Vendor} in SQLAuth CallQuery
- prepend timestamp to events in status port backlog
- BUGFIX(Routing.cxx) remove newlines from vendor string before sending out  RouteRequest to virtual queue
- BUGFIX(gksql_odbc.cxx) fix DSN initialization when having multiple DSNs at the same time
- new switch: [RoutedMode] UpdateCalledPartyToH225Destination=1 to always rewrite the CalledPartyNumberIE
  in Setup to the first E.164 of the H.225 destinationAddress
- BUGFIX(ProxyChannel.cxx) fix crash on shutdown
- new settings for [RoutedMode] ScreenDisplayIE=: 'Calling', 'Called', 'CallingCalled' to set the DisplayIE
  to the (rewritten) caller ID
- new switch: [RoutedMode] AppendToDisplayIE= to add a string to the DisplayIE when ScreenDisplayIE= is on
- changed default: H.460.18 keep-alive in traversal zone between neighbors now defaults to 19 sec (was 29)
- new switch: [RoutedMode] H46018KeepAliveInterval=
- BUGFIX(ProxyChannel.cxx) better port detection for H.239 when IgnoreSignaledPrivateH239IPs=1
- BUGFIX(gkacct.cxx) %{caller-port} and %{called-port} now default to "0" instead of the empty string
  when not available (eg. in direct mode) to avoid SQL errors when they are stored in a numeric column
- BUGFIX(RasSrv.cxx) fix additive registration with parent gatekeeper
- BUGFIX(ProxyChannel.cxx) fix IPv6 dual-stack proxy on Linux and Windows
- dump file descriptor usage on USR2 signal (Linux only)
- new switch [RoutedMode] DisableFastStart=1
- support for H.235.1, incl. setting and checking tokens in all RAS and Q.931 messages
- extend SimplePasswordAuth and FileIPAuth to all RAS and all Q.931 messages
- store only PBKDF2 hash for [GkStatus::Auth] password in config, not a recoverable password
- BUGFIX(ProxyChannel.cxx) fix crash when receiving message without UUIE
- new switch [EP::] DisabledCodecs=
- much improved TCS0 3rd-party call transfer using 'Reroute' command on status port
- BUGFIX(Routing.cxx) add field for destination alias in ARQ if missing and a dynamic routing policy sets it
- BUGFIX(ProxyChannel.cxx) fix crash in H.235 Media for endpoints with more than 64 capability entries in TCS
- new switch [Proxy] AllowSignaledIPs= to skip to skip auto-detect for network when IgnoreSignaledIPs=1

Ankur Deep Jaiswal | 16 Sep 12:21 2015

OpenExtendedChannel SessionID

Hi,
some devices reject the OLC of extended channel if the sessionid is 0(default), with (OLC reject) invalidsessionid.
This is defined in file h323caps.cxx, OnH239GenericMessageResponse as defaultSession=0,
after changing the value to 3. the OLC is accepted.

In the attached mail-list discussion it is mentioned that sessionid should not be 0 (http://lists.packetizer.com/pipermail/h323plus/2009-December/002105.html).

h323plus displays forgiving nature in this case. it happily accepts a sessionid of 0 in an extended channel.

please advise on this behaviour.
--
Ankur Deep Jaiswal
Jose Uceda | 23 Jul 12:52 2015

H323Transport GetLocalAddress bug using PTLIB>=2.11

We discovered this bug trying to register an endpoint (ip 62.22.27.131)
to a gatekeeper (ip 62.22.20.229),
using H323Plus v1.26.5 w ptlib 2.12.8.

As you can see in the trace log:

------------------------

   0:00.010      Yate H323G...f3d7464700   transports.cxx(2363) RAS
Gatekeeper discovery on interface: 62.22.27.131:59483
   0:00.021      Yate H323G...f3d7464700      h323pdu.cxx(79) Trans
Sending PDU [ip$62.22.27.131:59483/ip$62.22.20.229:1719] :
   gatekeeperRequest {
     requestSeqNum = 36153
     protocolIdentifier = 0.0.8.2250.0.7
     rasAddress = ipAddress {
       ip =  4 octets {
         3e 16 1b 83                                        >...
       }
       port = 59483
     }

     ^^^--- We see our RAS Address is set correctly (3e 16 1b 83 = 62.22.27.131) and port 59483
     ... rest of the PDU trace has been trimmed ...
   }

   0:00.076      Yate H323G...f3d7464700      h323pdu.cxx(79) H225RAS
Receiving PDU [ip$62.22.20.229:54287/ip$62.22.20.229:1719] :
   gatekeeperConfirm {
     requestSeqNum = 36153
     protocolIdentifier = 0.0.8.2250.0.7
     gatekeeperIdentifier =  9 characters {
       0047 004b 0040 0070 0070 0063 0069 0067   GK <at> ppcig
       006b                                      k
     }
     rasAddress = ipAddress {
       ip =  4 octets {
         3e 16 14 e5                                        >...
       }
       port = 1719
     }
   }
Raw PDU:
  size=25 pos=25.0 {
000 04 80 8d 38 06 00 08 91 4a 00 07 10 00 47 00 4b      8    J    G K
     00 40 00 70 00 70 00 63 00 69 00 67 00 6b 00 3e     <at>  p p c i g k >
     16 14 e5 06 b7
   }
   0:00.076      Yate H323G...f3d7464700     gkclient.cxx(288) RAS
Gatekeeper discovery found ip$62.22.20.229:1719
   0:00.076      Yate H323G...f3d7464700   transports.cxx(2461) RAS
Gatekeeper discovered at: 62.22.20.229:1719 (if=62.22.27.131:59483)

^^^^---- this transport still has the correct interface / local ip

  0:00.076      Yate H323G...f3d7464700       osutil.cxx(189) PTLib
File handle high water mark set: 26 Thread unblock pipe
   0:00.077      Yate H323G...f3d7464700     tlibthrd.cxx(305) PTLib
Created thread 0x7ff3b4008420 Transactor:%x
   0:00.077      PTLib Hous...f3d7568700      osutils.cxx(2158) PTLib
Cleaning 1 AutoDelete threads
   0:00.077          Transactor:d31ab700     tlibthrd.cxx(354) PTLib
Started thread 0x7ff3b4008420 (5287) "Transactor:d31ab700"
   0:00.077          Transactor:d31ab700    h323trans.cxx(266) Trans
Starting listener thread on Transport[remote=ip$62.22.20.229:1719
if=ip$62.22.20.229:54287]

^^^--- See that this new transport has a wrong "if=" (with remote GK address not our local address)

  0:00.077      Yate H323G...f3d7464700   transports.cxx(749) TCP
Appending H.225 transport ip$62.22.27.131:2720 using associated
transport Transport[remote=ip$62.22.20.229:1719 if=ip$62.22.20.229:54287]
   0:00.077          Transactor:d31ab700    h323trans.cxx(274) Trans
Reading PDU
   0:00.077          Transactor:d31ab700     tlibthrd.cxx(1012) PTLib
PThread::PXBlockOnIO(22,0)
   0:00.077      Yate H323G...f3d7464700    h323trans.cxx(435) Trans
Making request: registrationRequest
   0:00.077      Yate H323G...f3d7464700      h323pdu.cxx(79) Trans
Sending PDU [ip$62.22.20.229:54287/ip$62.22.20.229:1719] :
   registrationRequest {
     requestSeqNum = 36154
     protocolIdentifier = 0.0.8.2250.0.7
     discoveryComplete = true
     callSignalAddress = 1 entries {
       [0]=ipAddress {
         ip =  4 octets {
           3e 16 1b 83                                        >...
         }
         port = 2720
       }

   ^^^---- callSignalAddress is our endpoint IP address (62.22.27.131). Ok

  }
     rasAddress = 1 entries {
       [0]=ipAddress {
         ip =  4 octets {
           3e 16 14 e5                                        >...
         }
         port = 59483
       }
     }
     ^^^--- rasAddress has been set incorrectly to the remote gatekeeper address (62.22.20.229) although the port
            is OK (it's the same used in the previous GRQ pdu)
   }

  -------------------

By looking at the source code:

In transports.cxx, function H323TransportUDP::ReadPDU:

      PBoolean H323TransportUDP::ReadPDU(PBYTEArray & pdu)

     #if PTLIB_VER >= 2110
     if (canGetInterface) {
       WORD notused;
       // TODO: verify that this actually does the same as the pre
2.11.x version
       socket->GetLastReceiveAddress(lastReceivedInterface, notused);
     }
#else
     if (canGetInterface)
       lastReceivedInterface = socket->GetLastReceiveToAddress();
#endif

    Since the PTLIB's version we are using is 2.12.8, the compiled code is as follows:

       WORD notused;
       // TODO: verify that this actually does the same as the pre 2.11.x version
       socket->GetLastReceiveAddress(lastReceivedInterface, notused);

    Be noticed the comment and that the name of the called function is not the same as the pre 2.11.x code:
    GetLastReceiveAddress() vs GetLastReceiveToAddress()

    GetLastReceiveToAddress() returned local ip address but this function has been removed from PTLib and the
existing function (the one is used) GetLastReceiveAddress returns the address of the *sender* in the last connection.

    Due to use GetLastReceiveAddress, now lastReceivedInterface has the remote ip (62.22.20.229).
And lastReceivedInterface is used in the function H323TransportUDP::GetLocalAddress():

H323TransportAddress H323TransportUDP::GetLocalAddress() const
{
   if (canGetInterface && !lastReceivedInterface.IsLoopback())
     return H323TransportAddress(lastReceivedInterface, interfacePort);

.....

returning lastReceivedInterface (62.22.20.229) as our local address incorrectly.

The GetLocalAddress function is used in many places so this can cause many problems as the one we have
spotted here.


Gmane