summaryrefslogtreecommitdiff
path: root/src/stable/server.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/stable/server.cpp')
-rw-r--r--src/stable/server.cpp214
1 files changed, 214 insertions, 0 deletions
diff --git a/src/stable/server.cpp b/src/stable/server.cpp
new file mode 100644
index 0000000..1972a3f
--- /dev/null
+++ b/src/stable/server.cpp
@@ -0,0 +1,214 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/server.h"
9#include <errno.h>
10#include <unistd.h>
11#include "bu/tcpserversocket.h"
12#include "bu/client.h"
13#include "bu/tcpsocket.h"
14#include "bu/config.h"
15
16Bu::Server::Server() :
17 nTimeoutSec( 0 ),
18 nTimeoutUSec( 0 ),
19 bAutoTick( false )
20{
21 FD_ZERO( &fdActive );
22}
23
24Bu::Server::~Server()
25{
26 shutdown();
27}
28
29void Bu::Server::addPort( int nPort, int nPoolSize )
30{
31 TcpServerSocket *s = new TcpServerSocket( nPort, nPoolSize );
32 int nSocket = s->getSocket();
33 FD_SET( nSocket, &fdActive );
34 hServers.insert( nSocket, s );
35}
36
37void Bu::Server::addPort( const String &sAddr, int nPort, int nPoolSize )
38{
39 TcpServerSocket *s = new TcpServerSocket( sAddr, nPort, nPoolSize );
40 int nSocket = s->getSocket();
41 FD_SET( nSocket, &fdActive );
42 hServers.insert( nSocket, s );
43}
44
45void Bu::Server::setTimeout( int nTimeoutSec, int nTimeoutUSec )
46{
47 this->nTimeoutSec = nTimeoutSec;
48 this->nTimeoutUSec = nTimeoutUSec;
49}
50
51void Bu::Server::scan()
52{
53 struct timeval xTimeout = { nTimeoutSec, nTimeoutUSec };
54
55 fd_set fdRead = fdActive;
56 fd_set fdWrite /* = fdActive*/;
57 fd_set fdException = fdActive;
58
59 FD_ZERO( &fdWrite );
60 for( ClientHash::iterator i = hClients.begin(); i != hClients.end(); i++ )
61 {
62 if( (*i)->hasOutput() )
63 FD_SET( i.getKey(), &fdWrite );
64 }
65
66 if( TEMP_FAILURE_RETRY( select( FD_SETSIZE,
67 &fdRead, &fdWrite, &fdException, &xTimeout ) ) < 0 )
68 {
69 throw ExceptionBase("Error attempting to scan open connections.");
70 }
71
72 for( int j = 0; j < FD_SETSIZE; j++ )
73 {
74 if( FD_ISSET( j, &fdRead ) )
75 {
76 if( hServers.has( j ) )
77 {
78 TcpServerSocket *pSrv = hServers.get( j );
79 addClient( pSrv->accept(), pSrv->getPort() );
80 }
81 else
82 {
83 Client *pClient = hClients.get( j );
84 pClient->processInput();
85 if( !pClient->isOpen() )
86 {
87 closeClient( j );
88 }
89 }
90 }
91 if( FD_ISSET( j, &fdWrite ) )
92 {
93 try
94 {
95 Client *pClient = hClients.get( j );
96 try
97 {
98 pClient->processOutput();
99 }
100 catch( Bu::TcpSocketException &e )
101 {
102 closeClient( j );
103 }
104 }
105 catch( Bu::HashException &e )
106 {
107 // Do nothing, I guess, the client is already dead...
108 // TODO: Someday, we may want to handle this more graceully.
109 }
110 }
111 }
112
113 Bu::List<int> lDelete;
114 // Now we just try to write all the pending data on all the sockets.
115 // this could be done better eventually, if we care about the socket
116 // wanting to accept writes (using a select).
117 for( ClientHash::iterator i = hClients.begin(); i != hClients.end(); i++ )
118 {
119 if( (*i)->wantsDisconnect() && !(*i)->hasOutput() )
120 {
121 lDelete.append( i.getKey() );
122 }
123 }
124
125 for( Bu::List<int>::iterator i = lDelete.begin(); i != lDelete.end(); i++ )
126 {
127 closeClient( *i );
128 }
129
130 if( bAutoTick )
131 tick();
132}
133
134void Bu::Server::addClient( int nSocket, int nPort )
135{
136 FD_SET( nSocket, &fdActive );
137
138 Client *c = new Client(
139 new Bu::TcpSocket( nSocket ),
140 new SrvClientLinkFactory()
141 );
142 hClients.insert( nSocket, c );
143
144 onNewConnection( c, nPort );
145}
146
147Bu::Server::SrvClientLink::SrvClientLink( Bu::Client *pClient ) :
148 pClient( pClient )
149{
150}
151
152Bu::Server::SrvClientLink::~SrvClientLink()
153{
154}
155
156void Bu::Server::SrvClientLink::sendMessage( const Bu::String &sMsg )
157{
158 pClient->onMessage( sMsg );
159}
160
161Bu::Server::SrvClientLinkFactory::SrvClientLinkFactory()
162{
163}
164
165Bu::Server::SrvClientLinkFactory::~SrvClientLinkFactory()
166{
167}
168
169Bu::ClientLink *Bu::Server::SrvClientLinkFactory::createLink(
170 Bu::Client *pClient )
171{
172 return new SrvClientLink( pClient );
173}
174
175void Bu::Server::setAutoTick( bool bEnable )
176{
177 bAutoTick = bEnable;
178}
179
180void Bu::Server::tick()
181{
182 for( ClientHash::iterator i = hClients.begin(); i != hClients.end(); i++ )
183 {
184 (*i)->tick();
185 }
186}
187
188void Bu::Server::shutdown()
189{
190 for( SrvHash::iterator i = hServers.begin(); i != hServers.end(); i++ )
191 {
192 delete *i;
193 }
194
195 hServers.clear();
196
197 for( ClientHash::iterator i = hClients.begin(); i != hClients.end(); i++ )
198 {
199 closeClient( i.getKey() );
200 }
201
202 hClients.clear();
203}
204
205void Bu::Server::closeClient( int iSocket )
206{
207 Bu::Client *pClient = hClients.get( iSocket );
208 onClosedConnection( pClient );
209 pClient->close();
210 hClients.erase( iSocket );
211 FD_CLR( iSocket, &fdActive );
212 delete pClient;
213}
214