<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html><head><meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1"> <title>server.cpp Source File</title> <link href="doxygen.css" rel="stylesheet" type="text/css"> </head><body> <!-- Generated by Doxygen 1.2.17 --> <center> <a class="qindex" href="main.html">Main Page</a> <a class="qindex" href="namespaces.html">Namespace List</a> <a class="qindex" href="classes.html">Alphabetical List</a> <a class="qindex" href="annotated.html">Compound List</a> <a class="qindex" href="files.html">File List</a> <a class="qindex" href="functions.html">Compound Members</a> <a class="qindex" href="globals.html">File Members</a> <a class="qindex" href="pages.html">Related Pages</a> </center> <hr><h1>server.cpp</h1><a href="server_8cpp.html">Go to the documentation of this file.</a><div class="fragment"><pre>00001 00009 <span class="preprocessor">#include "<a class="code" href="sysconfig_8h.html">sysconfig.h</a>"</span> 00010 <span class="preprocessor">#include "<a class="code" href="server_8h.html">server.h</a>"</span> 00011 <span class="preprocessor">#include "<a class="code" href="event_8h.html">event.h</a>"</span> 00012 <a name="l00016"></a><a class="code" href="classServer.html#a0">00016</a> <a class="code" href="classServer.html#a0">Server::Server</a>(<a class="code" href="classEventQueue.html">EventQueue</a>& r_inque, <a class="code" href="classEventQueue.html">EventQueue</a>& r_outque, <a class="code" href="classLog.html">Log</a>& r_lgfile) 00017 : mShutdown(false), mrLog(r_lgfile), 00018 mrInQueue(r_inque), mrOutQueue(r_outque) { 00019 } 00020 <a name="l00028"></a><a class="code" href="classServer.html#a1">00028</a> <a class="code" href="classServer.html#a1">Server::~Server</a>() { 00029 ConnList::iterator i; 00030 <span class="keywordflow">for</span> (i = <a class="code" href="classServer.html#o5">mConns</a>.begin(); i != <a class="code" href="classServer.html#o5">mConns</a>.end(); i++) { 00031 <span class="keyword">delete</span> (*i); 00032 } 00033 } 00034 <a name="l00041"></a><a class="code" href="classServer.html#a2">00041</a> <span class="keywordtype">bool</span> <a class="code" href="classServer.html#a2">Server::Boot</a>(<span class="keywordtype">unsigned</span> <span class="keywordtype">short</span> port) { 00042 <span class="comment">// Get a TCP protocol socket for the server to listen on.</span> 00043 <a class="code" href="classServer.html#o3">mAcceptor</a> = socket (AF_INET, SOCK_STREAM, 0); 00044 <span class="keywordflow">if</span> (<a class="code" href="classServer.html#o3">mAcceptor</a> == INVALID_SOCKET) { 00045 <a class="code" href="classServer.html#a4">ServerLog</a>().<a class="code" href="classLog.html#a3">Write</a>(<span class="stringliteral">"ERROR-Server(socket): %d"</span>, WSAGetLastError()); 00046 <span class="keywordflow">return</span> <span class="keyword">false</span>; 00047 } 00048 00049 <span class="comment">// Set the listening socket to be non-blocking</span> 00050 <span class="keywordflow">if</span> (!<a class="code" href="classServer.html#c6">SetNonBlocking</a>(<a class="code" href="classServer.html#o3">mAcceptor</a>)) 00051 <span class="keywordflow">return</span> <span class="keyword">false</span>; 00052 00053 <span class="comment">// Set up listening socket to allow local address reuse</span> 00054 <span class="keywordtype">int</span> sockopt_val = 1; <span class="comment">// Non-zero means turn on for boolean options,</span> 00055 <span class="comment">// some options require other types and values.</span> 00056 <span class="keywordflow">if</span> (setsockopt(<a class="code" href="classServer.html#o3">mAcceptor</a>, SOL_SOCKET, SO_REUSEADDR, (<span class="keywordtype">char</span> *)&sockopt_val, 00057 <span class="keyword">sizeof</span>(sockopt_val)) == SOCKET_ERROR) { 00058 <a class="code" href="classServer.html#a4">ServerLog</a>().<a class="code" href="classLog.html#a3">Write</a>(<span class="stringliteral">"ERROR-Server(setsockopt): %d"</span>,WSAGetLastError()); 00059 closesocket(<a class="code" href="classServer.html#o3">mAcceptor</a>); 00060 <span class="keywordflow">return</span> <span class="keyword">false</span>; 00061 } 00062 00063 <span class="comment">// Associate our local address with this socket</span> 00064 <a class="code" href="classServer.html#o4">mTo</a>.sin_family = AF_INET; <span class="comment">// protocol - internet</span> 00065 <a class="code" href="classServer.html#o4">mTo</a>.sin_addr.s_addr = INADDR_ANY; <span class="comment">// accept on whatever IP we're set up as</span> 00066 <a class="code" href="classServer.html#o4">mTo</a>.sin_port = htons(port); <span class="comment">// port must be in network byte order</span> 00067 <span class="keywordflow">if</span> (bind(<a class="code" href="classServer.html#o3">mAcceptor</a>, (<span class="keyword">struct</span> sockaddr *)&<a class="code" href="classServer.html#o4">mTo</a>, <span class="keyword">sizeof</span>(<a class="code" href="classServer.html#o4">mTo</a>)) == SOCKET_ERROR) { 00068 <a class="code" href="classServer.html#a4">ServerLog</a>().<a class="code" href="classLog.html#a3">Write</a>(<span class="stringliteral">"ERROR-Server(bind): %d"</span>,WSAGetLastError()); 00069 closesocket(<a class="code" href="classServer.html#o3">mAcceptor</a>); 00070 <span class="keywordflow">return</span> <span class="keyword">false</span>; 00071 } 00072 <span class="comment">// Let's start listening for incoming connections</span> 00073 <span class="keywordflow">if</span> (listen(<a class="code" href="classServer.html#o3">mAcceptor</a>, 5) == SOCKET_ERROR) { <span class="comment">// Connection backlog of 5.</span> 00074 <a class="code" href="classServer.html#a4">ServerLog</a>().<a class="code" href="classLog.html#a3">Write</a>(<span class="stringliteral">"ERROR-Server(listen): %d"</span>,WSAGetLastError()); 00075 closesocket(<a class="code" href="classServer.html#o3">mAcceptor</a>); 00076 <span class="keywordflow">return</span> <span class="keyword">false</span>; 00077 } 00078 <span class="comment">/*</span> 00079 <span class="comment"> mNumFds is calculated for the select() function - Windows ignores</span> 00080 <span class="comment"> it as the underlying FD sets are constructed differently than Unixes</span> 00081 <span class="comment"> On Unixes FDs are include all files, pipes and sockets open.</span> 00082 <span class="comment"> We need to calculate the highest FD number for the Unix select.</span> 00083 <span class="comment"></span> 00084 <span class="comment"> In bootup the highest FD is the listening socket so...</span> 00085 <span class="comment"> */</span> 00086 <a class="code" href="classServer.html#o6">mNumFds</a> = <a class="code" href="classServer.html#o3">mAcceptor</a>; 00087 <span class="keywordflow">return</span> <span class="keyword">true</span>; 00088 } 00089 00102 <span class="preprocessor">#pragma argsused</span> <a name="l00103"></a><a class="code" href="classServer.html#a3">00103</a> <span class="preprocessor"></span><span class="keywordtype">void</span> <a class="code" href="classServer.html#a3">Server::Run</a>(<span class="keywordtype">void</span> * parms) { 00104 <a class="code" href="classServer.html#a4">ServerLog</a>().<a class="code" href="classLog.html#a3">Write</a>(<span class="stringliteral">"INFO-StartServer(): Server thread entered."</span>); 00105 <span class="keyword">struct </span>timeval timeout = { 0, 1 }; <span class="comment">// Will poll for 1 millisecond</span> 00106 00107 <span class="keywordflow">while</span> (!<a class="code" href="classServer.html#o0">mShutdown</a>) { <span class="comment">// Loops until a SHUTDOWN_E message is received.</span> 00108 ConnList::iterator i, curr; 00109 00110 <span class="comment">// Reset our socket interest set</span> 00111 <a class="code" href="classServer.html#c3">InitFDs</a>(); 00112 00113 <span class="comment">// Poll our socket interest set for about a millisec.</span> 00114 <span class="keywordflow">if</span> (select(<a class="code" href="classServer.html#o6">mNumFds</a> + 1, &<a class="code" href="classServer.html#o1">mInputFDs</a>, &<a class="code" href="classServer.html#o2">mOutputFDs</a>, NULL, &timeout) == SOCKET_ERROR) { 00115 <a class="code" href="classServer.html#a4">ServerLog</a>().<a class="code" href="classLog.html#a3">Write</a>(<span class="stringliteral">"ERROR-Server(select): %d"</span>,WSAGetLastError()); 00116 <span class="keywordflow">break</span>; 00117 } 00118 00119 <span class="comment">// If we have incoming connections on our listening port handle them.</span> 00120 <span class="keywordflow">if</span> (FD_ISSET(<a class="code" href="classServer.html#o3">mAcceptor</a>, &<a class="code" href="classServer.html#o1">mInputFDs</a>)) { 00121 <a class="code" href="classServer.html#c2">AcceptConnection</a>(); 00122 } 00123 00124 <span class="comment">// If we have incoming data on any connections handle it.</span> 00125 <span class="keywordflow">for</span>(i = <a class="code" href="classServer.html#o5">mConns</a>.begin(); i != <a class="code" href="classServer.html#o5">mConns</a>.end(); i++) { 00126 <span class="keywordflow">if</span> (FD_ISSET((*i)->GetSocket(), &<a class="code" href="classServer.html#o1">mInputFDs</a>)) { 00127 (*i)->HandleInput(); 00128 00129 <span class="comment">// Loop through fully formed messages (CRLF).</span> 00130 string* msg = (*i)->ReadMsg(); 00131 <span class="keywordflow">while</span>(msg) { 00132 <span class="comment">// notify the chat driver.</span> 00133 <a class="code" href="classServer.html#o9">mrOutQueue</a>.<a class="code" href="classEventQueue.html#a2">Push</a>(<span class="keyword">new</span> <a class="code" href="classEvent.html">Event</a>(<a class="code" href="event_8h.html#a5a3">MESSAGE_E</a>, 00134 (*i)->GetSocket(), msg->length(), msg->c_str())); 00135 <span class="keyword">delete</span> msg; <span class="comment">// ReadMsg creates a new string - we must delete it.</span> 00136 msg = (*i)->ReadMsg(); 00137 } <span class="comment">// while</span> 00138 } <span class="comment">// if</span> 00139 } <span class="comment">// for</span> 00140 00141 <span class="comment">// Process the event queue.</span> 00142 <a class="code" href="classServer.html#c4">ProcessQueue</a>(); 00143 00144 <span class="comment">// If we have outgoing data ready on any connections handle it.</span> 00145 <span class="keywordflow">for</span>(i = <a class="code" href="classServer.html#o5">mConns</a>.begin(); i != <a class="code" href="classServer.html#o5">mConns</a>.end(); i++) { 00146 <span class="keywordflow">if</span> (FD_ISSET((*i)->GetSocket(), &<a class="code" href="classServer.html#o2">mOutputFDs</a>)) 00147 (*i)->HandleOutput(); 00148 } 00149 00150 <span class="comment">// Cleanup sockets that have been scheduled for disconnection.</span> 00151 <span class="keywordflow">for</span>(i = <a class="code" href="classServer.html#o5">mConns</a>.begin(); i != <a class="code" href="classServer.html#o5">mConns</a>.end();) { 00152 curr = i++; 00153 <span class="keywordflow">if</span> ((*curr)->CanBeDisconnected()) { 00154 (*curr)->Disconnect(); 00155 <span class="comment">// Tell the chat driver about it.</span> 00156 <a class="code" href="classServer.html#o9">mrOutQueue</a>.<a class="code" href="classEventQueue.html#a2">Push</a>(<span class="keyword">new</span> <a class="code" href="classEvent.html">Event</a>(<a class="code" href="event_8h.html#a5a2">DISCONNECT_E</a>, (*curr)->GetSocket(), 00157 0, NULL)); 00158 <span class="keyword">delete</span> (*curr); 00159 <a class="code" href="classServer.html#o5">mConns</a>.erase(curr); 00160 } 00161 } 00162 } <span class="comment">// while</span> 00163 <a class="code" href="classServer.html#c5">ShutdownServer</a>(); 00164 <a class="code" href="classServer.html#a4">ServerLog</a>().<a class="code" href="classLog.html#a3">Write</a>(<span class="stringliteral">"INFO-StartServer(): Server thread exited."</span>); 00165 } 00166 <a name="l00174"></a><a class="code" href="classServer.html#c2">00174</a> <span class="keywordtype">void</span> <a class="code" href="classServer.html#c2">Server::AcceptConnection</a>() { 00175 <span class="keyword">struct </span>sockaddr_in addr; <span class="comment">// An address structure for our incoming connection.</span> 00176 <span class="keywordtype">int</span> addrlen = <span class="keyword">sizeof</span>(addr); 00177 00178 <span class="comment">// Try to accept the connection</span> 00179 SOCKET psock = accept(<a class="code" href="classServer.html#o3">mAcceptor</a>, (<span class="keyword">struct</span> sockaddr *)&addr, &addrlen); 00180 <span class="keywordflow">if</span> (psock != INVALID_SOCKET) { 00181 <span class="comment">// Set the socket to non-blocking.</span> 00182 <span class="keywordflow">if</span> (<a class="code" href="classServer.html#c6">SetNonBlocking</a>(psock)) { 00183 <span class="comment">// The socket set up correctly. Let us add a new Connection.</span> 00184 <a class="code" href="classConnection.html">Connection</a> *conn = <span class="keyword">new</span> <a class="code" href="classConnection.html">Connection</a>(psock, <span class="keyword">this</span>); 00185 <a class="code" href="classServer.html#a4">ServerLog</a>().<a class="code" href="classLog.html#a3">Write</a>(<span class="stringliteral">"INFO-Server(accept): Connection %d accepted"</span>, psock); 00186 <a class="code" href="classServer.html#o5">mConns</a>.push_back(conn); <span class="comment">// Put it on the connection list.</span> 00187 <span class="comment">// Tell the chat server we have a new connection</span> 00188 <a class="code" href="classServer.html#o9">mrOutQueue</a>.<a class="code" href="classEventQueue.html#a2">Push</a>(<span class="keyword">new</span> <a class="code" href="classEvent.html">Event</a>(<a class="code" href="event_8h.html#a5a1">CONNECT_E</a>, conn-><a class="code" href="classConnection.html#a11">GetSocket</a>(), 0, NULL)); 00189 } 00190 } <span class="keywordflow">else</span> { 00191 <span class="comment">// Weve encountered an error during accept.</span> 00192 <a class="code" href="classServer.html#a4">ServerLog</a>().<a class="code" href="classLog.html#a3">Write</a>(<span class="stringliteral">"ERROR-ServerAccept(accept): %d"</span>, WSAGetLastError()); 00193 } 00194 } 00195 <a name="l00211"></a><a class="code" href="classServer.html#c3">00211</a> <span class="keywordtype">void</span> <a class="code" href="classServer.html#c3">Server::InitFDs</a> () { 00212 FD_ZERO (&<a class="code" href="classServer.html#o1">mInputFDs</a>); <span class="comment">// Clears our interest sets out.</span> 00213 FD_ZERO (&<a class="code" href="classServer.html#o2">mOutputFDs</a>); 00214 00215 FD_SET (<a class="code" href="classServer.html#o3">mAcceptor</a>, &<a class="code" href="classServer.html#o1">mInputFDs</a>); <span class="comment">// Register interest in listening socket.</span> 00216 <span class="keywordflow">for</span>(ConnList::iterator i = <a class="code" href="classServer.html#o5">mConns</a>.begin(); i != <a class="code" href="classServer.html#o5">mConns</a>.end(); i++) { 00217 <span class="comment">/*</span> 00218 <span class="comment"> mNumFds is calculated for the select() function - Windows ignores</span> 00219 <span class="comment"> it as the underlying FD sets are constructed differently than Unixes</span> 00220 <span class="comment"> On Unixes FDs are include all files, pipes and sockets open.</span> 00221 <span class="comment"> We need to calculate the highest FD number for the Unix select.</span> 00222 <span class="comment"> */</span> 00223 <a class="code" href="classServer.html#o6">mNumFds</a> = max(<a class="code" href="classServer.html#o6">mNumFds</a>, (*i)->GetSocket()); 00224 FD_SET((*i)->GetSocket(), &<a class="code" href="classServer.html#o1">mInputFDs</a>); <span class="comment">// Always interested in input.</span> 00225 <span class="keywordflow">if</span> ((*i)->HasOutput()) <span class="comment">// See [1] above.</span> 00226 FD_SET((*i)->GetSocket(), &<a class="code" href="classServer.html#o2">mOutputFDs</a>); 00227 } 00228 } 00229 <a name="l00244"></a><a class="code" href="classServer.html#c4">00244</a> <span class="keywordtype">void</span> <a class="code" href="classServer.html#c4">Server::ProcessQueue</a>() { 00245 <span class="comment">// manage event queue</span> 00246 <a class="code" href="classEvent.html">Event</a>* e; 00247 <span class="keywordflow">while</span> ((e = <a class="code" href="classServer.html#o8">mrInQueue</a>.<a class="code" href="classEventQueue.html#a3">Pop</a>()) != NULL) { 00248 <span class="keywordflow">switch</span> (e-><a class="code" href="classEvent.html#m0">mEventType</a>) { 00249 <span class="keywordflow">case</span> <a class="code" href="event_8h.html#a5a2">DISCONNECT_E</a>: 00250 <span class="comment">// We've been told by the chat driver to kill a connection.</span> 00251 { 00252 <span class="comment">// Not yet implemented.</span> 00253 } 00254 <span class="keywordflow">break</span>; 00255 <span class="keywordflow">case</span> <a class="code" href="event_8h.html#a5a1">CONNECT_E</a>: 00256 <span class="comment">// Should never happen - included for completeness</span> 00257 <span class="keywordflow">break</span>; 00258 <span class="keywordflow">case</span> <a class="code" href="event_8h.html#a5a3">MESSAGE_E</a>: 00259 <span class="comment">// A message from the chat driver to route to a connection here.</span> 00260 { 00261 <span class="comment">// Test for null message data and ignore it</span> 00262 <span class="keywordflow">if</span> (e-><a class="code" href="classEvent.html#m3">mpData</a> && e-><a class="code" href="classEvent.html#m2">mDataLen</a>) { 00263 string msg; 00264 msg.append(e-><a class="code" href="classEvent.html#m3">mpData</a>, e-><a class="code" href="classEvent.html#m2">mDataLen</a>); 00265 <span class="keywordflow">for</span>(ConnList::iterator c = <a class="code" href="classServer.html#o5">mConns</a>.begin(); c != <a class="code" href="classServer.html#o5">mConns</a>.end(); c++) { 00266 <span class="keywordflow">if</span> ((*c)->GetSocket() == e-><a class="code" href="classEvent.html#m1">mClientId</a>) { 00267 (*c)->SendMsg(msg); 00268 <span class="comment">// Register interest as we have data ready on the wire</span> 00269 FD_SET ((*c)->GetSocket(), &<a class="code" href="classServer.html#o2">mOutputFDs</a>); 00270 } 00271 } 00272 } 00273 } 00274 <span class="keywordflow">break</span>; 00275 <span class="keywordflow">case</span> <a class="code" href="event_8h.html#a5a4">SHUTDOWN_E</a>: 00276 <span class="comment">// We've been requested to shutdown so let's comply.</span> 00277 <a class="code" href="classServer.html#o0">mShutdown</a> = <span class="keyword">true</span>; 00278 <span class="keywordflow">break</span>; 00279 <span class="keywordflow">case</span> <a class="code" href="event_8h.html#a5a0">NONE_E</a>: 00280 <span class="keywordflow">break</span>; 00281 } <span class="comment">// switch</span> 00282 <span class="keyword">delete</span> e; 00283 } <span class="comment">// while</span> 00284 } 00285 <a name="l00291"></a><a class="code" href="classServer.html#c5">00291</a> <span class="keywordtype">void</span> <a class="code" href="classServer.html#c5">Server::ShutdownServer</a>() { 00292 <a class="code" href="classServer.html#a4">ServerLog</a>().<a class="code" href="classLog.html#a3">Write</a>(<span class="stringliteral">"INFO-Server(shutdown): Server shutting down"</span>); 00293 ConnList::iterator ci, curr; 00294 <span class="keywordflow">for</span>(ci = <a class="code" href="classServer.html#o5">mConns</a>.begin(); ci != <a class="code" href="classServer.html#o5">mConns</a>.end();) { 00295 curr = ci++;<span class="comment">// :WARN: The list containers iterator is invalidated on erase.</span> 00296 <span class="comment">// So we need to increment it first and delete the old.</span> 00297 (*curr)->Disconnect(); 00298 <span class="comment">// Tell chat driver about each connection as it leaves</span> 00299 <a class="code" href="classServer.html#o9">mrOutQueue</a>.<a class="code" href="classEventQueue.html#a2">Push</a>(<span class="keyword">new</span> <a class="code" href="classEvent.html">Event</a>(<a class="code" href="event_8h.html#a5a2">DISCONNECT_E</a>, (*curr)->GetSocket(), 00300 0, NULL)); 00301 <span class="keyword">delete</span> (*curr); 00302 <a class="code" href="classServer.html#o5">mConns</a>.erase(curr); 00303 } 00304 closesocket(<a class="code" href="classServer.html#o3">mAcceptor</a>); 00305 <a class="code" href="classServer.html#o9">mrOutQueue</a>.<a class="code" href="classEventQueue.html#a2">Push</a>(<span class="keyword">new</span> <a class="code" href="classEvent.html">Event</a>(<a class="code" href="event_8h.html#a5a4">SHUTDOWN_E</a>, 0, 0, 0)); 00306 } 00307 <a name="l00314"></a><a class="code" href="classServer.html#a4">00314</a> <a class="code" href="classLog.html">Log</a>& <a class="code" href="classServer.html#a4">Server::ServerLog</a>() { 00315 <span class="keywordflow">return</span> <a class="code" href="classServer.html#o7">mrLog</a>; 00316 } 00317 <a name="l00325"></a><a class="code" href="classServer.html#c6">00325</a> <span class="keywordtype">bool</span> <a class="code" href="classServer.html#c6">Server::SetNonBlocking</a>(SOCKET s) { 00326 <span class="keywordtype">unsigned</span> <span class="keywordtype">long</span> ioctl_cmd = 1; <span class="comment">// Non-zero means turn on for ioctl commands.</span> 00327 <span class="keywordflow">if</span> (ioctlsocket(s, FIONBIO, &ioctl_cmd) == SOCKET_ERROR) { 00328 <a class="code" href="classServer.html#a4">ServerLog</a>().<a class="code" href="classLog.html#a3">Write</a>(<span class="stringliteral">"ERROR-Server(SetNonBlocking): %d on socket %d"</span>, 00329 WSAGetLastError(), s); 00330 closesocket(s); 00331 <span class="keywordflow">return</span> <span class="keyword">false</span>; 00332 } 00333 <span class="keywordflow">return</span> <span class="keyword">true</span>; 00334 } 00335 </pre></div><hr><address style="align: right;"><small>Generated on Mon Mar 29 23:12:53 2004 for Paradigm by <a href="http://www.doxygen.org/index.html"> <img src="doxygen.png" alt="doxygen" align="middle" border=0 width=110 height=53></a>1.2.17 </small></address> </body> </html>