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 lwipNetUdpSocket.cpp Source File

lwipNetUdpSocket.cpp

00001 #pragma diag_remark 1464
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   ip_addr_t hip(pHost->getIp().getStruct());
00101   err_t err = udp_sendto( (udp_pcb*) m_pPcb, p, &hip, pHost->getPort() );
00102   pbuf_free( p );
00103   if(err)
00104     return NETUDPSOCKET_SETUP; //Connection problem
00105   DBG("%d bytes sent in UDP Socket.\n", len);
00106   return len;
00107 }
00108 
00109 int /*if < 0 : NetUdpSocketErr*/ LwipNetUdpSocket::recvfrom(char* buf, int len, Host* pHost)
00110 {
00111   if( !m_pPcb ) //Pcb doesn't exist (anymore)
00112     return NETUDPSOCKET_MEM;
00113   int inLen = 0;
00114   int cpyLen = 0;
00115   
00116   static int rmgLen = 0; 
00117   //Contains the remaining len in this pbuf
00118   
00119   if( m_lInPkt.empty() )
00120     return 0;
00121     
00122   pbuf* pBuf = (pbuf*) m_lInPkt.front().pBuf;
00123   
00124   if(pHost)
00125     *pHost = Host( IpAddr(&m_lInPkt.front().addr), m_lInPkt.front().port );
00126   
00127   if( !pBuf )
00128   {
00129     rmgLen = 0;
00130     return 0;
00131   }
00132   
00133   if ( !rmgLen ) //We did not know m_pReadPbuf->len last time we called this fn
00134   {
00135     rmgLen = pBuf->len;
00136   }
00137   
00138   while ( inLen < len )
00139   {
00140     cpyLen = MIN( (len - inLen), rmgLen ); //Remaining len to copy, remaining len in THIS pbuf
00141     memcpy((void*)buf, (void*)((char*)(pBuf->payload) + (pBuf->len - rmgLen)), cpyLen);
00142     inLen += cpyLen;
00143     buf += cpyLen;
00144     
00145     rmgLen = rmgLen - cpyLen; //Update rmgLen
00146     
00147     if( rmgLen > 0 )
00148     {
00149       //We did not read this pbuf completely, so let's save it's pos & return
00150       break;
00151     }
00152     
00153     if(pBuf->next)
00154     {
00155       pbuf* pNextPBuf = pBuf->next;
00156       pBuf->next = NULL; //So that it is not freed as well
00157       //We get the reference to pNextPBuf from m_pReadPbuf
00158       pbuf_free((pbuf*)pBuf);
00159       pBuf = pNextPBuf;
00160       rmgLen = pBuf->len;
00161     }
00162     else
00163     {
00164       pbuf_free((pbuf*)pBuf);
00165       pBuf = NULL;
00166       rmgLen = 0;
00167       m_lInPkt.pop_front();
00168       break; //No more data to read
00169     } 
00170   }
00171   
00172   return inLen;
00173 }
00174 
00175 NetUdpSocketErr LwipNetUdpSocket::close()
00176 {
00177   DBG("LwipNetUdpSocket::close() : Closing...\n");
00178 
00179   if(m_closed)
00180     return NETUDPSOCKET_OK; //Already being closed
00181   m_closed = true;
00182   
00183   if( !m_pPcb ) //Pcb doesn't exist (anymore)
00184     return NETUDPSOCKET_MEM;
00185     
00186   DBG("LwipNetUdpSocket::close() : Cleanup...\n");
00187     
00188   //Cleanup incoming data
00189   cleanUp();
00190   
00191 
00192   DBG("LwipNetUdpSocket::close() : removing m_pPcb...\n");
00193   udp_remove( (udp_pcb*) m_pPcb);
00194     
00195   m_pPcb = NULL;
00196   return NETUDPSOCKET_OK;
00197 }
00198 
00199 NetUdpSocketErr LwipNetUdpSocket::poll()
00200 {
00201   NetUdpSocket::flushEvents();
00202   return NETUDPSOCKET_OK;
00203 }
00204 
00205 // Callbacks events
00206 
00207 void LwipNetUdpSocket::recvCb(udp_pcb* pcb, struct pbuf* p, ip_addr_t* addr, u16_t port)
00208 {
00209   DBG(" Packet of length %d arrived in UDP Socket.\n", p->tot_len);
00210   list<InPacket>::iterator it;
00211   for ( it = m_lInPkt.begin(); it != m_lInPkt.end(); it++ )
00212   {
00213     if( ip_addr_cmp((&((*it).addr)), addr) && ((*it).port == port) )
00214     {
00215       //Let's tail this packet to the previous one
00216       pbuf_cat((pbuf*)((*it).pBuf), p);
00217       //No need to queue an event in that case since the read buf has not been processed yet
00218       return;
00219     }
00220   }
00221 
00222   //New host, add a packet to the queue
00223   InPacket pkt;
00224   pkt.pBuf = p;
00225   pkt.addr = *addr;
00226   pkt.port = port;
00227   m_lInPkt.push_back(pkt);
00228   
00229   queueEvent(NETUDPSOCKET_READABLE);
00230 }
00231 
00232 void LwipNetUdpSocket::cleanUp() //Flush input buffer
00233 {
00234   //Ensure that further error won't be followed to this inst (which can be destroyed)
00235   if( m_pPcb )
00236   {
00237     udp_recv( (udp_pcb*) m_pPcb, NULL, (void*) NULL );
00238   }
00239   
00240   //Leaving multicast group(Ok because LwIP has a refscount for multicast group)
00241   #if LWIP_IGMP //Multicast support enabled
00242   if(m_multicastGroup.isMulticast())
00243   {
00244     igmp_leavegroup(IP_ADDR_ANY, &(m_multicastGroup.getStruct()));
00245     m_multicastGroup = IpAddr();
00246   }
00247   #endif
00248   
00249   list<InPacket>::iterator it;
00250   for ( it = m_lInPkt.begin(); it != m_lInPkt.end(); it++ )
00251   {
00252     //Free buf
00253     pbuf_free((pbuf*)((*it).pBuf));
00254   } 
00255   m_lInPkt.clear();
00256 }
00257 
00258 // Static callback from LwIp
00259 
00260 void LwipNetUdpSocket::sRecvCb(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port)
00261 {
00262   LwipNetUdpSocket* pMe = (LwipNetUdpSocket*) arg;
00263   return pMe->recvCb( pcb, p, addr, port );
00264 }
00265 
00266 #endif