NetServices Stack source

Dependents:   HelloWorld ServoInterfaceBoardExample1 4180_Lab4

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers lwipNetTcpSocket.cpp Source File

lwipNetTcpSocket.cpp

00001 
00002 /*
00003 Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
00004  
00005 Permission is hereby granted, free of charge, to any person obtaining a copy
00006 of this software and associated documentation files (the "Software"), to deal
00007 in the Software without restriction, including without limitation the rights
00008 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00009 copies of the Software, and to permit persons to whom the Software is
00010 furnished to do so, subject to the following conditions:
00011  
00012 The above copyright notice and this permission notice shall be included in
00013 all copies or substantial portions of the Software.
00014  
00015 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00016 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00017 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00018 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00019 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00020 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
00021 THE SOFTWARE.
00022 */
00023 
00024 #include "lwipNetTcpSocket.h"
00025 #include "lwip/tcp.h"
00026 
00027 //#define __DEBUG
00028 #include "dbg/dbg.h"
00029 
00030 #include "netCfg.h"
00031 #if NET_LWIP_STACK
00032 
00033 LwipNetTcpSocket::LwipNetTcpSocket(tcp_pcb* pPcb /*= NULL*/) : NetTcpSocket(), m_pPcb(pPcb), m_lpInNetTcpSocket(), //Passes a pcb if already created (by an accept req for instance), in that case transfers ownership
00034 m_pReadPbuf(NULL)
00035 {
00036   DBG("New NetTcpSocket %p\n", (void*)this);
00037   if(!m_pPcb)
00038   {
00039     m_pPcb = tcp_new();
00040     DBG("Creating new PCB %p\n", m_pPcb);
00041   }
00042   if(m_pPcb)
00043   {
00044     //Setup callbacks
00045     tcp_arg( (tcp_pcb*) m_pPcb, (void*) this ); //this will be passed to each static callback
00046     
00047     tcp_recv( (tcp_pcb*) m_pPcb, LwipNetTcpSocket::sRecvCb );
00048     tcp_sent((tcp_pcb*) m_pPcb, LwipNetTcpSocket::sSentCb );
00049     tcp_err( (tcp_pcb*) m_pPcb, LwipNetTcpSocket::sErrCb );
00050     //Connected callback is defined in connect()
00051     //Accept callback is defined in listen()
00052     DBG("NetTcpSocket created.\n");
00053   }
00054 }
00055 
00056 LwipNetTcpSocket::~LwipNetTcpSocket()
00057 {
00058 /*  if(m_pPcb)
00059     tcp_close( (tcp_pcb*) m_pPcb); //Disconnect & free pcb*/
00060   close();
00061 }
00062   
00063 NetTcpSocketErr LwipNetTcpSocket::bind(const Host& me)
00064 {
00065   if(!m_pPcb)
00066     return NETTCPSOCKET_MEM; //NetTcpSocket was not properly initialised, should destroy it & retry
00067     
00068   err_t err = tcp_bind( (tcp_pcb*) m_pPcb, IP_ADDR_ANY, me.getPort()); //IP_ADDR_ANY : Bind the connection to all local addresses
00069   if(err)
00070     return NETTCPSOCKET_INUSE;
00071     
00072   return NETTCPSOCKET_OK;
00073 }
00074 
00075 NetTcpSocketErr LwipNetTcpSocket::listen()
00076 {
00077   if(!m_pPcb)
00078     return NETTCPSOCKET_MEM; //NetTcpSocket was not properly initialised, should destroy it & retry
00079 /*
00080   From doc/rawapi.txt :
00081   
00082   The tcp_listen() function returns a new connection identifier, and
00083   the one passed as an argument to the function will be
00084   deallocated. The reason for this behavior is that less memory is
00085   needed for a connection that is listening, so tcp_listen() will
00086   reclaim the memory needed for the original connection and allocate a
00087   new smaller memory block for the listening connection.
00088 */
00089 
00090 //  tcp_pcb* pNewPcb = tcp_listen(m_pPcb);
00091   tcp_pcb* pNewPcb = tcp_listen_with_backlog((tcp_pcb*)m_pPcb, 5);
00092   if( !pNewPcb ) //Not enough memory to create the listening pcb
00093     return NETTCPSOCKET_MEM;
00094 
00095   m_pPcb = pNewPcb;
00096   
00097   tcp_accept( (tcp_pcb*) m_pPcb, LwipNetTcpSocket::sAcceptCb );
00098 
00099   return NETTCPSOCKET_OK;
00100 }
00101 
00102 NetTcpSocketErr LwipNetTcpSocket::connect(const Host& host)
00103 {
00104   if(!m_pPcb)
00105     return NETTCPSOCKET_MEM; //NetTcpSocket was not properly initialised, should destroy it & retry
00106   
00107   ip_addr_t ip = host.getIp().getStruct();
00108   err_t err = tcp_connect( (tcp_pcb*) m_pPcb, &ip, host.getPort(), LwipNetTcpSocket::sConnectedCb );
00109   
00110   if(err)
00111     return NETTCPSOCKET_MEM;
00112     
00113   return NETTCPSOCKET_OK;
00114 }
00115 
00116 NetTcpSocketErr LwipNetTcpSocket::accept(Host* pClient, NetTcpSocket** ppNewNetTcpSocket)
00117 {
00118   if( !m_pPcb ) //Pcb doesn't exist (anymore)
00119     return NETTCPSOCKET_MEM;
00120   //Dequeue a connection
00121   //if( m_lpInPcb.empty() )
00122   if( m_lpInNetTcpSocket.empty() )
00123     return NETTCPSOCKET_EMPTY;
00124   
00125   tcp_accepted( ((tcp_pcb*) m_pPcb) ); //Should fire proper events //WARN: m_pPcb is the GOOD param here (and not pInPcb)
00126   
00127 /*  tcp_pcb* pInPcb = m_lpInPcb.front();
00128   m_lpInPcb.pop();*/
00129   
00130   if( (m_lpInNetTcpSocket.front()) == NULL )
00131   {
00132     m_lpInNetTcpSocket.pop();
00133     return NETTCPSOCKET_RST;
00134   }
00135   
00136   if( (m_lpInNetTcpSocket.front())->m_closed )
00137   {
00138     Net::releaseTcpSocket(m_lpInNetTcpSocket.front());
00139     m_lpInNetTcpSocket.pop();
00140     return NETTCPSOCKET_RST;
00141   }
00142   
00143   ip_addr_t* ip = (ip_addr_t*) &( (m_lpInNetTcpSocket.front()->m_pPcb)->remote_ip);
00144   
00145   *ppNewNetTcpSocket = m_lpInNetTcpSocket.front();
00146   *pClient = Host(
00147     IpAddr( 
00148       ip
00149     ), 
00150     m_lpInNetTcpSocket.front()->m_pPcb->remote_port 
00151   );
00152   m_lpInNetTcpSocket.pop();
00153 //  *pClient = Host( IpAddr(pInPcb->remote_ip), pInPcb->remote_port );
00154   
00155   //Return a new socket
00156  // *ppNewNetTcpSocket = (NetTcpSocket*) new LwipNetTcpSocket(pInPcb);
00157 
00158   //tcp_accepted( ((tcp_pcb*) m_pPcb) ); //Should fire proper events //WARN: m_pPcb is the GOOD param here (and not pInPcb)
00159   
00160 /*  if(*ppNewNetTcpSocket == NULL)
00161   {
00162     DBG("Not enough mem, socket dropped in LwipNetTcpSocket::accept.\n");
00163     tcp_abort(pInPcb);
00164   }*/
00165   
00166   return NETTCPSOCKET_OK;
00167 }
00168 
00169 #define MAX(a,b) (((a)>(b))?(a):(b))
00170 #define MIN(a,b) (((a)<(b))?(a):(b))
00171 
00172 int /*if < 0 : NetTcpSocketErr*/ LwipNetTcpSocket::send(const char* buf, int len)
00173 {
00174   if( !m_pPcb ) //Pcb doesn't exist (anymore)
00175     return NETTCPSOCKET_MEM;
00176   int outLen = MIN( len, tcp_sndbuf( (tcp_pcb*) m_pPcb) ); 
00177   //tcp_sndbuf() returns the number of bytes available in the output queue, so never go above it
00178   err_t err = tcp_write( (tcp_pcb*) m_pPcb, (void*) buf, outLen, TCP_WRITE_FLAG_COPY );
00179   //Flags are TCP_WRITE_FLAG_COPY & TCP_WRITE_FLAG_MORE (see tcp_out.c) :
00180   //If TCP_WRITE_FLAG_MORE is not set ask client to push buffered data to app
00181   if(err)
00182   {
00183     switch( err )
00184     {
00185     case ERR_CONN:
00186       return (int) NETTCPSOCKET_SETUP; //Not connected properly
00187     case ERR_ARG:
00188       return (int) NETTCPSOCKET_SETUP; //Wrong args ! (like buf pointing to NULL)
00189     case ERR_MEM:
00190     default:
00191       return (int) NETTCPSOCKET_MEM; //Not enough memory
00192     }
00193   }
00194   return outLen;
00195 }
00196 
00197 int /*if < 0 : NetTcpSocketErr*/ LwipNetTcpSocket::recv(char* buf, int len)
00198 {
00199   if( !m_pPcb ) //Pcb doesn't exist (anymore)
00200     return NETTCPSOCKET_MEM;
00201   int inLen = 0;
00202   int cpyLen = 0;
00203   
00204   static int rmgLen = 0; 
00205   //Contains the remaining len in this pbuf
00206   
00207   if( !m_pReadPbuf )
00208   {
00209     rmgLen = 0;
00210     return 0;
00211   }
00212   
00213   if ( !rmgLen ) //We did not know m_pReadPbuf->len last time we called this fn
00214   {
00215     rmgLen = m_pReadPbuf->len;
00216   }
00217   
00218   while ( inLen < len )
00219   {
00220     cpyLen = MIN( (len - inLen), rmgLen ); //Remaining len to copy, remaining len in THIS pbuf
00221     memcpy((void*)buf, (void*)((char*)(m_pReadPbuf->payload) + (m_pReadPbuf->len - rmgLen)), cpyLen);
00222     inLen += cpyLen;
00223     buf += cpyLen;
00224     
00225     rmgLen = rmgLen - cpyLen; //Update rmgLen
00226     
00227     if( rmgLen > 0 )
00228     {
00229       //We did not read this pbuf completely, so let's save it's pos & return
00230       break;
00231     }
00232     
00233     if(m_pReadPbuf->next)
00234     {
00235       pbuf* pNextPBuf = m_pReadPbuf->next;
00236       m_pReadPbuf->next = NULL; //So that it is not freed as well
00237       //We get the reference to pNextPBuf from m_pReadPbuf
00238       pbuf_free((pbuf*)m_pReadPbuf);
00239       m_pReadPbuf = pNextPBuf;
00240       rmgLen = m_pReadPbuf->len;
00241     }
00242     else
00243     {
00244       pbuf_free((pbuf*)m_pReadPbuf);
00245       m_pReadPbuf = NULL;
00246       rmgLen = 0;
00247       break; //No more data to read
00248     }
00249     
00250   }
00251   
00252   //tcp_recved(m_pPcb, inLen); //Acknowledge the reception
00253   
00254   return inLen;
00255 }
00256 
00257 NetTcpSocketErr LwipNetTcpSocket::close()
00258 {
00259   //DBG("LwipNetTcpSocket::close() : Closing...\n");
00260 
00261   if(m_closed)
00262     return NETTCPSOCKET_OK; //Already being closed
00263   m_closed = true;
00264   
00265   if( !m_pPcb ) //Pcb doesn't exist (anymore)
00266     return NETTCPSOCKET_MEM;
00267     
00268   //Cleanup incoming data
00269   cleanUp();
00270  
00271   if( !!tcp_close( (tcp_pcb*) m_pPcb) )
00272   {
00273     DBG("LwipNetTcpSocket::close() could not close properly, abort.\n");
00274     tcp_abort( (tcp_pcb*) m_pPcb);
00275     m_pPcb = NULL;
00276     return NETTCPSOCKET_MEM;
00277   }
00278   
00279   DBG("LwipNetTcpSocket::close() : connection closed successfully.\n");
00280   
00281   m_pPcb = NULL;
00282   return NETTCPSOCKET_OK;
00283 }
00284 
00285 NetTcpSocketErr LwipNetTcpSocket::poll()
00286 {
00287   NetTcpSocket::flushEvents();
00288   return NETTCPSOCKET_OK;
00289 }
00290 
00291 // Callbacks events
00292 
00293 err_t LwipNetTcpSocket::acceptCb(struct tcp_pcb *newpcb, err_t err)
00294 {
00295   if(err)
00296   {
00297     DBG("Error %d in LwipNetTcpSocket::acceptCb.\n", err);
00298     return err;
00299   }
00300   //FIXME: MEM Errs
00301   //m_lpInPcb.push(newpcb); //Add connection to the queue
00302   LwipNetTcpSocket* pNewNetTcpSocket = new LwipNetTcpSocket(newpcb);
00303   
00304   if(pNewNetTcpSocket == NULL)
00305   {
00306     DBG("Not enough mem, socket dropped in LwipNetTcpSocket::acceptCb.\n");
00307     tcp_abort(newpcb);
00308     return ERR_ABRT;
00309   }
00310   
00311   pNewNetTcpSocket->m_refs++;
00312   m_lpInNetTcpSocket.push( pNewNetTcpSocket );
00313   
00314  // tcp_accepted(newpcb);
00315  // tcp_accepted( m_pPcb ); //Should fire proper events //WARN: m_pPcb is the GOOD param here (and not pInPcb)
00316   queueEvent(NETTCPSOCKET_ACCEPT);
00317   return ERR_OK;
00318 }
00319 
00320 err_t LwipNetTcpSocket::connectedCb(struct tcp_pcb *tpcb, err_t err)
00321 {
00322   queueEvent(NETTCPSOCKET_CONNECTED);
00323   return ERR_OK;
00324 }
00325 
00326 void LwipNetTcpSocket::errCb(err_t err)
00327 {
00328   DBG("NetTcpSocket %p - Error %d in LwipNetTcpSocket::errCb.\n", (void*)this, err);
00329   //WARN: At this point, m_pPcb has been freed by lwIP
00330   m_pPcb = NULL;
00331   //These errors are fatal, discard all events queued before so that the errors are handled first
00332   discardEvents();
00333   m_closed = true;
00334   cleanUp();
00335   if( err == ERR_ABRT)
00336     queueEvent(NETTCPSOCKET_CONABRT);
00337   else //if( err == ERR_RST)
00338     queueEvent(NETTCPSOCKET_CONRST);
00339 }
00340   
00341 err_t LwipNetTcpSocket::sentCb(tcp_pcb* tpcb, u16_t len)
00342 {
00343 //  DBG("%d bytes ACKed by host.\n", len);
00344   queueEvent(NETTCPSOCKET_WRITEABLE);
00345   return ERR_OK;
00346 }
00347 
00348 err_t LwipNetTcpSocket::recvCb(tcp_pcb* tpcb, pbuf *p, err_t err)
00349 {
00350   //Store pbuf ptr
00351  // DBG("Receive CB with err = %d & len = %d.\n", err, p->tot_len);
00352 //  tcp_recved( (tcp_pcb*) m_pPcb, p->tot_len); //Acknowledge the reception
00353   
00354   if(err)
00355   {
00356     queueEvent(NETTCPSOCKET_ERROR);
00357     return ERR_OK; //FIXME: More robust error handling there
00358   }
00359   else if(!p)
00360   {
00361     DBG("NetTcpSocket %p - Connection closed by remote host (LwipNetTcpSocket::recvCb).\n", (void*)this);
00362     //Buf is NULL, that means that the connection has been closed by remote host
00363     
00364     //FIX: 27/05/2010: We do not want to deallocate the socket while some data might still be readable
00365     //REMOVED:   close();
00366  
00367     //However we do not want to close the socket yet
00368  
00369     queueEvent(NETTCPSOCKET_DISCONNECTED);
00370     return ERR_OK; 
00371   }
00372   
00373   //We asserted that p is a valid pointer
00374 
00375   //New data processing
00376   tcp_recved( tpcb, p->tot_len); //Acknowledge the reception
00377   if(!m_pReadPbuf)
00378   {
00379     m_pReadPbuf = p;
00380     queueEvent(NETTCPSOCKET_READABLE);
00381   }
00382   else
00383   {
00384     pbuf_cat((pbuf*)m_pReadPbuf, p); //m_pReadPbuf is not empty, tail p to it and drop our ref
00385     //No need to queue an event in that case since the read buf has not been processed yet
00386   }
00387   return ERR_OK;
00388 }
00389 
00390 
00391 void LwipNetTcpSocket::cleanUp() //Flush input buffer
00392 {
00393   //Ensure that further error won't be followed to this inst (which can be destroyed)
00394   if( m_pPcb )
00395   {
00396     tcp_arg( (tcp_pcb*) m_pPcb, (void*) NULL );
00397     tcp_recv( (tcp_pcb*) m_pPcb, NULL );
00398     tcp_sent((tcp_pcb*) m_pPcb, NULL );
00399     tcp_err( (tcp_pcb*) m_pPcb, NULL );
00400   }
00401   
00402   if( m_pReadPbuf )
00403   {
00404     DBG("Deallocating unread data.\n");
00405     pbuf_free((pbuf*)m_pReadPbuf); //Free all unread data
00406     m_pReadPbuf = NULL;
00407     recv(NULL,0); //Update recv ptr position
00408   }
00409 }
00410 
00411 // Static callbacks from LwIp
00412 
00413 err_t LwipNetTcpSocket::sAcceptCb(void *arg, struct tcp_pcb *newpcb, err_t err)
00414 {
00415   LwipNetTcpSocket* pMe = (LwipNetTcpSocket*) arg;
00416   return pMe->acceptCb( newpcb, err );
00417 }
00418 
00419 err_t LwipNetTcpSocket::sConnectedCb(void *arg, struct tcp_pcb *tpcb, err_t err)
00420 {
00421   LwipNetTcpSocket* pMe = (LwipNetTcpSocket*) arg;
00422   return pMe->connectedCb( tpcb, err );
00423 }
00424 
00425 void LwipNetTcpSocket::sErrCb(void *arg, err_t err)
00426 {
00427   if( !arg )
00428   {
00429     DBG("NetTcpSocket - Error %d in LwipNetTcpSocket::sErrCb.\n", err);
00430     return; //The socket has been destroyed, discard error
00431   }
00432   LwipNetTcpSocket* pMe = (LwipNetTcpSocket*) arg;
00433   return pMe->errCb( err );
00434 }
00435   
00436 err_t LwipNetTcpSocket::sSentCb(void *arg, struct tcp_pcb *tpcb, u16_t len)
00437 {
00438   LwipNetTcpSocket* pMe = (LwipNetTcpSocket*) arg;
00439   return pMe->sentCb( tpcb, len );
00440 }
00441 
00442 err_t LwipNetTcpSocket::sRecvCb(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
00443 {
00444   if( tpcb->flags & TF_RXCLOSED )
00445   {
00446     //The Pcb is in a closing state
00447     //Discard that data here since we might have destroyed the corresponding socket object
00448     tcp_recved( tpcb, p->tot_len);
00449     pbuf_free( p );    
00450     return ERR_OK;
00451   }
00452   LwipNetTcpSocket* pMe = (LwipNetTcpSocket*) arg;
00453   return pMe->recvCb( tpcb, p, err );
00454 }
00455 
00456 #endif