Contiki-NG
udp-socket.c
1 /*
2  * Copyright (c) 2012-2014, Thingsquare, http://www.thingsquare.com/.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the copyright holder nor the names of its
14  * contributors may be used to endorse or promote products derived
15  * from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28  * OF THE POSSIBILITY OF SUCH DAMAGE.
29  *
30  */
31 
32 #include "contiki-net.h"
33 #include "udp-socket.h"
34 
35 #include <string.h>
36 
37 PROCESS(udp_socket_process, "UDP socket process");
38 
39 static uint8_t buf[UIP_BUFSIZE];
40 
41 #define UIP_IP_BUF ((struct uip_udpip_hdr *)&uip_buf[UIP_LLH_LEN])
42 
43 
44 /*---------------------------------------------------------------------------*/
45 static void
46 init(void)
47 {
48  static uint8_t inited = 0;
49  if(!inited) {
50  inited = 1;
51  process_start(&udp_socket_process, NULL);
52  }
53 }
54 /*---------------------------------------------------------------------------*/
55 int
56 udp_socket_register(struct udp_socket *c,
57  void *ptr,
58  udp_socket_input_callback_t input_callback)
59 {
60  init();
61 
62  if(c == NULL) {
63  return -1;
64  }
65  c->ptr = ptr;
66  c->input_callback = input_callback;
67 
68  c->p = PROCESS_CURRENT();
69  PROCESS_CONTEXT_BEGIN(&udp_socket_process);
70  c->udp_conn = udp_new(NULL, 0, c);
72 
73  if(c->udp_conn == NULL) {
74  return -1;
75  }
76  return 1;
77 }
78 /*---------------------------------------------------------------------------*/
79 int
80 udp_socket_close(struct udp_socket *c)
81 {
82  if(c == NULL) {
83  return -1;
84  }
85  if(c->udp_conn != NULL) {
86  uip_udp_remove(c->udp_conn);
87  return 1;
88  }
89  return -1;
90 }
91 /*---------------------------------------------------------------------------*/
92 int
93 udp_socket_bind(struct udp_socket *c,
94  uint16_t local_port)
95 {
96  if(c == NULL || c->udp_conn == NULL) {
97  return -1;
98  }
99  udp_bind(c->udp_conn, UIP_HTONS(local_port));
100 
101  return 1;
102 }
103 /*---------------------------------------------------------------------------*/
104 int
105 udp_socket_connect(struct udp_socket *c,
106  uip_ipaddr_t *remote_addr,
107  uint16_t remote_port)
108 {
109  if(c == NULL || c->udp_conn == NULL) {
110  return -1;
111  }
112 
113  if(remote_addr != NULL) {
114  uip_ipaddr_copy(&c->udp_conn->ripaddr, remote_addr);
115  }
116  c->udp_conn->rport = UIP_HTONS(remote_port);
117  return 1;
118 }
119 /*---------------------------------------------------------------------------*/
120 int
121 udp_socket_send(struct udp_socket *c,
122  const void *data, uint16_t datalen)
123 {
124  if(c == NULL || c->udp_conn == NULL) {
125  return -1;
126  }
127 
128  uip_udp_packet_send(c->udp_conn, data, datalen);
129  return datalen;
130 }
131 /*---------------------------------------------------------------------------*/
132 int
133 udp_socket_sendto(struct udp_socket *c,
134  const void *data, uint16_t datalen,
135  const uip_ipaddr_t *to,
136  uint16_t port)
137 {
138  if(c == NULL || c->udp_conn == NULL) {
139  return -1;
140  }
141 
142  if(c->udp_conn != NULL) {
143  uip_udp_packet_sendto(c->udp_conn, data, datalen,
144  to, UIP_HTONS(port));
145  return datalen;
146  }
147  return -1;
148 }
149 /*---------------------------------------------------------------------------*/
150 PROCESS_THREAD(udp_socket_process, ev, data)
151 {
152  struct udp_socket *c;
153  PROCESS_BEGIN();
154 
155  while(1) {
157  if(ev == tcpip_event) {
158 
159  /* An appstate pointer is passed to use from the IP stack
160  through the 'data' pointer. We registered this appstate when
161  we did the udp_new() call in udp_socket_register() as the
162  struct udp_socket pointer. So we extract this
163  pointer and use it when calling the reception callback. */
164  c = (struct udp_socket *)data;
165 
166  /* Defensive coding: although the appstate *should* be non-null
167  here, we make sure to avoid the program crashing on us. */
168  if(c != NULL) {
169 
170  /* If we were called because of incoming data, we should call
171  the reception callback. */
172  if(uip_newdata()) {
173  /* Copy the data from the uIP data buffer into our own
174  buffer to avoid the uIP buffer being messed with by the
175  callee. */
176  memcpy(buf, uip_appdata, uip_datalen());
177 
178  /* Call the client process. We use the PROCESS_CONTEXT
179  mechanism to temporarily switch process context to the
180  client process. */
181  if(c->input_callback != NULL) {
182  PROCESS_CONTEXT_BEGIN(c->p);
183  c->input_callback(c, c->ptr,
184  &(UIP_IP_BUF->srcipaddr),
185  UIP_HTONS(UIP_IP_BUF->srcport),
186  &(UIP_IP_BUF->destipaddr),
187  UIP_HTONS(UIP_IP_BUF->destport),
188  buf, uip_datalen());
190  }
191  }
192  }
193  }
194  }
195 
196  PROCESS_END();
197 }
198 /*---------------------------------------------------------------------------*/
199 /** @} */
#define UIP_IP_BUF
Pointer to IP header.
Definition: uip-nd6.c:97
#define PROCESS(name, strname)
Declare a process.
Definition: process.h:307
#define PROCESS_CONTEXT_END(p)
End a context switch.
Definition: process.h:440
#define PROCESS_WAIT_EVENT()
Wait for an event to be posted to the process.
Definition: process.h:141
#define PROCESS_BEGIN()
Define the beginning of a process.
Definition: process.h:120
#define PROCESS_END()
Define the end of a process.
Definition: process.h:131
process_event_t tcpip_event
The uIP event.
Definition: tcpip.c:66
#define UIP_BUFSIZE
The size of the uIP packet buffer.
Definition: uipopt.h:154
#define PROCESS_CURRENT()
Get a pointer to the currently running process.
Definition: process.h:402
#define uip_newdata()
Is new incoming data available?
Definition: uip.h:729
struct uip_udp_conn * udp_new(const uip_ipaddr_t *ripaddr, uint16_t port, void *appstate)
Create a new UDP connection.
Definition: tcpip.c:265
#define uip_ipaddr_copy(dest, src)
Copy an IP address from one place to another.
Definition: uip.h:1018
#define UIP_HTONS(n)
Convert 16-bit quantity from host byte order to network byte order.
Definition: uip.h:1230
#define PROCESS_CONTEXT_BEGIN(p)
Switch context to another process.
Definition: process.h:426
#define uip_udp_remove(conn)
Remove a UDP connection.
Definition: uip.h:867
PROCESS_THREAD(cc2538_rf_process, ev, data)
Implementation of the cc2538 RF driver process.
Definition: cc2538-rf.c:1035
#define udp_bind(conn, port)
Bind a UDP connection to a local port.
Definition: tcpip.h:261
void * uip_appdata
Pointer to the application data in the packet buffer.
Definition: uip6.c:168
#define uip_datalen()
The length of any incoming data that is currently available (if available) in the uip_appdata buffer...
Definition: uip.h:642
void process_start(struct process *p, process_data_t data)
Start a process.
Definition: process.c:99