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 /*---------------------------------------------------------------------------*/
42 static void
43 init(void)
44 {
45  static uint8_t inited = 0;
46  if(!inited) {
47  inited = 1;
48  process_start(&udp_socket_process, NULL);
49  }
50 }
51 /*---------------------------------------------------------------------------*/
52 int
53 udp_socket_register(struct udp_socket *c,
54  void *ptr,
55  udp_socket_input_callback_t input_callback)
56 {
57  init();
58 
59  if(c == NULL) {
60  return -1;
61  }
62  c->ptr = ptr;
63  c->input_callback = input_callback;
64 
65  c->p = PROCESS_CURRENT();
66  PROCESS_CONTEXT_BEGIN(&udp_socket_process);
67  c->udp_conn = udp_new(NULL, 0, c);
69 
70  if(c->udp_conn == NULL) {
71  return -1;
72  }
73  return 1;
74 }
75 /*---------------------------------------------------------------------------*/
76 int
77 udp_socket_close(struct udp_socket *c)
78 {
79  if(c == NULL) {
80  return -1;
81  }
82  if(c->udp_conn != NULL) {
83  uip_udp_remove(c->udp_conn);
84  return 1;
85  }
86  return -1;
87 }
88 /*---------------------------------------------------------------------------*/
89 int
90 udp_socket_bind(struct udp_socket *c,
91  uint16_t local_port)
92 {
93  if(c == NULL || c->udp_conn == NULL) {
94  return -1;
95  }
96  udp_bind(c->udp_conn, UIP_HTONS(local_port));
97 
98  return 1;
99 }
100 /*---------------------------------------------------------------------------*/
101 int
102 udp_socket_connect(struct udp_socket *c,
103  uip_ipaddr_t *remote_addr,
104  uint16_t remote_port)
105 {
106  if(c == NULL || c->udp_conn == NULL) {
107  return -1;
108  }
109 
110  if(remote_addr != NULL) {
111  uip_ipaddr_copy(&c->udp_conn->ripaddr, remote_addr);
112  }
113  c->udp_conn->rport = UIP_HTONS(remote_port);
114  return 1;
115 }
116 /*---------------------------------------------------------------------------*/
117 int
118 udp_socket_send(struct udp_socket *c,
119  const void *data, uint16_t datalen)
120 {
121  if(c == NULL || c->udp_conn == NULL) {
122  return -1;
123  }
124 
125  uip_udp_packet_send(c->udp_conn, data, datalen);
126  return datalen;
127 }
128 /*---------------------------------------------------------------------------*/
129 int
130 udp_socket_sendto(struct udp_socket *c,
131  const void *data, uint16_t datalen,
132  const uip_ipaddr_t *to,
133  uint16_t port)
134 {
135  if(c == NULL || c->udp_conn == NULL) {
136  return -1;
137  }
138 
139  if(c->udp_conn != NULL) {
140  uip_udp_packet_sendto(c->udp_conn, data, datalen,
141  to, UIP_HTONS(port));
142  return datalen;
143  }
144  return -1;
145 }
146 /*---------------------------------------------------------------------------*/
147 PROCESS_THREAD(udp_socket_process, ev, data)
148 {
149  struct udp_socket *c;
150  PROCESS_BEGIN();
151 
152  while(1) {
154  if(ev == tcpip_event) {
155 
156  /* An appstate pointer is passed to use from the IP stack
157  through the 'data' pointer. We registered this appstate when
158  we did the udp_new() call in udp_socket_register() as the
159  struct udp_socket pointer. So we extract this
160  pointer and use it when calling the reception callback. */
161  c = (struct udp_socket *)data;
162 
163  /* Defensive coding: although the appstate *should* be non-null
164  here, we make sure to avoid the program crashing on us. */
165  if(c != NULL) {
166 
167  /* If we were called because of incoming data, we should call
168  the reception callback. */
169  if(uip_newdata()) {
170  /* Copy the data from the uIP data buffer into our own
171  buffer to avoid the uIP buffer being messed with by the
172  callee. */
173  memcpy(buf, uip_appdata, uip_datalen());
174 
175  /* Call the client process. We use the PROCESS_CONTEXT
176  mechanism to temporarily switch process context to the
177  client process. */
178  if(c->input_callback != NULL) {
179  PROCESS_CONTEXT_BEGIN(c->p);
180  c->input_callback(c, c->ptr,
181  &(UIP_IP_BUF->srcipaddr),
182  UIP_HTONS(UIP_UDP_BUF->srcport),
183  &(UIP_IP_BUF->destipaddr),
184  UIP_HTONS(UIP_UDP_BUF->destport),
185  buf, uip_datalen());
187  }
188  }
189  }
190  }
191  }
192 
193  PROCESS_END();
194 }
195 /*---------------------------------------------------------------------------*/
196 /** @} */
#define UIP_IP_BUF
Direct access to IPv6 header.
Definition: uip.h:71
#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:62
#define UIP_BUFSIZE
The size of the uIP packet buffer.
Definition: uipopt.h:134
#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:726
struct uip_udp_conn * udp_new(const uip_ipaddr_t *ripaddr, uint16_t port, void *appstate)
Create a new UDP connection.
Definition: tcpip.c:261
#define uip_ipaddr_copy(dest, src)
Copy an IP address from one place to another.
Definition: uip.h:1015
#define UIP_HTONS(n)
Convert 16-bit quantity from host byte order to network byte order.
Definition: uip.h:1223
#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:864
PROCESS_THREAD(cc2538_rf_process, ev, data)
Implementation of the cc2538 RF driver process.
Definition: cc2538-rf.c:1107
#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:148
#define uip_datalen()
The length of any incoming data that is currently available (if available) in the uip_appdata buffer...
Definition: uip.h:639
void process_start(struct process *p, process_data_t data)
Start a process.
Definition: process.c:99