v2 / vlib / net / unix / common.c.v
130 lines · 108 sloc · 3.47 KB · ae05c4efb6d4474a2ef30ccf69af1343afd1b9dd
Raw
1module unix
2
3import time
4import net
5
6// no_deadline should be given to functions when no deadline is wanted (i.e. all functions
7// return instantly)
8const no_deadline = time.unix(0)
9// no_timeout should be given to functions when no timeout is wanted (i.e. all functions
10// return instantly)
11const no_timeout = time.Duration(0)
12// infinite_timeout should be given to functions when an infinite_timeout is wanted (i.e. functions
13// only ever return with data)
14const infinite_timeout = time.infinite
15
16fn C.strncpy(&char, &char, i32)
17
18// close a socket, given its file descriptor `handle`.
19pub fn close(handle int) ! {
20 net.close(handle)!
21}
22
23// shutdown shutsdown a socket, given its file descriptor `handle`.
24// By default it shuts it down in both directions, both for reading
25// and for writing. You can change that using `net.shutdown(handle, how: .read)`
26// or `net.shutdown(handle, how: .write)`
27pub fn shutdown(handle int, config net.ShutdownConfig) int {
28 return net.shutdown(handle, config)
29}
30
31// Select waits for an io operation (specified by parameter `test`) to be available
32fn select(handle int, test Select, timeout time.Duration) !bool {
33 set := C.fd_set{}
34
35 C.FD_ZERO(&set)
36 C.FD_SET(handle, &set)
37
38 mut tt := C.timeval{}
39 mut timeval_timeout := &tt
40
41 // infinite timeout is signaled by passing null as the timeout to
42 // select.
43 if timeout == infinite_timeout {
44 timeval_timeout = &C.timeval(unsafe { nil })
45 } else {
46 seconds := timeout / time.second
47 microseconds := time.Duration(timeout - (seconds * time.second)).microseconds()
48 tt = C.timeval{
49 tv_sec: u64(seconds)
50 tv_usec: u64(microseconds)
51 }
52 }
53
54 match test {
55 .read {
56 net.socket_error(C.select(handle + 1, &set, C.NULL, C.NULL, timeval_timeout))!
57 }
58 .write {
59 net.socket_error(C.select(handle + 1, C.NULL, &set, C.NULL, timeval_timeout))!
60 }
61 .except {
62 net.socket_error(C.select(handle + 1, C.NULL, C.NULL, &set, timeval_timeout))!
63 }
64 }
65
66 return C.FD_ISSET(handle, &set) != 0
67}
68
69@[inline]
70fn select_deadline(handle int, test Select, deadline time.Time) !bool {
71 // if we have a 0 deadline here then the timeout that was passed was infinite...
72 infinite := deadline.unix() == 0
73 for infinite || time.now() <= deadline {
74 timeout := if infinite { net.infinite_timeout } else { deadline - time.now() }
75 ready := select(handle, test, timeout) or {
76 if err.code() == 4 {
77 // Spurious wakeup from signal, keep waiting
78 continue
79 }
80
81 // NOT a spurious wakeup
82 return err
83 }
84
85 return ready
86 }
87
88 // Deadline elapsed
89 return net.err_timed_out
90}
91
92// wait_for_common wraps the common wait code
93fn wait_for_common(handle int, deadline time.Time, timeout time.Duration, test Select) ! {
94 // Convert timeouts to deadlines
95 real_deadline := if timeout == net.infinite_timeout {
96 time.unix(0)
97 } else if timeout <= 0 {
98 // No timeout set, so assume deadline
99 deadline
100 } else {
101 // timeout
102 time.now().add(timeout)
103 }
104
105 ready := select_deadline(handle, test, real_deadline)!
106
107 if ready {
108 return
109 }
110
111 return net.err_timed_out
112}
113
114// wait_for_write waits for a write io operation to be available
115fn wait_for_write(handle int, deadline time.Time, timeout time.Duration) ! {
116 return wait_for_common(handle, deadline, timeout, .write)
117}
118
119// wait_for_read waits for a read io operation to be available
120fn wait_for_read(handle int, deadline time.Time, timeout time.Duration) ! {
121 return wait_for_common(handle, deadline, timeout, .read)
122}
123
124@[inline]
125fn wrap_read_result(result int) !int {
126 if result != 0 {
127 return result
128 }
129 return error('none')
130}
131