v / vlib / net / raw.c.v
261 lines · 224 sloc · 6.99 KB · 9e1d3ca05db333f60c4201e1d35db705c319d4dd
Raw
1module net
2
3import time
4
5const raw_default_read_timeout = time.second / 10
6const raw_default_write_timeout = time.second / 10
7
8struct RawSocket {
9 Socket
10 l Addr
11mut:
12 has_r bool
13 r Addr
14 protocol Protocol
15}
16
17// RawConn represents a raw socket connection for low-level network access.
18// Raw sockets allow sending and receiving packets at the IP layer,
19// bypassing the TCP/UDP transport layer.
20pub struct RawConn {
21pub mut:
22 sock RawSocket
23mut:
24 write_deadline time.Time
25 read_deadline time.Time
26 read_timeout time.Duration
27 write_timeout time.Duration
28}
29
30// RawSocketConfig configures the creation of a raw socket.
31@[params]
32pub struct RawSocketConfig {
33pub:
34 family AddrFamily = .ip
35 protocol Protocol = .icmp
36}
37
38// new_raw_socket creates a new raw socket with the given configuration.
39// Raw sockets typically require elevated privileges (root/administrator).
40pub fn new_raw_socket(config RawSocketConfig) !&RawConn {
41 sockfd := socket_error(C.socket(i32(config.family), i32(SocketType.raw), i32(config.protocol)))!
42 mut s := &RawSocket{
43 handle: sockfd
44 protocol: config.protocol
45 l: Addr{
46 addr: AddrData{
47 Ip6: Ip6{}
48 }
49 }
50 r: Addr{
51 addr: AddrData{
52 Ip6: Ip6{}
53 }
54 }
55 }
56
57 $if net_nonblocking_sockets ? {
58 set_blocking(sockfd, false)!
59 }
60
61 return &RawConn{
62 sock: s
63 read_timeout: raw_default_read_timeout
64 write_timeout: raw_default_write_timeout
65 }
66}
67
68// write_ptr writes data from `b` of length `len` to the connected remote address.
69pub fn (mut c RawConn) write_ptr(b &u8, len int) !int {
70 remote := c.sock.remote() or { return error('no remote address set for raw socket') }
71 return c.write_to_ptr(remote, b, len)
72}
73
74// write writes `buf` to the connected remote address.
75pub fn (mut c RawConn) write(buf []u8) !int {
76 return c.write_ptr(buf.data, buf.len)
77}
78
79// write_string writes string `s` to the connected remote address.
80pub fn (mut c RawConn) write_string(s string) !int {
81 return c.write_ptr(s.str, s.len)
82}
83
84// write_to_ptr writes data from `b` of length `len` to the specified `addr`.
85pub fn (mut c RawConn) write_to_ptr(addr Addr, b &u8, len int) !int {
86 res := C.sendto(c.sock.handle, b, len, 0, voidptr(&addr), addr.len())
87 if res >= 0 {
88 return res
89 }
90 code := error_code()
91 if code == int(error_ewouldblock) {
92 c.wait_for_write()!
93 socket_error(C.sendto(c.sock.handle, b, len, 0, voidptr(&addr), addr.len()))!
94 } else {
95 wrap_error(code)!
96 }
97 return error('write failed')
98}
99
100// write_to writes `buf` to the specified `addr`.
101pub fn (mut c RawConn) write_to(addr Addr, buf []u8) !int {
102 return c.write_to_ptr(addr, buf.data, buf.len)
103}
104
105// write_to_string writes string `s` to the specified `addr`.
106pub fn (mut c RawConn) write_to_string(addr Addr, s string) !int {
107 return c.write_to_ptr(addr, s.str, s.len)
108}
109
110// read_ptr reads from the socket into `buf_ptr` up to `len` bytes,
111// returning the number of bytes read and the source `Addr`.
112pub fn (c &RawConn) read_ptr(buf_ptr &u8, len int) !(int, Addr) {
113 mut addr := Addr{
114 addr: AddrData{
115 Ip6: Ip6{}
116 }
117 }
118 addr_len := sizeof(Addr)
119 mut res := wrap_read_result(C.recvfrom(c.sock.handle, voidptr(buf_ptr), len, 0, voidptr(&addr),
120 &addr_len))!
121 if res > 0 {
122 return res, addr
123 }
124 code := error_code()
125 if code == int(error_ewouldblock) {
126 c.wait_for_read()!
127 res = wrap_read_result(C.recvfrom(c.sock.handle, voidptr(buf_ptr), len, 0, voidptr(&addr),
128 &addr_len))!
129 res2 := socket_error(res)!
130 return res2, addr
131 } else {
132 wrap_error(code)!
133 }
134 return error('read failed')
135}
136
137// read reads from the socket into `buf`, returning the number of bytes read and the source `Addr`.
138pub fn (mut c RawConn) read(mut buf []u8) !(int, Addr) {
139 return c.read_ptr(buf.data, buf.len)!
140}
141
142// read_deadline returns the current read deadline.
143pub fn (c &RawConn) read_deadline() !time.Time {
144 if c.read_deadline.unix() == 0 {
145 return c.read_deadline
146 }
147 return error('none')
148}
149
150// set_read_deadline sets the read deadline.
151pub fn (mut c RawConn) set_read_deadline(deadline time.Time) {
152 c.read_deadline = deadline
153}
154
155// write_deadline returns the current write deadline.
156pub fn (c &RawConn) write_deadline() !time.Time {
157 if c.write_deadline.unix() == 0 {
158 return c.write_deadline
159 }
160 return error('none')
161}
162
163// set_write_deadline sets the write deadline.
164pub fn (mut c RawConn) set_write_deadline(deadline time.Time) {
165 c.write_deadline = deadline
166}
167
168// read_timeout returns the current read timeout duration.
169pub fn (c &RawConn) read_timeout() time.Duration {
170 return c.read_timeout
171}
172
173// set_read_timeout sets the read timeout duration.
174pub fn (mut c RawConn) set_read_timeout(t time.Duration) {
175 c.read_timeout = t
176}
177
178// write_timeout returns the current write timeout duration.
179pub fn (c &RawConn) write_timeout() time.Duration {
180 return c.write_timeout
181}
182
183// set_write_timeout sets the write timeout duration.
184pub fn (mut c RawConn) set_write_timeout(t time.Duration) {
185 c.write_timeout = t
186}
187
188// wait_for_read waits for a read operation to be available.
189@[inline]
190pub fn (c &RawConn) wait_for_read() ! {
191 return wait_for_read(c.sock.handle, c.read_deadline, c.read_timeout)
192}
193
194// wait_for_write waits for a write operation to be available.
195@[inline]
196pub fn (mut c RawConn) wait_for_write() ! {
197 return wait_for_write(c.sock.handle, c.write_deadline, c.write_timeout)
198}
199
200// str returns a string representation of the RawConn.
201pub fn (c &RawConn) str() string {
202 return 'RawConn'
203}
204
205// close closes the raw socket connection.
206pub fn (mut c RawConn) close() ! {
207 return c.sock.close()
208}
209
210// set_remote sets the remote address for write operations.
211pub fn (mut c RawConn) set_remote(addr Addr) {
212 c.sock.has_r = true
213 c.sock.r = addr
214}
215
216// protocol returns the protocol used by this socket.
217pub fn (c &RawConn) protocol() Protocol {
218 return c.sock.protocol
219}
220
221// set_option_bool sets a boolean socket option.
222pub fn (mut s RawSocket) set_option_bool(opt SocketOption, value bool) ! {
223 x := int(value)
224 socket_error(C.setsockopt(s.handle, C.SOL_SOCKET, int(opt), &x, sizeof(int)))!
225}
226
227// set_option_int sets an integer socket option.
228pub fn (mut s RawSocket) set_option_int(opt SocketOption, value int) ! {
229 socket_error(C.setsockopt(s.handle, C.SOL_SOCKET, int(opt), &value, sizeof(int)))!
230}
231
232// set_ip_header_included enables or disables the IP_HDRINCL option.
233// When enabled, the user must provide the complete IP header.
234pub fn (mut s RawSocket) set_ip_header_included(on bool) ! {
235 x := int(on)
236 socket_error(C.setsockopt(s.handle, C.IPPROTO_IP, C.IP_HDRINCL, &x, sizeof(int)))!
237}
238
239// close shuts down and closes the socket.
240pub fn (mut s RawSocket) close() ! {
241 shutdown(s.handle)
242 return close(s.handle)
243}
244
245// select waits for no more than `timeout` for the IO operation, defined by `test`, to be available.
246pub fn (mut s RawSocket) select(test Select, timeout time.Duration) !bool {
247 return select(s.handle, test, timeout)
248}
249
250// remote returns the remote `Addr` of the socket or `none` if not set.
251pub fn (s &RawSocket) remote() ?Addr {
252 if s.has_r {
253 return s.r
254 }
255 return none
256}
257
258// addr returns the local address of the socket.
259pub fn (c &RawConn) addr() !Addr {
260 return c.sock.address()
261}
262