Merge pull request #620 from adamdunkels/push/socket-api
New TCP and UDP socket APIs
This commit is contained in:
commit
3829860c3c
|
@ -54,6 +54,9 @@
|
||||||
|
|
||||||
#include "net/ip/psock.h"
|
#include "net/ip/psock.h"
|
||||||
|
|
||||||
|
#include "net/ip/udp-socket.h"
|
||||||
|
#include "net/ip/tcp-socket.h"
|
||||||
|
|
||||||
#include "net/rime/rime.h"
|
#include "net/rime/rime.h"
|
||||||
|
|
||||||
#include "net/netstack.h"
|
#include "net/netstack.h"
|
||||||
|
|
365
core/net/ip/tcp-socket.c
Normal file
365
core/net/ip/tcp-socket.c
Normal file
|
@ -0,0 +1,365 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2012-2014, Thingsquare, http://www.thingsquare.com/.
|
||||||
|
* 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 copyright holder 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 COPYRIGHT HOLDERS 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
|
||||||
|
* COPYRIGHT HOLDER 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "contiki.h"
|
||||||
|
#include "contiki-net.h"
|
||||||
|
|
||||||
|
#include "lib/list.h"
|
||||||
|
|
||||||
|
#include "tcp-socket.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||||
|
|
||||||
|
LIST(socketlist);
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
PROCESS(tcp_socket_process, "TCP socket process");
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static void
|
||||||
|
call_event(struct tcp_socket *s, tcp_socket_event_t event)
|
||||||
|
{
|
||||||
|
if(s != NULL && s->event_callback != NULL) {
|
||||||
|
s->event_callback(s, s->ptr, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static void
|
||||||
|
senddata(struct tcp_socket *s)
|
||||||
|
{
|
||||||
|
int len;
|
||||||
|
|
||||||
|
if(s->output_data_len > 0) {
|
||||||
|
len = MIN(s->output_data_len, uip_mss());
|
||||||
|
s->output_data_send_nxt = len;
|
||||||
|
uip_send(s->output_data_ptr, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static void
|
||||||
|
acked(struct tcp_socket *s)
|
||||||
|
{
|
||||||
|
if(s->output_data_len > 0) {
|
||||||
|
/* Copy the data in the outputbuf down and update outputbufptr and
|
||||||
|
outputbuf_lastsent */
|
||||||
|
|
||||||
|
if(s->output_data_send_nxt > 0) {
|
||||||
|
memcpy(&s->output_data_ptr[0],
|
||||||
|
&s->output_data_ptr[s->output_data_send_nxt],
|
||||||
|
s->output_data_maxlen - s->output_data_send_nxt);
|
||||||
|
}
|
||||||
|
if(s->output_data_len < s->output_data_send_nxt) {
|
||||||
|
printf("tcp: acked assertion failed s->output_data_len (%d) < s->output_data_send_nxt (%d)\n",
|
||||||
|
s->output_data_len,
|
||||||
|
s->output_data_send_nxt);
|
||||||
|
}
|
||||||
|
s->output_data_len -= s->output_data_send_nxt;
|
||||||
|
s->output_data_send_nxt = 0;
|
||||||
|
|
||||||
|
call_event(s, TCP_SOCKET_DATA_SENT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static void
|
||||||
|
newdata(struct tcp_socket *s)
|
||||||
|
{
|
||||||
|
uint16_t len, copylen, bytesleft;
|
||||||
|
uint8_t *dataptr;
|
||||||
|
len = uip_datalen();
|
||||||
|
dataptr = uip_appdata;
|
||||||
|
|
||||||
|
/* We have a segment with data coming in. We copy as much data as
|
||||||
|
possible into the input buffer and call the input callback
|
||||||
|
function. The input callback returns the number of bytes that
|
||||||
|
should be retained in the buffer, or zero if all data should be
|
||||||
|
consumed. If there is data to be retained, the highest bytes of
|
||||||
|
data are copied down into the input buffer. */
|
||||||
|
do {
|
||||||
|
copylen = MIN(len, s->input_data_maxlen);
|
||||||
|
memcpy(s->input_data_ptr, dataptr, copylen);
|
||||||
|
if(s->input_callback) {
|
||||||
|
bytesleft = s->input_callback(s, s->ptr,
|
||||||
|
s->input_data_ptr, copylen);
|
||||||
|
} else {
|
||||||
|
bytesleft = 0;
|
||||||
|
}
|
||||||
|
if(bytesleft > 0) {
|
||||||
|
printf("tcp: newdata, bytesleft > 0 (%d) not implemented\n", bytesleft);
|
||||||
|
}
|
||||||
|
dataptr += copylen;
|
||||||
|
len -= copylen;
|
||||||
|
|
||||||
|
} while(len > 0);
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static void
|
||||||
|
relisten(struct tcp_socket *s)
|
||||||
|
{
|
||||||
|
if(s != NULL && s->listen_port != 0) {
|
||||||
|
s->flags |= TCP_SOCKET_FLAGS_LISTENING;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static void
|
||||||
|
appcall(void *state)
|
||||||
|
{
|
||||||
|
struct tcp_socket *s = state;
|
||||||
|
|
||||||
|
if(uip_connected()) {
|
||||||
|
/* Check if this connection originated in a local listen
|
||||||
|
socket. We do this by checking the state pointer - if NULL,
|
||||||
|
this is an incoming listen connection. If so, we need to
|
||||||
|
connect the socket to the uip_conn and call the event
|
||||||
|
function. */
|
||||||
|
if(s == NULL) {
|
||||||
|
for(s = list_head(socketlist);
|
||||||
|
s != NULL;
|
||||||
|
s = list_item_next(s)) {
|
||||||
|
if((s->flags & TCP_SOCKET_FLAGS_LISTENING) != 0 &&
|
||||||
|
s->listen_port != 0 &&
|
||||||
|
s->listen_port == uip_htons(uip_conn->lport)) {
|
||||||
|
s->flags &= ~TCP_SOCKET_FLAGS_LISTENING;
|
||||||
|
tcp_markconn(uip_conn, s);
|
||||||
|
call_event(s, TCP_SOCKET_CONNECTED);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
call_event(s, TCP_SOCKET_CONNECTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(s == NULL) {
|
||||||
|
uip_abort();
|
||||||
|
} else {
|
||||||
|
if(uip_newdata()) {
|
||||||
|
newdata(s);
|
||||||
|
}
|
||||||
|
senddata(s);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(uip_timedout()) {
|
||||||
|
call_event(s, TCP_SOCKET_TIMEDOUT);
|
||||||
|
relisten(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(uip_aborted()) {
|
||||||
|
call_event(s, TCP_SOCKET_ABORTED);
|
||||||
|
relisten(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(s == NULL) {
|
||||||
|
uip_abort();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(uip_acked()) {
|
||||||
|
acked(s);
|
||||||
|
}
|
||||||
|
if(uip_newdata()) {
|
||||||
|
newdata(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(uip_rexmit() ||
|
||||||
|
uip_newdata() ||
|
||||||
|
uip_acked()) {
|
||||||
|
senddata(s);
|
||||||
|
} else if(uip_poll()) {
|
||||||
|
senddata(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(s->output_data_len == 0 && s->flags & TCP_SOCKET_FLAGS_CLOSING) {
|
||||||
|
s->flags &= ~TCP_SOCKET_FLAGS_CLOSING;
|
||||||
|
uip_close();
|
||||||
|
tcp_markconn(uip_conn, NULL);
|
||||||
|
call_event(s, TCP_SOCKET_CLOSED);
|
||||||
|
relisten(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(uip_closed()) {
|
||||||
|
tcp_markconn(uip_conn, NULL);
|
||||||
|
call_event(s, TCP_SOCKET_CLOSED);
|
||||||
|
relisten(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
PROCESS_THREAD(tcp_socket_process, ev, data)
|
||||||
|
{
|
||||||
|
PROCESS_BEGIN();
|
||||||
|
while(1) {
|
||||||
|
PROCESS_WAIT_EVENT();
|
||||||
|
|
||||||
|
if(ev == tcpip_event) {
|
||||||
|
appcall(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PROCESS_END();
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static void
|
||||||
|
init(void)
|
||||||
|
{
|
||||||
|
static uint8_t inited = 0;
|
||||||
|
if(!inited) {
|
||||||
|
list_init(socketlist);
|
||||||
|
process_start(&tcp_socket_process, NULL);
|
||||||
|
inited = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
int
|
||||||
|
tcp_socket_register(struct tcp_socket *s, void *ptr,
|
||||||
|
uint8_t *input_databuf, int input_databuf_len,
|
||||||
|
uint8_t *output_databuf, int output_databuf_len,
|
||||||
|
tcp_socket_data_callback_t input_callback,
|
||||||
|
tcp_socket_event_callback_t event_callback)
|
||||||
|
{
|
||||||
|
|
||||||
|
init();
|
||||||
|
|
||||||
|
if(s == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
s->ptr = ptr;
|
||||||
|
s->input_data_ptr = input_databuf;
|
||||||
|
s->input_data_maxlen = input_databuf_len;
|
||||||
|
s->output_data_ptr = output_databuf;
|
||||||
|
s->output_data_maxlen = output_databuf_len;
|
||||||
|
s->input_callback = input_callback;
|
||||||
|
s->event_callback = event_callback;
|
||||||
|
list_add(socketlist, s);
|
||||||
|
|
||||||
|
s->listen_port = 0;
|
||||||
|
s->flags = TCP_SOCKET_FLAGS_NONE;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
int
|
||||||
|
tcp_socket_connect(struct tcp_socket *s,
|
||||||
|
uip_ipaddr_t *ipaddr,
|
||||||
|
uint16_t port)
|
||||||
|
{
|
||||||
|
if(s == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
PROCESS_CONTEXT_BEGIN(&tcp_socket_process);
|
||||||
|
s->c = tcp_connect(ipaddr, uip_htons(port), s);
|
||||||
|
PROCESS_CONTEXT_END();
|
||||||
|
if(s->c == NULL) {
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
int
|
||||||
|
tcp_socket_listen(struct tcp_socket *s,
|
||||||
|
uint16_t port)
|
||||||
|
{
|
||||||
|
if(s == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
s->listen_port = port;
|
||||||
|
PROCESS_CONTEXT_BEGIN(&tcp_socket_process);
|
||||||
|
tcp_listen(uip_htons(port));
|
||||||
|
PROCESS_CONTEXT_END();
|
||||||
|
s->flags |= TCP_SOCKET_FLAGS_LISTENING;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
int
|
||||||
|
tcp_socket_unlisten(struct tcp_socket *s)
|
||||||
|
{
|
||||||
|
if(s == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
PROCESS_CONTEXT_BEGIN(&tcp_socket_process);
|
||||||
|
tcp_unlisten(uip_htons(s->listen_port));
|
||||||
|
PROCESS_CONTEXT_END();
|
||||||
|
s->listen_port = 0;
|
||||||
|
s->flags &= ~TCP_SOCKET_FLAGS_LISTENING;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
int
|
||||||
|
tcp_socket_send(struct tcp_socket *s,
|
||||||
|
const uint8_t *data, int datalen)
|
||||||
|
{
|
||||||
|
int len;
|
||||||
|
|
||||||
|
if(s == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
len = MIN(datalen, s->output_data_maxlen - s->output_data_len);
|
||||||
|
|
||||||
|
memcpy(&s->output_data_ptr[s->output_data_len], data, len);
|
||||||
|
s->output_data_len += len;
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
int
|
||||||
|
tcp_socket_send_str(struct tcp_socket *s,
|
||||||
|
const char *str)
|
||||||
|
{
|
||||||
|
return tcp_socket_send(s, (const uint8_t *)str, strlen(str));
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
int
|
||||||
|
tcp_socket_close(struct tcp_socket *s)
|
||||||
|
{
|
||||||
|
if(s == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
s->flags |= TCP_SOCKET_FLAGS_CLOSING;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
int
|
||||||
|
tcp_socket_unregister(struct tcp_socket *s)
|
||||||
|
{
|
||||||
|
if(s == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
tcp_socket_unlisten(s);
|
||||||
|
if(s->c != NULL) {
|
||||||
|
tcp_attach(s->c, NULL);
|
||||||
|
}
|
||||||
|
list_remove(socketlist, s);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
268
core/net/ip/tcp-socket.h
Normal file
268
core/net/ip/tcp-socket.h
Normal file
|
@ -0,0 +1,268 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2012-2014, Thingsquare, http://www.thingsquare.com/.
|
||||||
|
* 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 copyright holder 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 COPYRIGHT HOLDERS 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
|
||||||
|
* COPYRIGHT HOLDER 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TCP_SOCKET_H
|
||||||
|
#define TCP_SOCKET_H
|
||||||
|
|
||||||
|
struct tcp_socket;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
TCP_SOCKET_CONNECTED,
|
||||||
|
TCP_SOCKET_CLOSED,
|
||||||
|
TCP_SOCKET_TIMEDOUT,
|
||||||
|
TCP_SOCKET_ABORTED,
|
||||||
|
TCP_SOCKET_DATA_SENT
|
||||||
|
} tcp_socket_event_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief TCP data callback function
|
||||||
|
* \param s A pointer to a TCP socket
|
||||||
|
* \param ptr A user-defined pointer
|
||||||
|
* \param input_data_ptr A pointer to the incoming data
|
||||||
|
* \param input_data_len The length of the incoming data
|
||||||
|
* \return The function should return the number of bytes to leave in the input buffer
|
||||||
|
*
|
||||||
|
* The TCP socket input callback function gets
|
||||||
|
* called whenever there is new data on the socket. The
|
||||||
|
* function can choose to either consume the data
|
||||||
|
* directly, or leave it in the buffer for later. The
|
||||||
|
* function must return the amount of data to leave in the
|
||||||
|
* buffer. I.e., if the callback function consumes all
|
||||||
|
* incoming data, it should return 0.
|
||||||
|
*/
|
||||||
|
typedef int (* tcp_socket_data_callback_t)(struct tcp_socket *s,
|
||||||
|
void *ptr,
|
||||||
|
const uint8_t *input_data_ptr,
|
||||||
|
int input_data_len);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief TCP event callback function
|
||||||
|
* \param s A pointer to a TCP socket
|
||||||
|
* \param ptr A user-defined pointer
|
||||||
|
* \param event The event number
|
||||||
|
*
|
||||||
|
* The TCP socket event callback function gets
|
||||||
|
* called whenever there is an event on a socket, such as
|
||||||
|
* the socket getting connected or closed.
|
||||||
|
*/
|
||||||
|
typedef void (* tcp_socket_event_callback_t)(struct tcp_socket *s,
|
||||||
|
void *ptr,
|
||||||
|
tcp_socket_event_t event);
|
||||||
|
|
||||||
|
struct tcp_socket {
|
||||||
|
struct tcp_socket *next;
|
||||||
|
|
||||||
|
tcp_socket_data_callback_t input_callback;
|
||||||
|
tcp_socket_event_callback_t event_callback;
|
||||||
|
void *ptr;
|
||||||
|
|
||||||
|
struct process *p;
|
||||||
|
|
||||||
|
uint8_t *input_data_ptr;
|
||||||
|
uint8_t *output_data_ptr;
|
||||||
|
|
||||||
|
uint16_t input_data_maxlen;
|
||||||
|
uint16_t input_data_len;
|
||||||
|
uint16_t output_data_maxlen;
|
||||||
|
uint16_t output_data_len;
|
||||||
|
uint16_t output_data_send_nxt;
|
||||||
|
|
||||||
|
uint8_t flags;
|
||||||
|
uint16_t listen_port;
|
||||||
|
struct uip_conn *c;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
TCP_SOCKET_FLAGS_NONE = 0x00,
|
||||||
|
TCP_SOCKET_FLAGS_LISTENING = 0x01,
|
||||||
|
TCP_SOCKET_FLAGS_CLOSING = 0x02,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Register a TCP socket
|
||||||
|
* \param s A pointer to a TCP socket
|
||||||
|
* \param ptr A user-defined pointer that will be sent to callbacks for this socket
|
||||||
|
* \param input_databuf A pointer to a memory area this socket will use for input data
|
||||||
|
* \param input_databuf_len The size of the input data buffer
|
||||||
|
* \param output_databuf A pointer to a memory area this socket will use for outgoing data
|
||||||
|
* \param output_databuf_len The size of the output data buffer
|
||||||
|
* \param data_callback A pointer to the data callback function for this socket
|
||||||
|
* \param event_callback A pointer to the event callback function for this socket
|
||||||
|
* \retval -1 If an error occurs
|
||||||
|
* \retval 1 If the operation succeeds.
|
||||||
|
*
|
||||||
|
* This function registers a TCP socket. The function sets
|
||||||
|
* up the output and input buffers for the socket and
|
||||||
|
* callback pointers.
|
||||||
|
*
|
||||||
|
* TCP sockets use input and output buffers for incoming
|
||||||
|
* and outgoing data. The memory for these buffers must be
|
||||||
|
* allocated by the caller. The size of the buffers
|
||||||
|
* determine the amount of data that can be received and
|
||||||
|
* sent, and the principle is that the application that
|
||||||
|
* sets up the TCP socket will know roughly how large
|
||||||
|
* these buffers should be. The rule of thumb is that the
|
||||||
|
* input buffer should be large enough to hold the largest
|
||||||
|
* application layer message that the application will
|
||||||
|
* receive and the output buffer should be large enough to
|
||||||
|
* hold the largest application layer message the
|
||||||
|
* application will send.
|
||||||
|
*
|
||||||
|
* TCP throttles incoming data so that if the input buffer
|
||||||
|
* is filled, the connection will halt until the
|
||||||
|
* application has read out the data from the input
|
||||||
|
* buffer.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int tcp_socket_register(struct tcp_socket *s, void *ptr,
|
||||||
|
uint8_t *input_databuf, int input_databuf_len,
|
||||||
|
uint8_t *output_databuf, int output_databuf_len,
|
||||||
|
tcp_socket_data_callback_t data_callback,
|
||||||
|
tcp_socket_event_callback_t event_callback);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Connect a TCP socket to a remote host
|
||||||
|
* \param s A pointer to a TCP socket that must have been previously registered with tcp_socket_register()
|
||||||
|
* \param ipaddr The IP address of the remote host
|
||||||
|
* \param port The TCP port number, in host byte order, of the remote host
|
||||||
|
* \retval -1 If an error occurs
|
||||||
|
* \retval 1 If the operation succeeds.
|
||||||
|
*
|
||||||
|
* This function connects a TCP socket to a remote host.
|
||||||
|
*
|
||||||
|
* When the socket has connected, the event callback will
|
||||||
|
* get called with the TCP_SOCKET_CONNECTED event. If the
|
||||||
|
* remote host does not accept the connection, the
|
||||||
|
* TCP_SOCKET_ABORTED will be sent to the callback. If the
|
||||||
|
* connection times out before conecting to the remote
|
||||||
|
* host, the TCP_SOCKET_TIMEDOUT event is sent to the
|
||||||
|
* callback.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int tcp_socket_connect(struct tcp_socket *s,
|
||||||
|
uip_ipaddr_t *ipaddr,
|
||||||
|
uint16_t port);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Start listening on a specific port
|
||||||
|
* \param s A pointer to a TCP socket that must have been previously registered with tcp_socket_register()
|
||||||
|
* \param port The TCP port number, in host byte order, of the remote host
|
||||||
|
* \retval -1 If an error occurs
|
||||||
|
* \retval 1 If the operation succeeds.
|
||||||
|
*
|
||||||
|
* This function causes the TCP socket to start listening
|
||||||
|
* on the given TCP port.
|
||||||
|
*
|
||||||
|
* Several sockets can listen on the same port. If a
|
||||||
|
* remote host connects to the port, one of the listening
|
||||||
|
* sockets will get connected and the event callback will
|
||||||
|
* be called with the TCP_SOCKET_CONNECTED event. When the
|
||||||
|
* connection closes, the socket will go back to listening
|
||||||
|
* for new connections.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int tcp_socket_listen(struct tcp_socket *s,
|
||||||
|
uint16_t port);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Stop listening for new connections
|
||||||
|
* \param s A pointer to a TCP socket that must have been previously registered with tcp_socket_register()
|
||||||
|
* \retval -1 If an error occurs
|
||||||
|
* \retval 1 If the operation succeeds.
|
||||||
|
*
|
||||||
|
* This function causes a listening TCP socket to stop
|
||||||
|
* listen. The socket must previously been put into listen
|
||||||
|
* mode with tcp_socket_listen().
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int tcp_socket_unlisten(struct tcp_socket *s);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Send data on a connected TCP socket
|
||||||
|
* \param s A pointer to a TCP socket that must have been previously registered with tcp_socket_register()
|
||||||
|
* \param dataptr A pointer to the data to be sent
|
||||||
|
* \param datalen The length of the data to be sent
|
||||||
|
* \retval -1 If an error occurs
|
||||||
|
* \return The number of bytes that were successfully sent
|
||||||
|
*
|
||||||
|
* This function sends data over a connected TCP
|
||||||
|
* socket. The data is placed in the output buffer and
|
||||||
|
* sent to the remote host as soon as possiblce. When the
|
||||||
|
* data has been acknowledged by the remote host, the
|
||||||
|
* event callback is sent with the TCP_SOCKET_DATA_SENT
|
||||||
|
* event.
|
||||||
|
*/
|
||||||
|
int tcp_socket_send(struct tcp_socket *s,
|
||||||
|
const uint8_t *dataptr,
|
||||||
|
int datalen);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Send a string on a connected TCP socket
|
||||||
|
* \param s A pointer to a TCP socket that must have been previously registered with tcp_socket_register()
|
||||||
|
* \param strptr A pointer to the string to be sent
|
||||||
|
* \retval -1 If an error occurs
|
||||||
|
* \return The number of bytes that were successfully sent
|
||||||
|
*
|
||||||
|
* This is a convenience function for sending strings on a
|
||||||
|
* TCP socket. The function calls tcp_socket_send() to
|
||||||
|
* send the string.
|
||||||
|
*/
|
||||||
|
int tcp_socket_send_str(struct tcp_socket *s,
|
||||||
|
const char *strptr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Close a connected TCP socket
|
||||||
|
* \param s A pointer to a TCP socket that must have been previously registered with tcp_socket_register()
|
||||||
|
* \retval -1 If an error occurs
|
||||||
|
* \retval 1 If the operation succeeds.
|
||||||
|
*
|
||||||
|
* This function closes a connected TCP socket. When the
|
||||||
|
* socket has been successfully closed, the event callback
|
||||||
|
* is called with the TCP_SOCKET_CLOSED event.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int tcp_socket_close(struct tcp_socket *s);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Unregister a registered socket
|
||||||
|
* \param s A pointer to a TCP socket that must have been previously registered with tcp_socket_register()
|
||||||
|
* \retval -1 If an error occurs
|
||||||
|
* \retval 1 If the operation succeeds.
|
||||||
|
*
|
||||||
|
* This function unregisters a previously registered
|
||||||
|
* socket. This must be done if the process will be
|
||||||
|
* unloaded from memory. If the TCP socket is connected,
|
||||||
|
* the connection will be reset.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int tcp_socket_unregister(struct tcp_socket *s);
|
||||||
|
#endif /* TCP_SOCKET_H */
|
199
core/net/ip/udp-socket.c
Normal file
199
core/net/ip/udp-socket.c
Normal file
|
@ -0,0 +1,199 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2012-2014, Thingsquare, http://www.thingsquare.com/.
|
||||||
|
* 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 copyright holder 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 COPYRIGHT HOLDERS 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
|
||||||
|
* COPYRIGHT HOLDER 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "contiki-net.h"
|
||||||
|
#include "udp-socket.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
PROCESS(udp_socket_process, "UDP socket process");
|
||||||
|
|
||||||
|
static uint8_t buf[UIP_BUFSIZE];
|
||||||
|
|
||||||
|
#define UIP_IP_BUF ((struct uip_udpip_hdr *)&uip_buf[UIP_LLH_LEN])
|
||||||
|
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static void
|
||||||
|
init(void)
|
||||||
|
{
|
||||||
|
static uint8_t inited = 0;
|
||||||
|
if(!inited) {
|
||||||
|
inited = 1;
|
||||||
|
process_start(&udp_socket_process, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
int
|
||||||
|
udp_socket_register(struct udp_socket *c,
|
||||||
|
void *ptr,
|
||||||
|
udp_socket_input_callback_t input_callback)
|
||||||
|
{
|
||||||
|
init();
|
||||||
|
|
||||||
|
if(c == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
c->ptr = ptr;
|
||||||
|
c->input_callback = input_callback;
|
||||||
|
|
||||||
|
c->p = PROCESS_CURRENT();
|
||||||
|
PROCESS_CONTEXT_BEGIN(&udp_socket_process);
|
||||||
|
c->udp_conn = udp_new(NULL, 0, c);
|
||||||
|
PROCESS_CONTEXT_END();
|
||||||
|
|
||||||
|
if(c->udp_conn == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
int
|
||||||
|
udp_socket_close(struct udp_socket *c)
|
||||||
|
{
|
||||||
|
if(c == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if(c->udp_conn != NULL) {
|
||||||
|
uip_udp_remove(c->udp_conn);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
int
|
||||||
|
udp_socket_bind(struct udp_socket *c,
|
||||||
|
uint16_t local_port)
|
||||||
|
{
|
||||||
|
if(c == NULL || c->udp_conn == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
udp_bind(c->udp_conn, UIP_HTONS(local_port));
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
int
|
||||||
|
udp_socket_connect(struct udp_socket *c,
|
||||||
|
uip_ipaddr_t *remote_addr,
|
||||||
|
uint16_t remote_port)
|
||||||
|
{
|
||||||
|
if(c == NULL || c->udp_conn == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(remote_addr != NULL) {
|
||||||
|
uip_ipaddr_copy(&c->udp_conn->ripaddr, remote_addr);
|
||||||
|
}
|
||||||
|
c->udp_conn->rport = UIP_HTONS(remote_port);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
int
|
||||||
|
udp_socket_send(struct udp_socket *c,
|
||||||
|
const void *data, uint16_t datalen)
|
||||||
|
{
|
||||||
|
if(c == NULL || c->udp_conn == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uip_udp_packet_send(c->udp_conn, data, datalen);
|
||||||
|
return datalen;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
int
|
||||||
|
udp_socket_sendto(struct udp_socket *c,
|
||||||
|
const void *data, uint16_t datalen,
|
||||||
|
const uip_ipaddr_t *to,
|
||||||
|
uint16_t port)
|
||||||
|
{
|
||||||
|
if(c == NULL || c->udp_conn == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(c->udp_conn != NULL) {
|
||||||
|
uip_udp_packet_sendto(c->udp_conn, data, datalen,
|
||||||
|
to, UIP_HTONS(port));
|
||||||
|
return datalen;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
PROCESS_THREAD(udp_socket_process, ev, data)
|
||||||
|
{
|
||||||
|
struct udp_socket *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 udp_socket_register() as the
|
||||||
|
struct udp_socket pointer. So we extract this
|
||||||
|
pointer and use it when calling the reception callback. */
|
||||||
|
c = (struct udp_socket *)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(buf, 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->input_callback != NULL) {
|
||||||
|
PROCESS_CONTEXT_BEGIN(c->p);
|
||||||
|
c->input_callback(c, c->ptr,
|
||||||
|
&(UIP_IP_BUF->srcipaddr),
|
||||||
|
UIP_HTONS(UIP_IP_BUF->srcport),
|
||||||
|
&(UIP_IP_BUF->destipaddr),
|
||||||
|
UIP_HTONS(UIP_IP_BUF->destport),
|
||||||
|
buf, uip_datalen());
|
||||||
|
PROCESS_CONTEXT_END();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PROCESS_END();
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/** @} */
|
193
core/net/ip/udp-socket.h
Normal file
193
core/net/ip/udp-socket.h
Normal file
|
@ -0,0 +1,193 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2012-2014, Thingsquare, http://www.thingsquare.com/.
|
||||||
|
* 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 copyright holder 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 COPYRIGHT HOLDERS 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
|
||||||
|
* COPYRIGHT HOLDER 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef UDP_SOCKET_H
|
||||||
|
#define UDP_SOCKET_H
|
||||||
|
|
||||||
|
#include "net/ip/uip.h"
|
||||||
|
|
||||||
|
struct udp_socket;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief A UDP socket callback function
|
||||||
|
* \param c A pointer to the struct udp_socket that received the data
|
||||||
|
* \param ptr An opaque pointer that was specified when the UDP socket was registered with udp_socket_register()
|
||||||
|
* \param source_addr The IP address from which the datagram was sent
|
||||||
|
* \param source_port The UDP port number, in host byte order, from which the datagram was sent
|
||||||
|
* \param dest_addr The IP address that this datagram was sent to
|
||||||
|
* \param dest_port The UDP port number, in host byte order, that the datagram was sent to
|
||||||
|
* \param data A pointer to the data contents of the UDP datagram
|
||||||
|
* \param datalen The length of the data being pointed to by the data pointer
|
||||||
|
*
|
||||||
|
* Each UDP socket has a callback function that is
|
||||||
|
* registered as part of the call to
|
||||||
|
* udp_socket_register(). The callback function gets
|
||||||
|
* called every time a UDP packet is received.
|
||||||
|
*/
|
||||||
|
typedef void (* udp_socket_input_callback_t)(struct udp_socket *c,
|
||||||
|
void *ptr,
|
||||||
|
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 udp_socket {
|
||||||
|
udp_socket_input_callback_t input_callback;
|
||||||
|
void *ptr;
|
||||||
|
|
||||||
|
struct process *p;
|
||||||
|
|
||||||
|
struct uip_udp_conn *udp_conn;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Register a UDP socket
|
||||||
|
* \param c A pointer to the struct udp_socket that should be registered
|
||||||
|
* \param ptr An opaque pointer that will be passed to callbacks
|
||||||
|
* \param receive_callback A function pointer to the callback function that will be called when data arrives
|
||||||
|
* \retval -1 The registration failed
|
||||||
|
* \retval 1 The registration succeeded
|
||||||
|
*
|
||||||
|
* This function registers the UDP socket with the
|
||||||
|
* system. A UDP socket must be registered before any data
|
||||||
|
* can be sent or received over the socket.
|
||||||
|
*
|
||||||
|
* The caller must allocate memory for the struct
|
||||||
|
* udp_socket that is to be registered.
|
||||||
|
*
|
||||||
|
* A UDP socket can begin to receive data by calling
|
||||||
|
* udp_socket_bind().
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int udp_socket_register(struct udp_socket *c,
|
||||||
|
void *ptr,
|
||||||
|
udp_socket_input_callback_t receive_callback);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Bind a UDP socket to a local port
|
||||||
|
* \param c A pointer to the struct udp_socket that should be bound to a local port
|
||||||
|
* \param local_port The UDP port number, in host byte order, to bind the UDP socket to
|
||||||
|
* \retval -1 Binding the UDP socket to the local port failed
|
||||||
|
* \retval 1 Binding the UDP socket to the local port succeeded
|
||||||
|
*
|
||||||
|
* This function binds the UDP socket to a local port so
|
||||||
|
* that it will begin to receive data that arrives on the
|
||||||
|
* specified port. A UDP socket will receive data
|
||||||
|
* addressed to the specified port number on any IP
|
||||||
|
* address of the host.
|
||||||
|
*
|
||||||
|
* A UDP socket that is bound to a local port will use
|
||||||
|
* this port number as a source port in outgoing UDP
|
||||||
|
* messages.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int udp_socket_bind(struct udp_socket *c,
|
||||||
|
uint16_t local_port);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Bind a UDP socket to a remote address and port
|
||||||
|
* \param c A pointer to the struct udp_socket that should be connected
|
||||||
|
* \param remote_addr The IP address of the remote host, or NULL if the UDP socket should only be connected to a specific port
|
||||||
|
* \param remote_port The UDP port number, in host byte order, to which the UDP socket should be connected
|
||||||
|
* \retval -1 Connecting the UDP socket failed
|
||||||
|
* \retval 1 Connecting the UDP socket succeeded
|
||||||
|
*
|
||||||
|
* This function connects the UDP socket to a specific
|
||||||
|
* remote port and optional remote IP address. When a UDP
|
||||||
|
* socket is connected to a remote port and address, it
|
||||||
|
* will only receive packets that are sent from the remote
|
||||||
|
* port and address. When sending data over a connected
|
||||||
|
* UDP socket, the data will be sent to the connected
|
||||||
|
* remote address.
|
||||||
|
*
|
||||||
|
* A UDP socket can be connected to a remote port, but not
|
||||||
|
* a remote IP address, by providing a NULL parameter as
|
||||||
|
* the remote_addr parameter. This lets the UDP socket
|
||||||
|
* receive data from any IP address on the specified port.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int udp_socket_connect(struct udp_socket *c,
|
||||||
|
uip_ipaddr_t *remote_addr,
|
||||||
|
uint16_t remote_port);
|
||||||
|
/**
|
||||||
|
* \brief Send data on a UDP socket
|
||||||
|
* \param c A pointer to the struct udp_socket on which the data should be sent
|
||||||
|
* \param data A pointer to the data that should be sent
|
||||||
|
* \param datalen The length of the data to be sent
|
||||||
|
* \return The number of bytes sent, or -1 if an error occurred
|
||||||
|
*
|
||||||
|
* This function sends data over a UDP socket. The UDP
|
||||||
|
* socket must have been connected to a remote address and
|
||||||
|
* port with udp_socket_connect().
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int udp_socket_send(struct udp_socket *c,
|
||||||
|
const void *data, uint16_t datalen);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Send data on a UDP socket to a specific address and port
|
||||||
|
* \param c A pointer to the struct udp_socket on which the data should be sent
|
||||||
|
* \param data A pointer to the data that should be sent
|
||||||
|
* \param datalen The length of the data to be sent
|
||||||
|
* \param addr The IP address to which the data should be sent
|
||||||
|
* \param port The UDP port number, in host byte order, to which the data should be sent
|
||||||
|
* \return The number of bytes sent, or -1 if an error occurred
|
||||||
|
*
|
||||||
|
* This function sends data over a UDP socket to a
|
||||||
|
* specific address and port.
|
||||||
|
*
|
||||||
|
* The UDP socket does not have to be connected to use
|
||||||
|
* this function.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int udp_socket_sendto(struct udp_socket *c,
|
||||||
|
const void *data, uint16_t datalen,
|
||||||
|
const uip_ipaddr_t *addr, uint16_t port);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Close a UDP socket
|
||||||
|
* \param c A pointer to the struct udp_socket to be closed
|
||||||
|
* \retval -1 If closing the UDP socket failed
|
||||||
|
* \retval 1 If closing the UDP socket succeeded
|
||||||
|
*
|
||||||
|
* This function closes a UDP socket that has previously
|
||||||
|
* been registered with udp_socket_register(). All
|
||||||
|
* registered UDP sockets must be closed before exiting
|
||||||
|
* the process that registered them, or undefined behavior
|
||||||
|
* may occur.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int udp_socket_close(struct udp_socket *c);
|
||||||
|
|
||||||
|
#endif /* UDP_SOCKET_H */
|
5
examples/tcp-socket/Makefile
Normal file
5
examples/tcp-socket/Makefile
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
all: tcp-server
|
||||||
|
|
||||||
|
CONTIKI=../..
|
||||||
|
|
||||||
|
include $(CONTIKI)/Makefile.include
|
119
examples/tcp-socket/tcp-server.c
Normal file
119
examples/tcp-socket/tcp-server.c
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2012, Thingsquare, http://www.thingsquare.com/.
|
||||||
|
* 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 copyright holder 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 COPYRIGHT HOLDERS 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
|
||||||
|
* COPYRIGHT HOLDER 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "contiki-net.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define SERVER_PORT 80
|
||||||
|
|
||||||
|
static struct tcp_socket socket;
|
||||||
|
|
||||||
|
#define INPUTBUFSIZE 400
|
||||||
|
static uint8_t inputbuf[INPUTBUFSIZE];
|
||||||
|
|
||||||
|
#define OUTPUTBUFSIZE 400
|
||||||
|
static uint8_t outputbuf[OUTPUTBUFSIZE];
|
||||||
|
|
||||||
|
PROCESS(tcp_server_process, "TCP echo process");
|
||||||
|
AUTOSTART_PROCESSES(&tcp_server_process);
|
||||||
|
static uint8_t get_received;
|
||||||
|
static int bytes_to_send;
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static int
|
||||||
|
input(struct tcp_socket *s, void *ptr,
|
||||||
|
const uint8_t *inputptr, int inputdatalen)
|
||||||
|
{
|
||||||
|
printf("input %d bytes '%s'\n", inputdatalen, inputptr);
|
||||||
|
if(!get_received) {
|
||||||
|
/* See if we have a full GET request in the buffer. */
|
||||||
|
if(strncmp((char *)inputptr, "GET /", 5) == 0 &&
|
||||||
|
atoi((char *)&inputptr[5]) != 0) {
|
||||||
|
bytes_to_send = atoi((char *)&inputptr[5]);
|
||||||
|
printf("bytes_to_send %d\n", bytes_to_send);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
printf("inputptr '%.*s'\n", inputdatalen, inputptr);
|
||||||
|
/* Return the number of data bytes we received, to keep them all
|
||||||
|
in the buffer. */
|
||||||
|
return inputdatalen;
|
||||||
|
} else {
|
||||||
|
/* Discard everything */
|
||||||
|
return 0; /* all data consumed */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static void
|
||||||
|
event(struct tcp_socket *s, void *ptr,
|
||||||
|
tcp_socket_event_t ev)
|
||||||
|
{
|
||||||
|
printf("event %d\n", ev);
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
PROCESS_THREAD(tcp_server_process, ev, data)
|
||||||
|
{
|
||||||
|
PROCESS_BEGIN();
|
||||||
|
|
||||||
|
tcp_socket_register(&socket, NULL,
|
||||||
|
inputbuf, sizeof(inputbuf),
|
||||||
|
outputbuf, sizeof(outputbuf),
|
||||||
|
input, event);
|
||||||
|
tcp_socket_listen(&socket, SERVER_PORT);
|
||||||
|
|
||||||
|
printf("Listening on %d\n", SERVER_PORT);
|
||||||
|
while(1) {
|
||||||
|
PROCESS_PAUSE();
|
||||||
|
|
||||||
|
if(bytes_to_send > 0) {
|
||||||
|
/* Send header */
|
||||||
|
printf("sending header\n");
|
||||||
|
tcp_socket_send_str(&socket, "HTTP/1.0 200 ok\r\nServer: Contiki tcp-socket example\r\n\r\n");
|
||||||
|
|
||||||
|
/* Send data */
|
||||||
|
printf("sending data\n");
|
||||||
|
while(bytes_to_send > 0) {
|
||||||
|
PROCESS_PAUSE();
|
||||||
|
int len, tosend;
|
||||||
|
#define MIN(a,b) ((a)<(b)?(a):(b))
|
||||||
|
tosend = MIN(bytes_to_send, sizeof(outputbuf));
|
||||||
|
len = tcp_socket_send(&socket, (uint8_t *)"", tosend);
|
||||||
|
bytes_to_send -= len;
|
||||||
|
}
|
||||||
|
|
||||||
|
tcp_socket_close(&socket);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
PROCESS_END();
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
|
@ -27,6 +27,7 @@ sky-ip/sky \
|
||||||
sky-shell/sky \
|
sky-shell/sky \
|
||||||
sky-shell-exec/sky \
|
sky-shell-exec/sky \
|
||||||
sky-shell-webserver/sky \
|
sky-shell-webserver/sky \
|
||||||
|
tcp-socket/minimal-net \
|
||||||
telnet-server/minimal-net \
|
telnet-server/minimal-net \
|
||||||
webserver/minimal-net \
|
webserver/minimal-net \
|
||||||
webserver-ipv6/exp5438 \
|
webserver-ipv6/exp5438 \
|
||||||
|
|
Loading…
Reference in a new issue