summaryrefslogtreecommitdiff
path: root/src/connectionmanager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/connectionmanager.cpp')
-rw-r--r--src/connectionmanager.cpp343
1 files changed, 343 insertions, 0 deletions
diff --git a/src/connectionmanager.cpp b/src/connectionmanager.cpp
new file mode 100644
index 0000000..36ff961
--- /dev/null
+++ b/src/connectionmanager.cpp
@@ -0,0 +1,343 @@
1#include <time.h>
2#include <string.h>
3#include <stdio.h>
4#include <errno.h>
5#include <stdlib.h>
6#include <unistd.h>
7#include <sys/types.h>
8#include <sys/socket.h>
9#include <termios.h>
10#include <netinet/in.h>
11#include <netdb.h>
12#include <arpa/inet.h>
13#include "connectionmanager.h"
14#include <fcntl.h>
15
16ConnectionManager::ConnectionManager()
17{
18 pLog = MultiLog::getLog();
19 nMasterSocket = -1;
20 pMonitor = NULL;
21}
22
23ConnectionManager::~ConnectionManager()
24{
25 std::list<Connection *>::const_iterator i;
26 for( i = lActive.begin(); i != lActive.end(); i++ )
27 {
28 delete (*i);
29 }
30 for( i = lInactive.begin(); i != lInactive.end(); i++ )
31 {
32 delete (*i);
33 }
34}
35
36bool ConnectionManager::startServer( int nPort, int nInitPool )
37{
38 /* Create the socket and set it up to accept connections. */
39 struct sockaddr_in name;
40
41 /* Create the socket. */
42 nMasterSocket = socket (PF_INET, SOCK_STREAM, 0);
43 if (nMasterSocket < 0)
44 {
45 pLog->LineLog( MultiLog::LError, "Couldn't create a listen socket.");
46 return false;
47 }
48
49 /* Give the socket a name. */
50 name.sin_family = AF_INET;
51 name.sin_port = htons( nPort );
52
53 // I think this specifies who we will accept connections from,
54 // a good thing to make configurable later on
55 name.sin_addr.s_addr = htonl( INADDR_ANY );
56
57 int opt = 1;
58 setsockopt( nMasterSocket, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt));
59
60 if (bind (nMasterSocket, (struct sockaddr *) &name, sizeof (name)) < 0)
61 {
62 pLog->LineLog( MultiLog::LError, "Couldn't bind to the listen socket.");
63 return false;
64 }
65
66 if (listen (nMasterSocket, 1) < 0)
67 {
68 pLog->LineLog( MultiLog::LError, "Couldn't begin listening to the server socket.");
69 return false;
70 }
71
72 /* Initialize the set of active sockets. */
73 FD_ZERO (&fdActive);
74 FD_ZERO (&fdRead);
75 FD_ZERO (&fdWrite);
76 FD_ZERO (&fdException);
77 FD_SET (nMasterSocket, &fdActive);
78
79 for( int j = 0; j < nInitPool; j++ )
80 {
81 lInactive.insert( lInactive.begin(), new Connection() );
82 }
83
84 return true;
85}
86
87bool ConnectionManager::startServer( int nPort, int nInitPool, int nNumTries, int nTimeout )
88{
89 struct timeval xTimeout;
90
91 for( int j = 0; j < nNumTries; j++ )
92 {
93 pLog->LineLog( MultiLog::LStatus, "Attempting to create server socket (attempt [%d/%d])...", j+1, nNumTries );
94 if( startServer( nPort, nInitPool ) == true )
95 {
96 return true;
97 }
98 else if( j < nNumTries-1 )
99 {
100 pLog->LineLog( MultiLog::LStatus, "Waiting for %d secconds to allow port to clear...", nTimeout );
101 xTimeout.tv_sec = nTimeout;
102 xTimeout.tv_usec = 0;
103 if (select(0, (fd_set *) 0, (fd_set *) 0, (fd_set *) 0, &xTimeout) < 0) {
104 pLog->LineLog( MultiLog::LError, "Error using select to sleep for a while.");
105 }
106 usleep( nTimeout );
107 }
108 }
109
110 return false;
111}
112
113bool ConnectionManager::scanConnections( int nTimeout, bool bForceTimeout )
114{
115 struct timeval xTimeout;
116
117 xTimeout.tv_sec = nTimeout / 1000000;
118 xTimeout.tv_usec = nTimeout % 1000000;
119
120 /* Block until input arrives on one or more active sockets. */
121 fdRead = fdActive;
122 fdWrite = fdActive;
123 fdException = fdActive;
124
125 // We removed the write checking because it just checks to see if you *can*
126 // write...that's stupid, they're all open, so it always exits immediately
127 // if there are ANY connections there...
128 if( TEMP_FAILURE_RETRY( select( FD_SETSIZE, &fdRead, (fd_set *)0/*&fdWrite*/, &fdException, &xTimeout ) ) < 0 )
129 {
130 pLog->LineLog( MultiLog::LError, "Error attempting to scan open connections.");
131 perror("ConnectionManager");
132 return false;
133 }
134 // Now we use select to sleep as well as to scan for connections, now we
135 // just need to fix the fact that if there are no connections, the seccond
136 // select call doesn't return until there is a connection...
137 if( bForceTimeout )
138 {
139 if (select(0, (fd_set *) 0, (fd_set *) 0, (fd_set *) 0, &xTimeout) < 0) {
140 pLog->LineLog( MultiLog::LError, "Error using select to sleep for a while.");
141 }
142 }
143
144 /* Service all the sockets with input pending. */
145 for( int i = 0; i < FD_SETSIZE; ++i )
146 {
147 if( FD_ISSET( i, &fdRead ) )
148 {
149 if( i == nMasterSocket )
150 {
151 addConnection();
152 }
153 else
154 {
155 Connection *pCon = findActiveConnection( i );
156 if( pCon == NULL )
157 {
158 pLog->LineLog( MultiLog::LError, "A connection object was lost, or never created!");
159 return false;
160 }
161
162 /* Data arriving on an already-connected socket. */
163 if( pCon->readInput() != true )
164 {
165 pLog->LineLog( MultiLog::LStatus, "Closing connection due to disconnect.");
166 close( i );
167 FD_CLR( i, &fdActive );
168 pMonitor->onClosedConnection( pCon );
169 pCon->close();
170 }
171 else
172 {
173 // We actually read something...but the connection handles
174 // protocol notification, so we don't need to do anything
175 // here...
176 }
177 }
178 }
179 }
180 std::list<Connection *>::iterator i;
181 for( i = lActive.begin(); i != lActive.end(); i++ )
182 {
183 if( (*i)->isActive() == false )
184 {
185 std::list<Connection *>::iterator l = i;
186 i--;
187 lInactive.insert( lInactive.end(), *l );
188 lActive.erase( l );
189 continue;
190 }
191 if( (*i)->hasOutput() )
192 {
193 (*i)->writeOutput();
194 }
195 if( (*i)->needDisconnect() )
196 {
197 int prt = (*i)->getSocket();
198 close( prt );
199 FD_CLR( prt, &fdActive );
200 pMonitor->onClosedConnection( *i );
201 (*i)->close();
202 lInactive.insert( lInactive.end(), *i );
203 std::list<Connection *>::iterator l = i;
204 i--;
205 lActive.erase( l );
206 pLog->LineLog( MultiLog::LStatus, "Closing connection due to server request.");
207 }
208 }
209
210 return true;
211}
212
213bool ConnectionManager::shutdownServer()
214{
215 while( !lActive.empty() )
216 {
217 Connection *i = *(lActive.begin());
218 if( i->isActive() )
219 {
220 i->close();
221 pMonitor->onClosedConnection( i );
222 lInactive.insert( lInactive.end(), i );
223 lActive.erase( lActive.begin() );
224 }
225 }
226/*
227 for( int i = 0; i < nPoolSize; i++ )
228 {
229
230 int prt = axConPool[i].getSocket();
231 close( prt );
232// FD_CLR( prt, &fdActive );
233 pMonitor->onClosedConnection( &axConPool[i] );
234 axConPool[i].close();
235 }
236*/
237 shutdown( nMasterSocket, SHUT_RDWR );
238 close( nMasterSocket );
239
240 return true;
241}
242
243bool ConnectionManager::broadcastMessage( const char *lpData, int nExcludeSocket )
244{
245 std::list<Connection *>::const_iterator i;
246 for( i = lActive.begin(); i != lActive.end(); i++ )
247 {
248 if( (*i)->isActive() &&
249 (*i)->getSocket() != nExcludeSocket )
250 {
251 (*i)->appendOutput( lpData );
252 }
253 }
254
255 return true;
256}
257
258bool ConnectionManager::addConnection()
259{
260 struct sockaddr_in clientname;
261 size_t size;
262 int newSocket;
263
264 size = sizeof( clientname );
265#ifdef __CYGWIN__
266 newSocket = accept( nMasterSocket, (struct sockaddr *) &clientname, (int *)&size );
267#else
268 newSocket = accept( nMasterSocket, (struct sockaddr *) &clientname, &size );
269#endif
270 if( newSocket < 0 )
271 {
272 pLog->LineLog( MultiLog::LError, "Error accepting a new connection!" );
273 return false;
274 }
275// char *tmpa = inet_ntoa(clientname.sin_addr);
276 char tmpa[20];
277 inet_ntop( AF_INET, (void *)&clientname.sin_addr, tmpa, 20 );
278 pLog->LineLog( MultiLog::LStatus, "New connection from host %s, port %hd.", tmpa, ntohs (clientname.sin_port) );
279/*
280 int nCnt = 0;
281 for( int j = 0; j < nPoolSize; j++ )
282 {
283 if( axConPool[j].isActive() )
284 {
285 nCnt++;
286 }
287 }
288 pLog->LineLog( MultiLog::LStatus, "Connections %d/%d.", nCnt, nPoolSize );
289 */
290// free( tmpa );
291 FD_SET( newSocket, &fdActive );
292
293 //void nonblock(socket_t s)
294 {
295 int flags;
296
297 flags = fcntl(newSocket, F_GETFL, 0);
298 flags |= O_NONBLOCK;
299 if (fcntl(newSocket, F_SETFL, flags) < 0)
300 {
301 return false;
302 }
303 }
304
305 Connection *pCon = getInactiveConnection();
306 pCon->open( newSocket );
307
308 pMonitor->onNewConnection( pCon );
309
310 lActive.insert( lActive.end(), pCon );
311
312 return true;
313}
314
315Connection *ConnectionManager::getInactiveConnection()
316{
317 if( lInactive.empty() )
318 {
319 return new Connection();
320 }
321 Connection *pCon = *(lInactive.begin());
322 lInactive.erase( lInactive.begin() );
323 return pCon;
324}
325
326Connection *ConnectionManager::findActiveConnection( int nSocket )
327{
328 std::list<Connection *>::const_iterator i;
329 for( i = lActive.begin(); i != lActive.end(); i++ )
330 {
331 if( (*i)->getSocket() == nSocket )
332 {
333 return *i;
334 }
335 }
336
337 return NULL;
338}
339
340void ConnectionManager::setConnectionMonitor( ConnectionMonitor *pNewMonitor )
341{
342 pMonitor = pNewMonitor;
343}