1 /**************************************************************************
3 * Copyright 2013-2014 RAD Game Tools and Valve Software
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 **************************************************************************/
31 #include "../common/radlogging.h"
35 using namespace ports;
37 PortManager::PortManager(int portStart, int portIncrement, int portEnd)
39 m_fInitialized = false;
41 m_portStart = portStart;
42 m_portIncrement = portIncrement;
45 m_numPorts = (m_portEnd - m_portStart) / m_portIncrement;
50 PortManager::~PortManager()
52 if (false == m_fInitialized)
58 (void)pthread_mutex_destroy(&m_portList_mutex); // Nothing to look at
62 PortManager::FInitialize(int portReserved)
66 if ((portReserved < m_portStart) || (portReserved > m_portEnd))
68 syslog(RAD_CRITICAL, "PortMgr::Finitialize(%d) - portReserved out of range (%d - %d).\n", portReserved, m_portStart, m_portEnd);
72 fReturn = FInitialize();
77 // Now reserve this particular port in the list
79 m_rgPortUsage[portReserved - m_portStart] = true;
86 PortManager::FInitialize()
89 pthread_mutexattr_t mAttr;
93 goto out; // already initialized
96 // Need to allocate the array of ports
101 m_rgPortUsage = (bool *)malloc(1 + m_numPorts);
102 if (NULL == m_rgPortUsage)
104 syslog(RAD_CRITICAL, "Unable to allocate memory for PortMgr array.\n");
108 // Initialize to unused (false)
109 for (int iPort = 0; iPort < m_numPorts; iPort++)
110 m_rgPortUsage[iPort] = false;
112 // Initialize mutex for assigning new ports
113 // setup recursive mutex for mutex attribute - this is most like, in behavior, to Windows critical sections
115 // PTHREAD_MUTEX_RECURSIVE_NP means that the mutex can be used recursively.
117 The pthread_mutexattr_settype() function shall fail if:
118 EINVAL The value type is invalid.
120 rc = pthread_mutexattr_init(&mAttr);
123 syslog(RAD_CRITICAL, "Error on pthread_mutexattr_init(return code = %x)\nTerminating...\n", rc);
127 rc = pthread_mutexattr_settype(&mAttr, PTHREAD_MUTEX_RECURSIVE_NP);
130 syslog(RAD_CRITICAL, "Error on pthread_mutexattr_settype(return code = %x)\nTerminating...\n", rc);
133 // Use the mutex attribute to create the mutex
135 The pthread_mutex_init() function shall fail if:
136 EAGAIN The system lacked the necessary resources (other than memory) to initialize another mutex.
137 ENOMEM Insufficient memory exists to initialize the mutex.
138 EPERM The caller does not have the privilege to perform the operation.
140 The pthread_mutex_init() function may fail if:
141 EBUSY The implementation has detected an attempt to reinitialize the object referenced by mutex, a previously initialized, but not yet destroyed, mutex.
142 EINVAL The value specified by attr is invalid.
144 rc = pthread_mutex_init(&m_portList_mutex, &mAttr);
147 syslog(RAD_CRITICAL, "Error on port manager pthread_mutex_init(return code = %x)\nTerminating...\n", rc);
150 m_fInitialized = true;
154 return m_fInitialized;
157 int PortManager::GetNextAvailablePort()
163 if (false == m_fInitialized)
166 ec = pthread_mutex_lock(&m_portList_mutex);
167 for (int i = 0; i < m_numPorts; i++)
169 if (false == m_rgPortUsage[i])
172 freePort = (i * m_portIncrement) + m_portStart;
173 m_rgPortUsage[i] = true;
177 pthread_mutex_unlock(&m_portList_mutex);
182 int PortManager::ReleasePort(int port)
184 int portIndex = (port - m_portStart) / m_portIncrement;
188 if (false == m_fInitialized)
191 if (portIndex < 0 || portIndex >= m_numPorts)
193 syslog(RAD_WARN, "Attempting to release port number out of range(%d)\n", port);
197 ec = pthread_mutex_lock(&m_portList_mutex);
199 m_rgPortUsage[portIndex] = false;
201 pthread_mutex_unlock(&m_portList_mutex);