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