Fork of NetServicesMin with some warnings removed

Dependencies:   lwip-sys lwip

Fork of NetServicesMin by Hendrik Lipka

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 
00329   DBG("NetTcpSocket %p - Error %d in LwipNetTcpSocket::errCb.\n", (void*)this, err);
00330   //WARN: At this point, m_pPcb has been freed by lwIP
00331   m_pPcb = NULL;
00332   //These errors are fatal, discard all events queued before so that the errors are handled first
00333   discardEvents();
00334   m_closed = true;
00335   cleanUp();
00336   if( err == ERR_ABRT)
00337     queueEvent(NETTCPSOCKET_CONABRT);
00338   else //if( err == ERR_RST)
00339     queueEvent(NETTCPSOCKET_CONRST);
00340 }
00341   
00342 err_t LwipNetTcpSocket::sentCb(tcp_pcb* tpcb, u16_t len)
00343 {
00344 //  DBG("%d bytes ACKed by host.\n", len);
00345   queueEvent(NETTCPSOCKET_WRITEABLE);
00346   return ERR_OK;
00347 }
00348 
00349 err_t LwipNetTcpSocket::recvCb(tcp_pcb* tpcb, pbuf *p, err_t err)
00350 {
00351   //Store pbuf ptr
00352  // DBG("Receive CB with err = %d & len = %d.\n", err, p->tot_len);
00353 //  tcp_recved( (tcp_pcb*) m_pPcb, p->tot_len); //Acknowledge the reception
00354   
00355   if(err)
00356   {
00357     queueEvent(NETTCPSOCKET_ERROR);
00358     return ERR_OK; //FIXME: More robust error handling there
00359   }
00360   else if(!p)
00361   {
00362     DBG("NetTcpSocket %p - Connection closed by remote host (LwipNetTcpSocket::recvCb).\n", (void*)this);
00363     //Buf is NULL, that means that the connection has been closed by remote host
00364     
00365     //FIX: 27/05/2010: We do not want to deallocate the socket while some data might still be readable
00366     //REMOVED:   close();
00367  
00368     //However we do not want to close the socket yet
00369  
00370     queueEvent(NETTCPSOCKET_DISCONNECTED);
00371     return ERR_OK; 
00372   }
00373   
00374   //We asserted that p is a valid pointer
00375 
00376   //New data processing
00377   tcp_recved( tpcb, p->tot_len); //Acknowledge the reception
00378   if(!m_pReadPbuf)
00379   {
00380     m_pReadPbuf = p;
00381     queueEvent(NETTCPSOCKET_READABLE);
00382   }
00383   else
00384   {
00385     pbuf_cat((pbuf*)m_pReadPbuf, p); //m_pReadPbuf is not empty, tail p to it and drop our ref
00386     //No need to queue an event in that case since the read buf has not been processed yet
00387   }
00388   return ERR_OK;
00389 }
00390 
00391 
00392 void LwipNetTcpSocket::cleanUp() //Flush input buffer
00393 {
00394   //Ensure that further error won't be followed to this inst (which can be destroyed)
00395   if( m_pPcb )
00396   {
00397     tcp_arg( (tcp_pcb*) m_pPcb, (void*) NULL );
00398     tcp_recv( (tcp_pcb*) m_pPcb, NULL );
00399     tcp_sent((tcp_pcb*) m_pPcb, NULL );
00400     tcp_err( (tcp_pcb*) m_pPcb, NULL );
00401   }
00402   
00403   if( m_pReadPbuf )
00404   {
00405     DBG("Deallocating unread data.\n");
00406     pbuf_free((pbuf*)m_pReadPbuf); //Free all unread data
00407     m_pReadPbuf = NULL;
00408     recv(NULL,0); //Update recv ptr position
00409   }
00410 }
00411 
00412 // Static callbacks from LwIp
00413 
00414 err_t LwipNetTcpSocket::sAcceptCb(void *arg, struct tcp_pcb *newpcb, err_t err)
00415 {
00416   LwipNetTcpSocket* pMe = (LwipNetTcpSocket*) arg;
00417   return pMe->acceptCb( newpcb, err );
00418 }
00419 
00420 err_t LwipNetTcpSocket::sConnectedCb(void *arg, struct tcp_pcb *tpcb, err_t err)
00421 {
00422   LwipNetTcpSocket* pMe = (LwipNetTcpSocket*) arg;
00423   return pMe->connectedCb( tpcb, err );
00424 }
00425 
00426 void LwipNetTcpSocket::sErrCb(void *arg, err_t err)
00427 {
00428   if( !arg )
00429   {
00430     DBG("NetTcpSocket - Error %d in LwipNetTcpSocket::sErrCb.\n", err);
00431     return; //The socket has been destroyed, discard error
00432   }
00433   LwipNetTcpSocket* pMe = (LwipNetTcpSocket*) arg;
00434   return pMe->errCb( err );
00435 }
00436   
00437 err_t LwipNetTcpSocket::sSentCb(void *arg, struct tcp_pcb *tpcb, u16_t len)
00438 {
00439   LwipNetTcpSocket* pMe = (LwipNetTcpSocket*) arg;
00440   return pMe->sentCb( tpcb, len );
00441 }
00442 
00443 err_t LwipNetTcpSocket::sRecvCb(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
00444 {
00445   if( tpcb->flags & TF_RXCLOSED )
00446   {
00447     //The Pcb is in a closing state
00448     //Discard that data here since we might have destroyed the corresponding socket object
00449     tcp_recved( tpcb, p->tot_len);
00450     pbuf_free( p );    
00451     return ERR_OK;
00452   }
00453   LwipNetTcpSocket* pMe = (LwipNetTcpSocket*) arg;
00454   return pMe->recvCb( tpcb, p, err );
00455 }
00456 
00457 #endif