-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsocket_util.c.v
119 lines (109 loc) · 3.11 KB
/
socket_util.c.v
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
module picoev
import net
import picohttpparser
import socket
#include <errno.h>
$if windows {
#include <winsock2.h>
#include <ws2tcpip.h>
} $else $if freebsd || macos {
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
} $else {
#include <netinet/tcp.h>
#include <sys/resource.h>
}
@[inline]
fn get_time() i64 {
// time.now() is slow
return i64(C.time(C.NULL))
}
@[inline]
fn accept(fd int) int {
return C.accept(fd, 0, 0)
}
@[inline]
fn close_socket(fd int) {
trace_fd('close ${fd}')
$if windows {
C.closesocket(fd)
} $else {
C.close(fd)
}
}
@[inline]
fn setup_sock(fd int) ! {
flag := 1
if C.setsockopt(fd, C.IPPROTO_TCP, C.TCP_NODELAY, &flag, sizeof(int)) < 0 {
return error('setup_sock.setup_sock failed')
}
$if freebsd {
if C.fcntl(fd, C.F_SETFL, C.SOCK_NONBLOCK) != 0 {
return error('fcntl failed')
}
} $else $if windows {
non_blocking_mode := u32(1)
if C.ioctlsocket(fd, C.FIONBIO, &non_blocking_mode) == C.SOCKET_ERROR {
return error('icotlsocket failed')
}
} $else {
// linux and macos
if C.fcntl(fd, C.F_SETFL, C.O_NONBLOCK) != 0 {
return error('fcntl failed')
}
}
}
@[inline]
fn req_read(fd int, buffer &u8, max_len int, offset int) int {
return socket.read_socket(fd, buffer, max_len, offset)
}
fn fatal_socket_error(fd int) bool {
return socket.is_fatal_error(fd)
}
// listen creates a listening tcp socket and returns its file descriptor
fn listen(config Config) !int {
// not using the `net` modules sockets, because not all socket options are defined
fd := C.socket(config.family, net.SocketType.tcp, 0)
if fd == -1 {
return error('Failed to create socket')
}
trace_fd('listen: ${fd}')
// Setting flags for socket
flag := 1
flag_zero := 0
net.socket_error(C.setsockopt(fd, C.SOL_SOCKET, C.SO_REUSEADDR, &flag, sizeof(int)))!
if config.family == .ip6 {
// set socket to dualstack so connections to both ipv4 and ipv6 addresses
// can be accepted
net.socket_error(C.setsockopt(fd, C.IPPROTO_IPV6, C.IPV6_V6ONLY, &flag_zero, sizeof(int)))!
}
$if linux {
// epoll socket options
net.socket_error(C.setsockopt(fd, C.SOL_SOCKET, C.SO_REUSEPORT, &flag, sizeof(int)))!
net.socket_error(C.setsockopt(fd, C.IPPROTO_TCP, C.TCP_QUICKACK, &flag, sizeof(int)))!
$if !support_wsl1 ? {
net.socket_error(C.setsockopt(fd, C.IPPROTO_TCP, C.TCP_DEFER_ACCEPT, &config.timeout_secs,
sizeof(int)))!
queue_len := max_queue
net.socket_error(C.setsockopt(fd, C.IPPROTO_TCP, C.TCP_FASTOPEN, &queue_len,
sizeof(int)))!
}
}
// addr settings
saddr := '${config.host}:${config.port}'
addrs := net.resolve_addrs(saddr, config.family, .tcp) or {
panic('Error while resolving `${saddr}`, err: ${err}')
}
addr := addrs[0]
alen := addr.len()
net.socket_error_message(C.bind(fd, voidptr(&addr), alen), 'binding to ${saddr} failed')!
net.socket_error_message(C.listen(fd, C.SOMAXCONN), 'listening on ${saddr} with maximum backlog pending queue of ${C.SOMAXCONN}, failed')!
setup_sock(fd) or {
mut req := &picohttpparser.Request{}
config.err_cb(config.user_data, *req, mut &picohttpparser.Response{}, err)
return err
}
return fd
}