📄 aaa_route_msg_router.cxx
字号:
/* The Diameter protocol requires that agents maintain transaction state, which is used for failover purposes. Transaction state implies that upon forwarding a request, the Hop-by-Hop identifier is saved; the field is replaced with a locally unique identifier, which is restored to its original value when the corresponding answer is received. The request's state is released upon receipt of the answer. A stateless agent is one that only maintains transaction state. */ int h2hIndex, rcode; if (source) { int localHH = AAA_HOPBYHOP_GEN()->Get(); h2hIndex = Add(localHH, msg, source, dest); msg->hdr.hh = localHH; } else { // locally generated if (msg->hdr.hh == 0) { msg->hdr.hh = AAA_HOPBYHOP_GEN()->Get(); } if (msg->hdr.ee == 0) { msg->hdr.ee = AAA_ENDTOEND_GEN()->Get(); } h2hIndex = Add(msg->hdr.hh, msg, source, dest); } rcode = (dest->Send(msg) >= 0) ? 0 : (-1); if (h2hIndex > 0) { StoreRequestMessage(h2hIndex, msg); } return rcode; } return (0);}AAA_ROUTE_RESULT AAA_MsgRouter::DcReject::Process(std::auto_ptr<AAAMessage> msg, AAA_PeerEntry *source, AAA_PeerEntry *dest){ /* 6.2.1. Processing received Answers A Diameter client or proxy MUST match the Hop-by-Hop Identifier in an answer received against the list of pending requests. The corresponding message should be removed from the list of pending requests. It SHOULD ignore answers received that do not match a known Hop-by-Hop Identifier. */ AAA_LOG(LM_INFO, "(%P|%t) *** Router rejected answer message ***\n"); AAA_MsgDump::Dump(*msg); return (AAA_ROUTE_RESULT_SUCCESS);}int AAA_MsgRouter::DcReject::RequestMsg(std::auto_ptr<AAAMessage> msg, AAA_PeerEntry *source, AAA_PeerEntry *dest){ /* 6.1. Diameter Request Routing Overview . . . 4. If none of the above is successful, an answer is returned with the Result-Code set to AAA_UNABLE_TO_DELIVER, with the E-bit set. */ AAA_LOG(LM_INFO, "(%P|%t) *** Router rejected request message ***\n"); AAA_MsgDump::Dump(*msg); msg->hdr.flags.r = 0; msg->hdr.flags.e = 1; AAA_MsgResultCode rcode(*msg); rcode.ResultCode(AAA_UNABLE_TO_DELIVER); if (! source) { // request must have been locally generated m_Arg[AAA_MsgRouterHandlerTable::H_ERROR]-> Request(msg, source, dest); return (0); } else { return (source->Send(msg) == 0) ? 0 : (-1); }}AAA_ROUTE_RESULT AAA_MsgRouter::DcReject::Lookup(std::auto_ptr<AAAMessage> &msg, AAA_PeerEntry *&dest){ /* 6.2.1. Processing received Answers A Diameter client or proxy MUST match the Hop-by-Hop Identifier in an answer received against the list of pending requests. The corresponding message should be removed from the list of pending requests. It SHOULD ignore answers received that do not match a known Hop-by-Hop Identifier. */ return (AAA_ROUTE_RESULT_SUCCESS);}int AAA_MsgRouter::RedirectAgent::Request(std::auto_ptr<AAAMessage> &msg, AAA_PeerEntry *source, AAA_PeerEntry *dest){ /* 6.1.7. Redirecting requests When a redirect agent receives a request whose routing entry is set to REDIRECT, it MUST reply with an answer message with the 'E' bit set, while maintaining the Hop-by-Hop Identifier in the header, and include the Result-Code AVP to AAA_REDIRECT_INDICATION. Each of the servers associated with the routing entry are added in separate Redirect-Host AVP. +------------------+ | Diameter | | Redirect Agent | +------------------+ ^ | 2. command + 'E' bit 1. Request | | Result-Code = joe@example.com | | AAA_REDIRECT_INDICATION + | | Redirect-Host AVP(s) | v +-------------+ 3. Request +-------------+ | example.com |------------->| example.net | | Relay | | Diameter | | Agent |<-------------| Server | +-------------+ 4. Answer +-------------+ Figure 5: Diameter Redirect Agent The receiver of the answer message with the 'E' bit set, and the Result-Code AVP set to AAA_REDIRECT_INDICATION uses the hop-by- hop field in the Diameter header to identify the request in the pending message queue (see Section 5.3) that is to be redirected. If no transport connection exists with the new agent, one is created, and the request is sent directly to it. Multiple Redirect-Host AVPs are allowed. The receiver of the answer message with the 'E' bit set selects exactly one of these hosts as the destination of the redirected message. */ AAA_IdentityAvpContainerWidget destRealm(msg->acl); diameter_identity_t *DestRealm = destRealm.GetAvp(AAA_AVPNAME_DESTREALM); AAA_RouteEntry *route = AAA_ROUTE_TABLE()->Lookup(*DestRealm); try { diameter_unsigned32_t *idPtr; char *avpNames[] = { AAA_AVPNAME_AUTHAPPID, AAA_AVPNAME_ACCTAPPID }; AAA_UInt32AvpContainerWidget id(msg->acl); for (int i=0; i<sizeof(avpNames)/sizeof(char*); i++) { if ((idPtr = id.GetAvp(avpNames[i]))) { break; } } AAA_RouteApplication *app = NULL; if (idPtr) { app = route->Lookup(*idPtr, 0); // base protocol only } else { AAA_GroupedAvpContainerWidget vendorSpecificId(msg->acl); diameter_grouped_t *grouped = vendorSpecificId.GetAvp (AAA_AVPNAME_VENDORAPPID); if (grouped) { AAA_ApplicationIdLst vendorIdLst; AAA_UInt32AvpContainerWidget gVendorId(*grouped); diameter_unsigned32_t *value = gVendorId.GetAvp(AAA_AVPNAME_VENDORID); for (int p=1; value; p++) { vendorIdLst.push_back(*value); value = gVendorId.GetAvp(AAA_AVPNAME_VENDORID, p); } char *avpNames[] = { AAA_AVPNAME_AUTHAPPID, AAA_AVPNAME_ACCTAPPID }; AAA_UInt32AvpContainerWidget gId(*grouped); for (int i=0; i<sizeof(avpNames)/sizeof(char*); i++) { if ((value = gId.GetAvp(avpNames[i]))) { break; } } if (value) { AAA_ApplicationIdLst::iterator i = vendorIdLst.begin(); for (; (app == NULL) && (i != vendorIdLst.end()); i++) { if ((app = route->Lookup(*value, *i))) { break; } } } } } if (app) { AAA_DiamUriAvpWidget redirect(AAA_AVPNAME_REDIRECTHOST); AAA_RouteServerEntry *server = app->Servers().First(); while (server) { redirect.Get().fqdn = server->Server(); server = app->Servers().Next(*server); } if (! redirect.empty()) { AAA_EnumAvpWidget redirectUsage(AAA_AVPNAME_REDIRECTHOSTUSAGE); redirectUsage.Get() = route->RedirectUsage(); msg->acl.add(redirect()); msg->acl.add(redirectUsage()); } } } catch (...) { return (-1); } msg->hdr.flags.r = 0; msg->hdr.flags.e = 1; AAA_MsgResultCode rcode(*msg); rcode.ResultCode(AAA_REDIRECT_INDICATION); return (source->Send(msg) >= 0) ? 0 : (-1);}int AAA_MsgRouter::RedirectAgent::Answer(std::auto_ptr<AAAMessage> &msg, AAA_PeerEntry *source, AAA_PeerEntry *dest){ /* 2.8.3. Redirect Agents Redirect agents are useful in scenarios where the Diameter routing configuration needs to be centralized. An example is a redirect agent that provides services to all members of a consortium, but does not wish to be burdened with relaying all messages between realms. This scenario is advantageous since it does not require that the consortium provide routing updates to its members when changes are made to a member's infrastructure. Since redirect agents do not relay messages, and only return an answer with the information necessary for Diameter agents to communicate directly, they do not modify messages. Since redirect agents do not receive answer messages, they cannot maintain session state. Further, since redirect agents never relay requests, they are not required to maintain transaction state. The example provided in Figure 3 depicts a request issued from the access device, NAS, for the user bob@example.com. The message is forwarded by the NAS to its relay, DRL, which does not have a routing entry in its Diameter Routing Table for example.com. DRL has a default route configured to DRD, which is a redirect agent that returns a redirect notification to DRL, as well as HMS' contact information. Upon receipt of the redirect notification, DRL establishes a transport connection with HMS, if one doesn't already exist, and forwards the request to it. +------+ | | | DRD | | | +------+ ^ | 2. Request | | 3. Redirection | | Notification | v +------+ ---------> +------+ ---------> +------+ | | 1. Request | | 4. Request | | | NAS | | DRL | | HMS | | | 6. Answer | | 5. Answer | | +------+ <--------- +------+ <--------- +------+ example.net example.net example.com Figure 3: Redirecting a Diameter Message Since redirect agents do not perform any application level processing, they provide relaying services for all Diameter applications, and therefore MUST advertise the Relay Application Identifier. */ msg->hdr.flags.r = 1; msg->hdr.flags.e = 0; AAA_UInt32AvpContainerWidget resultCode(msg->acl); resultCode.DelAvp(AAA_AVPNAME_RESULTCODE); AAA_DiamUriAvpContainerWidget redirect(msg->acl); diameter_uri_t *RedirectHost = redirect.GetAvp(AAA_AVPNAME_REDIRECTHOST); for (int p=1; RedirectHost; p++) { AAA_PeerEntry *peer = AAA_PEER_TABLE()->Lookup(RedirectHost->fqdn); if (peer) { if (peer->IsOpen()) { AAA_IdentityAvpWidget destHost(AAA_AVPNAME_DESTHOST); destHost.Get() = RedirectHost->fqdn; msg->acl.add(destHost()); redirect.DelAvp(AAA_AVPNAME_REDIRECTHOST); return (peer->Send(msg) >= 0) ? 0 : (-1); } else { // try opening it [TBD] } } else { // try to make connection to it [TBD] } RedirectHost = redirect.GetAvp(AAA_AVPNAME_REDIRECTHOST, p); } return (0);}bool AAA_MsgRouter::RedirectAgent::IsRedirected(std::auto_ptr<AAAMessage> &msg){ /* The receiver of the answer message with the 'E' bit set, and the Result-Code AVP set to AAA_REDIRECT_INDICATION uses the hop-by- hop field in the Diameter header to identify the request in the pending message queue (see Section 5.3) that is to be redirected. If no transport connection exists with the new agent, one is created, and the request is sent directly to it. Multiple Redirect-Host AVPs are allowed. The receiver of the answer message with the 'E' bit set selects exactly one of these hosts as the destination of the redirected message. */ AAA_MsgResultCode rcode(*msg); return ((msg->hdr.flags.r == 0) && (msg->hdr.flags.e) && (rcode.ResultCode() == AAA_REDIRECT_INDICATION));}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -