<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/> <title>GNU CommonC++: SampleSocketPort.cpp</title> <link href="tabs.css" rel="stylesheet" type="text/css"/> <link href="doxygen.css" rel="stylesheet" type="text/css"/> </head> <body> <!-- Generated by Doxygen 1.6.3 --> <div class="navigation" id="top"> <div class="tabs"> <ul> <li><a href="index.html"><span>Main Page</span></a></li> <li><a href="namespaces.html"><span>Namespaces</span></a></li> <li><a href="annotated.html"><span>Classes</span></a></li> <li><a href="files.html"><span>Files</span></a></li> <li><a href="examples.html"><span>Examples</span></a></li> </ul> </div> </div> <div class="contents"> <h1>SampleSocketPort.cpp</h1><div class="fragment"><pre class="fragment"> <span class="preprocessor">#include "SampleSocketPort.h"</span> SampleSocketPort::SampleSocketPort(SocketService *pService, TCPSocket & tcpSocket) : SocketPort(pService, tcpSocket) { <a name="a0"></a><a class="code" href="namespaceost.html#a3c74a1a40c359fd349f3e3e1b96ebfc7" title="Transport Protocol Ports.">tpport_t</a> port; <a name="a1"></a><a class="code" href="address_8h.html#a5eba36aa908d5a479c8ba7d0bc4512b1">InetHostAddress</a> ia = getPeer( & port ); cerr << <span class="stringliteral">"connecting from "</span> << ia.getHostname() << <span class="stringliteral">":"</span> << port << endl; <span class="comment">// Set up non-blocking reads</span> setCompletion( <span class="keyword">false</span> ); <span class="comment">//1.9.3 THIS LINE DOES NOT SEEM TO BE REQUIRED ANYMORE!</span> <span class="comment">//This sorts out a bug which prevents connections after a disconnect</span> <span class="comment">//setDetectOutput(true);</span> m_bOpen = <span class="keyword">true</span>; m_bDoDisconnect = <span class="keyword">false</span>; m_bTimedOut = <span class="keyword">false</span>; m_bReceptionStarted = <span class="keyword">false</span>; m_nLastBytesAvail = 0; m_pBuf = <span class="keyword">new</span> <span class="keywordtype">char</span>[MAX_RXBUF]; } SampleSocketPort::~SampleSocketPort() { endSocket(); <span class="keyword">delete</span> [] m_pBuf; } <span class="keywordtype">void</span> SampleSocketPort::pending(<span class="keywordtype">void</span>) { <span class="comment">//cerr << "Pending called " << endl;</span> <span class="keywordflow">if</span>(!m_bOpen) <span class="keywordflow">return</span>; <span class="comment">// Read all available bytes into our buffer</span> <span class="keywordtype">int</span> nBytesAvail = <a name="a2"></a><a class="code" href="classost_1_1_buffer.html#a2066fdf67ab3b6727be90a51fc5c4d64">peek</a>(m_pBuf, MAX_RXBUF); <span class="comment">//cerr << "Pending .. " << nBytesAvail << endl;</span> <span class="keywordflow">if</span>(!m_bReceptionStarted) { <span class="comment">//Start the receive timer</span> ResetReadTimeout(MAX_RXTIMEOUT); <span class="comment">//Got 'n' seconds to get all the data else we timeout</span> m_bReceptionStarted = <span class="keyword">true</span>; } <span class="keywordflow">else</span> { <span class="keywordflow">if</span>(m_bTimedOut) <span class="comment">//The receive timer has expired...this is a timeout condition</span> { ResetReadTimeout(MAX_RXTIMEOUT); <span class="comment">//Clear the timeout flag</span> m_nLastBytesAvail = 0; <span class="comment">//Reset the flags</span> m_bReceptionStarted = <span class="keyword">false</span>; OnRxTimeout(); <span class="comment">//Do whatever 'we' do for a timeout (probably a flush or disconnect)...</span> <span class="keywordflow">return</span>; } } <span class="keywordflow">if</span>(m_nLastBytesAvail == nBytesAvail) <span class="comment">//Check if any more data has been received since last time</span> { <span class="comment">//No point in parsing unless this has changed!</span> <span class="comment">//Maybe yield in here!</span> <span class="comment">//Thread::yield();</span> <span class="keywordflow">if</span>(nBytesAvail == 0) <span class="comment">//If we have been called with 0 bytes available (twice now)</span> { <span class="comment">//a disconnection has occurred</span> <span class="keywordflow">if</span>(!m_bDoDisconnect) { CloseSocket(); <span class="comment">//Force the close</span> } } <span class="keywordflow">return</span>; } <span class="comment">//Depending on your application you may want to attempt to process the extra data</span> <span class="comment">//(or change your MAX_RXBUF).</span> <span class="comment">//</span> <span class="comment">//Here I just flush the whole lot, because I assume a 'legal' client wont send more than</span> <span class="comment">//we can receive....maybe someone is trying to flood / overrun us!</span> <span class="keywordflow">if</span>(nBytesAvail > MAX_RXBUF) { cerr << <span class="stringliteral">"TCP/IP overflow..."</span> << endl; FlushRxData(); m_nLastBytesAvail = 0; m_bReceptionStarted = <span class="keyword">false</span>; <span class="keywordflow">return</span>; } m_nLastBytesAvail = nBytesAvail; <span class="comment">//In this loop you may parse the received data to determine whether a whole</span> <span class="comment">//'packet' has arrived. What you do in here depends on what data you are sending.</span> <span class="comment">//Here we will just look for a /r/n terminator sequence.</span> <span class="keywordflow">for</span>(<span class="keywordtype">int</span> i=0; i < nBytesAvail; i++) { <span class="comment">/***************************SHOULD BE CUSTOMISED*******************/</span> <span class="keywordflow">if</span>(m_pBuf[i] == <span class="charliteral">'\r'</span>) { <span class="keywordflow">if</span>(i+1 < nBytesAvail) { <span class="keywordflow">if</span>(m_pBuf[i+1] == <span class="charliteral">'\n'</span>) { <span class="comment">//Terminator sequence found</span> <span class="comment">/**************************************************************/</span> <span class="comment">// COMPULSORY ... Clear the flag and count..</span> <span class="comment">// do this when you have received a good packet</span> m_nLastBytesAvail = 0; m_bReceptionStarted = <span class="keyword">false</span>; <span class="comment">/**************************************************************/</span> <span class="comment">// Now receive the data into a buffer and call our receive function</span> <span class="keywordtype">int</span> nLen = i+2; <span class="keywordtype">char</span> *pszRxData = <span class="keyword">new</span> <span class="keywordtype">char</span>[nLen+1]; <span class="comment">//Allow space for terminator</span> receive(pszRxData, nLen); <span class="comment">//Receive the data</span> pszRxData[nLen] = <span class="charliteral">'\0'</span>; <span class="comment">//Terminate it</span> OnDataReceived(pszRxData, nLen); <span class="keyword">delete</span> [] pszRxData; <span class="keywordflow">return</span>; } } } <span class="comment">/***************************END CUSTOMISATION*******************/</span> } } <span class="keywordtype">void</span> SampleSocketPort::disconnect(<span class="keywordtype">void</span>) { <span class="keywordflow">if</span>(m_bOpen) { m_bDoDisconnect = <span class="keyword">true</span>; CloseSocket(); } } <span class="keywordtype">void</span> SampleSocketPort::expired(<span class="keywordtype">void</span>) { <span class="keywordflow">if</span>(m_bDoDisconnect && m_bOpen) { CloseSocket(); } <span class="keywordflow">else</span> <span class="keywordflow">if</span>(m_bOpen && m_bReceptionStarted) { <span class="comment">//Timer must have expired because the rx data has not all been received</span> m_bTimedOut = <span class="keyword">true</span>; } } <span class="keywordtype">bool</span> SampleSocketPort::CloseSocket(<span class="keywordtype">void</span>) { <span class="keywordflow">if</span>(m_bOpen && m_bDoDisconnect) { <span class="comment">//This is where the disconnection really occurs</span> m_bOpen = <span class="keyword">false</span>; <span class="comment">//If m_bDoDisconnect == true we know this has been called</span> OnConnectionClosed(); <span class="comment">//through the timer, so 'delete this' is safe!</span> <span class="keyword">delete</span> <span class="keyword">this</span>; } <span class="keywordflow">else</span> <span class="keywordflow">if</span>(m_bOpen) { m_bDoDisconnect = <span class="keyword">true</span>; <span class="comment">//Just set the timer and the flag so we can</span> setTimer(DISCONNECT_MS); <span class="comment">//disconnect safely, in DISCONNECT_MS</span> } <span class="keywordflow">return</span>(<span class="keyword">true</span>); } ssize_t SampleSocketPort::DoSend(<span class="keywordtype">void</span> *buf, <span class="keywordtype">size_t</span> len) { <span class="comment">//If we are disconnecting, just pretend all the bytes were sent</span> <span class="keywordflow">if</span>(m_bDoDisconnect) <span class="keywordflow">return</span>((ssize_t)len); ssize_t nSent = send(buf, len); <span class="keywordflow">while</span>(!isPending(Socket::pendingOutput, 0)) <span class="comment">//Wait for output to complete</span> { <span class="keywordflow">if</span>(m_bDoDisconnect || !m_bOpen) { <span class="comment">//If we are disconnecting, just pretend all the bytes were sent</span> <span class="keywordflow">return</span>((ssize_t)len); } <span class="comment">//I like to yield whenever waiting for things...</span> <span class="comment">//this is optional and may not suit your implementation!</span> Thread::yield(); } <span class="keywordflow">return</span>(nSent); } <span class="keywordtype">bool</span> SampleSocketPort::WriteData(<span class="keyword">const</span> <span class="keywordtype">char</span> *szTxData, <span class="keyword">const</span> <span class="keywordtype">size_t</span> nByteCount) { <span class="comment">//First calculate how many bytes we are to send</span> ssize_t nLen = nByteCount; <span class="keywordflow">if</span>(nLen == -1) nLen = (ssize_t)strlen(szTxData); <span class="keywordtype">size_t</span> nBytesToSend = nLen; <span class="keywordflow">while</span>(m_bOpen && nLen) { nLen -= DoSend((<span class="keywordtype">void</span> *)&(szTxData[nBytesToSend - nLen]), nLen); } <span class="comment">// If we are sending a terminator.....uncomment the following lines</span> <span class="comment">// char chTerminator = '\n';</span> <span class="comment">// while(DoSend((void *)&chTerminator, 1) != 1);</span> <span class="keywordflow">return</span>(<span class="keyword">true</span>); } <span class="preprocessor">#define WITH_EXAMPLE</span> <span class="preprocessor"></span> <span class="preprocessor">#ifdef WITH_EXAMPLE</span> <span class="preprocessor"></span> <span class="comment">/************ THE FOLLOWING CODE DEMONSTRATES THE USE OF THE ABOVE CLASS ********************</span> <span class="comment"> ****</span> <span class="comment"> **** To test it, compile with:</span> <span class="comment"> ****</span> <span class="comment"> **** g++ SampleSocketPort.cpp -lccgnu -lpthread -ldl -oSampleSocketPort -ggdb -I/usr/local/include/cc++/</span> <span class="comment"> **** Run the program.</span> <span class="comment"> ****</span> <span class="comment"> **** From another terminal telnet to port 3999 of the server</span> <span class="comment"> ****</span> <span class="comment"> **** 'telnet localhost 3999'</span> <span class="comment"> ****</span> <span class="comment"> **** Anything you type should be sent back to you in reverse!</span> <span class="comment"> ****</span> <span class="comment"> **** To test the corrupt data detection, send a control code (like ^D),</span> <span class="comment"> **** if the terminating charcters are not detected within the specified time</span> <span class="comment"> **** the receive timeout will occur.</span> <span class="comment"> ****</span> <span class="comment"> ****/</span> <span class="comment">//define the following to include the example classes and functions</span> <span class="keywordtype">int</span> g_nOpenPorts = 0; <span class="comment">//Dirty global to allow us to quit simply</span> <span class="keyword">class </span>ReverserPort : <span class="keyword">public</span> SampleSocketPort { <span class="keyword">public</span>: ReverserPort(SocketService *pService, TCPSocket & tcpSocket) : SampleSocketPort(pService, tcpSocket) { g_nOpenPorts++; } <span class="keyword">virtual</span> ~ReverserPort() { g_nOpenPorts--; } <span class="keyword">virtual</span> <span class="keywordtype">void</span> OnConnectionClosed(<span class="keywordtype">void</span>) { cerr << <span class="stringliteral">"Connection Closed!"</span> << endl; } <span class="keyword">virtual</span> <span class="keywordtype">void</span> OnDataReceived(<span class="keywordtype">char</span> *pszData, <span class="keywordtype">unsigned</span> <span class="keywordtype">int</span> nByteCount) { <span class="comment">//Reverse the data and send it back</span> <span class="keywordtype">size_t</span> nLen = strlen(pszData); <span class="keywordtype">char</span> *szToSend = <span class="keyword">new</span> <span class="keywordtype">char</span>[nLen+1]; <span class="comment">//No need to reverse the \r\n or \0</span> <span class="keywordtype">size_t</span> nIndex = nLen-3; <span class="keywordtype">size_t</span> i; <span class="keywordflow">for</span>(i=0; i < nLen - 2; i++) { szToSend[i] = pszData[nIndex - i]; } szToSend[i++] = <span class="charliteral">'\r'</span>; szToSend[i++] = <span class="charliteral">'\n'</span>; szToSend[nLen] = <span class="charliteral">'\0'</span>; WriteData(szToSend, nLen); <span class="keyword">delete</span> [] szToSend; } }; <span class="keyword">class </span>ReverserServer : <span class="keyword">public</span> SampleSocketServiceServer { <span class="keyword">public</span>: ReverserServer(<a class="code" href="address_8h.html#a5eba36aa908d5a479c8ba7d0bc4512b1">InetHostAddress</a> & machine, <span class="keywordtype">int</span> port) : TCPSocket(machine, port), Thread(), SampleSocketServiceServer(machine, port) { } <span class="keyword">virtual</span> ~ReverserServer() { } <span class="keyword">virtual</span> SocketPort *CreateSocketPort(SocketService *pService, TCPSocket & Socket) { <span class="keywordflow">return</span>(<span class="keyword">new</span> ReverserPort(pService, Socket)); } }; <span class="keywordtype">int</span> main(<span class="keywordtype">void</span>) { <a class="code" href="address_8h.html#a5eba36aa908d5a479c8ba7d0bc4512b1">InetHostAddress</a> LocalHost; LocalHost = htonl(INADDR_ANY); ReverserServer *Server = NULL; <span class="keywordflow">try</span> { Server = <span class="keyword">new</span> ReverserServer(LocalHost, 3999); Server->StartServer(); } <span class="keywordflow">catch</span>(...) { cerr << <span class="stringliteral">"Failed to start server"</span> << endl; <span class="keywordflow">return</span>(<span class="keyword">false</span>); } cerr << <span class="stringliteral">"Waiting for connections...type \"quit\" to exit."</span> << endl; <span class="keywordtype">char</span> cmd[255]; cin.getline(cmd, 255); <span class="keywordflow">while</span>(strcmp(cmd, <span class="stringliteral">"quit"</span>) != 0) { cin.getline(cmd, 255); } Server->StopServer(); <span class="keyword">delete</span> Server; <span class="keywordflow">return</span> 0; } <span class="preprocessor">#endif //WITH_EXAMPLE</span> <span class="preprocessor"></span> </pre></div> </div> <hr class="footer"/><address style="text-align: right;"><small>Generated on Fri Mar 12 10:07:38 2010 for GNU CommonC++ by <a href="http://www.doxygen.org/index.html"> <img class="footer" src="doxygen.png" alt="doxygen"/></a> 1.6.3 </small></address> </body> </html>