From 7ce313eef6a0a8e5c7b08cfef41e05601bad9fe6 Mon Sep 17 00:00:00 2001 From: Adam Dunkels Date: Mon, 29 Aug 2011 21:30:21 +0200 Subject: [PATCH] A significantly simpler API for sending UDP packets --- core/net/simple-udp.c | 212 ++++++++++++++++++++++++++++++++++++++++++ core/net/simple-udp.h | 94 +++++++++++++++++++ 2 files changed, 306 insertions(+) create mode 100644 core/net/simple-udp.c create mode 100644 core/net/simple-udp.h diff --git a/core/net/simple-udp.c b/core/net/simple-udp.c new file mode 100644 index 000000000..75537f172 --- /dev/null +++ b/core/net/simple-udp.c @@ -0,0 +1,212 @@ +/** + * \addtogroup simple-udp + * @{ + */ + + +/* + * Copyright (c) 2011, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + * \file + * Header file for the simple-udp module. + * \author + * Adam Dunkels + * + */ + +#include "simple-udp.h" +#include "contiki-net.h" + +PROCESS(simple_udp_process, "Simple UDP process"); +static uint8_t started = 0; +static uint8_t databuffer[UIP_BUFSIZE]; + +#define UIP_IP_BUF ((struct uip_udpip_hdr *)&uip_buf[UIP_LLH_LEN]) + +/*---------------------------------------------------------------------------*/ +static void +init_simple_udp(void) +{ + if(started == 0) { + process_start(&simple_udp_process, NULL); + started = 1; + } +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Send a UDP packet + * \param c A pointer to a struct simple_udp_connection + * \param data A pointer to the data to be sent + * \param datalen The length of the data + * + * This function sends a UDP packet. The packet will be + * sent to the IP address and with the UDP ports that were + * specified when the connection wa registered with + * simple_udp_register(). + * + * \sa simple_udp_sendto() + */ +int +simple_udp_send(struct simple_udp_connection *c, + const void *data, uint16_t datalen) +{ + if(c->udp_conn != NULL) { + uip_udp_packet_sendto(c->udp_conn, data, datalen, + &c->remote_addr, UIP_HTONS(c->remote_port)); + } + return 0; +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Send a UDP packet to a specified IP address + * \param c A pointer to a struct simple_udp_connection + * \param data A pointer to the data to be sent + * \param datalen The length of the data + * \param to The IP address of the receiver + * + * This function sends a UDP packet to a specified IP + * address. The packet will be sent with the UDP ports + * that were specified when the connection wa registered + * with simple_udp_register(). + * + * \sa simple_udp_send() + */ +int +simple_udp_sendto(struct simple_udp_connection *c, + const void *data, uint16_t datalen, + const uip_ipaddr_t *to) +{ + if(c->udp_conn != NULL) { + uip_udp_packet_sendto(c->udp_conn, data, datalen, + to, UIP_HTONS(c->remote_port)); + } + return 0; +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Register a UDP connection + * \param c A pointer to a struct simple_udp_connection + * \param local_port The local UDP port in host byte order + * \param remote_addr The remote IP address + * \param remote_port The remote UDP port in host byte order + * \param receive_callback A pointer to a function to be called for incoming packets + * \retval 0 If no UDP connection could be allocated + * \retval 1 If the connection was successfully allocated + * + * This function registers a UDP connection and attaches a + * callback function to it. The callback function will be + * called for incoming packets. The local UDP port can be + * set to 0 to indicate that an ephemeral UDP port should + * be allocated. The remote IP address can be NULL, to + * indicate that packets from any IP address should be + * accepted. + * + */ +int +simple_udp_register(struct simple_udp_connection *c, + uint16_t local_port, + uip_ipaddr_t *remote_addr, + uint16_t remote_port, + simple_udp_callback receive_callback) +{ + + init_simple_udp(); + + c->local_port = local_port; + c->remote_port = remote_port; + if(remote_addr != NULL) { + uip_ipaddr_copy(&c->remote_addr, remote_addr); + } + c->receive_callback = receive_callback; + + PROCESS_CONTEXT_BEGIN(&simple_udp_process); + c->udp_conn = udp_new(remote_addr, UIP_HTONS(remote_port), c); + if(c->udp_conn != NULL) { + udp_bind(c->udp_conn, UIP_HTONS(local_port)); + } + PROCESS_CONTEXT_END(); + + if(c->udp_conn == NULL) { + return 0; + } + return 1; +} +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(simple_udp_process, ev, data) +{ + struct simple_udp_connection *c; + PROCESS_BEGIN(); + + while(1) { + PROCESS_WAIT_EVENT(); + if(ev == tcpip_event) { + + /* An appstate pointer is passed to use from the IP stack + through the 'data' pointer. We registered this appstate when + we did the udp_new() call in simple_udp_register() as the + struct simple_udp_connection pointer. So we extract this + pointer and use it when calling the reception callback. */ + c = (struct simple_udp_connection *)data; + + /* Defensive coding: although the appstate *should* be non-null + here, we make sure to avoid the program crashing on us. */ + if(c != NULL) { + + /* If we were called because of incoming data, we should call + the reception callback. */ + if(uip_newdata()) { + /* Copy the data from the uIP data buffer into our own + buffer to avoid the uIP buffer being messed with by the + callee. */ + memcpy(databuffer, uip_appdata, uip_datalen()); + + /* Call the client process. We use the PROCESS_CONTEXT + mechanism to temporarily switch process context to the + client process. */ + if(c->receive_callback != NULL) { + PROCESS_CONTEXT_BEGIN(c->client_process); + c->receive_callback(c, + &(UIP_IP_BUF->srcipaddr), + UIP_HTONS(UIP_IP_BUF->srcport), + &(UIP_IP_BUF->destipaddr), + UIP_HTONS(UIP_IP_BUF->destport), + databuffer, uip_datalen()); + PROCESS_CONTEXT_END(); + } + } + } + } + + } + + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/ +/** @} */ diff --git a/core/net/simple-udp.h b/core/net/simple-udp.h new file mode 100644 index 000000000..8579dc497 --- /dev/null +++ b/core/net/simple-udp.h @@ -0,0 +1,94 @@ +/** + * \addtogroup uip + * @{ + */ + + +/** + * \defgroup simple-udp + * + * The default Contiki UDP API is difficult to use. The simple-udp + * module provides a significantly simpler API. + * + * @{ + */ + +/* + * Copyright (c) 2011, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + * \file + * Header file for the simple-udp module. + * \author + * Adam Dunkels + * + */ + +#ifndef SIMPLE_UDP_H +#define SIMPLE_UDP_H + +#include "net/uip.h" + +struct simple_udp_connection; + +typedef void (* simple_udp_callback)(struct simple_udp_connection *c, + const uip_ipaddr_t *source_addr, + uint16_t source_port, + const uip_ipaddr_t *dest_addr, + uint16_t dest_port, + const uint8_t *data, uint16_t datalen); + +struct simple_udp_connection { + struct simple_udp_connection *next; + uip_ipaddr_t remote_addr; + uint16_t remote_port, local_port; + simple_udp_callback receive_callback; + struct uip_udp_conn *udp_conn; + struct process *client_process; +}; + +int simple_udp_register(struct simple_udp_connection *c, + uint16_t local_port, + uip_ipaddr_t *remote_addr, + uint16_t remote_port, + simple_udp_callback receive_callback); + +int simple_udp_send(struct simple_udp_connection *c, + const void *data, uint16_t datalen); + +int simple_udp_sendto(struct simple_udp_connection *c, + const void *data, uint16_t datalen, + const uip_ipaddr_t *to); + +void simple_udp_init(void); + +#endif /* SIMPLE_UDP_H */ + +/** @} */ +/** @} */