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