This commit is contained in:
ge
2026-04-13 04:02:42 +03:00
parent 2d2281b8cc
commit 7b17a4a33b
9 changed files with 253 additions and 73 deletions
+43 -19
View File
@@ -2,6 +2,8 @@ module netio
import encoding.binary
struct C.sockaddr_storage {}
// max_unix_path_size value is used to pad the sockaddr_un struct.
const max_unix_path_size = $if linux {
108
@@ -11,6 +13,13 @@ const max_unix_path_size = $if linux {
104
}
pub struct SocketAddr {
mut:
data &u8 = unsafe { nil }
len int
pos int
}
// SocketAddr.ipv4 creates new AF_INET socket address.
// addr must be set in network (big-endian) byte order.
pub fn SocketAddr.ipv4(addr [4]u8, port u16) SocketAddr {
@@ -54,14 +63,14 @@ pub fn SocketAddr.unix(path string) !SocketAddr {
// the address itself, you need to do that manually. The benefit is that you can create the
// any kind of socket address.
//
// SocketAddr is a "constructor" for
// SocketAddr is a builder 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`.
// Use this function only if you understand what you do. Using the `push()` method you must
// 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
@@ -118,6 +127,9 @@ pub fn SocketAddr.new(af AddrFamily, size isize) SocketAddr {
// SocketAddr.from_ptr creates new socket address by copying data from specified pointer.
@[unsafe]
pub fn SocketAddr.from_ptr(ptr voidptr, size isize) !SocketAddr {
if isnil(ptr) {
return error('${@METHOD}: cannot accept nil ptr')
}
data := unsafe { vcalloc(usize(size)) }
unsafe {
vmemcpy(data, ptr, size)
@@ -128,25 +140,37 @@ pub fn SocketAddr.from_ptr(ptr voidptr, size isize) !SocketAddr {
}
}
pub struct SocketAddr {
mut:
data &u8 = unsafe { nil }
len int
pos int
}
// family returns the socket address family.
// Note: It returns 0 if socket address is nil, see also `is_empty()`.
pub fn (a SocketAddr) family() AddrFamily {
mut f := AddrFamily(0)
if isnil(a.data) {
return 0
}
mut f := 0
unsafe { vmemcpy(&f, a.data, isize(2)) }
return f
}
// is_empty returns true if socket address is unspecified — the data pointer is nil or
// data contains only zeros. Empty address cannot be used in `bind` and `connect` calls.
pub fn (a SocketAddr) is_empty() bool {
if isnil(a.data) {
return true
}
if a.u8_array().all(|e| e == 0) {
return true
}
return false
}
// push appends the `inp` bytes into internal data buffer.
@[unsafe]
pub fn (mut a SocketAddr) push(inp []u8) ! {
if isnil(a.data) {
return error('${@METHOD}: SocketAddr is nil')
}
if a.pos + inp.len > a.len {
return error('push: data overflow')
return error('${@METHOD}: data overflow')
}
mut i := 0
for a.pos + 1 < a.len {
@@ -180,9 +204,9 @@ pub fn (a SocketAddr) u8_array() []u8 {
// str returns the string representation of socket address.
// Supported address families are AF_INET, AF_INET6, and AF_UNIX.
// For others a string like 'SocketAddr(0x00000000)' will be returned.
// Examples: '172.16.16.132:1080', '[fdf1:72d1:0033:0000:0000:0000:0000:0247]:25535,
// '/run/app.sock'. See also `translate_name()`.
// Examples: '172.16.16.132:1080', '[fdf1:72d1:0033:0000:0000:0000:0000:0247]:25535',
// '/run/app.sock'. For others a string like 'SocketAddr(0x00000000)' will be returned.
// See also `translate_name()`.
pub fn (a SocketAddr) str() string {
match a.family() {
af_inet {