\section{Sample\-Socket\-Port.cpp} \footnotesize\begin{verbatim}1 48 #include "SampleSocketPort.h" 49 50 SampleSocketPort::SampleSocketPort(SocketService *pService, TCPSocket & tcpSocket) : 51 SocketPort(pService, tcpSocket) 52 { 53 tpport_t port; 54 InetHostAddress ia = getPeer( & port ); 55 cerr << "connecting from " << ia.getHostname() << ":" << port << endl; 56 57 // Set up non-blocking reads 58 setCompletion( false ); 59 60 //1.9.3 THIS LINE DOES NOT SEEM TO BE REQUIRED ANYMORE! 61 //This sorts out a bug which prevents connections after a disconnect 62 //setDetectOutput(true); 63 64 m_bOpen = true; 65 m_bDoDisconnect = false; 66 m_bTimedOut = false; 67 m_bReceptionStarted = false; 68 m_nLastBytesAvail = 0; 69 m_pBuf = new char[MAX_RXBUF]; 70 } 71 72 73 SampleSocketPort::~SampleSocketPort() 74 { 75 endSocket(); 76 delete [] m_pBuf; 77 } 78 79 void SampleSocketPort::pending(void) 80 { 81 //cerr << "Pending called " << endl; 82 if(!m_bOpen) 83 return; 84 85 // Read all available bytes into our buffer 86 int nBytesAvail = peek(m_pBuf, MAX_RXBUF); 87 //cerr << "Pending .. " << nBytesAvail << endl; 88 89 if(!m_bReceptionStarted) 90 { //Start the receive timer 91 ResetReadTimeout(MAX_RXTIMEOUT); //Got 'n' seconds to get all the data else we timeout 92 m_bReceptionStarted = true; 93 } 94 else 95 { 96 if(m_bTimedOut) //The receive timer has expired...this is a timeout condition 97 { 98 ResetReadTimeout(MAX_RXTIMEOUT); //Clear the timeout flag 99 m_nLastBytesAvail = 0; //Reset the flags 100 m_bReceptionStarted = false; 101 OnRxTimeout(); //Do whatever 'we' do for a timeout (probably a flush or disconnect)... 102 return; 103 } 104 } 105 106 if(m_nLastBytesAvail == nBytesAvail) //Check if any more data has been received since last time 107 { //No point in parsing unless this has changed! 108 //Maybe yield in here! 109 //Thread::yield(); 110 if(nBytesAvail == 0) //If we have been called with 0 bytes available (twice now) 111 { //a disconnection has occurred 112 if(!m_bDoDisconnect) 113 { 114 CloseSocket(); //Force the close 115 } 116 } 117 return; 118 } 119 120 //Depending on your application you may want to attempt to process the extra data 121 //(or change your MAX_RXBUF). 122 // 123 //Here I just flush the whole lot, because I assume a 'legal' client wont send more than 124 //we can receive....maybe someone is trying to flood / overrun us! 125 if(nBytesAvail > MAX_RXBUF) 126 { 127 cerr << "TCP/IP overflow..." << endl; 128 FlushRxData(); 129 m_nLastBytesAvail = 0; 130 m_bReceptionStarted = false; 131 return; 132 } 133 m_nLastBytesAvail = nBytesAvail; 134 135 //In this loop you may parse the received data to determine whether a whole 136 //'packet' has arrived. What you do in here depends on what data you are sending. 137 //Here we will just look for a /r/n terminator sequence. 138 for(int i=0; i < nBytesAvail; i++) 139 { 140 141 /***************************SHOULD BE CUSTOMISED*******************/ 142 143 if(m_pBuf[i] == '\r') 144 { 145 if(i+1 < nBytesAvail) 146 { 147 if(m_pBuf[i+1] == '\n') 148 { //Terminator sequence found 149 150 /**************************************************************/ 151 // COMPULSORY ... Clear the flag and count.. 152 // do this when you have received a good packet 153 m_nLastBytesAvail = 0; 154 m_bReceptionStarted = false; 155 /**************************************************************/ 156 157 // Now receive the data into a buffer and call our receive function 158 int nLen = i+2; 159 char *pszRxData = new char[nLen+1]; //Allow space for terminator 160 receive(pszRxData, nLen); //Receive the data 161 pszRxData[nLen] = '\0'; //Terminate it 162 OnDataReceived(pszRxData, nLen); 163 delete [] pszRxData; 164 return; 165 } 166 } 167 } 168 /***************************END CUSTOMISATION*******************/ 169 170 } 171 } 172 173 void SampleSocketPort::disconnect(void) 174 { 175 if(m_bOpen) 176 { 177 m_bDoDisconnect = true; 178 CloseSocket(); 179 } 180 } 181 182 void SampleSocketPort::expired(void) 183 { 184 if(m_bDoDisconnect && m_bOpen) 185 { 186 CloseSocket(); 187 } 188 else if(m_bOpen && m_bReceptionStarted) 189 { 190 //Timer must have expired because the rx data has not all been received 191 m_bTimedOut = true; 192 } 193 } 194 195 196 bool SampleSocketPort::CloseSocket(void) 197 { 198 if(m_bOpen && m_bDoDisconnect) 199 { //This is where the disconnection really occurs 200 m_bOpen = false; //If m_bDoDisconnect == true we know this has been called 201 OnConnectionClosed(); //through the timer, so 'delete this' is safe! 202 delete this; 203 } 204 else if(m_bOpen) 205 { 206 m_bDoDisconnect = true; //Just set the timer and the flag so we can 207 setTimer(DISCONNECT_MS); //disconnect safely, in DISCONNECT_MS 208 } 209 return(true); 210 } 211 212 213 ssize_t SampleSocketPort::DoSend(void *buf, size_t len) 214 { 215 //If we are disconnecting, just pretend all the bytes were sent 216 if(m_bDoDisconnect) 217 return((ssize_t)len); 218 219 ssize_t nSent = send(buf, len); 220 while(!isPending(Socket::pendingOutput, 0)) //Wait for output to complete 221 { 222 if(m_bDoDisconnect || !m_bOpen) 223 { 224 //If we are disconnecting, just pretend all the bytes were sent 225 return((ssize_t)len); 226 } 227 //I like to yield whenever waiting for things... 228 //this is optional and may not suit your implementation! 229 Thread::yield(); 230 } 231 return(nSent); 232 } 233 234 bool SampleSocketPort::WriteData(const char *szTxData, const size_t nByteCount) 235 { 236 //First calculate how many bytes we are to send 237 ssize_t nLen = nByteCount; 238 239 if(nLen == -1) 240 nLen = (ssize_t)strlen(szTxData); 241 242 size_t nBytesToSend = nLen; 243 244 while(m_bOpen && nLen) 245 { 246 nLen -= DoSend((void *)&(szTxData[nBytesToSend - nLen]), nLen); 247 } 248 249 // If we are sending a terminator.....uncomment the following lines 250 // char chTerminator = '\n'; 251 // while(DoSend((void *)&chTerminator, 1) != 1); 252 253 return(true); 254 } 255 256 257 258 #define WITH_EXAMPLE 259 260 #ifdef WITH_EXAMPLE 261 262 263 /************ THE FOLLOWING CODE DEMONSTRATES THE USE OF THE ABOVE CLASS ******************** 264 **** 265 **** To test it, compile with: 266 **** 267 **** g++ SampleSocketPort.cpp -lccgnu -lpthread -ldl -oSampleSocketPort -ggdb -I/usr/local/include/cc++/ 268 **** Run the program. 269 **** 270 **** From another terminal telnet to port 3999 of the server 271 **** 272 **** 'telnet localhost 3999' 273 **** 274 **** Anything you type should be sent back to you in reverse! 275 **** 276 **** To test the corrupt data detection, send a control code (like ^D), 277 **** if the terminating charcters are not detected within the specified time 278 **** the receive timeout will occur. 279 **** 280 ****/ 281 282 283 //define the following to include the example classes and functions 284 285 int g_nOpenPorts = 0; //Dirty global to allow us to quit simply 286 287 class ReverserPort : public SampleSocketPort 288 { 289 public: 290 ReverserPort(SocketService *pService, TCPSocket & tcpSocket) : 291 SampleSocketPort(pService, tcpSocket) 292 { 293 g_nOpenPorts++; 294 } 295 virtual ~ReverserPort() 296 { 297 g_nOpenPorts--; 298 } 299 virtual void OnConnectionClosed(void) 300 { cerr << "Connection Closed!" << endl; } 301 306 virtual void OnDataReceived(char *pszData, unsigned int nByteCount) 307 { 308 //Reverse the data and send it back 309 310 size_t nLen = strlen(pszData); 311 char *szToSend = new char[nLen+1]; 312 313 //No need to reverse the \r\n or \0 314 size_t nIndex = nLen-3; 315 316 size_t i; 317 for(i=0; i < nLen - 2; i++) 318 { 319 szToSend[i] = pszData[nIndex - i]; 320 } 321 szToSend[i++] = '\r'; 322 szToSend[i++] = '\n'; 323 szToSend[nLen] = '\0'; 324 325 WriteData(szToSend, nLen); 326 delete [] szToSend; 327 } 328 329 }; 330 331 class ReverserServer : public SampleSocketServiceServer 332 { 333 public: 334 ReverserServer(InetHostAddress & machine, int port) : 335 TCPSocket(machine, port), Thread(), SampleSocketServiceServer(machine, port) 336 { 337 } 338 virtual ~ReverserServer() 339 { 340 } 341 virtual SocketPort *CreateSocketPort(SocketService *pService, TCPSocket & Socket) 342 { 343 return(new ReverserPort(pService, Socket)); 344 } 345 }; 346 347 348 int main(void) 349 { 350 InetHostAddress LocalHost; 351 LocalHost = htonl(INADDR_ANY); 352 ReverserServer *Server = NULL; 353 try 354 { 355 Server = new ReverserServer(LocalHost, 3999); 356 Server->StartServer(); 357 } 358 catch(...) 359 { 360 cerr << "Failed to start server" << endl; 361 return(false); 362 } 363 cerr << "Waiting for connections...type \"quit\" to exit." << endl; 364 365 char cmd[255]; 366 367 cin.getline(cmd, 255); 368 369 370 while(strcmp(cmd, "quit") != 0) 371 { 372 cin.getline(cmd, 255); 373 } 374 375 Server->StopServer(); 376 delete Server; 377 return 0; 378 } 379 380 #endif //WITH_EXAMPLE 381 \end{verbatim} \normalsize