reSIProcate
SIP stack, Dialog Usage Manager and related libraries
Loading...
Searching...
No Matches
RRDecorator.cxx
Go to the documentation of this file.
1#ifdef HAVE_CONFIG_H
2#include "config.h"
3#endif
4
6
7#include "repro/Proxy.hxx"
8
13#include "resip/stack/Tuple.hxx"
15
16#include "rutil/Logger.hxx"
18
19#define RESIPROCATE_SUBSYSTEM resip::Subsystem::REPRO
20
22using resip::NameAddr;
23using resip::UDP;
24using resip::h_RecordRoutes;
25using resip::h_Paths;
27using resip::h_Routes;
28using resip::p_comp;
29
30namespace repro
31{
32RRDecorator::RRDecorator(const Proxy& proxy,
38 bool doPath,
40 mProxy(proxy),
41 mAddedRecordRoute(0),
42 mAlreadySingleRecordRouted(alreadySingleRecordRouted),
43 mHasInboundFlowToken(hasInboundFlowToken),
44 mForceRecordRouteEnabled(forceRecordRouteEnabled),
45 mDoPath(doPath),
46 mIsOriginalSenderBehindNAT(isOriginalSenderBehindNAT),
47 mReceivedTransportTuple(receivedTransportTuple),
48 mReceivedTransportRecordRoute(receivedTransportRecordRoute)
49{}
50
53
54void
56 const resip::Tuple &source,
57 const resip::Tuple &destination,
58 const resip::Data& sigcompId)
59{
60 DebugLog(<<"Proxy::decorateMessage called.");
62
63 if(isTransportSwitch(source))
64 {
65 if(mAlreadySingleRecordRouted)
66 {
67 singleRecordRoute(request, source, destination, sigcompId);
68 }
69 else
70 {
71 doubleRecordRoute(request, source, destination, sigcompId);
72 }
73 }
74 else
75 {
76 // We might still want to record-route in this case; if we need an
77 // outbound flow token or we've already added an inbound flow token
78 if(outboundFlowTokenNeeded(request, source, destination, sigcompId) ||
79 mHasInboundFlowToken) // or we have an inbound flow
80 {
81 resip_assert(mAlreadySingleRecordRouted);
82 singleRecordRoute(request, source, destination, sigcompId);
83 }
84 }
85
86 static ExtensionParameter p_drr("drr");
88 if(mDoPath)
89 {
90 routes=&(request.header(resip::h_Paths));
91 }
92 else
93 {
94 routes=&(request.header(resip::h_RecordRoutes));
95 }
96
97 if(routes->size() > 1 &&
98 mAddedRecordRoute &&
99 routes->front().uri().exists(p_drr))
100 {
101 // .bwc. It is possible that we have duplicate Record-Routes at this
102 // point, if we have done a transport switch but both transports use the
103 // same FQDN.
104 resip::NameAddrs::iterator second = ++(routes->begin());
105 if(*second == routes->front())
106 {
107 // Duplicated record-routes; pare down to a single one.
108 routes->pop_front();
109 --mAddedRecordRoute;
110 routes->front().uri().remove(p_drr);
111 }
112 }
113}
114
115void
116RRDecorator::singleRecordRoute(resip::SipMessage& request,
117 const resip::Tuple &source,
118 const resip::Tuple &destination,
119 const resip::Data& sigcompId)
120{
122 // .bwc. outboundFlowTokenNeeded means that we are assuming that whoever is
123 // just downstream will remain in the call-path throughout the dialog.
124 if(outboundFlowTokenNeeded(request, source, destination, sigcompId))
125 {
126 if(isSecure(destination.getType()))
127 {
128 rt = mProxy.getRecordRoute(destination.mTransportKey);
129 rt.uri().scheme()="sips";
130 }
131 else
132 {
135 // If record-route is not transport specific (ie: global record route setting), then generate appropriate one from source
137 {
138 // .bwc. It is safe to put ip+port+proto here, since we have an
139 // existing flow to the next hop.
141 rt.uri().port() = source.getPort();
142 rt.uri().param(resip::p_transport) = resip::Tuple::toDataLower(source.getType());
143 }
144 }
145 // .bwc. If our target has an outbound flow to us, we need to put a flow
146 // token in a Record-Route.
150
151 rt.uri().user()=binaryFlowToken.base64encode();
152 }
153 else
154 {
155 // No need for a flow-token; just use an ordinary record-route.
156 rt = mProxy.getRecordRoute(destination.mTransportKey);
158 }
159
160#ifdef USE_SIGCOMP
161 if(mProxy.compressionEnabled() && !sigcompId.empty())
162 {
163 rt.uri().param(p_comp)="sigcomp";
164 }
165#endif
166
168 if (mDoPath)
169 {
170 routes = &(request.header(resip::h_Paths));
171 InfoLog(<< "Adding outbound Path: " << rt);
172 }
173 else
174 {
175 routes = &(request.header(resip::h_RecordRoutes));
176 InfoLog(<< "Adding outbound Record-Route: " << rt);
177 }
178
179 if (routes->empty())
180 {
181 routes->push_front(rt);
182 }
183 else
184 {
185 static ExtensionParameter p_drr("drr");
186 rt.uri().param(p_drr);
187 routes->front().uri().param(p_drr);
188 routes->push_front(rt);
189 }
190 ++mAddedRecordRoute;
191}
192
193void
194RRDecorator::doubleRecordRoute(resip::SipMessage& request,
195 const resip::Tuple &source,
196 const resip::Tuple &destination,
197 const resip::Data& sigcompId)
198{
199 // We only use this on transport switch when we have not yet Record-Routed.
200 // If we needed a flow-token in the inbound Record-Route, it would have been
201 // added already.
202 resip::NameAddr rt(mReceivedTransportRecordRoute);
204 if(mDoPath)
205 {
206 request.header(h_Paths).push_front(rt);
207 }
208 else
209 {
210 request.header(h_RecordRoutes).push_front(rt);
211 }
212 ++mAddedRecordRoute;
213 singleRecordRoute(request, source, destination, sigcompId);
214}
215
216bool
217RRDecorator::isTransportSwitch(const resip::Tuple& sendingFrom)
218{
219 if(mForceRecordRouteEnabled)
220 {
221 // If we are forcing record routes to be added, then DRR on any transport switch
222 return mReceivedTransportTuple.mTransportKey != sendingFrom.mTransportKey;
223 }
224 else
225 {
226 // If record routing is not forced then only DRR if we are switching transport types or
227 // protocol versions, since the interfaces themselves may all be equally reachable
228 // !slg! - could make this behavior more configurable
229 return sendingFrom.getType() != mReceivedTransportTuple.getType() ||
230 sendingFrom.ipVersion() != mReceivedTransportTuple.ipVersion();
231 }
232}
233
234bool
235RRDecorator::outboundFlowTokenNeeded(resip::SipMessage &msg,
236 const resip::Tuple &source,
237 const resip::Tuple &destination,
238 const resip::Data& sigcompId)
239{
240 return (destination.onlyUseExistingConnection // destination is an outbound target
241 || resip::InteropHelper::getRRTokenHackEnabled() // or the token is enabled
242 || mIsOriginalSenderBehindNAT // or the nat detection hack is enabled
243 || !sigcompId.empty()); // or we are routing to a SigComp transport
244 // ?slg? For Sigcomp are we guaranteed to always have
245 // single RR at this point? If not, then strangeness
246 // will happen when singleRecordRoute adds a ;drr param
247}
248
249void
251{
252 resip::NameAddrs* routes = mDoPath ?
253 &(request.header(resip::h_Paths)) :
254 &(request.header(resip::h_RecordRoutes));
255
256 if (mAddedRecordRoute < 0)
257 {
258 ErrLog(<< "RRDecorator::rollbackMessage: mAddedRecordRoute=" << mAddedRecordRoute << " is < 0, logic error, resetting to 0");
259 mAddedRecordRoute = 0;
260 }
261
262 while (mAddedRecordRoute > 0 && !routes->empty())
263 {
264 routes->pop_front();
265 --mAddedRecordRoute;
266 }
267
268 if (mAlreadySingleRecordRouted && !routes->empty())
269 {
270 static ExtensionParameter p_drr("drr");
271 routes->front().uri().remove(p_drr);
272 }
273}
274
277{
278 return new RRDecorator(*this);
279}
280
281} // of namespace repro
#define DebugLog(args_)
Definition Logger.hxx:128
#define InfoLog(args_)
Definition Logger.hxx:131
#define ErrLog(args_)
Definition Logger.hxx:137
#define resip_assert(x)
This file needs to work for both C and C++ code.
const resip::NameAddr & getRecordRoute(unsigned int transportKey, bool *transportSpecific=0) const
Definition Proxy.cxx:664
static resip::Data FlowTokenSalt
Definition Proxy.hxx:61
bool compressionEnabled() const
Definition Proxy.cxx:685
virtual MessageDecorator * clone() const
virtual void decorateMessage(resip::SipMessage &msg, const resip::Tuple &source, const resip::Tuple &destination, const resip::Data &sigcompId)
virtual void rollbackMessage(resip::SipMessage &msg)
An alternative to std::string, encapsulates an arbitrary buffer of bytes.
Definition Data.hxx:90
bool empty() const noexcept
Checks whether the Data is empty.
Definition Data.hxx:591
static void massageRoute(const SipMessage &request, NameAddr &route)
Definition Helper.cxx:1719
static bool getRRTokenHackEnabled()
Represents the "name-addr" and the "addr-spec" elements in the RFC 3261 grammar.
Definition NameAddr.hxx:19
void pop_front()
if mParsers vector is not empty, erase the first element
Represents a SIP message.
Represents a network address.
Definition Tuple.hxx:59
IpVersion ipVersion() const
Returns V4 or V6 as appropriate.
Definition Tuple.cxx:537
bool onlyUseExistingConnection
Definition Tuple.hxx:192
static const Data & toDataLower(TransportType type)
Definition Tuple.cxx:933
static void writeBinaryToken(const Tuple &tuple, Data &container, const Data &salt=Data::Empty)
Definition Tuple.cxx:266
TransportType getType() const
Definition Tuple.hxx:122
static Data inet_ntop(const Tuple &tuple)
Converts the binary socket address to presentation format, via the DnsUtil::inet_ntop() method.
Definition Tuple.cxx:939
TransportKey mTransportKey
Definition Tuple.hxx:190
Data & scheme()
Definition Uri.hxx:143
Data & host()
Definition Uri.hxx:40
This Class is used to implement a primitive form of RPC using loose XML formatting.
RequestLineType h_RequestLine
Definition Headers.cxx:347
void list()
Definition userAdmin.cxx:66