| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Hypersonic::Socket; |
|
2
|
|
|
|
|
|
|
|
|
3
|
41
|
|
|
41
|
|
594716
|
use strict; |
|
|
41
|
|
|
|
|
58
|
|
|
|
41
|
|
|
|
|
1300
|
|
|
4
|
41
|
|
|
41
|
|
255
|
use warnings; |
|
|
41
|
|
|
|
|
69
|
|
|
|
41
|
|
|
|
|
1788
|
|
|
5
|
41
|
|
|
41
|
|
630
|
use 5.010; |
|
|
41
|
|
|
|
|
107
|
|
|
6
|
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
our $VERSION = '0.15'; |
|
8
|
|
|
|
|
|
|
|
|
9
|
41
|
|
|
41
|
|
2217
|
use XS::JIT; |
|
|
41
|
|
|
|
|
4894
|
|
|
|
41
|
|
|
|
|
928
|
|
|
10
|
41
|
|
|
41
|
|
2964
|
use XS::JIT::Builder; |
|
|
41
|
|
|
|
|
7115
|
|
|
|
41
|
|
|
|
|
1744
|
|
|
11
|
41
|
|
|
41
|
|
17646
|
use Hypersonic::JIT::Util; |
|
|
41
|
|
|
|
|
90
|
|
|
|
41
|
|
|
|
|
36068
|
|
|
12
|
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
# Platform detection |
|
14
|
|
|
|
|
|
|
sub platform { |
|
15
|
7
|
50
|
|
7
|
1
|
384712
|
return 'darwin' if $^O eq 'darwin'; |
|
16
|
7
|
50
|
|
|
|
37
|
return 'linux' if $^O eq 'linux'; |
|
17
|
0
|
0
|
|
|
|
0
|
return 'freebsd' if $^O eq 'freebsd'; |
|
18
|
0
|
0
|
|
|
|
0
|
return 'openbsd' if $^O eq 'openbsd'; |
|
19
|
0
|
0
|
|
|
|
0
|
return 'netbsd' if $^O eq 'netbsd'; |
|
20
|
0
|
0
|
|
|
|
0
|
return 'mswin32' if $^O eq 'MSWin32'; |
|
21
|
0
|
0
|
|
|
|
0
|
return 'cygwin' if $^O eq 'cygwin'; |
|
22
|
0
|
|
|
|
|
0
|
die "Unsupported platform: $^O"; |
|
23
|
|
|
|
|
|
|
} |
|
24
|
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
# Event backend detection (delegates to Hypersonic::Event) |
|
26
|
|
|
|
|
|
|
sub event_backend { |
|
27
|
1
|
|
|
1
|
0
|
694
|
require Hypersonic::Event; |
|
28
|
1
|
|
|
|
|
7
|
return Hypersonic::Event->best_backend(); |
|
29
|
|
|
|
|
|
|
} |
|
30
|
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
my $COMPILED = 0; |
|
32
|
|
|
|
|
|
|
my $MODULE_ID = 0; |
|
33
|
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
# Unified compile interface |
|
35
|
|
|
|
|
|
|
sub compile { |
|
36
|
0
|
|
|
0
|
0
|
0
|
my ($class, %opts) = @_; |
|
37
|
0
|
|
|
|
|
0
|
return $class->compile_socket_ops(%opts); |
|
38
|
|
|
|
|
|
|
} |
|
39
|
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
# Generate and compile JIT socket functions using Builder |
|
41
|
|
|
|
|
|
|
sub compile_socket_ops { |
|
42
|
42
|
|
|
42
|
1
|
95
|
my ($class, %opts) = @_; |
|
43
|
|
|
|
|
|
|
|
|
44
|
42
|
100
|
|
|
|
173
|
return 1 if $COMPILED; |
|
45
|
|
|
|
|
|
|
|
|
46
|
41
|
|
50
|
|
|
215
|
my $cache_dir = $opts{cache_dir} // '_hypersonic_cache/socket'; |
|
47
|
41
|
|
|
|
|
139
|
my $module_name = 'Hypersonic::Socket::Ops_' . $MODULE_ID++; |
|
48
|
|
|
|
|
|
|
|
|
49
|
41
|
|
|
|
|
357
|
my $builder = XS::JIT::Builder->new; |
|
50
|
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
# Common includes via centralized utility |
|
52
|
41
|
|
|
|
|
170
|
Hypersonic::JIT::Util->add_standard_includes($builder, |
|
53
|
|
|
|
|
|
|
qw(stdio unistd fcntl socket)); |
|
54
|
|
|
|
|
|
|
|
|
55
|
41
|
|
|
|
|
188
|
$builder->line('#define RECV_BUF_SIZE 65536') |
|
56
|
|
|
|
|
|
|
->blank |
|
57
|
|
|
|
|
|
|
->line('static char recv_buf[RECV_BUF_SIZE];') |
|
58
|
|
|
|
|
|
|
->blank; |
|
59
|
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
# Windows: WSAStartup must run before any socket call. We don't |
|
61
|
|
|
|
|
|
|
# have a BOOT hook in the JIT module, so guard with a static flag |
|
62
|
|
|
|
|
|
|
# and call it from create_listen_socket (the first entrypoint |
|
63
|
|
|
|
|
|
|
# users hit). socket() requires Winsock to be initialized; otherwise |
|
64
|
|
|
|
|
|
|
# it returns INVALID_SOCKET with WSANOTINITIALISED. |
|
65
|
41
|
|
|
|
|
122
|
$builder->raw(<<'C'); |
|
66
|
|
|
|
|
|
|
#ifdef _WIN32 |
|
67
|
|
|
|
|
|
|
static int hs_wsa_initialized = 0; |
|
68
|
|
|
|
|
|
|
static void hs_wsa_init(void) { |
|
69
|
|
|
|
|
|
|
if (!hs_wsa_initialized) { |
|
70
|
|
|
|
|
|
|
WSADATA wsa; |
|
71
|
|
|
|
|
|
|
if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0) { |
|
72
|
|
|
|
|
|
|
return; /* leave flag unset; create_listen_socket will croak */ |
|
73
|
|
|
|
|
|
|
} |
|
74
|
|
|
|
|
|
|
hs_wsa_initialized = 1; |
|
75
|
|
|
|
|
|
|
} |
|
76
|
|
|
|
|
|
|
} |
|
77
|
|
|
|
|
|
|
#else |
|
78
|
|
|
|
|
|
|
static inline void hs_wsa_init(void) {} |
|
79
|
|
|
|
|
|
|
#endif |
|
80
|
|
|
|
|
|
|
C |
|
81
|
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
# Generate create_listen_socket |
|
83
|
41
|
|
|
|
|
12871
|
$builder->xs_function('jit_create_listen_socket') |
|
84
|
|
|
|
|
|
|
->xs_preamble |
|
85
|
|
|
|
|
|
|
->line('IV port;') |
|
86
|
|
|
|
|
|
|
->line('int fd;') |
|
87
|
|
|
|
|
|
|
->line('int opt;') |
|
88
|
|
|
|
|
|
|
->line('struct sockaddr_in addr;') |
|
89
|
|
|
|
|
|
|
->blank |
|
90
|
|
|
|
|
|
|
->line('if (items != 1) croak("Usage: create_listen_socket(port)");') |
|
91
|
|
|
|
|
|
|
->line('port = SvIV(ST(0));') |
|
92
|
|
|
|
|
|
|
->blank |
|
93
|
|
|
|
|
|
|
->line('hs_wsa_init(); /* no-op on POSIX */') |
|
94
|
|
|
|
|
|
|
->line('fd = socket(AF_INET, SOCK_STREAM, 0);') |
|
95
|
|
|
|
|
|
|
->if('fd < 0') |
|
96
|
|
|
|
|
|
|
# Surface the actual errno - returning silent -1 hides why the |
|
97
|
|
|
|
|
|
|
# child server died on platforms where bind/listen/socket fail |
|
98
|
|
|
|
|
|
|
# for non-obvious reasons (see OpenBSD smoke reports). |
|
99
|
|
|
|
|
|
|
->line('croak("socket() failed: %s", strerror(errno));') |
|
100
|
|
|
|
|
|
|
->endif |
|
101
|
|
|
|
|
|
|
->blank |
|
102
|
|
|
|
|
|
|
->line('opt = 1;') |
|
103
|
|
|
|
|
|
|
->line('setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char*)&opt, sizeof(opt));') |
|
104
|
|
|
|
|
|
|
->line('#ifdef SO_REUSEPORT') |
|
105
|
|
|
|
|
|
|
->line('setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (const char*)&opt, sizeof(opt));') |
|
106
|
|
|
|
|
|
|
->line('#endif') |
|
107
|
|
|
|
|
|
|
->blank |
|
108
|
|
|
|
|
|
|
->line('hs_set_nonblocking(fd);') |
|
109
|
|
|
|
|
|
|
->blank |
|
110
|
|
|
|
|
|
|
->line('memset(&addr, 0, sizeof(addr));') |
|
111
|
|
|
|
|
|
|
->line('addr.sin_family = AF_INET;') |
|
112
|
|
|
|
|
|
|
->line('addr.sin_port = htons((uint16_t)port);') |
|
113
|
|
|
|
|
|
|
->line('addr.sin_addr.s_addr = INADDR_ANY;') |
|
114
|
|
|
|
|
|
|
->blank |
|
115
|
|
|
|
|
|
|
->if('bind(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0') |
|
116
|
|
|
|
|
|
|
->line('int saved_errno = errno;') |
|
117
|
|
|
|
|
|
|
->line('close(fd);') |
|
118
|
|
|
|
|
|
|
->line('croak("bind(port=%d) failed: %s", (int)port, strerror(saved_errno));') |
|
119
|
|
|
|
|
|
|
->endif |
|
120
|
|
|
|
|
|
|
->blank |
|
121
|
|
|
|
|
|
|
->if('listen(fd, SOMAXCONN) < 0') |
|
122
|
|
|
|
|
|
|
->line('int saved_errno = errno;') |
|
123
|
|
|
|
|
|
|
->line('close(fd);') |
|
124
|
|
|
|
|
|
|
->line('croak("listen() failed: %s", strerror(saved_errno));') |
|
125
|
|
|
|
|
|
|
->endif |
|
126
|
|
|
|
|
|
|
->blank |
|
127
|
|
|
|
|
|
|
->line('ST(0) = sv_2mortal(newSViv(fd));') |
|
128
|
|
|
|
|
|
|
->xs_return('1') |
|
129
|
|
|
|
|
|
|
->xs_end; |
|
130
|
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
# Event loop functions (create_event_loop, event_add, event_del, ev_poll) |
|
132
|
|
|
|
|
|
|
# have been moved to Hypersonic::Event::* backend modules |
|
133
|
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
# Generate http_accept |
|
135
|
41
|
|
|
|
|
1063
|
$builder->xs_function('jit_http_accept') |
|
136
|
|
|
|
|
|
|
->xs_preamble |
|
137
|
|
|
|
|
|
|
->line('if (items != 1) croak("Usage: http_accept(listen_fd)");') |
|
138
|
|
|
|
|
|
|
->line('IV listen_fd = SvIV(ST(0));') |
|
139
|
|
|
|
|
|
|
->blank |
|
140
|
|
|
|
|
|
|
->line('struct sockaddr_in client_addr;') |
|
141
|
|
|
|
|
|
|
->line('socklen_t client_len = sizeof(client_addr);') |
|
142
|
|
|
|
|
|
|
->blank |
|
143
|
|
|
|
|
|
|
->line('int client_fd = accept((int)listen_fd, (struct sockaddr*)&client_addr, &client_len);') |
|
144
|
|
|
|
|
|
|
->blank |
|
145
|
|
|
|
|
|
|
->if('client_fd < 0') |
|
146
|
|
|
|
|
|
|
->line('ST(0) = sv_2mortal(newSViv(-1));') |
|
147
|
|
|
|
|
|
|
->line('XSRETURN(1);') |
|
148
|
|
|
|
|
|
|
->endif |
|
149
|
|
|
|
|
|
|
->blank |
|
150
|
|
|
|
|
|
|
->line('int flags = fcntl(client_fd, F_GETFL, 0);') |
|
151
|
|
|
|
|
|
|
->line('fcntl(client_fd, F_SETFL, flags | O_NONBLOCK);') |
|
152
|
|
|
|
|
|
|
->blank |
|
153
|
|
|
|
|
|
|
->line('ST(0) = sv_2mortal(newSViv(client_fd));') |
|
154
|
|
|
|
|
|
|
->xs_return('1') |
|
155
|
|
|
|
|
|
|
->xs_end; |
|
156
|
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
# Generate http_recv - zero-copy HTTP parsing |
|
158
|
41
|
|
|
|
|
3826
|
$builder->xs_function('jit_http_recv') |
|
159
|
|
|
|
|
|
|
->xs_preamble |
|
160
|
|
|
|
|
|
|
->line('if (items != 1) croak("Usage: http_recv(fd)");') |
|
161
|
|
|
|
|
|
|
->line('IV fd = SvIV(ST(0));') |
|
162
|
|
|
|
|
|
|
->blank |
|
163
|
|
|
|
|
|
|
->line('ssize_t len = recv((int)fd, recv_buf, RECV_BUF_SIZE - 1, 0);') |
|
164
|
|
|
|
|
|
|
->blank |
|
165
|
|
|
|
|
|
|
->if('len <= 0') |
|
166
|
|
|
|
|
|
|
->line('ST(0) = &PL_sv_undef;') |
|
167
|
|
|
|
|
|
|
->line('XSRETURN(1);') |
|
168
|
|
|
|
|
|
|
->endif |
|
169
|
|
|
|
|
|
|
->blank |
|
170
|
|
|
|
|
|
|
->line('recv_buf[len] = \'\\0\';') |
|
171
|
|
|
|
|
|
|
->blank |
|
172
|
|
|
|
|
|
|
->comment('Quick parse - extract method, path, detect keep-alive') |
|
173
|
|
|
|
|
|
|
->line('const char* p = recv_buf;') |
|
174
|
|
|
|
|
|
|
->line('const char* end = recv_buf + len;') |
|
175
|
|
|
|
|
|
|
->blank |
|
176
|
|
|
|
|
|
|
->comment('Method') |
|
177
|
|
|
|
|
|
|
->line('const char* method = p;') |
|
178
|
|
|
|
|
|
|
->line('while (p < end && *p != \' \') p++;') |
|
179
|
|
|
|
|
|
|
->line('int method_len = p - method;') |
|
180
|
|
|
|
|
|
|
->if('p >= end') |
|
181
|
|
|
|
|
|
|
->line('ST(0) = &PL_sv_undef;') |
|
182
|
|
|
|
|
|
|
->line('XSRETURN(1);') |
|
183
|
|
|
|
|
|
|
->endif |
|
184
|
|
|
|
|
|
|
->line('p++;') |
|
185
|
|
|
|
|
|
|
->blank |
|
186
|
|
|
|
|
|
|
->comment('Path') |
|
187
|
|
|
|
|
|
|
->line('const char* path = p;') |
|
188
|
|
|
|
|
|
|
->line('while (p < end && *p != \' \' && *p != \'?\') p++;') |
|
189
|
|
|
|
|
|
|
->line('int path_len = p - path;') |
|
190
|
|
|
|
|
|
|
->if('p >= end') |
|
191
|
|
|
|
|
|
|
->line('ST(0) = &PL_sv_undef;') |
|
192
|
|
|
|
|
|
|
->line('XSRETURN(1);') |
|
193
|
|
|
|
|
|
|
->endif |
|
194
|
|
|
|
|
|
|
->blank |
|
195
|
|
|
|
|
|
|
->comment('Skip to end of request line') |
|
196
|
|
|
|
|
|
|
->line('while (p < end && *p != \'\\n\') p++;') |
|
197
|
|
|
|
|
|
|
->if('p >= end') |
|
198
|
|
|
|
|
|
|
->line('ST(0) = &PL_sv_undef;') |
|
199
|
|
|
|
|
|
|
->line('XSRETURN(1);') |
|
200
|
|
|
|
|
|
|
->endif |
|
201
|
|
|
|
|
|
|
->line('p++;') |
|
202
|
|
|
|
|
|
|
->blank |
|
203
|
|
|
|
|
|
|
->comment('Check for Connection: close') |
|
204
|
|
|
|
|
|
|
->line('int keep_alive = 1;') |
|
205
|
|
|
|
|
|
|
->line('while (p < end) {') |
|
206
|
|
|
|
|
|
|
->line(' if (*p == \'\\r\' || *p == \'\\n\') break;') |
|
207
|
|
|
|
|
|
|
->line(' if (end - p > 17 && strncasecmp(p, "Connection: close", 17) == 0) {') |
|
208
|
|
|
|
|
|
|
->line(' keep_alive = 0;') |
|
209
|
|
|
|
|
|
|
->line(' }') |
|
210
|
|
|
|
|
|
|
->line(' while (p < end && *p != \'\\n\') p++;') |
|
211
|
|
|
|
|
|
|
->line(' if (p < end) p++;') |
|
212
|
|
|
|
|
|
|
->line('}') |
|
213
|
|
|
|
|
|
|
->blank |
|
214
|
|
|
|
|
|
|
->comment('Skip blank line') |
|
215
|
|
|
|
|
|
|
->line('if (p < end && *p == \'\\r\') p++;') |
|
216
|
|
|
|
|
|
|
->line('if (p < end && *p == \'\\n\') p++;') |
|
217
|
|
|
|
|
|
|
->blank |
|
218
|
|
|
|
|
|
|
->comment('Body') |
|
219
|
|
|
|
|
|
|
->line('const char* body = p;') |
|
220
|
|
|
|
|
|
|
->line('int body_len = end - p;') |
|
221
|
|
|
|
|
|
|
->blank |
|
222
|
|
|
|
|
|
|
->comment('Build request array: [method, path, body, keep_alive, fd]') |
|
223
|
|
|
|
|
|
|
->line('AV* req = newAV();') |
|
224
|
|
|
|
|
|
|
->line('av_push(req, newSVpvn(method, method_len));') |
|
225
|
|
|
|
|
|
|
->line('av_push(req, newSVpvn(path, path_len));') |
|
226
|
|
|
|
|
|
|
->line('av_push(req, newSVpvn(body, body_len));') |
|
227
|
|
|
|
|
|
|
->line('av_push(req, newSViv(keep_alive));') |
|
228
|
|
|
|
|
|
|
->line('av_push(req, newSViv(fd));') |
|
229
|
|
|
|
|
|
|
->blank |
|
230
|
|
|
|
|
|
|
->line('ST(0) = sv_2mortal(newRV_noinc((SV*)req));') |
|
231
|
|
|
|
|
|
|
->xs_return('1') |
|
232
|
|
|
|
|
|
|
->xs_end; |
|
233
|
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
# Generate http_send - writev for zero-copy |
|
235
|
41
|
|
|
|
|
951
|
$builder->xs_function('jit_http_send') |
|
236
|
|
|
|
|
|
|
->xs_preamble |
|
237
|
|
|
|
|
|
|
->line('if (items < 2 || items > 3) croak("Usage: http_send(fd, body, [content_type])");') |
|
238
|
|
|
|
|
|
|
->line('IV fd = SvIV(ST(0));') |
|
239
|
|
|
|
|
|
|
->blank |
|
240
|
|
|
|
|
|
|
->line('STRLEN body_len;') |
|
241
|
|
|
|
|
|
|
->line('const char* body = SvPV(ST(1), body_len);') |
|
242
|
|
|
|
|
|
|
->blank |
|
243
|
|
|
|
|
|
|
->line('const char* content_type = "text/plain";') |
|
244
|
|
|
|
|
|
|
->if('items == 3 && SvOK(ST(2))') |
|
245
|
|
|
|
|
|
|
->line('STRLEN ct_len;') |
|
246
|
|
|
|
|
|
|
->line('content_type = SvPV(ST(2), ct_len);') |
|
247
|
|
|
|
|
|
|
->endif |
|
248
|
|
|
|
|
|
|
->blank |
|
249
|
|
|
|
|
|
|
->line('static __thread char header[512];') |
|
250
|
|
|
|
|
|
|
->line('int hdr_len = snprintf(header, sizeof(header),') |
|
251
|
|
|
|
|
|
|
->line(' "HTTP/1.1 200 OK\\r\\n"') |
|
252
|
|
|
|
|
|
|
->line(' "Content-Type: %s\\r\\n"') |
|
253
|
|
|
|
|
|
|
->line(' "Content-Length: %zu\\r\\n"') |
|
254
|
|
|
|
|
|
|
->line(' "Connection: keep-alive\\r\\n\\r\\n",') |
|
255
|
|
|
|
|
|
|
->line(' content_type, body_len);') |
|
256
|
|
|
|
|
|
|
->blank |
|
257
|
|
|
|
|
|
|
->line('struct iovec iov[2];') |
|
258
|
|
|
|
|
|
|
->line('iov[0].iov_base = header;') |
|
259
|
|
|
|
|
|
|
->line('iov[0].iov_len = (size_t)hdr_len;') |
|
260
|
|
|
|
|
|
|
->line('iov[1].iov_base = (void*)body;') |
|
261
|
|
|
|
|
|
|
->line('iov[1].iov_len = body_len;') |
|
262
|
|
|
|
|
|
|
->blank |
|
263
|
|
|
|
|
|
|
->line('ssize_t sent = writev((int)fd, iov, 2);') |
|
264
|
|
|
|
|
|
|
->line('ST(0) = sv_2mortal(newSViv((IV)sent));') |
|
265
|
|
|
|
|
|
|
->xs_return('1') |
|
266
|
|
|
|
|
|
|
->xs_end; |
|
267
|
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
# Generate http_send_404 |
|
269
|
41
|
|
|
|
|
776
|
$builder->xs_function('jit_http_send_404') |
|
270
|
|
|
|
|
|
|
->xs_preamble |
|
271
|
|
|
|
|
|
|
->line('if (items != 1) croak("Usage: http_send_404(fd)");') |
|
272
|
|
|
|
|
|
|
->line('IV fd = SvIV(ST(0));') |
|
273
|
|
|
|
|
|
|
->blank |
|
274
|
|
|
|
|
|
|
->line('static const char resp[] =') |
|
275
|
|
|
|
|
|
|
->line(' "HTTP/1.1 404 Not Found\\r\\n"') |
|
276
|
|
|
|
|
|
|
->line(' "Content-Type: text/plain\\r\\n"') |
|
277
|
|
|
|
|
|
|
->line(' "Content-Length: 9\\r\\n"') |
|
278
|
|
|
|
|
|
|
->line(' "Connection: close\\r\\n\\r\\n"') |
|
279
|
|
|
|
|
|
|
->line(' "Not Found";') |
|
280
|
|
|
|
|
|
|
->blank |
|
281
|
|
|
|
|
|
|
->line('ssize_t sent = send((int)fd, resp, sizeof(resp) - 1, 0);') |
|
282
|
|
|
|
|
|
|
->line('ST(0) = sv_2mortal(newSViv((IV)sent));') |
|
283
|
|
|
|
|
|
|
->xs_return('1') |
|
284
|
|
|
|
|
|
|
->xs_end; |
|
285
|
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
# Generate close_fd |
|
287
|
41
|
|
|
|
|
286
|
$builder->xs_function('jit_close_fd') |
|
288
|
|
|
|
|
|
|
->xs_preamble |
|
289
|
|
|
|
|
|
|
->line('if (items != 1) croak("Usage: close_fd(fd)");') |
|
290
|
|
|
|
|
|
|
->line('IV fd = SvIV(ST(0));') |
|
291
|
|
|
|
|
|
|
->line('int result = close((int)fd);') |
|
292
|
|
|
|
|
|
|
->line('ST(0) = sv_2mortal(newSViv(result));') |
|
293
|
|
|
|
|
|
|
->xs_return('1') |
|
294
|
|
|
|
|
|
|
->xs_end; |
|
295
|
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
# Compile via XS::JIT (socket-only functions - event loop is in backends) |
|
297
|
41
|
50
|
|
|
|
1850031
|
XS::JIT->compile( |
|
298
|
|
|
|
|
|
|
code => $builder->code, |
|
299
|
|
|
|
|
|
|
name => $module_name, |
|
300
|
|
|
|
|
|
|
cache_dir => $cache_dir, |
|
301
|
|
|
|
|
|
|
# Windows needs to link against Winsock for the JIT-compiled .so |
|
302
|
|
|
|
|
|
|
# to resolve socket()/recv()/send()/etc. |
|
303
|
|
|
|
|
|
|
($^O eq 'MSWin32' ? (extra_ldflags => '-lws2_32') : ()), |
|
304
|
|
|
|
|
|
|
functions => { |
|
305
|
|
|
|
|
|
|
'Hypersonic::Socket::create_listen_socket' => { source => 'jit_create_listen_socket', is_xs_native => 1 }, |
|
306
|
|
|
|
|
|
|
'Hypersonic::Socket::http_accept' => { source => 'jit_http_accept', is_xs_native => 1 }, |
|
307
|
|
|
|
|
|
|
'Hypersonic::Socket::http_recv' => { source => 'jit_http_recv', is_xs_native => 1 }, |
|
308
|
|
|
|
|
|
|
'Hypersonic::Socket::http_send' => { source => 'jit_http_send', is_xs_native => 1 }, |
|
309
|
|
|
|
|
|
|
'Hypersonic::Socket::http_send_404' => { source => 'jit_http_send_404', is_xs_native => 1 }, |
|
310
|
|
|
|
|
|
|
'Hypersonic::Socket::close_fd' => { source => 'jit_close_fd', is_xs_native => 1 }, |
|
311
|
|
|
|
|
|
|
}, |
|
312
|
|
|
|
|
|
|
); |
|
313
|
|
|
|
|
|
|
|
|
314
|
41
|
|
|
|
|
357
|
$COMPILED = 1; |
|
315
|
41
|
|
|
|
|
399259
|
return 1; |
|
316
|
|
|
|
|
|
|
} |
|
317
|
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
# Auto-compile on import |
|
319
|
|
|
|
|
|
|
sub import { |
|
320
|
42
|
|
|
42
|
|
1315
|
my $class = shift; |
|
321
|
42
|
|
|
|
|
89
|
my %opts = @_; |
|
322
|
42
|
|
|
|
|
149
|
$class->compile_socket_ops(%opts); |
|
323
|
|
|
|
|
|
|
} |
|
324
|
|
|
|
|
|
|
|
|
325
|
|
|
|
|
|
|
1; |
|
326
|
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
__END__ |