lwip_sock_udp.c
3.48 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
/*
* Copyright (C) 2016 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @{
*
* @file
* @author Martine Lenders <m.lenders@fu-berlin.de>
*/
#include <errno.h>
#include "net/ipv4/addr.h"
#include "net/ipv6/addr.h"
#include "net/sock/udp.h"
#include "timex.h"
#include "lwip/api.h"
#include "lwip/opt.h"
#include "lwip/sys.h"
#include "lwip/sock_internal.h"
int sock_udp_create(sock_udp_t *sock, const sock_udp_ep_t *local,
const sock_udp_ep_t *remote, uint16_t flags)
{
assert(sock != NULL);
assert(local == NULL || local->port != 0);
assert(remote == NULL || remote->port != 0);
int res;
struct netconn *tmp = NULL;
if ((res = lwip_sock_create(&tmp, (struct _sock_tl_ep *)local,
(struct _sock_tl_ep *)remote, 0, flags,
NETCONN_UDP)) == 0) {
sock->conn = tmp;
}
return res;
}
void sock_udp_close(sock_udp_t *sock)
{
assert(sock != NULL);
if (sock->conn != NULL) {
netconn_delete(sock->conn);
sock->conn = NULL;
}
}
int sock_udp_get_local(sock_udp_t *sock, sock_udp_ep_t *ep)
{
assert(sock != NULL);
return (lwip_sock_get_addr(sock->conn, (struct _sock_tl_ep *)ep,
1)) ? -EADDRNOTAVAIL : 0;
}
int sock_udp_get_remote(sock_udp_t *sock, sock_udp_ep_t *ep)
{
assert(sock != NULL);
return (lwip_sock_get_addr(sock->conn, (struct _sock_tl_ep *)ep,
0)) ? -ENOTCONN : 0;
}
ssize_t sock_udp_recv(sock_udp_t *sock, void *data, size_t max_len,
uint32_t timeout, sock_udp_ep_t *remote)
{
uint8_t *data_ptr = data;
struct netbuf *buf;
int res;
assert((sock != NULL) && (data != NULL) && (max_len > 0));
if ((res = lwip_sock_recv(sock->conn, timeout, &buf)) < 0) {
return res;
}
res = buf->p->tot_len;
if ((unsigned)res > max_len) {
netbuf_delete(buf);
return -ENOBUFS;
}
if (remote != NULL) {
/* convert remote */
size_t addr_len;
#if LWIP_IPV6
if (sock->conn->type & NETCONN_TYPE_IPV6) {
addr_len = sizeof(ipv6_addr_t);
remote->family = AF_INET6;
}
else {
#endif
#if LWIP_IPV4
addr_len = sizeof(ipv4_addr_t);
remote->family = AF_INET;
#else
netbuf_delete(buf);
return -EPROTO;
#endif
#if LWIP_IPV6
}
#endif
#if LWIP_NETBUF_RECVINFO
remote->netif = lwip_sock_bind_addr_to_netif(&buf->toaddr);
#else
remote->netif = SOCK_ADDR_ANY_NETIF;
#endif
/* copy address */
memcpy(&remote->addr, &buf->addr, addr_len);
remote->port = buf->port;
}
/* copy data */
for (struct pbuf *q = buf->p; q != NULL; q = q->next) {
memcpy(data_ptr, q->payload, q->len);
data_ptr += q->len;
}
netbuf_delete(buf);
return (ssize_t)res;
}
ssize_t sock_udp_send(sock_udp_t *sock, const void *data, size_t len,
const sock_udp_ep_t *remote)
{
assert((sock != NULL) || (remote != NULL));
assert((len == 0) || (data != NULL)); /* (len != 0) => (data != NULL) */
if ((remote != NULL) && (remote->port == 0)) {
return -EINVAL;
}
return lwip_sock_send(&sock->conn, data, len, 0, (struct _sock_tl_ep *)remote,
NETCONN_UDP);
}
/** @} */