diff --git a/ProxyChannel.cxx b/ProxyChannel.cxx index c314fdb9..0e7714a2 100644 --- a/ProxyChannel.cxx +++ b/ProxyChannel.cxx @@ -1291,6 +1291,7 @@ class H245ProxyHandler : public H245Handler { bool IsCaller() const { return m_isCaller; } bool IsH245Master() const { return m_isH245Master; } bool IsRTPInactive(short session) const; + void AbortLogicalChannel(short session); protected: @@ -9200,6 +9201,14 @@ bool CallSignalSocket::IsRTPInactive(short session) const } } +void CallSignalSocket::AbortLogicalChannel(short session) +{ + H245ProxyHandler * proxyhandler = dynamic_cast(m_h245handler); + if (proxyhandler) { + proxyhandler->AbortLogicalChannel(session); + } +} + // class H245Handler H245Handler::H245Handler(const PIPSocket::Address & local, const PIPSocket::Address & remote, const PIPSocket::Address & masq) @@ -11088,6 +11097,9 @@ UDPProxySocket::UDPProxySocket(const char *t, PINDEX no) m_lastPacketFromForwardSrc = time(NULL); m_lastPacketFromReverseSrc = time(NULL); m_inactivityTimeout = GkConfig()->GetInteger(ProxySection, "RTPInactivityTimeout", 300); // 300 sec = 5 min + m_portDetectionTimeout = GkConfig()->GetInteger(ProxySection, "PortDetectionTimeout", -1); // in seconds, -1 is off + m_firstMedia = 0; + m_mediaFailDetected = false; } UDPProxySocket::~UDPProxySocket() @@ -11582,7 +11594,7 @@ ProxySocket::Result UDPProxySocket::ReceiveData() } } if (!IsSet(m_multiplexDestination_A) && !IsSet(m_multiplexDestination_B)) { - // set if only one side sends multiplexex to GnuGk + // set if only one side sends multiplexed to GnuGk H46019Session h46019chan = MultiplexedRTPHandler::Instance()->GetChannel(m_callNo, m_sessionID); if ((h46019chan.m_multiplexID_fromA != INVALID_MULTIPLEX_ID) && (h46019chan.m_multiplexID_fromB == INVALID_MULTIPLEX_ID)) { if (h46019chan.IsValid()) { @@ -11821,6 +11833,22 @@ ProxySocket::Result UDPProxySocket::ReceiveData() PTRACE(6, Type() << "\tForward from " << AsString(fromIP, fromPort) << " blocked, remote socket (" << AsString(fDestIP, fDestPort) << ") not yet known or ready"); + + PTRACE(0, "JW Check1: rtp=" << isRTP << " ignore=" << m_ignoreSignaledIPs << " timeout=" << m_portDetectionTimeout); + if (isRTP && m_ignoreSignaledIPs && m_portDetectionTimeout > 0) { + time_t now = time(NULL); + PTRACE(0, "JW checking firstmedia=" << m_firstMedia << " now=" << now << " diff=" << (now - m_firstMedia)); + if (m_firstMedia == 0) + m_firstMedia = now; + // TODO: add check if we were able to send packets in the mean time ? + if (!m_mediaFailDetected && (now - m_firstMedia >= m_portDetectionTimeout)) { + PTRACE(0, "JW media fail"); + m_mediaFailDetected = true; + (void)RasServer::Instance()->LogAcctEvent(GkAcctLogger::AcctMediaFail, *m_call); // plus string "H.239" ? + //(*m_call)->AbortLogicalChannel(m_sessionID); + } + } + if (m_dontQueueRTP) return NoData; } @@ -11843,6 +11871,22 @@ ProxySocket::Result UDPProxySocket::ReceiveData() PTRACE(6, Type() << "\tForward from " << AsString(fromIP, fromPort) << " blocked, remote socket (" << AsString(rDestIP, rDestPort) << ") not yet known or ready"); + + PTRACE(0, "JW Check2: rtp=" << isRTP << " ignore=" << m_ignoreSignaledIPs << " timeout=" << m_portDetectionTimeout); + if (isRTP && m_ignoreSignaledIPs && m_portDetectionTimeout > 0) { + time_t now = time(NULL); + PTRACE(0, "JW checking firstmedia=" << m_firstMedia << " now=" << now << " diff=" << (now - m_firstMedia)); + if (m_firstMedia == 0) + m_firstMedia = now; + // TODO: add check if we were able to send packets in the mean time ? + if (!m_mediaFailDetected && (now - m_firstMedia >= m_portDetectionTimeout)) { + PTRACE(0, "JW media fail"); + m_mediaFailDetected = true; + (void)RasServer::Instance()->LogAcctEvent(GkAcctLogger::AcctMediaFail, *m_call); // plus string "H.239" ? + //(*m_call)->AbortLogicalChannel(m_sessionID); + } + } + if (m_dontQueueRTP) return NoData; } @@ -14490,6 +14534,23 @@ bool H245ProxyHandler::IsRTPInactive(short session) const return inactive; } +void H245ProxyHandler::AbortLogicalChannel(short session) +{ + RTPLogicalChannel * lc = FindRTPLogicalChannelBySessionID(session); + if (lc) { + WORD flcn = lc->GetChannelNumber(); +/* + if (h245sock) { + PTRACE(4, "H245\tTo send (CallID: " << h245sock->GetCallIdentifierAsString() << "): " << h245msg); + h245sock->Send(h245msg); + } else { + CallSignalSocket * css = call->GetCallSignalSocketCalling(); + css->SendTunneledH245(h245msg); + } +*/ + } +} + //void H245ProxyHandler::DumpChannels(const PString & msg, bool dumpPeer) const //{ // if (PTrace::CanTrace(7)) { diff --git a/ProxyChannel.h b/ProxyChannel.h index b8f4d40f..50a485fd 100644 --- a/ProxyChannel.h +++ b/ProxyChannel.h @@ -308,6 +308,9 @@ class UDPProxySocket : public UDPSocket, public ProxySocket { int m_inactivityTimeout; time_t m_lastPacketFromForwardSrc; time_t m_lastPacketFromReverseSrc; + int m_portDetectionTimeout; + time_t m_firstMedia; + bool m_mediaFailDetected; }; #if H323_H450 @@ -433,6 +436,7 @@ class CallSignalSocket : public TCPProxySocket { CallSignalSocket * GetRemote() const { return dynamic_cast(remote); } bool IsRTPInactive(short session) const; + void AbortLogicalChannel(short session); protected: void ForwardCall(FacilityMsg *msg); diff --git a/RasTbl.cxx b/RasTbl.cxx index 2ed95f75..32e2a898 100644 --- a/RasTbl.cxx +++ b/RasTbl.cxx @@ -5140,6 +5140,16 @@ bool CallRec::IsRTPInactive(short session) const } } +void CallRec::AbortLogicalChannel(short session) +{ + if (m_callingSocket) { + m_callingSocket->AbortLogicalChannel(session); + } + if (m_calledSocket) { + m_calledSocket->AbortLogicalChannel(session); + } +} + /* bool CallRec::IsTimeout( const time_t now, diff --git a/RasTbl.h b/RasTbl.h index 82ff9099..1b49c6ec 100644 --- a/RasTbl.h +++ b/RasTbl.h @@ -1451,6 +1451,7 @@ class CallRec { #endif bool IsRTPInactive(short session) const; + void AbortLogicalChannel(short session); private: void SendDRQ(); diff --git a/changes.txt b/changes.txt index 50037f44..6fb91721 100644 --- a/changes.txt +++ b/changes.txt @@ -1,5 +1,7 @@ Changes from 5.0 to 5.1 ======================= +- new accounting event MediaFail +- new switch: [Proxy] PortDetectionTimeout= - public IP detection for Google Cloud diff --git a/gk.cxx b/gk.cxx index 0be1f180..32855753 100644 --- a/gk.cxx +++ b/gk.cxx @@ -377,6 +377,8 @@ const char * KnownConfigEntries[][2] = { { "HttpAcct", "AlertURL" }, { "HttpAcct", "ConnectBody" }, { "HttpAcct", "ConnectURL" }, + { "HttpAcct", "MediaFailBody" }, + { "HttpAcct", "MediaFailURL" }, { "HttpAcct", "Method" }, { "HttpAcct", "OffBody" }, { "HttpAcct", "OffURL" }, @@ -453,6 +455,7 @@ const char * KnownConfigEntries[][2] = { { "Proxy", "InternalNetwork" }, #ifdef HAS_H46018 { "Proxy", "LegacyPortDetection" }, + { "Proxy", "PortDetectionTimeout" }, #endif { "Proxy", "ProxyAlways" }, { "Proxy", "ProxyForNAT" }, diff --git a/gkacct.cxx b/gkacct.cxx index f1b231ed..aa27c733 100644 --- a/gkacct.cxx +++ b/gkacct.cxx @@ -105,6 +105,8 @@ int GkAcctLogger::GetEvents(const PStringArray & tokens) const mask |= AcctOff; else if (token *= "reject") mask |= AcctReject; + else if (token *= "mediafail") + mask |= AcctMediaFail; } return mask; diff --git a/gkacct.h b/gkacct.h index 0434b197..37cd2046 100644 --- a/gkacct.h +++ b/gkacct.h @@ -73,6 +73,7 @@ class GkAcctLogger : public NamedObject AcctRegister = 0x0100, /// endpoint registered AcctUnregister = 0x0200, /// endpoint unregistered AcctReject = 0x0400, /// rejected calls (ARJ) + AcctMediaFail = 0x0800, /// media failure AcctAll = -1, AcctNone = 0 }; diff --git a/httpacct.cxx b/httpacct.cxx index 44a65ed3..93b21ce4 100644 --- a/httpacct.cxx +++ b/httpacct.cxx @@ -57,6 +57,8 @@ HttpAcct::HttpAcct(const char* moduleName, const char* cfgSecName) m_offBody = cfg->GetString(cfgSec, "OffBody", ""); m_rejectURL = cfg->GetString(cfgSec, "RejectURL", ""); m_rejectBody = cfg->GetString(cfgSec, "RejectBody", ""); + m_mediaFailURL = cfg->GetString(cfgSec, "MediaFailURL", ""); + m_mediaFailBody = cfg->GetString(cfgSec, "MediaFailBody", ""); } HttpAcct::~HttpAcct() @@ -101,6 +103,9 @@ GkAcctLogger::Status HttpAcct::Log(GkAcctLogger::AcctEvent evt, const callptr & } else if (evt == AcctReject) { eventURL = m_rejectURL; eventBody = m_rejectBody; + } else if (evt == AcctMediaFail) { + eventURL = m_mediaFailURL; + eventBody = m_mediaFailBody; } if (eventURL.IsEmpty()) { diff --git a/httpacct.h b/httpacct.h index c7647b66..a3626cd6 100644 --- a/httpacct.h +++ b/httpacct.h @@ -28,7 +28,7 @@ class HttpAcct : public GkAcctLogger enum Constants { /// events recognized by this module - HttpAcctEvents = AcctStart | AcctStop | AcctUpdate | AcctConnect | AcctAlert | AcctRegister | AcctUnregister | AcctOn | AcctOff | AcctReject + HttpAcctEvents = AcctStart | AcctStop | AcctUpdate | AcctConnect | AcctAlert | AcctRegister | AcctUnregister | AcctOn | AcctOff | AcctReject | AcctMediaFail }; HttpAcct( @@ -89,6 +89,9 @@ class HttpAcct : public GkAcctLogger /// parametrized strings for the reject event PString m_rejectURL; PString m_rejectBody; + /// parametrized strings for the mediafail event + PString m_mediaFailURL; + PString m_mediaFailBody; /// HTTP method: GET or POST PString m_method; /// timestamp formatting string diff --git a/statusacct.cxx b/statusacct.cxx index e1676872..782a71c3 100644 --- a/statusacct.cxx +++ b/statusacct.cxx @@ -3,7 +3,7 @@ * * accounting module for GNU Gatekeeper for the status port. * - * Copyright (c) 2005-2016, Jan Willamowius + * Copyright (c) 2005-2018, Jan Willamowius * * This work is published under the GNU Public License version 2 (GPLv2) * see file COPYING for details. @@ -34,6 +34,8 @@ StatusAcct::StatusAcct(const char* moduleName, const char* cfgSecName) m_alertEvent = cfg->GetString(cfgSec, "AlertEvent", "CALL|Alert|%{caller-ip}:%{caller-port}|%{callee-ip}:%{callee-port}|%{CallId}"); m_registerEvent = cfg->GetString(cfgSec, "RegisterEvent", "EP|Register|%{endpoint-ip}:%{endpoint-port}|%{aliases}"); m_unregisterEvent = cfg->GetString(cfgSec, "UnregisterEvent", "EP|Unregister|%{endpoint-ip}:%{endpoint-port}|%{aliases}"); + m_rejectEvent = cfg->GetString(cfgSec, "RejectEvent", "CALL|Reject|%{caller-ip}:%{caller-port}|%{callee-ip}:%{callee-port}|%{CallId}"); + m_mediaFailEvent = cfg->GetString(cfgSec, "MediaFailEvent", "CALL|MediaFail|%{caller-ip}:%{caller-port}|%{callee-ip}:%{callee-port}|%{CallId}"); } StatusAcct::~StatusAcct() @@ -63,6 +65,10 @@ GkAcctLogger::Status StatusAcct::Log(GkAcctLogger::AcctEvent evt, const callptr eventTmpl = m_stopEvent; } else if (evt == AcctAlert) { eventTmpl = m_alertEvent; + } else if (evt == AcctReject) { + eventTmpl = m_rejectEvent; + } else if (evt == AcctMediaFail) { + eventTmpl = m_mediaFailEvent; } if (!eventTmpl.IsEmpty()) { // don't send event if the template string is empty diff --git a/statusacct.h b/statusacct.h index 91adbbea..4ee8dd61 100644 --- a/statusacct.h +++ b/statusacct.h @@ -28,7 +28,7 @@ class StatusAcct : public GkAcctLogger enum Constants { /// events recognized by this module - StatusAcctEvents = AcctStart | AcctStop | AcctUpdate | AcctConnect | AcctAlert | AcctRegister | AcctUnregister + StatusAcctEvents = AcctStart | AcctStop | AcctUpdate | AcctConnect | AcctAlert | AcctRegister | AcctUnregister | AcctReject | AcctMediaFail }; StatusAcct( @@ -78,6 +78,10 @@ class StatusAcct : public GkAcctLogger PString m_registerEvent; /// parametrized string for the endpoint un-register event PString m_unregisterEvent; + /// parametrized string for the call reject event + PString m_rejectEvent; + /// parametrized string for the call mediafail event + PString m_mediaFailEvent; /// timestamp formatting string PString m_timestampFormat; };