On 2009-06-16 19:47 +0200, Jan Willamowius wrote openh323gk-us...@lists.sou...:


Hi, patch against current cvs version, untested, but builds fine and should 
work, i test it tomorrow.

diff -ruN openh323gk/ProxyChannel.cxx openh323gk-new/ProxyChannel.cxx
--- openh323gk/ProxyChannel.cxx 2009-06-14 13:04:00.000000000 +0400
+++ openh323gk-new/ProxyChannel.cxx     2009-06-19 12:19:39.000000000 +0400
@@ -287,10 +287,10 @@
 
        UDPProxySocket(const char *);
 
-       void SetDestination(H245_UnicastAddress_iPAddress &);
-       void SetForwardDestination(const Address &, WORD, const 
H245_UnicastAddress_iPAddress &);
-       void SetReverseDestination(const Address &, WORD, const 
H245_UnicastAddress_iPAddress &);
-       typedef void (UDPProxySocket::*pMem)(const Address &, WORD, const 
H245_UnicastAddress_iPAddress &);
+       void SetDestination(H245_UnicastAddress_iPAddress &,callptr &);
+       void SetForwardDestination(const Address &, WORD, const 
H245_UnicastAddress_iPAddress &, callptr &);
+       void SetReverseDestination(const Address &, WORD, const 
H245_UnicastAddress_iPAddress &, callptr &);
+       typedef void (UDPProxySocket::*pMem)(const Address &, WORD, const 
H245_UnicastAddress_iPAddress &, callptr &);
 
        bool Bind(WORD pt);
        bool Bind(const Address &localAddr, WORD pt);
@@ -310,6 +310,10 @@
        virtual bool Flush();
        virtual bool ErrorHandler(PSocket::ErrorGroup);
 
+       //RTCP handler
+       void BuildReceiverReport(const RTP_ControlFrame & frame, PINDEX offset, 
bool direct);
+
+       callptr *  m_call;
 private:
        UDPProxySocket();
        UDPProxySocket(const UDPProxySocket&);
@@ -362,7 +366,7 @@
        WORD GetChannelNumber() const { return channelNumber; }
        void SetChannelNumber(WORD cn) { channelNumber = cn; }
 
-       virtual bool SetDestination(H245_OpenLogicalChannelAck &, H245Handler 
*) = 0;
+       virtual bool SetDestination(H245_OpenLogicalChannelAck &, H245Handler 
*,callptr &) = 0;
        virtual void StartReading(ProxyHandler *) = 0;
        virtual void SetRTPMute(bool toMute) = 0;
 
@@ -381,11 +385,11 @@
        void SetMediaChannelSource(const H245_UnicastAddress_iPAddress &);
        void SetMediaControlChannelSource(const H245_UnicastAddress_iPAddress 
&);
        PIPSocket::Address GetSourceIP() const;
-       void HandleMediaChannel(H245_UnicastAddress_iPAddress *, 
H245_UnicastAddress_iPAddress *, const PIPSocket::Address &, bool);
-       bool OnLogicalChannelParameters(H245_H2250LogicalChannelParameters &, 
const PIPSocket::Address &, bool);
+       void HandleMediaChannel(H245_UnicastAddress_iPAddress *, 
H245_UnicastAddress_iPAddress *, const PIPSocket::Address &, bool, callptr &);
+       bool OnLogicalChannelParameters(H245_H2250LogicalChannelParameters &, 
const PIPSocket::Address &, bool, callptr &);
 
        // override from class LogicalChannel
-       virtual bool SetDestination(H245_OpenLogicalChannelAck &, H245Handler 
*);
+       virtual bool SetDestination(H245_OpenLogicalChannelAck &, H245Handler 
*,callptr &);
        virtual void StartReading(ProxyHandler *);
        virtual void SetRTPMute(bool toMute);
 
@@ -413,7 +417,7 @@
        virtual ~T120LogicalChannel();
 
        // override from class LogicalChannel
-       virtual bool SetDestination(H245_OpenLogicalChannelAck &, H245Handler 
*);
+       virtual bool SetDestination(H245_OpenLogicalChannelAck &, H245Handler 
*,callptr &);
        virtual void StartReading(ProxyHandler *);
        virtual void SetRTPMute(bool /*toMute*/) {};   /// We do not Mute T.120 
Channels
 
@@ -463,10 +467,10 @@
        virtual ~H245Handler();
 
        virtual void OnH245Address(H225_TransportAddress &);
-       virtual bool HandleMesg(H245_MultimediaSystemControlMessage &, bool & 
suppress);
-       virtual bool HandleFastStartSetup(H245_OpenLogicalChannel &);
-       virtual bool HandleFastStartResponse(H245_OpenLogicalChannel &);
-       typedef bool (H245Handler::*pMem)(H245_OpenLogicalChannel &);
+       virtual bool HandleMesg(H245_MultimediaSystemControlMessage &, bool & 
suppress, callptr & mcall);
+       virtual bool HandleFastStartSetup(H245_OpenLogicalChannel &, callptr &);
+       virtual bool HandleFastStartResponse(H245_OpenLogicalChannel &, callptr 
&);
+       typedef bool (H245Handler::*pMem)(H245_OpenLogicalChannel &,callptr &);
 
        PIPSocket::Address GetLocalAddr() const { return localAddr; }
     PIPSocket::Address GetRemoteAddr() const { return remoteAddr; }
@@ -477,7 +481,7 @@
 
 protected:
        virtual bool HandleRequest(H245_RequestMessage &);
-       virtual bool HandleResponse(H245_ResponseMessage &);
+       virtual bool HandleResponse(H245_ResponseMessage &,callptr &);
        virtual bool HandleCommand(H245_CommandMessage &);
        virtual bool HandleIndication(H245_IndicationMessage &, bool & 
suppress);
 
@@ -499,8 +503,8 @@
        virtual ~H245ProxyHandler();
 
        // override from class H245Handler
-       virtual bool HandleFastStartSetup(H245_OpenLogicalChannel &);
-       virtual bool HandleFastStartResponse(H245_OpenLogicalChannel &);
+       virtual bool HandleFastStartSetup(H245_OpenLogicalChannel &,callptr &);
+       virtual bool HandleFastStartResponse(H245_OpenLogicalChannel &,callptr 
&);
 
        void SetHandler(ProxyHandler *);
        LogicalChannel *FindLogicalChannel(WORD);
@@ -511,12 +515,12 @@
 private:
        // override from class H245Handler
        virtual bool HandleRequest(H245_RequestMessage &);
-       virtual bool HandleResponse(H245_ResponseMessage &);
+       virtual bool HandleResponse(H245_ResponseMessage &, callptr &);
        virtual bool HandleIndication(H245_IndicationMessage &, bool & 
suppress);
 
        bool OnLogicalChannelParameters(H245_H2250LogicalChannelParameters *, 
WORD);
        bool HandleOpenLogicalChannel(H245_OpenLogicalChannel &);
-       bool HandleOpenLogicalChannelAck(H245_OpenLogicalChannelAck &);
+       bool HandleOpenLogicalChannelAck(H245_OpenLogicalChannelAck &, callptr 
&);
        bool HandleOpenLogicalChannelReject(H245_OpenLogicalChannelReject &);
        bool HandleCloseLogicalChannel(H245_CloseLogicalChannel &);
        void HandleMuteRTPChannel();
@@ -1296,7 +1300,7 @@
                }
        }
 
-       if ((!m_h245handler || !m_h245handler->HandleMesg(h245msg, suppress)) 
&& !changed)
+       if ((!m_h245handler || !m_h245handler->HandleMesg(h245msg, suppress, 
m_call)) && !changed)
                return false;
 
        strm.BeginEncoding();
@@ -3023,10 +3027,9 @@
                } else 
                        PTRACE(5, "Q931\tFailover inactive for call " << 
m_call->GetCallNumber() << ", Q931 cause " << cause);
        }
-       
+
        if (m_call)
                CallTable::Instance()->RemoveCall(m_call);
-               
        m_result = Closing;
 }
 
@@ -3361,7 +3364,7 @@
                }
 
                H245Handler::pMem handlefs = (fromCaller) ? 
&H245Handler::HandleFastStartSetup : &H245Handler::HandleFastStartResponse;
-               if ((m_h245handler->*handlefs)(olc)) {
+               if ((m_h245handler->*handlefs)(olc, m_call)) {
                        PPER_Stream wtstrm;
                        olc.Encode(wtstrm);
                        wtstrm.CompleteEncoding();
@@ -4111,7 +4114,7 @@
                hnat->TranslateH245Address(addr);
 }
 
-bool H245Handler::HandleMesg(H245_MultimediaSystemControlMessage & h245msg, 
bool & suppress)
+bool H245Handler::HandleMesg(H245_MultimediaSystemControlMessage & h245msg, 
bool & suppress, callptr & mcall)
 {
        bool changed = false;
 
@@ -4121,7 +4124,7 @@
                        changed = HandleRequest(h245msg);
                        break;
                case H245_MultimediaSystemControlMessage::e_response:
-                       changed = HandleResponse(h245msg);
+                       changed = HandleResponse(h245msg, mcall);
                        break;
                case H245_MultimediaSystemControlMessage::e_command:
                        changed = HandleCommand(h245msg);
@@ -4136,12 +4139,12 @@
        return changed;
 }
 
-bool H245Handler::HandleFastStartSetup(H245_OpenLogicalChannel & olc)
+bool H245Handler::HandleFastStartSetup(H245_OpenLogicalChannel & olc,callptr & 
mcall)
 {
        return hnat ? hnat->HandleOpenLogicalChannel(olc) : false;
 }
 
-bool H245Handler::HandleFastStartResponse(H245_OpenLogicalChannel & olc)
+bool H245Handler::HandleFastStartResponse(H245_OpenLogicalChannel & olc, 
callptr & mcall)
 {
        return hnat ? hnat->HandleOpenLogicalChannel(olc) : false;
 }
@@ -4158,7 +4161,7 @@
        }
 }
 
-bool H245Handler::HandleResponse(H245_ResponseMessage & Response)
+bool H245Handler::HandleResponse(H245_ResponseMessage & Response, callptr & 
mcall)
 {
        PTRACE(4, "H245\tResponse: " << Response.GetTagName());
        if (hnat && Response.GetTag() == 
H245_ResponseMessage::e_openLogicalChannelAck)
@@ -4576,7 +4579,7 @@
        PTRACE(5, Type() << "\tfnat=" << fnat << " rnat=" << rnat);
 }
 
-void UDPProxySocket::SetForwardDestination(const Address & srcIP, WORD 
srcPort, const H245_UnicastAddress_iPAddress & addr)
+void UDPProxySocket::SetForwardDestination(const Address & srcIP, WORD 
srcPort, const H245_UnicastAddress_iPAddress & addr, callptr & mcall)
 {
        if ((DWORD)srcIP != 0)
                fSrcIP = srcIP, fSrcPort = srcPort;
@@ -4593,17 +4596,38 @@
                << " to " << fDestIP << ':' << fDestPort
                );
        SetConnected(true);
+
+       if (Type() == "RTCP"){
+           mcall->SetSRC_media_control_IP(fDestIP.AsString());
+           mcall->SetDST_media_control_IP(srcIP.AsString());
+       }
+       if (Type() == "RTP"){
+           mcall->SetSRC_media_IP(fDestIP.AsString());
+           mcall->SetDST_media_IP(srcIP.AsString());
+       }
+       
+       m_call = &mcall;                
 }
 
-void UDPProxySocket::SetReverseDestination(const Address & srcIP, WORD 
srcPort, const H245_UnicastAddress_iPAddress & addr)
+void UDPProxySocket::SetReverseDestination(const Address & srcIP, WORD 
srcPort, const H245_UnicastAddress_iPAddress & addr, callptr & mcall)
 {
        if( (DWORD)srcIP != 0 )
                rSrcIP = srcIP, rSrcPort = srcPort;
 
        addr >> rDestIP >> rDestPort;
-
+    
        PTRACE(5, Type() << "\tReverse " << srcIP << ':' << srcPort << " to " 
<< rDestIP << ':' << rDestPort);
        SetConnected(true);
+       if (Type() == "RTCP"){
+           mcall->SetSRC_media_control_IP(srcIP.AsString());
+           mcall->SetDST_media_control_IP(rDestIP.AsString());
+       }
+       if (Type() == "RTP"){
+           mcall->SetSRC_media_IP(srcIP.AsString());
+           mcall->SetDST_media_IP(rDestIP.AsString());
+       }
+       m_call = &mcall;
+
 }
 
 ProxySocket::Result UDPProxySocket::ReceiveData()
@@ -4681,9 +4705,168 @@
                if (fnat)
                        fDestIP = fromIP, fDestPort = fromPort;
        }
+       if (Type() == "RTCP"){
+       bool direct = true;
+    
+       if ((*m_call)->GetSRC_media_control_IP() == fromIP.AsString()){
+           direct = true;
+       }else {
+           direct = false;
+       }
+
+       PIPSocket::Address addr = (DWORD)0; 
+       (*m_call)->GetMediaOriginatingIp(addr);
+       
+       RTP_ControlFrame frame(2048);
+       frame.Attach(wbuffer,buflen);
+       do {
+           BYTE * payload = frame.GetPayloadPtr();
+           unsigned size = frame.GetPayloadSize(); 
+           if ((payload == NULL) || (size == 0) || ((payload + size) > 
(frame.GetPointer() + frame.GetSize()))){
+               /* TODO: 1.shall we test for a maximum size ? Indeed but what's 
the value ? *
+                        2. what's the correct exit status ? */
+//             PTRACE(2, "RTCP\tSession invalid frame");
+       
+               break;
+           }
+           switch (frame.GetPayloadType()) {
+               case RTP_ControlFrame::e_SenderReport :
+                   PTRACE(5, "RTCP\tSession SenderReport packet");
+                   if (size >= sizeof(RTP_ControlFrame::SenderReport)) {
+                       const RTP_ControlFrame::SenderReport & sr = *(const 
RTP_ControlFrame::SenderReport *)(payload);
+                       if (direct){
+                           (*m_call)->SetRTCP_DST_packet_count(sr.psent);
+                           PTRACE(5, "RTCP\tSession 
SetRTCP_DST_packet_count:"<<sr.psent);
+                       }else{
+                           (*m_call)->SetRTCP_SRC_packet_count(sr.psent);
+                           PTRACE(5, "RTCP\tSession 
SetRTCP_SRC_packet_count:"<<sr.psent);
+                       }       
+                       BuildReceiverReport(frame, 
sizeof(RTP_ControlFrame::SenderReport),direct);
+                   }else {
+                       PTRACE(5, "RTCP\tSession  SenderReport packet 
truncated");
+                   }
+                   break;
+               case RTP_ControlFrame::e_ReceiverReport :
+                   PTRACE(5, "RTCP\tSession ReceiverReport packet");
+                   if (size >= 4)
+                       BuildReceiverReport(frame, sizeof(PUInt32b),direct);
+                   else {
+                       PTRACE(5, "RTP\tSession ReceiverReport packet 
truncated");
+                   }
+                   break;
+               case RTP_ControlFrame::e_SourceDescription :
+                   PTRACE(5, "RTCP\tSession SourceDescription packet");        
            
+                   if 
((!(*m_call)->GetRTCP_SRC_sdes_flag()&&direct)||(!(*m_call)->GetRTCP_DST_sdes_flag()&&!direct))
+                   if (size >= 
frame.GetCount()*sizeof(RTP_ControlFrame::SourceDescription)) {
+                       const RTP_ControlFrame::SourceDescription * sdes = 
(const RTP_ControlFrame::SourceDescription *)payload;
+                       PINDEX srcIdx;
+                       for (srcIdx = 0; srcIdx < (PINDEX)frame.GetCount(); 
srcIdx++){
+                           const RTP_ControlFrame::SourceDescription::Item * 
item = sdes->item;
+                           while ((item != NULL) && (item->type != 
RTP_ControlFrame::e_END)){
+                               if (item->length != NULL && item->length != 0){
+                                   switch (item->type){
+                                       case RTP_ControlFrame::e_CNAME:
+                                           if (!direct){
+                                               
(*m_call)->SetRTCP_DST_sdes("cname="+((PString)(item->data)).Left(item->length));
+                                           }else{
+                                               
(*m_call)->SetRTCP_SRC_sdes("cname="+((PString)(item->data)).Left(item->length));
+                                           }
+                                           break;
+                                       case RTP_ControlFrame::e_NAME:
+                                           if (!direct){
+                                               
(*m_call)->SetRTCP_DST_sdes("name="+((PString)(item->data)).Left(item->length));
+                                           }else{
+                                               
(*m_call)->SetRTCP_SRC_sdes("name="+((PString)(item->data)).Left(item->length));
+                                           }
+                                           break;
+                                       case RTP_ControlFrame::e_EMAIL:
+                                           if (!direct){
+                                               
(*m_call)->SetRTCP_DST_sdes("email="+((PString)(item->data)).Left(item->length));
+                                           }else{
+                                               
(*m_call)->SetRTCP_SRC_sdes("email="+((PString)(item->data)).Left(item->length));
+                                           }
+                                           break;
+                                       case RTP_ControlFrame::e_PHONE:
+                                           if (!direct){
+                                               
(*m_call)->SetRTCP_DST_sdes("phone="+((PString)(item->data)).Left(item->length));
+                                           }else{
+                                               
(*m_call)->SetRTCP_SRC_sdes("phone="+((PString)(item->data)).Left(item->length));
+                                           }
+                                           break;
+                                       case RTP_ControlFrame::e_LOC:
+                                           if (!direct){
+                                               
(*m_call)->SetRTCP_DST_sdes("loc="+((PString)(item->data)).Left(item->length));
+                                           }else{
+                                               
(*m_call)->SetRTCP_SRC_sdes("loc="+((PString)(item->data)).Left(item->length));
+                                           }
+                                           break;
+                                       case RTP_ControlFrame::e_TOOL:
+                                           if (!direct){
+                                               
(*m_call)->SetRTCP_DST_sdes("tool="+((PString)(item->data)).Left(item->length));
+                                           }else{
+                                               
(*m_call)->SetRTCP_SRC_sdes("tool="+((PString)(item->data)).Left(item->length));
+                                           }
+                                           break;
+                                       case RTP_ControlFrame::e_NOTE:
+                                           if (!direct){
+                                               
(*m_call)->SetRTCP_DST_sdes("note="+((PString)(item->data)).Left(item->length));
+                                           }else{
+                                               
(*m_call)->SetRTCP_SRC_sdes("note="+((PString)(item->data)).Left(item->length));
+                                           }
+                                           break;
+                                       default :
+                                           PTRACE(5,"RTCP\tSession  
SourceDescription bad item");
+                                           break;
+                                   }
+                               }    
+                               item = item->GetNextItem();
+                           }
+                           /* RTP_ControlFrame::e_END doesn't have a length 
field, so do NOT call item->GetNextItem()
+                               otherwise it reads over the buffer */
+                           if((item == NULL) || 
+                               (item->type == RTP_ControlFrame::e_END) || 
+                               ((sdes = (const 
RTP_ControlFrame::SourceDescription *)item->GetNextItem()) == NULL)){
+                               break;
+                           }
+                       }
+                   }
+                   break;
+               case RTP_ControlFrame::e_Goodbye :
+                   PTRACE(5, "RTCP\tSession Goodbye packet");
+                   break;
+               case RTP_ControlFrame::e_ApplDefined :
+                   PTRACE(5, "RTCP\tSession ApplDefined packet");
+                   break;
+               default :
+                   PTRACE(5, "RTCP\tSession  Unknown control payload type: " 
<< frame.GetPayloadType());
+                   break;
+           }
+       } while (frame.ReadNextCompound());
+       }       
        return Forwarding;
 }
 
+void UDPProxySocket::BuildReceiverReport(const RTP_ControlFrame & frame, 
PINDEX offset, bool direct)
+{
+  const RTP_ControlFrame::ReceiverReport * rr = (const 
RTP_ControlFrame::ReceiverReport *)(frame.GetPayloadPtr()+offset);
+  for (PINDEX repIdx = 0; repIdx < (PINDEX)frame.GetCount(); repIdx++) {
+    RTP_Session::ReceiverReport * report = new RTP_Session::ReceiverReport;
+    if (direct){
+       (*m_call)->SetRTCP_DST_packet_lost(report->totalLost = 
rr->GetLostPackets());
+       (*m_call)->SetRTCP_DST_jitter(rr->jitter);
+       PTRACE(5, "RTCP\tSession 
SetRTCP_DST_packet_lost:"<<rr->GetLostPackets());
+       PTRACE(5, "RTCP\tSession SetRTCP_DST_jitter:"<<rr->jitter);
+    } else{
+       (*m_call)->SetRTCP_SRC_packet_lost(report->totalLost = 
rr->GetLostPackets());
+       (*m_call)->SetRTCP_SRC_jitter(rr->jitter);
+       PTRACE(5, "RTCP\tSession 
SetRTCP_SRC_packet_lost:"<<rr->GetLostPackets());
+       PTRACE(5, "RTCP\tSession SetRTCP_SRC_jitter:"<<rr->jitter);
+    }
+    rr++;
+  }
+}
+
+
 bool UDPProxySocket::WriteData(const BYTE *buffer, int len)
 {
        if (!IsSocketOpen())
@@ -4908,7 +5091,7 @@
        addr >> SrcIP >> SrcPort;
 }
 
-void RTPLogicalChannel::HandleMediaChannel(H245_UnicastAddress_iPAddress 
*mediaControlChannel, H245_UnicastAddress_iPAddress *mediaChannel, const 
PIPSocket::Address & local, bool rev)
+void RTPLogicalChannel::HandleMediaChannel(H245_UnicastAddress_iPAddress 
*mediaControlChannel, H245_UnicastAddress_iPAddress *mediaChannel, const 
PIPSocket::Address & local, bool rev, callptr & mcall)
 {
        // mediaControlChannel should be non-zero.
        H245_UnicastAddress_iPAddress tmp, tmpmedia, tmpmediacontrol, *dest = 
mediaControlChannel;
@@ -4937,7 +5120,7 @@
                }
        }
        UDPProxySocket::pMem SetDest = (reversed) ? 
&UDPProxySocket::SetReverseDestination : &UDPProxySocket::SetForwardDestination;
-       (rtcp->*SetDest)(tmpSrcIP, tmpSrcPort, *dest);
+       (rtcp->*SetDest)(tmpSrcIP, tmpSrcPort, *dest, mcall);
        *mediaControlChannel << local << (port + 1);
 
        if (mediaChannel) {
@@ -4946,7 +5129,7 @@
                } else {
                        dest = mediaChannel;
                }
-               (rtp->*SetDest)(tmpSrcIP, tmpSrcPort - 1, *dest);
+               (rtp->*SetDest)(tmpSrcIP, tmpSrcPort - 1, *dest, mcall);
                *mediaChannel << local << port;
        }
 }
@@ -4957,24 +5140,24 @@
                rtp->SetMute(toMute);
 }
 
-bool 
RTPLogicalChannel::OnLogicalChannelParameters(H245_H2250LogicalChannelParameters
 & h225Params, const PIPSocket::Address & local, bool rev)
+bool 
RTPLogicalChannel::OnLogicalChannelParameters(H245_H2250LogicalChannelParameters
 & h225Params, const PIPSocket::Address & local, bool rev, callptr & mcall)
 {
        if 
(!h225Params.HasOptionalField(H245_H2250LogicalChannelParameters::e_mediaControlChannel))
                return false;
        H245_UnicastAddress_iPAddress *mediaControlChannel = 
GetH245UnicastAddress(h225Params.m_mediaControlChannel);
        H245_UnicastAddress_iPAddress *mediaChannel = 
h225Params.HasOptionalField(H245_H2250LogicalChannelParameters::e_mediaChannel) 
? GetH245UnicastAddress(h225Params.m_mediaChannel) : 0;
-       HandleMediaChannel(mediaControlChannel, mediaChannel, local, rev);
+       HandleMediaChannel(mediaControlChannel, mediaChannel, local, rev,mcall);
        return true;
 }
 
-bool RTPLogicalChannel::SetDestination(H245_OpenLogicalChannelAck & olca, 
H245Handler *handler)
+bool RTPLogicalChannel::SetDestination(H245_OpenLogicalChannelAck & olca, 
H245Handler *handler, callptr & mcall)
 {
        H245_UnicastAddress_iPAddress *mediaControlChannel, *mediaChannel;
        GetChannelsFromOLCA(olca, mediaControlChannel, mediaChannel);
        if (mediaControlChannel == NULL && mediaChannel == NULL) {
                return false;
        }
-       HandleMediaChannel(mediaControlChannel, mediaChannel, 
handler->GetMasqAddr(), false);
+       HandleMediaChannel(mediaControlChannel, mediaChannel, 
handler->GetMasqAddr(), false,mcall);
        return true;
 }
 
@@ -5035,7 +5218,7 @@
        PTRACE(4, "T120\tDelete logical channel " << channelNumber);
 }
 
-bool T120LogicalChannel::SetDestination(H245_OpenLogicalChannelAck & olca, 
H245Handler * _handler)
+bool T120LogicalChannel::SetDestination(H245_OpenLogicalChannelAck & olca, 
H245Handler * _handler, callptr & mcall)
 {
        return 
(olca.HasOptionalField(H245_OpenLogicalChannelAck::e_separateStack)) ?
                OnSeparateStack(olca.m_separateStack, _handler) : false;
@@ -5167,14 +5350,14 @@
        return false;
 }
 
-bool H245ProxyHandler::HandleResponse(H245_ResponseMessage & Response)
+bool H245ProxyHandler::HandleResponse(H245_ResponseMessage & Response, callptr 
& mcall)
 {
        PTRACE(4, "H245\tResponse: " << Response.GetTagName());
        if (peer)
                switch (Response.GetTag())
                {
                        case H245_ResponseMessage::e_openLogicalChannelAck:
-                               return HandleOpenLogicalChannelAck(Response);
+                               return HandleOpenLogicalChannelAck(Response, 
mcall);
                        case H245_ResponseMessage::e_openLogicalChannelReject:
                                return HandleOpenLogicalChannelReject(Response);
                        default:
@@ -5293,7 +5476,7 @@
        return false; // nothing changed :)
 }
 
-bool H245ProxyHandler::HandleOpenLogicalChannelAck(H245_OpenLogicalChannelAck 
& olca)
+bool H245ProxyHandler::HandleOpenLogicalChannelAck(H245_OpenLogicalChannelAck 
& olca, callptr & mcall)
 {
        if (hnat)
                hnat->HandleOpenLogicalChannelAck(olca);
@@ -5345,7 +5528,7 @@
        }
 #endif
 
-       bool result = lc->SetDestination(olca, this);
+       bool result = lc->SetDestination(olca, this, mcall);
        if (result)
                lc->StartReading(handler);
        return result;
@@ -5421,7 +5604,7 @@
        return false; // nothing changed :)
 }
 
-bool H245ProxyHandler::HandleFastStartSetup(H245_OpenLogicalChannel & olc)
+bool H245ProxyHandler::HandleFastStartSetup(H245_OpenLogicalChannel & 
olc,callptr & mcall)
 {
        if (!peer)
                return false;
@@ -5447,7 +5630,7 @@
        return ((h225Params) ? OnLogicalChannelParameters(h225Params, 0) : 
false) || changed;
 }
 
-bool H245ProxyHandler::HandleFastStartResponse(H245_OpenLogicalChannel & olc)
+bool H245ProxyHandler::HandleFastStartResponse(H245_OpenLogicalChannel & 
olc,callptr & mcall)
 {
        if (!peer)
                return false;
@@ -5495,7 +5678,7 @@
                                peer->logicalChannels[flcn] = 
peer->sessionIDs[id] = lc = new RTPLogicalChannel(lc, flcn, hnat != 0);
                }
        }
-       if (lc && (changed = lc->OnLogicalChannelParameters(*h225Params, 
GetMasqAddr(), isReverseLC)))
+       if (lc && (changed = lc->OnLogicalChannelParameters(*h225Params, 
GetMasqAddr(), isReverseLC, mcall)))
                lc->StartReading(handler);
        return changed;
 }
diff -ruN openh323gk/radacct.cxx openh323gk-new/radacct.cxx
--- openh323gk/radacct.cxx      2009-05-25 09:10:00.000000000 +0400
+++ openh323gk-new/radacct.cxx  2009-06-19 12:19:39.000000000 +0400
@@ -320,6 +320,62 @@
                                
pdu->AppendCiscoAttr(RadiusAttr::CiscoVSA_release_source,call->GetReleaseSource());
                                
pdu->AppendCiscoAttr(RadiusAttr::CiscoVSA_preferred_codec,call->GetCodec());
                                
pdu->AppendCiscoAttr(RadiusAttr::CiscoVSA_rewritten_e164_num,call->GetCalledStationId());
+                               //RTCP SOURCE REPORT
+                               
+                               
pdu->AppendCiscoAttr(RadiusAttr::CiscoVSA_AV_Pair,
+                                   
PString("RTP_source_IP=")+call->GetSRC_media_IP(),
+                                   true
+                               );
+                               
+                               
pdu->AppendCiscoAttr(RadiusAttr::CiscoVSA_AV_Pair,
+                                   
PString("RTP_destination_IP=")+call->GetDST_media_IP(),
+                                   true
+                               );
+                               
+                               
pdu->AppendCiscoAttr(RadiusAttr::CiscoVSA_AV_Pair,
+                                   
PString("RTCP_source_packet_count=")+PString(PString::Unsigned,call->GetRTCP_SRC_packet_count()),
+                                   true
+                               );
+                               
pdu->AppendCiscoAttr(RadiusAttr::CiscoVSA_AV_Pair,
+                                   
PString("RTCP_source_packet_lost=")+PString(PString::Unsigned,call->GetRTCP_SRC_packet_lost()),
+                                   true
+                               );
+                               
pdu->AppendCiscoAttr(RadiusAttr::CiscoVSA_AV_Pair,
+                                   
PString("RTCP_source_jitter=")+PString(PString::Unsigned,call->GetRTCP_SRC_jitter_min())+PString("|")+PString(PString::Unsigned,call->GetRTCP_SRC_jitter_avg())+PString("|")+PString(PString::Unsigned,call->GetRTCP_SRC_jitter_max()),
+                                   true
+                               );
+                               
+                               PINDEX i_sdes = 0;
+                               PStringList sdes = call->GetRTCP_SRC_sdes();
+                               while (i_sdes < sdes.GetSize()) {
+                                   
pdu->AppendCiscoAttr(RadiusAttr::CiscoVSA_AV_Pair,
+                                       
PString("RTCP_source_sdes_")+sdes[i_sdes],
+                                       true
+                                   );
+                                   i_sdes ++;
+                               }
+                               //RTCP DESTINATION REPORT
+                               
pdu->AppendCiscoAttr(RadiusAttr::CiscoVSA_AV_Pair,
+                                   
PString("RTCP_destination_packet_count=")+PString(PString::Unsigned,call->GetRTCP_DST_packet_count()),
+                                   true
+                               );
+                               
pdu->AppendCiscoAttr(RadiusAttr::CiscoVSA_AV_Pair,
+                                   
PString("RTCP_destination_packet_lost=")+PString(PString::Unsigned,call->GetRTCP_DST_packet_lost()),
+                                   true
+                               );
+                               
pdu->AppendCiscoAttr(RadiusAttr::CiscoVSA_AV_Pair,
+                                   
PString("RTCP_destination_jitter=")+PString(PString::Unsigned,call->GetRTCP_DST_jitter_min())+PString("|")+PString(PString::Unsigned,call->GetRTCP_DST_jitter_avg())+PString("|")+PString(PString::Unsigned,call->GetRTCP_DST_jitter_max()),
+                                   true
+                               );
+                               i_sdes = 0;
+                               sdes = call->GetRTCP_DST_sdes();
+                               while (i_sdes < sdes.GetSize()) {
+                                   
pdu->AppendCiscoAttr(RadiusAttr::CiscoVSA_AV_Pair,
+                                       
PString("RTCP_destination_sdes_")+sdes[i_sdes],
+                                       true
+                                   );
+                                   i_sdes ++;
+                               }
                        }                                       
                        
                        if (call->GetDestSignalAddr(addr,port))
@@ -332,6 +388,7 @@
                                        + 
GetGUIDString(call->GetCallIdentifier().m_guid),
                                true
                                );
+                       
                }
        
                pdu->AppendAttr(RadiusAttr::AcctDelayTime, 0);
diff -ruN openh323gk/RasTbl.cxx openh323gk-new/RasTbl.cxx
--- openh323gk/RasTbl.cxx       2009-06-14 13:04:00.000000000 +0400
+++ openh323gk-new/RasTbl.cxx   2009-06-19 12:19:39.000000000 +0400
@@ -2347,6 +2347,134 @@
        m_disabledcodecs = codecs.Trim();
 }
 
+void CallRec::SetSRC_media_control_IP(PString IP)
+{
+    m_src_media_control_IP = IP;
+}
+
+
+void CallRec::SetDST_media_control_IP(PString IP)
+{
+    m_dst_media_control_IP = IP;
+}
+
+void CallRec::SetSRC_media_IP(PString IP)
+{
+    m_src_media_IP = IP;
+}
+
+
+void CallRec::SetDST_media_IP(PString IP)
+{
+    m_dst_media_IP = IP;
+}
+
+
+void CallRec::InitRTCP_report(){
+    m_rtcp_source_packet_count = 0;
+    m_rtcp_destination_packet_count = 0;
+    m_rtcp_source_packet_lost = 0;
+    m_rtcp_destination_packet_lost = 0;
+    
+    m_rtcp_source_jitter_max = 0;
+    m_rtcp_source_jitter_min = 0;
+    m_rtcp_source_jitter_avg = 0;
+    m_rtcp_source_jitter_avg_count = 0;
+    m_rtcp_source_jitter_avg_sum = 0;
+    
+    m_rtcp_destination_jitter_max = 0;
+    m_rtcp_destination_jitter_min = 0;
+    m_rtcp_destination_jitter_avg = 0;
+    m_rtcp_destination_jitter_avg_count = 0;
+    m_rtcp_destination_jitter_avg_sum = 0;
+    
+    m_src_media_IP = "0.0.0.0";
+    m_dst_media_IP = "0.0.0.0";
+    
+    m_src_media_control_IP = "0.0.0.0";
+    m_dst_media_control_IP = "0.0.0.0";
+    
+    m_rtcp_source_sdes_flag = false;
+    m_rtcp_destination_sdes_flag = false;
+}
+
+
+void CallRec::SetRTCP_SRC_sdes(PString val)
+{
+    m_rtcp_source_sdes.AppendString(val);
+    m_rtcp_source_sdes_flag = true;
+}
+
+void CallRec::SetRTCP_DST_sdes(PString val)
+{    
+    m_rtcp_destination_sdes.AppendString(val);
+    m_rtcp_destination_sdes_flag = true;    
+}
+
+
+void CallRec::SetRTCP_SRC_packet_count(long val)
+{
+    m_rtcp_source_packet_count = val;
+}
+
+void CallRec::SetRTCP_DST_packet_count(long val)
+{
+    m_rtcp_destination_packet_count = val;
+}
+
+void CallRec::SetRTCP_SRC_packet_lost(long val)
+{
+    m_rtcp_source_packet_lost = val;
+}
+
+void CallRec::SetRTCP_DST_packet_lost(long val)
+{
+    m_rtcp_destination_packet_lost = val;
+}
+
+void CallRec::SetRTCP_SRC_jitter(int val)
+{      
+    if (val > 0){
+        if (m_rtcp_source_jitter_min == 0) {
+           m_rtcp_source_jitter_min = val;
+       }else if (m_rtcp_source_jitter_min > val) {
+            m_rtcp_source_jitter_min = val;
+       }
+       if (m_rtcp_source_jitter_max == 0){
+           m_rtcp_source_jitter_max = val;
+       }else if (m_rtcp_source_jitter_max < val){
+           m_rtcp_source_jitter_max =val;
+       }
+       m_rtcp_source_jitter_avg_count ++;
+       m_rtcp_source_jitter_avg_sum +=val;
+       m_rtcp_source_jitter_avg = 
(int)(m_rtcp_source_jitter_avg_sum/m_rtcp_source_jitter_avg_count);
+    }else{
+       m_rtcp_source_jitter_avg = 0;
+    }
+}
+
+void CallRec::SetRTCP_DST_jitter(int val)
+{
+    if (val > 0){
+        if (m_rtcp_destination_jitter_min == 0){
+           m_rtcp_destination_jitter_min = val;
+       }else if (m_rtcp_destination_jitter_min > val){
+           m_rtcp_destination_jitter_min =val;
+       }
+       if (m_rtcp_destination_jitter_max == 0){
+           m_rtcp_destination_jitter_max = val;
+       }else if (m_rtcp_destination_jitter_max < val){
+           m_rtcp_destination_jitter_max =val;
+       }
+       m_rtcp_destination_jitter_avg_count ++;
+       m_rtcp_destination_jitter_avg_sum +=val;
+       m_rtcp_destination_jitter_avg = 
(int)(m_rtcp_destination_jitter_avg_sum/m_rtcp_destination_jitter_avg_count);
+    }else{
+       m_rtcp_destination_jitter_avg = 0;
+    }
+}
+
+
 void CallRec::InternalSetEP(endptr & ep, const endptr & nep)
 {
        if (ep != nep) {
@@ -3127,6 +3255,7 @@
        }
        CallList.push_back(NewRec);
        ++m_activeCall;
+       NewRec->InitRTCP_report();
        PTRACE(2, "CallTable::Insert(CALL) Call No. " << 
NewRec->GetCallNumber() << ", total sessions : " << m_activeCall);
 }
 
diff -ruN openh323gk/RasTbl.h openh323gk-new/RasTbl.h
--- openh323gk/RasTbl.h 2009-06-14 13:04:00.000000000 +0400
+++ openh323gk-new/RasTbl.h     2009-06-19 12:33:45.000000000 +0400
@@ -764,6 +764,63 @@
                has not been yet received.
                Meaningful only in GK routed mode.
        */
+
+       PString GetSRC_media_control_IP() const;
+        PString GetDST_media_control_IP() const;
+    
+        void SetSRC_media_control_IP(PString IP);
+        void SetDST_media_control_IP(PString IP);
+    
+        PString GetSRC_media_IP() const; 
+        PString GetDST_media_IP() const; 
+                                             
+        void SetSRC_media_IP(PString IP);
+        void SetDST_media_IP(PString IP);
+    
+        void SetRTCP_SRC_sdes(PString val);
+        void SetRTCP_DST_sdes(PString val);
+    
+        PStringList GetRTCP_SRC_sdes() const;
+        PStringList GetRTCP_DST_sdes() const;
+    
+        bool GetRTCP_SRC_sdes_flag() const;
+        bool GetRTCP_DST_sdes_flag() const;
+       
+        void InitRTCP_report();
+    
+        void SetRTCP_SRC_packet_count(long val);
+        void SetRTCP_DST_packet_count(long val);
+    
+        void SetRTCP_SRC_packet_lost(long val);
+        void SetRTCP_DST_packet_lost(long val);
+    
+        void SetRTCP_SRC_jitter(int val);
+    
+        void SetRTCP_DST_jitter(int val);
+
+        // Get RTCP source packet count
+        long GetRTCP_SRC_packet_count() const;
+        // Get RTCP destination packet count
+        long GetRTCP_DST_packet_count() const;
+    
+        // Get RTCP source packet lost
+        long GetRTCP_SRC_packet_lost() const;
+        // Get RTCP destination packet lost
+        long GetRTCP_DST_packet_lost() const;
+    
+        // Get RTCP source jitter max
+        int GetRTCP_SRC_jitter_max() const;
+        // Get RTCP source jitter min
+        int GetRTCP_SRC_jitter_min() const;
+        // Get RTCP source jitter avg
+        int GetRTCP_SRC_jitter_avg() const;
+    
+        //Get RTCP destinaton jitter max
+        int GetRTCP_DST_jitter_max() const;
+        //Get RTCP destinaton jitter in
+        int GetRTCP_DST_jitter_min() const;
+        //Get RTCP destinaton jitter avg
+        int GetRTCP_DST_jitter_avg() const;
        time_t GetSetupTime() const;
 
        /** Set timestamp for a Setup message associated with this call. */
@@ -1086,6 +1143,42 @@
        
        /// list of disabled codes
        PString m_disabledcodecs;
+       
+       PString m_src_media_control_IP, m_dst_media_control_IP;
+        PString m_src_media_IP, m_dst_media_IP;
+    
+        PStringList m_rtcp_source_sdes;
+        bool m_rtcp_source_sdes_flag;
+    
+        PStringList m_rtcp_destination_sdes;  
+        bool m_rtcp_destination_sdes_flag;
+    
+        // RTCP_source_packet_count
+        long m_rtcp_source_packet_count;
+        // RTCP_destination_packet_count       
+        long m_rtcp_destination_packet_count;
+    
+        // RTCP_source_packet_lost
+        long m_rtcp_source_packet_lost;
+        // RTCP_destination_packet_lost
+        long m_rtcp_destination_packet_lost;
+    
+        // RTCP_source_jitter
+        int m_rtcp_source_jitter_min;
+        int m_rtcp_source_jitter_max;
+        int m_rtcp_source_jitter_avg;
+    
+        // RTCP_destination_jitter
+        int m_rtcp_destination_jitter_min;
+        int m_rtcp_destination_jitter_max;
+        int m_rtcp_destination_jitter_avg;
+
+
+        int m_rtcp_source_jitter_avg_count;
+        long m_rtcp_source_jitter_avg_sum;
+    
+        int m_rtcp_destination_jitter_avg_count;
+        long m_rtcp_destination_jitter_avg_sum;
 
        /// current timeout (or duration limit) for the call
        time_t m_timeout;
@@ -1566,6 +1659,96 @@
                (m_Called && m_Called->GetCallSignalAddress() == *adr);
 }
 
+inline PString CallRec::GetSRC_media_control_IP() const
+{
+    return m_src_media_control_IP;
+}
+
+inline PString CallRec::GetDST_media_control_IP() const
+{
+    return m_dst_media_control_IP;
+}
+
+inline PString CallRec::GetSRC_media_IP() const
+{
+    return m_src_media_IP;
+}
+
+inline PString CallRec::GetDST_media_IP() const
+{
+    return m_dst_media_IP;
+}
+
+inline bool CallRec::GetRTCP_SRC_sdes_flag() const
+{
+    return m_rtcp_source_sdes_flag;
+}
+
+inline bool CallRec::GetRTCP_DST_sdes_flag() const
+{
+    return m_rtcp_destination_sdes_flag;
+}
+
+inline PStringList CallRec::GetRTCP_SRC_sdes() const
+{
+    return m_rtcp_source_sdes;
+}
+
+inline PStringList CallRec::GetRTCP_DST_sdes() const
+{
+    return m_rtcp_destination_sdes;
+}
+
+inline long CallRec::GetRTCP_SRC_packet_count() const
+{
+    return m_rtcp_source_packet_count;
+}
+
+inline long CallRec::GetRTCP_DST_packet_count() const
+{
+    return m_rtcp_destination_packet_count;
+}
+
+inline long CallRec::GetRTCP_SRC_packet_lost() const
+{
+    return m_rtcp_source_packet_lost;
+}
+
+inline long CallRec::GetRTCP_DST_packet_lost() const
+{
+    return m_rtcp_destination_packet_lost;
+}
+
+inline int CallRec::GetRTCP_SRC_jitter_max() const
+{
+    return m_rtcp_source_jitter_max;
+}
+
+inline int CallRec::GetRTCP_SRC_jitter_min() const
+{
+    return m_rtcp_source_jitter_min;
+}
+
+inline int CallRec::GetRTCP_SRC_jitter_avg() const
+{
+    return m_rtcp_source_jitter_avg;
+}
+
+inline int CallRec::GetRTCP_DST_jitter_max() const
+{
+    return m_rtcp_destination_jitter_max;
+}
+
+inline int CallRec::GetRTCP_DST_jitter_min() const
+{
+    return m_rtcp_destination_jitter_min;
+}
+
+inline int CallRec::GetRTCP_DST_jitter_avg() const
+{
+    return m_rtcp_destination_jitter_avg;
+}
+
 inline time_t CallRec::GetSetupTime() const
 {
        return m_setupTime;



JW>Hi,
JW>
JW>I see H.460.9 support in most videconferecing endpoints these days,
JW>but for now, we can start by just passing the RTCP data out.
JW>
JW>I just tried to apply your patch to the current CVS, but allmost all of
JW>it failed. Do you have an updated version against the current CVS or at
JW>least a diff -u ?
JW>
JW>Thanks,
JW>Jan
JW>
JW>
JW>Georgiewskiy Yuriy wrote:
JW>> On 2009-06-09 11:23 +0200, Jan Willamowius wrote 
openh323gk-us...@lists.sou...:
JW>> 
JW>> Hi, i think processing of call quality metrics is billing/routing engine 
task, not gatekeeper,
JW>> so i think we must just pass data related to qos out.
JW>> 
JW>> About integrating my patch with H.460.9 - i have enabled H.460.9 
statistics on our gk's long 
JW>> time ago, we work with about ~35 voip operators and i see no any H.460.9 
stats at all, also i 
JW>> try to google any voip hardware which support H.460.9 and have no luck. in 
my opinion H.460.9
JW>> is not usable beetween voip operators at this time.
JW>> 
JW>> 
JW>> JW>Hi Yuriy,
JW>> JW>
JW>> JW>thanks for the patch! (I prefer diff -u, but thats no problem.)
JW>> JW>I think we should add it right after the 2.3.0 release is out.
JW>> JW>
JW>> JW>Some food for thought:
JW>> JW>Right now we lack good statistics about call quality. So there RTCP
JW>> JW>stats are a good first step. Should we integrate them with the H.460.9
JW>> JW>reports GnuGk is getting ? Should we have some statistics module to
JW>> JW>use this raw data and make it available in an aggregated form, or
JW>> JW>should we just pass this data out (like this patch does) and leave the
JW>> JW>processing to some other entity ?
JW>> JW>
JW>> JW>Regards,
JW>> JW>Jan
JW>> JW>
JW>> JW>
JW>> JW>Georgiewskiy Yuriy wrote:
JW>> JW>> 
JW>> JW>> Patch to send RTCP statistic in radius accounting packets in cisco 
vsa attributes if rtp proxy 
JW>> JW>> enabled and rtcp packets is present.
JW>> JW>> 
JW>> JW>> example of radius vsa attributes in stop accounting packet:
JW>> JW>> 
JW>> JW>> Cisco-AVPair = "RTP_source_IP=192.168.168.6" 
JW>> JW>> Cisco-AVPair = "RTP_destination_IP=193.58.235.18" 
JW>> JW>> Cisco-AVPair = "RTCP_source_packet_count=172914" 
JW>> JW>> Cisco-AVPair = "RTCP_source_packet_lost=32" 
JW>> JW>> Cisco-AVPair = "RTCP_source_jitter=72|109|288" 
JW>> JW>> Cisco-AVPair = "rtcp_source_sdes_cname=0....@192.168.168.6" 
JW>> JW>> Cisco-AVPair = "RTCP_source_sdes_name=Cisco IOS, VoIP Gateway" 
JW>> JW>> Cisco-AVPair = "RTCP_source_sdes_tool=Cisco IOS, VoIP Gateway" 
JW>> JW>> Cisco-AVPair = "RTCP_destination_packet_count=172926" 
JW>> JW>> Cisco-AVPair = "RTCP_destination_packet_lost=25" 
JW>> JW>> Cisco-AVPair = "RTCP_destination_jitter=16|69|168" 
JW>> JW>> Cisco-AVPair = "rtcp_destination_sdes_cname=0....@66.110.89.228" 
JW>> JW>> Cisco-AVPair = "RTCP_destination_sdes_name=Cisco IOS, VoIP Gateway" 
JW>> JW>> Cisco-AVPair = "RTCP_destination_sdes_tool=Cisco IOS, VoIP Gateway"
JW>> JW>> 
JW>> JW>> jitter values in order min/average/max and not in millisecondss, 
JW>> JW>> to calculate ms use formula X*(1/8000)*1000 where X is value from 
JW>> JW>> RTCP jitter attribute.
JW>> JW>
JW>> JW>> [...]
JW>> JW>
JW>> JW>
JW>> JW>
JW>> 
JW>> C уважением                       With Best Regards
JW>> Георгиевский Юрий.                Georgiewskiy Yuriy
JW>> +7 4872 711666                    +7 4872 711666
JW>> факс +7 4872 711143               fax +7 4872 711143
JW>> Компания ООО "Ай Ти Сервис"       IT Service Ltd
JW>> http://nkoort.ru                  http://nkoort.ru
JW>> JID: ghh...@jabber.tula-ix.net.ru JID: ghh...@jabber.tula-ix.net.ru
JW>> YG129-RIPE                        YG129-RIPE
JW>
JW>
JW>

C уважением                       With Best Regards
Георгиевский Юрий.                Georgiewskiy Yuriy
+7 4872 711666                    +7 4872 711666
факс +7 4872 711143               fax +7 4872 711143
Компания ООО "Ай Ти Сервис"       IT Service Ltd
http://nkoort.ru                  http://nkoort.ru
JID: ghh...@jabber.tula-ix.net.ru JID: ghh...@jabber.tula-ix.net.ru
YG129-RIPE                        YG129-RIPE
------------------------------------------------------------------------------
Crystal Reports - New Free Runtime and 30 Day Trial
Check out the new simplified licensing option that enables unlimited
royalty-free distribution of the report engine for externally facing 
server and web deployment.
http://p.sf.net/sfu/businessobjects
_______________________________________________________

Posting: mailto:Openh323gk-users@lists.sourceforge.net
Archive: 
http://sourceforge.net/mailarchive/forum.php?forum_name=openh323gk-users
Unsubscribe: http://lists.sourceforge.net/lists/listinfo/openh323gk-users
Homepage: http://www.gnugk.org/

Reply via email to