Bonjour/Zerconf library

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers lwipNetUdpSocket.cpp Source File

lwipNetUdpSocket.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 "lwipNetUdpSocket.h"
00025 #include "lwip/udp.h"
00026 
00027 //#define __DEBUG
00028 #include "dbg/dbg.h"
00029 
00030 #include "netCfg.h"
00031 #if NET_LWIP_STACK
00032 
00033 LwipNetUdpSocket::LwipNetUdpSocket(udp_pcb* pPcb /*= NULL*/) : NetUdpSocket(), m_pPcb(pPcb), m_lInPkt() //Passes a pcb if already created (by an accept req for instance), in that case transfers ownership
00034 {
00035   DBG("\r\nNew LwipNetUdpSocket %p (pPCb=%p)\r\n", (void*)this, (void*) pPcb);
00036   if(!m_pPcb)
00037     m_pPcb = udp_new();
00038   if(m_pPcb)
00039   {
00040     //Setup callback
00041     udp_recv( (udp_pcb*) m_pPcb, LwipNetUdpSocket::sRecvCb, (void*) this );
00042   }
00043 }
00044 
00045 LwipNetUdpSocket::~LwipNetUdpSocket()
00046 {
00047   close();
00048 }
00049   
00050 NetUdpSocketErr LwipNetUdpSocket::bind(const Host& me)
00051 {
00052   if(!m_pPcb)
00053     return NETUDPSOCKET_MEM; //NetUdpSocket was not properly initialised, should destroy it & retry
00054 
00055   err_t err = udp_bind( (udp_pcb*) m_pPcb, IP_ADDR_ANY, me.getPort()); //IP_ADDR_ANY : Bind the connection to all local addresses
00056   if(err)
00057     return NETUDPSOCKET_INUSE;
00058 
00059   //Setup callback
00060   udp_recv( (udp_pcb*) m_pPcb, LwipNetUdpSocket::sRecvCb, (void*) this );
00061     
00062   return NETUDPSOCKET_OK;
00063 }
00064 
00065 #define MAX(a,b) ((a>b)?a:b)
00066 #define MIN(a,b) ((a<b)?a:b)
00067 
00068 int /*if < 0 : NetUdpSocketErr*/ LwipNetUdpSocket::sendto(const char* buf, int len, Host* pHost)
00069 {
00070   if( !m_pPcb ) //Pcb doesn't exist (anymore)
00071     return NETUDPSOCKET_MEM;
00072   pbuf* p = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_POOL);
00073   if( !p )
00074     return NETUDPSOCKET_MEM;
00075   char* pBuf = (char*) buf;
00076   pbuf* q = p; 
00077   do
00078   {
00079     memcpy (q->payload, (void*)pBuf, q->len);  
00080     pBuf += q->len;
00081     q = q->next;
00082   } while(q != NULL);
00083 
00084   err_t err = udp_sendto( (udp_pcb*) m_pPcb, p, &(pHost->getIp().getStruct()), pHost->getPort() );
00085   pbuf_free( p );
00086   if(err)
00087     return NETUDPSOCKET_SETUP; //Connection problem
00088   DBG("\r\n%d bytes sent in UDP Socket.\r\n", len);
00089   return len;
00090 }
00091 
00092 int /*if < 0 : NetUdpSocketErr*/ LwipNetUdpSocket::recvfrom(char* buf, int len, Host* pHost)
00093 {
00094   if( !m_pPcb ) //Pcb doesn't exist (anymore)
00095     return NETUDPSOCKET_MEM;
00096   int inLen = 0;
00097   int cpyLen = 0;
00098   
00099   static int rmgLen = 0; 
00100   //Contains the remaining len in this pbuf
00101   
00102   if( m_lInPkt.empty() )
00103     return 0;
00104     
00105   pbuf* pBuf = (pbuf*) m_lInPkt.front().pBuf;
00106   
00107   if(pHost)
00108     *pHost = Host( IpAddr(&m_lInPkt.front().addr), m_lInPkt.front().port );
00109   
00110   if( !pBuf )
00111   {
00112     rmgLen = 0;
00113     return 0;
00114   }
00115   
00116   if ( !rmgLen ) //We did not know m_pReadPbuf->len last time we called this fn
00117   {
00118     rmgLen = pBuf->len;
00119   }
00120   
00121   while ( inLen < len )
00122   {
00123     cpyLen = MIN( (len - inLen), rmgLen ); //Remaining len to copy, remaining len in THIS pbuf
00124     memcpy((void*)buf, (void*)((char*)(pBuf->payload) + (pBuf->len - rmgLen)), cpyLen);
00125     inLen += cpyLen;
00126     buf += cpyLen;
00127     
00128     rmgLen = rmgLen - cpyLen; //Update rmgLen
00129     
00130     if( rmgLen > 0 )
00131     {
00132       //We did not read this pbuf completely, so let's save it's pos & return
00133       break;
00134     }
00135     
00136     if(pBuf->next)
00137     {
00138       pbuf* pNextPBuf = pBuf->next;
00139       pBuf->next = NULL; //So that it is not freed as well
00140       //We get the reference to pNextPBuf from m_pReadPbuf
00141       pbuf_free((pbuf*)pBuf);
00142       pBuf = pNextPBuf;
00143       rmgLen = pBuf->len;
00144     }
00145     else
00146     {
00147       pbuf_free((pbuf*)pBuf);
00148       pBuf = NULL;
00149       rmgLen = 0;
00150       m_lInPkt.pop_front();
00151       break; //No more data to read
00152     } 
00153   }
00154   
00155   return inLen;
00156 }
00157 
00158 NetUdpSocketErr LwipNetUdpSocket::close()
00159 {
00160   DBG("\r\nLwipNetUdpSocket::close() : Closing...\r\n");
00161 
00162   if(m_closed)
00163     return NETUDPSOCKET_OK; //Already being closed
00164   m_closed = true;
00165   
00166   if( !m_pPcb ) //Pcb doesn't exist (anymore)
00167     return NETUDPSOCKET_MEM;
00168     
00169   DBG("\r\nLwipNetUdpSocket::close() : Cleanup...\r\n");
00170     
00171   //Cleanup incoming data
00172   cleanUp();
00173  
00174   DBG("\r\nLwipNetUdpSocket::close() : removing m_pPcb...\r\n");
00175   udp_remove( (udp_pcb*) m_pPcb);
00176     
00177   m_pPcb = NULL;
00178   return NETUDPSOCKET_OK;
00179 }
00180 
00181 NetUdpSocketErr LwipNetUdpSocket::poll()
00182 {
00183   NetUdpSocket::flushEvents();
00184   return NETUDPSOCKET_OK;
00185 }
00186 
00187 // Callbacks events
00188 
00189 void LwipNetUdpSocket::recvCb(udp_pcb* pcb, struct pbuf* p, ip_addr_t* addr, u16_t port)
00190 {
00191   DBG("\r\n Packet of length %d arrived in UDP Socket.\r\n", p->tot_len);
00192   list<InPacket>::iterator it;
00193   for ( it = m_lInPkt.begin(); it != m_lInPkt.end(); it++ )
00194   {
00195     if( ip_addr_cmp((&((*it).addr)), addr) && ((*it).port == port) )
00196     {
00197       //Let's tail this packet to the previous one
00198       pbuf_cat((pbuf*)((*it).pBuf), p);
00199       //No need to queue an event in that case since the read buf has not been processed yet
00200       return;
00201     }
00202   }
00203 
00204   //New host, add a packet to the queue
00205   InPacket pkt;
00206   pkt.pBuf = p;
00207   pkt.addr = *addr;
00208   pkt.port = port;
00209   m_lInPkt.push_back(pkt);
00210   
00211   queueEvent(NETUDPSOCKET_READABLE);
00212 }
00213 
00214 void LwipNetUdpSocket::cleanUp() //Flush input buffer
00215 {
00216   //Ensure that further error won't be followed to this inst (which can be destroyed)
00217   if( m_pPcb )
00218   {
00219     udp_recv( (udp_pcb*) m_pPcb, NULL, (void*) NULL );
00220   }
00221   
00222   list<InPacket>::iterator it;
00223   for ( it = m_lInPkt.begin(); it != m_lInPkt.end(); it++ )
00224   {
00225     //Free buf
00226     pbuf_free((pbuf*)((*it).pBuf));
00227   } 
00228   m_lInPkt.clear();
00229 }
00230 
00231 // Static callback from LwIp
00232 
00233 void LwipNetUdpSocket::sRecvCb(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port)
00234 {
00235   LwipNetUdpSocket* pMe = (LwipNetUdpSocket*) arg;
00236   return pMe->recvCb( pcb, p, addr, port );
00237 }
00238 
00239 #endif