////////////////////////////////////////////////////////////////// // // GkClient.cxx // // Copyright (c) Citron Network Inc. 2001-2003 // // This work is published under the GNU Public License (GPL) // see file COPYING for details. // We also explicitely grant the right to link this code // with the OpenH323 library. // // initial author: Chih-Wei Huang // initial version: 02/27/2002 // ////////////////////////////////////////////////////////////////// #if defined(_WIN32) && (_MSC_VER <= 1200) #pragma warning(disable:4786) // warning about too long debug symbol off #pragma warning(disable:4284) #endif #include #include #include #include "stl_supp.h" #include "RasPDU.h" #include "RasSrv.h" #include "ProxyChannel.h" #include "sigmsg.h" #include "cisco.h" #include "GkClient.h" using std::vector; using std::multimap; using std::make_pair; using std::for_each; using std::mem_fun; using std::bind1st; using Routing::Route; namespace { const char* const EndpointSection = "Endpoint"; const char* const RewriteE164Section = "Endpoint::RewriteE164"; } class AlternateGKs { public: AlternateGKs(const PIPSocket::Address &, WORD); void Set(const H225_ArrayOf_AlternateGK &); bool Get(PIPSocket::Address &, WORD &); private: typedef multimap GKList; GKList AltGKs; GKList::iterator index; PIPSocket::Address pgkaddr, pgkport; }; AlternateGKs::AlternateGKs(const PIPSocket::Address & gkaddr, WORD gkport) { pgkaddr = gkaddr, pgkport = gkport; } void AlternateGKs::Set(const H225_ArrayOf_AlternateGK & agk) { AltGKs.clear(); for (PINDEX i = 0; i < agk.GetSize(); ++i) { const H225_AlternateGK & gk = agk[i]; AltGKs.insert(make_pair(int(gk.m_priority), gk.m_rasAddress)); } index = AltGKs.begin(); } bool AlternateGKs::Get(PIPSocket::Address & gkaddr, WORD & gkport) { if (AltGKs.size() > 0) { if (index == AltGKs.end()) { index = AltGKs.begin(); // switch back to original GK gkaddr = pgkaddr; gkport = (WORD)pgkport; return false; } const H225_TransportAddress & rasAddress = (index++)->second; if (GetIPAndPortFromTransportAddr(rasAddress, gkaddr, gkport)) return true; PTRACE(3, "GKC\tInvalid AlternateGK Address!" ); return Get(gkaddr, gkport); // try next } return false; } class NATClient : public RegularJob { public: NATClient(const H225_TransportAddress &, const H225_EndpointIdentifier &); // override from class RegularJob virtual void Stop(); private: // override from class Task virtual void Exec(); bool DetectIncomingCall(); void SendInfo(int); PIPSocket::Address gkip; WORD gkport; PString endpointId; CallSignalSocket *socket; }; NATClient::NATClient(const H225_TransportAddress & addr, const H225_EndpointIdentifier & id) { GetIPAndPortFromTransportAddr(addr, gkip, gkport); endpointId = id.GetValue(); socket = 0; SetName("NATClient"); Execute(); } void NATClient::Stop() { PWaitAndSignal lock(m_deletionPreventer); RegularJob::Stop(); if (socket) { SendInfo(Q931::CallState_DisconnectRequest); socket->Close(); } } void NATClient::Exec() { ReadLock lockConfig(ConfigReloadMutex); socket = new CallSignalSocket; socket->SetPort(gkport); if (socket->Connect(gkip)) { PTRACE(2, "GKC\t" << socket->GetName() << " connected, wainting for incoming call"); if (DetectIncomingCall()) { PTRACE(3, "GKC\tIncoming call detected"); CreateJob(socket, &CallSignalSocket::Dispatch, "NAT call"); socket = 0; return; } } delete socket; socket = 0; int retryInterval = GkConfig()->GetInteger(EndpointSection, "NATRetryInterval", 60); ReadUnlock unlockConfig(ConfigReloadMutex); Wait(retryInterval * 1000); } bool NATClient::DetectIncomingCall() { while (socket->IsOpen()) { long retry = GkConfig()->GetInteger( EndpointSection, "NATKeepaliveInterval", 86400 ); // one day SendInfo(Q931::CallState_IncomingCallProceeding); ReadUnlock unlockConfig(ConfigReloadMutex); while (socket->IsOpen() && --retry > 0) if (socket->IsReadable(1000)) // one second return socket->IsOpen(); } return false; } void NATClient::SendInfo(int state) { Q931 information; information.BuildInformation(0, false); PBYTEArray buf, epid(endpointId, endpointId.GetLength(), false); information.SetIE(Q931::FacilityIE, epid); information.SetCallState(Q931::CallStates(state)); information.Encode(buf); socket->TransmitData(buf); } class GRQRequester : public RasRequester { public: GRQRequester(const PString &); ~GRQRequester(); // override from class RasRequester virtual bool SendRequest(const Address &, WORD, int = 2); private: // override from class RasHandler virtual bool IsExpected(const RasMsg *) const; H225_RasMessage grq_ras; }; GRQRequester::GRQRequester(const PString & gkid) : RasRequester(grq_ras) { grq_ras.SetTag(H225_RasMessage::e_gatekeeperRequest); H225_GatekeeperRequest & grq = grq_ras; grq.m_requestSeqNum = GetSeqNum(); grq.m_protocolIdentifier.SetValue(H225_ProtocolID); grq.m_endpointType.IncludeOptionalField(H225_EndpointType::e_gatekeeper); grq.IncludeOptionalField(H225_GatekeeperRequest::e_supportsAltGK); if (!gkid) { grq.IncludeOptionalField(H225_GatekeeperRequest::e_gatekeeperIdentifier); grq.m_gatekeeperIdentifier = gkid; } grq.IncludeOptionalField(H225_GatekeeperRequest::e_authenticationCapability); grq.IncludeOptionalField(H225_GatekeeperRequest::e_algorithmOIDs); H235AuthSimpleMD5 md5auth; md5auth.SetPassword("dummy"); // activate it md5auth.SetCapability(grq.m_authenticationCapability, grq.m_algorithmOIDs); H235AuthCAT catauth; catauth.SetPassword("dummy"); // activate it catauth.SetCapability(grq.m_authenticationCapability, grq.m_algorithmOIDs); m_rasSrv->RegisterHandler(this); } GRQRequester::~GRQRequester() { m_rasSrv->UnregisterHandler(this); } bool GRQRequester::SendRequest(const Address & addr, WORD pt, int r) { m_txAddr = addr, m_txPort = pt, m_retry = r; H225_GatekeeperRequest & grq = grq_ras; vector
GKHome; Toolkit::Instance()->GetGKHome(GKHome); for (std::vector
::iterator i = GKHome.begin(); i != GKHome.end(); ++i) { if ((IsLoopback(addr) || IsLoopback(*i)) && addr != *i) continue; RasListener *socket = m_rasSrv->SelectInterface(*i)->GetRasListener(); grq.m_rasAddress = socket->GetRasAddress(addr == INADDR_BROADCAST ? *i : addr); if (addr == INADDR_BROADCAST) socket->SetOption(SO_BROADCAST, 1); socket->SendRas(grq_ras, addr, pt); if (addr == INADDR_BROADCAST) socket->SetOption(SO_BROADCAST, 0); } m_sentTime = PTime(); return true; } bool GRQRequester::IsExpected(const RasMsg *ras) const { if (ras->GetSeqNum() == GetSeqNum()) if (ras->GetTag() == H225_RasMessage::e_gatekeeperRequest) return m_txAddr == INADDR_BROADCAST; // catch broadcasted GRQ to avoid loop else if (ras->GetTag() == H225_RasMessage::e_gatekeeperConfirm || ras->GetTag() == H225_RasMessage::e_gatekeeperReject) return (m_txAddr == INADDR_BROADCAST) ? true : ras->IsFrom(m_txAddr, m_txPort); return false; } // handler to process requests to GkClient class GkClientHandler : public RasHandler { public: typedef bool (GkClient::*Handler)(RasMsg *); GkClientHandler(GkClient *c, Handler h, unsigned t) : client(c), handlePDU(h), tag(t) {} private: // override from class RasHandler virtual bool IsExpected(const RasMsg *ras) const; virtual void Process(RasMsg *); void OnRequest(RasMsg *ras); GkClient *client; Handler handlePDU; unsigned tag; }; bool GkClientHandler::IsExpected(const RasMsg *ras) const { return (ras->GetTag() == tag) && client->CheckFrom(ras); } void GkClientHandler::Process(RasMsg *ras) { CreateJob(this, &GkClientHandler::OnRequest, ras, ras->GetTagName()); } void GkClientHandler::OnRequest(RasMsg *ras) { ReadLock lockConfig(ConfigReloadMutex); if ((client->*handlePDU)(ras)) ras->Reply(); delete ras; } namespace { const long DEFAULT_TTL = 60; const long DEFAULT_RRQ_RETRY = 3; } // class GkClient GkClient::GkClient() : m_rasSrv(RasServer::Instance()), m_registered(false), m_discoveryComplete(false), m_ttl(GkConfig()->GetInteger(EndpointSection, "TimeToLive", DEFAULT_TTL)), m_timer(0), m_retry(GkConfig()->GetInteger(EndpointSection, "RRQRetryInterval", DEFAULT_RRQ_RETRY)), m_rewriteInfo(NULL), m_natClient(NULL), m_parentVendor(ParentVendor_GnuGk), m_endpointType(EndpointType_Gateway), m_discoverParent(true) { m_resend = m_retry; m_gkfailtime = m_retry * 128; m_gkport = 0; m_useAltGKPermanent = false; m_gkList = new AlternateGKs(m_gkaddr, m_gkport); m_handlers[0] = new GkClientHandler(this, &GkClient::OnURQ, H225_RasMessage::e_unregistrationRequest); m_handlers[1] = new GkClientHandler(this, &GkClient::OnBRQ, H225_RasMessage::e_bandwidthRequest); m_handlers[2] = new GkClientHandler(this, &GkClient::OnDRQ, H225_RasMessage::e_disengageRequest); m_handlers[3] = new GkClientHandler(this, &GkClient::OnIRQ, H225_RasMessage::e_infoRequest); } GkClient::~GkClient() { DeleteObjectsInArray(m_handlers, m_handlers + 4); delete m_gkList; delete m_rewriteInfo; PTRACE(1, "GKC\tDelete GkClient"); } void GkClient::OnReload() { PConfig *cfg = GkConfig(); if (IsRegistered()) if (Toolkit::AsBool(cfg->GetString(EndpointSection, "UnregisterOnReload", "0"))) SendURQ(); // TODO else Unregister(); m_password = Toolkit::Instance()->ReadPassword(EndpointSection, "Password"); m_retry = m_resend = cfg->GetInteger(EndpointSection, "RRQRetryInterval", DEFAULT_RRQ_RETRY); m_gkfailtime = m_retry * 128; m_authMode = -1; PCaselessString s = GkConfig()->GetString(EndpointSection, "Vendor", "GnuGk"); if (s == "Generic" || s == "Unknown") m_parentVendor = ParentVendor_Generic; else if (s == "Cisco") m_parentVendor = ParentVendor_Cisco; else m_parentVendor = ParentVendor_GnuGk; s = GkConfig()->GetString(EndpointSection, "Type", "GnuGk"); if (s[0] == 't' || s[0] == 'T') { m_endpointType = EndpointType_Terminal; m_prefixes.RemoveAll(); } else { m_endpointType = EndpointType_Gateway; m_prefixes = cfg->GetString(EndpointSection, "Prefix", "").Tokenise(",;", FALSE); } m_discoverParent = Toolkit::AsBool(cfg->GetString(EndpointSection, "Discovery", "1")); m_h323Id = cfg->GetString( EndpointSection, "H323ID", (const char *)Toolkit::GKName() ).Tokenise(" ,;\t", FALSE); m_e164 = cfg->GetString(EndpointSection, "E164", "").Tokenise(" ,;\t", FALSE); PIPSocket::Address gkaddr = m_gkaddr; WORD gkport = m_gkport; const PCaselessString gk(cfg->GetString(EndpointSection, "Gatekeeper", "no")); if (!IsRegistered()) m_ttl = GkConfig()->GetInteger(EndpointSection, "TimeToLive", DEFAULT_TTL); if (gk == "no") { m_timer = 0; m_rrjReason = PString(); return; } else if (gk == "auto") { m_gkaddr = INADDR_BROADCAST; m_gkport = GK_DEF_UNICAST_RAS_PORT; m_discoveryComplete = false; } else if (GetTransportAddress(gk, GK_DEF_UNICAST_RAS_PORT, m_gkaddr, m_gkport)) { m_discoveryComplete = (m_gkaddr == gkaddr) && (m_gkport == gkport); } else { // unresolvable? PTRACE(1, "GKC\tWarning: Can't resolve parent GK " << gk); return; } m_timer = 100; delete m_rewriteInfo; m_rewriteInfo = new Toolkit::RewriteData(cfg, RewriteE164Section); } void GkClient::CheckRegistration() { if (m_timer > 0 && (PTime() - m_registeredTime) > m_timer) Register(); } bool GkClient::CheckFrom(const RasMsg *ras) const { return ras->IsFrom(m_gkaddr, m_gkport); } PString GkClient::GetParent() const { return IsRegistered() ? AsString(m_gkaddr, m_gkport) + '\t' + m_endpointId.GetValue() : "not registered\t" + m_rrjReason; } bool GkClient::OnSendingRRQ(H225_RegistrationRequest &rrq) { if (m_parentVendor == ParentVendor_GnuGk) { PIPSocket::Address sigip; if (rrq.m_callSignalAddress.GetSize() > 0 && GetIPFromTransportAddr(rrq.m_callSignalAddress[0], sigip)) { rrq.IncludeOptionalField(H225_RegistrationRequest::e_nonStandardData); rrq.m_nonStandardData.m_data = "IP=" + sigip.AsString(); } } return true; } bool GkClient::OnSendingARQ(H225_AdmissionRequest &arq, Routing::AdmissionRequest &req) { if (m_parentVendor == ParentVendor_Cisco) { Cisco_ARQnonStandardInfo nonStandardData; arq.IncludeOptionalField(H225_AdmissionRequest::e_nonStandardData); arq.m_nonStandardData.m_nonStandardIdentifier.SetTag(H225_NonStandardIdentifier::e_h221NonStandard); H225_H221NonStandard & h221 = arq.m_nonStandardData.m_nonStandardIdentifier; h221.m_manufacturerCode = 18; h221.m_t35CountryCode = 181; h221.m_t35Extension = 0; PPER_Stream buff; nonStandardData.Encode(buff); buff.CompleteEncoding(); arq.m_nonStandardData.m_data = buff; } return true; } bool GkClient::OnSendingLRQ(H225_LocationRequest &lrq, Routing::LocationRequest &/*req*/) { if (m_parentVendor == ParentVendor_Cisco) { Cisco_LRQnonStandardInfo nonStandardData; nonStandardData.m_ttl = 6; if (lrq.HasOptionalField(H225_LocationRequest::e_sourceInfo)) { nonStandardData.IncludeOptionalField(Cisco_LRQnonStandardInfo::e_gatewaySrcInfo); nonStandardData.m_gatewaySrcInfo.SetSize(lrq.m_sourceInfo.GetSize()); for (PINDEX i = 0; i < lrq.m_sourceInfo.GetSize(); i++) nonStandardData.m_gatewaySrcInfo[i] = lrq.m_sourceInfo[i]; } else { if (m_h323Id.GetSize() > 0) { nonStandardData.IncludeOptionalField(Cisco_LRQnonStandardInfo::e_gatewaySrcInfo); nonStandardData.m_gatewaySrcInfo.SetSize(m_h323Id.GetSize()); for (PINDEX i = 0; i < m_h323Id.GetSize(); i++) H323SetAliasAddress(m_h323Id[i], nonStandardData.m_gatewaySrcInfo[i], H225_AliasAddress::e_h323_ID); } if (m_e164.GetSize() > 0) { nonStandardData.IncludeOptionalField(Cisco_LRQnonStandardInfo::e_gatewaySrcInfo); PINDEX sz = nonStandardData.m_gatewaySrcInfo.GetSize(); nonStandardData.m_gatewaySrcInfo.SetSize(sz + m_e164.GetSize()); for (PINDEX i = 0; i < m_e164.GetSize(); i++) H323SetAliasAddress(m_e164[i], nonStandardData.m_gatewaySrcInfo[sz + i]); } } lrq.IncludeOptionalField(H225_LocationRequest::e_nonStandardData); lrq.m_nonStandardData.m_nonStandardIdentifier.SetTag(H225_NonStandardIdentifier::e_h221NonStandard); H225_H221NonStandard & h221 = lrq.m_nonStandardData.m_nonStandardIdentifier; h221.m_manufacturerCode = 18; h221.m_t35CountryCode = 181; h221.m_t35Extension = 0; PPER_Stream buff; nonStandardData.Encode(buff); buff.CompleteEncoding(); lrq.m_nonStandardData.m_data = buff; } return true; } bool GkClient::OnSendingARQ(H225_AdmissionRequest &arq, Routing::SetupRequest &req, bool /*answer*/) { if (m_parentVendor == ParentVendor_Cisco) { const Q931 &setup = req.GetWrapper()->GetQ931(); Cisco_ARQnonStandardInfo nonStandardData; if (setup.HasIE(Q931::CallingPartyNumberIE)) { PBYTEArray data = setup.GetIE(Q931::CallingPartyNumberIE); if (data.GetSize() >= 2 && (data[0] & 0x80) == 0x80) { nonStandardData.IncludeOptionalField(Cisco_ARQnonStandardInfo::e_callingOctet3a); nonStandardData.m_callingOctet3a = data[1]; } } arq.IncludeOptionalField(H225_AdmissionRequest::e_nonStandardData); arq.m_nonStandardData.m_nonStandardIdentifier.SetTag(H225_NonStandardIdentifier::e_h221NonStandard); H225_H221NonStandard & h221 = arq.m_nonStandardData.m_nonStandardIdentifier; h221.m_manufacturerCode = 18; h221.m_t35CountryCode = 181; h221.m_t35Extension = 0; PPER_Stream buff; nonStandardData.Encode(buff); buff.CompleteEncoding(); arq.m_nonStandardData.m_data = buff; } return true; } bool GkClient::OnSendingARQ(H225_AdmissionRequest &arq, Routing::FacilityRequest &/*req*/) { if (m_parentVendor == ParentVendor_Cisco) { Cisco_ARQnonStandardInfo nonStandardData; arq.IncludeOptionalField(H225_AdmissionRequest::e_nonStandardData); arq.m_nonStandardData.m_nonStandardIdentifier.SetTag(H225_NonStandardIdentifier::e_h221NonStandard); H225_H221NonStandard & h221 = arq.m_nonStandardData.m_nonStandardIdentifier; h221.m_manufacturerCode = 18; h221.m_t35CountryCode = 181; h221.m_t35Extension = 0; PPER_Stream buff; nonStandardData.Encode(buff); buff.CompleteEncoding(); arq.m_nonStandardData.m_data = buff; } return true; } bool GkClient::OnSendingDRQ(H225_DisengageRequest &/*drq*/, const callptr &/*call*/) { return true; } bool GkClient::OnSendingURQ(H225_UnregistrationRequest &/*urq*/) { return true; } bool GkClient::SendARQ(Routing::AdmissionRequest & arq_obj) { const H225_AdmissionRequest & oarq = arq_obj.GetRequest(); H225_RasMessage arq_ras; Requester request(arq_ras, m_loaddr); H225_AdmissionRequest & arq = BuildARQ(arq_ras); if (oarq.HasOptionalField(H225_AdmissionRequest::e_destinationInfo)) { arq.IncludeOptionalField(H225_AdmissionRequest::e_destinationInfo); arq.m_destinationInfo = oarq.m_destinationInfo; } if (oarq.HasOptionalField(H225_AdmissionRequest::e_destExtraCallInfo)) { arq.IncludeOptionalField(H225_AdmissionRequest::e_destExtraCallInfo); arq.m_destExtraCallInfo = oarq.m_destExtraCallInfo; } arq.m_srcInfo = oarq.m_srcInfo; RewriteE164(arq.m_srcInfo, true); arq.m_bandWidth = oarq.m_bandWidth; arq.m_callReferenceValue = oarq.m_callReferenceValue; arq.m_conferenceID = oarq.m_conferenceID; if (oarq.HasOptionalField(H225_AdmissionRequest::e_callIdentifier)) { arq.IncludeOptionalField(H225_AdmissionRequest::e_callIdentifier); arq.m_callIdentifier = oarq.m_callIdentifier; } return OnSendingARQ(arq, arq_obj) && WaitForACF(request, &arq_obj); } bool GkClient::SendLRQ(Routing::LocationRequest & lrq_obj) { const H225_LocationRequest & olrq = lrq_obj.GetRequest(); H225_RasMessage lrq_ras; Requester request(lrq_ras, m_loaddr); H225_LocationRequest & lrq = lrq_ras; lrq.m_destinationInfo = olrq.m_destinationInfo; lrq.m_replyAddress = m_rasSrv->GetRasAddress(m_loaddr); lrq.IncludeOptionalField(H225_LocationRequest::e_endpointIdentifier); lrq.m_endpointIdentifier = m_endpointId; if (olrq.HasOptionalField(H225_LocationRequest::e_sourceInfo)) { lrq.IncludeOptionalField(H225_LocationRequest::e_sourceInfo); lrq.m_sourceInfo = olrq.m_sourceInfo; RewriteE164(lrq.m_sourceInfo, true); } if (olrq.HasOptionalField(H225_LocationRequest::e_canMapAlias)) { lrq.IncludeOptionalField(H225_LocationRequest::e_canMapAlias); lrq.m_canMapAlias = olrq.m_canMapAlias; } SetNBPassword(lrq); if (!OnSendingLRQ(lrq, lrq_obj)) return false; request.SendRequest(m_gkaddr, m_gkport); if (request.WaitForResponse(5000)) { RasMsg *ras = request.GetReply(); unsigned tag = ras->GetTag(); if (tag == H225_RasMessage::e_locationConfirm) { H225_LocationConfirm & lcf = (*ras)->m_recvRAS; lrq_obj.AddRoute(Route("parent", lcf.m_callSignalAddress)); RasMsg *oras = lrq_obj.GetWrapper(); (*oras)->m_replyRAS.SetTag(H225_RasMessage::e_locationConfirm); H225_LocationConfirm & nlcf = (*oras)->m_replyRAS; if (lcf.HasOptionalField(H225_LocationConfirm::e_cryptoTokens)) { nlcf.IncludeOptionalField(H225_LocationConfirm::e_cryptoTokens); nlcf.m_cryptoTokens = lcf.m_cryptoTokens; } return true; } } return false; } bool GkClient::SendARQ(Routing::SetupRequest & setup_obj, bool answer) { H225_RasMessage arq_ras; Requester request(arq_ras, m_loaddr); H225_AdmissionRequest & arq = BuildARQ(arq_ras); H225_Setup_UUIE & setup = setup_obj.GetRequest(); arq.m_callReferenceValue = setup_obj.GetWrapper()->GetCallReference(); arq.m_conferenceID = setup.m_conferenceID; if (setup.HasOptionalField(H225_Setup_UUIE::e_callIdentifier)) { arq.IncludeOptionalField(H225_AdmissionRequest::e_callIdentifier); arq.m_callIdentifier = setup.m_callIdentifier; } if (setup.HasOptionalField(H225_Setup_UUIE::e_sourceAddress)) { arq.m_srcInfo = setup.m_sourceAddress; if (!answer) RewriteE164(arq.m_srcInfo, true); } else { // no sourceAddress privided in Q.931 Setup? // since srcInfo is mandatory, set my aliases as the srcInfo if (m_h323Id.GetSize() > 0) { arq.m_srcInfo.SetSize(1); H323SetAliasAddress(m_h323Id[0], arq.m_srcInfo[0], H225_AliasAddress::e_h323_ID); } if (m_e164.GetSize() > 0) { PINDEX sz = arq.m_srcInfo.GetSize(); arq.m_srcInfo.SetSize(sz + 1); H323SetAliasAddress(m_e164[0], arq.m_srcInfo[sz]); } } if (setup.HasOptionalField(H225_Setup_UUIE::e_destinationAddress)) { arq.IncludeOptionalField(H225_AdmissionRequest::e_destinationInfo); arq.m_destinationInfo = setup.m_destinationAddress; if (answer) RewriteE164(arq.m_destinationInfo, true); } arq.m_answerCall = answer; // workaround for bandwidth, as OpenH323 library :p arq.m_bandWidth = 1280; return OnSendingARQ(arq, setup_obj, answer) && WaitForACF(request, answer ? 0 : &setup_obj); } bool GkClient::SendARQ(Routing::FacilityRequest & facility_obj) { H225_RasMessage arq_ras; Requester request(arq_ras, m_loaddr); H225_AdmissionRequest & arq = BuildARQ(arq_ras); H225_Facility_UUIE & facility = facility_obj.GetRequest(); arq.m_callReferenceValue = facility_obj.GetWrapper()->GetCallReference(); if (facility.HasOptionalField(H225_Facility_UUIE::e_conferenceID)) arq.m_conferenceID = facility.m_conferenceID; if (facility.HasOptionalField(H225_Facility_UUIE::e_callIdentifier)) { arq.IncludeOptionalField(H225_AdmissionRequest::e_callIdentifier); arq.m_callIdentifier = facility.m_callIdentifier; } if (m_h323Id.GetSize() > 0) { arq.m_srcInfo.SetSize(1); H323SetAliasAddress(m_h323Id[0], arq.m_srcInfo[0], H225_AliasAddress::e_h323_ID); } if (m_e164.GetSize() > 0) { PINDEX sz = arq.m_srcInfo.GetSize(); arq.m_srcInfo.SetSize(sz + 1); H323SetAliasAddress(m_e164[0], arq.m_srcInfo[sz]); } if (facility.HasOptionalField(H225_Facility_UUIE::e_alternativeAliasAddress)) { arq.IncludeOptionalField(H225_AdmissionRequest::e_destinationInfo); arq.m_destinationInfo = facility.m_alternativeAliasAddress; } arq.m_answerCall = false; // workaround for bandwidth, as OpenH323 library :p arq.m_bandWidth = 1280; return OnSendingARQ(arq, facility_obj) && WaitForACF(request, &facility_obj); } void GkClient::SendDRQ(const callptr & call) { H225_RasMessage drq_ras; Requester request(drq_ras, m_loaddr); H225_DisengageRequest & drq = drq_ras; call->BuildDRQ(drq, H225_DisengageReason::e_normalDrop); drq.IncludeOptionalField(H225_DisengageRequest::e_gatekeeperIdentifier); drq.m_gatekeeperIdentifier = m_gatekeeperId; drq.m_endpointIdentifier = m_endpointId; drq.m_answeredCall = !call->GetCallingParty(); SetPassword(drq); if (OnSendingDRQ(drq, call)) { request.SendRequest(m_gkaddr, m_gkport); request.WaitForResponse(3000); } // ignore response } void GkClient::SendURQ() { // the order is important: build URQ, close NAT socket, then send URQ H225_RasMessage urq_ras; urq_ras.SetTag(H225_RasMessage::e_unregistrationRequest); H225_UnregistrationRequest & urq = urq_ras; urq.m_requestSeqNum = m_rasSrv->GetRequestSeqNum(); urq.IncludeOptionalField(H225_UnregistrationRequest::e_gatekeeperIdentifier); urq.m_gatekeeperIdentifier = m_gatekeeperId; urq.IncludeOptionalField(H225_UnregistrationRequest::e_endpointIdentifier); urq.m_endpointIdentifier = m_endpointId; SetCallSignalAddress(urq.m_callSignalAddress); SetPassword(urq); Unregister(); if (OnSendingURQ(urq)) m_rasSrv->SendRas(urq_ras, m_gkaddr, m_gkport, m_loaddr); } bool GkClient::RewriteE164(H225_AliasAddress & alias, bool fromInternal) { if (alias.GetTag() != H225_AliasAddress::e_dialedDigits) return false; PString e164 = AsString(alias, FALSE); bool changed = RewriteString(e164, fromInternal); if (changed) H323SetAliasAddress(e164, alias); return changed; } bool GkClient::RewriteE164(H225_ArrayOf_AliasAddress & aliases, bool fromInternal) { bool changed = false; for (PINDEX i = 0; i < aliases.GetSize(); ++i) if (RewriteE164(aliases[i], fromInternal)) changed = true; return changed; } bool GkClient::RewriteE164( SetupMsg &setup, bool fromInternal ) { Q931 &q931 = setup.GetQ931(); H225_Setup_UUIE &setupBody = setup.GetUUIEBody(); unsigned plan, type; PString number; bool result = false; if (fromInternal) { bool r1 = q931.GetCallingPartyNumber(number, &plan, &type); if (r1 && (result = RewriteString(number, true))) { q931.SetCallingPartyNumber(number, plan, type); setup.SetChanged(); } if ((!r1 || result) && setupBody.HasOptionalField(H225_Setup_UUIE::e_sourceAddress)) if (RewriteE164(setupBody.m_sourceAddress, true)) { result = true; setup.SetUUIEChanged(); } } else { bool r1 = q931.GetCalledPartyNumber(number, &plan, &type); if (r1 && (result = RewriteString(number, false))) { q931.SetCalledPartyNumber(number, plan, type); setup.SetChanged(); } if ((!r1 || result) && setupBody.HasOptionalField(H225_Setup_UUIE::e_destinationAddress)) if (RewriteE164(setupBody.m_destinationAddress, false)) { result = true; setup.SetUUIEChanged(); } } return result; } bool GkClient::Discovery() { m_loaddr = m_gkaddr; m_gatekeeperId = PString(); if (!m_discoverParent) return true; GRQRequester request(GkConfig()->GetString(EndpointSection, "GatekeeperIdentifier", "")); // the spec: timeout value 5 sec, retry count 2 request.SendRequest(m_gkaddr, m_gkport); while (request.WaitForResponse(5000)) { RasMsg *ras = request.GetReply(); if (ras->GetTag() == H225_RasMessage::e_gatekeeperConfirm) { H225_GatekeeperConfirm & gcf = (*ras)->m_recvRAS; m_loaddr = (*ras)->m_localAddr; if (gcf.HasOptionalField(H225_GatekeeperConfirm::e_gatekeeperIdentifier)) m_gatekeeperId = gcf.m_gatekeeperIdentifier; GetIPAndPortFromTransportAddr(gcf.m_rasAddress, m_gkaddr, m_gkport); if (gcf.HasOptionalField(H225_GatekeeperConfirm::e_authenticationMode)) m_authMode = gcf.m_authenticationMode.GetTag(); PTRACE(2, "GKC\tDiscover GK " << AsString(m_gkaddr, m_gkport) << " at " << m_loaddr); return true; } else if (ras->GetTag() == H225_RasMessage::e_gatekeeperReject) { H225_GatekeeperReject & grj = (*ras)->m_recvRAS; if (grj.HasOptionalField(H225_GatekeeperReject::e_altGKInfo)) { m_gkList->Set(grj.m_altGKInfo.m_alternateGatekeeper); m_useAltGKPermanent = grj.m_altGKInfo.m_altGKisPermanent; break; } } } return false; } void GkClient::Register() { PWaitAndSignal lock(m_rrqMutex); m_rrjReason = "no response"; if (!IsRegistered() && !m_discoveryComplete) while (!(m_discoveryComplete = Discovery())) if (!GetAltGK()) return; H225_RasMessage rrq_ras; Requester request(rrq_ras, m_loaddr); BuildRRQ(rrq_ras); OnSendingRRQ(rrq_ras); request.SendRequest(m_gkaddr, m_gkport); m_registeredTime = PTime(); if (request.WaitForResponse(m_retry * 1000)) { RasMsg *ras = request.GetReply(); switch (ras->GetTag()) { case H225_RasMessage::e_registrationConfirm: OnRCF(ras); return; case H225_RasMessage::e_registrationReject: OnRRJ(ras); break; } } GetAltGK(); } void GkClient::Unregister() { if (m_natClient) { m_natClient->Stop(); m_natClient = NULL; } for_each(m_handlers, m_handlers + 4, bind1st(mem_fun(&RasServer::UnregisterHandler), m_rasSrv)); m_registered = false; } bool GkClient::GetAltGK() { Unregister(); // always re-register bool result = false; if (Toolkit::AsBool(GkConfig()->GetString(EndpointSection, "UseAlternateGK", "1"))) result = m_gkList->Get(m_gkaddr, m_gkport); PString altgk(AsString(m_gkaddr, m_gkport)); if (m_useAltGKPermanent) Toolkit::Instance()->SetConfig(1, EndpointSection, "Gatekeeper", altgk); if (result) { m_timer = 100, m_resend = m_retry, m_discoveryComplete = false; PTRACE(1, "GKC\tUse Alternate GK " << altgk << (m_useAltGKPermanent ? " permanently" : " temporarily")); } else { // if no alternate gatekeeper found // increase our resent time to avoid flooding the parent m_timer = (m_resend *= 2) * 1000; if (m_resend >= m_gkfailtime) { // FIXME: not thread-safed Toolkit::Instance()->GetRouteTable()->InitTable(); m_resend = m_gkfailtime; } } return result; } void GkClient::BuildRRQ(H225_RegistrationRequest & rrq) { rrq.m_protocolIdentifier.SetValue(H225_ProtocolID); rrq.m_discoveryComplete = m_discoveryComplete; SetRasAddress(rrq.m_rasAddress); SetCallSignalAddress(rrq.m_callSignalAddress); rrq.IncludeOptionalField(H225_RegistrationRequest::e_supportsAltGK); IsRegistered() ? BuildLightWeightRRQ(rrq) : BuildFullRRQ(rrq); SetPassword(rrq); } void GkClient::BuildFullRRQ(H225_RegistrationRequest & rrq) { rrq.m_terminalType.IncludeOptionalField(H225_EndpointType::e_gatekeeper); PINDEX as, p; if (m_endpointType == EndpointType_Terminal) { rrq.m_terminalType.IncludeOptionalField(H225_EndpointType::e_terminal); } else { rrq.m_terminalType.IncludeOptionalField(H225_EndpointType::e_gateway); as = m_prefixes.GetSize(); if (as > 0) { rrq.m_terminalType.m_gateway.IncludeOptionalField(H225_GatewayInfo::e_protocol); rrq.m_terminalType.m_gateway.m_protocol.SetSize(1); H225_SupportedProtocols & protocol = rrq.m_terminalType.m_gateway.m_protocol[0]; protocol.SetTag(H225_SupportedProtocols::e_voice); H225_VoiceCaps & voicecap = (H225_VoiceCaps &)protocol; voicecap.m_supportedPrefixes.SetSize(as); for (PINDEX p = 0; p < as; ++p) H323SetAliasAddress(m_prefixes[p].Trim(), voicecap.m_supportedPrefixes[p].m_prefix); } // rrq.IncludeOptionalField(H225_RegistrationRequest::e_multipleCalls); // rrq.m_multipleCalls = FALSE; } rrq.IncludeOptionalField(H225_RegistrationRequest::e_terminalAlias); as = m_h323Id.GetSize(); rrq.m_terminalAlias.SetSize(as); for (p = 0; p < as; ++p) H323SetAliasAddress(m_h323Id[p], rrq.m_terminalAlias[p], H225_AliasAddress::e_h323_ID); PINDEX s = m_e164.GetSize() + as; rrq.m_terminalAlias.SetSize(s); for (p = as; p < s; ++p) H323SetAliasAddress(m_e164[p-as], rrq.m_terminalAlias[p]); int ttl = GkConfig()->GetInteger(EndpointSection, "TimeToLive", DEFAULT_TTL); if (ttl > 0) { rrq.IncludeOptionalField(H225_RegistrationRequest::e_timeToLive); rrq.m_timeToLive = ttl; } H225_VendorIdentifier & vendor = rrq.m_endpointVendor; vendor.IncludeOptionalField(H225_VendorIdentifier::e_productId); vendor.m_productId = PString(PString::Printf, "GNU Gatekeeper on %s %s %s, %s %s", (const unsigned char*)(PProcess::GetOSName()), (const unsigned char*)(PProcess::GetOSHardware()), (const unsigned char*)(PProcess::GetOSVersion()) ,__DATE__, __TIME__); vendor.IncludeOptionalField(H225_VendorIdentifier::e_versionId); vendor.m_versionId = "Version " + PProcess::Current().GetVersion(); // set user provided endpointIdentifier, if any PString endpointId(GkConfig()->GetString(EndpointSection, "EndpointIdentifier", "")); if (!endpointId) { rrq.IncludeOptionalField(H225_RegistrationRequest::e_endpointIdentifier); rrq.m_endpointIdentifier = endpointId; } // set gatekeeperIdentifier found in discovery procedure if (!m_gatekeeperId.GetValue()) { rrq.IncludeOptionalField(H225_RegistrationRequest::e_gatekeeperIdentifier); rrq.m_gatekeeperIdentifier = m_gatekeeperId; } rrq.m_keepAlive = FALSE; } void GkClient::BuildLightWeightRRQ(H225_RegistrationRequest & rrq) { rrq.IncludeOptionalField(H225_RegistrationRequest::e_endpointIdentifier); rrq.m_endpointIdentifier = m_endpointId; rrq.IncludeOptionalField(H225_RegistrationRequest::e_gatekeeperIdentifier); rrq.m_gatekeeperIdentifier = m_gatekeeperId; rrq.m_keepAlive = TRUE; } bool GkClient::WaitForACF(RasRequester & request, Routing::RoutingRequest *robj) { request.SendRequest(m_gkaddr, m_gkport); if (request.WaitForResponse(5000)) { RasMsg *ras = request.GetReply(); if (ras->GetTag() == H225_RasMessage::e_admissionConfirm) { if (robj) { H225_AdmissionConfirm & acf = (*ras)->m_recvRAS; Route route("parent", acf.m_destCallSignalAddress); route.m_flags |= Route::e_toParent; robj->AddRoute(route); } return true; } if (ras->GetTag() == H225_RasMessage::e_admissionReject) OnARJ(ras); } return false; } H225_AdmissionRequest & GkClient::BuildARQ(H225_AdmissionRequest & arq) { arq.m_callType.SetTag(H225_CallType::e_pointToPoint); arq.m_endpointIdentifier = m_endpointId; arq.IncludeOptionalField(H225_AdmissionRequest::e_srcCallSignalAddress); arq.m_srcCallSignalAddress = m_rasSrv->GetCallSignalAddress(m_loaddr); arq.IncludeOptionalField(H225_AdmissionRequest::e_canMapAlias); arq.m_canMapAlias = TRUE; arq.IncludeOptionalField(H225_AdmissionRequest::e_gatekeeperIdentifier); arq.m_gatekeeperIdentifier = m_gatekeeperId; SetPassword(arq); return arq; } void GkClient::OnRCF(RasMsg *ras) { H225_RegistrationConfirm & rcf = (*ras)->m_recvRAS; if (!IsRegistered()) { PTRACE(2, "GKC\tRegister with " << AsString(m_gkaddr, m_gkport) << " successfully"); m_registered = true; m_endpointId = rcf.m_endpointIdentifier; m_gatekeeperId = rcf.m_gatekeeperIdentifier; if (rcf.HasOptionalField(H225_RegistrationConfirm::e_alternateGatekeeper)) m_gkList->Set(rcf.m_alternateGatekeeper); for_each(m_handlers, m_handlers + 4, bind1st(mem_fun(&RasServer::RegisterHandler), m_rasSrv)); } // Not all RCF contain TTL, in that case keep old value if (rcf.HasOptionalField(H225_RegistrationConfirm::e_timeToLive)) { m_ttl = PMAX(rcf.m_timeToLive - m_retry, 30); // Have it reregister at 3/4 of TimeToLive, otherwise the parent // might go out of sync and ends up sending an URQ m_ttl = (m_ttl / 4) * 3; } m_timer = m_ttl * 1000; m_resend = m_retry; // NAT handling if (rcf.HasOptionalField(H225_RegistrationConfirm::e_nonStandardData)) if (rcf.m_nonStandardData.m_data.AsString().Find("NAT=") == 0) if (!m_natClient && rcf.m_callSignalAddress.GetSize() > 0) m_natClient = new NATClient(rcf.m_callSignalAddress[0], m_endpointId); } void GkClient::OnRRJ(RasMsg *ras) { H225_RegistrationReject & rrj = (*ras)->m_recvRAS; m_rrjReason = "Reason: " + rrj.m_rejectReason.GetTagName(); PTRACE(1, "GKC\tRegistration Rejected: " << rrj.m_rejectReason.GetTagName()); if (rrj.HasOptionalField(H225_RegistrationReject::e_altGKInfo)) { m_gkList->Set(rrj.m_altGKInfo.m_alternateGatekeeper); m_useAltGKPermanent = rrj.m_altGKInfo.m_altGKisPermanent; GetAltGK(); } else if (rrj.m_rejectReason.GetTag() == H225_RegistrationRejectReason::e_fullRegistrationRequired) { SendURQ(); m_timer = 100; Toolkit::Instance()->GetRouteTable()->InitTable(); } } void GkClient::OnARJ(RasMsg *ras) { H225_AdmissionReject & arj = (*ras)->m_recvRAS; if (arj.HasOptionalField(H225_AdmissionReject::e_altGKInfo)) { m_gkList->Set(arj.m_altGKInfo.m_alternateGatekeeper); m_useAltGKPermanent = arj.m_altGKInfo.m_altGKisPermanent; GetAltGK(); } else if (arj.m_rejectReason.GetTag() == H225_AdmissionRejectReason::e_callerNotRegistered) { Unregister(); m_timer = 100; // re-register again } } bool GkClient::OnURQ(RasMsg *ras) { Unregister(); m_registeredTime = PTime(); H225_UnregistrationRequest & urq = (*ras)->m_recvRAS; switch (urq.m_reason.GetTag()) { case H225_UnregRequestReason::e_reregistrationRequired: case H225_UnregRequestReason::e_ttlExpired: m_timer = 500; break; default: m_timer = m_retry * 1000; if (urq.HasOptionalField(H225_UnregistrationRequest::e_alternateGatekeeper)) { m_gkList->Set(urq.m_alternateGatekeeper); GetAltGK(); } break; } (*ras)->m_replyRAS.SetTag(H225_RasMessage::e_unregistrationConfirm); H225_UnregistrationConfirm & ucf = (*ras)->m_replyRAS; ucf.m_requestSeqNum = urq.m_requestSeqNum; return true; } bool GkClient::OnDRQ(RasMsg *ras) { H225_DisengageRequest & drq = (*ras)->m_recvRAS; if (callptr call = drq.HasOptionalField(H225_DisengageRequest::e_callIdentifier) ? CallTable::Instance()->FindCallRec(drq.m_callIdentifier) : CallTable::Instance()->FindCallRec(drq.m_callReferenceValue)) call->Disconnect(true); (*ras)->m_replyRAS.SetTag(H225_RasMessage::e_disengageConfirm); H225_DisengageConfirm & dcf = (*ras)->m_replyRAS; dcf.m_requestSeqNum = drq.m_requestSeqNum; return true; } bool GkClient::OnBRQ(RasMsg *ras) { // lazy implementation, just reply confirm H225_BandwidthRequest & brq = (*ras)->m_recvRAS; (*ras)->m_replyRAS.SetTag(H225_RasMessage::e_bandwidthConfirm); H225_BandwidthConfirm & bcf = (*ras)->m_replyRAS; bcf.m_requestSeqNum = brq.m_requestSeqNum; bcf.m_bandWidth = brq.m_bandWidth; return true; } bool GkClient::OnIRQ(RasMsg *ras) { // TODO H225_InfoRequest & irq = (*ras)->m_recvRAS; (*ras)->m_replyRAS.SetTag(H225_RasMessage::e_infoRequestResponse); H225_InfoRequestResponse & irr = (*ras)->m_replyRAS; irr.m_requestSeqNum = irq.m_requestSeqNum; return true; } bool GkClient::RewriteString(PString & alias, bool fromInternal) const { if (!m_rewriteInfo) return false; for (PINDEX i = 0; i < m_rewriteInfo->Size(); ++i) { PString prefix, insert; if (fromInternal) { insert = m_rewriteInfo->Key(i); prefix = m_rewriteInfo->Value(i); } else { prefix = m_rewriteInfo->Key(i); insert = m_rewriteInfo->Value(i); } int len = prefix.GetLength(); if (len == 0 || strncmp(prefix, alias, len) == 0){ PString result = insert + alias.Mid(len); PTRACE(2, "GKC\tRewritePString: " << alias << " to " << result); alias = result; return true; } } return false; } void GkClient::SetClearTokens(H225_ArrayOf_ClearToken & clearTokens, const PString & id) { clearTokens.RemoveAll(); H235AuthCAT auth; // avoid copying for thread-safely auth.SetLocalId((const char *)id); auth.SetPassword((const char *)m_password); H225_ArrayOf_CryptoH323Token dumbTokens; auth.PrepareTokens(clearTokens, dumbTokens); } void GkClient::SetCryptoTokens(H225_ArrayOf_CryptoH323Token & cryptoTokens, const PString & id) { cryptoTokens.RemoveAll(); H235AuthSimpleMD5 auth; // avoid copying for thread-safely auth.SetLocalId((const char *)id); auth.SetPassword((const char *)m_password); H225_ArrayOf_ClearToken dumbTokens; auth.PrepareTokens(dumbTokens, cryptoTokens); } void GkClient::SetRasAddress(H225_ArrayOf_TransportAddress & addr) { addr.SetSize(1); addr[0] = m_rasSrv->GetRasAddress(m_loaddr); } void GkClient::SetCallSignalAddress(H225_ArrayOf_TransportAddress & addr) { addr.SetSize(1); addr[0] = m_rasSrv->GetCallSignalAddress(m_loaddr); } void GkClient::SetNBPassword( H225_LocationRequest& lrq, /// LRQ message to be filled with tokens const PString& id // login name ) { if (!m_password) { lrq.IncludeOptionalField(H225_LocationRequest::e_cryptoTokens), SetCryptoTokens(lrq.m_cryptoTokens, id); lrq.IncludeOptionalField(H225_LocationRequest::e_tokens), SetClearTokens(lrq.m_tokens, id); } }