Files
herolib/aiprompts/v_advanced/net.md
Mahmoud-Emad 46a3bcb840 refactor: Migrate from vweb to veb web framework
- Update all references from `vweb` to `veb`
- Add `veb.StaticHandler` to `Playground` struct
- Ensure error propagation for static file serving calls
- Apply consistent indentation across various module definitions
- Adjust documentation and comments for `veb` framework
2025-09-01 13:00:17 +03:00

15 KiB

module net ## Description

`net` provides networking functions. It is mostly a wrapper to BSD sockets, so you can listen on a port, connect to remote TCP/UDP services, and communicate with them.

const msg_nosignal = 0x4000 const err_connection_refused = error_with_code('net: connection refused', errors_base + 10) const err_option_wrong_type = error_with_code('net: set_option_xxx option wrong type', errors_base + 3) const opts_can_set = [ SocketOption.broadcast, .debug, .dont_route, .keep_alive, .linger, .oob_inline, .receive_buf_size, .receive_low_size, .receive_timeout, .send_buf_size, .send_low_size, .send_timeout, .ipv6_only, ] const error_eagain = C.EAGAIN const err_port_out_of_range = error_with_code('net: port out of range', errors_base + 5) const opts_bool = [SocketOption.broadcast, .debug, .dont_route, .error, .keep_alive, .oob_inline] const err_connect_failed = error_with_code('net: connect failed', errors_base + 7) const errors_base = 0 Well defined errors that are returned from socket functions const opts_int = [ SocketOption.receive_buf_size, .receive_low_size, .receive_timeout, .send_buf_size, .send_low_size, .send_timeout, ] const error_eintr = C.EINTR const error_ewouldblock = C.EWOULDBLOCK const err_no_udp_remote = error_with_code('net: no udp remote', errors_base + 6) const error_einprogress = C.EINPROGRESS const err_timed_out_code = errors_base + 9 const err_connect_timed_out = error_with_code('net: connect timed out', errors_base + 8) const err_new_socket_failed = error_with_code('net: new_socket failed to create socket', errors_base + 1) const msg_dontwait = C.MSG_DONTWAIT const infinite_timeout = time.infinite infinite_timeout should be given to functions when an infinite_timeout is wanted (i.e. functions only ever return with data) const no_timeout = time.Duration(0) no_timeout should be given to functions when no timeout is wanted (i.e. all functions return instantly) const err_timed_out = error_with_code('net: op timed out', errors_base + 9) const tcp_default_read_timeout = 30 time.second const err_option_not_settable = error_with_code('net: set_option_xxx option not settable', errors_base + 2) const tcp_default_write_timeout = 30 time.second fn addr_from_socket_handle(handle int) Addr addr_from_socket_handle returns an address, based on the given integer socket handle fn close(handle int) ! close a socket, given its file descriptor handle. In non-blocking mode, if close() does not succeed immediately, it causes an error to be propagated to TcpSocket.close(), which is not intended. Therefore, select is used just like connect(). fn default_tcp_dialer() Dialer default_tcp_dialer will give you an instance of Dialer, that is suitable for making new tcp connections. fn dial_tcp(oaddress string) !&TcpConn dial_tcp will try to create a new TcpConn to the given address. fn dial_tcp_with_bind(saddr string, laddr string) !&TcpConn dial_tcp_with_bind will bind the given local address laddr and dial. fn dial_udp(raddr string) !&UdpConn fn error_code() int fn listen_tcp(family AddrFamily, saddr string, options ListenOptions) !&TcpListener fn listen_udp(laddr string) !&UdpConn fn new_ip(port u16, addr [4]u8) Addr new_ip creates a new Addr from the IPv4 address family, based on the given port and addr fn new_ip6(port u16, addr [16]u8) Addr new_ip6 creates a new Addr from the IP6 address family, based on the given port and addr fn peer_addr_from_socket_handle(handle int) !Addr peer_addr_from_socket_handle retrieves the ip address and port number, given a socket handle fn resolve_addrs(addr string, family AddrFamily, @type SocketType) ![]Addr resolve_addrs converts the given addr, family and @type to a list of addresses fn resolve_addrs_fuzzy(addr string, @type SocketType) ![]Addr resolve_addrs converts the given addr and @type to a list of addresses fn resolve_ipaddrs(addr string, family AddrFamily, typ SocketType) ![]Addr resolve_ipaddrs converts the given addr, family and typ to a list of addresses fn set_blocking(handle int, state bool) ! set_blocking will change the state of the socket to either blocking, when state is true, or non blocking (false). fn shutdown(handle int, config ShutdownConfig) int shutdown shutsdown a socket, given its file descriptor handle. By default it shuts it down in both directions, both for reading and for writing. You can change that using net.shutdown(handle, how: .read) or net.shutdown(handle, how: .write) In non-blocking mode, shutdown() may not succeed immediately, so select is also used to make sure that the function doesn't return an incorrect result. fn socket_error(potential_code int) !int fn socket_error_message(potential_code int, s string) !int fn split_address(addr string) !(string, u16) split_address splits an address into its host name and its port fn tcp_socket_from_handle_raw(sockfd int) TcpSocket tcp_socket_from_handle_raw is similar to tcp_socket_from_handle, but it does not modify any socket options fn validate_port(port int) !u16 validate_port checks whether a port is valid and returns the port or an error fn wrap_error(error_code int) ! interface Connection { addr() !Addr peer_addr() !Addr mut: read(mut []u8) !int write([]u8) !int close() ! } Connection provides a generic SOCK_STREAM style interface that protocols can use as a base connection object to support TCP, UNIX Domain Sockets and various proxying solutions. interface Dialer { dial(address string) !Connection } Dialer is an abstract dialer interface for producing connections to adresses. fn (mut s TcpSocket) set_option_bool(opt SocketOption, value bool) ! fn (mut s TcpSocket) set_option_int(opt SocketOption, value int) ! fn (mut s TcpSocket) set_dualstack(on bool) ! fn (mut s TcpSocket) bind(addr string) ! bind a local rddress for TcpSocket fn (mut s UdpSocket) set_option_bool(opt SocketOption, value bool) ! fn (mut s UdpSocket) set_dualstack(on bool) ! enum AddrFamily { unix = C.AF_UNIX ip = C.AF_INET ip6 = C.AF_INET6 unspec = C.AF_UNSPEC } AddrFamily are the available address families enum ShutdownDirection { read write read_and_write } ShutdownDirection is used by net.shutdown, for specifying the direction for which the communication will be cut. enum SocketOption { // TODO: SO_ACCEPT_CONN is not here because windows doesn't support it // and there is no easy way to define it broadcast = C.SO_BROADCAST debug = C.SO_DEBUG dont_route = C.SO_DONTROUTE error = C.SO_ERROR keep_alive = C.SO_KEEPALIVE linger = C.SO_LINGER oob_inline = C.SO_OOBINLINE reuse_addr = C.SO_REUSEADDR receive_buf_size = C.SO_RCVBUF receive_low_size = C.SO_RCVLOWAT receive_timeout = C.SO_RCVTIMEO send_buf_size = C.SO_SNDBUF send_low_size = C.SO_SNDLOWAT send_timeout = C.SO_SNDTIMEO socket_type = C.SO_TYPE ipv6_only = C.IPV6_V6ONLY } enum SocketType { udp = C.SOCK_DGRAM tcp = C.SOCK_STREAM seqpacket = C.SOCK_SEQPACKET } SocketType are the available sockets struct Addr { pub: len u8 f u8 addr AddrData } fn (a Addr) family() AddrFamily family returns the family/kind of the given address a fn (a Addr) len() u32 len returns the length in bytes of the address a, depending on its family fn (a Addr) port() !u16 port returns the ip or ip6 port of the given address a fn (a Addr) str() string str returns a string representation of the address a struct C.addrinfo { mut: ai_family int ai_socktype int ai_flags int ai_protocol int ai_addrlen int ai_addr voidptr ai_canonname voidptr ai_next voidptr } struct C.fd_set {} struct C.sockaddr_in { mut: sin_len u8 sin_family u8 sin_port u16 sin_addr u32 sin_zero [8]char } struct C.sockaddr_in6 { mut: // 1 + 1 + 2 + 4 + 16 + 4 = 28; sin6_len u8 // 1 sin6_family u8 // 1 sin6_port u16 // 2 sin6_flowinfo u32 // 4 sin6_addr [16]u8 // 16 sin6_scope_id u32 // 4 } struct C.sockaddr_un { mut: sun_len u8 sun_family u8 sun_path [max_unix_path]char } struct Ip { port u16 addr [4]u8 // Pad to size so that socket functions // dont complain to us (see in.h and bind()) // TODO(emily): I would really like to use // some constant calculations here // so that this doesnt have to be hardcoded sin_pad [8]u8 } fn (a Ip) str() string str returns a string representation of a struct Ip6 { port u16 flow_info u32 addr [16]u8 scope_id u32 } fn (a Ip6) str() string str returns a string representation of a struct ListenOptions { pub: dualstack bool = true backlog int = 128 } struct ShutdownConfig { pub: how ShutdownDirection = .read_and_write } struct Socket { pub: handle int } fn (s &Socket) address() !Addr address gets the address of a socket struct TCPDialer {} TCPDialer is a concrete instance of the Dialer interface, for creating tcp connections. fn (t TCPDialer) dial(address string) !Connection dial will try to create a new abstract connection to the given address. It will return an error, if that is not possible. struct TcpConn { pub mut: sock TcpSocket handle int write_deadline time.Time read_deadline time.Time read_timeout time.Duration write_timeout time.Duration is_blocking bool = true } fn (c &TcpConn) addr() !Addr fn (mut c TcpConn) close() ! close closes the tcp connection fn (mut con TcpConn) get_blocking() bool get_blocking returns whether the connection is in a blocking state, that is calls to .read_line, C.recv etc will block till there is new data arrived, instead of returning immediately. fn (c &TcpConn) peer_addr() !Addr peer_addr retrieves the ip address and port number used by the peer fn (c &TcpConn) peer_ip() !string peer_ip retrieves the ip address used by the peer, and returns it as a string fn (c TcpConn) read(mut buf []u8) !int read reads data from the tcp connection into the mutable buffer buf. The number of bytes read is limited to the length of the buffer buf.len. The returned value is the number of read bytes (between 0 and buf.len). fn (mut c TcpConn) read_deadline() !time.Time fn (mut con TcpConn) read_line() string read_line is a simple, non customizable, blocking line reader. It will return a line, ending with LF, or just '', on EOF.

Note: if you want more control over the buffer, please use a buffered IO reader instead: `io.new_buffered_reader({reader: io.make_reader(con)})`

fn (mut con TcpConn) read_line_max(max_line_len int) string read_line_max is a simple, non customizable, blocking line reader. It will return a line, ending with LF, '' on EOF. It stops reading, when the result line length exceeds max_line_len. fn (c TcpConn) read_ptr(buf_ptr &u8, len int) !int read_ptr reads data from the tcp connection to the given buffer. It reads at most len bytes. It returns the number of actually read bytes, which can vary between 0 to len. fn (c &TcpConn) read_timeout() time.Duration fn (mut con TcpConn) set_blocking(state bool) ! set_blocking will change the state of the connection to either blocking, when state is true, or non blocking (false). The default for net tcp connections is the blocking mode. Calling .read_line will set the connection to blocking mode. In general, changing the blocking mode after a successful connection may cause unexpected surprises, so this function is not recommended to be called anywhere but for this file. fn (mut c TcpConn) set_read_deadline(deadline time.Time) fn (mut c TcpConn) set_read_timeout(t time.Duration) fn (mut c TcpConn) set_sock() ! set_sock initialises the c.sock field. It should be called after .accept_only()!.

Note: just use `.accept()!`. In most cases it is simpler, and calls `.set_sock()!` for you.

fn (mut c TcpConn) set_write_deadline(deadline time.Time) fn (mut c TcpConn) set_write_timeout(t time.Duration) fn (c TcpConn) str() string fn (c TcpConn) wait_for_read() ! fn (mut c TcpConn) wait_for_write() ! fn (mut c TcpConn) write(bytes []u8) !int write blocks and attempts to write all data fn (mut c TcpConn) write_deadline() !time.Time fn (mut c TcpConn) write_ptr(b &u8, len int) !int write_ptr blocks and attempts to write all data fn (mut c TcpConn) write_string(s string) !int write_string blocks and attempts to write all data fn (c &TcpConn) write_timeout() time.Duration struct TcpListener { pub mut: sock TcpSocket accept_timeout time.Duration accept_deadline time.Time is_blocking bool = true } fn (mut l TcpListener) accept() !&TcpConn accept a tcp connection from an external source to the listener l. fn (mut l TcpListener) accept_only() !&TcpConn accept_only accepts a tcp connection from an external source to the listener l. Unlike accept, accept_only will not call .set_sock()! on the result, and is thus faster.

Note: you *need* to call `.set_sock()!` manually, before using theconnection after calling `.accept_only()!`, but that does not have to happen in the same thread that called `.accept_only()!`. The intention of this API, is to have a more efficient way to accept connections, that are later processed by a thread pool, while the main thread remains active, so that it can accept other connections. See also vlib/veb/veb.v .

If you do not need that, just call `.accept()!` instead, which will call `.set_sock()!` for you.

fn (c &TcpListener) accept_deadline() !time.Time fn (mut c TcpListener) set_accept_deadline(deadline time.Time) fn (c &TcpListener) accept_timeout() time.Duration fn (mut c TcpListener) set_accept_timeout(t time.Duration) fn (mut c TcpListener) wait_for_accept() ! fn (mut c TcpListener) close() ! fn (c &TcpListener) addr() !Addr struct UdpConn { pub mut: sock UdpSocket mut: write_deadline time.Time read_deadline time.Time read_timeout time.Duration write_timeout time.Duration } fn (mut c UdpConn) write_ptr(b &u8, len int) !int sock := UdpSocket{ handle: sbase.handle l: local r: resolve_wrapper(raddr) } } fn (mut c UdpConn) write(buf []u8) !int fn (mut c UdpConn) write_string(s string) !int fn (mut c UdpConn) write_to_ptr(addr Addr, b &u8, len int) !int fn (mut c UdpConn) write_to(addr Addr, buf []u8) !int write_to blocks and writes the buf to the remote addr specified fn (mut c UdpConn) write_to_string(addr Addr, s string) !int write_to_string blocks and writes the buf to the remote addr specified fn (mut c UdpConn) read(mut buf []u8) !(int, Addr) read reads from the socket into buf up to buf.len returning the number of bytes read fn (c &UdpConn) read_deadline() !time.Time fn (mut c UdpConn) set_read_deadline(deadline time.Time) fn (c &UdpConn) write_deadline() !time.Time fn (mut c UdpConn) set_write_deadline(deadline time.Time) fn (c &UdpConn) read_timeout() time.Duration fn (mut c UdpConn) set_read_timeout(t time.Duration) fn (c &UdpConn) write_timeout() time.Duration fn (mut c UdpConn) set_write_timeout(t time.Duration) fn (mut c UdpConn) wait_for_read() ! fn (mut c UdpConn) wait_for_write() ! fn (c &UdpConn) str() string fn (mut c UdpConn) close() ! struct Unix { path [max_unix_path]char }