reSIProcate
SIP stack, Dialog Usage Manager and related libraries
Loading...
Searching...
No Matches
RTPPortManager.cxx
Go to the documentation of this file.
1
2#include <rutil/Logger.hxx>
3#include <rutil/ResipAssert.h>
4#include <rutil/Subsystem.hxx>
5#include <rutil/DnsUtil.hxx>
6#include <rutil/Socket.hxx>
7#include "RTPPortManager.hxx"
8
9#include <cstring>
10
11using namespace resip;
12using namespace std;
13
14#define RESIPROCATE_SUBSYSTEM resip::Subsystem::MEDIA
15
16// We are only handing out even RTP ports; the next higher odd port is used for RTCP
17RTPPortManager::RTPPortManager(int portRangeMin, int portRangeMax)
18 : mPortRangeMin(portRangeMin),
19 mPortRangeMax(portRangeMax),
20 mTotalPortPairs(0) // set below
21{
22 // Ensure we start on an even port
23 if(mPortRangeMin & 0x1)
24 {
25 mPortRangeMin++;
26 }
27 // Ensure we end on an even port, even though mPortMax+1
28 // is considered valid for RTCP stream of mPortMax port
29 if(mPortRangeMax & 0x1)
30 {
31 mPortRangeMax--;
32 }
33 resip_assert(mPortRangeMax >= mPortRangeMin);
34 for(unsigned int i = mPortRangeMin; i <= mPortRangeMax;)
35 {
36 mRTPPortFreeList.push_back(i);
37 i=i+2; // only add even ports
38 }
39 mTotalPortPairs = (unsigned int)mRTPPortFreeList.size();
40 StackLog(<< "RTPPortManager: min even port=" << mPortRangeMin << ", max even port=" << mPortRangeMax);
41}
42
43unsigned int
45{
46 unsigned int port = 0;
47 if(!mRTPPortFreeList.empty())
48 {
49 port = mRTPPortFreeList.front();
50 mRTPPortFreeList.pop_front();
51 }
52 StackLog(<<"allocateRTPPort: port == " << port);
53 return port;
54}
55
56// Whether a UDP socket can be bound to address and port, without sharing it with another socket:
57// on Windows, SO_EXCLUSIVEADDRUSE, so it's not given a port another socket has bound with
58// SO_REUSEADDR; elsewhere, no SO_REUSEADDR. Only the port being in use (or reserved: access
59// denied) makes it false. If address isn't an IP address, no socket can be created, or the bind
60// fails for another reason - eg. address isn't one of this host's - there's nothing to say about
61// the port: true, and the media stream's socket reports the error.
62static bool
63canBindUdp(const Data& address, unsigned int port)
64{
65 sockaddr_storage storage;
66 memset(&storage, 0, sizeof(storage));
67 socklen_t length = 0;
68 if(DnsUtil::isIpV4Address(address))
69 {
70 sockaddr_in& v4 = reinterpret_cast<sockaddr_in&>(storage);
71 v4.sin_family = AF_INET;
72 v4.sin_port = htons((unsigned short)port);
73 DnsUtil::inet_pton(address, v4.sin_addr);
74 length = sizeof(v4);
75 }
76#ifdef USE_IPV6
77 else if(DnsUtil::isIpV6Address(address))
78 {
79 sockaddr_in6& v6 = reinterpret_cast<sockaddr_in6&>(storage);
80 v6.sin6_family = AF_INET6;
81 v6.sin6_port = htons((unsigned short)port);
82 DnsUtil::inet_pton(address, v6.sin6_addr);
83 length = sizeof(v6);
84 }
85#endif
86 else
87 {
88 return true;
89 }
90
91 Socket fd = ::socket(storage.ss_family, SOCK_DGRAM, IPPROTO_UDP);
92 if(fd == INVALID_SOCKET)
93 {
94 return true;
95 }
96#ifdef _WIN32
97 BOOL on = TRUE;
98 ::setsockopt(fd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (const char*)&on, sizeof(on));
99#elif defined(USE_IPV6) && defined(__linux__)
100 if(storage.ss_family == AF_INET6)
101 {
102 int on = 1;
103 ::setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
104 }
105#endif
106 bool usable = true;
107 if(::bind(fd, reinterpret_cast<sockaddr*>(&storage), length) != 0)
108 {
109 const int e = getErrno();
110#ifdef _WIN32
111 usable = !(e == EADDRINUSE || e == WSAEACCES);
112#else
113 usable = !(e == EADDRINUSE || e == EACCES);
114#endif
115 }
116 closeSocket(fd);
117 return usable;
118}
119
120unsigned int
122{
123 for(size_t tries = mRTPPortFreeList.size(); tries > 0; --tries) // each free port once
124 {
125 const unsigned int port = allocateRTPPort();
126 if(canBindUdp(address, port) && canBindUdp(address, port + 1))
127 {
128 return port;
129 }
130 InfoLog(<< "allocateRTPPort: RTP port " << port << ", or the RTCP port after it, can't be bound on " << address
131 << " (eg. another socket has it): trying the next port");
132 mRTPPortFreeList.push_back(port);
133 }
134 WarningLog(<< "allocateRTPPort: no free RTP port can be bound on " << address);
135 return 0;
136}
137
138void
140{
141 StackLog(<<"freeRTPPort: port == " << port);
142 resip_assert(port >= mPortRangeMin && port <= mPortRangeMax);
143 resip_assert((port & 0x1) == 0);
144 mRTPPortFreeList.push_back(port);
145}
146
147
148/* ====================================================================
149
150 Copyright (c) 2010-2026, SIP Spectrum, Inc. http://www.sipspectrum.com
151 Copyright (c) 2014 Daniel Pocock http://danielpocock.com
152 Copyright (c) 2007-2008, Plantronics, Inc.
153 All rights reserved.
154
155 Redistribution and use in source and binary forms, with or without
156 modification, are permitted provided that the following conditions are
157 met:
158
159 1. Redistributions of source code must retain the above copyright
160 notice, this list of conditions and the following disclaimer.
161
162 2. Redistributions in binary form must reproduce the above copyright
163 notice, this list of conditions and the following disclaimer in the
164 documentation and/or other materials provided with the distribution.
165
166 3. Neither the name of Plantronics nor the names of its contributors
167 may be used to endorse or promote products derived from this
168 software without specific prior written permission.
169
170 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
171 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
172 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
173 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
174 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
175 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
176 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
177 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
178 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
179 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
180 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
181
182 ==================================================================== */
#define StackLog(args_)
Definition Logger.hxx:125
#define InfoLog(args_)
Definition Logger.hxx:131
#define WarningLog(args_)
Definition Logger.hxx:134
static bool canBindUdp(const Data &address, unsigned int port)
#define resip_assert(x)
This file needs to work for both C and C++ code.
Handles cross-platform sockets compatibility.
#define INVALID_SOCKET
Definition Socket.hxx:95
int Socket
An alternative to std::string, encapsulates an arbitrary buffer of bytes.
Definition Data.hxx:90
static bool isIpV6Address(const Data &ipAddress)
Definition DnsUtil.cxx:386
static int inet_pton(const Data &printableIp, struct in_addr &dst)
Convert from the presentation format of the IPv4 address to struct in_addr.
Definition DnsUtil.cxx:275
static bool isIpV4Address(const Data &ipAddress)
Definition DnsUtil.cxx:290
unsigned int allocateRTPPort()
Allocates an RTP port (even - the RTCP port is the one after it). Returns 0 if none is free.
RTPPortManager(int portRangeMin=17000, int portRangeMax=18000)
void freeRTPPort(unsigned int port)
dcm! – add UnusedChecking(_enum) below;
int closeSocket(Socket fd)
Definition Socket.cxx:134
int getErrno()
Definition Socket.hxx:97