From b27f835d33034710ca792b673278888ee53b4e15 Mon Sep 17 00:00:00 2001 From: ge Date: Wed, 1 Apr 2026 00:53:36 +0300 Subject: [PATCH] init --- .editorconfig | 8 ++ .gitattributes | 8 ++ .gitignore | 27 +++++ README.md | 5 + addr.c.v | 310 +++++++++++++++++++++++++++++++++++++++++++++++ af_darwin.c.v | 44 +++++++ af_default.c.v | 10 ++ af_freebsd.c.v | 96 +++++++++++++++ af_linux.c.v | 56 +++++++++ main.v | 45 +++++++ netio.v | 25 ++++ option.v | 1 + protocol.c.v | 104 ++++++++++++++++ so_darwin.c.v | 47 +++++++ so_freebsd.c.v | 53 ++++++++ so_linux.c.v | 94 ++++++++++++++ sock_default.c.v | 11 ++ sock_linux.c.v | 13 ++ socket.c.v | 92 ++++++++++++++ sol_default.c.v | 7 ++ sol_linux.c.v | 35 ++++++ tcp.v | 5 + udp.v | 3 + v.mod | 7 ++ 24 files changed, 1106 insertions(+) create mode 100644 .editorconfig create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 README.md create mode 100644 addr.c.v create mode 100644 af_darwin.c.v create mode 100644 af_default.c.v create mode 100644 af_freebsd.c.v create mode 100644 af_linux.c.v create mode 100644 main.v create mode 100644 netio.v create mode 100644 option.v create mode 100644 protocol.c.v create mode 100644 so_darwin.c.v create mode 100644 so_freebsd.c.v create mode 100644 so_linux.c.v create mode 100644 sock_default.c.v create mode 100644 sock_linux.c.v create mode 100644 socket.c.v create mode 100644 sol_default.c.v create mode 100644 sol_linux.c.v create mode 100644 tcp.v create mode 100644 udp.v create mode 100644 v.mod diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..01072ca --- /dev/null +++ b/.editorconfig @@ -0,0 +1,8 @@ +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true + +[*.v] +indent_style = tab diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..9a98968 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,8 @@ +* text=auto eol=lf +*.bat eol=crlf + +*.v linguist-language=V +*.vv linguist-language=V +*.vsh linguist-language=V +v.mod linguist-language=V +.vdocignore linguist-language=ignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..33d591b --- /dev/null +++ b/.gitignore @@ -0,0 +1,27 @@ +# Binaries for programs and plugins +main +netio +*.exe +*.exe~ +*.so +*.dylib +*.dll + +# Ignore binary output folders +bin/ + +# Ignore common editor/system specific metadata +.DS_Store +.idea/ +.vscode/ +*.iml + +# ENV +.env + +# vweb and database +*.db +*.js + +# Ignore installed modules through `v install --local`: +modules/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..ed27ff8 --- /dev/null +++ b/README.md @@ -0,0 +1,5 @@ +# Networking Library for V + +**netio** is a networking library for V programming language. +This implementation aims to be as flexible and portable. +It heavily relies on the libc. diff --git a/addr.c.v b/addr.c.v new file mode 100644 index 0000000..75d99c9 --- /dev/null +++ b/addr.c.v @@ -0,0 +1,310 @@ +module netio + +import dlmalloc +import encoding.binary +import os + +#include + +struct C.addrinfo { +mut: + ai_flags i32 + ai_family i32 + ai_socktype i32 + ai_protocol i32 + ai_addrlen i32 + ai_addr voidptr + ai_canonname voidptr + ai_next voidptr +} + +fn C.getaddrinfo(node &char, srvc &char, hints &C.addrinfo, res &&C.addrinfo) int +fn C.freeaddrinfo(info &C.addrinfo) + +const max_unix_path_size = $if linux { + 108 +} $else $if windows { + 108 +} $else { + 104 +} + +// AddrInfo represents the [addrinfo](https://man7.org/linux/man-pages/man3/getaddrinfo.3.html). +pub struct AddrInfo { +pub: + flags int + family AddrFamily + sock_type SocketType + protocol Protocol + addr SocketAddr + canonical string +} + +@[params] +pub struct TranslateAddrHints { +pub: + node ?string + service ?string + family AddrFamily = af_unspec + sock_type SocketType + protocol Protocol + flags int +} + +// translate_addr translates the network address. +// See also [getaddrinfo(3)](https://man7.org/linux/man-pages/man3/getaddrinfo.3.html). +// Example: +// ```v +// import os +// import netio +// +// // Resolve the host FQND +// addrs := netio.translate_addr(node: os.hostname()!, flags: C.AI_CANONNAME)! +// for addr in addrs { +// println(addr.canonical) +// } +// ``` +pub fn translate_addr(hints TranslateAddrHints) ![]AddrInfo { + mut hints_ := C.addrinfo{} + unsafe { vmemset(&hints_, 0, int(sizeof(hints_))) } + hints_.ai_family = i32(hints.family) + hints_.ai_socktype = i32(hints.sock_type) + hints_.ai_protocol = i32(hints.protocol) + hints_.ai_flags = i32(hints.flags) + mut node := unsafe { nil } + if hints.node != none { + node = &char(hints.node.str) + } + mut service := unsafe { nil } + if hints.service != none { + service = &char(hints.service.str) + } + mut results := &C.addrinfo(unsafe { nil }) + if C.getaddrinfo(node, service, &hints_, &results) == -1 { + return os.last_error() + } + defer { + C.freeaddrinfo(results) + } + mut addrs := []AddrInfo{} + for result := unsafe { results }; !isnil(result); result = result.ai_next { + addrs << AddrInfo{ + flags: int(result.ai_flags) + family: int(result.ai_family) + sock_type: int(result.ai_socktype) + protocol: int(result.ai_protocol) + addr: unsafe { SocketAddr.from_ptr(result.ai_addr, result.ai_addrlen)! } + canonical: if isnil(result.ai_canonname) { + '' + } else { + unsafe { + cstring_to_vstring(result.ai_canonname) + } + } + } + } + return addrs +} + +// SocketAddr.ipv4 creates new AF_INET socket address. +// addr must be in big-endian byte order. +pub fn SocketAddr.ipv4(addr [4]u8, port u16) SocketAddr { + mut sock_addr := unsafe { SocketAddr.empty(af_inet, 16) } + unsafe { + sock_addr.push(binary.little_endian_get_u16(u16(af_inet))) or {} + sock_addr.push(binary.big_endian_get_u16(port)) or {} + sock_addr.push(addr[..]) or {} + } + return sock_addr +} + +// SocketAddr.ipv6 creates new AF_INET6 socket address. +// addr must be in big-endian byte order. +pub fn SocketAddr.ipv6(addr [16]u8, port u16, flow_info u32, scope_id u32) SocketAddr { + mut sock_addr := unsafe { SocketAddr.empty(af_inet6, 28) } + unsafe { + sock_addr.push(binary.big_endian_get_u16(port)) or {} + sock_addr.push(binary.big_endian_get_u32(flow_info)) or {} + sock_addr.push(addr[..]) or {} + sock_addr.push(binary.big_endian_get_u32(scope_id)) or {} + } + return sock_addr +} + +// SocketAddr.unix creates new AF_UNIX socket address. +pub fn SocketAddr.unix(path string) SocketAddr { + mut sock_addr := unsafe { SocketAddr.empty(af_unix, usize(max_unix_path_size) + 2) } + unsafe { + sock_addr.push(path.bytes()) or {} + } + return sock_addr +} + +// SocketAddr.empty creates new instance of SocketAddr with specified address family and size. +// +// Note: This function only allocates memory (zero filled) for the address, but **does not** +// initialize the address itself, you need to do that manually. The benefit is that you can +// create the any type of address. +// +// Note: This function sets the address family for you. +// This field is always first and have 2-byte size (`u16` type). +// +// SocketAddr is a "constructor" for +// [sockaddr(3type)](https://www.man7.org/linux/man-pages/man3/sockaddr.3type.html) objects. +// Use this function only if you understand what you do. You must manually write the data +// for the desired socket address, ensuring the correct sizes of all types, the order of +// the fields in the struct, the byte order, and the total size of the struct. The sizes +// and byte order may vary by platform, so you'll need to keep an eye on that as well. +// A mistake while creating an address will crash your application. So this function is +// marked as `unsafe`. +// +// The example below creates a `sockaddr_in` struct describing the loopback IPv4-address +// 127.0.0.1 with port number 1080. Note the comment in the example. This is a fragment +// of [sockaddr_in(3type)](https://www.man7.org/linux/man-pages/man3/sockaddr.3type.html) +// manual page, which shows the target C struct. Summing the field sizes yields 8 +// bytes, but we need to allocate 16 bytes according to the . +// Data must be padded to sockaddr struct size which is 16 bytes. Each field is then +// written in turn, from top to bottom. Keep in mind that address family field (sin_family +// in this case) are already written. According to the manual page, the address and port +// are written using the network (big endian) byte order. +// +// Example: +// ```v +// import encoding.binary +// import netio +// +// // struct sockaddr_in { +// // sa_family_t sin_family; /* AF_INET */ +// // in_port_t sin_port; /* Port number */ +// // struct in_addr sin_addr; /* IPv4 address */ +// // }; +// // +// // struct in_addr { +// // in_addr_t s_addr; +// // }; +// // +// // typedef uint32_t in_addr_t; +// // typedef uint16_t in_port_t; +// +// mut sa := unsafe { netio.SocketAddr.empty(u16(C.AF_INET), 16) } +// unsafe { +// sa.push(binary.big_endian_get_u16(u16(1080)))! +// sa.push([u8(127), 0, 0, 1])! +// } +// ``` +@[unsafe] +pub fn SocketAddr.empty(af AddrFamily, size isize) SocketAddr { + ptr := unsafe { dlmalloc.calloc(usize(size)) } + mut sock_addr := SocketAddr{ + data: ptr + len: int(size) + } + unsafe { + $if little_endian { + sock_addr.push(binary.little_endian_get_u16(u16(af))) or {} + } $else { + sock_addr.push(binary.big_endian_get_u16(u16(af))) or {} + } + } + return sock_addr +} + +// SocketAddr.from_ptr creates new socket address by copying data from specified pointer. +@[unsafe] +pub fn SocketAddr.from_ptr(ptr voidptr, size isize) !SocketAddr { + data := unsafe { dlmalloc.calloc(usize(size)) } + unsafe { + vmemcpy(data, ptr, size) + } + return SocketAddr{ + data: data + len: int(size) + } +} + +struct SocketAddr { +mut: + data &u8 = unsafe { nil } + len int + pos int +} + +// family returns the socket address family. +pub fn (a SocketAddr) family() AddrFamily { + mut f := u16(-1) + unsafe { vmemcpy(&f, a.data, isize(2)) } + return f +} + +// push appends the `inp` bytes into internal data buffer. +@[unsafe] +pub fn (mut a SocketAddr) push(inp []u8) ! { + if a.pos + inp.len > a.len { + return error('push: data overflow') + } + mut i := 0 + for a.pos + 1 < a.len { + unsafe { + a.data[a.pos + i] = inp[i] + } + i++ + if i >= inp.len { + break + } + } + a.pos += inp.len +} + +// ptr returns the pointer to sockaddr data. +pub fn (a SocketAddr) ptr() &u8 { + return a.data +} + +// size reports the size of sockaddr data. +pub fn (a SocketAddr) size() u32 { + return u32(a.len) +} + +pub fn (a SocketAddr) str() string { + family := a.family() + match family { + af_inet { + mut addr := [4]u8{} + mut port := [2]u8{} + unsafe { + vmemcpy(port, a.ptr() + 2, 2) + vmemcpy(addr, a.ptr() + 4, 4) + } + port_int := binary.big_endian_u16_fixed(port) + return '${addr[0]}.${addr[1]}.${addr[2]}.${addr[3]}:${port_int}' + } + af_inet6 { + mut addr := [16]u8{} + mut port := [2]u8{} + mut res := '' + unsafe { + vmemcpy(port, a.ptr() + 2, 2) + vmemcpy(addr, a.ptr() + 8, 16) + } + for i := 0; i < 16; i += 2 { + res += addr[i..i + 2].hex() + if i < 14 { + res += ':' + } + } + return res + } + af_unix { + mut path := [max_unix_path_size]u8{} + mut res := '' + unsafe { + vmemcpy(path, a.ptr() + 2, max_unix_path_size) + res = tos_clone(&u8(path[..].data)) + } + return res + } + else { + return 'SocketAddr(${a.data.str()})' + } + } +} diff --git a/af_darwin.c.v b/af_darwin.c.v new file mode 100644 index 0000000..0c380b7 --- /dev/null +++ b/af_darwin.c.v @@ -0,0 +1,44 @@ +module netio + +/* + Address families defined on Darwin. +*/ + +pub const af_appletalk = AddrFamily(u16(C.AF_APPLETALK)) +pub const af_ccitt = AddrFamily(u16(C.AF_CCITT)) +pub const af_chaos = AddrFamily(u16(C.AF_CHAOS)) +pub const af_cnt = AddrFamily(u16(C.AF_CNT)) +pub const af_coip = AddrFamily(u16(C.AF_COIP)) +pub const af_datakit = AddrFamily(u16(C.AF_DATAKIT)) +pub const af_decnet = AddrFamily(u16(C.AF_DECnet)) +pub const af_dli = AddrFamily(u16(C.AF_DLI)) +pub const af_e164 = AddrFamily(u16(C.AF_E164)) +pub const af_ecma = AddrFamily(u16(C.AF_ECMA)) +pub const af_hylink = AddrFamily(u16(C.AF_HYLINK)) +pub const af_ieee80211 = AddrFamily(u16(C.AF_IEEE80211)) +pub const af_implink = AddrFamily(u16(C.AF_IMPLINK)) +pub const af_inet6 = AddrFamily(u16(C.AF_INET6)) +pub const af_inet = AddrFamily(u16(C.AF_INET)) +pub const af_ipx = AddrFamily(u16(C.AF_IPX)) +pub const af_isdn = AddrFamily(u16(C.AF_ISDN)) +pub const af_iso = AddrFamily(u16(C.AF_ISO)) +pub const af_lat = AddrFamily(u16(C.AF_LAT)) +pub const af_link = AddrFamily(u16(C.AF_LINK)) +pub const af_local = AddrFamily(u16(C.AF_LOCAL)) +pub const af_max = AddrFamily(u16(C.AF_MAX)) +pub const af_natm = AddrFamily(u16(C.AF_NATM)) +pub const af_ndrv = AddrFamily(u16(C.AF_NDRV)) +pub const af_netbios = AddrFamily(u16(C.AF_NETBIOS)) +pub const af_ns = AddrFamily(u16(C.AF_NS)) +pub const af_osi = AddrFamily(u16(C.AF_OSI)) +pub const af_ppp = AddrFamily(u16(C.AF_PPP)) +pub const af_pup = AddrFamily(u16(C.AF_PUP)) +pub const af_reserved_36 = AddrFamily(u16(C.AF_RESERVED_36)) +pub const af_route = AddrFamily(u16(C.AF_ROUTE)) +pub const af_sip = AddrFamily(u16(C.AF_SIP)) +pub const af_sna = AddrFamily(u16(C.AF_SNA)) +pub const af_system = AddrFamily(u16(C.AF_SYSTEM)) +pub const af_unix = AddrFamily(u16(C.AF_UNIX)) +pub const af_unspec = AddrFamily(u16(C.AF_UNSPEC)) +pub const af_utun = AddrFamily(u16(C.AF_UTUN)) +pub const af_vsock = AddrFamily(u16(C.AF_VSOCK)) diff --git a/af_default.c.v b/af_default.c.v new file mode 100644 index 0000000..4e556a3 --- /dev/null +++ b/af_default.c.v @@ -0,0 +1,10 @@ +module netio + +/* + Well defined address families. Must work on all platforms. +*/ + +pub const af_unspec = AddrFamily(u16(C.AF_UNSPEC)) +pub const af_unix = AddrFamily(u16(C.AF_UNIX)) +pub const af_inet = AddrFamily(u16(C.AF_INET)) +pub const af_inet6 = AddrFamily(u16(C.AF_INET6)) diff --git a/af_freebsd.c.v b/af_freebsd.c.v new file mode 100644 index 0000000..c46f482 --- /dev/null +++ b/af_freebsd.c.v @@ -0,0 +1,96 @@ +module netio + +/* + Address families defined on FreeBSD. +*/ + +pub const af_appletalk = AddrFamily(u16(C.AF_APPLETALK)) +pub const af_arp = AddrFamily(u16(C.AF_ARP)) +pub const af_atm = AddrFamily(u16(C.AF_ATM)) +pub const af_bluetooth = AddrFamily(u16(C.AF_BLUETOOTH)) +pub const af_ccitt = AddrFamily(u16(C.AF_CCITT)) +pub const af_chaos = AddrFamily(u16(C.AF_CHAOS)) +pub const af_cnt = AddrFamily(u16(C.AF_CNT)) +pub const af_coip = AddrFamily(u16(C.AF_COIP)) +pub const af_datakit = AddrFamily(u16(C.AF_DATAKIT)) +pub const af_decnet = AddrFamily(u16(C.AF_DECnet)) +pub const af_divert = AddrFamily(u16(C.AF_DIVERT)) +pub const af_dli = AddrFamily(u16(C.AF_DLI)) +pub const af_e164 = AddrFamily(u16(C.AF_E164)) +pub const af_ecma = AddrFamily(u16(C.AF_ECMA)) +pub const af_hylink = AddrFamily(u16(C.AF_HYLINK)) +pub const af_hyperv = AddrFamily(u16(C.AF_HYPERV)) +pub const af_ieee80211 = AddrFamily(u16(C.AF_IEEE80211)) +pub const af_implink = AddrFamily(u16(C.AF_IMPLINK)) +pub const af_inet6 = AddrFamily(u16(C.AF_INET6)) +pub const af_inet6_sdp = AddrFamily(u16(C.AF_INET6_SDP)) +pub const af_inet = AddrFamily(u16(C.AF_INET)) +pub const af_inet_sdp = AddrFamily(u16(C.AF_INET_SDP)) +pub const af_ipfwlog = AddrFamily(u16(C.AF_IPFWLOG)) +pub const af_ipx = AddrFamily(u16(C.AF_IPX)) +pub const af_isdn = AddrFamily(u16(C.AF_ISDN)) +pub const af_iso = AddrFamily(u16(C.AF_ISO)) +pub const af_lat = AddrFamily(u16(C.AF_LAT)) +pub const af_link = AddrFamily(u16(C.AF_LINK)) +pub const af_local = AddrFamily(u16(C.AF_LOCAL)) +pub const af_max = AddrFamily(u16(C.AF_MAX)) +pub const af_natm = AddrFamily(u16(C.AF_NATM)) +pub const af_netbios = AddrFamily(u16(C.AF_NETBIOS)) +pub const af_netgraph = AddrFamily(u16(C.AF_NETGRAPH)) +pub const af_netlink = AddrFamily(u16(C.AF_NETLINK)) +pub const af_osi = AddrFamily(u16(C.AF_OSI)) +pub const af_pup = AddrFamily(u16(C.AF_PUP)) +pub const af_route = AddrFamily(u16(C.AF_ROUTE)) +pub const af_scluster = AddrFamily(u16(C.AF_SCLUSTER)) +pub const af_sip = AddrFamily(u16(C.AF_SIP)) +pub const af_slow = AddrFamily(u16(C.AF_SLOW)) +pub const af_sna = AddrFamily(u16(C.AF_SNA)) +pub const af_unix = AddrFamily(u16(C.AF_UNIX)) +pub const af_unspec = AddrFamily(u16(C.AF_UNSPEC)) +pub const af_vendor00 = AddrFamily(u16(C.AF_VENDOR00)) +pub const af_vendor01 = AddrFamily(u16(C.AF_VENDOR01)) +pub const af_vendor03 = AddrFamily(u16(C.AF_VENDOR03)) +pub const af_vendor04 = AddrFamily(u16(C.AF_VENDOR04)) +pub const af_vendor05 = AddrFamily(u16(C.AF_VENDOR05)) +pub const af_vendor06 = AddrFamily(u16(C.AF_VENDOR06)) +pub const af_vendor07 = AddrFamily(u16(C.AF_VENDOR07)) +pub const af_vendor08 = AddrFamily(u16(C.AF_VENDOR08)) +pub const af_vendor09 = AddrFamily(u16(C.AF_VENDOR09)) +pub const af_vendor10 = AddrFamily(u16(C.AF_VENDOR10)) +pub const af_vendor11 = AddrFamily(u16(C.AF_VENDOR11)) +pub const af_vendor12 = AddrFamily(u16(C.AF_VENDOR12)) +pub const af_vendor13 = AddrFamily(u16(C.AF_VENDOR13)) +pub const af_vendor14 = AddrFamily(u16(C.AF_VENDOR14)) +pub const af_vendor15 = AddrFamily(u16(C.AF_VENDOR15)) +pub const af_vendor16 = AddrFamily(u16(C.AF_VENDOR16)) +pub const af_vendor17 = AddrFamily(u16(C.AF_VENDOR17)) +pub const af_vendor18 = AddrFamily(u16(C.AF_VENDOR18)) +pub const af_vendor19 = AddrFamily(u16(C.AF_VENDOR19)) +pub const af_vendor20 = AddrFamily(u16(C.AF_VENDOR20)) +pub const af_vendor21 = AddrFamily(u16(C.AF_VENDOR21)) +pub const af_vendor22 = AddrFamily(u16(C.AF_VENDOR22)) +pub const af_vendor23 = AddrFamily(u16(C.AF_VENDOR23)) +pub const af_vendor24 = AddrFamily(u16(C.AF_VENDOR24)) +pub const af_vendor25 = AddrFamily(u16(C.AF_VENDOR25)) +pub const af_vendor26 = AddrFamily(u16(C.AF_VENDOR26)) +pub const af_vendor27 = AddrFamily(u16(C.AF_VENDOR27)) +pub const af_vendor28 = AddrFamily(u16(C.AF_VENDOR28)) +pub const af_vendor29 = AddrFamily(u16(C.AF_VENDOR29)) +pub const af_vendor30 = AddrFamily(u16(C.AF_VENDOR30)) +pub const af_vendor31 = AddrFamily(u16(C.AF_VENDOR31)) +pub const af_vendor32 = AddrFamily(u16(C.AF_VENDOR32)) +pub const af_vendor33 = AddrFamily(u16(C.AF_VENDOR33)) +pub const af_vendor34 = AddrFamily(u16(C.AF_VENDOR34)) +pub const af_vendor35 = AddrFamily(u16(C.AF_VENDOR35)) +pub const af_vendor36 = AddrFamily(u16(C.AF_VENDOR36)) +pub const af_vendor37 = AddrFamily(u16(C.AF_VENDOR37)) +pub const af_vendor38 = AddrFamily(u16(C.AF_VENDOR38)) +pub const af_vendor39 = AddrFamily(u16(C.AF_VENDOR39)) +pub const af_vendor40 = AddrFamily(u16(C.AF_VENDOR40)) +pub const af_vendor41 = AddrFamily(u16(C.AF_VENDOR41)) +pub const af_vendor42 = AddrFamily(u16(C.AF_VENDOR42)) +pub const af_vendor43 = AddrFamily(u16(C.AF_VENDOR43)) +pub const af_vendor44 = AddrFamily(u16(C.AF_VENDOR44)) +pub const af_vendor45 = AddrFamily(u16(C.AF_VENDOR45)) +pub const af_vendor46 = AddrFamily(u16(C.AF_VENDOR46)) +pub const af_vendor47 = AddrFamily(u16(C.AF_VENDOR47)) diff --git a/af_linux.c.v b/af_linux.c.v new file mode 100644 index 0000000..c8d4a36 --- /dev/null +++ b/af_linux.c.v @@ -0,0 +1,56 @@ +module netio + +/* + Address families defined on Linux. +*/ + +pub const af_alg = AddrFamily(u16(C.AF_ALG)) +pub const af_appletalk = AddrFamily(u16(C.AF_APPLETALK)) +pub const af_ash = AddrFamily(u16(C.AF_ASH)) +pub const af_atmpvc = AddrFamily(u16(C.AF_ATMPVC)) +pub const af_atmsvc = AddrFamily(u16(C.AF_ATMSVC)) +pub const af_ax25 = AddrFamily(u16(C.AF_AX25)) +pub const af_bluetooth = AddrFamily(u16(C.AF_BLUETOOTH)) +pub const af_bridge = AddrFamily(u16(C.AF_BRIDGE)) +pub const af_caif = AddrFamily(u16(C.AF_CAIF)) +pub const af_can = AddrFamily(u16(C.AF_CAN)) +pub const af_decnet = AddrFamily(u16(C.AF_DECnet)) +pub const af_econet = AddrFamily(u16(C.AF_ECONET)) +pub const af_file = AddrFamily(u16(C.AF_FILE)) +pub const af_ib = AddrFamily(u16(C.AF_IB)) +pub const af_ieee802154 = AddrFamily(u16(C.AF_IEEE802154)) +pub const af_inet6 = AddrFamily(u16(C.AF_INET6)) +pub const af_inet = AddrFamily(u16(C.AF_INET)) +pub const af_ipx = AddrFamily(u16(C.AF_IPX)) +pub const af_irda = AddrFamily(u16(C.AF_IRDA)) +pub const af_isdn = AddrFamily(u16(C.AF_ISDN)) +pub const af_iucv = AddrFamily(u16(C.AF_IUCV)) +pub const af_kcm = AddrFamily(u16(C.AF_KCM)) +pub const af_key = AddrFamily(u16(C.AF_KEY)) +pub const af_llc = AddrFamily(u16(C.AF_LLC)) +pub const af_local = AddrFamily(u16(C.AF_LOCAL)) +pub const af_max = AddrFamily(u16(C.AF_MAX)) +pub const af_mctp = AddrFamily(u16(C.AF_MCTP)) +pub const af_mpls = AddrFamily(u16(C.AF_MPLS)) +pub const af_netbeui = AddrFamily(u16(C.AF_NETBEUI)) +pub const af_netlink = AddrFamily(u16(C.AF_NETLINK)) +pub const af_netrom = AddrFamily(u16(C.AF_NETROM)) +pub const af_nfc = AddrFamily(u16(C.AF_NFC)) +pub const af_packet = AddrFamily(u16(C.AF_PACKET)) +pub const af_phonet = AddrFamily(u16(C.AF_PHONET)) +pub const af_pppox = AddrFamily(u16(C.AF_PPPOX)) +pub const af_qipcrtr = AddrFamily(u16(C.AF_QIPCRTR)) +pub const af_rds = AddrFamily(u16(C.AF_RDS)) +pub const af_rose = AddrFamily(u16(C.AF_ROSE)) +pub const af_route = AddrFamily(u16(C.AF_ROUTE)) +pub const af_rxrpc = AddrFamily(u16(C.AF_RXRPC)) +pub const af_security = AddrFamily(u16(C.AF_SECURITY)) +pub const af_smc = AddrFamily(u16(C.AF_SMC)) +pub const af_sna = AddrFamily(u16(C.AF_SNA)) +pub const af_tipc = AddrFamily(u16(C.AF_TIPC)) +pub const af_unix = AddrFamily(u16(C.AF_UNIX)) +pub const af_unspec = AddrFamily(u16(C.AF_UNSPEC)) +pub const af_vsock = AddrFamily(u16(C.AF_VSOCK)) +pub const af_wanpipe = AddrFamily(u16(C.AF_WANPIPE)) +pub const af_x25 = AddrFamily(u16(C.AF_X25)) +pub const af_xdp = AddrFamily(u16(C.AF_XDP)) diff --git a/main.v b/main.v new file mode 100644 index 0000000..52e8b4d --- /dev/null +++ b/main.v @@ -0,0 +1,45 @@ +// import net +import netio +// import time +import os + +fn main() { + listen_addr := netio.SocketAddr.ipv4([u8(127), 0, 0, 1]!, 1081) + eprintln(listen_addr.family()) + + // eprintln(listen_addr) + // mut socket := netio.Socket.new(netio.af_inet, .tcp, 0)! + // socket.bind(listen_addr)! + // socket.listen(10)! + // println('Server started...') + // for { + // conn_fd := socket.accept()!.fd + // mut sock := net.tcp_socket_from_handle_raw(conn_fd) + // mut conn := net.TcpConn{ + // sock: sock + // handle: conn_fd + // read_timeout: 30 * time.second + // write_timeout: 30 * time.second + // } + // read := conn.read_line() + // println('Data read: ${read}') + // net.close(conn_fd)! + // } + // socket.close()! + + // hostname := dump(os.hostname()!) + ai := netio.translate_addr( + node: 'localhost' + flags: C.AI_CANONNAME + family: netio.af_inet + sock_type: netio.sock_stream + )! + dump(ai.len) + for a in ai { + println(a) + // println('Protocol: ' + netio.protocol_by_number(a.protocol)!.name) + // println('Address: ' + a.addr.str()) + // println('Canonical name: ' + a.canonical) + // println('---') + } +} diff --git a/netio.v b/netio.v new file mode 100644 index 0000000..a214a18 --- /dev/null +++ b/netio.v @@ -0,0 +1,25 @@ +module netio + +import sync + +fn init() { + netio_protoent_mutex = sync.new_mutex() +} + +fn cleanup() { + netio_protoent_mutex.destroy() + unsafe { free(netio_protoent_mutex) } +} + +// The socket address family type. +// See [address_families(7)](https://www.man7.org/linux/man-pages/man7/address_families.7.html). +pub type AddrFamily = u16 + +// The socket type. +pub type SocketType = int + +// The socket level type. +pub type SocketLevel = int + +// The socket option type. +pub type SocketOption = int diff --git a/option.v b/option.v new file mode 100644 index 0000000..c621b02 --- /dev/null +++ b/option.v @@ -0,0 +1 @@ +module netio diff --git a/protocol.c.v b/protocol.c.v new file mode 100644 index 0000000..6f37309 --- /dev/null +++ b/protocol.c.v @@ -0,0 +1,104 @@ +@[has_globals] +module netio + +import os +import sync + +// Mutex for accessing to protocol entries via getprotoent(3). +__global netio_protoent_mutex &sync.Mutex + +struct C.protoent { + p_name &char + p_aliases &&char + p_proto i32 +} + +fn C.getprotoent() &C.protoent +fn C.getprotobyname(&char) &C.protoent +fn C.getprotobynumber(i32) &C.protoent +fn C.setprotoent(i32) +fn C.endprotoent() + +// The protocol number type. +// See [protocols(5)](https://man7.org/linux/man-pages/man5/protocols.5.html), +// and [getprotoent(3)](https://man7.org/linux/man-pages/man3/getprotoent.3.html) for details. +pub type Protocol = int + +// entry returns the protocol entry from database. +pub fn (p Protocol) entry() !ProtocolEntry { + return protocol_by_number(p)! +} + +pub struct ProtocolEntry { +pub: + name string // The official name of protocol. + aliases []string // List of alternative names for the protocol. + number int // The protocol number. +} + +fn make_proto(ent C.protoent) ProtocolEntry { + mut aliases := []string{} + if unsafe { ent.p_aliases[0] != nil } { + mut ptr := *ent.p_aliases + mut nullterm := 1 + for { + if *ptr == 0 { + break + } + str := unsafe { cstring_to_vstring(ptr) } + ptr = unsafe { ptr + str.len + nullterm } + nullterm++ + aliases << str + } + } + return ProtocolEntry{ + name: unsafe { cstring_to_vstring(ent.p_name) } + aliases: aliases + number: int(ent.p_proto) + } +} + +// protocols returns all protocol entries from database in arbitrary order. +pub fn protocols() []ProtocolEntry { + netio_protoent_mutex.@lock() + C.setprotoent(1) + defer { + C.endprotoent() + netio_protoent_mutex.unlock() + } + mut protos := []ProtocolEntry{} + for { + proto := C.getprotoent() + if isnil(proto) { + break + } + protos << make_proto(proto) + } + return protos +} + +// protocol_by_name returns the protocol entry by name e.g. 'tcp', 'icmp'. +pub fn protocol_by_name(name string) !ProtocolEntry { + netio_protoent_mutex.@lock() + defer { + netio_protoent_mutex.unlock() + } + proto := C.getprotobyname(&char(name.str)) + if isnil(proto) { + return os.last_error() + } + return make_proto(proto) +} + +// protocol_by_number returns the protocol entry by protocol number. +pub fn protocol_by_number(num int) !ProtocolEntry { + netio_protoent_mutex.@lock() + defer { + netio_protoent_mutex.unlock() + } + proto := C.getprotobynumber(num) + if isnil(proto) { + return os.last_error() + } + return make_proto(proto) +} diff --git a/so_darwin.c.v b/so_darwin.c.v new file mode 100644 index 0000000..35cf7ff --- /dev/null +++ b/so_darwin.c.v @@ -0,0 +1,47 @@ +module netio + +/* + Socket options defined on Darwin. +*/ + +pub const so_acceptconn = SocketOption(C.SO_ACCEPTCONN) +pub const so_bindtodevice = SocketOption(C.SO_BINDTODEVICE) +pub const so_broadcast = SocketOption(C.SO_BROADCAST) +pub const so_debug = SocketOption(C.SO_DEBUG) +pub const so_dontroute = SocketOption(C.SO_DONTROUTE) +pub const so_donttrunc = SocketOption(C.SO_DONTTRUNC) +pub const so_error = SocketOption(C.SO_ERROR) +pub const so_keepalive = SocketOption(C.SO_KEEPALIVE) +pub const so_label = SocketOption(C.SO_LABEL) +pub const so_linger = SocketOption(C.SO_LINGER) +pub const so_linger_sec = SocketOption(C.SO_LINGER_SEC) +pub const so_netsvc_marking_level = SocketOption(C.SO_NETSVC_MARKING_LEVEL) +pub const so_net_service_type = SocketOption(C.SO_NET_SERVICE_TYPE) +pub const so_nke = SocketOption(C.SO_NKE) +pub const so_noaddrerr = SocketOption(C.SO_NOADDRERR) +pub const so_nosigpipe = SocketOption(C.SO_NOSIGPIPE) +pub const so_notifyconflict = SocketOption(C.SO_NOTIFYCONFLICT) +pub const so_np_extensions = SocketOption(C.SO_NP_EXTENSIONS) +pub const so_nread = SocketOption(C.SO_NREAD) +pub const so_numrcvpkt = SocketOption(C.SO_NUMRCVPKT) +pub const so_nwrite = SocketOption(C.SO_NWRITE) +pub const so_oobinline = SocketOption(C.SO_OOBINLINE) +pub const so_peerlabel = SocketOption(C.SO_PEERLABEL) +pub const so_randomport = SocketOption(C.SO_RANDOMPORT) +pub const so_rcvbuf = SocketOption(C.SO_RCVBUF) +pub const so_rcvlowat = SocketOption(C.SO_RCVLOWAT) +pub const so_rcvtimeo = SocketOption(C.SO_RCVTIMEO) +pub const so_resolver_signature = SocketOption(C.SO_RESOLVER_SIGNATURE) +pub const so_reuseaddr = SocketOption(C.SO_REUSEADDR) +pub const so_reuseport = SocketOption(C.SO_REUSEPORT) +pub const so_reuseshareuid = SocketOption(C.SO_REUSESHAREUID) +pub const so_sndbuf = SocketOption(C.SO_SNDBUF) +pub const so_sndlowat = SocketOption(C.SO_SNDLOWAT) +pub const so_sndtimeo = SocketOption(C.SO_SNDTIMEO) +pub const so_timestamp = SocketOption(C.SO_TIMESTAMP) +pub const so_timestamp_monotonic = SocketOption(C.SO_TIMESTAMP_MONOTONIC) +pub const so_type = SocketOption(C.SO_TYPE) +pub const so_upcallclosewait = SocketOption(C.SO_UPCALLCLOSEWAIT) +pub const so_useloopback = SocketOption(C.SO_USELOOPBACK) +pub const so_wantmore = SocketOption(C.SO_WANTMORE) +pub const so_wantoobflag = SocketOption(C.SO_WANTOOBFLAG) diff --git a/so_freebsd.c.v b/so_freebsd.c.v new file mode 100644 index 0000000..ea6c3c0 --- /dev/null +++ b/so_freebsd.c.v @@ -0,0 +1,53 @@ +module netio + +/* + Socket options defined on FreeBSD. +*/ + +pub const so_acceptconn = SocketOption(C.SO_ACCEPTCONN) +pub const so_acceptfilter = SocketOption(C.SO_ACCEPTFILTER) +pub const so_bintime = SocketOption(C.SO_BINTIME) +pub const so_broadcast = SocketOption(C.SO_BROADCAST) +pub const so_debug = SocketOption(C.SO_DEBUG) +pub const so_domain = SocketOption(C.SO_DOMAIN) +pub const so_dontroute = SocketOption(C.SO_DONTROUTE) +pub const so_error = SocketOption(C.SO_ERROR) +pub const so_fib = SocketOption(C.SO_FIB) +pub const so_keepalive = SocketOption(C.SO_KEEPALIVE) +pub const so_label = SocketOption(C.SO_LABEL) +pub const so_linger = SocketOption(C.SO_LINGER) +pub const so_listenincqlen = SocketOption(C.SO_LISTENINCQLEN) +pub const so_listenqlen = SocketOption(C.SO_LISTENQLEN) +pub const so_listenqlimit = SocketOption(C.SO_LISTENQLIMIT) +pub const so_max_pacing_rate = SocketOption(C.SO_MAX_PACING_RATE) +pub const so_nosigpipe = SocketOption(C.SO_NOSIGPIPE) +pub const so_no_ddp = SocketOption(C.SO_NO_DDP) +pub const so_no_offload = SocketOption(C.SO_NO_OFFLOAD) +pub const so_oobinline = SocketOption(C.SO_OOBINLINE) +pub const so_peerlabel = SocketOption(C.SO_PEERLABEL) +pub const so_protocol = SocketOption(C.SO_PROTOCOL) +pub const so_prototype = SocketOption(C.SO_PROTOTYPE) +pub const so_rcvbuf = SocketOption(C.SO_RCVBUF) +pub const so_rcvlowat = SocketOption(C.SO_RCVLOWAT) +pub const so_rcvtimeo = SocketOption(C.SO_RCVTIMEO) +pub const so_rerror = SocketOption(C.SO_RERROR) +pub const so_reuseaddr = SocketOption(C.SO_REUSEADDR) +pub const so_reuseport = SocketOption(C.SO_REUSEPORT) +pub const so_reuseport_lb = SocketOption(C.SO_REUSEPORT_LB) +pub const so_setfib = SocketOption(C.SO_SETFIB) +pub const so_sndbuf = SocketOption(C.SO_SNDBUF) +pub const so_sndlowat = SocketOption(C.SO_SNDLOWAT) +pub const so_sndtimeo = SocketOption(C.SO_SNDTIMEO) +pub const so_splice = SocketOption(C.SO_SPLICE) +pub const so_timestamp = SocketOption(C.SO_TIMESTAMP) +pub const so_ts_bintime = SocketOption(C.SO_TS_BINTIME) +pub const so_ts_clock = SocketOption(C.SO_TS_CLOCK) +pub const so_ts_clock_max = SocketOption(C.SO_TS_CLOCK_MAX) +pub const so_ts_default = SocketOption(C.SO_TS_DEFAULT) +pub const so_ts_monotonic = SocketOption(C.SO_TS_MONOTONIC) +pub const so_ts_realtime = SocketOption(C.SO_TS_REALTIME) +pub const so_ts_realtime_micro = SocketOption(C.SO_TS_REALTIME_MICRO) +pub const so_type = SocketOption(C.SO_TYPE) +pub const so_useloopback = SocketOption(C.SO_USELOOPBACK) +pub const so_user_cookie = SocketOption(C.SO_USER_COOKIE) +pub const so_vendor = SocketOption(C.SO_VENDOR) diff --git a/so_linux.c.v b/so_linux.c.v new file mode 100644 index 0000000..c233dae --- /dev/null +++ b/so_linux.c.v @@ -0,0 +1,94 @@ +module netio + +/* + Socket options defined on Linux. +*/ + +pub const so_acceptconn = SocketOption(C.SO_ACCEPTCONN) +pub const so_attach_bpf = SocketOption(C.SO_ATTACH_BPF) +pub const so_attach_filter = SocketOption(C.SO_ATTACH_FILTER) +pub const so_attach_reuseport_cbpf = SocketOption(C.SO_ATTACH_REUSEPORT_CBPF) +pub const so_attach_reuseport_ebpf = SocketOption(C.SO_ATTACH_REUSEPORT_EBPF) +pub const so_bindtodevice = SocketOption(C.SO_BINDTODEVICE) +pub const so_bindtoifindex = SocketOption(C.SO_BINDTOIFINDEX) +pub const so_bpf_extensions = SocketOption(C.SO_BPF_EXTENSIONS) +pub const so_broadcast = SocketOption(C.SO_BROADCAST) +pub const so_bsdcompat = SocketOption(C.SO_BSDCOMPAT) +pub const so_buf_lock = SocketOption(C.SO_BUF_LOCK) +pub const so_busy_poll = SocketOption(C.SO_BUSY_POLL) +pub const so_busy_poll_budget = SocketOption(C.SO_BUSY_POLL_BUDGET) +pub const so_cnx_advice = SocketOption(C.SO_CNX_ADVICE) +pub const so_cookie = SocketOption(C.SO_COOKIE) +pub const so_debug = SocketOption(C.SO_DEBUG) +pub const so_detach_bpf = SocketOption(C.SO_DETACH_BPF) +pub const so_detach_filter = SocketOption(C.SO_DETACH_FILTER) +pub const so_detach_reuseport_bpf = SocketOption(C.SO_DETACH_REUSEPORT_BPF) +pub const so_devmem_dmabuf = SocketOption(C.SO_DEVMEM_DMABUF) +pub const so_devmem_dontneed = SocketOption(C.SO_DEVMEM_DONTNEED) +pub const so_devmem_linear = SocketOption(C.SO_DEVMEM_LINEAR) +pub const so_domain = SocketOption(C.SO_DOMAIN) +pub const so_dontroute = SocketOption(C.SO_DONTROUTE) +pub const so_error = SocketOption(C.SO_ERROR) +pub const so_get_filter = SocketOption(C.SO_GET_FILTER) +pub const so_incoming_cpu = SocketOption(C.SO_INCOMING_CPU) +pub const so_incoming_napi_id = SocketOption(C.SO_INCOMING_NAPI_ID) +pub const so_inq = SocketOption(C.SO_INQ) +pub const so_keepalive = SocketOption(C.SO_KEEPALIVE) +pub const so_linger = SocketOption(C.SO_LINGER) +pub const so_lock_filter = SocketOption(C.SO_LOCK_FILTER) +pub const so_mark = SocketOption(C.SO_MARK) +pub const so_max_pacing_rate = SocketOption(C.SO_MAX_PACING_RATE) +pub const so_meminfo = SocketOption(C.SO_MEMINFO) +pub const so_netns_cookie = SocketOption(C.SO_NETNS_COOKIE) +pub const so_nofcs = SocketOption(C.SO_NOFCS) +pub const so_no_check = SocketOption(C.SO_NO_CHECK) +pub const so_oobinline = SocketOption(C.SO_OOBINLINE) +pub const so_passcred = SocketOption(C.SO_PASSCRED) +pub const so_passpidfd = SocketOption(C.SO_PASSPIDFD) +pub const so_passrights = SocketOption(C.SO_PASSRIGHTS) +pub const so_passsec = SocketOption(C.SO_PASSSEC) +pub const so_peek_off = SocketOption(C.SO_PEEK_OFF) +pub const so_peercred = SocketOption(C.SO_PEERCRED) +pub const so_peergroups = SocketOption(C.SO_PEERGROUPS) +pub const so_peername = SocketOption(C.SO_PEERNAME) +pub const so_peerpidfd = SocketOption(C.SO_PEERPIDFD) +pub const so_peersec = SocketOption(C.SO_PEERSEC) +pub const so_prefer_busy_poll = SocketOption(C.SO_PREFER_BUSY_POLL) +pub const so_priority = SocketOption(C.SO_PRIORITY) +pub const so_protocol = SocketOption(C.SO_PROTOCOL) +pub const so_rcvbufforce = SocketOption(C.SO_RCVBUFFORCE) +pub const so_rcvbuf = SocketOption(C.SO_RCVBUF) +pub const so_rcvlowat = SocketOption(C.SO_RCVLOWAT) +pub const so_rcvmark = SocketOption(C.SO_RCVMARK) +pub const so_rcvpriority = SocketOption(C.SO_RCVPRIORITY) +pub const so_rcvtimeo = SocketOption(C.SO_RCVTIMEO) +pub const so_rcvtimeo_new = SocketOption(C.SO_RCVTIMEO_NEW) +pub const so_rcvtimeo_old = SocketOption(C.SO_RCVTIMEO_OLD) +pub const so_reserve_mem = SocketOption(C.SO_RESERVE_MEM) +pub const so_reuseaddr = SocketOption(C.SO_REUSEADDR) +pub const so_reuseport = SocketOption(C.SO_REUSEPORT) +pub const so_rxq_ovfl = SocketOption(C.SO_RXQ_OVFL) +pub const so_security_authentication = SocketOption(C.SO_SECURITY_AUTHENTICATION) +pub const so_security_encryption_network = SocketOption(C.SO_SECURITY_ENCRYPTION_NETWORK) +pub const so_security_encryption_transport = SocketOption(C.SO_SECURITY_ENCRYPTION_TRANSPORT) +pub const so_select_err_queue = SocketOption(C.SO_SELECT_ERR_QUEUE) +pub const so_sndbufforce = SocketOption(C.SO_SNDBUFFORCE) +pub const so_sndbuf = SocketOption(C.SO_SNDBUF) +pub const so_sndlowat = SocketOption(C.SO_SNDLOWAT) +pub const so_sndtimeo = SocketOption(C.SO_SNDTIMEO) +pub const so_sndtimeo_new = SocketOption(C.SO_SNDTIMEO_NEW) +pub const so_sndtimeo_old = SocketOption(C.SO_SNDTIMEO_OLD) +pub const so_timestamping = SocketOption(C.SO_TIMESTAMPING) +pub const so_timestamping_new = SocketOption(C.SO_TIMESTAMPING_NEW) +pub const so_timestamping_old = SocketOption(C.SO_TIMESTAMPING_OLD) +pub const so_timestampns = SocketOption(C.SO_TIMESTAMPNS) +pub const so_timestampns_new = SocketOption(C.SO_TIMESTAMPNS_NEW) +pub const so_timestampns_old = SocketOption(C.SO_TIMESTAMPNS_OLD) +pub const so_timestamp = SocketOption(C.SO_TIMESTAMP) +pub const so_timestamp_new = SocketOption(C.SO_TIMESTAMP_NEW) +pub const so_timestamp_old = SocketOption(C.SO_TIMESTAMP_OLD) +pub const so_txrehash = SocketOption(C.SO_TXREHASH) +pub const so_txtime = SocketOption(C.SO_TXTIME) +pub const so_type = SocketOption(C.SO_TYPE) +pub const so_wifi_status = SocketOption(C.SO_WIFI_STATUS) +pub const so_zerocopy = SocketOption(C.SO_ZEROCOPY) diff --git a/sock_default.c.v b/sock_default.c.v new file mode 100644 index 0000000..c4f2f56 --- /dev/null +++ b/sock_default.c.v @@ -0,0 +1,11 @@ +module netio + +/* + Well defined socket types. +*/ + +pub const sock_stream = SocketType(C.SOCK_STREAM) +pub const sock_dgram = SocketType(C.SOCK_DGRAM) +pub const sock_seqpacket = SocketType(C.SOCK_SEQPACKET) +pub const sock_raw = SocketType(C.SOCK_RAW) +pub const sock_rdm = SocketType(C.SOCK_RDM) diff --git a/sock_linux.c.v b/sock_linux.c.v new file mode 100644 index 0000000..50056e6 --- /dev/null +++ b/sock_linux.c.v @@ -0,0 +1,13 @@ +module netio + +/* + Socket types defined on Linux. +*/ + +pub const sock_stream = SocketType(C.SOCK_STREAM) +pub const sock_dgram = SocketType(C.SOCK_DGRAM) +pub const sock_seqpacket = SocketType(C.SOCK_SEQPACKET) +pub const sock_raw = SocketType(C.SOCK_RAW) +pub const sock_rdm = SocketType(C.SOCK_RDM) +pub const sock_nonblock = SocketType(C.SOCK_NONBLOCK) +pub const sock_cloexec = SocketType(C.SOCK_CLOEXEC) diff --git a/socket.c.v b/socket.c.v new file mode 100644 index 0000000..4b559db --- /dev/null +++ b/socket.c.v @@ -0,0 +1,92 @@ +module netio + +import os + +#include + +fn C.socket(i32, i32, i32) i32 +fn C.bind(i32, voidptr, i32) i32 +fn C.connect(i32, voidptr, i32) i32 +fn C.listen(i32, i32) i32 +fn C.accept(i32, voidptr, i32) i32 +fn C.shutdown(i32, i32) i32 +fn C.close(i32) i32 +fn C.setsockopt(i32, i32, i32, voidptr, i32) i32 +fn C.getsockopt(i32, i32, i32, voidptr, i32) i32 + +pub struct Socket { +pub: + fd int +} + +// Socket.new creates new socket. +// See [socket(7)](https://www.man7.org/linux/man-pages/man7/socket.7.html) and +// [socket(3)](https://man7.org/linux/man-pages/man3/socket.3p.html) for details. +pub fn Socket.new(domain AddrFamily, typ SocketType, protocol Protocol) !Socket { + fd := C.socket(i32(domain), i32(typ), i32(protocol)) + if fd == -1 { + return os.last_error() + } + return Socket{ + fd: fd + } +} + +// Socket shutdown modes. See [shutdown(3p)](https://man7.org/linux/man-pages/man3/shutdown.3p.html) for details. +pub enum Shutdown { + read = C.SHUT_RD + write = C.SHUT_WR + read_and_write = C.SHUT_RDWR +} + +// connect connects a socket. +pub fn (s Socket) connect(addr SocketAddr) ! { + if C.connect(s.fd, addr.ptr(), addr.size()) == -1 { + return os.last_error() + } +} + +// bind binds a name to a socket. +pub fn (s Socket) bind(addr SocketAddr) ! { + if C.bind(s.fd, addr.ptr(), addr.size()) == -1 { + return os.last_error() + } +} + +// listen starts listening for socket connections and limit the queue of incoming connections. +pub fn (s Socket) listen(backlog int) ! { + if C.listen(s.fd, backlog) == -1 { + return os.last_error() + } +} + +// accept accepts a new connection on a socket. +pub fn (s Socket) accept() !Socket { + new_fd := C.accept(s.fd, 0, 0) + if new_fd == -1 { + return os.last_error() + } + return Socket{ + fd: new_fd + } +} + +// set_option sets the socket option. +pub fn (s Socket) set_option(level SocketLevel, option SocketOption, value int) ! {} + +// get_option gets the socket option. +pub fn (s Socket) get_option(level SocketLevel, option SocketOption) ! {} + +// shutdown shut downs socket send and receive operations. +pub fn (s Socket) shutdown(how Shutdown) ! { + if C.shutdown(s.fd, i32(how)) == -1 { + return os.last_error() + } +} + +// close closes the socket. +pub fn (s Socket) close() ! { + if C.close(s.fd) == -1 { + return os.last_error() + } +} diff --git a/sol_default.c.v b/sol_default.c.v new file mode 100644 index 0000000..66ff9c1 --- /dev/null +++ b/sol_default.c.v @@ -0,0 +1,7 @@ +module netio + +/* + Well defined socket levels. +*/ + +pub const sol_socket = C.SOL_SOCKET diff --git a/sol_linux.c.v b/sol_linux.c.v new file mode 100644 index 0000000..bdb3ab8 --- /dev/null +++ b/sol_linux.c.v @@ -0,0 +1,35 @@ +module netio + +/* + Socket levels defined on Linux. +*/ + +pub const sol_aal = SocketOption(C.SOL_AAL) +pub const sol_alg = SocketOption(C.SOL_ALG) +pub const sol_atm = SocketOption(C.SOL_ATM) +pub const sol_bluetooth = SocketOption(C.SOL_BLUETOOTH) +pub const sol_caif = SocketOption(C.SOL_CAIF) +pub const sol_dccp = SocketOption(C.SOL_DCCP) +pub const sol_decnet = SocketOption(C.SOL_DECNET) +pub const sol_irda = SocketOption(C.SOL_IRDA) +pub const sol_iucv = SocketOption(C.SOL_IUCV) +pub const sol_kcm = SocketOption(C.SOL_KCM) +pub const sol_llc = SocketOption(C.SOL_LLC) +pub const sol_mctp = SocketOption(C.SOL_MCTP) +pub const sol_mptcp = SocketOption(C.SOL_MPTCP) +pub const sol_netbeui = SocketOption(C.SOL_NETBEUI) +pub const sol_netlink = SocketOption(C.SOL_NETLINK) +pub const sol_nfc = SocketOption(C.SOL_NFC) +pub const sol_packet = SocketOption(C.SOL_PACKET) +pub const sol_pnpipe = SocketOption(C.SOL_PNPIPE) +pub const sol_pppol2tp = SocketOption(C.SOL_PPPOL2TP) +pub const sol_raw = SocketOption(C.SOL_RAW) +pub const sol_rds = SocketOption(C.SOL_RDS) +pub const sol_rxrpc = SocketOption(C.SOL_RXRPC) +pub const sol_smc = SocketOption(C.SOL_SMC) +pub const sol_socket = SocketOption(C.SOL_SOCKET) +pub const sol_tipc = SocketOption(C.SOL_TIPC) +pub const sol_tls = SocketOption(C.SOL_TLS) +pub const sol_vsock = SocketOption(C.SOL_VSOCK) +pub const sol_x25 = SocketOption(C.SOL_X25) +pub const sol_xdp = SocketOption(C.SOL_XDP) diff --git a/tcp.v b/tcp.v new file mode 100644 index 0000000..08ba4cf --- /dev/null +++ b/tcp.v @@ -0,0 +1,5 @@ +module netio + +pub struct TCPListener {} + +pub struct TCPStream {} diff --git a/udp.v b/udp.v new file mode 100644 index 0000000..7520b33 --- /dev/null +++ b/udp.v @@ -0,0 +1,3 @@ +module netio + +pub struct UDPSocket {} diff --git a/v.mod b/v.mod new file mode 100644 index 0000000..2313966 --- /dev/null +++ b/v.mod @@ -0,0 +1,7 @@ +Module { + name: 'netio' + description: 'Networking library' + version: '0.0.0' + license: 'MIT' + dependencies: [] +}