SampleSocketPort.cpp

00001 
00048 #include "SampleSocketPort.h"
00049 
00050 SampleSocketPort::SampleSocketPort(SocketService *pService, TCPSocket & tcpSocket) : 
00051                                 SocketPort(pService, tcpSocket)
00052 {
00053         tpport_t port;
00054         InetHostAddress ia = getPeer( & port );
00055         cerr << "connecting from " << ia.getHostname() << ":" << port << endl;
00056 
00057         // Set up non-blocking reads
00058         setCompletion( false );
00059 
00060         //1.9.3 THIS LINE DOES NOT SEEM TO BE REQUIRED ANYMORE!
00061         //This sorts out a bug which prevents connections after a disconnect
00062         //setDetectOutput(true);
00063 
00064         m_bOpen = true;
00065         m_bDoDisconnect = false;
00066         m_bTimedOut = false;
00067         m_bReceptionStarted = false;
00068         m_nLastBytesAvail = 0;
00069         m_pBuf = new char[MAX_RXBUF];
00070 }
00071 
00072 
00073 SampleSocketPort::~SampleSocketPort()
00074 {
00075         endSocket();
00076         delete [] m_pBuf;
00077 }
00078 
00079 void SampleSocketPort::pending(void)
00080 {
00081 //cerr << "Pending called " << endl;
00082         if(!m_bOpen)
00083                 return;
00084 
00085         // Read all available bytes into our buffer
00086         int nBytesAvail = peek(m_pBuf, MAX_RXBUF);
00087 //cerr << "Pending .. " << nBytesAvail << endl;
00088 
00089         if(!m_bReceptionStarted)
00090         {       //Start the receive timer
00091                 ResetReadTimeout(MAX_RXTIMEOUT);        //Got 'n' seconds to get all the data else we timeout
00092                 m_bReceptionStarted = true;
00093         }
00094         else
00095         {
00096                 if(m_bTimedOut) //The receive timer has expired...this is a timeout condition
00097                 {
00098                         ResetReadTimeout(MAX_RXTIMEOUT); //Clear the timeout flag
00099                         m_nLastBytesAvail = 0;          //Reset the flags
00100                         m_bReceptionStarted = false;
00101                         OnRxTimeout();  //Do whatever 'we' do for a timeout (probably a flush or disconnect)...
00102                         return;
00103                 }
00104         }
00105 
00106         if(m_nLastBytesAvail == nBytesAvail)    //Check if any more data has been received since last time
00107         {                                                                               //No point in parsing unless this has changed!
00108                 //Maybe yield in here!
00109                 //Thread::yield();
00110                 if(nBytesAvail == 0)            //If we have been called with 0 bytes available (twice now)
00111                 {                                                       //a disconnection has occurred
00112                         if(!m_bDoDisconnect)
00113                         {
00114                                 CloseSocket();  //Force the close
00115                         }
00116                 }
00117                 return;
00118         }
00119 
00120         //Depending on your application you may want to attempt to process the extra data 
00121         //(or change your MAX_RXBUF).
00122         //
00123         //Here I just flush the whole lot, because I assume a 'legal' client wont send more than
00124         //we can receive....maybe someone is trying to flood / overrun us!
00125         if(nBytesAvail > MAX_RXBUF)     
00126         {
00127                 cerr << "TCP/IP overflow..." << endl;
00128                 FlushRxData();
00129                 m_nLastBytesAvail = 0;
00130                 m_bReceptionStarted = false;
00131                 return;
00132         }
00133         m_nLastBytesAvail = nBytesAvail;
00134 
00135         //In this loop you may parse the received data to determine whether a whole
00136         //'packet' has arrived. What you do in here depends on what data you are sending.
00137         //Here we will just look for a /r/n terminator sequence.
00138         for(int i=0; i < nBytesAvail; i++)
00139         {
00140 
00141 /***************************SHOULD BE CUSTOMISED*******************/
00142 
00143                 if(m_pBuf[i] == '\r')
00144                 {
00145                         if(i+1 < nBytesAvail)
00146                         {
00147                                 if(m_pBuf[i+1] == '\n')
00148                                 {       //Terminator sequence found
00149 
00150                                         /**************************************************************/
00151                                         // COMPULSORY ... Clear the flag and count..
00152                                         // do this when you have received a good packet
00153                                         m_nLastBytesAvail = 0;
00154                                         m_bReceptionStarted = false;
00155                                         /**************************************************************/
00156 
00157                                         // Now receive the data into a buffer and call our receive function
00158                                         int nLen = i+2;
00159                                         char *pszRxData = new char[nLen+1];     //Allow space for terminator
00160                                         receive(pszRxData, nLen);               //Receive the data
00161                                         pszRxData[nLen] = '\0';         //Terminate it
00162                                         OnDataReceived(pszRxData, nLen);
00163                                         delete [] pszRxData;
00164                                         return;
00165                                 }
00166                         }
00167                 }
00168 /***************************END CUSTOMISATION*******************/
00169 
00170         }
00171 }
00172 
00173 void SampleSocketPort::disconnect(void)
00174 {
00175         if(m_bOpen)
00176         {
00177                 m_bDoDisconnect = true;
00178                 CloseSocket();
00179         }
00180 }
00181 
00182 void SampleSocketPort::expired(void)
00183 {
00184         if(m_bDoDisconnect && m_bOpen)
00185         {
00186                 CloseSocket();
00187         }
00188         else if(m_bOpen && m_bReceptionStarted)
00189         {
00190                 //Timer must have expired because the rx data has not all been received
00191                 m_bTimedOut = true;
00192         }
00193 }
00194 
00195 
00196 bool SampleSocketPort::CloseSocket(void)
00197 {
00198         if(m_bOpen && m_bDoDisconnect)
00199         {                                                                       //This is where the disconnection really occurs
00200                 m_bOpen = false;                                //If m_bDoDisconnect == true we know this has been called 
00201                 OnConnectionClosed();                   //through the timer, so 'delete this' is safe!
00202                 delete this;
00203         }
00204         else if(m_bOpen)
00205         {
00206                 m_bDoDisconnect = true;                 //Just set the timer and the flag so we can 
00207                 setTimer(DISCONNECT_MS);                //disconnect safely, in DISCONNECT_MS
00208         }
00209         return(true);
00210 }
00211 
00212 
00213 ssize_t SampleSocketPort::DoSend(void *buf, size_t len)
00214 {
00215         //If we are disconnecting, just pretend all the bytes were sent
00216         if(m_bDoDisconnect)
00217                 return((ssize_t)len);
00218 
00219         ssize_t nSent = send(buf, len);
00220         while(!isPending(Socket::pendingOutput, 0))             //Wait for output to complete
00221         {
00222                 if(m_bDoDisconnect || !m_bOpen)
00223                 {
00224                         //If we are disconnecting, just pretend all the bytes were sent
00225                         return((ssize_t)len);
00226                 }
00227                 //I like to yield whenever waiting for things...
00228                 //this is optional and may not suit your implementation!
00229                 Thread::yield();
00230         }
00231         return(nSent);
00232 }
00233 
00234 bool SampleSocketPort::WriteData(const char *szTxData, const size_t nByteCount)
00235 {
00236         //First calculate how many bytes we are to send
00237         ssize_t nLen = nByteCount;
00238 
00239         if(nLen == -1)
00240                 nLen = (ssize_t)strlen(szTxData);
00241 
00242         size_t nBytesToSend = nLen;
00243 
00244         while(m_bOpen && nLen)
00245         {
00246                 nLen -= DoSend((void *)&(szTxData[nBytesToSend - nLen]), nLen);
00247         }
00248 
00249 //      If we are sending a terminator.....uncomment the following lines
00250 //      char chTerminator = '\n';
00251 //      while(DoSend((void *)&chTerminator, 1) != 1);
00252 
00253         return(true);
00254 }
00255 
00256 
00257 
00258 #define WITH_EXAMPLE
00259 
00260 #ifdef WITH_EXAMPLE
00261 
00262 
00263 /************ THE FOLLOWING CODE DEMONSTRATES THE USE OF THE ABOVE CLASS ********************
00264  ****
00265  ****   To test it, compile with:
00266  ****           
00267  ****   g++ SampleSocketPort.cpp -lccgnu -lpthread -ldl -oSampleSocketPort -ggdb -I/usr/local/include/cc++/
00268  ****   Run the program.
00269  ****   
00270  ****   From another terminal telnet to port 3999 of the server
00271  ****   
00272  ****           'telnet localhost 3999'
00273  ****           
00274  ****   Anything you type should be sent back to you in reverse!
00275  ****   
00276  ****   To test the corrupt data detection, send a control code (like ^D),
00277  ****   if the terminating charcters are not detected within the specified time
00278  ****   the receive timeout will occur.
00279  ****   
00280  ****/
00281 
00282 
00283 //define the following to include the example classes and functions
00284 
00285 int g_nOpenPorts = 0;                   //Dirty global to allow us to quit simply
00286 
00287 class ReverserPort : public SampleSocketPort
00288 {
00289 public:
00290         ReverserPort(SocketService *pService, TCPSocket & tcpSocket) : 
00291                         SampleSocketPort(pService, tcpSocket)
00292         {
00293                 g_nOpenPorts++;
00294         }
00295         virtual ~ReverserPort()
00296         {
00297                 g_nOpenPorts--;
00298         }
00299         virtual void OnConnectionClosed(void)
00300         { cerr << "Connection Closed!" << endl; }
00301 
00306         virtual void OnDataReceived(char *pszData, unsigned int nByteCount)
00307         {
00308                 //Reverse the data and send it back
00309 
00310                 size_t nLen = strlen(pszData);
00311                 char *szToSend = new char[nLen+1];
00312                 
00313                 //No need to reverse the \r\n or \0
00314                 size_t nIndex = nLen-3;
00315 
00316                 size_t i;
00317                 for(i=0; i < nLen - 2; i++)
00318                 {
00319                         szToSend[i] = pszData[nIndex - i];
00320                 }
00321                 szToSend[i++] = '\r';
00322                 szToSend[i++] = '\n';
00323                 szToSend[nLen] = '\0';
00324 
00325                 WriteData(szToSend, nLen);
00326                 delete [] szToSend;
00327         }
00328 
00329 };
00330 
00331 class ReverserServer : public SampleSocketServiceServer
00332 {
00333 public:
00334         ReverserServer(InetHostAddress & machine, int port) : 
00335         TCPSocket(machine, port), Thread(), SampleSocketServiceServer(machine, port)
00336         {
00337         }
00338         virtual ~ReverserServer()
00339         {
00340         }
00341         virtual SocketPort *CreateSocketPort(SocketService *pService, TCPSocket & Socket)
00342         {
00343                 return(new ReverserPort(pService, Socket));
00344         }
00345 };
00346 
00347 
00348 int main(void)
00349 {
00350         InetHostAddress LocalHost;
00351         LocalHost = htonl(INADDR_ANY);
00352         ReverserServer *Server = NULL;
00353         try
00354         {
00355                 Server = new ReverserServer(LocalHost, 3999);
00356                 Server->StartServer();
00357         }
00358         catch(...)
00359         {
00360                 cerr << "Failed to start server" << endl;
00361                 return(false);
00362         }
00363         cerr << "Waiting for connections...type \"quit\" to exit." << endl;
00364 
00365         char cmd[255];
00366  
00367         cin.getline(cmd, 255);
00368 
00369 
00370         while(strcmp(cmd, "quit") != 0)
00371         {
00372                 cin.getline(cmd, 255);
00373         }
00374  
00375         Server->StopServer();
00376         delete Server;
00377         return 0;       
00378 }
00379 
00380 #endif  //WITH_EXAMPLE
00381 

Generated on Thu Nov 9 19:34:53 2006 for GNU CommonC++ by  doxygen 1.5.1