Example program with HTTPServer and sensor data streaming over TCPSockets, using Donatien Garnier's Net APIs and services code on top of LWIP. Files StreamServer.h and .cpp encapsulate streaming over TCPSockets. Broadcast is done by sendToAll(), and all incoming data is echoed back to the client. Echo code can be replaced with some remote control of the streaming interface. See main() that shows how to periodically send some data to all subscribed clients. To subscribe, a client should open a socket at <mbed_ip> port 123. I used few lines in TCL code to set up a quick sink for the data. HTTP files are served on port 80 concurrently to the streaming.

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers raw.c Source File

raw.c

Go to the documentation of this file.
00001 /**
00002  * @file
00003  * Implementation of raw protocol PCBs for low-level handling of
00004  * different types of protocols besides (or overriding) those
00005  * already available in lwIP.
00006  *
00007  */
00008 
00009 /*
00010  * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
00011  * All rights reserved.
00012  *
00013  * Redistribution and use in source and binary forms, with or without modification,
00014  * are permitted provided that the following conditions are met:
00015  *
00016  * 1. Redistributions of source code must retain the above copyright notice,
00017  *    this list of conditions and the following disclaimer.
00018  * 2. Redistributions in binary form must reproduce the above copyright notice,
00019  *    this list of conditions and the following disclaimer in the documentation
00020  *    and/or other materials provided with the distribution.
00021  * 3. The name of the author may not be used to endorse or promote products
00022  *    derived from this software without specific prior written permission.
00023  *
00024  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
00025  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00026  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
00027  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00028  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
00029  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00030  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00031  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
00032  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
00033  * OF SUCH DAMAGE.
00034  *
00035  * This file is part of the lwIP TCP/IP stack.
00036  *
00037  * Author: Adam Dunkels <adam@sics.se>
00038  *
00039  */
00040 
00041 #include "lwip/opt.h"
00042 
00043 #if LWIP_RAW /* don't build if not configured for use in lwipopts.h */
00044 
00045 #include "lwip/def.h"
00046 #include "lwip/memp.h"
00047 #include "lwip/ip_addr.h"
00048 #include "lwip/netif.h"
00049 #include "lwip/raw.h"
00050 #include "lwip/stats.h"
00051 #include "arch/perf.h"
00052 
00053 #include <string.h>
00054 
00055 /** The list of RAW PCBs */
00056 static struct raw_pcb *raw_pcbs;
00057 
00058 /**
00059  * Determine if in incoming IP packet is covered by a RAW PCB
00060  * and if so, pass it to a user-provided receive callback function.
00061  *
00062  * Given an incoming IP datagram (as a chain of pbufs) this function
00063  * finds a corresponding RAW PCB and calls the corresponding receive
00064  * callback function.
00065  *
00066  * @param p pbuf to be demultiplexed to a RAW PCB.
00067  * @param inp network interface on which the datagram was received.
00068  * @return - 1 if the packet has been eaten by a RAW PCB receive
00069  *           callback function. The caller MAY NOT not reference the
00070  *           packet any longer, and MAY NOT call pbuf_free().
00071  * @return - 0 if packet is not eaten (pbuf is still referenced by the
00072  *           caller).
00073  *
00074  */
00075 u8_t
00076 raw_input(struct pbuf *p, struct netif *inp)
00077 {
00078   struct raw_pcb *pcb, *prev;
00079   struct ip_hdr *iphdr;
00080   s16_t proto;
00081   u8_t eaten = 0;
00082 
00083   LWIP_UNUSED_ARG(inp);
00084 
00085   iphdr = (struct ip_hdr *)p->payload;
00086   proto = IPH_PROTO(iphdr);
00087 
00088   prev = NULL;
00089   pcb = raw_pcbs;
00090   /* loop through all raw pcbs until the packet is eaten by one */
00091   /* this allows multiple pcbs to match against the packet by design */
00092   while ((eaten == 0) && (pcb != NULL)) {
00093     if ((pcb->protocol == proto) &&
00094         (ip_addr_isany(&pcb->local_ip) ||
00095          ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest)))) {
00096 #if IP_SOF_BROADCAST_RECV
00097       /* broadcast filter? */
00098       if ((pcb->so_options & SOF_BROADCAST) || !ip_addr_isbroadcast(&(iphdr->dest), inp))
00099 #endif /* IP_SOF_BROADCAST_RECV */
00100       {
00101         /* receive callback function available? */
00102         if (pcb->recv != NULL) {
00103           /* the receive callback function did not eat the packet? */
00104           if (pcb->recv(pcb->recv_arg, pcb, p, &(iphdr->src)) != 0) {
00105             /* receive function ate the packet */
00106             p = NULL;
00107             eaten = 1;
00108             if (prev != NULL) {
00109             /* move the pcb to the front of raw_pcbs so that is
00110                found faster next time */
00111               prev->next = pcb->next;
00112               pcb->next = raw_pcbs;
00113               raw_pcbs = pcb;
00114             }
00115           }
00116         }
00117         /* no receive callback function was set for this raw PCB */
00118       }
00119       /* drop the packet */
00120     }
00121     prev = pcb;
00122     pcb = pcb->next;
00123   }
00124   return eaten;
00125 }
00126 
00127 /**
00128  * Bind a RAW PCB.
00129  *
00130  * @param pcb RAW PCB to be bound with a local address ipaddr.
00131  * @param ipaddr local IP address to bind with. Use IP_ADDR_ANY to
00132  * bind to all local interfaces.
00133  *
00134  * @return lwIP error code.
00135  * - ERR_OK. Successful. No error occured.
00136  * - ERR_USE. The specified IP address is already bound to by
00137  * another RAW PCB.
00138  *
00139  * @see raw_disconnect()
00140  */
00141 err_t
00142 raw_bind(struct raw_pcb *pcb, ip_addr_t *ipaddr)
00143 {
00144   ip_addr_set(&pcb->local_ip, ipaddr);
00145   return ERR_OK;
00146 }
00147 
00148 /**
00149  * Connect an RAW PCB. This function is required by upper layers
00150  * of lwip. Using the raw api you could use raw_sendto() instead
00151  *
00152  * This will associate the RAW PCB with the remote address.
00153  *
00154  * @param pcb RAW PCB to be connected with remote address ipaddr and port.
00155  * @param ipaddr remote IP address to connect with.
00156  *
00157  * @return lwIP error code
00158  *
00159  * @see raw_disconnect() and raw_sendto()
00160  */
00161 err_t
00162 raw_connect(struct raw_pcb *pcb, ip_addr_t *ipaddr)
00163 {
00164   ip_addr_set(&pcb->remote_ip, ipaddr);
00165   return ERR_OK;
00166 }
00167 
00168 
00169 /**
00170  * Set the callback function for received packets that match the
00171  * raw PCB's protocol and binding. 
00172  * 
00173  * The callback function MUST either
00174  * - eat the packet by calling pbuf_free() and returning non-zero. The
00175  *   packet will not be passed to other raw PCBs or other protocol layers.
00176  * - not free the packet, and return zero. The packet will be matched
00177  *   against further PCBs and/or forwarded to another protocol layers.
00178  * 
00179  * @return non-zero if the packet was free()d, zero if the packet remains
00180  * available for others.
00181  */
00182 void
00183 raw_recv(struct raw_pcb *pcb, raw_recv_fn recv, void *recv_arg)
00184 {
00185   /* remember recv() callback and user data */
00186   pcb->recv = recv;
00187   pcb->recv_arg = recv_arg;
00188 }
00189 
00190 /**
00191  * Send the raw IP packet to the given address. Note that actually you cannot
00192  * modify the IP headers (this is inconsistent with the receive callback where
00193  * you actually get the IP headers), you can only specify the IP payload here.
00194  * It requires some more changes in lwIP. (there will be a raw_send() function
00195  * then.)
00196  *
00197  * @param pcb the raw pcb which to send
00198  * @param p the IP payload to send
00199  * @param ipaddr the destination address of the IP packet
00200  *
00201  */
00202 err_t
00203 raw_sendto(struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr)
00204 {
00205   err_t err;
00206   struct netif *netif;
00207   ip_addr_t *src_ip;
00208   struct pbuf *q; /* q will be sent down the stack */
00209   
00210   LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, ("raw_sendto\n"));
00211   
00212   /* not enough space to add an IP header to first pbuf in given p chain? */
00213   if (pbuf_header(p, IP_HLEN)) {
00214     /* allocate header in new pbuf */
00215     q = pbuf_alloc(PBUF_IP, 0, PBUF_RAM);
00216     /* new header pbuf could not be allocated? */
00217     if (q == NULL) {
00218       LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("raw_sendto: could not allocate header\n"));
00219       return ERR_MEM;
00220     }
00221     /* chain header q in front of given pbuf p */
00222     pbuf_chain(q, p);
00223     /* { first pbuf q points to header pbuf } */
00224     LWIP_DEBUGF(RAW_DEBUG, ("raw_sendto: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p));
00225   }  else {
00226     /* first pbuf q equals given pbuf */
00227     q = p;
00228     if(pbuf_header(q, -IP_HLEN)) {
00229       LWIP_ASSERT("Can't restore header we just removed!", 0);
00230       return ERR_MEM;
00231     }
00232   }
00233 
00234   if ((netif = ip_route(ipaddr)) == NULL) {
00235     LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
00236       ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr)));
00237     /* free any temporary header pbuf allocated by pbuf_header() */
00238     if (q != p) {
00239       pbuf_free(q);
00240     }
00241     return ERR_RTE;
00242   }
00243 
00244 #if IP_SOF_BROADCAST
00245   /* broadcast filter? */
00246   if (((pcb->so_options & SOF_BROADCAST) == 0) && ip_addr_isbroadcast(ipaddr, netif)) {
00247     LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: SOF_BROADCAST not enabled on pcb %p\n", (void *)pcb));
00248     /* free any temporary header pbuf allocated by pbuf_header() */
00249     if (q != p) {
00250       pbuf_free(q);
00251     }
00252     return ERR_VAL;
00253   }
00254 #endif /* IP_SOF_BROADCAST */
00255 
00256   if (ip_addr_isany(&pcb->local_ip)) {
00257     /* use outgoing network interface IP address as source address */
00258     src_ip = &(netif->ip_addr);
00259   } else {
00260     /* use RAW PCB local IP address as source address */
00261     src_ip = &(pcb->local_ip);
00262   }
00263 
00264 #if LWIP_NETIF_HWADDRHINT
00265   netif->addr_hint = &(pcb->addr_hint);
00266 #endif /* LWIP_NETIF_HWADDRHINT*/
00267   err = ip_output_if (q, src_ip, ipaddr, pcb->ttl, pcb->tos, pcb->protocol, netif);
00268 #if LWIP_NETIF_HWADDRHINT
00269   netif->addr_hint = NULL;
00270 #endif /* LWIP_NETIF_HWADDRHINT*/
00271 
00272   /* did we chain a header earlier? */
00273   if (q != p) {
00274     /* free the header */
00275     pbuf_free(q);
00276   }
00277   return err;
00278 }
00279 
00280 /**
00281  * Send the raw IP packet to the address given by raw_connect()
00282  *
00283  * @param pcb the raw pcb which to send
00284  * @param p the IP payload to send
00285  *
00286  */
00287 err_t
00288 raw_send(struct raw_pcb *pcb, struct pbuf *p)
00289 {
00290   return raw_sendto(pcb, p, &pcb->remote_ip);
00291 }
00292 
00293 /**
00294  * Remove an RAW PCB.
00295  *
00296  * @param pcb RAW PCB to be removed. The PCB is removed from the list of
00297  * RAW PCB's and the data structure is freed from memory.
00298  *
00299  * @see raw_new()
00300  */
00301 void
00302 raw_remove(struct raw_pcb *pcb)
00303 {
00304   struct raw_pcb *pcb2;
00305   /* pcb to be removed is first in list? */
00306   if (raw_pcbs == pcb) {
00307     /* make list start at 2nd pcb */
00308     raw_pcbs = raw_pcbs->next;
00309     /* pcb not 1st in list */
00310   } else {
00311     for(pcb2 = raw_pcbs; pcb2 != NULL; pcb2 = pcb2->next) {
00312       /* find pcb in raw_pcbs list */
00313       if (pcb2->next != NULL && pcb2->next == pcb) {
00314         /* remove pcb from list */
00315         pcb2->next = pcb->next;
00316       }
00317     }
00318   }
00319   memp_free(MEMP_RAW_PCB, pcb);
00320 }
00321 
00322 /**
00323  * Create a RAW PCB.
00324  *
00325  * @return The RAW PCB which was created. NULL if the PCB data structure
00326  * could not be allocated.
00327  *
00328  * @param proto the protocol number of the IPs payload (e.g. IP_PROTO_ICMP)
00329  *
00330  * @see raw_remove()
00331  */
00332 struct raw_pcb *
00333 raw_new(u8_t proto)
00334 {
00335   struct raw_pcb *pcb;
00336 
00337   LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, ("raw_new\n"));
00338 
00339   pcb = (struct raw_pcb *)memp_malloc(MEMP_RAW_PCB);
00340   /* could allocate RAW PCB? */
00341   if (pcb != NULL) {
00342     /* initialize PCB to all zeroes */
00343     memset(pcb, 0, sizeof(struct raw_pcb));
00344     pcb->protocol = proto;
00345     pcb->ttl = RAW_TTL;
00346     pcb->next = raw_pcbs;
00347     raw_pcbs = pcb;
00348   }
00349   return pcb;
00350 }
00351 
00352 #endif /* LWIP_RAW */