aboutsummaryrefslogtreecommitdiff
path: root/v_windows/v/vlib/net/unix/common.v
blob: 75e591f24ca0aa68fd96619cbe2918c05f17ce3c (plain)
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
120
121
122
123
124
125
126
127
128
module unix

import time
import net

const (
	error_ewouldblock = C.EWOULDBLOCK
)

fn C.SUN_LEN(ptr &C.sockaddr_un) int

fn C.strncpy(&char, &char, int)

// Shutdown shutsdown a socket and closes it
fn shutdown(handle int) ? {
	$if windows {
		C.shutdown(handle, C.SD_BOTH)
		net.socket_error(C.closesocket(handle)) ?
	} $else {
		C.shutdown(handle, C.SHUT_RDWR)
		net.socket_error(C.close(handle)) ?
	}
}

// Select waits for an io operation (specified by parameter `test`) to be available
fn @select(handle int, test Select, timeout time.Duration) ?bool {
	set := C.fd_set{}

	C.FD_ZERO(&set)
	C.FD_SET(handle, &set)

	seconds := timeout / time.second
	microseconds := time.Duration(timeout - (seconds * time.second)).microseconds()

	mut tt := C.timeval{
		tv_sec: u64(seconds)
		tv_usec: u64(microseconds)
	}

	mut timeval_timeout := &tt

	// infinite timeout is signaled by passing null as the timeout to
	// select
	if timeout == unix.infinite_timeout {
		timeval_timeout = &C.timeval(0)
	}

	match test {
		.read {
			net.socket_error(C.@select(handle + 1, &set, C.NULL, C.NULL, timeval_timeout)) ?
		}
		.write {
			net.socket_error(C.@select(handle + 1, C.NULL, &set, C.NULL, timeval_timeout)) ?
		}
		.except {
			net.socket_error(C.@select(handle + 1, C.NULL, C.NULL, &set, timeval_timeout)) ?
		}
	}

	return C.FD_ISSET(handle, &set)
}

// wait_for_common wraps the common wait code
fn wait_for_common(handle int, deadline time.Time, timeout time.Duration, test Select) ? {
	if deadline.unix == 0 {
		// do not accept negative timeout
		if timeout < 0 {
			return net.err_timed_out
		}
		ready := @select(handle, test, timeout) ?
		if ready {
			return
		}
		return net.err_timed_out
	}
	// Convert the deadline into a timeout
	// and use that
	d_timeout := deadline.unix - time.now().unix
	if d_timeout < 0 {
		// deadline is in the past so this has already
		// timed out
		return net.err_timed_out
	}

	ready := @select(handle, test, d_timeout) ?
	if ready {
		return
	}
	return net.err_timed_out
}

// wait_for_write waits for a write io operation to be available
fn wait_for_write(handle int, deadline time.Time, timeout time.Duration) ? {
	return wait_for_common(handle, deadline, timeout, .write)
}

// wait_for_read waits for a read io operation to be available
fn wait_for_read(handle int, deadline time.Time, timeout time.Duration) ? {
	return wait_for_common(handle, deadline, timeout, .read)
}

// no_deadline should be given to functions when no deadline is wanted (i.e. all functions
// return instantly)
const (
	no_deadline = time.Time{
		unix: 0
	}
)

// no_timeout should be given to functions when no timeout is wanted (i.e. all functions
// return instantly)
const (
	no_timeout = time.Duration(0)
)

// infinite_timeout should be given to functions when an infinite_timeout is wanted (i.e. functions
// only ever return with data)
const (
	infinite_timeout = time.infinite
)

[inline]
fn wrap_read_result(result int) ?int {
	if result != 0 {
		return result
	}
	return none
}