diff options
author | Mike Buland <eichlan@xagasoft.com> | 2012-03-25 20:00:08 +0000 |
---|---|---|
committer | Mike Buland <eichlan@xagasoft.com> | 2012-03-25 20:00:08 +0000 |
commit | 469bbcf0701e1eb8a6670c23145b0da87357e178 (patch) | |
tree | b5b062a16e46a6c5d3410b4e574cd0cc09057211 /src/stable/server.cpp | |
parent | ee1b79396076edc4e30aefb285fada03bb45e80d (diff) | |
download | libbu++-469bbcf0701e1eb8a6670c23145b0da87357e178.tar.gz libbu++-469bbcf0701e1eb8a6670c23145b0da87357e178.tar.bz2 libbu++-469bbcf0701e1eb8a6670c23145b0da87357e178.tar.xz libbu++-469bbcf0701e1eb8a6670c23145b0da87357e178.zip |
Code is all reorganized. We're about ready to release. I should write up a
little explenation of the arrangement.
Diffstat (limited to 'src/stable/server.cpp')
-rw-r--r-- | src/stable/server.cpp | 214 |
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 | |||
16 | Bu::Server::Server() : | ||
17 | nTimeoutSec( 0 ), | ||
18 | nTimeoutUSec( 0 ), | ||
19 | bAutoTick( false ) | ||
20 | { | ||
21 | FD_ZERO( &fdActive ); | ||
22 | } | ||
23 | |||
24 | Bu::Server::~Server() | ||
25 | { | ||
26 | shutdown(); | ||
27 | } | ||
28 | |||
29 | void 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 | |||
37 | void 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 | |||
45 | void Bu::Server::setTimeout( int nTimeoutSec, int nTimeoutUSec ) | ||
46 | { | ||
47 | this->nTimeoutSec = nTimeoutSec; | ||
48 | this->nTimeoutUSec = nTimeoutUSec; | ||
49 | } | ||
50 | |||
51 | void 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 | |||
134 | void 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 | |||
147 | Bu::Server::SrvClientLink::SrvClientLink( Bu::Client *pClient ) : | ||
148 | pClient( pClient ) | ||
149 | { | ||
150 | } | ||
151 | |||
152 | Bu::Server::SrvClientLink::~SrvClientLink() | ||
153 | { | ||
154 | } | ||
155 | |||
156 | void Bu::Server::SrvClientLink::sendMessage( const Bu::String &sMsg ) | ||
157 | { | ||
158 | pClient->onMessage( sMsg ); | ||
159 | } | ||
160 | |||
161 | Bu::Server::SrvClientLinkFactory::SrvClientLinkFactory() | ||
162 | { | ||
163 | } | ||
164 | |||
165 | Bu::Server::SrvClientLinkFactory::~SrvClientLinkFactory() | ||
166 | { | ||
167 | } | ||
168 | |||
169 | Bu::ClientLink *Bu::Server::SrvClientLinkFactory::createLink( | ||
170 | Bu::Client *pClient ) | ||
171 | { | ||
172 | return new SrvClientLink( pClient ); | ||
173 | } | ||
174 | |||
175 | void Bu::Server::setAutoTick( bool bEnable ) | ||
176 | { | ||
177 | bAutoTick = bEnable; | ||
178 | } | ||
179 | |||
180 | void Bu::Server::tick() | ||
181 | { | ||
182 | for( ClientHash::iterator i = hClients.begin(); i != hClients.end(); i++ ) | ||
183 | { | ||
184 | (*i)->tick(); | ||
185 | } | ||
186 | } | ||
187 | |||
188 | void 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 | |||
205 | void 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 | |||