paradigm_3/html/
<!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> &nbsp; <a class="qindex" href="namespaces.html">Namespace List</a> &nbsp; <a class="qindex" href="classes.html">Alphabetical List</a> &nbsp; <a class="qindex" href="annotated.html">Compound List</a> &nbsp; <a class="qindex" href="files.html">File List</a> &nbsp; <a class="qindex" href="functions.html">Compound Members</a> &nbsp; <a class="qindex" href="globals.html">File Members</a> &nbsp; <a class="qindex" href="pages.html">Related Pages</a> &nbsp; </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>&amp; r_inque, <a class="code" href="classEventQueue.html">EventQueue</a>&amp; r_outque, <a class="code" href="classLog.html">Log</a>&amp; 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> *)&amp;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 *)&amp;<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, &amp;<a class="code" href="classServer.html#o1">mInputFDs</a>, &amp;<a class="code" href="classServer.html#o2">mOutputFDs</a>, NULL, &amp;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>, &amp;<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)-&gt;GetSocket(), &amp;<a class="code" href="classServer.html#o1">mInputFDs</a>)) {
00127         (*i)-&gt;HandleInput();
00128 
00129         <span class="comment">// Loop through fully formed messages (CRLF).</span>
00130         string* msg = (*i)-&gt;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)-&gt;GetSocket(), msg-&gt;length(), msg-&gt;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)-&gt;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)-&gt;GetSocket(), &amp;<a class="code" href="classServer.html#o2">mOutputFDs</a>))
00147         (*i)-&gt;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)-&gt;CanBeDisconnected()) {
00154         (*curr)-&gt;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)-&gt;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 *)&amp;addr, &amp;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-&gt;<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 (&amp;<a class="code" href="classServer.html#o1">mInputFDs</a>);           <span class="comment">// Clears our interest sets out.</span>
00213   FD_ZERO (&amp;<a class="code" href="classServer.html#o2">mOutputFDs</a>);
00214 
00215   FD_SET (<a class="code" href="classServer.html#o3">mAcceptor</a>, &amp;<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)-&gt;GetSocket());
00224     FD_SET((*i)-&gt;GetSocket(), &amp;<a class="code" href="classServer.html#o1">mInputFDs</a>);  <span class="comment">// Always interested in input.</span>
00225     <span class="keywordflow">if</span> ((*i)-&gt;HasOutput())        <span class="comment">// See [1] above.</span>
00226       FD_SET((*i)-&gt;GetSocket(), &amp;<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-&gt;<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-&gt;<a class="code" href="classEvent.html#m3">mpData</a> &amp;&amp; e-&gt;<a class="code" href="classEvent.html#m2">mDataLen</a>) {
00263           string msg;
00264           msg.append(e-&gt;<a class="code" href="classEvent.html#m3">mpData</a>, e-&gt;<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)-&gt;GetSocket() == e-&gt;<a class="code" href="classEvent.html#m1">mClientId</a>) {
00267               (*c)-&gt;SendMsg(msg);
00268               <span class="comment">// Register interest as we have data ready on the wire</span>
00269               FD_SET ((*c)-&gt;GetSocket(), &amp;<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)-&gt;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)-&gt;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>&amp; <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, &amp;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>