Contiki-NG
Loading...
Searching...
No Matches
tcp-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#define DEBUG DEBUG_NONE
33#include "net/ipv6/uip-debug.h"
34
35#include "contiki.h"
36#include "sys/cc.h"
37#include "contiki-net.h"
38
39#include "lib/list.h"
40
41#include "tcp-socket.h"
42
43#if UIP_TCP
44
45#include <string.h>
46
47static void relisten(struct tcp_socket *s);
48
49LIST(socketlist);
50/*---------------------------------------------------------------------------*/
51PROCESS(tcp_socket_process, "TCP socket process");
52/*---------------------------------------------------------------------------*/
53static void
54call_event(struct tcp_socket *s, tcp_socket_event_t event)
55{
56 if(s != NULL && s->event_callback != NULL) {
57 s->event_callback(s, s->ptr, event);
58 }
59}
60/*---------------------------------------------------------------------------*/
61static void
62senddata(struct tcp_socket *s)
63{
64 int len = MIN(s->output_data_max_seg, uip_mss());
65
66 if(s->output_senddata_len > 0) {
67 len = MIN(s->output_senddata_len, len);
68 s->output_data_send_nxt = len;
69 uip_send(s->output_data_ptr, len);
70 }
71}
72/*---------------------------------------------------------------------------*/
73static void
74acked(struct tcp_socket *s)
75{
76 if(s->output_senddata_len > 0) {
77 /* Copy the data in the outputbuf down and update outputbufptr and
78 outputbuf_lastsent */
79
80 if(s->output_data_send_nxt > 0) {
81 memmove(&s->output_data_ptr[0],
82 &s->output_data_ptr[s->output_data_send_nxt],
83 s->output_data_maxlen - s->output_data_send_nxt);
84 }
85 if(s->output_data_len < s->output_data_send_nxt) {
86 PRINTF("tcp: acked assertion failed s->output_data_len (%d) < s->output_data_send_nxt (%d)\n",
87 s->output_data_len,
88 s->output_data_send_nxt);
89 tcp_markconn(uip_conn, NULL);
90 uip_abort();
91 call_event(s, TCP_SOCKET_ABORTED);
92 relisten(s);
93 return;
94 }
95 s->output_data_len -= s->output_data_send_nxt;
96 s->output_senddata_len = s->output_data_len;
97 s->output_data_send_nxt = 0;
98
99 call_event(s, TCP_SOCKET_DATA_SENT);
100 }
101}
102/*---------------------------------------------------------------------------*/
103static void
104newdata(struct tcp_socket *s)
105{
106 uint16_t len, copylen, bytesleft;
107 uint8_t *dataptr;
108 len = uip_datalen();
109 dataptr = uip_appdata;
110
111 /* We have a segment with data coming in. We copy as much data as
112 possible into the input buffer and call the input callback
113 function. The input callback returns the number of bytes that
114 should be retained in the buffer, or zero if all data should be
115 consumed. If there is data to be retained, the highest bytes of
116 data are copied down into the input buffer. */
117 do {
118 copylen = MIN(len, s->input_data_maxlen);
119 memcpy(s->input_data_ptr, dataptr, copylen);
120 if(s->input_callback) {
121 bytesleft = s->input_callback(s, s->ptr,
122 s->input_data_ptr, copylen);
123 } else {
124 bytesleft = 0;
125 }
126 if(bytesleft > 0) {
127 PRINTF("tcp: newdata, bytesleft > 0 (%d) not implemented\n", bytesleft);
128 }
129 dataptr += copylen;
130 len -= copylen;
131
132 } while(len > 0);
133}
134/*---------------------------------------------------------------------------*/
135static void
136relisten(struct tcp_socket *s)
137{
138 if(s != NULL && s->listen_port != 0) {
139 s->flags |= TCP_SOCKET_FLAGS_LISTENING;
140 }
141}
142/*---------------------------------------------------------------------------*/
143static void
144appcall(void *state)
145{
146 struct tcp_socket *s = state;
147
148 if(s != NULL && s->c != NULL && s->c != uip_conn) {
149 /* Safe-guard: this should not happen, as the incoming event relates to
150 * a previous connection */
151 return;
152 }
153 if(uip_connected()) {
154 /* Check if this connection originated in a local listen
155 socket. We do this by checking the state pointer - if NULL,
156 this is an incoming listen connection. If so, we need to
157 connect the socket to the uip_conn and call the event
158 function. */
159 if(s == NULL) {
160 for(s = list_head(socketlist);
161 s != NULL;
162 s = list_item_next(s)) {
163 if((s->flags & TCP_SOCKET_FLAGS_LISTENING) != 0 &&
164 s->listen_port != 0 &&
165 s->listen_port == uip_htons(uip_conn->lport)) {
166 s->flags &= ~TCP_SOCKET_FLAGS_LISTENING;
167 s->output_data_max_seg = uip_mss();
168 tcp_markconn(uip_conn, s);
169 call_event(s, TCP_SOCKET_CONNECTED);
170 break;
171 }
172 }
173 } else {
174 s->output_data_max_seg = uip_mss();
175 call_event(s, TCP_SOCKET_CONNECTED);
176 }
177
178 if(s == NULL) {
179 uip_abort();
180 } else {
181 if(uip_newdata()) {
182 newdata(s);
183 }
184 senddata(s);
185 }
186 return;
187 }
188
189 if(uip_timedout()) {
190 call_event(s, TCP_SOCKET_TIMEDOUT);
191 relisten(s);
192 }
193
194 if(uip_aborted()) {
195 tcp_markconn(uip_conn, NULL);
196 call_event(s, TCP_SOCKET_ABORTED);
197 relisten(s);
198
199 }
200
201 if(s == NULL) {
202 uip_abort();
203 return;
204 }
205
206 if(uip_acked()) {
207 acked(s);
208 }
209 if(uip_newdata()) {
210 newdata(s);
211 }
212
213 if(uip_rexmit() ||
214 uip_newdata() ||
215 uip_acked()) {
216 senddata(s);
217 } else if(uip_poll()) {
218 senddata(s);
219 }
220
221 if(s->output_data_len == 0 && s->flags & TCP_SOCKET_FLAGS_CLOSING) {
222 s->flags &= ~TCP_SOCKET_FLAGS_CLOSING;
223 uip_close();
224 s->c = NULL;
225 tcp_markconn(uip_conn, NULL);
226 s->c = NULL;
227 relisten(s);
228 }
229
230 if(uip_closed()) {
231 tcp_markconn(uip_conn, NULL);
232 s->c = NULL;
233 call_event(s, TCP_SOCKET_CLOSED);
234 relisten(s);
235 }
236}
237/*---------------------------------------------------------------------------*/
238PROCESS_THREAD(tcp_socket_process, ev, data)
239{
241 while(1) {
243
244 if(ev == tcpip_event) {
245 appcall(data);
246 }
247 }
248 PROCESS_END();
249}
250/*---------------------------------------------------------------------------*/
251static void
252init(void)
253{
254 static uint8_t inited = 0;
255 if(!inited) {
256 list_init(socketlist);
257 process_start(&tcp_socket_process, NULL);
258 inited = 1;
259 }
260}
261/*---------------------------------------------------------------------------*/
262int
263tcp_socket_register(struct tcp_socket *s, void *ptr,
264 uint8_t *input_databuf, int input_databuf_len,
265 uint8_t *output_databuf, int output_databuf_len,
266 tcp_socket_data_callback_t input_callback,
267 tcp_socket_event_callback_t event_callback)
268{
269
270 init();
271
272 if(s == NULL) {
273 return -1;
274 }
275 s->ptr = ptr;
276 s->input_data_ptr = input_databuf;
277 s->input_data_maxlen = input_databuf_len;
278 s->output_data_len = 0;
279 s->output_data_ptr = output_databuf;
280 s->output_data_maxlen = output_databuf_len;
281 s->input_callback = input_callback;
282 s->event_callback = event_callback;
283 list_add(socketlist, s);
284
285 s->listen_port = 0;
286 s->flags = TCP_SOCKET_FLAGS_NONE;
287 return 1;
288}
289/*---------------------------------------------------------------------------*/
290int
291tcp_socket_connect(struct tcp_socket *s,
292 const uip_ipaddr_t *ipaddr,
293 uint16_t port)
294{
295 if(s == NULL) {
296 return -1;
297 }
298 if(s->c != NULL) {
299 tcp_markconn(s->c, NULL);
300 }
301 PROCESS_CONTEXT_BEGIN(&tcp_socket_process);
302 s->c = tcp_connect(ipaddr, uip_htons(port), s);
304 if(s->c == NULL) {
305 return -1;
306 } else {
307 return 1;
308 }
309}
310/*---------------------------------------------------------------------------*/
311int
312tcp_socket_listen(struct tcp_socket *s,
313 uint16_t port)
314{
315 if(s == NULL) {
316 return -1;
317 }
318
319 s->listen_port = port;
320 PROCESS_CONTEXT_BEGIN(&tcp_socket_process);
321 tcp_listen(uip_htons(port));
323 s->flags |= TCP_SOCKET_FLAGS_LISTENING;
324 return 1;
325}
326/*---------------------------------------------------------------------------*/
327int
328tcp_socket_unlisten(struct tcp_socket *s)
329{
330 if(s == NULL) {
331 return -1;
332 }
333
334 PROCESS_CONTEXT_BEGIN(&tcp_socket_process);
335 tcp_unlisten(uip_htons(s->listen_port));
337 s->listen_port = 0;
338 s->flags &= ~TCP_SOCKET_FLAGS_LISTENING;
339 return 1;
340}
341/*---------------------------------------------------------------------------*/
342int
343tcp_socket_send(struct tcp_socket *s,
344 const uint8_t *data, int datalen)
345{
346 int len;
347
348 if(s == NULL) {
349 return -1;
350 }
351
352 len = MIN(datalen, s->output_data_maxlen - s->output_data_len);
353
354 memmove(&s->output_data_ptr[s->output_data_len], data, len);
355 s->output_data_len += len;
356
357 if(s->output_senddata_len == 0) {
358 s->output_senddata_len = s->output_data_len;
359 }
360
361 tcpip_poll_tcp(s->c);
362
363 return len;
364}
365/*---------------------------------------------------------------------------*/
366int
367tcp_socket_send_str(struct tcp_socket *s,
368 const char *str)
369{
370 return tcp_socket_send(s, (const uint8_t *)str, strlen(str));
371}
372/*---------------------------------------------------------------------------*/
373int
374tcp_socket_close(struct tcp_socket *s)
375{
376 if(s == NULL) {
377 return -1;
378 }
379
380 s->flags |= TCP_SOCKET_FLAGS_CLOSING;
381 return 1;
382}
383/*---------------------------------------------------------------------------*/
384int
385tcp_socket_unregister(struct tcp_socket *s)
386{
387 if(s == NULL) {
388 return -1;
389 }
390
391 tcp_socket_unlisten(s);
392 if(s->c != NULL) {
393 tcp_attach(s->c, NULL);
394 }
395 list_remove(socketlist, s);
396 return 1;
397}
398/*---------------------------------------------------------------------------*/
399int
400tcp_socket_max_sendlen(struct tcp_socket *s)
401{
402 return s->output_data_maxlen - s->output_data_len;
403}
404/*---------------------------------------------------------------------------*/
405int
406tcp_socket_queuelen(struct tcp_socket *s)
407{
408 return s->output_data_len;
409}
410/*---------------------------------------------------------------------------*/
411#endif /* UIP_TCP */
Default definitions of C compiler quirk work-arounds.
static void list_init(list_t list)
Initialize a list.
Definition list.h:152
#define LIST(name)
Declare a linked list.
Definition list.h:90
static void * list_item_next(const void *item)
Get the next item following this item.
Definition list.h:294
void list_add(list_t list, void *item)
Add an item at the end of a list.
Definition list.c:71
void list_remove(list_t list, const void *item)
Remove a specific element from a list.
Definition list.c:134
static void * list_head(const_list_t list)
Get a pointer to the first element of a list.
Definition list.h:169
#define PROCESS(name, strname)
Declare a process.
Definition process.h:307
#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
void process_start(struct process *p, process_data_t data)
Start a process.
Definition process.c:107
#define PROCESS_CONTEXT_BEGIN(p)
Switch context to another process.
Definition process.h:426
#define PROCESS_THREAD(name, ev, data)
Define the body of a process.
Definition process.h:273
#define PROCESS_CONTEXT_END(p)
End a context switch.
Definition process.h:440
void tcp_unlisten(uint16_t port)
Close a listening TCP port.
Definition tcpip.c:214
process_event_t tcpip_event
The uIP event.
Definition tcpip.c:62
struct uip_conn * tcp_connect(const uip_ipaddr_t *ripaddr, uint16_t port, void *appstate)
Open a TCP connection to the specified IP address and port.
void tcp_attach(struct uip_conn *conn, void *appstate)
Attach a TCP connection to the current process.
Definition tcpip.c:250
void tcpip_poll_tcp(struct uip_conn *conn)
Cause a specified TCP connection to be polled.
Definition tcpip.c:747
void tcp_listen(uint16_t port)
Open a TCP port.
Definition tcpip.c:232
void * uip_appdata
Pointer to the application data in the packet buffer.
Definition uip6.c:148
void uip_send(const void *data, int len)
Send data on the current connection.
Definition uip6.c:2353
#define uip_datalen()
The length of any incoming data that is currently available (if available) in the uip_appdata buffer.
Definition uip.h:593
#define uip_newdata()
Is new incoming data available?
Definition uip.h:680
#define uip_poll()
Is the connection being polled by uIP?
Definition uip.h:759
#define uip_close()
Close the current connection.
Definition uip.h:613
#define uip_timedout()
Has the connection timed out?
Definition uip.h:733
#define uip_abort()
Abort the current connection.
Definition uip.h:624
#define uip_rexmit()
Do we need to retransmit previously data?
Definition uip.h:745
#define uip_mss()
Get the current maximum segment size that can be sent on the current connection.
Definition uip.h:780
#define uip_connected()
Has the connection just been connected?
Definition uip.h:703
#define uip_acked()
Has previously sent data been acknowledged?
Definition uip.h:691
#define uip_closed()
Has the connection been closed by the other end?
Definition uip.h:713
#define uip_aborted()
Has the connection been aborted by the other end?
Definition uip.h:723
uint16_t uip_htons(uint16_t val)
Convert a 16-bit quantity from host byte order to network byte order.
Definition uip6.c:2341
static void newdata(void)
Definition resolv.c:719
Linked list manipulation routines.
Representation of a uIP TCP connection.
Definition uip.h:1258
uint16_t lport
The local TCP port, in network byte order.
Definition uip.h:1261
A set of debugging macros for the IP stack.
static uip_ipaddr_t ipaddr
Pointer to prefix information option in uip_buf.
Definition uip-nd6.c:116