]> git.cworth.org Git - vogl/blob - src/common/portmgr.cpp
Initial vogl checkin
[vogl] / src / common / portmgr.cpp
1 /**************************************************************************
2  *
3  * Copyright 2013-2014 RAD Game Tools and Valve Software
4  * All Rights Reserved.
5  *
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:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
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
22  * THE SOFTWARE.
23  *
24  **************************************************************************/
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <unistd.h>
29 #include <errno.h>
30 #include <pthread.h>
31 #include "../common/radlogging.h"
32
33 #include "portmgr.h"
34
35 using namespace ports;
36
37 PortManager::PortManager(int portStart, int portIncrement, int portEnd)
38 {
39     m_fInitialized = false;
40
41     m_portStart = portStart;
42     m_portIncrement = portIncrement;
43     m_portEnd = portEnd;
44
45     m_numPorts = (m_portEnd - m_portStart) / m_portIncrement;
46
47     m_rgPortUsage = NULL;
48 }
49
50 PortManager::~PortManager()
51 {
52     if (false == m_fInitialized)
53         return;
54
55     if (m_rgPortUsage)
56         free(m_rgPortUsage);
57
58     (void)pthread_mutex_destroy(&m_portList_mutex); //  Nothing to look at
59 }
60
61 bool
62 PortManager::FInitialize(int portReserved)
63 {
64     bool fReturn = false;
65
66     if ((portReserved < m_portStart) || (portReserved > m_portEnd))
67     {
68         syslog(RAD_CRITICAL, "PortMgr::Finitialize(%d) - portReserved out of range (%d - %d).\n", portReserved, m_portStart, m_portEnd);
69         goto out;
70     }
71
72     fReturn = FInitialize();
73     if (false == fReturn)
74         goto out;
75
76     //
77     //  Now reserve this particular port in the list
78     //
79     m_rgPortUsage[portReserved - m_portStart] = true;
80
81 out:
82     return fReturn;
83 }
84
85 bool
86 PortManager::FInitialize()
87 {
88
89     pthread_mutexattr_t mAttr;
90     int rc = 0;
91
92     if (m_fInitialized)
93         goto out; // already initialized
94
95     //
96     //  Need to allocate the array of ports
97     //
98     if (m_rgPortUsage)
99         free(m_rgPortUsage);
100
101     m_rgPortUsage = (bool *)malloc(1 + m_numPorts);
102     if (NULL == m_rgPortUsage)
103     {
104         syslog(RAD_CRITICAL, "Unable to allocate memory for PortMgr array.\n");
105         goto out;
106     }
107
108     //  Initialize to unused (false)
109     for (int iPort = 0; iPort < m_numPorts; iPort++)
110         m_rgPortUsage[iPort] = false;
111
112     //  Initialize mutex for assigning new ports
113     // setup recursive mutex for mutex attribute - this is most like, in behavior, to Windows critical sections
114     //
115     //  PTHREAD_MUTEX_RECURSIVE_NP means that the mutex can be used recursively.
116     /*
117                         The pthread_mutexattr_settype() function shall fail if:
118                         EINVAL  The value type is invalid.
119         */
120     rc = pthread_mutexattr_init(&mAttr);
121     if (0 != rc)
122     {
123         syslog(RAD_CRITICAL, "Error on pthread_mutexattr_init(return code = %x)\nTerminating...\n", rc);
124         goto out;
125     }
126
127     rc = pthread_mutexattr_settype(&mAttr, PTHREAD_MUTEX_RECURSIVE_NP);
128     if (0 != rc)
129     {
130         syslog(RAD_CRITICAL, "Error on pthread_mutexattr_settype(return code = %x)\nTerminating...\n", rc);
131         goto out;
132     }
133     // Use the mutex attribute to create the mutex
134     /*
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.
139
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.
143         */
144     rc = pthread_mutex_init(&m_portList_mutex, &mAttr);
145     if (0 != rc)
146     {
147         syslog(RAD_CRITICAL, "Error on port manager pthread_mutex_init(return code = %x)\nTerminating...\n", rc);
148         goto out;
149     }
150     m_fInitialized = true;
151
152 out:
153
154     return m_fInitialized;
155 }
156
157 int PortManager::GetNextAvailablePort()
158 {
159     int freePort = -1;
160     int ec = 0;
161     (void)ec;
162
163     if (false == m_fInitialized)
164         return -1;
165
166     ec = pthread_mutex_lock(&m_portList_mutex);
167     for (int i = 0; i < m_numPorts; i++)
168     {
169         if (false == m_rgPortUsage[i])
170         {
171             //  This port is free
172             freePort = (i * m_portIncrement) + m_portStart;
173             m_rgPortUsage[i] = true;
174             break;
175         }
176     }
177     pthread_mutex_unlock(&m_portList_mutex);
178
179     return freePort;
180 }
181
182 int PortManager::ReleasePort(int port)
183 {
184     int portIndex = (port - m_portStart) / m_portIncrement;
185     int ec = 0;
186     (void)ec;
187
188     if (false == m_fInitialized)
189         return -1;
190
191     if (portIndex < 0 || portIndex >= m_numPorts)
192     {
193         syslog(RAD_WARN, "Attempting to release port number out of range(%d)\n", port);
194         return -1;
195     }
196
197     ec = pthread_mutex_lock(&m_portList_mutex);
198
199     m_rgPortUsage[portIndex] = false;
200
201     pthread_mutex_unlock(&m_portList_mutex);
202
203     return port;
204 }