/[resiprocate]/main/reTurn/TurnAllocation.cxx
ViewVC logotype

Contents of /main/reTurn/TurnAllocation.cxx

Parent Directory Parent Directory | Revision Log Revision Log


Revision 10138 - (show annotations) (download)
Sun Apr 28 19:58:33 2013 UTC (6 years, 6 months ago) by sgodin
File MIME type: text/plain
File size: 13816 byte(s)
-track allocations per connection - reduces map sizes and lookups when TCP/TLS 
 client connections are used
1 #include <boost/bind.hpp>
2
3 #include "TurnAllocation.hxx"
4 #include "TurnAllocationManager.hxx"
5 #include "TurnManager.hxx"
6 #include "TurnPermission.hxx"
7 #include "AsyncSocketBase.hxx"
8 #include "UdpRelayServer.hxx"
9 #include "RemotePeer.hxx"
10 #include <rutil/WinLeakCheck.hxx>
11 #include <rutil/Logger.hxx>
12 #include "ReTurnSubsystem.hxx"
13
14 #define RESIPROCATE_SUBSYSTEM ReTurnSubsystem::RETURN
15
16 using namespace std;
17 using namespace resip;
18
19 #define TURN_PERMISSION_LIFETIME_SECONDS 300 // 5 minuntes
20 //#define TURN_PERMISSION_LIFETIME_SECONDS 30 // TESTING only
21
22 namespace reTurn {
23
24 TurnAllocation::TurnAllocation(TurnManager& turnManager,
25 TurnAllocationManager& turnAllocationManager,
26 AsyncSocketBase* localTurnSocket,
27 const StunTuple& clientLocalTuple,
28 const StunTuple& clientRemoteTuple,
29 const StunAuth& clientAuth,
30 const StunTuple& requestedTuple,
31 unsigned int lifetime) :
32 mKey(clientLocalTuple, clientRemoteTuple),
33 mClientAuth(clientAuth),
34 mRequestedTuple(requestedTuple),
35 mTurnManager(turnManager),
36 mTurnAllocationManager(turnAllocationManager),
37 mAllocationTimer(turnManager.getIOService()),
38 mLocalTurnSocket(localTurnSocket),
39 mBadChannelErrorLogged(false),
40 mNoPermissionToPeerLogged(false),
41 mNoPermissionFromPeerLogged(false)
42 {
43 InfoLog(<< "TurnAllocation created: clientLocal=" << clientLocalTuple << " clientRemote=" <<
44 clientRemoteTuple << " allocation=" << requestedTuple << " lifetime=" << lifetime);
45
46 refresh(lifetime);
47
48 // Register for Turn Transport onDestroyed notification
49 mLocalTurnSocket->registerAsyncSocketBaseHandler(this);
50 }
51
52 TurnAllocation::~TurnAllocation()
53 {
54 InfoLog(<< "TurnAllocation destroyed: clientLocal=" << mKey.getClientLocalTuple() << " clientRemote=" <<
55 mKey.getClientRemoteTuple() << " allocation=" << mRequestedTuple);
56
57 stopRelay();
58
59 // Deallocate Port
60 mTurnManager.deallocatePort(mRequestedTuple.getTransportType(), mRequestedTuple.getPort());
61
62 // Cleanup Permission Memory
63 TurnPermissionMap::iterator it;
64 for(it = mTurnPermissionMap.begin(); it != mTurnPermissionMap.end(); it++)
65 {
66 delete it->second;
67 }
68
69 // Unregister for TurnTransport notifications
70 if(mLocalTurnSocket)
71 {
72 mLocalTurnSocket->registerAsyncSocketBaseHandler(0);
73 }
74 }
75
76 bool
77 TurnAllocation::startRelay()
78 {
79 if(mRequestedTuple.getTransportType() == StunTuple::UDP)
80 {
81 mUdpRelayServer.reset(new UdpRelayServer(mTurnManager.getIOService(), *this));
82 if(!mUdpRelayServer->startReceiving())
83 {
84 stopRelay(); // Ensure allocation timer is stopped
85 return false;
86 }
87 return true;
88 }
89 else
90 {
91 ErrLog(<< "Only UDP relay's are currently implemented!");
92 assert(false);
93 stopRelay(); // Ensure allocation timer is stopped
94 return false;
95 }
96 }
97
98 void
99 TurnAllocation::stopRelay()
100 {
101 // Stop and detach Relay Server
102 if(mUdpRelayServer.get())
103 {
104 mUdpRelayServer->stop();
105 mUdpRelayServer.reset();
106 }
107 mAllocationTimer.cancel();
108 }
109
110 void
111 TurnAllocation::refresh(unsigned int lifetime) // update expiration time
112 {
113 InfoLog(<< "TurnAllocation refreshed: clientLocal=" << mKey.getClientLocalTuple() << " clientRemote=" <<
114 mKey.getClientRemoteTuple() << " allocation=" << mRequestedTuple << " lifetime=" << lifetime);
115
116 mExpires = time(0) + lifetime;
117
118 // start timer
119 mAllocationTimer.expires_from_now(boost::posix_time::seconds(lifetime));
120 mAllocationTimer.async_wait(boost::bind(&TurnAllocationManager::allocationExpired, &mTurnAllocationManager, asio::placeholders::error, mKey));
121 }
122
123 bool
124 TurnAllocation::existsPermission(const asio::ip::address& address)
125 {
126 TurnPermissionMap::iterator it = mTurnPermissionMap.find(address);
127 if(it != mTurnPermissionMap.end())
128 {
129 if(it->second->isExpired()) // check if expired
130 {
131 InfoLog(<< "TurnAllocation has expired permission: clientLocal=" << mKey.getClientLocalTuple() << " clientRemote=" <<
132 mKey.getClientRemoteTuple() << " allocation=" << mRequestedTuple << " exipred address=" << it->first.to_string());
133 delete it->second;
134 mTurnPermissionMap.erase(it);
135 return false;
136 }
137 return true;
138 }
139 return false;
140 }
141
142 void
143 TurnAllocation::refreshPermission(const asio::ip::address& address)
144 {
145 TurnPermissionMap::iterator it = mTurnPermissionMap.find(address);
146 TurnPermission* turnPermission = 0;
147 if(it != mTurnPermissionMap.end())
148 {
149 turnPermission = it->second;
150 }
151 if(!turnPermission) // create if doesn't exist
152 {
153 mTurnPermissionMap[address] = new TurnPermission(address, TURN_PERMISSION_LIFETIME_SECONDS);
154 InfoLog(<< "Permission for " << address.to_string() << " created: clientLocal=" << mKey.getClientLocalTuple() << " clientRemote=" <<
155 mKey.getClientRemoteTuple() << " allocation=" << mRequestedTuple);
156 }
157 else
158 {
159 turnPermission->refresh();
160 InfoLog(<< "Permission for " << address.to_string() << " refreshed: clientLocal=" << mKey.getClientLocalTuple() << " clientRemote=" <<
161 mKey.getClientRemoteTuple() << " allocation=" << mRequestedTuple);
162 }
163 }
164
165 void
166 TurnAllocation::onSocketDestroyed()
167 {
168 mTurnAllocationManager.removeTurnAllocation(mKey); // will delete this
169 }
170
171 void
172 TurnAllocation::sendDataToPeer(unsigned short channelNumber, boost::shared_ptr<DataBuffer>& data, bool isFramed)
173 {
174 RemotePeer* remotePeer = mChannelManager.findRemotePeerByChannel(channelNumber);
175 if(remotePeer)
176 {
177 // channel found - send Data
178 sendDataToPeer(remotePeer->getPeerTuple(), data, isFramed);
179 }
180 else
181 {
182 // Log at Warning level first time only
183 if(mBadChannelErrorLogged)
184 {
185 DebugLog(<< "sendDataToPeer bad channel number - discarding data: clientLocal=" << mKey.getClientLocalTuple() << " clientRemote=" <<
186 mKey.getClientRemoteTuple() << " allocation=" << mRequestedTuple << " channelNumber=" << channelNumber);
187 }
188 else
189 {
190 mBadChannelErrorLogged = true;
191 WarningLog(<< "sendDataToPeer bad channel number - discarding data: clientLocal=" << mKey.getClientLocalTuple() << " clientRemote=" <<
192 mKey.getClientRemoteTuple() << " allocation=" << mRequestedTuple << " channelNumber=" << channelNumber);
193 }
194 }
195 }
196
197 void
198 TurnAllocation::sendDataToPeer(const StunTuple& peerAddress, boost::shared_ptr<DataBuffer>& data, bool isFramed)
199 {
200 DebugLog(<< "TurnAllocation sendDataToPeer: clientLocal=" << mKey.getClientLocalTuple() << " clientRemote=" <<
201 mKey.getClientRemoteTuple() << " allocation=" << mRequestedTuple << " peerAddress=" << peerAddress);
202
203 // Ensure permission exists
204 if(!existsPermission(peerAddress.getAddress()))
205 {
206 // Log at Warning level first time only
207 if(mNoPermissionToPeerLogged)
208 {
209 DebugLog(<< "Turn send indication for destination=" << peerAddress.getAddress() << ", but no permission installed. Dropping.");
210 }
211 else
212 {
213 mNoPermissionToPeerLogged = true;
214 WarningLog(<< "Turn send indication for destination=" << peerAddress.getAddress() << ", but no permission installed. Dropping.");
215 }
216 return;
217 }
218 if(mRequestedTuple.getTransportType() == StunTuple::UDP)
219 {
220 assert(mUdpRelayServer);
221 mUdpRelayServer->doSend(peerAddress, data, isFramed ? 4 /* bufferStartPos is 4 so that framing is skipped */ : 0);
222 }
223 else
224 {
225 if(data->size() <=4)
226 {
227 WarningLog(<< "Turn send indication with no data for non-UDP transport. Dropping.");
228 return;
229 }
230 // !SLG! TODO - implement TCP relays
231 assert(false);
232 }
233 }
234
235 void
236 TurnAllocation::sendDataToClient(const StunTuple& peerAddress, boost::shared_ptr<DataBuffer>& data)
237 {
238 // See if a permission exists
239 if(!existsPermission(peerAddress.getAddress()))
240 {
241 // Log at Warning level first time only
242 if(mNoPermissionFromPeerLogged)
243 {
244 DebugLog(<< "Data received from peer=" << peerAddress << ", but no permission installed. Dropping.");
245 }
246 else
247 {
248 mNoPermissionFromPeerLogged = true;
249 WarningLog(<< "Data received from peer=" << peerAddress << ", but no permission installed. Dropping.");
250 }
251 return;
252 }
253 // See if a channel binding exists - if so, use it
254 RemotePeer* remotePeer = mChannelManager.findRemotePeerByPeerAddress(peerAddress);
255 if(remotePeer)
256 {
257 // send data to local client
258 mLocalTurnSocket->doSend(mKey.getClientRemoteTuple(), remotePeer->getChannel(), data);
259
260 DebugLog(<< "TurnAllocation sendDataToClient: clientLocal=" << mKey.getClientLocalTuple() << " clientRemote=" <<
261 mKey.getClientRemoteTuple() << " allocation=" << mRequestedTuple << " peer=" << peerAddress <<
262 " channelNumber=" << (int)remotePeer->getChannel());
263 }
264 else
265 {
266 // No Channel Binding - use DataInd
267 StunMessage dataInd;
268 dataInd.createHeader(StunMessage::StunClassIndication, StunMessage::TurnDataMethod);
269 dataInd.mCntTurnXorPeerAddress = 1;
270 StunMessage::setStunAtrAddressFromTuple(dataInd.mTurnXorPeerAddress[0], peerAddress);
271 dataInd.setTurnData(data->data(), (unsigned int)data->size());
272
273 // send DataInd to local client
274 unsigned int bufferSize = (unsigned int)data->size() + 8 /* Stun Header */ + 36 /* Remote Address (v6) */ + 8 /* TurnData Header + potential pad */;
275 boost::shared_ptr<DataBuffer> buffer = AsyncSocketBase::allocateBuffer(bufferSize);
276 unsigned int size = dataInd.stunEncodeMessage((char*)buffer->data(), bufferSize);
277 buffer->truncate(size); // Set size to proper size
278 mLocalTurnSocket->doSend(mKey.getClientRemoteTuple(), buffer);
279
280 DebugLog(<< "TurnAllocation sendDataToClient: clientLocal=" << mKey.getClientLocalTuple() << " clientRemote=" <<
281 mKey.getClientRemoteTuple() << " allocation=" << mRequestedTuple << " peer=" << peerAddress <<
282 " using DataInd.");
283 }
284 }
285
286 bool
287 TurnAllocation::addChannelBinding(const StunTuple& peerAddress, unsigned short channelNumber)
288 {
289 RemotePeer* remotePeer = mChannelManager.findRemotePeerByChannel(channelNumber);
290 if(remotePeer)
291 {
292 if(remotePeer->getPeerTuple() != peerAddress)
293 {
294 WarningLog(<< "addChannelBinding failed since channel is already in use: clientLocal=" << mKey.getClientLocalTuple() << " clientRemote=" <<
295 mKey.getClientRemoteTuple() << " allocation=" << mRequestedTuple << " channelNumber=" << channelNumber << " peerAddress=" << peerAddress);
296 return false;
297 }
298 // refresh channel binding lifetime
299 remotePeer->refresh();
300
301 InfoLog(<< "Channel " << channelNumber << " binding to " << peerAddress << " refreshed: clientLocal=" << mKey.getClientLocalTuple() << " clientRemote=" <<
302 mKey.getClientRemoteTuple() << " allocation=" << mRequestedTuple);
303 }
304 else
305 {
306 remotePeer = mChannelManager.findRemotePeerByPeerAddress(peerAddress);
307 if(remotePeer)
308 {
309 WarningLog(<< "addChannelBinding failed since peerAddress is alredy in use: clientLocal=" << mKey.getClientLocalTuple() << " clientRemote=" <<
310 mKey.getClientRemoteTuple() << " allocation=" << mRequestedTuple << " channelNumber=" << channelNumber << " peerAddress=" << peerAddress);
311 return false;
312 }
313 mChannelManager.createChannelBinding(peerAddress, channelNumber);
314
315 InfoLog(<< "Channel " << channelNumber << " binding to " << peerAddress << " created: clientLocal=" << mKey.getClientLocalTuple() << " clientRemote=" <<
316 mKey.getClientRemoteTuple() << " allocation=" << mRequestedTuple);
317 }
318
319 // Add or refresh permission
320 refreshPermission(peerAddress.getAddress());
321
322 return true;
323 }
324
325
326 } // namespace
327
328
329 /* ====================================================================
330
331 Copyright (c) 2007-2008, Plantronics, Inc.
332 All rights reserved.
333
334 Redistribution and use in source and binary forms, with or without
335 modification, are permitted provided that the following conditions are
336 met:
337
338 1. Redistributions of source code must retain the above copyright
339 notice, this list of conditions and the following disclaimer.
340
341 2. Redistributions in binary form must reproduce the above copyright
342 notice, this list of conditions and the following disclaimer in the
343 documentation and/or other materials provided with the distribution.
344
345 3. Neither the name of Plantronics nor the names of its contributors
346 may be used to endorse or promote products derived from this
347 software without specific prior written permission.
348
349 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
350 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
351 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
352 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
353 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
354 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
355 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
356 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
357 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
358 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
359 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
360
361 ==================================================================== */

Properties

Name Value
svn:eol-style native
svn:mime-type text/plain

webmaster AT resiprocate DOT org
ViewVC Help
Powered by ViewVC 1.1.27