opal-up 0.0.2 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/LICENSE +209 -0
- data/README.md +81 -28
- data/bin/up_ruby +4 -0
- data/bin/up_ruby_cluster +4 -0
- data/ext/up_ext/App.h +606 -0
- data/ext/up_ext/AsyncSocket.h +355 -0
- data/ext/up_ext/AsyncSocketData.h +87 -0
- data/ext/up_ext/BloomFilter.h +83 -0
- data/ext/up_ext/ChunkedEncoding.h +236 -0
- data/ext/up_ext/ClientApp.h +36 -0
- data/ext/up_ext/HttpContext.h +502 -0
- data/ext/up_ext/HttpContextData.h +56 -0
- data/ext/up_ext/HttpErrors.h +53 -0
- data/ext/up_ext/HttpParser.h +680 -0
- data/ext/up_ext/HttpResponse.h +578 -0
- data/ext/up_ext/HttpResponseData.h +95 -0
- data/ext/up_ext/HttpRouter.h +380 -0
- data/ext/up_ext/Loop.h +204 -0
- data/ext/up_ext/LoopData.h +112 -0
- data/ext/up_ext/MoveOnlyFunction.h +377 -0
- data/ext/up_ext/PerMessageDeflate.h +315 -0
- data/ext/up_ext/ProxyParser.h +163 -0
- data/ext/up_ext/QueryParser.h +120 -0
- data/ext/up_ext/TopicTree.h +363 -0
- data/ext/up_ext/Utilities.h +66 -0
- data/ext/up_ext/WebSocket.h +381 -0
- data/ext/up_ext/WebSocketContext.h +434 -0
- data/ext/up_ext/WebSocketContextData.h +109 -0
- data/ext/up_ext/WebSocketData.h +86 -0
- data/ext/up_ext/WebSocketExtensions.h +256 -0
- data/ext/up_ext/WebSocketHandshake.h +145 -0
- data/ext/up_ext/WebSocketProtocol.h +506 -0
- data/ext/up_ext/bsd.c +767 -0
- data/ext/up_ext/bsd.h +109 -0
- data/ext/up_ext/context.c +524 -0
- data/ext/up_ext/epoll_kqueue.c +458 -0
- data/ext/up_ext/epoll_kqueue.h +67 -0
- data/ext/up_ext/extconf.rb +5 -0
- data/ext/up_ext/internal.h +224 -0
- data/ext/up_ext/libusockets.h +350 -0
- data/ext/up_ext/libuwebsockets.cpp +1374 -0
- data/ext/up_ext/libuwebsockets.h +260 -0
- data/ext/up_ext/loop.c +386 -0
- data/ext/up_ext/loop_data.h +38 -0
- data/ext/up_ext/socket.c +231 -0
- data/ext/up_ext/up_ext.c +278 -0
- data/lib/up/node/rack_env.rb +2 -2
- data/lib/up/ruby/cluster_cli.rb +10 -0
- data/lib/up/ruby/rack_cluster.rb +26 -0
- data/lib/up/ruby/rack_env.rb +97 -0
- data/lib/up/ruby/rack_server.rb +26 -0
- data/lib/up/ruby/server_cli.rb +10 -0
- data/lib/up/u_web_socket/rack_env.rb +1 -1
- data/lib/up/version.rb +1 -1
- metadata +71 -18
- data/.gitignore +0 -5
- data/Gemfile +0 -2
- data/example_rack_app/Gemfile +0 -3
- data/example_rack_app/config.ru +0 -6
- data/example_rack_app/rack_app.rb +0 -5
- data/example_roda_app/Gemfile +0 -6
- data/example_roda_app/config.ru +0 -6
- data/example_roda_app/roda_app.rb +0 -37
- data/example_sinatra_app/Gemfile +0 -6
- data/example_sinatra_app/config.ru +0 -6
- data/example_sinatra_app/sinatra_app.rb +0 -7
- data/opal-up.gemspec +0 -27
- data/up_logo.svg +0 -256
data/ext/up_ext/bsd.c
ADDED
@@ -0,0 +1,767 @@
|
|
1
|
+
/*
|
2
|
+
* Authored by Alex Hultman, 2018-2021.
|
3
|
+
* Intellectual property of third-party.
|
4
|
+
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
* you may not use this file except in compliance with the License.
|
7
|
+
* You may obtain a copy of the License at
|
8
|
+
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
* See the License for the specific language governing permissions and
|
15
|
+
* limitations under the License.
|
16
|
+
*/
|
17
|
+
|
18
|
+
/* Todo: this file should lie in networking/bsd.c */
|
19
|
+
|
20
|
+
#define __APPLE_USE_RFC_3542
|
21
|
+
|
22
|
+
#include "libusockets.h"
|
23
|
+
#include "internal.h"
|
24
|
+
|
25
|
+
#include <stdio.h>
|
26
|
+
#include <stdlib.h>
|
27
|
+
|
28
|
+
#ifndef _WIN32
|
29
|
+
//#define _GNU_SOURCE
|
30
|
+
#include <sys/types.h>
|
31
|
+
#include <sys/socket.h>
|
32
|
+
#include <netinet/in.h>
|
33
|
+
#include <netinet/tcp.h>
|
34
|
+
#include <netdb.h>
|
35
|
+
#include <string.h>
|
36
|
+
#include <unistd.h>
|
37
|
+
#include <fcntl.h>
|
38
|
+
#include <errno.h>
|
39
|
+
#endif
|
40
|
+
|
41
|
+
/* Internal structure of packet buffer */
|
42
|
+
struct us_internal_udp_packet_buffer {
|
43
|
+
#if defined(_WIN32) || defined(__APPLE__)
|
44
|
+
char *buf[LIBUS_UDP_MAX_NUM];
|
45
|
+
size_t len[LIBUS_UDP_MAX_NUM];
|
46
|
+
struct sockaddr_storage addr[LIBUS_UDP_MAX_NUM];
|
47
|
+
#else
|
48
|
+
struct mmsghdr msgvec[LIBUS_UDP_MAX_NUM];
|
49
|
+
struct iovec iov[LIBUS_UDP_MAX_NUM];
|
50
|
+
struct sockaddr_storage addr[LIBUS_UDP_MAX_NUM];
|
51
|
+
char control[LIBUS_UDP_MAX_NUM][256];
|
52
|
+
#endif
|
53
|
+
};
|
54
|
+
|
55
|
+
/* We need to emulate sendmmsg, recvmmsg on platform who don't have it */
|
56
|
+
int bsd_sendmmsg(LIBUS_SOCKET_DESCRIPTOR fd, void *msgvec, unsigned int vlen, int flags) {
|
57
|
+
#if defined(__APPLE__)
|
58
|
+
|
59
|
+
struct mmsghdr {
|
60
|
+
struct msghdr msg_hdr; /* Message header */
|
61
|
+
unsigned int msg_len; /* Number of bytes transmitted */
|
62
|
+
};
|
63
|
+
|
64
|
+
struct mmsghdr *hdrs = (struct mmsghdr *) msgvec;
|
65
|
+
|
66
|
+
for (int i = 0; i < vlen; i++) {
|
67
|
+
int ret = sendmsg(fd, &hdrs[i].msg_hdr, flags);
|
68
|
+
if (ret == -1) {
|
69
|
+
if (i) {
|
70
|
+
return i;
|
71
|
+
} else {
|
72
|
+
return -1;
|
73
|
+
}
|
74
|
+
} else {
|
75
|
+
hdrs[i].msg_len = ret;
|
76
|
+
}
|
77
|
+
}
|
78
|
+
|
79
|
+
return vlen;
|
80
|
+
|
81
|
+
#elif defined(_WIN32)
|
82
|
+
|
83
|
+
struct us_internal_udp_packet_buffer *packet_buffer = (struct us_internal_udp_packet_buffer *) msgvec;
|
84
|
+
|
85
|
+
/* Let's just use sendto here */
|
86
|
+
/* Winsock does not have sendmsg, while macOS has, however, we simply use sendto since both macOS and Winsock has it.
|
87
|
+
* Besides, you should use Linux either way to get best performance with the sendmmsg */
|
88
|
+
|
89
|
+
|
90
|
+
// while we do not get error, send next
|
91
|
+
|
92
|
+
for (int i = 0; i < LIBUS_UDP_MAX_NUM; i++) {
|
93
|
+
// need to support ipv6 addresses also!
|
94
|
+
int ret = sendto(fd, packet_buffer->buf[i], packet_buffer->len[i], flags, (struct sockaddr *)&packet_buffer->addr[i], sizeof(struct sockaddr_in));
|
95
|
+
|
96
|
+
if (ret == -1) {
|
97
|
+
// if we fail then we need to buffer up, no that's not our problem
|
98
|
+
// we do need to register poll out though and have a callback for it
|
99
|
+
return i;
|
100
|
+
}
|
101
|
+
|
102
|
+
//printf("sendto: %d\n", ret);
|
103
|
+
}
|
104
|
+
|
105
|
+
return LIBUS_UDP_MAX_NUM; // one message
|
106
|
+
#else
|
107
|
+
return sendmmsg(fd, (struct mmsghdr *)msgvec, vlen, flags | MSG_NOSIGNAL);
|
108
|
+
#endif
|
109
|
+
}
|
110
|
+
|
111
|
+
int bsd_recvmmsg(LIBUS_SOCKET_DESCRIPTOR fd, void *msgvec, unsigned int vlen, int flags, void *timeout) {
|
112
|
+
#if defined(_WIN32) || defined(__APPLE__)
|
113
|
+
struct us_internal_udp_packet_buffer *packet_buffer = (struct us_internal_udp_packet_buffer *) msgvec;
|
114
|
+
|
115
|
+
|
116
|
+
for (int i = 0; i < LIBUS_UDP_MAX_NUM; i++) {
|
117
|
+
socklen_t addr_len = sizeof(struct sockaddr_storage);
|
118
|
+
int ret = recvfrom(fd, packet_buffer->buf[i], LIBUS_UDP_MAX_SIZE, flags, (struct sockaddr *)&packet_buffer->addr[i], &addr_len);
|
119
|
+
|
120
|
+
if (ret == -1) {
|
121
|
+
return i;
|
122
|
+
}
|
123
|
+
|
124
|
+
packet_buffer->len[i] = ret;
|
125
|
+
}
|
126
|
+
|
127
|
+
return LIBUS_UDP_MAX_NUM;
|
128
|
+
#else
|
129
|
+
// we need to set controllen for ip packet
|
130
|
+
for (int i = 0; i < vlen; i++) {
|
131
|
+
((struct mmsghdr *)msgvec)[i].msg_hdr.msg_controllen = 256;
|
132
|
+
}
|
133
|
+
|
134
|
+
return recvmmsg(fd, (struct mmsghdr *)msgvec, vlen, flags, 0);
|
135
|
+
#endif
|
136
|
+
}
|
137
|
+
|
138
|
+
// this one is needed for knowing the destination addr of udp packet
|
139
|
+
// an udp socket can only bind to one port, and that port never changes
|
140
|
+
// this function returns ONLY the IP address, not any port
|
141
|
+
int bsd_udp_packet_buffer_local_ip(void *msgvec, int index, char *ip) {
|
142
|
+
#if defined(_WIN32) || defined(__APPLE__)
|
143
|
+
return 0; // not supported
|
144
|
+
#else
|
145
|
+
struct msghdr *mh = &((struct mmsghdr *) msgvec)[index].msg_hdr;
|
146
|
+
for (struct cmsghdr *cmsg = CMSG_FIRSTHDR(mh); cmsg != NULL; cmsg = CMSG_NXTHDR(mh, cmsg)) {
|
147
|
+
// Linux ipv4
|
148
|
+
#ifdef IP_PKTINFO
|
149
|
+
if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_PKTINFO) {
|
150
|
+
struct in_pktinfo *pi = (struct in_pktinfo *) CMSG_DATA(cmsg);
|
151
|
+
memcpy(ip, &pi->ipi_addr, 4);
|
152
|
+
return 4;
|
153
|
+
}
|
154
|
+
// FreeBSD ipv4
|
155
|
+
#elif IP_RECVDSTADDR
|
156
|
+
if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_RECVDSTADDR) {
|
157
|
+
struct in_addr *addr = (struct in_addr *) CMSG_DATA(cmsg);
|
158
|
+
memcpy(ip, addr, 4);
|
159
|
+
return 4;
|
160
|
+
}
|
161
|
+
#endif
|
162
|
+
|
163
|
+
// Linux, FreeBSD ipv6
|
164
|
+
if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) {
|
165
|
+
struct in6_pktinfo *pi6 = (struct in6_pktinfo *) CMSG_DATA(cmsg);
|
166
|
+
memcpy(ip, &pi6->ipi6_addr, 16);
|
167
|
+
return 16;
|
168
|
+
}
|
169
|
+
}
|
170
|
+
|
171
|
+
return 0; // no length
|
172
|
+
|
173
|
+
#endif
|
174
|
+
}
|
175
|
+
|
176
|
+
char *bsd_udp_packet_buffer_peer(void *msgvec, int index) {
|
177
|
+
#if defined(_WIN32) || defined(__APPLE__)
|
178
|
+
struct us_internal_udp_packet_buffer *packet_buffer = (struct us_internal_udp_packet_buffer *) msgvec;
|
179
|
+
return (char *)&packet_buffer->addr[index];
|
180
|
+
#else
|
181
|
+
return ((struct mmsghdr *) msgvec)[index].msg_hdr.msg_name;
|
182
|
+
#endif
|
183
|
+
}
|
184
|
+
|
185
|
+
char *bsd_udp_packet_buffer_payload(void *msgvec, int index) {
|
186
|
+
#if defined(_WIN32) || defined(__APPLE__)
|
187
|
+
struct us_internal_udp_packet_buffer *packet_buffer = (struct us_internal_udp_packet_buffer *) msgvec;
|
188
|
+
return packet_buffer->buf[index];
|
189
|
+
#else
|
190
|
+
return ((struct mmsghdr *) msgvec)[index].msg_hdr.msg_iov[0].iov_base;
|
191
|
+
#endif
|
192
|
+
}
|
193
|
+
|
194
|
+
int bsd_udp_packet_buffer_payload_length(void *msgvec, int index) {
|
195
|
+
#if defined(_WIN32) || defined(__APPLE__)
|
196
|
+
struct us_internal_udp_packet_buffer *packet_buffer = (struct us_internal_udp_packet_buffer *) msgvec;
|
197
|
+
return packet_buffer->len[index];
|
198
|
+
#else
|
199
|
+
return ((struct mmsghdr *) msgvec)[index].msg_len;
|
200
|
+
#endif
|
201
|
+
}
|
202
|
+
|
203
|
+
void bsd_udp_buffer_set_packet_payload(struct us_udp_packet_buffer_t *send_buf, int index, int offset, void *payload, int length, void *peer_addr) {
|
204
|
+
#if defined(_WIN32) || defined(__APPLE__)
|
205
|
+
struct us_internal_udp_packet_buffer *packet_buffer = (struct us_internal_udp_packet_buffer *) send_buf;
|
206
|
+
|
207
|
+
memcpy(packet_buffer->buf[index], payload, length);
|
208
|
+
memcpy(&packet_buffer->addr[index], peer_addr, sizeof(struct sockaddr_storage));
|
209
|
+
|
210
|
+
packet_buffer->len[index] = length;
|
211
|
+
#else
|
212
|
+
//printf("length: %d, offset: %d\n", length, offset);
|
213
|
+
|
214
|
+
struct mmsghdr *ss = (struct mmsghdr *) send_buf;
|
215
|
+
|
216
|
+
// copy the peer address
|
217
|
+
memcpy(ss[index].msg_hdr.msg_name, peer_addr, /*ss[index].msg_hdr.msg_namelen*/ sizeof(struct sockaddr_in));
|
218
|
+
|
219
|
+
// set control length to 0
|
220
|
+
ss[index].msg_hdr.msg_controllen = 0;
|
221
|
+
|
222
|
+
// copy the payload
|
223
|
+
|
224
|
+
ss[index].msg_hdr.msg_iov->iov_len = length + offset;
|
225
|
+
|
226
|
+
|
227
|
+
memcpy(((char *) ss[index].msg_hdr.msg_iov->iov_base) + offset, payload, length);
|
228
|
+
#endif
|
229
|
+
}
|
230
|
+
|
231
|
+
/* The maximum UDP payload size is 64kb, but in IPV6 you can have jumbopackets larger than so.
|
232
|
+
* We do not support those jumbo packets currently, but will safely ignore them.
|
233
|
+
* Any sane sender would assume we don't support them if we consistently drop them.
|
234
|
+
* Therefore a udp_packet_buffer_t will be 64 MB in size (64kb * 1024). */
|
235
|
+
void *bsd_create_udp_packet_buffer() {
|
236
|
+
#if defined(_WIN32) || defined(__APPLE__)
|
237
|
+
struct us_internal_udp_packet_buffer *b = malloc(sizeof(struct us_internal_udp_packet_buffer) + LIBUS_UDP_MAX_SIZE * LIBUS_UDP_MAX_NUM);
|
238
|
+
|
239
|
+
for (int i = 0; i < LIBUS_UDP_MAX_NUM; i++) {
|
240
|
+
b->buf[i] = ((char *) b) + sizeof(struct us_internal_udp_packet_buffer) + LIBUS_UDP_MAX_SIZE * i;
|
241
|
+
}
|
242
|
+
|
243
|
+
return (struct us_udp_packet_buffer_t *) b;
|
244
|
+
#else
|
245
|
+
/* Allocate 64kb times 1024 */
|
246
|
+
struct us_internal_udp_packet_buffer *b = malloc(sizeof(struct us_internal_udp_packet_buffer) + LIBUS_UDP_MAX_SIZE * LIBUS_UDP_MAX_NUM);
|
247
|
+
|
248
|
+
for (int n = 0; n < LIBUS_UDP_MAX_NUM; ++n) {
|
249
|
+
|
250
|
+
b->iov[n].iov_base = &((char *) (b + 1))[n * LIBUS_UDP_MAX_SIZE];
|
251
|
+
b->iov[n].iov_len = LIBUS_UDP_MAX_SIZE;
|
252
|
+
|
253
|
+
b->msgvec[n].msg_hdr = (struct msghdr) {
|
254
|
+
.msg_name = &b->addr,
|
255
|
+
.msg_namelen = sizeof (struct sockaddr_storage),
|
256
|
+
|
257
|
+
.msg_iov = &b->iov[n],
|
258
|
+
.msg_iovlen = 1,
|
259
|
+
|
260
|
+
.msg_control = b->control[n],
|
261
|
+
.msg_controllen = 256,
|
262
|
+
};
|
263
|
+
}
|
264
|
+
|
265
|
+
return (struct us_udp_packet_buffer_t *) b;
|
266
|
+
#endif
|
267
|
+
}
|
268
|
+
|
269
|
+
LIBUS_SOCKET_DESCRIPTOR apple_no_sigpipe(LIBUS_SOCKET_DESCRIPTOR fd) {
|
270
|
+
#ifdef __APPLE__
|
271
|
+
if (fd != LIBUS_SOCKET_ERROR) {
|
272
|
+
int no_sigpipe = 1;
|
273
|
+
setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, (void *) &no_sigpipe, sizeof(int));
|
274
|
+
}
|
275
|
+
#endif
|
276
|
+
return fd;
|
277
|
+
}
|
278
|
+
|
279
|
+
LIBUS_SOCKET_DESCRIPTOR bsd_set_nonblocking(LIBUS_SOCKET_DESCRIPTOR fd) {
|
280
|
+
#ifdef _WIN32
|
281
|
+
/* Libuv will set windows sockets as non-blocking */
|
282
|
+
#else
|
283
|
+
fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
|
284
|
+
#endif
|
285
|
+
return fd;
|
286
|
+
}
|
287
|
+
|
288
|
+
void bsd_socket_nodelay(LIBUS_SOCKET_DESCRIPTOR fd, int enabled) {
|
289
|
+
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (void *) &enabled, sizeof(enabled));
|
290
|
+
}
|
291
|
+
|
292
|
+
void bsd_socket_flush(LIBUS_SOCKET_DESCRIPTOR fd) {
|
293
|
+
// Linux TCP_CORK has the same underlying corking mechanism as with MSG_MORE
|
294
|
+
#ifdef TCP_CORK
|
295
|
+
int enabled = 0;
|
296
|
+
setsockopt(fd, IPPROTO_TCP, TCP_CORK, (void *) &enabled, sizeof(int));
|
297
|
+
#endif
|
298
|
+
}
|
299
|
+
|
300
|
+
LIBUS_SOCKET_DESCRIPTOR bsd_create_socket(int domain, int type, int protocol) {
|
301
|
+
// returns INVALID_SOCKET on error
|
302
|
+
int flags = 0;
|
303
|
+
#if defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK)
|
304
|
+
flags = SOCK_CLOEXEC | SOCK_NONBLOCK;
|
305
|
+
#endif
|
306
|
+
|
307
|
+
LIBUS_SOCKET_DESCRIPTOR created_fd = socket(domain, type | flags, protocol);
|
308
|
+
|
309
|
+
return bsd_set_nonblocking(apple_no_sigpipe(created_fd));
|
310
|
+
}
|
311
|
+
|
312
|
+
void bsd_close_socket(LIBUS_SOCKET_DESCRIPTOR fd) {
|
313
|
+
#ifdef _WIN32
|
314
|
+
closesocket(fd);
|
315
|
+
#else
|
316
|
+
close(fd);
|
317
|
+
#endif
|
318
|
+
}
|
319
|
+
|
320
|
+
void bsd_shutdown_socket(LIBUS_SOCKET_DESCRIPTOR fd) {
|
321
|
+
#ifdef _WIN32
|
322
|
+
shutdown(fd, SD_SEND);
|
323
|
+
#else
|
324
|
+
shutdown(fd, SHUT_WR);
|
325
|
+
#endif
|
326
|
+
}
|
327
|
+
|
328
|
+
void bsd_shutdown_socket_read(LIBUS_SOCKET_DESCRIPTOR fd) {
|
329
|
+
#ifdef _WIN32
|
330
|
+
shutdown(fd, SD_RECEIVE);
|
331
|
+
#else
|
332
|
+
shutdown(fd, SHUT_RD);
|
333
|
+
#endif
|
334
|
+
}
|
335
|
+
|
336
|
+
void internal_finalize_bsd_addr(struct bsd_addr_t *addr) {
|
337
|
+
// parse, so to speak, the address
|
338
|
+
if (addr->mem.ss_family == AF_INET6) {
|
339
|
+
addr->ip = (char *) &((struct sockaddr_in6 *) addr)->sin6_addr;
|
340
|
+
addr->ip_length = sizeof(struct in6_addr);
|
341
|
+
addr->port = ntohs(((struct sockaddr_in6 *) addr)->sin6_port);
|
342
|
+
} else if (addr->mem.ss_family == AF_INET) {
|
343
|
+
addr->ip = (char *) &((struct sockaddr_in *) addr)->sin_addr;
|
344
|
+
addr->ip_length = sizeof(struct in_addr);
|
345
|
+
addr->port = ntohs(((struct sockaddr_in *) addr)->sin_port);
|
346
|
+
} else {
|
347
|
+
addr->ip_length = 0;
|
348
|
+
addr->port = -1;
|
349
|
+
}
|
350
|
+
}
|
351
|
+
|
352
|
+
int bsd_local_addr(LIBUS_SOCKET_DESCRIPTOR fd, struct bsd_addr_t *addr) {
|
353
|
+
addr->len = sizeof(addr->mem);
|
354
|
+
if (getsockname(fd, (struct sockaddr *) &addr->mem, &addr->len)) {
|
355
|
+
return -1;
|
356
|
+
}
|
357
|
+
internal_finalize_bsd_addr(addr);
|
358
|
+
return 0;
|
359
|
+
}
|
360
|
+
|
361
|
+
int bsd_remote_addr(LIBUS_SOCKET_DESCRIPTOR fd, struct bsd_addr_t *addr) {
|
362
|
+
addr->len = sizeof(addr->mem);
|
363
|
+
if (getpeername(fd, (struct sockaddr *) &addr->mem, &addr->len)) {
|
364
|
+
return -1;
|
365
|
+
}
|
366
|
+
internal_finalize_bsd_addr(addr);
|
367
|
+
return 0;
|
368
|
+
}
|
369
|
+
|
370
|
+
char *bsd_addr_get_ip(struct bsd_addr_t *addr) {
|
371
|
+
return addr->ip;
|
372
|
+
}
|
373
|
+
|
374
|
+
int bsd_addr_get_ip_length(struct bsd_addr_t *addr) {
|
375
|
+
return addr->ip_length;
|
376
|
+
}
|
377
|
+
|
378
|
+
int bsd_addr_get_port(struct bsd_addr_t *addr) {
|
379
|
+
return addr->port;
|
380
|
+
}
|
381
|
+
|
382
|
+
// called by dispatch_ready_poll
|
383
|
+
LIBUS_SOCKET_DESCRIPTOR bsd_accept_socket(LIBUS_SOCKET_DESCRIPTOR fd, struct bsd_addr_t *addr) {
|
384
|
+
LIBUS_SOCKET_DESCRIPTOR accepted_fd;
|
385
|
+
addr->len = sizeof(addr->mem);
|
386
|
+
|
387
|
+
#if defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK)
|
388
|
+
// Linux, FreeBSD
|
389
|
+
accepted_fd = accept4(fd, (struct sockaddr *) addr, &addr->len, SOCK_CLOEXEC | SOCK_NONBLOCK);
|
390
|
+
#else
|
391
|
+
// Windows, OS X
|
392
|
+
accepted_fd = accept(fd, (struct sockaddr *) addr, &addr->len);
|
393
|
+
|
394
|
+
#endif
|
395
|
+
|
396
|
+
/* We cannot rely on addr since it is not initialized if failed */
|
397
|
+
if (accepted_fd == LIBUS_SOCKET_ERROR) {
|
398
|
+
return LIBUS_SOCKET_ERROR;
|
399
|
+
}
|
400
|
+
|
401
|
+
internal_finalize_bsd_addr(addr);
|
402
|
+
|
403
|
+
return bsd_set_nonblocking(apple_no_sigpipe(accepted_fd));
|
404
|
+
}
|
405
|
+
|
406
|
+
int bsd_recv(LIBUS_SOCKET_DESCRIPTOR fd, void *buf, int length, int flags) {
|
407
|
+
return recv(fd, buf, length, flags);
|
408
|
+
}
|
409
|
+
|
410
|
+
#if !defined(_WIN32)
|
411
|
+
#include <sys/uio.h>
|
412
|
+
|
413
|
+
int bsd_write2(LIBUS_SOCKET_DESCRIPTOR fd, const char *header, int header_length, const char *payload, int payload_length) {
|
414
|
+
struct iovec chunks[2];
|
415
|
+
|
416
|
+
chunks[0].iov_base = (char *)header;
|
417
|
+
chunks[0].iov_len = header_length;
|
418
|
+
chunks[1].iov_base = (char *)payload;
|
419
|
+
chunks[1].iov_len = payload_length;
|
420
|
+
|
421
|
+
return writev(fd, chunks, 2);
|
422
|
+
}
|
423
|
+
#else
|
424
|
+
int bsd_write2(LIBUS_SOCKET_DESCRIPTOR fd, const char *header, int header_length, const char *payload, int payload_length) {
|
425
|
+
int written = bsd_send(fd, header, header_length, 0);
|
426
|
+
if (written == header_length) {
|
427
|
+
int second_write = bsd_send(fd, payload, payload_length, 0);
|
428
|
+
if (second_write > 0) {
|
429
|
+
written += second_write;
|
430
|
+
}
|
431
|
+
}
|
432
|
+
return written;
|
433
|
+
}
|
434
|
+
#endif
|
435
|
+
|
436
|
+
int bsd_send(LIBUS_SOCKET_DESCRIPTOR fd, const char *buf, int length, int msg_more) {
|
437
|
+
|
438
|
+
// MSG_MORE (Linux), MSG_PARTIAL (Windows), TCP_NOPUSH (BSD)
|
439
|
+
|
440
|
+
#ifndef MSG_NOSIGNAL
|
441
|
+
#define MSG_NOSIGNAL 0
|
442
|
+
#endif
|
443
|
+
|
444
|
+
#ifdef MSG_MORE
|
445
|
+
|
446
|
+
// for Linux we do not want signals
|
447
|
+
return send(fd, buf, length, ((msg_more != 0) * MSG_MORE) | MSG_NOSIGNAL);
|
448
|
+
|
449
|
+
#else
|
450
|
+
|
451
|
+
// use TCP_NOPUSH
|
452
|
+
|
453
|
+
return send(fd, buf, length, MSG_NOSIGNAL);
|
454
|
+
|
455
|
+
#endif
|
456
|
+
}
|
457
|
+
|
458
|
+
int bsd_would_block() {
|
459
|
+
#ifdef _WIN32
|
460
|
+
return WSAGetLastError() == WSAEWOULDBLOCK;
|
461
|
+
#else
|
462
|
+
return errno == EWOULDBLOCK;// || errno == EAGAIN;
|
463
|
+
#endif
|
464
|
+
}
|
465
|
+
|
466
|
+
// return LIBUS_SOCKET_ERROR or the fd that represents listen socket
|
467
|
+
// listen both on ipv6 and ipv4
|
468
|
+
LIBUS_SOCKET_DESCRIPTOR bsd_create_listen_socket(const char *host, int port, int options) {
|
469
|
+
struct addrinfo hints, *result;
|
470
|
+
memset(&hints, 0, sizeof(struct addrinfo));
|
471
|
+
|
472
|
+
hints.ai_flags = AI_PASSIVE;
|
473
|
+
hints.ai_family = AF_UNSPEC;
|
474
|
+
hints.ai_socktype = SOCK_STREAM;
|
475
|
+
|
476
|
+
char port_string[16];
|
477
|
+
snprintf(port_string, 16, "%d", port);
|
478
|
+
|
479
|
+
if (getaddrinfo(host, port_string, &hints, &result)) {
|
480
|
+
return LIBUS_SOCKET_ERROR;
|
481
|
+
}
|
482
|
+
|
483
|
+
LIBUS_SOCKET_DESCRIPTOR listenFd = LIBUS_SOCKET_ERROR;
|
484
|
+
struct addrinfo *listenAddr;
|
485
|
+
for (struct addrinfo *a = result; a && listenFd == LIBUS_SOCKET_ERROR; a = a->ai_next) {
|
486
|
+
if (a->ai_family == AF_INET6) {
|
487
|
+
listenFd = bsd_create_socket(a->ai_family, a->ai_socktype, a->ai_protocol);
|
488
|
+
listenAddr = a;
|
489
|
+
}
|
490
|
+
}
|
491
|
+
|
492
|
+
for (struct addrinfo *a = result; a && listenFd == LIBUS_SOCKET_ERROR; a = a->ai_next) {
|
493
|
+
if (a->ai_family == AF_INET) {
|
494
|
+
listenFd = bsd_create_socket(a->ai_family, a->ai_socktype, a->ai_protocol);
|
495
|
+
listenAddr = a;
|
496
|
+
}
|
497
|
+
}
|
498
|
+
|
499
|
+
if (listenFd == LIBUS_SOCKET_ERROR) {
|
500
|
+
freeaddrinfo(result);
|
501
|
+
return LIBUS_SOCKET_ERROR;
|
502
|
+
}
|
503
|
+
|
504
|
+
if (port != 0) {
|
505
|
+
/* Otherwise, always enable SO_REUSEPORT and SO_REUSEADDR _unless_ options specify otherwise */
|
506
|
+
#ifdef _WIN32
|
507
|
+
if (options & LIBUS_LISTEN_EXCLUSIVE_PORT) {
|
508
|
+
int optval2 = 1;
|
509
|
+
setsockopt(listenFd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (void *) &optval2, sizeof(optval2));
|
510
|
+
} else {
|
511
|
+
int optval3 = 1;
|
512
|
+
setsockopt(listenFd, SOL_SOCKET, SO_REUSEADDR, (void *) &optval3, sizeof(optval3));
|
513
|
+
}
|
514
|
+
#else
|
515
|
+
#if /*defined(__linux) &&*/ defined(SO_REUSEPORT)
|
516
|
+
if (!(options & LIBUS_LISTEN_EXCLUSIVE_PORT)) {
|
517
|
+
int optval = 1;
|
518
|
+
setsockopt(listenFd, SOL_SOCKET, SO_REUSEPORT, (void *) &optval, sizeof(optval));
|
519
|
+
}
|
520
|
+
#endif
|
521
|
+
int enabled = 1;
|
522
|
+
setsockopt(listenFd, SOL_SOCKET, SO_REUSEADDR, (void *) &enabled, sizeof(enabled));
|
523
|
+
#endif
|
524
|
+
|
525
|
+
}
|
526
|
+
|
527
|
+
#ifdef IPV6_V6ONLY
|
528
|
+
int disabled = 0;
|
529
|
+
setsockopt(listenFd, IPPROTO_IPV6, IPV6_V6ONLY, (void *) &disabled, sizeof(disabled));
|
530
|
+
#endif
|
531
|
+
|
532
|
+
if (bind(listenFd, listenAddr->ai_addr, (socklen_t) listenAddr->ai_addrlen) || listen(listenFd, 512)) {
|
533
|
+
bsd_close_socket(listenFd);
|
534
|
+
freeaddrinfo(result);
|
535
|
+
return LIBUS_SOCKET_ERROR;
|
536
|
+
}
|
537
|
+
|
538
|
+
freeaddrinfo(result);
|
539
|
+
return listenFd;
|
540
|
+
}
|
541
|
+
|
542
|
+
#ifndef _WIN32
|
543
|
+
#include <sys/un.h>
|
544
|
+
#else
|
545
|
+
#include <afunix.h>
|
546
|
+
#include <io.h>
|
547
|
+
#endif
|
548
|
+
#include <sys/stat.h>
|
549
|
+
#include <stddef.h>
|
550
|
+
LIBUS_SOCKET_DESCRIPTOR bsd_create_listen_socket_unix(const char *path, int options) {
|
551
|
+
|
552
|
+
LIBUS_SOCKET_DESCRIPTOR listenFd = LIBUS_SOCKET_ERROR;
|
553
|
+
|
554
|
+
listenFd = bsd_create_socket(AF_UNIX, SOCK_STREAM, 0);
|
555
|
+
|
556
|
+
if (listenFd == LIBUS_SOCKET_ERROR) {
|
557
|
+
return LIBUS_SOCKET_ERROR;
|
558
|
+
}
|
559
|
+
|
560
|
+
#ifndef _WIN32
|
561
|
+
// 700 permission by default
|
562
|
+
fchmod(listenFd, S_IRWXU);
|
563
|
+
#else
|
564
|
+
_chmod(path, S_IREAD | S_IWRITE | S_IEXEC);
|
565
|
+
#endif
|
566
|
+
|
567
|
+
struct sockaddr_un server_address;
|
568
|
+
memset(&server_address, 0, sizeof(server_address));
|
569
|
+
server_address.sun_family = AF_UNIX;
|
570
|
+
strcpy(server_address.sun_path, path);
|
571
|
+
int size = offsetof(struct sockaddr_un, sun_path) + strlen(server_address.sun_path);
|
572
|
+
#ifdef _WIN32
|
573
|
+
_unlink(path);
|
574
|
+
#else
|
575
|
+
unlink(path);
|
576
|
+
#endif
|
577
|
+
|
578
|
+
if (bind(listenFd, (struct sockaddr *)&server_address, size) || listen(listenFd, 512)) {
|
579
|
+
bsd_close_socket(listenFd);
|
580
|
+
return LIBUS_SOCKET_ERROR;
|
581
|
+
}
|
582
|
+
|
583
|
+
return listenFd;
|
584
|
+
}
|
585
|
+
|
586
|
+
LIBUS_SOCKET_DESCRIPTOR bsd_create_udp_socket(const char *host, int port) {
|
587
|
+
struct addrinfo hints, *result;
|
588
|
+
memset(&hints, 0, sizeof(struct addrinfo));
|
589
|
+
|
590
|
+
hints.ai_flags = AI_PASSIVE;
|
591
|
+
hints.ai_family = AF_UNSPEC;
|
592
|
+
hints.ai_socktype = SOCK_DGRAM;
|
593
|
+
|
594
|
+
char port_string[16];
|
595
|
+
snprintf(port_string, 16, "%d", port);
|
596
|
+
|
597
|
+
if (getaddrinfo(host, port_string, &hints, &result)) {
|
598
|
+
return LIBUS_SOCKET_ERROR;
|
599
|
+
}
|
600
|
+
|
601
|
+
LIBUS_SOCKET_DESCRIPTOR listenFd = LIBUS_SOCKET_ERROR;
|
602
|
+
struct addrinfo *listenAddr;
|
603
|
+
for (struct addrinfo *a = result; a && listenFd == LIBUS_SOCKET_ERROR; a = a->ai_next) {
|
604
|
+
if (a->ai_family == AF_INET6) {
|
605
|
+
listenFd = bsd_create_socket(a->ai_family, a->ai_socktype, a->ai_protocol);
|
606
|
+
listenAddr = a;
|
607
|
+
}
|
608
|
+
}
|
609
|
+
|
610
|
+
for (struct addrinfo *a = result; a && listenFd == LIBUS_SOCKET_ERROR; a = a->ai_next) {
|
611
|
+
if (a->ai_family == AF_INET) {
|
612
|
+
listenFd = bsd_create_socket(a->ai_family, a->ai_socktype, a->ai_protocol);
|
613
|
+
listenAddr = a;
|
614
|
+
}
|
615
|
+
}
|
616
|
+
|
617
|
+
if (listenFd == LIBUS_SOCKET_ERROR) {
|
618
|
+
freeaddrinfo(result);
|
619
|
+
return LIBUS_SOCKET_ERROR;
|
620
|
+
}
|
621
|
+
|
622
|
+
if (port != 0) {
|
623
|
+
/* Should this also go for UDP? */
|
624
|
+
int enabled = 1;
|
625
|
+
setsockopt(listenFd, SOL_SOCKET, SO_REUSEADDR, (void *) &enabled, sizeof(enabled));
|
626
|
+
}
|
627
|
+
|
628
|
+
#ifdef IPV6_V6ONLY
|
629
|
+
int disabled = 0;
|
630
|
+
setsockopt(listenFd, IPPROTO_IPV6, IPV6_V6ONLY, (void *) &disabled, sizeof(disabled));
|
631
|
+
#endif
|
632
|
+
|
633
|
+
/* We need destination address for udp packets in both ipv6 and ipv4 */
|
634
|
+
|
635
|
+
/* On FreeBSD this option seems to be called like so */
|
636
|
+
#ifndef IPV6_RECVPKTINFO
|
637
|
+
#define IPV6_RECVPKTINFO IPV6_PKTINFO
|
638
|
+
#endif
|
639
|
+
|
640
|
+
int enabled = 1;
|
641
|
+
if (setsockopt(listenFd, IPPROTO_IPV6, IPV6_RECVPKTINFO, (void *) &enabled, sizeof(enabled)) == -1) {
|
642
|
+
if (errno == 92) {
|
643
|
+
// Linux ipv4
|
644
|
+
#ifdef IP_PKTINFO
|
645
|
+
if (setsockopt(listenFd, IPPROTO_IP, IP_PKTINFO, (void *) &enabled, sizeof(enabled)) != 0) {
|
646
|
+
printf("Error setting IPv4 pktinfo!\n");
|
647
|
+
}
|
648
|
+
// FreeBSD ipv4
|
649
|
+
#elif IP_RECVDSTADDR
|
650
|
+
if (setsockopt(listenFd, IPPROTO_IP, IP_RECVDSTADDR, (void *) &enabled, sizeof(enabled)) != 0) {
|
651
|
+
printf("Error setting IPv4 pktinfo!\n");
|
652
|
+
}
|
653
|
+
#endif
|
654
|
+
} else {
|
655
|
+
printf("Error setting IPv6 pktinfo!\n");
|
656
|
+
}
|
657
|
+
}
|
658
|
+
|
659
|
+
/* These are used for getting the ECN */
|
660
|
+
if (setsockopt(listenFd, IPPROTO_IPV6, IPV6_RECVTCLASS, (void *) &enabled, sizeof(enabled)) == -1) {
|
661
|
+
if (errno == 92) {
|
662
|
+
if (setsockopt(listenFd, IPPROTO_IP, IP_RECVTOS, (void *) &enabled, sizeof(enabled)) != 0) {
|
663
|
+
printf("Error setting IPv4 ECN!\n");
|
664
|
+
}
|
665
|
+
} else {
|
666
|
+
printf("Error setting IPv6 ECN!\n");
|
667
|
+
}
|
668
|
+
}
|
669
|
+
|
670
|
+
/* We bind here as well */
|
671
|
+
if (bind(listenFd, listenAddr->ai_addr, (socklen_t) listenAddr->ai_addrlen)) {
|
672
|
+
bsd_close_socket(listenFd);
|
673
|
+
freeaddrinfo(result);
|
674
|
+
return LIBUS_SOCKET_ERROR;
|
675
|
+
}
|
676
|
+
|
677
|
+
freeaddrinfo(result);
|
678
|
+
return listenFd;
|
679
|
+
}
|
680
|
+
|
681
|
+
int bsd_udp_packet_buffer_ecn(void *msgvec, int index) {
|
682
|
+
|
683
|
+
#if defined(_WIN32) || defined(__APPLE__)
|
684
|
+
printf("ECN not supported!\n");
|
685
|
+
#else
|
686
|
+
// we should iterate all control messages once, after recvmmsg and then only fetch them with these functions
|
687
|
+
struct msghdr *mh = &((struct mmsghdr *) msgvec)[index].msg_hdr;
|
688
|
+
for (struct cmsghdr *cmsg = CMSG_FIRSTHDR(mh); cmsg != NULL; cmsg = CMSG_NXTHDR(mh, cmsg)) {
|
689
|
+
// do we need to get TOS from ipv6 also?
|
690
|
+
if (cmsg->cmsg_level == IPPROTO_IP) {
|
691
|
+
if (cmsg->cmsg_type == IP_TOS) {
|
692
|
+
uint8_t tos = *(uint8_t *)CMSG_DATA(cmsg);
|
693
|
+
return tos & 3;
|
694
|
+
}
|
695
|
+
}
|
696
|
+
|
697
|
+
if (cmsg->cmsg_level == IPPROTO_IPV6) {
|
698
|
+
if (cmsg->cmsg_type == IPV6_TCLASS) {
|
699
|
+
// is this correct?
|
700
|
+
uint8_t tos = *(uint8_t *)CMSG_DATA(cmsg);
|
701
|
+
return tos & 3;
|
702
|
+
}
|
703
|
+
}
|
704
|
+
}
|
705
|
+
#endif
|
706
|
+
|
707
|
+
printf("We got no ECN!\n");
|
708
|
+
|
709
|
+
return 0; // no ecn defaults to 0
|
710
|
+
}
|
711
|
+
|
712
|
+
LIBUS_SOCKET_DESCRIPTOR bsd_create_connect_socket(const char *host, int port, const char *source_host, int options) {
|
713
|
+
struct addrinfo hints, *result;
|
714
|
+
memset(&hints, 0, sizeof(struct addrinfo));
|
715
|
+
hints.ai_family = AF_UNSPEC;
|
716
|
+
hints.ai_socktype = SOCK_STREAM;
|
717
|
+
|
718
|
+
char port_string[16];
|
719
|
+
snprintf(port_string, 16, "%d", port);
|
720
|
+
|
721
|
+
if (getaddrinfo(host, port_string, &hints, &result) != 0) {
|
722
|
+
return LIBUS_SOCKET_ERROR;
|
723
|
+
}
|
724
|
+
|
725
|
+
LIBUS_SOCKET_DESCRIPTOR fd = bsd_create_socket(result->ai_family, result->ai_socktype, result->ai_protocol);
|
726
|
+
if (fd == LIBUS_SOCKET_ERROR) {
|
727
|
+
freeaddrinfo(result);
|
728
|
+
return LIBUS_SOCKET_ERROR;
|
729
|
+
}
|
730
|
+
|
731
|
+
if (source_host) {
|
732
|
+
struct addrinfo *interface_result;
|
733
|
+
if (!getaddrinfo(source_host, NULL, NULL, &interface_result)) {
|
734
|
+
int ret = bind(fd, interface_result->ai_addr, (socklen_t) interface_result->ai_addrlen);
|
735
|
+
freeaddrinfo(interface_result);
|
736
|
+
if (ret == LIBUS_SOCKET_ERROR) {
|
737
|
+
bsd_close_socket(fd);
|
738
|
+
freeaddrinfo(result);
|
739
|
+
return LIBUS_SOCKET_ERROR;
|
740
|
+
}
|
741
|
+
}
|
742
|
+
}
|
743
|
+
|
744
|
+
connect(fd, result->ai_addr, (socklen_t) result->ai_addrlen);
|
745
|
+
freeaddrinfo(result);
|
746
|
+
|
747
|
+
return fd;
|
748
|
+
}
|
749
|
+
|
750
|
+
LIBUS_SOCKET_DESCRIPTOR bsd_create_connect_socket_unix(const char *server_path, int options) {
|
751
|
+
|
752
|
+
struct sockaddr_un server_address;
|
753
|
+
memset(&server_address, 0, sizeof(server_address));
|
754
|
+
server_address.sun_family = AF_UNIX;
|
755
|
+
strcpy(server_address.sun_path, server_path);
|
756
|
+
int size = offsetof(struct sockaddr_un, sun_path) + strlen(server_address.sun_path);
|
757
|
+
|
758
|
+
LIBUS_SOCKET_DESCRIPTOR fd = bsd_create_socket(AF_UNIX, SOCK_STREAM, 0);
|
759
|
+
|
760
|
+
if (fd == LIBUS_SOCKET_ERROR) {
|
761
|
+
return LIBUS_SOCKET_ERROR;
|
762
|
+
}
|
763
|
+
|
764
|
+
connect(fd, (struct sockaddr *)&server_address, size);
|
765
|
+
|
766
|
+
return fd;
|
767
|
+
}
|