SampleSocketPort.cpp

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

Generated on Tue Dec 4 13:39:21 2007 for GNU CommonC++ by  doxygen 1.5.2