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

Contents of /main/reTurn/UdpServer.cxx

Parent Directory Parent Directory | Revision Log Revision Log


Revision 10481 - (show annotations) (download)
Thu Sep 12 07:59:36 2013 UTC (6 years, 2 months ago) by dpocock
File MIME type: text/plain
File size: 9465 byte(s)
reTurn: revert commits 10472 and 10473, now on branch b-reTurn-async
1 #include "UdpServer.hxx"
2 #include "StunMessage.hxx"
3 #include <boost/bind.hpp>
4 #include <rutil/WinLeakCheck.hxx>
5 #include <rutil/Logger.hxx>
6 #include "ReTurnSubsystem.hxx"
7
8 #define RESIPROCATE_SUBSYSTEM ReTurnSubsystem::RETURN
9
10 using namespace std;
11 using namespace resip;
12
13 namespace reTurn {
14
15 UdpServer::UdpServer(asio::io_service& ioService, RequestHandler& requestHandler, const asio::ip::address& address, unsigned short port)
16 : AsyncUdpSocketBase(ioService),
17 mRequestHandler(requestHandler),
18 mAlternatePortUdpServer(0),
19 mAlternateIpUdpServer(0),
20 mAlternateIpPortUdpServer(0)
21 {
22 asio::error_code ec = bind(address, port);
23 if(ec)
24 {
25 ErrLog(<< "Unable to start UdpServer listening on " << address.to_string() << ":" << port << ", error=" << ec.value() << " - " << ec.message());
26 throw asio::system_error(ec);
27 }
28 else
29 {
30 InfoLog(<< "UdpServer started. Listening on " << address.to_string() << ":" << port);
31 }
32 }
33
34 UdpServer::~UdpServer()
35 {
36 ResponseMap::iterator it = mResponseMap.begin();
37 for(;it != mResponseMap.end(); it++)
38 {
39 delete it->second;
40 }
41 mResponseMap.clear();
42 }
43
44 void
45 UdpServer::start()
46 {
47 asio::error_code ec;
48 mLocalAddress = mSocket.local_endpoint(ec).address();
49 mLocalPort = mSocket.local_endpoint(ec).port();
50 doReceive();
51 }
52
53 void
54 UdpServer::setAlternateUdpServers(UdpServer* alternatePort, UdpServer* alternateIp, UdpServer* alternateIpPort)
55 {
56 assert(!mAlternatePortUdpServer);
57 assert(!mAlternateIpUdpServer);
58 assert(!mAlternateIpPortUdpServer);
59 mAlternatePortUdpServer = alternatePort;
60 mAlternateIpUdpServer = alternateIp;
61 mAlternateIpPortUdpServer = alternateIpPort;
62 }
63
64 bool
65 UdpServer::isRFC3489BackwardsCompatServer()
66 {
67 return mAlternatePortUdpServer != 0; // Just check that any of the alternate servers is populated - if so, we are running in back compat mode
68 }
69
70 asio::ip::udp::socket&
71 UdpServer::getSocket()
72 {
73 return mSocket;
74 }
75
76 void
77 UdpServer::onReceiveSuccess(const asio::ip::address& address, unsigned short port, boost::shared_ptr<DataBuffer>& data)
78 {
79 if (data->size() > 4)
80 {
81 /*
82 std::cout << "Read " << bytesTransferred << " bytes from udp socket (" << address.to_string() << ":" << port << "): " << std::endl;
83 cout << std::hex;
84 for(int i = 0; i < data->size(); i++)
85 {
86 std::cout << (char)(*data)[i] << "(" << int((*data)[i]) << ") ";
87 }
88 std::cout << std::dec << std::endl;
89 */
90
91 if(((*data)[0] & 0xC0) == 0) // Stun/Turn Messages always have bits 0 and 1 as 00 - otherwise ChannelData message
92 {
93 // Try to parse stun message
94 StunMessage request(StunTuple(StunTuple::UDP, mLocalAddress, mLocalPort),
95 StunTuple(StunTuple::UDP, address, port),
96 (char*)&(*data)[0], data->size());
97 if(request.isValid())
98 {
99 StunMessage* response;
100 UdpServer* responseUdpServer;
101 ResponseMap::iterator it = mResponseMap.find(request.mHeader.magicCookieAndTid);
102 if(it == mResponseMap.end())
103 {
104 response = new StunMessage;
105 RequestHandler::ProcessResult result = mRequestHandler.processStunMessage(this, mTurnAllocationManager, request, *response, isRFC3489BackwardsCompatServer());
106
107 switch(result)
108 {
109 case RequestHandler::NoResponseToSend:
110 // No response to send - just receive next message
111 delete response;
112 doReceive();
113 return;
114 case RequestHandler::RespondFromAlternatePort:
115 responseUdpServer = mAlternatePortUdpServer;
116 break;
117 case RequestHandler::RespondFromAlternateIp:
118 responseUdpServer = mAlternateIpUdpServer;
119 break;
120 case RequestHandler::RespondFromAlternateIpPort:
121 responseUdpServer = mAlternateIpPortUdpServer;
122 break;
123 case RequestHandler::RespondFromReceiving:
124 default:
125 responseUdpServer = this;
126 break;
127 }
128
129 // Store response in Map - to be resent if a retranmission is received
130 mResponseMap[response->mHeader.magicCookieAndTid] = new ResponseEntry(this, responseUdpServer, response);
131 }
132 else
133 {
134 InfoLog(<< "UdpServer: received retransmission of request with tid: " << request.mHeader.magicCookieAndTid);
135 response = it->second->mResponseMessage;
136 responseUdpServer = it->second->mResponseUdpServer;
137 }
138
139 #define RESPONSE_BUFFER_SIZE 1024
140 boost::shared_ptr<DataBuffer> buffer = allocateBuffer(RESPONSE_BUFFER_SIZE);
141 unsigned int responseSize;
142 responseSize = response->stunEncodeMessage((char*)buffer->data(), RESPONSE_BUFFER_SIZE);
143 buffer->truncate(responseSize); // set size to real size
144
145 responseUdpServer->doSend(response->mRemoteTuple, buffer);
146 }
147 }
148 else // ChannelData message
149 {
150 unsigned short channelNumber;
151 memcpy(&channelNumber, &(*data)[0], 2);
152 channelNumber = ntohs(channelNumber);
153
154 unsigned short dataLen;
155 memcpy(&dataLen, &(*data)[2], 2);
156 dataLen = ntohs(dataLen);
157
158 // Check if the UDP datagram size is too short to contain the claimed length of the ChannelData message, then discard
159 if(data->size() < (unsigned int)(dataLen + 4))
160 {
161 WarningLog(<< "ChannelData message size=" << dataLen+4 << " too larger for UDP packet size=" << data->size() <<". Dropping.");
162 }
163 else
164 {
165 mRequestHandler.processTurnData(mTurnAllocationManager,
166 channelNumber,
167 StunTuple(StunTuple::UDP, mLocalAddress, mLocalPort),
168 StunTuple(StunTuple::UDP, address, port),
169 data);
170 }
171 }
172 }
173 else
174 {
175 WarningLog(<< "Not enough data for stun message or framed message. Dropping.");
176 }
177
178 doReceive();
179 }
180
181 void
182 UdpServer::onReceiveFailure(const asio::error_code& e)
183 {
184 if(e != asio::error::operation_aborted)
185 {
186 InfoLog(<< "UdpServer::onReceiveFailure: " << e.value() << "-" << e.message());
187
188 doReceive();
189 }
190 }
191
192 void
193 UdpServer::onSendSuccess()
194 {
195 }
196
197 void
198 UdpServer::onSendFailure(const asio::error_code& error)
199 {
200 if(error != asio::error::operation_aborted)
201 {
202 InfoLog(<< "UdpServer::onSendFailure: " << error.value() << "-" << error.message());
203 }
204 }
205
206 UdpServer::ResponseEntry::ResponseEntry(UdpServer* requestUdpServer, UdpServer* responseUdpServer, StunMessage* responseMessage) :
207 mResponseUdpServer(responseUdpServer),
208 mResponseMessage(responseMessage),
209 mCleanupTimer(requestUdpServer->mIOService)
210 {
211 // start timer
212 mCleanupTimer.expires_from_now(boost::posix_time::seconds(10)); // Transaction Responses are cached for 10 seconds
213 mCleanupTimer.async_wait(boost::bind(&UdpServer::cleanupResponseMap, requestUdpServer, asio::placeholders::error, responseMessage->mHeader.magicCookieAndTid));
214 }
215
216 UdpServer::ResponseEntry::~ResponseEntry()
217 {
218 delete mResponseMessage;
219 }
220
221 void
222 UdpServer::cleanupResponseMap(const asio::error_code& e, UInt128 tid)
223 {
224 ResponseMap::iterator it = mResponseMap.find(tid);
225 if(it != mResponseMap.end())
226 {
227 DebugLog(<< "UdpServer::cleanupResponseMap - removing transaction id=" << tid);
228 delete it->second;
229 mResponseMap.erase(it);
230 }
231 }
232
233 }
234
235
236 /* ====================================================================
237
238 Copyright (c) 2007-2008, Plantronics, Inc.
239 All rights reserved.
240
241 Redistribution and use in source and binary forms, with or without
242 modification, are permitted provided that the following conditions are
243 met:
244
245 1. Redistributions of source code must retain the above copyright
246 notice, this list of conditions and the following disclaimer.
247
248 2. Redistributions in binary form must reproduce the above copyright
249 notice, this list of conditions and the following disclaimer in the
250 documentation and/or other materials provided with the distribution.
251
252 3. Neither the name of Plantronics nor the names of its contributors
253 may be used to endorse or promote products derived from this
254 software without specific prior written permission.
255
256 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
257 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
258 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
259 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
260 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
261 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
262 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
263 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
264 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
265 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
266 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
267
268 ==================================================================== */

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