1 /* Copyright (c) 2021-2021 Huawei Device Co., Ltd. All rights reserved.
2 *
3 * Redistribution and use in source and binary forms, with or without modification,
4 * are permitted provided that the following conditions are met:
5 *
6 * 1. Redistributions of source code must retain the above copyright notice, this list of
7 * conditions and the following disclaimer.
8 *
9 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
10 * of conditions and the following disclaimer in the documentation and/or other materials
11 * provided with the distribution.
12 *
13 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
14 * to endorse or promote products derived from this software without specific prior written
15 * 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 LIMITED TO,
19 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
21 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
24 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
27 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 #include "lwip/opt.h"
31
32 #if LWIP_ENABLE_DISTRIBUTED_NET
33
34 #include "lwip/distributed_net/distributed_net_core.h"
35 #include "lwip/distributed_net/distributed_net_utils.h"
36 #include "lwip/distributed_net/udp_transmit.h"
37 #include "lwip/priv/sockets_priv.h"
38
distributed_net_connect(int sock,const struct sockaddr * addr,socklen_t addr_len)39 int distributed_net_connect(int sock, const struct sockaddr *addr, socklen_t addr_len)
40 {
41 CHECK_PARA(SOCKET_TO_INDEX(sock) >= 0 && SOCKET_TO_INDEX(sock) < NUM_SOCKETS, EBADF);
42 CHECK_PARA(addr != NULL, EINVAL);
43 CHECK_PARA(addr_len > 0, EINVAL);
44
45 struct sockaddr_in addr_in = {0};
46 (void)memset_s(&addr_in, sizeof(addr_in), 0, sizeof(addr_in));
47 (void)memcpy_s(&addr_in, sizeof(addr_in), addr, MIN(sizeof(addr_in), addr_len));
48 if (is_no_proxy_network_segment(&addr_in)) {
49 return lwip_connect_internal(sock, addr, addr_len);
50 }
51
52 (void)memset_s(&addr_in, sizeof(addr_in), 0, sizeof(addr_in));
53 INIT_SOCK_ADDR(&addr_in, LOCAL_SERVER_IP, get_local_tcp_server_port());
54 if (lwip_connect_internal(sock, (struct sockaddr *)&addr_in, sizeof(addr_in)) < 0) {
55 if (get_errno() != EINPROGRESS) {
56 return -1;
57 }
58 }
59 set_distributed_net_socket(sock);
60
61 (void)memset_s(&addr_in, sizeof(addr_in), 0, sizeof(addr_in));
62 (void)memcpy_s(&addr_in, sizeof(addr_in), addr, MIN(sizeof(addr_in), addr_len));
63
64 tcp_connect_data data = {0};
65 (void)memset_s(&data, sizeof(data), 0, sizeof(data));
66 (void)strcpy_s(data.dest_addr, sizeof(data.dest_addr), inet_ntoa(addr_in.sin_addr));
67 data.dest_port = ntohs(addr_in.sin_port);
68
69 if (lwip_send(sock, &data, sizeof(data), 0) < 0) {
70 reset_distributed_net_socket(sock);
71 return -1;
72 }
73 return 0;
74 }
75
distributed_net_close(int sock)76 int distributed_net_close(int sock)
77 {
78 CHECK_PARA(SOCKET_TO_INDEX(sock) >= 0 && SOCKET_TO_INDEX(sock) < NUM_SOCKETS, EBADF);
79
80 reset_distributed_net_socket(sock);
81 return lwip_close_internal(sock);
82 }
83
84 #if LWIP_USE_GET_HOST_BY_NAME_EXTERNAL
85 typedef union {
86 struct sockaddr sa;
87 #if LWIP_IPV6
88 struct sockaddr_in6 sin6;
89 #endif /* LWIP_IPV6 */
90 #if LWIP_IPV4
91 struct sockaddr_in sin;
92 #endif /* LWIP_IPV4 */
93 } aligned_sockaddr;
94
distributed_net_sendto(int sock,const void * buf,size_t buf_len,int flags,const struct sockaddr * addr,socklen_t addr_len)95 ssize_t distributed_net_sendto(int sock, const void *buf, size_t buf_len, int flags, const struct sockaddr *addr,
96 socklen_t addr_len)
97 {
98 CHECK_PARA(SOCKET_TO_INDEX(sock) >= 0 && SOCKET_TO_INDEX(sock) < NUM_SOCKETS, EBADF);
99 CHECK_PARA(buf != NULL, EINVAL);
100 CHECK_PARA(buf_len > 0, EINVAL);
101
102 int type = 0;
103 socklen_t type_len = sizeof(type);
104 if (lwip_getsockopt(sock, SOL_SOCKET, SO_TYPE, (void *)&type, &type_len) < 0) {
105 return -1;
106 }
107
108 if (type != SOCK_DGRAM) {
109 return lwip_sendto_internal(sock, buf, buf_len, flags, addr, addr_len);
110 }
111
112 struct sockaddr_in addr_in = {0};
113 (void)memset_s(&addr_in, sizeof(addr_in), 0, sizeof(addr_in));
114 if (addr != NULL && addr_len != 0) {
115 (void)memcpy_s(&addr_in, sizeof(addr_in), addr, MIN(sizeof(addr_in), addr_len));
116 }
117
118 if (IS_LOCAL_UDP_SERVER_ADDR(&addr_in)) {
119 set_errno(EPERM);
120 return -1;
121 }
122
123 if (is_no_proxy_network_segment(&addr_in)) {
124 return lwip_sendto_internal(sock, buf, buf_len, flags, addr, addr_len);
125 }
126
127 if (!IS_DNS_PORT(addr_in)) {
128 set_errno(EPERM);
129 return -1;
130 }
131
132 ssize_t ret = udp_transmit_sendto(sock, buf, buf_len, &addr_in);
133 return ret > 0 ? UDP_PAYLOAD_LEN(ret) : -1;
134 }
135
136 #if LWIP_DISTRIBUTED_NET_ENABLE_SENDMSG
distributed_net_sendmsg(int sock,const struct msghdr * hdr,int flags)137 ssize_t distributed_net_sendmsg(int sock, const struct msghdr *hdr, int flags)
138 {
139 CHECK_PARA(SOCKET_TO_INDEX(sock) >= 0 && SOCKET_TO_INDEX(sock) < NUM_SOCKETS, EBADF);
140 CHECK_PARA(hdr != NULL, EINVAL);
141 CHECK_PARA(hdr->msg_iov != NULL, EINVAL);
142 CHECK_PARA(hdr->msg_iovlen > 0, EINVAL);
143
144 int type = 0;
145 socklen_t type_len = sizeof(type);
146 if (lwip_getsockopt(sock, SOL_SOCKET, SO_TYPE, (void *)&type, &type_len) < 0) {
147 return -1;
148 }
149
150 if (type != SOCK_DGRAM) {
151 return lwip_sendmsg_internal(sock, hdr, flags);
152 }
153
154 const struct sockaddr *addr = (const struct sockaddr *)hdr->msg_name;
155 socklen_t addr_len = hdr->msg_namelen;
156
157 struct sockaddr_in addr_in = {0};
158 (void)memset_s(&addr_in, sizeof(addr_in), 0, sizeof(addr_in));
159 if (addr != NULL && addr_len != 0) {
160 (void)memcpy_s(&addr_in, sizeof(addr_in), addr, MIN(sizeof(addr_in), addr_len));
161 }
162
163 if (IS_LOCAL_UDP_SERVER_ADDR(&addr_in)) {
164 set_errno(EPERM);
165 return -1;
166 }
167
168 if (is_no_proxy_network_segment(&addr_in)) {
169 return lwip_sendmsg_internal(sock, hdr, flags);
170 }
171
172 if (!IS_DNS_PORT(addr_in)) {
173 set_errno(EPERM);
174 return -1;
175 }
176
177 ssize_t ret = udp_transmit_sendmsg(sock, hdr);
178 return ret > 0 ? UDP_PAYLOAD_LEN(ret) : -1;
179 }
180 #endif /* LWIP_DISTRIBUTED_NET_ENABLE_SENDMSG */
181
distributed_net_recvfrom(int sock,void * buf,size_t buf_len,int flags,struct sockaddr * from,socklen_t * from_len)182 ssize_t distributed_net_recvfrom(int sock, void *buf, size_t buf_len, int flags, struct sockaddr *from,
183 socklen_t *from_len)
184 {
185 CHECK_PARA(SOCKET_TO_INDEX(sock) >= 0 && SOCKET_TO_INDEX(sock) < NUM_SOCKETS, EBADF);
186 CHECK_PARA(buf != NULL, EINVAL);
187 CHECK_PARA(buf_len > 0, EINVAL);
188
189 int type = 0;
190 socklen_t type_len = sizeof(type);
191 if (lwip_getsockopt(sock, SOL_SOCKET, SO_TYPE, (void *)&type, &type_len) < 0) {
192 return -1;
193 }
194
195 if (type != SOCK_DGRAM) {
196 return lwip_recvfrom_internal(sock, buf, buf_len, flags, from, from_len);
197 }
198
199 size_t new_buf_len = buf_len + sizeof(udp_data);
200 void *new_buf = mem_malloc(new_buf_len);
201 if (new_buf == NULL) {
202 set_errno(ENOMEM);
203 return -1;
204 }
205
206 aligned_sockaddr addr_from = {0};
207 socklen_t addr_from_len = sizeof(addr_from);
208 ssize_t ret =
209 lwip_recvfrom_internal(sock, new_buf, new_buf_len, flags, (struct sockaddr *)&addr_from, &addr_from_len);
210 if (ret <= 0) {
211 mem_free(new_buf);
212 return ret;
213 }
214
215 if (!IS_LOCAL_UDP_SERVER_ADDR((struct sockaddr_in *)(&addr_from))) {
216 (void)memcpy_s(buf, buf_len, new_buf, ret);
217 if (from != NULL && from_len != NULL) {
218 if (*from_len > addr_from_len) {
219 *from_len = addr_from_len;
220 }
221 (void)memcpy_s(from, *from_len, &addr_from, *from_len);
222 mem_free(new_buf);
223 return ret;
224 }
225 }
226
227 if (ret <= sizeof(udp_data)) {
228 mem_free(new_buf);
229 set_errno(EINVAL);
230 return -1;
231 }
232
233 udp_data *data = (udp_data *)new_buf;
234 (void)memcpy_s(buf, buf_len, data->payload, ret - sizeof(udp_data));
235 if (from != NULL && from_len != NULL) {
236 (void)memcpy_s(from, *from_len, &addr_from, MIN(addr_from_len, *from_len));
237 if (*from_len >= sizeof(struct sockaddr_in) - SIN_ZERO_LEN) {
238 struct sockaddr_in *temp_addr = (struct sockaddr_in *)from;
239 INIT_SOCK_ADDR(temp_addr, data->dest_addr, data->dest_port);
240 if (*from_len > sizeof(struct sockaddr_in)) {
241 *from_len = sizeof(struct sockaddr_in);
242 }
243 }
244 }
245
246 mem_free(new_buf);
247 return ret - (ssize_t)sizeof(udp_data);
248 }
249 #endif /* LWIP_USE_GET_HOST_BY_NAME_EXTERNAL */
250
251 #endif /* LWIP_ENABLE_DISTRIBUTED_NET */
252