Project Alice
Loading...
Searching...
No Matches
pcp_socket.c
Go to the documentation of this file.
1/*
2 Copyright (c) 2014 by Cisco Systems, Inc.
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 are met:
7
8 1. Redistributions of source code must retain the above copyright notice, this
9 list of conditions and the following disclaimer.
10 2. Redistributions in binary form must reproduce the above copyright notice,
11 this list of conditions and the following disclaimer in the documentation
12 and/or other materials provided with the distribution.
13
14 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
15 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
18 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#ifdef HAVE_CONFIG_H
27#include "config.h"
28#else
29#include "default_config.h"
30#endif
31
32#include <stdio.h>
33#include <string.h>
34#include <assert.h>
35#ifdef WIN32
37#else //WIN32
38#include <sys/socket.h>
39#include <netinet/in.h>
40#ifndef PCP_SOCKET_IS_VOIDPTR
41#include <unistd.h>
42#include <fcntl.h>
43#include <errno.h>
44#endif //PCP_SOCKET_IS_VOIDPTR
45#endif
46#include "pcp.h"
47#include "unp.h"
48#include "pcp_utils.h"
49#include "pcp_socket.h"
50
51static PCP_SOCKET pcp_socket_create_impl(int domain, int type, int protocol);
52static int pcp_socket_recvfrom_impl(PCP_SOCKET sock, void *buf, size_t len,
53 int flags, struct sockaddr *src_addr, socklen_t *addrlen);
54static int pcp_socket_sendto_impl(PCP_SOCKET sock, const void *buf,
55 size_t len, int flags, struct sockaddr *dest_addr, socklen_t addrlen);
56static int pcp_socket_close_impl(PCP_SOCKET sock);
57
59 pcp_socket_create_impl,
60 pcp_socket_recvfrom_impl,
61 pcp_socket_sendto_impl,
62 pcp_socket_close_impl
63};
64
65#ifdef WIN32
66// function calling WSAStartup (used in pcp-server and pcp_app)
67int pcp_win_sock_startup()
68{
69 int err;
70 WORD wVersionRequested;
71 WSADATA wsaData;
72
73 /* Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h */
74 wVersionRequested=MAKEWORD(2, 2);
75 err=WSAStartup(wVersionRequested, &wsaData);
76 if (err != 0) {
77 /* Tell the user that we could not find a usable */
78 /* Winsock DLL. */
79 perror("WSAStartup failed with error");
80 return 1;
81 }
82
83 return 0;
84}
85
86/* function calling WSACleanup
87 * returns 0 on success and 1 on failure
88 */
89int pcp_win_sock_cleanup()
90{
91 if (WSACleanup() == PCP_SOCKET_ERROR) {
92 printf("WSACleanup failed.\n");
93 return 1;
94 }
95 return 0;
96}
97#endif
98
99void pcp_fill_in6_addr(struct in6_addr *dst_ip6, uint16_t *dst_port,
100 struct sockaddr *src)
101{
102 if (src->sa_family == AF_INET) {
103 struct sockaddr_in *src_ip4=(struct sockaddr_in *)src;
104
105 if (dst_ip6) {
106 if (src_ip4->sin_addr.s_addr != INADDR_ANY) {
107 S6_ADDR32(dst_ip6)[0]=0;
108 S6_ADDR32(dst_ip6)[1]=0;
109 S6_ADDR32(dst_ip6)[2]=htonl(0xFFFF);
110 S6_ADDR32(dst_ip6)[3]=src_ip4->sin_addr.s_addr;
111 } else {
112 unsigned i;
113 for (i=0; i < 4; ++i)
114 S6_ADDR32(dst_ip6)[i]=0;
115 }
116 }
117 if (dst_port) {
118 *dst_port=src_ip4->sin_port;
119 }
120 } else if (src->sa_family == AF_INET6) {
121 struct sockaddr_in6 *src_ip6=(struct sockaddr_in6 *)src;
122
123 if (dst_ip6) {
124 memcpy(dst_ip6, src_ip6->sin6_addr.s6_addr, sizeof(*dst_ip6));
125 }
126 if (dst_port) {
127 *dst_port=src_ip6->sin6_port;
128 }
129 }
130}
131
132void pcp_fill_sockaddr(struct sockaddr *dst, struct in6_addr *sip,
133 uint16_t sport, int ret_ipv6_mapped_ipv4, uint32_t scope_id)
134{
135 if ((!ret_ipv6_mapped_ipv4) && (IN6_IS_ADDR_V4MAPPED(sip))) {
136 struct sockaddr_in *s=(struct sockaddr_in *)dst;
137
138 s->sin_family=AF_INET;
139 s->sin_addr.s_addr=S6_ADDR32(sip)[3];
140 s->sin_port=sport;
141 SET_SA_LEN(s, sizeof(struct sockaddr_in));
142 } else {
143 struct sockaddr_in6 *s=(struct sockaddr_in6 *)dst;
144
145 s->sin6_family=AF_INET6;
146 s->sin6_addr=*sip;
147 s->sin6_port=sport;
148 s->sin6_scope_id=scope_id;
149 SET_SA_LEN(s, sizeof(struct sockaddr_in6));
150 }
151}
152
153#ifndef PCP_SOCKET_IS_VOIDPTR
154static pcp_errno pcp_get_error()
155{
156#ifdef WIN32
157 int errnum=WSAGetLastError();
158
159 switch (errnum) {
160 case WSAEADDRINUSE:
161 return PCP_ERR_ADDRINUSE;
162 case WSAEWOULDBLOCK:
163 return PCP_ERR_WOULDBLOCK;
164 default:
165 return PCP_ERR_UNKNOWN;
166 }
167#else
168 switch (errno) {
169 case EADDRINUSE:
170 return PCP_ERR_ADDRINUSE;
171// case EAGAIN:
172 case EWOULDBLOCK:
173 return PCP_ERR_WOULDBLOCK;
174 default:
175 return PCP_ERR_UNKNOWN;
176 }
177#endif
178}
179#endif
180
181PCP_SOCKET pcp_socket_create(struct pcp_ctx_s *ctx, int domain, int type,
182 int protocol)
183{
184 assert(ctx && ctx->virt_socket_tb && ctx->virt_socket_tb->sock_create);
185
186 return ctx->virt_socket_tb->sock_create(domain, type, protocol);
187}
188
189ssize_t pcp_socket_recvfrom(struct pcp_ctx_s *ctx, void *buf, size_t len,
190 int flags, struct sockaddr *src_addr, socklen_t *addrlen)
191{
193
194 return ctx->virt_socket_tb->sock_recvfrom(ctx->socket, buf, len, flags,
195 src_addr, addrlen);
196}
197
198ssize_t pcp_socket_sendto(struct pcp_ctx_s *ctx, const void *buf, size_t len,
199 int flags, struct sockaddr *dest_addr, socklen_t addrlen)
200{
201 assert(ctx && ctx->virt_socket_tb && ctx->virt_socket_tb->sock_sendto);
202
203 return ctx->virt_socket_tb->sock_sendto(ctx->socket, buf, len, flags,
204 dest_addr, addrlen);
205}
206
208{
209 assert(ctx && ctx->virt_socket_tb && ctx->virt_socket_tb->sock_close);
210
211 return ctx->virt_socket_tb->sock_close(ctx->socket);
212}
213
214static PCP_SOCKET pcp_socket_create_impl(int domain, int type, int protocol)
215{
216#ifdef PCP_SOCKET_IS_VOIDPTR
217 return PCP_INVALID_SOCKET;
218#else
219 PCP_SOCKET s;
220 uint32_t flg;
221 unsigned long iMode=1;
222 struct sockaddr_storage sas;
223 struct sockaddr_in *sin=(struct sockaddr_in *)&sas;
224 struct sockaddr_in6 *sin6=(struct sockaddr_in6 *)&sas;
225
226 OSDEP(iMode);
227 OSDEP(flg);
228
229 memset(&sas, 0, sizeof(sas));
230 sas.ss_family=(ADDRESS_FAMILY)domain;
231 if (domain == AF_INET) {
232 sin->sin_port=htons(5350);
233 SET_SA_LEN(sin, sizeof(struct sockaddr_in));
234 } else if (domain == AF_INET6) {
235 sin6->sin6_port=htons(5350);
236 SET_SA_LEN(sin6, sizeof(struct sockaddr_in6));
237 } else {
238 PCP_LOG(PCP_LOGLVL_ERR, "Unsupported socket domain:%d", domain);
239 }
240
241 s=(PCP_SOCKET)socket(domain, type, protocol);
242 if (s == PCP_INVALID_SOCKET)
243 return PCP_INVALID_SOCKET;
244
245#ifdef WIN32
246 if (ioctlsocket(s, FIONBIO, &iMode)) {
248 "Unable to set nonblocking mode for socket.");
249 CLOSE(s);
250 return PCP_INVALID_SOCKET;
251 }
252#else
253 flg=fcntl(s, F_GETFL, 0);
254 if (fcntl(s, F_SETFL, flg | O_NONBLOCK)) {
256 "Unable to set nonblocking mode for socket.");
257 CLOSE(s);
258 return PCP_INVALID_SOCKET;
259 }
260#endif
261#ifdef PCP_USE_IPV6_SOCKET
262 flg=0;
264 == setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&flg,
265 sizeof(flg))) {
267 "Dual-stack sockets are not supported on this platform. "
268 "Recompile library with disabled IPv6 support.");
269 CLOSE(s);
270 return PCP_INVALID_SOCKET;
271 }
272#endif //PCP_USE_IPV6_SOCKET
273 while (bind(s, (struct sockaddr *)&sas,
274 (int)SA_LEN((struct sockaddr *)&sas)) == PCP_SOCKET_ERROR) {
275 if (pcp_get_error() == PCP_ERR_ADDRINUSE) {
276 if (sas.ss_family == AF_INET) {
277 sin->sin_port=htons(ntohs(sin->sin_port) + 1);
278 } else {
279 sin6->sin6_port=htons(ntohs(sin6->sin6_port) + 1);
280 }
281 } else {
282 PCP_LOG(PCP_LOGLVL_ERR, "%s", "bind error");
283 CLOSE(s);
284 return PCP_INVALID_SOCKET;
285 }
286 }
287 PCP_LOG(PCP_LOGLVL_DEBUG, "%s: return %d", __FUNCTION__, s);
288 return s;
289#endif
290}
291
292static int pcp_socket_recvfrom_impl(PCP_SOCKET sock, void *buf,
293 size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen)
294{
295 int ret=-1;
296
297#ifndef PCP_SOCKET_IS_VOIDPTR
298 ret=recvfrom(sock, (char*)buf, (int)len, flags, src_addr, addrlen);
299 if (ret == PCP_SOCKET_ERROR) {
300 if (pcp_get_error() == PCP_ERR_WOULDBLOCK) {
302 } else {
304 }
305 }
306#endif //PCP_SOCKET_IS_VOIDPTR
307
308 return ret;
309}
310
311static int pcp_socket_sendto_impl(PCP_SOCKET sock, const void *buf,
312 size_t len, int flags UNUSED, struct sockaddr *dest_addr, socklen_t addrlen)
313{
314 int ret=-1;
315
316#ifndef PCP_SOCKET_IS_VOIDPTR
317 ret=sendto(sock, (const char*)buf, (int)len, 0, dest_addr, addrlen);
318 if ((ret == PCP_SOCKET_ERROR) || (ret != (ssize_t)len)) {
319 if (pcp_get_error() == PCP_ERR_WOULDBLOCK) {
321 } else {
323 }
324 }
325#endif
326 return ret;
327}
328
329static int pcp_socket_close_impl(PCP_SOCKET sock)
330{
331#ifndef PCP_SOCKET_IS_VOIDPTR
332 return CLOSE(sock);
333#else
334 return PCP_SOCKET_ERROR;
335#endif
336}
#define assert(condition)
Definition: debug.h:74
float sin(float x) noexcept
Definition: math_fns.hpp:18
uint uint32_t
@ PCP_LOGLVL_ERR
Definition: pcp.h:86
@ PCP_LOGLVL_DEBUG
Definition: pcp.h:90
#define PCP_SOCKET
Definition: pcp.h:55
pcp_errno
Definition: pcp.h:65
@ PCP_ERR_ADDRINUSE
Definition: pcp.h:80
@ PCP_ERR_WOULDBLOCK
Definition: pcp.h:79
@ PCP_ERR_RECV_FAILED
Definition: pcp.h:71
@ PCP_ERR_UNKNOWN
Definition: pcp.h:75
@ PCP_ERR_SEND_FAILED
Definition: pcp.h:70
#define PCP_LOG(level, fmt,...)
Definition: pcp_logger.h:71
void pcp_fill_in6_addr(struct in6_addr *dst_ip6, uint16_t *dst_port, struct sockaddr *src)
Definition: pcp_socket.c:99
int pcp_socket_close(struct pcp_ctx_s *ctx)
Definition: pcp_socket.c:207
pcp_socket_vt_t default_socket_vt
Definition: pcp_socket.c:58
ssize_t pcp_socket_recvfrom(struct pcp_ctx_s *ctx, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen)
Definition: pcp_socket.c:189
PCP_SOCKET pcp_socket_create(struct pcp_ctx_s *ctx, int domain, int type, int protocol)
Definition: pcp_socket.c:181
void pcp_fill_sockaddr(struct sockaddr *dst, struct in6_addr *sip, uint16_t sport, int ret_ipv6_mapped_ipv4, uint32_t scope_id)
Definition: pcp_socket.c:132
ssize_t pcp_socket_sendto(struct pcp_ctx_s *ctx, const void *buf, size_t len, int flags, struct sockaddr *dest_addr, socklen_t addrlen)
Definition: pcp_socket.c:198
#define PCP_INVALID_SOCKET
Definition: pcp_socket.h:61
#define CLOSE(sockfd)
Definition: pcp_socket.h:62
#define SET_SA_LEN(s, l)
Definition: pcp_socket.h:119
#define PCP_SOCKET_ERROR
Definition: pcp_socket.h:60
#define SA_LEN(addr)
Definition: pcp_socket.h:112
#define S6_ADDR32(sa6)
Definition: pcp_utils.h:114
#define OSDEP(x)
Definition: pcp_utils.h:109
#define UNUSED
Definition: pcp_utils.h:38
#define ssize_t
pcp_socket_vt_t * virt_socket_tb
PCP_SOCKET socket
PCP_SOCKET(* sock_create)(int domain, int type, int protocol)
Definition: pcp.h:104
int(* sock_recvfrom)(PCP_SOCKET sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen)
Definition: pcp.h:105
int(* sock_close)(PCP_SOCKET sockfd)
Definition: pcp.h:109
int(* sock_sendto)(PCP_SOCKET sockfd, const void *buf, size_t len, int flags, struct sockaddr *dest_addr, socklen_t addrlen)
Definition: pcp.h:107