iodine 0.2.17 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of iodine might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/README.md +36 -3
- data/bin/config.ru +23 -2
- data/bin/http-hello +1 -1
- data/bin/ws-shootout +5 -0
- data/ext/iodine/defer.c +468 -0
- data/ext/iodine/defer.h +105 -0
- data/ext/iodine/evio.c +263 -0
- data/ext/iodine/evio.h +133 -0
- data/ext/iodine/extconf.rb +2 -1
- data/ext/iodine/facil.c +958 -0
- data/ext/iodine/facil.h +423 -0
- data/ext/iodine/http.c +90 -0
- data/ext/iodine/http.h +50 -12
- data/ext/iodine/http1.c +200 -267
- data/ext/iodine/http1.h +17 -26
- data/ext/iodine/http1_request.c +81 -0
- data/ext/iodine/http1_request.h +58 -0
- data/ext/iodine/http1_response.c +403 -0
- data/ext/iodine/http1_response.h +90 -0
- data/ext/iodine/http1_simple_parser.c +124 -108
- data/ext/iodine/http1_simple_parser.h +8 -3
- data/ext/iodine/http_request.c +104 -0
- data/ext/iodine/http_request.h +58 -102
- data/ext/iodine/http_response.c +212 -208
- data/ext/iodine/http_response.h +89 -252
- data/ext/iodine/iodine_core.c +57 -46
- data/ext/iodine/iodine_core.h +3 -1
- data/ext/iodine/iodine_http.c +105 -81
- data/ext/iodine/iodine_websocket.c +17 -13
- data/ext/iodine/iodine_websocket.h +1 -0
- data/ext/iodine/rb-call.c +9 -7
- data/ext/iodine/{rb-libasync.h → rb-defer.c} +57 -49
- data/ext/iodine/rb-rack-io.c +12 -6
- data/ext/iodine/rb-rack-io.h +1 -1
- data/ext/iodine/rb-registry.c +5 -2
- data/ext/iodine/sock.c +1159 -0
- data/ext/iodine/{libsock.h → sock.h} +138 -142
- data/ext/iodine/spnlock.inc +77 -0
- data/ext/iodine/websockets.c +101 -112
- data/ext/iodine/websockets.h +38 -19
- data/iodine.gemspec +3 -3
- data/lib/iodine/version.rb +1 -1
- data/lib/rack/handler/iodine.rb +6 -6
- metadata +23 -19
- data/ext/iodine/http_response_http1.h +0 -382
- data/ext/iodine/libasync.c +0 -570
- data/ext/iodine/libasync.h +0 -122
- data/ext/iodine/libreact.c +0 -350
- data/ext/iodine/libreact.h +0 -244
- data/ext/iodine/libserver.c +0 -957
- data/ext/iodine/libserver.h +0 -481
- data/ext/iodine/libsock.c +0 -1025
- data/ext/iodine/spnlock.h +0 -243
data/ext/iodine/libsock.c
DELETED
@@ -1,1025 +0,0 @@
|
|
1
|
-
/*
|
2
|
-
Copyright: Boaz Segev, 2016-2017
|
3
|
-
License: MIT
|
4
|
-
|
5
|
-
Feel free to copy, use and enjoy according to the license provided.
|
6
|
-
*/
|
7
|
-
#ifndef _GNU_SOURCE
|
8
|
-
#define _GNU_SOURCE
|
9
|
-
#endif
|
10
|
-
|
11
|
-
#include "libsock.h"
|
12
|
-
|
13
|
-
#include <errno.h>
|
14
|
-
#include <fcntl.h>
|
15
|
-
#include <limits.h>
|
16
|
-
#include <netdb.h>
|
17
|
-
#include <stdio.h>
|
18
|
-
#include <string.h>
|
19
|
-
#include <sys/mman.h>
|
20
|
-
#include <sys/resource.h>
|
21
|
-
#include <sys/socket.h>
|
22
|
-
#include <sys/time.h>
|
23
|
-
#include <sys/types.h>
|
24
|
-
#include <time.h>
|
25
|
-
|
26
|
-
/* *****************************************************************************
|
27
|
-
Use spinlocks "spnlock.h".
|
28
|
-
|
29
|
-
For portability, it's possible copy "spnlock.h" directly after this line.
|
30
|
-
*/
|
31
|
-
#include "spnlock.h"
|
32
|
-
|
33
|
-
/* *****************************************************************************
|
34
|
-
Support `libreact` on_close callback, if exist.
|
35
|
-
*/
|
36
|
-
|
37
|
-
#pragma weak reactor_on_close
|
38
|
-
void reactor_on_close(intptr_t uuid) { (void)(uuid); }
|
39
|
-
#pragma weak reactor_remove
|
40
|
-
int reactor_remove(intptr_t uuid) {
|
41
|
-
(void)(uuid);
|
42
|
-
return -1;
|
43
|
-
}
|
44
|
-
|
45
|
-
/* *****************************************************************************
|
46
|
-
Support timeout setting.
|
47
|
-
*/
|
48
|
-
#pragma weak sock_touch
|
49
|
-
void sock_touch(intptr_t uuid) { (void)(uuid); }
|
50
|
-
|
51
|
-
/* *****************************************************************************
|
52
|
-
Support event based `write` scheduling.
|
53
|
-
*/
|
54
|
-
#pragma weak async_run
|
55
|
-
int async_run(void (*task)(void *), void *arg) {
|
56
|
-
(void)(task);
|
57
|
-
(void)(arg);
|
58
|
-
return -1;
|
59
|
-
}
|
60
|
-
|
61
|
-
/* *****************************************************************************
|
62
|
-
OS Sendfile settings.
|
63
|
-
*/
|
64
|
-
|
65
|
-
#ifndef USE_SENDFILE
|
66
|
-
|
67
|
-
#if defined(__linux__) /* linux sendfile works */
|
68
|
-
#include <sys/sendfile.h>
|
69
|
-
#define USE_SENDFILE 1
|
70
|
-
#elif defined(__unix__) /* BSD sendfile should work, but isn't tested */
|
71
|
-
#include <sys/uio.h>
|
72
|
-
#define USE_SENDFILE 0
|
73
|
-
#elif defined(__APPLE__) /* Is the apple sendfile still broken? */
|
74
|
-
#include <sys/uio.h>
|
75
|
-
#define USE_SENDFILE 1
|
76
|
-
#else /* sendfile might not be available - always set to 0 */
|
77
|
-
#define USE_SENDFILE 0
|
78
|
-
#endif
|
79
|
-
|
80
|
-
#endif
|
81
|
-
|
82
|
-
/* *****************************************************************************
|
83
|
-
Buffer and socket map memory allocation. Defaults to mmap.
|
84
|
-
*/
|
85
|
-
#ifndef USE_MALLOC
|
86
|
-
#define USE_MALLOC 0
|
87
|
-
#endif
|
88
|
-
|
89
|
-
/* *****************************************************************************
|
90
|
-
The system call to `write` (non-blocking) can be defered when using `libasync`.
|
91
|
-
|
92
|
-
However, this will not prevent `sock_write` from cycling through the sockets and
|
93
|
-
flushing them (block emulation) when both the system and the user level buffers
|
94
|
-
are full.
|
95
|
-
|
96
|
-
Defaults to 1 (defered).
|
97
|
-
*/
|
98
|
-
#ifndef SOCK_DELAY_WRITE
|
99
|
-
#define SOCK_DELAY_WRITE 1
|
100
|
-
#endif
|
101
|
-
|
102
|
-
/* *****************************************************************************
|
103
|
-
Library related helper functions
|
104
|
-
*/
|
105
|
-
|
106
|
-
/**
|
107
|
-
Sets a socket to non blocking state.
|
108
|
-
*/
|
109
|
-
inline int sock_set_non_block(int fd) // Thanks to Bjorn Reese
|
110
|
-
{
|
111
|
-
/* If they have O_NONBLOCK, use the Posix way to do it */
|
112
|
-
#if defined(O_NONBLOCK)
|
113
|
-
/* Fixme: O_NONBLOCK is defined but broken on SunOS 4.1.x and AIX 3.2.5. */
|
114
|
-
int flags;
|
115
|
-
if (-1 == (flags = fcntl(fd, F_GETFL, 0)))
|
116
|
-
flags = 0;
|
117
|
-
// printf("flags initial value was %d\n", flags);
|
118
|
-
return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
|
119
|
-
#else
|
120
|
-
/* Otherwise, use the old way of doing it */
|
121
|
-
static int flags = 1;
|
122
|
-
return ioctl(fd, FIOBIO, &flags);
|
123
|
-
#endif
|
124
|
-
}
|
125
|
-
|
126
|
-
/**
|
127
|
-
Gets the maximum number of file descriptors this process can be allowed to
|
128
|
-
access (== maximum fd value + 1).
|
129
|
-
*/
|
130
|
-
ssize_t sock_max_capacity(void) {
|
131
|
-
// get current limits
|
132
|
-
static ssize_t flim = 0;
|
133
|
-
if (flim)
|
134
|
-
return flim;
|
135
|
-
#ifdef _SC_OPEN_MAX
|
136
|
-
flim = sysconf(_SC_OPEN_MAX);
|
137
|
-
#elif defined(OPEN_MAX)
|
138
|
-
flim = OPEN_MAX;
|
139
|
-
#endif
|
140
|
-
// try to maximize limits - collect max and set to max
|
141
|
-
struct rlimit rlim = {.rlim_max = 0};
|
142
|
-
getrlimit(RLIMIT_NOFILE, &rlim);
|
143
|
-
// printf("Meximum open files are %llu out of %llu\n", rlim.rlim_cur,
|
144
|
-
// rlim.rlim_max);
|
145
|
-
#if defined(__APPLE__) /* Apple's getrlimit is broken. */
|
146
|
-
rlim.rlim_cur = rlim.rlim_max >= OPEN_MAX ? OPEN_MAX : rlim.rlim_max;
|
147
|
-
#else
|
148
|
-
rlim.rlim_cur = rlim.rlim_max;
|
149
|
-
#endif
|
150
|
-
|
151
|
-
setrlimit(RLIMIT_NOFILE, &rlim);
|
152
|
-
getrlimit(RLIMIT_NOFILE, &rlim);
|
153
|
-
// printf("Meximum open files are %llu out of %llu\n", rlim.rlim_cur,
|
154
|
-
// rlim.rlim_max);
|
155
|
-
// if the current limit is higher than it was, update
|
156
|
-
if (flim < ((ssize_t)rlim.rlim_cur))
|
157
|
-
flim = rlim.rlim_cur;
|
158
|
-
// return what we have
|
159
|
-
return flim;
|
160
|
-
}
|
161
|
-
|
162
|
-
/* *****************************************************************************
|
163
|
-
Library Core Data
|
164
|
-
*/
|
165
|
-
|
166
|
-
typedef struct {
|
167
|
-
/** write buffer - a linked list */
|
168
|
-
sock_packet_s *packet;
|
169
|
-
/** The fd UUID for the current connection */
|
170
|
-
fduuid_u fduuid;
|
171
|
-
/** the amount of data sent from the current buffer packet */
|
172
|
-
uint32_t sent;
|
173
|
-
/** state lock */
|
174
|
-
spn_lock_i lock;
|
175
|
-
/* -- state flags -- */
|
176
|
-
/** Connection is open */
|
177
|
-
unsigned open : 1;
|
178
|
-
/** indicated that the connection should be closed. */
|
179
|
-
unsigned close : 1;
|
180
|
-
/** indicated that the connection experienced an error. */
|
181
|
-
unsigned err : 1;
|
182
|
-
/** future flags. */
|
183
|
-
unsigned rsv : 5;
|
184
|
-
/* -- placement enforces padding to guaranty memory alignment -- */
|
185
|
-
/** Read/Write hooks. */
|
186
|
-
sock_rw_hook_s *rw_hooks;
|
187
|
-
} fd_info_s;
|
188
|
-
|
189
|
-
#define LIB_SOCK_STATE_OPEN 1
|
190
|
-
#define LIB_SOCK_STATE_CLOSED 0
|
191
|
-
|
192
|
-
static fd_info_s *fd_info = NULL;
|
193
|
-
static size_t fd_capacity = 0;
|
194
|
-
|
195
|
-
#define uuid2info(uuid) fd_info[sock_uuid2fd(uuid)]
|
196
|
-
#define is_valid(uuid) \
|
197
|
-
(sock_uuid2fd(uuid) >= 0 && sock_uuid2fd(uuid) <= (int)fd_capacity && \
|
198
|
-
fd_info[sock_uuid2fd(uuid)].fduuid.data.counter == \
|
199
|
-
((fduuid_u *)(&uuid))->data.counter && \
|
200
|
-
uuid2info(uuid).open)
|
201
|
-
|
202
|
-
static struct {
|
203
|
-
sock_packet_s *volatile pool;
|
204
|
-
sock_packet_s *allocated;
|
205
|
-
spn_lock_i lock;
|
206
|
-
} buffer_pool = {.lock = SPN_LOCK_INIT};
|
207
|
-
|
208
|
-
#define BUFFER_PACKET_REAL_SIZE (sizeof(sock_packet_s) + BUFFER_PACKET_SIZE)
|
209
|
-
|
210
|
-
/* reset a socket state */
|
211
|
-
static inline void set_fd(int fd, unsigned int state) {
|
212
|
-
fd_info_s old_data;
|
213
|
-
// lock and update
|
214
|
-
spn_lock(&fd_info[fd].lock);
|
215
|
-
old_data = fd_info[fd];
|
216
|
-
fd_info[fd] = (fd_info_s){
|
217
|
-
.fduuid.data.counter = fd_info[fd].fduuid.data.counter + state,
|
218
|
-
.fduuid.data.fd = fd,
|
219
|
-
.lock = fd_info[fd].lock,
|
220
|
-
.open = state,
|
221
|
-
};
|
222
|
-
// unlock
|
223
|
-
spn_unlock(&fd_info[fd].lock);
|
224
|
-
// should be called within the lock? - no function calling within a
|
225
|
-
// spinlock.
|
226
|
-
if (old_data.rw_hooks && old_data.rw_hooks->on_clear)
|
227
|
-
old_data.rw_hooks->on_clear(old_data.fduuid.uuid, old_data.rw_hooks);
|
228
|
-
// clear old data
|
229
|
-
if (old_data.packet)
|
230
|
-
sock_free_packet(old_data.packet);
|
231
|
-
// call callback if exists
|
232
|
-
if (old_data.open) {
|
233
|
-
// if (state == LIB_SOCK_STATE_OPEN)
|
234
|
-
// printf(
|
235
|
-
// "STRONG FD COLLISION PROTECTION: A new connection was accepted "
|
236
|
-
// "while the old one was marked as open.\n");
|
237
|
-
reactor_remove(old_data.fduuid.uuid);
|
238
|
-
reactor_on_close(old_data.fduuid.uuid);
|
239
|
-
}
|
240
|
-
}
|
241
|
-
|
242
|
-
/**
|
243
|
-
Destroys the library data.
|
244
|
-
|
245
|
-
Call this function before calling any `libsock` functions.
|
246
|
-
*/
|
247
|
-
static void destroy_lib_data(void) {
|
248
|
-
if (fd_info) {
|
249
|
-
while (fd_capacity--) { // include 0 in countdown
|
250
|
-
// if (fd_info[fd_capacity].open) {
|
251
|
-
// fprintf(stderr, "Socket %lu is marked as open\n", fd_capacity);
|
252
|
-
// }
|
253
|
-
set_fd(fd_capacity, LIB_SOCK_STATE_CLOSED);
|
254
|
-
}
|
255
|
-
#if USE_MALLOC == 1
|
256
|
-
free(fd_info);
|
257
|
-
#else
|
258
|
-
munmap(fd_info,
|
259
|
-
(BUFFER_PACKET_REAL_SIZE * BUFFER_PACKET_POOL) +
|
260
|
-
(sizeof(fd_info_s) * fd_capacity));
|
261
|
-
#endif
|
262
|
-
}
|
263
|
-
fd_info = NULL;
|
264
|
-
buffer_pool.pool = NULL;
|
265
|
-
buffer_pool.allocated = NULL;
|
266
|
-
buffer_pool.lock = SPN_LOCK_INIT;
|
267
|
-
}
|
268
|
-
|
269
|
-
/**
|
270
|
-
Initializes the library.
|
271
|
-
|
272
|
-
Call this function before calling any `libsock` functions.
|
273
|
-
*/
|
274
|
-
static void sock_lib_init(void) {
|
275
|
-
if (fd_info)
|
276
|
-
return;
|
277
|
-
|
278
|
-
fd_capacity = sock_max_capacity();
|
279
|
-
size_t fd_map_mem_size = sizeof(fd_info_s) * fd_capacity;
|
280
|
-
size_t buffer_mem_size = BUFFER_PACKET_REAL_SIZE * BUFFER_PACKET_POOL;
|
281
|
-
|
282
|
-
void *buff_mem;
|
283
|
-
#if USE_MALLOC == 1
|
284
|
-
buff_mem = malloc(fd_map_mem_size + buffer_mem_size);
|
285
|
-
if (buff_mem == NULL) {
|
286
|
-
perror("Couldn't initialize libsock - not enough memory? ");
|
287
|
-
exit(1);
|
288
|
-
}
|
289
|
-
#else
|
290
|
-
buff_mem = mmap(NULL, fd_map_mem_size + buffer_mem_size,
|
291
|
-
PROT_READ | PROT_WRITE | PROT_EXEC,
|
292
|
-
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
293
|
-
// MAP_SHARED | MAP_ANONYMOUS, -1, 0);
|
294
|
-
if (buff_mem == MAP_FAILED || buff_mem == NULL) {
|
295
|
-
perror("Couldn't initialize libsock - not enough memory? ");
|
296
|
-
exit(1);
|
297
|
-
}
|
298
|
-
#endif
|
299
|
-
fd_info = buff_mem;
|
300
|
-
for (size_t i = 0; i < fd_capacity; i++) {
|
301
|
-
fd_info[i] = (fd_info_s){.lock = SPN_LOCK_INIT};
|
302
|
-
spn_unlock(&fd_info[i].lock);
|
303
|
-
}
|
304
|
-
/* initialize pool */
|
305
|
-
buffer_pool.allocated = (void *)((uintptr_t)buff_mem + fd_map_mem_size);
|
306
|
-
buffer_pool.pool = buffer_pool.allocated;
|
307
|
-
sock_packet_s *pos = buffer_pool.pool;
|
308
|
-
for (size_t i = 0; i < BUFFER_PACKET_POOL - 1; i++) {
|
309
|
-
*pos = (sock_packet_s){
|
310
|
-
.metadata.next = (void *)(((uintptr_t)pos) + BUFFER_PACKET_REAL_SIZE),
|
311
|
-
};
|
312
|
-
pos = pos->metadata.next;
|
313
|
-
}
|
314
|
-
pos->metadata.next = 0;
|
315
|
-
/* deallocate and manage on exit */
|
316
|
-
atexit(destroy_lib_data);
|
317
|
-
#ifdef DEBUG
|
318
|
-
fprintf(stderr, "\nInitialized libsock for %lu sockets, "
|
319
|
-
"each one requires %lu bytes.\n"
|
320
|
-
"overall ovearhead: %lu bytes.\n"
|
321
|
-
"Initialized packet pool for %d elements, "
|
322
|
-
"each one %lu bytes.\n"
|
323
|
-
"overall buffer ovearhead: %lu bytes.\n"
|
324
|
-
"=== Total: %lu bytes ===\n\n",
|
325
|
-
fd_capacity, sizeof(*fd_info), sizeof(*fd_info) * fd_capacity,
|
326
|
-
BUFFER_PACKET_POOL, BUFFER_PACKET_REAL_SIZE,
|
327
|
-
BUFFER_PACKET_REAL_SIZE * BUFFER_PACKET_POOL,
|
328
|
-
(BUFFER_PACKET_REAL_SIZE * BUFFER_PACKET_POOL) +
|
329
|
-
(sizeof(*fd_info) * fd_capacity));
|
330
|
-
#endif
|
331
|
-
}
|
332
|
-
|
333
|
-
#define review_lib() \
|
334
|
-
if (fd_info == NULL) \
|
335
|
-
sock_lib_init();
|
336
|
-
|
337
|
-
/* *****************************************************************************
|
338
|
-
Read / Write internals
|
339
|
-
*/
|
340
|
-
|
341
|
-
#define ERR_OK (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOTCONN)
|
342
|
-
#define ERR_TRY_AGAIN (errno == EINTR)
|
343
|
-
|
344
|
-
static inline int sock_flush_fd_failed(int fd) {
|
345
|
-
sock_free_packet(fd_info[fd].packet);
|
346
|
-
fd_info[fd].packet = NULL;
|
347
|
-
fd_info[fd].close = 1;
|
348
|
-
fd_info[fd].err = 1;
|
349
|
-
return 0;
|
350
|
-
}
|
351
|
-
|
352
|
-
#if USE_SENDFILE == 1
|
353
|
-
|
354
|
-
#if defined(__linux__) /* linux sendfile API */
|
355
|
-
static inline int sock_flush_os_sendfile(int fd) {
|
356
|
-
ssize_t sent;
|
357
|
-
sock_packet_s *packet = fd_info[fd].packet;
|
358
|
-
sent =
|
359
|
-
sendfile64(fd, (int)((ssize_t)packet->buffer), &packet->metadata.offset,
|
360
|
-
packet->length - fd_info[fd].sent);
|
361
|
-
|
362
|
-
if (sent < 0) {
|
363
|
-
if (ERR_OK)
|
364
|
-
return -1;
|
365
|
-
else if (ERR_TRY_AGAIN)
|
366
|
-
return 0;
|
367
|
-
else
|
368
|
-
return sock_flush_fd_failed(fd);
|
369
|
-
}
|
370
|
-
if (sent == 0)
|
371
|
-
fd_info[fd].sent = packet->length;
|
372
|
-
fd_info[fd].sent += sent;
|
373
|
-
return 0;
|
374
|
-
}
|
375
|
-
|
376
|
-
#elif defined(__APPLE__) || defined(__unix__) /* BSD / Apple API */
|
377
|
-
|
378
|
-
static inline int sock_flush_os_sendfile(int fd) {
|
379
|
-
off_t act_sent;
|
380
|
-
sock_packet_s *packet = fd_info[fd].packet;
|
381
|
-
act_sent = packet->length - fd_info[fd].sent;
|
382
|
-
|
383
|
-
#if defined(__APPLE__)
|
384
|
-
if (sendfile((int)((ssize_t)packet->buffer), fd, packet->metadata.offset,
|
385
|
-
&act_sent, NULL, 0) < 0 &&
|
386
|
-
act_sent == 0)
|
387
|
-
#else
|
388
|
-
if (sendfile((int)((ssize_t)packet->buffer), fd, packet->metadata.offset,
|
389
|
-
(size_t)act_sent, NULL, &act_sent, 0) < 0 &&
|
390
|
-
act_sent == 0)
|
391
|
-
#endif
|
392
|
-
{
|
393
|
-
if (ERR_OK)
|
394
|
-
return -1;
|
395
|
-
else if (ERR_TRY_AGAIN)
|
396
|
-
return 0;
|
397
|
-
else
|
398
|
-
return sock_flush_fd_failed(fd);
|
399
|
-
}
|
400
|
-
if (act_sent == 0) {
|
401
|
-
fd_info[fd].sent = packet->length;
|
402
|
-
return 0;
|
403
|
-
}
|
404
|
-
packet->metadata.offset += act_sent;
|
405
|
-
fd_info[fd].sent += act_sent;
|
406
|
-
return 0;
|
407
|
-
}
|
408
|
-
#endif
|
409
|
-
|
410
|
-
#else
|
411
|
-
|
412
|
-
static inline int sock_flush_os_sendfile(int fd) { return -1; }
|
413
|
-
|
414
|
-
#endif
|
415
|
-
|
416
|
-
static inline int sock_flush_fd(int fd) {
|
417
|
-
if (USE_SENDFILE && fd_info[fd].rw_hooks == NULL)
|
418
|
-
return sock_flush_os_sendfile(fd);
|
419
|
-
ssize_t sent;
|
420
|
-
sock_packet_s *packet = fd_info[fd].packet;
|
421
|
-
// how much data are we expecting to send...?
|
422
|
-
ssize_t i_exp = (BUFFER_PACKET_SIZE > packet->length) ? packet->length
|
423
|
-
: BUFFER_PACKET_SIZE;
|
424
|
-
|
425
|
-
// read data into the internal buffer
|
426
|
-
if (packet->metadata.internal_flag == 0) {
|
427
|
-
ssize_t i_read;
|
428
|
-
i_read = pread((int)((ssize_t)packet->buffer), packet + 1, i_exp,
|
429
|
-
packet->metadata.offset);
|
430
|
-
if (i_read <= 0) {
|
431
|
-
fd_info[fd].sent = fd_info[fd].packet->length;
|
432
|
-
return 0;
|
433
|
-
} else {
|
434
|
-
packet->metadata.offset += i_read;
|
435
|
-
packet->metadata.internal_flag = 1;
|
436
|
-
}
|
437
|
-
}
|
438
|
-
// send the data
|
439
|
-
if (fd_info[fd].rw_hooks && fd_info[fd].rw_hooks->write)
|
440
|
-
sent = fd_info[fd].rw_hooks->write(
|
441
|
-
fd_info[fd].fduuid.uuid,
|
442
|
-
(void *)(((uintptr_t)(packet + 1)) + fd_info[fd].sent),
|
443
|
-
i_exp - fd_info[fd].sent);
|
444
|
-
else
|
445
|
-
sent = write(fd, (void *)(((uintptr_t)(packet + 1)) + fd_info[fd].sent),
|
446
|
-
i_exp - fd_info[fd].sent);
|
447
|
-
// review result and update packet data
|
448
|
-
if (sent < 0) {
|
449
|
-
if (ERR_OK)
|
450
|
-
return -1;
|
451
|
-
else if (ERR_TRY_AGAIN)
|
452
|
-
return 0;
|
453
|
-
else
|
454
|
-
return sock_flush_fd_failed(fd);
|
455
|
-
}
|
456
|
-
fd_info[fd].sent += sent;
|
457
|
-
if (fd_info[fd].sent >= i_exp) {
|
458
|
-
packet->metadata.internal_flag = 0;
|
459
|
-
fd_info[fd].sent = 0;
|
460
|
-
packet->length -= i_exp;
|
461
|
-
}
|
462
|
-
return 0;
|
463
|
-
}
|
464
|
-
|
465
|
-
static inline int sock_flush_data(int fd) {
|
466
|
-
ssize_t sent;
|
467
|
-
if (fd_info[fd].rw_hooks && fd_info[fd].rw_hooks->write)
|
468
|
-
sent = fd_info[fd].rw_hooks->write(
|
469
|
-
fd_info[fd].fduuid.uuid,
|
470
|
-
(void *)((uintptr_t)fd_info[fd].packet->buffer + fd_info[fd].sent),
|
471
|
-
fd_info[fd].packet->length - fd_info[fd].sent);
|
472
|
-
else
|
473
|
-
sent = write(
|
474
|
-
fd, (void *)((uintptr_t)fd_info[fd].packet->buffer + fd_info[fd].sent),
|
475
|
-
fd_info[fd].packet->length - fd_info[fd].sent);
|
476
|
-
if (sent < 0) {
|
477
|
-
if (ERR_OK)
|
478
|
-
return -1;
|
479
|
-
else if (ERR_TRY_AGAIN)
|
480
|
-
return 0;
|
481
|
-
else
|
482
|
-
return sock_flush_fd_failed(fd);
|
483
|
-
}
|
484
|
-
fd_info[fd].sent += sent;
|
485
|
-
return 0;
|
486
|
-
}
|
487
|
-
|
488
|
-
static void sock_flush_unsafe(int fd) {
|
489
|
-
while (fd_info[fd].packet) {
|
490
|
-
if (fd_info[fd].packet->metadata.is_fd == 0) {
|
491
|
-
if (sock_flush_data(fd))
|
492
|
-
return;
|
493
|
-
} else {
|
494
|
-
if (sock_flush_fd(fd))
|
495
|
-
return;
|
496
|
-
}
|
497
|
-
if (fd_info[fd].packet && fd_info[fd].packet->length <= fd_info[fd].sent) {
|
498
|
-
sock_packet_s *packet = fd_info[fd].packet;
|
499
|
-
fd_info[fd].packet = packet->metadata.next;
|
500
|
-
packet->metadata.next = NULL;
|
501
|
-
fd_info[fd].sent = 0;
|
502
|
-
sock_free_packet(packet);
|
503
|
-
}
|
504
|
-
}
|
505
|
-
}
|
506
|
-
|
507
|
-
#if SOCK_DELAY_WRITE == 1
|
508
|
-
|
509
|
-
static inline void sock_flush_schd(intptr_t uuid) {
|
510
|
-
if (async_run((void (*)(void *))sock_flush, (void *)uuid) == -1)
|
511
|
-
goto fallback;
|
512
|
-
return;
|
513
|
-
fallback:
|
514
|
-
sock_flush_unsafe(sock_uuid2fd(uuid));
|
515
|
-
}
|
516
|
-
|
517
|
-
#define _write_to_sock() sock_flush_schd(sfd->fduuid.uuid)
|
518
|
-
|
519
|
-
#else
|
520
|
-
|
521
|
-
#define _write_to_sock() sock_flush_unsafe(fd)
|
522
|
-
|
523
|
-
#endif
|
524
|
-
|
525
|
-
static inline void sock_send_packet_unsafe(int fd, sock_packet_s *packet) {
|
526
|
-
fd_info_s *sfd = fd_info + fd;
|
527
|
-
if (sfd->packet == NULL) {
|
528
|
-
/* no queue, nothing to check */
|
529
|
-
sfd->packet = packet;
|
530
|
-
_write_to_sock();
|
531
|
-
return;
|
532
|
-
|
533
|
-
} else if (packet->metadata.urgent == 0) {
|
534
|
-
/* not urgent, last in line */
|
535
|
-
sock_packet_s *pos = sfd->packet;
|
536
|
-
while (pos->metadata.next)
|
537
|
-
pos = pos->metadata.next;
|
538
|
-
pos->metadata.next = packet;
|
539
|
-
_write_to_sock();
|
540
|
-
return;
|
541
|
-
|
542
|
-
} else {
|
543
|
-
/* urgent, find a spot we can interrupt */
|
544
|
-
sock_packet_s **pos = &sfd->packet;
|
545
|
-
while (*pos && (*pos)->metadata.can_interrupt == 0)
|
546
|
-
pos = &(*pos)->metadata.next;
|
547
|
-
sock_packet_s *tail = *pos;
|
548
|
-
*pos = packet;
|
549
|
-
if (tail) {
|
550
|
-
pos = &packet->metadata.next;
|
551
|
-
while (*pos)
|
552
|
-
pos = &(*pos)->metadata.next;
|
553
|
-
*pos = tail;
|
554
|
-
}
|
555
|
-
}
|
556
|
-
_write_to_sock();
|
557
|
-
}
|
558
|
-
|
559
|
-
/* *****************************************************************************
|
560
|
-
Listen
|
561
|
-
*/
|
562
|
-
|
563
|
-
/**
|
564
|
-
Opens a listening non-blocking socket. Return's the socket's UUID.
|
565
|
-
*/
|
566
|
-
intptr_t sock_listen(const char *address, const char *port) {
|
567
|
-
review_lib();
|
568
|
-
int srvfd;
|
569
|
-
// setup the address
|
570
|
-
struct addrinfo hints;
|
571
|
-
struct addrinfo *servinfo; // will point to the results
|
572
|
-
memset(&hints, 0, sizeof hints); // make sure the struct is empty
|
573
|
-
hints.ai_family = AF_UNSPEC; // don't care IPv4 or IPv6
|
574
|
-
hints.ai_socktype = SOCK_STREAM; // TCP stream sockets
|
575
|
-
hints.ai_flags = AI_PASSIVE; // fill in my IP for me
|
576
|
-
if (getaddrinfo(address, port, &hints, &servinfo)) {
|
577
|
-
// perror("addr err");
|
578
|
-
return -1;
|
579
|
-
}
|
580
|
-
// get the file descriptor
|
581
|
-
srvfd =
|
582
|
-
socket(servinfo->ai_family, servinfo->ai_socktype, servinfo->ai_protocol);
|
583
|
-
if (srvfd <= 0) {
|
584
|
-
// perror("socket err");
|
585
|
-
freeaddrinfo(servinfo);
|
586
|
-
return -1;
|
587
|
-
}
|
588
|
-
// make sure the socket is non-blocking
|
589
|
-
if (sock_set_non_block(srvfd) < 0) {
|
590
|
-
// perror("couldn't set socket as non blocking! ");
|
591
|
-
freeaddrinfo(servinfo);
|
592
|
-
close(srvfd);
|
593
|
-
return -1;
|
594
|
-
}
|
595
|
-
// avoid the "address taken"
|
596
|
-
{
|
597
|
-
int optval = 1;
|
598
|
-
setsockopt(srvfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
|
599
|
-
}
|
600
|
-
// bind the address to the socket
|
601
|
-
{
|
602
|
-
int bound = 0;
|
603
|
-
for (struct addrinfo *p = servinfo; p != NULL; p = p->ai_next) {
|
604
|
-
if (!bind(srvfd, p->ai_addr, p->ai_addrlen))
|
605
|
-
bound = 1;
|
606
|
-
}
|
607
|
-
|
608
|
-
if (!bound) {
|
609
|
-
// perror("bind err");
|
610
|
-
freeaddrinfo(servinfo);
|
611
|
-
close(srvfd);
|
612
|
-
return -1;
|
613
|
-
}
|
614
|
-
}
|
615
|
-
freeaddrinfo(servinfo);
|
616
|
-
// listen in
|
617
|
-
if (listen(srvfd, SOMAXCONN) < 0) {
|
618
|
-
// perror("couldn't start listening");
|
619
|
-
close(srvfd);
|
620
|
-
return -1;
|
621
|
-
}
|
622
|
-
set_fd(srvfd, LIB_SOCK_STATE_OPEN);
|
623
|
-
return fd_info[srvfd].fduuid.uuid;
|
624
|
-
}
|
625
|
-
|
626
|
-
/* *****************************************************************************
|
627
|
-
Accept
|
628
|
-
*/
|
629
|
-
|
630
|
-
intptr_t sock_accept(intptr_t srv_uuid) {
|
631
|
-
review_lib();
|
632
|
-
static socklen_t cl_addrlen = 0;
|
633
|
-
int client;
|
634
|
-
#ifdef SOCK_NONBLOCK
|
635
|
-
client = accept4(sock_uuid2fd(srv_uuid), NULL, &cl_addrlen, SOCK_NONBLOCK);
|
636
|
-
if (client <= 0)
|
637
|
-
return -1;
|
638
|
-
#else
|
639
|
-
client = accept(sock_uuid2fd(srv_uuid), NULL, &cl_addrlen);
|
640
|
-
if (client <= 0)
|
641
|
-
return -1;
|
642
|
-
sock_set_non_block(client);
|
643
|
-
#endif
|
644
|
-
set_fd(client, LIB_SOCK_STATE_OPEN);
|
645
|
-
return fd_info[client].fduuid.uuid;
|
646
|
-
}
|
647
|
-
|
648
|
-
/* *****************************************************************************
|
649
|
-
Connect
|
650
|
-
*/
|
651
|
-
intptr_t sock_connect(char *address, char *port) {
|
652
|
-
review_lib();
|
653
|
-
int fd;
|
654
|
-
// setup the address
|
655
|
-
struct addrinfo hints;
|
656
|
-
struct addrinfo *addrinfo; // will point to the results
|
657
|
-
memset(&hints, 0, sizeof hints); // make sure the struct is empty
|
658
|
-
hints.ai_family = AF_UNSPEC; // don't care IPv4 or IPv6
|
659
|
-
hints.ai_socktype = SOCK_STREAM; // TCP stream sockets
|
660
|
-
hints.ai_flags = AI_PASSIVE; // fill in my IP for me
|
661
|
-
if (getaddrinfo(address, port, &hints, &addrinfo)) {
|
662
|
-
return -1;
|
663
|
-
}
|
664
|
-
// get the file descriptor
|
665
|
-
fd =
|
666
|
-
socket(addrinfo->ai_family, addrinfo->ai_socktype, addrinfo->ai_protocol);
|
667
|
-
if (fd <= 0) {
|
668
|
-
freeaddrinfo(addrinfo);
|
669
|
-
return -1;
|
670
|
-
}
|
671
|
-
// make sure the socket is non-blocking
|
672
|
-
if (sock_set_non_block(fd) < 0) {
|
673
|
-
freeaddrinfo(addrinfo);
|
674
|
-
close(fd);
|
675
|
-
return -1;
|
676
|
-
}
|
677
|
-
|
678
|
-
if (connect(fd, addrinfo->ai_addr, addrinfo->ai_addrlen) < 0 &&
|
679
|
-
errno != EINPROGRESS) {
|
680
|
-
close(fd);
|
681
|
-
freeaddrinfo(addrinfo);
|
682
|
-
return -1;
|
683
|
-
}
|
684
|
-
freeaddrinfo(addrinfo);
|
685
|
-
set_fd(fd, LIB_SOCK_STATE_OPEN);
|
686
|
-
return fd_info[fd].fduuid.uuid;
|
687
|
-
}
|
688
|
-
|
689
|
-
/* *****************************************************************************
|
690
|
-
Open existing
|
691
|
-
*/
|
692
|
-
|
693
|
-
intptr_t sock_open(int fd) {
|
694
|
-
review_lib();
|
695
|
-
set_fd(fd, LIB_SOCK_STATE_OPEN);
|
696
|
-
return fd_info[fd].fduuid.uuid;
|
697
|
-
}
|
698
|
-
|
699
|
-
/* *****************************************************************************
|
700
|
-
Information about the socket
|
701
|
-
*/
|
702
|
-
|
703
|
-
/**
|
704
|
-
Returns 1 if the uuid refers to a valid and open, socket.
|
705
|
-
|
706
|
-
Returns 0 if not.
|
707
|
-
*/
|
708
|
-
int sock_isvalid(intptr_t uuid) { return fd_info && is_valid(uuid); }
|
709
|
-
|
710
|
-
/**
|
711
|
-
`sock_fd2uuid` takes an existing file decriptor `fd` and returns it's active
|
712
|
-
`uuid`.
|
713
|
-
*/
|
714
|
-
intptr_t sock_fd2uuid(int fd) {
|
715
|
-
return (fd_info && fd_info[fd].open) ? fd_info[fd].fduuid.uuid : -1;
|
716
|
-
}
|
717
|
-
|
718
|
-
/* *****************************************************************************
|
719
|
-
Buffer API.
|
720
|
-
*/
|
721
|
-
|
722
|
-
static inline sock_packet_s *sock_try_checkout_packet(void) {
|
723
|
-
sock_packet_s *packet;
|
724
|
-
spn_lock(&buffer_pool.lock);
|
725
|
-
packet = buffer_pool.pool;
|
726
|
-
if (packet) {
|
727
|
-
buffer_pool.pool = packet->metadata.next;
|
728
|
-
spn_unlock(&buffer_pool.lock);
|
729
|
-
*packet = (sock_packet_s){.buffer = packet + 1, .metadata.next = NULL};
|
730
|
-
return packet;
|
731
|
-
}
|
732
|
-
spn_unlock(&buffer_pool.lock);
|
733
|
-
return packet;
|
734
|
-
}
|
735
|
-
|
736
|
-
/**
|
737
|
-
Checks out a `sock_packet_s` from the packet pool, transfering the
|
738
|
-
ownership of the memory to the calling function. The function will hang until
|
739
|
-
a
|
740
|
-
packet becomes available, so never check out more then a single packet at a
|
741
|
-
time.
|
742
|
-
*/
|
743
|
-
sock_packet_s *sock_checkout_packet(void) {
|
744
|
-
review_lib();
|
745
|
-
sock_packet_s *packet = NULL;
|
746
|
-
for (;;) {
|
747
|
-
spn_lock(&buffer_pool.lock);
|
748
|
-
packet = buffer_pool.pool;
|
749
|
-
if (packet) {
|
750
|
-
buffer_pool.pool = packet->metadata.next;
|
751
|
-
spn_unlock(&buffer_pool.lock);
|
752
|
-
*packet = (sock_packet_s){
|
753
|
-
.buffer = packet + 1, .metadata.next = NULL, .metadata.dealloc = free,
|
754
|
-
};
|
755
|
-
return packet;
|
756
|
-
}
|
757
|
-
spn_unlock(&buffer_pool.lock);
|
758
|
-
reschedule_thread();
|
759
|
-
sock_flush_all();
|
760
|
-
}
|
761
|
-
}
|
762
|
-
/**
|
763
|
-
Attaches a packet to a socket's output buffer and calls `sock_flush` for the
|
764
|
-
socket.
|
765
|
-
*/
|
766
|
-
ssize_t sock_send_packet(intptr_t uuid, sock_packet_s *packet) {
|
767
|
-
if (!fd_info || !is_valid(uuid)) {
|
768
|
-
sock_free_packet(packet);
|
769
|
-
return -1;
|
770
|
-
}
|
771
|
-
spn_lock(&uuid2info(uuid).lock);
|
772
|
-
sock_send_packet_unsafe(sock_uuid2fd(uuid), packet);
|
773
|
-
spn_unlock(&uuid2info(uuid).lock);
|
774
|
-
return 0;
|
775
|
-
}
|
776
|
-
|
777
|
-
/**
|
778
|
-
Returns TRUE (non 0) if there is data waiting to be written to the socket in
|
779
|
-
the
|
780
|
-
user-land buffer.
|
781
|
-
*/
|
782
|
-
int sock_packets_pending(intptr_t uuid) {
|
783
|
-
return fd_info && uuid2info(uuid).packet != NULL;
|
784
|
-
}
|
785
|
-
|
786
|
-
/**
|
787
|
-
Use `sock_free_packet` to free unused packets that were checked-out using
|
788
|
-
`sock_checkout_packet`.
|
789
|
-
*/
|
790
|
-
void sock_free_packet(sock_packet_s *packet) {
|
791
|
-
sock_packet_s *next = packet;
|
792
|
-
if (packet == NULL)
|
793
|
-
return;
|
794
|
-
for (;;) {
|
795
|
-
if (next->metadata.is_fd) {
|
796
|
-
if (next->metadata.keep_open == 0)
|
797
|
-
close((int)((ssize_t)next->buffer));
|
798
|
-
} else if (next->metadata.external)
|
799
|
-
next->metadata.dealloc(next->buffer);
|
800
|
-
if (next->metadata.next == NULL)
|
801
|
-
break; /* next will hold the last packet in the chain. */
|
802
|
-
next = next->metadata.next;
|
803
|
-
}
|
804
|
-
spn_lock(&buffer_pool.lock);
|
805
|
-
next->metadata.next = buffer_pool.pool;
|
806
|
-
buffer_pool.pool = packet;
|
807
|
-
spn_unlock(&buffer_pool.lock);
|
808
|
-
}
|
809
|
-
|
810
|
-
/* *****************************************************************************
|
811
|
-
Reading
|
812
|
-
*/
|
813
|
-
ssize_t sock_read(intptr_t uuid, void *buf, size_t count) {
|
814
|
-
if (!fd_info || !is_valid(uuid)) {
|
815
|
-
errno = ENODEV;
|
816
|
-
return -1;
|
817
|
-
}
|
818
|
-
ssize_t i_read;
|
819
|
-
fd_info_s *sfd = fd_info + sock_uuid2fd(uuid);
|
820
|
-
if (sfd->rw_hooks && sfd->rw_hooks->read)
|
821
|
-
i_read = sfd->rw_hooks->read(uuid, buf, count);
|
822
|
-
else
|
823
|
-
i_read = read(sock_uuid2fd(uuid), buf, count);
|
824
|
-
|
825
|
-
if (i_read > 0) {
|
826
|
-
sock_touch(uuid);
|
827
|
-
return i_read;
|
828
|
-
}
|
829
|
-
if (i_read == -1 && (ERR_OK || ERR_TRY_AGAIN))
|
830
|
-
return 0;
|
831
|
-
// fprintf(stderr, "Read Error for %lu bytes from fd %d (closing))\n",
|
832
|
-
// count,
|
833
|
-
// sock_uuid2fd(uuid));
|
834
|
-
sock_close(uuid);
|
835
|
-
return -1;
|
836
|
-
}
|
837
|
-
|
838
|
-
/* *****************************************************************************
|
839
|
-
Flushing
|
840
|
-
*/
|
841
|
-
|
842
|
-
ssize_t sock_flush(intptr_t uuid) {
|
843
|
-
if (!fd_info || !is_valid(uuid))
|
844
|
-
return -1;
|
845
|
-
if (uuid2info(uuid).packet == NULL)
|
846
|
-
goto no_packet;
|
847
|
-
spn_lock(&uuid2info(uuid).lock);
|
848
|
-
sock_flush_unsafe(sock_uuid2fd(uuid));
|
849
|
-
spn_unlock(&uuid2info(uuid).lock);
|
850
|
-
no_packet:
|
851
|
-
if (uuid2info(uuid).close) {
|
852
|
-
sock_force_close(uuid);
|
853
|
-
return -1;
|
854
|
-
}
|
855
|
-
return 0;
|
856
|
-
}
|
857
|
-
/**
|
858
|
-
`sock_flush_strong` performs the same action as `sock_flush` but returns only
|
859
|
-
after all the data was sent. This is an "active" wait, polling isn't
|
860
|
-
performed.
|
861
|
-
*/
|
862
|
-
void sock_flush_strong(intptr_t uuid) {
|
863
|
-
if (!fd_info)
|
864
|
-
return;
|
865
|
-
while (is_valid(uuid) && uuid2info(uuid).packet)
|
866
|
-
sock_flush(uuid);
|
867
|
-
}
|
868
|
-
/**
|
869
|
-
Calls `sock_flush` for each file descriptor that's buffer isn't empty.
|
870
|
-
*/
|
871
|
-
void sock_flush_all(void) {
|
872
|
-
for (size_t i = 0; i < fd_capacity; i++) {
|
873
|
-
if (fd_info[i].packet == NULL || spn_is_locked(&fd_info[i].lock))
|
874
|
-
continue;
|
875
|
-
sock_flush(fd_info[i].fduuid.uuid);
|
876
|
-
}
|
877
|
-
}
|
878
|
-
|
879
|
-
/* *****************************************************************************
|
880
|
-
Writing
|
881
|
-
*/
|
882
|
-
|
883
|
-
ssize_t sock_write2_fn(sock_write_info_s options) {
|
884
|
-
if (!fd_info || !is_valid(options.fduuid)) {
|
885
|
-
errno = ENODEV;
|
886
|
-
return -1;
|
887
|
-
}
|
888
|
-
if (options.buffer == NULL)
|
889
|
-
return -1;
|
890
|
-
if (!options.length && !options.is_fd)
|
891
|
-
options.length = strlen(options.buffer);
|
892
|
-
if (options.length == 0)
|
893
|
-
return -1;
|
894
|
-
sock_packet_s *packet = sock_checkout_packet();
|
895
|
-
packet->metadata.can_interrupt = 1;
|
896
|
-
packet->metadata.urgent = options.urgent;
|
897
|
-
|
898
|
-
if (options.is_fd) {
|
899
|
-
packet->buffer = (void *)options.buffer;
|
900
|
-
packet->length = options.length;
|
901
|
-
packet->metadata.is_fd = options.is_fd;
|
902
|
-
packet->metadata.offset = options.offset;
|
903
|
-
return sock_send_packet(options.fduuid, packet);
|
904
|
-
} else {
|
905
|
-
if (options.move) {
|
906
|
-
packet->buffer = (void *)options.buffer;
|
907
|
-
packet->length = options.length;
|
908
|
-
packet->metadata.external = 1;
|
909
|
-
return sock_send_packet(options.fduuid, packet);
|
910
|
-
} else {
|
911
|
-
if (options.length <= BUFFER_PACKET_SIZE) {
|
912
|
-
memcpy(packet->buffer, options.buffer, options.length);
|
913
|
-
packet->length = options.length;
|
914
|
-
return sock_send_packet(options.fduuid, packet);
|
915
|
-
} else {
|
916
|
-
if (packet->metadata.urgent) {
|
917
|
-
fprintf(stderr, "Socket err:"
|
918
|
-
"Large data cannot be sent as an urgent packet.\n"
|
919
|
-
"Urgency silently ignored\n");
|
920
|
-
packet->metadata.urgent = 0;
|
921
|
-
}
|
922
|
-
size_t to_cpy;
|
923
|
-
spn_lock(&uuid2info(options.fduuid).lock);
|
924
|
-
for (;;) {
|
925
|
-
to_cpy = options.length > BUFFER_PACKET_SIZE ? BUFFER_PACKET_SIZE
|
926
|
-
: options.length;
|
927
|
-
memcpy(packet->buffer, options.buffer, to_cpy);
|
928
|
-
packet->length = to_cpy;
|
929
|
-
options.length -= to_cpy;
|
930
|
-
options.buffer = (void *)((uintptr_t)options.buffer + to_cpy);
|
931
|
-
sock_send_packet_unsafe(sock_uuid2fd(options.fduuid), packet);
|
932
|
-
if (!is_valid(options.fduuid) || uuid2info(options.fduuid).err == 1 ||
|
933
|
-
options.length == 0)
|
934
|
-
break;
|
935
|
-
packet = sock_try_checkout_packet();
|
936
|
-
while (packet == NULL) {
|
937
|
-
sock_flush_all();
|
938
|
-
sock_flush_unsafe(sock_uuid2fd(options.fduuid));
|
939
|
-
packet = sock_try_checkout_packet();
|
940
|
-
}
|
941
|
-
}
|
942
|
-
spn_unlock(&uuid2info(options.fduuid).lock);
|
943
|
-
if (uuid2info(options.fduuid).packet == NULL &&
|
944
|
-
uuid2info(options.fduuid).close) {
|
945
|
-
sock_force_close(options.fduuid);
|
946
|
-
return -1;
|
947
|
-
}
|
948
|
-
return is_valid(options.fduuid) ? 0 : -1;
|
949
|
-
}
|
950
|
-
}
|
951
|
-
}
|
952
|
-
// how did we get here?
|
953
|
-
return -1;
|
954
|
-
}
|
955
|
-
|
956
|
-
/* *****************************************************************************
|
957
|
-
Closing.
|
958
|
-
*/
|
959
|
-
|
960
|
-
void sock_close(intptr_t uuid) {
|
961
|
-
// fprintf(stderr, "called sock_close for %lu (%d)\n", uuid,
|
962
|
-
// sock_uuid2fd(uuid));
|
963
|
-
if (!fd_info || !is_valid(uuid))
|
964
|
-
return;
|
965
|
-
fd_info[sock_uuid2fd(uuid)].close = 1;
|
966
|
-
sock_flush(uuid);
|
967
|
-
}
|
968
|
-
|
969
|
-
void sock_force_close(intptr_t uuid) {
|
970
|
-
// fprintf(stderr, "called sock_force_close for %lu (%d)\n", uuid,
|
971
|
-
// sock_uuid2fd(uuid));
|
972
|
-
if (!fd_info || !is_valid(uuid))
|
973
|
-
return;
|
974
|
-
shutdown(sock_uuid2fd(uuid), SHUT_RDWR);
|
975
|
-
close(sock_uuid2fd(uuid));
|
976
|
-
set_fd(sock_uuid2fd(uuid), LIB_SOCK_STATE_CLOSED);
|
977
|
-
}
|
978
|
-
|
979
|
-
/* *****************************************************************************
|
980
|
-
RW hooks implementation
|
981
|
-
*/
|
982
|
-
|
983
|
-
/** Gets a socket hook state (a pointer to the struct). */
|
984
|
-
struct sock_rw_hook_s *sock_rw_hook_get(intptr_t uuid) {
|
985
|
-
if (!fd_info || !is_valid(uuid))
|
986
|
-
return NULL;
|
987
|
-
return uuid2info(uuid).rw_hooks;
|
988
|
-
}
|
989
|
-
|
990
|
-
/** Sets a socket hook state (a pointer to the struct). */
|
991
|
-
int sock_rw_hook_set(intptr_t uuid, sock_rw_hook_s *rw_hooks) {
|
992
|
-
if (!fd_info || !is_valid(uuid))
|
993
|
-
return -1;
|
994
|
-
spn_lock(&(uuid2info(uuid).lock));
|
995
|
-
uuid2info(uuid).rw_hooks = rw_hooks;
|
996
|
-
spn_unlock(&uuid2info(uuid).lock);
|
997
|
-
return 0;
|
998
|
-
}
|
999
|
-
|
1000
|
-
/* *****************************************************************************
|
1001
|
-
test
|
1002
|
-
*/
|
1003
|
-
#ifdef DEBUG
|
1004
|
-
void sock_libtest(void) {
|
1005
|
-
sock_lib_init();
|
1006
|
-
sock_packet_s *p, *pl;
|
1007
|
-
size_t count = 0;
|
1008
|
-
fprintf(stderr, "Testing packet pool\n");
|
1009
|
-
for (size_t i = 0; i < BUFFER_PACKET_POOL * 2; i++) {
|
1010
|
-
count = 1;
|
1011
|
-
pl = p = sock_checkout_packet();
|
1012
|
-
while (buffer_pool.pool) {
|
1013
|
-
count++;
|
1014
|
-
pl->metadata.next = sock_checkout_packet();
|
1015
|
-
pl = pl->metadata.next;
|
1016
|
-
}
|
1017
|
-
sock_free_packet(p);
|
1018
|
-
// fprintf(stderr, "Collected and freed %lu packets.\n", count);
|
1019
|
-
}
|
1020
|
-
fprintf(stderr,
|
1021
|
-
"liniar (no-contention) packet checkout + free shows %lu packets. "
|
1022
|
-
"test %s\n",
|
1023
|
-
count, count == BUFFER_PACKET_POOL ? "passed." : "FAILED!");
|
1024
|
-
}
|
1025
|
-
#endif
|