Browse Source

Implement POSIX linux support for poll and netinet_tcp. Incomplete support for netinet/in.

Isaac Andrade 11 months ago
parent
commit
f072136c04
3 changed files with 196 additions and 2 deletions
  1. 168 0
      core/sys/posix/netinet_in.odin
  2. 1 1
      core/sys/posix/netinet_tcp.odin
  3. 27 1
      core/sys/posix/poll.odin

+ 168 - 0
core/sys/posix/netinet_in.odin

@@ -194,6 +194,174 @@ when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS
 		)
 		)
 	}
 	}
 
 
+} else when ODIN_OS == .Linux {
+
+	in_addr :: struct {
+		s_addr: in_addr_t, /* [PSX] big endian address */
+	}
+
+	in6_addr :: struct {
+		using _: struct #raw_union {
+			s6_addr:     [16]c.uint8_t, /* [PSX] big endian address */
+			__u6_addr16: [8]c.uint16_t,
+			__u6_addr32: [4]c.uint32_t,
+		},
+	}
+
+	sockaddr_in :: struct {
+		sin_family: sa_family_t, /* [PSX] AF_INET (but a smaller size) */
+		sin_port:   in_port_t,   /* [PSX] port number */
+		sin_addr:   in_addr,     /* [PSX] IP address */
+		sin_zero: [size_of(sockaddr) -
+			u16 -
+			size_of(in_port_t) -
+			size_of(in_addr)]c.char,
+	}
+
+	sockaddr_in6 :: struct {
+		sin6_family:   sa_family_t, /* [PSX] AF_INET6 (but a smaller size) */
+		sin6_port:     in_port_t,   /* [PSX] port number */
+		sin6_flowinfo: u32be,  /* [PSX] IPv6 traffic class and flow information */
+		sin6_addr:     in6_addr,    /* [PSX] IPv6 address */
+		sin6_scope_id: c.uint32_t,  /* [PSX] set of interfaces for a scope */
+	}
+
+	ipv6_mreq :: struct {
+		ipv6mr_multiaddr: in6_addr, /* [PSX] IPv6 multicast address */
+		ipv6mr_interface: c.int,   /* [PSX] interface index */
+	}
+
+	IPPROTO_IP   :: 0
+	IPPROTO_ICMP :: 1
+	IPPROTO_IPV6 :: 41
+	IPPROTO_RAW  :: 255
+	IPPROTO_TCP  :: 6
+	IPPROTO_UDP  :: 17
+
+	INADDR_ANY       :: 0x00000000
+	INADDR_BROADCAST :: 0xFFFFFFFF
+
+	IPV6_MULTICAST_IF   :: 17
+	IPV6_UNICAST_HOPS   :: 16
+	IPV6_MULTICAST_HOPS :: 18
+	IPV6_MULTICAST_LOOP :: 19
+	IPV6_JOIN_GROUP     :: 20
+	IPV6_LEAVE_GROUP    :: 21
+	IPV6_V6ONLY         :: 26
+
+	// TODO: (Isaac Andrade, 2024-09-02) Copied from the BSDs block above. Needs to be implemented for Linux.
+	// Get mentoring from a more senior C and Odin developer or leave this to one of them.
+
+	//IN6_IS_ADDR_UNSPECIFIED :: #force_inline proc "contextless" (a: in6_addr) -> b32 {
+	//	return a.s6_addr == 0
+	//}
+	//
+	//IN6_IS_ADDR_LOOPBACK :: #force_inline proc "contextless" (a: in6_addr) -> b32 {
+	//	a := a
+	//	return (
+	//		(^c.uint32_t)(&a.s6_addr[0])^  == 0 &&
+	//		(^c.uint32_t)(&a.s6_addr[4])^  == 0 &&
+	//		(^c.uint32_t)(&a.s6_addr[8])^  == 0 &&
+	//		(^u32be)(&a.s6_addr[12])^ == 1 \
+	//	)
+	//}
+	//
+	//IN6_IS_ADDR_MULTICAST :: #force_inline proc "contextless" (a: in6_addr) -> b32 {
+	//	return a.s6_addr[0] == 0xff
+	//}
+	//
+	//IN6_IS_ADDR_LINKLOCAL :: #force_inline proc "contextless" (a: in6_addr) -> b32 {
+	//	return a.s6_addr[0] == 0xfe && a.s6_addr[1] & 0xc0 == 0x80
+	//}
+	//
+	//IN6_IS_ADDR_SITELOCAL :: #force_inline proc "contextless" (a: in6_addr) -> b32 {
+	//	return a.s6_addr[0] == 0xfe && a.s6_addr[1] & 0xc0 == 0xc0
+	//}
+	//
+	//IN6_IS_ADDR_V4MAPPED :: #force_inline proc "contextless" (a: in6_addr) -> b32 {
+	//	a := a
+	//	return (
+	//		(^c.uint32_t)(&a.s6_addr[0])^ == 0 &&
+	//		(^c.uint32_t)(&a.s6_addr[4])^ == 0 &&
+	//		(^u32be)(&a.s6_addr[8])^ == 0x0000ffff \
+	//	)
+	//}
+	//
+	//IN6_IS_ADDR_V4COMPAT :: #force_inline proc "contextless" (a: in6_addr) -> b32 {
+	//	a := a
+	//	return (
+	//		(^c.uint32_t)(&a.s6_addr[0])^  == 0 &&
+	//		(^c.uint32_t)(&a.s6_addr[4])^  == 0 &&
+	//		(^c.uint32_t)(&a.s6_addr[8])^  == 0 &&
+	//		(^c.uint32_t)(&a.s6_addr[12])^ != 0 &&
+	//		(^u32be)(&a.s6_addr[12])^ != 1 \
+	//	)
+	//}
+	//
+	//@(private)
+	//__IPV6_ADDR_SCOPE_NODELOCAL :: 0x01
+	//@(private)
+	//__IPV6_ADDR_SCOPE_LINKLOCAL :: 0x02
+	//@(private)
+	//__IPV6_ADDR_SCOPE_SITELOCAL :: 0x05
+	//@(private)
+	//__IPV6_ADDR_SCOPE_ORGLOCAL  :: 0x08
+	//@(private)
+	//__IPV6_ADDR_SCOPE_GLOBAL    :: 0x0e
+	//
+	//@(private)
+	//IPV6_ADDR_MC_FLAGS :: #force_inline proc "contextless" (a: in6_addr) -> c.uint8_t {
+	//	return a.s6_addr[1] & 0xf0
+	//}
+	//
+	//@(private)
+	//IPV6_ADDR_MC_FLAGS_TRANSIENT     :: 0x10
+	//@(private)
+	//IPV6_ADDR_MC_FLAGS_PREFIX        :: 0x20
+	//@(private)
+	//IPV6_ADDR_MC_FLAGS_UNICAST_BASED :: IPV6_ADDR_MC_FLAGS_TRANSIENT | IPV6_ADDR_MC_FLAGS_PREFIX
+	//
+	//@(private)
+	//__IPV6_ADDR_MC_SCOPE :: #force_inline proc "contextless" (a: in6_addr) -> c.uint8_t {
+	//	return a.s6_addr[1] & 0x0f
+	//}
+	//
+	//IN6_IS_ADDR_MC_NODELOCAL :: #force_inline proc "contextless" (a: in6_addr) -> b32 {
+	//	return (
+	//		IN6_IS_ADDR_MULTICAST(a) &&
+	//		(__IPV6_ADDR_MC_SCOPE(a) == __IPV6_ADDR_SCOPE_NODELOCAL) \
+	//	)
+	//}
+	//
+	//IN6_IS_ADDR_MC_LINKLOCAL :: #force_inline proc "contextless" (a: in6_addr) -> b32 {
+	//	return (
+	//		IN6_IS_ADDR_MULTICAST(a) &&
+	//		(IPV6_ADDR_MC_FLAGS(a) != IPV6_ADDR_MC_FLAGS_UNICAST_BASED) &&
+	//		(__IPV6_ADDR_MC_SCOPE(a) == __IPV6_ADDR_SCOPE_LINKLOCAL) \
+	//	)
+	//}
+	//
+	//IN6_IS_ADDR_MC_SITELOCAL :: #force_inline proc "contextless" (a: in6_addr) -> b32 {
+	//	return (
+	//		IN6_IS_ADDR_MULTICAST(a) &&
+	//		(__IPV6_ADDR_MC_SCOPE(a) == __IPV6_ADDR_SCOPE_SITELOCAL) \
+	//	)
+	//}
+	//
+	//IN6_IS_ADDR_MC_ORGLOCAL :: #force_inline proc "contextless" (a: in6_addr) -> b32 {
+	//	return (
+	//		IN6_IS_ADDR_MULTICAST(a) &&
+	//		(__IPV6_ADDR_MC_SCOPE(a) == __IPV6_ADDR_SCOPE_ORGLOCAL) \
+	//	)
+	//}
+	//
+	//IN6_IS_ADDR_MC_GLOBAL :: #force_inline proc "contextless" (a: in6_addr) -> b32 {
+	//	return (
+	//		IN6_IS_ADDR_MULTICAST(a) &&
+	//		(__IPV6_ADDR_MC_SCOPE(a) == __IPV6_ADDR_SCOPE_GLOBAL) \
+	//	)
+	//}
+
 } else {
 } else {
 	#panic("posix is unimplemented for the current target")
 	#panic("posix is unimplemented for the current target")
 }
 }

+ 1 - 1
core/sys/posix/netinet_tcp.odin

@@ -2,7 +2,7 @@ package posix
 
 
 // netinet/tcp.h - definitions for the Internet Transmission Control Protocol (TCP)
 // netinet/tcp.h - definitions for the Internet Transmission Control Protocol (TCP)
 
 
-when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD {
+when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD || ODIN_OS == .Linux {
 
 
 	TCP_NODELAY :: 0x01
 	TCP_NODELAY :: 0x01
 
 

+ 27 - 1
core/sys/posix/poll.odin

@@ -21,11 +21,17 @@ foreign lib {
 
 
 	[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/poll.html ]]
 	[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/poll.html ]]
 	*/
 	*/
-	poll :: proc(fds: [^]pollfd, nfds: nfds_t, timeout: c.int) -> c.int ---
+	poll :: proc(fds: [^]pollfd, nfds: nfds_t, timeout: c.int) -> Poll_Error ---
 }
 }
 
 
 nfds_t :: c.uint
 nfds_t :: c.uint
 
 
+Poll_Error :: enum c.int {
+	EAGAIN = Errno.EAGAIN,
+	EINTR  = Errno.EINTR,
+	EINVAL = Errno.EINVAL,
+}
+
 Poll_Event_Bits :: enum c.short {
 Poll_Event_Bits :: enum c.short {
 	// Data other than high-priority data may be read without blocking.
 	// Data other than high-priority data may be read without blocking.
 	IN     = log2(POLLIN),
 	IN     = log2(POLLIN),
@@ -72,6 +78,26 @@ when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS
 	POLLHUP    :: 0x0010
 	POLLHUP    :: 0x0010
 	POLLNVAL   :: 0x0020
 	POLLNVAL   :: 0x0020
 
 
+} else when ODIN_OS == .Linux {
+
+	pollfd :: struct {
+		fd:      FD,         /* [PSX] the following descriptor being polled */
+		events:  Poll_Event, /* [PSX] the input event flags */
+		revents: Poll_Event, /* [PSX] the output event flags */
+	}
+
+	POLLIN     :: 0x0001
+	POLLRDNORM :: 0x0040
+	POLLRDBAND :: 0x0080
+	POLLPRI    :: 0x0002
+	POLLOUT    :: 0x0004
+	POLLWRNORM :: 0x0100
+	POLLWRBAND :: 0x0200
+
+	POLLERR    :: 0x0008
+	POLLHUP    :: 0x0010
+	POLLNVAL   :: 0x0020
+
 } else {
 } else {
 	#panic("posix is unimplemented for the current target")
 	#panic("posix is unimplemented for the current target")
 }
 }