ZG2100 Network interface source

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