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