module Runtime.NativeSocketEndpoint import Compiler.MachineX86Native import Compiler.MachineX86NativeAssembly import Runtime.NativeDescriptor import Runtime.NativeSocketRoutine import Runtime.NativePhysicalNative import Std.List import Std.Natural -- Linux x86-64 endpoint operations. connect uses the stream ABI's fd/address/ -- extent/timeout/attempt registers; accept uses fd/unused/1/timeout/attempts. -- Both require O_NONBLOCK before any potentially blocking operation. The -- caller retains descriptor ownership on error and must close/abandon it. -- A successful accept returns an owned nonblocking, close-on-exec descriptor. -- The common poll budget covers retries and readiness races; it is not yet a -- session-wide monotonic deadline. No retry makes a failed connection usable. -- Sources, checked 2026-10-02: Linux UAPI asm/unistd_64.h, asm-generic/fcntl.h, -- asm-generic/socket.h; https://man7.org/linux/man-pages/man2/connect.2.html -- and https://man7.org/linux/man-pages/man2/accept.2.html. -- The common pollfd storage becomes SO_ERROR(int) + socklen_t after poll: -- these lifetimes do not overlap and both views occupy exactly eight bytes. def nativeSocketNonblock : Nat = 2048 def nativeSocketCloseOnExec : Nat = 524288 def nativeSocketEndpointFlags = (naturalAdd nativeSocketNonblock nativeSocketCloseOnExec) def nativeSocketRequireNonblocking = (lambda unrestricted tail : (family X86NativeAssembly) . (nativePhysicalNativeEmit (nativePhysicalNativeMove (constructor X86NativeRegister64 X86NativeRBX) (constructor X86NativeRegister64 X86NativeRDI)) (nativePhysicalNativeEmit (nativePhysicalNativeMoveImmediate32 (constructor X86NativeRegister64 X86NativeRSI) (nativeSocketImmediate 3)) (nativePhysicalNativeEmit (nativePhysicalNativeMoveImmediate32 (constructor X86NativeRegister64 X86NativeRAX) (nativeSocketImmediate 72)) (nativePhysicalNativeEmit nativePhysicalNativeSystemCallInstruction (nativePhysicalNativeEmit (nativePhysicalNativeTest (constructor X86NativeRegister64 X86NativeRAX) (constructor X86NativeRegister64 X86NativeRAX)) (nativePhysicalNativeJumpCondition (constructor X86NativeCondition X86NativeConditionSign) b"socket-return" (nativePhysicalNativeEmit (constructor X86NativeInstruction X86NativeAndImmediate64 (constructor X86NativeRegister64 X86NativeRAX) (nativeSocketImmediate nativeSocketNonblock)) (nativePhysicalNativeEmit (nativePhysicalNativeTest (constructor X86NativeRegister64 X86NativeRAX) (constructor X86NativeRegister64 X86NativeRAX)) (nativePhysicalNativeJumpCondition (constructor X86NativeCondition X86NativeConditionZero) b"socket-invalid" tail)))))))))) -- Initiate once, then wait only for EINPROGRESS. A failed connect never -- reuses an indeterminate socket by trying the address again. def nativeSocketConnectStart = (lambda unrestricted tail : (family X86NativeAssembly) . (nativePhysicalNativeEmit (nativePhysicalNativeMove (constructor X86NativeRegister64 X86NativeRBX) (constructor X86NativeRegister64 X86NativeRDI)) (nativePhysicalNativeEmit (nativePhysicalNativeMove (constructor X86NativeRegister64 X86NativeR12) (constructor X86NativeRegister64 X86NativeRSI)) (nativePhysicalNativeEmit (nativePhysicalNativeMove (constructor X86NativeRegister64 X86NativeR13) (constructor X86NativeRegister64 X86NativeRDX)) (nativePhysicalNativeEmit (nativePhysicalNativeMoveImmediate32 (constructor X86NativeRegister64 X86NativeRAX) (nativeSocketImmediate 42)) (nativePhysicalNativeEmit nativePhysicalNativeSystemCallInstruction (nativePhysicalNativeEmit (nativePhysicalNativeTest (constructor X86NativeRegister64 X86NativeRAX) (constructor X86NativeRegister64 X86NativeRAX)) (nativePhysicalNativeJumpCondition (constructor X86NativeCondition X86NativeConditionZero) b"socket-return" (nativePhysicalNativeEmit (nativePhysicalNativeCompareImmediate (constructor X86NativeRegister64 X86NativeRAX) (nativeSocketImmediate (naturalSaturatingSubtract 4294967296 115))) (nativePhysicalNativeJumpCondition (constructor X86NativeCondition X86NativeConditionZero) b"socket-loop" (nativePhysicalNativeJump b"socket-return" tail))))))))))) -- Writability includes refusal. Read the full int SO_ERROR, negate its errno, -- and only then report success. Reuse the no-longer-live pollfd stack bytes. def nativeSocketReadConnectStatus = (lambda unrestricted tail : (family X86NativeAssembly) . (nativePhysicalNativeEmit (nativePhysicalNativeMoveImmediate32 (constructor X86NativeRegister64 X86NativeRAX) (nativeSocketImmediate 0)) (nativePhysicalNativeEmit (constructor X86NativeInstruction X86NativeStoreMemory32 (constructor X86NativeRegister64 X86NativeRSP) (nativeSocketDisplacement nativeSocketPollSlot) (constructor X86NativeRegister64 X86NativeRAX)) (nativePhysicalNativeEmit (nativePhysicalNativeMoveImmediate32 (constructor X86NativeRegister64 X86NativeRAX) (nativeSocketImmediate nativeSocketPollFdBytes)) (nativePhysicalNativeEmit (constructor X86NativeInstruction X86NativeStoreMemory32 (constructor X86NativeRegister64 X86NativeRSP) (nativeSocketDisplacement nativeSocketPollEventsSlot) (constructor X86NativeRegister64 X86NativeRAX)) (nativePhysicalNativeEmit (nativePhysicalNativeMove (constructor X86NativeRegister64 X86NativeRBX) (constructor X86NativeRegister64 X86NativeRDI)) (nativePhysicalNativeEmit (nativePhysicalNativeMoveImmediate32 (constructor X86NativeRegister64 X86NativeRSI) (nativeSocketImmediate 1)) (nativePhysicalNativeEmit (nativePhysicalNativeMoveImmediate32 (constructor X86NativeRegister64 X86NativeRDX) (nativeSocketImmediate 4)) (nativePhysicalNativeEmit (nativePhysicalNativeMove (constructor X86NativeRegister64 X86NativeRSP) (constructor X86NativeRegister64 X86NativeR10)) (nativePhysicalNativeEmit (nativePhysicalNativeAddImmediate (constructor X86NativeRegister64 X86NativeR10) (nativeSocketImmediate nativeSocketPollSlot)) (nativePhysicalNativeEmit (nativePhysicalNativeMove (constructor X86NativeRegister64 X86NativeRSP) (constructor X86NativeRegister64 X86NativeR8)) (nativePhysicalNativeEmit (nativePhysicalNativeAddImmediate (constructor X86NativeRegister64 X86NativeR8) (nativeSocketImmediate nativeSocketPollEventsSlot)) (nativePhysicalNativeEmit (nativePhysicalNativeMoveImmediate32 (constructor X86NativeRegister64 X86NativeRAX) (nativeSocketImmediate 55)) (nativePhysicalNativeEmit nativePhysicalNativeSystemCallInstruction (nativePhysicalNativeEmit (nativePhysicalNativeCompareImmediate (constructor X86NativeRegister64 X86NativeRAX) (nativeSocketImmediate (naturalSaturatingSubtract 4294967296 4))) (nativePhysicalNativeJumpCondition (constructor X86NativeCondition X86NativeConditionZero) b"socket-loop" (nativePhysicalNativeEmit (nativePhysicalNativeTest (constructor X86NativeRegister64 X86NativeRAX) (constructor X86NativeRegister64 X86NativeRAX)) (nativePhysicalNativeJumpCondition (constructor X86NativeCondition X86NativeConditionSign) b"socket-return" (nativePhysicalNativeEmit (constructor X86NativeInstruction X86NativeLoadMemory32ZeroExtend64 (constructor X86NativeRegister64 X86NativeR13) (constructor X86NativeRegister64 X86NativeRSP) (nativeSocketDisplacement nativeSocketPollEventsSlot)) (nativePhysicalNativeEmit (nativePhysicalNativeCompareImmediate (constructor X86NativeRegister64 X86NativeR13) (nativeSocketImmediate nativeSocketPollFdBytes)) (nativePhysicalNativeJumpCondition (constructor X86NativeCondition X86NativeConditionNotZero) b"socket-invalid" (nativePhysicalNativeEmit (constructor X86NativeInstruction X86NativeLoadMemory32ZeroExtend64 (constructor X86NativeRegister64 X86NativeR13) (constructor X86NativeRegister64 X86NativeRSP) (nativeSocketDisplacement nativeSocketPollSlot)) (nativePhysicalNativeEmit (constructor X86NativeInstruction X86NativeClear32 (constructor X86NativeRegister64 X86NativeRAX)) (nativePhysicalNativeEmit (nativePhysicalNativeSubtract (constructor X86NativeRegister64 X86NativeR13) (constructor X86NativeRegister64 X86NativeRAX)) (nativePhysicalNativeJump b"socket-return" tail))))))))))))))))))))))))) def nativeSocketConnectAssembly = (nativeSocketEntry (nativeSocketRequireNonblocking (nativeSocketConnectStart (nativeSocketPoll 4 (nativeSocketReadConnectStatus (nativeSocketReturn (constructor X86NativeAssembly X86NativeAssemblyEnd))))))) -- accept4 may race with another accept or surface a pending TCP error. -- These are the classes accept(2) documents as retryable for a nonblocking -- listener -- EINTR and EAGAIN, plus the pending network errors Linux passes -- through (ENETDOWN, EPROTO, ENOPROTOOPT, EHOSTDOWN, ENONET, EHOSTUNREACH, -- EOPNOTSUPP, ENETUNREACH) and ECONNABORTED. They retry through the bounded -- poll loop, in this order; every other result returns. The list is the one -- owner of that classification: each host realization of accept (x86-64 here, -- Platform.AArch64.SocketRoutine) folds over it. The errno numbers are -- asm-generic and identical on x86-64 and AArch64 Linux. def nativeSocketAcceptTransientErrors : (family StdList Nat) = (constructor StdList StdListCons Nat 4 (constructor StdList StdListCons Nat 11 (constructor StdList StdListCons Nat 100 (constructor StdList StdListCons Nat 71 (constructor StdList StdListCons Nat 92 (constructor StdList StdListCons Nat 112 (constructor StdList StdListCons Nat 64 (constructor StdList StdListCons Nat 113 (constructor StdList StdListCons Nat 95 (constructor StdList StdListCons Nat 101 (constructor StdList StdListCons Nat 103 (constructor StdList StdListEmpty Nat)))))))))))) def nativeSocketRetryOn = (lambda unrestricted errno : Nat . (lambda unrestricted tail : (family X86NativeAssembly) . (nativePhysicalNativeEmit (nativePhysicalNativeCompareImmediate (constructor X86NativeRegister64 X86NativeRAX) (nativeSocketImmediate (naturalSaturatingSubtract 4294967296 errno))) (nativePhysicalNativeJumpCondition (constructor X86NativeCondition X86NativeConditionZero) b"socket-loop" tail)))) def nativeSocketAcceptReady = (lambda unrestricted tail : (family X86NativeAssembly) . (nativePhysicalNativeEmit (nativePhysicalNativeMove (constructor X86NativeRegister64 X86NativeRBX) (constructor X86NativeRegister64 X86NativeRDI)) (nativePhysicalNativeEmit (nativePhysicalNativeMoveImmediate32 (constructor X86NativeRegister64 X86NativeRSI) (nativeSocketImmediate 0)) (nativePhysicalNativeEmit (nativePhysicalNativeMoveImmediate32 (constructor X86NativeRegister64 X86NativeRDX) (nativeSocketImmediate 0)) (nativePhysicalNativeEmit (nativePhysicalNativeMoveImmediate32 (constructor X86NativeRegister64 X86NativeR10) (nativeSocketImmediate nativeSocketEndpointFlags)) (nativePhysicalNativeEmit (nativePhysicalNativeMoveImmediate32 (constructor X86NativeRegister64 X86NativeRAX) (nativeSocketImmediate 288)) (nativePhysicalNativeEmit nativePhysicalNativeSystemCallInstruction (stdListFold Nat (family X86NativeAssembly) nativeSocketRetryOn (nativePhysicalNativeJump b"socket-return" tail) nativeSocketAcceptTransientErrors)))))))) def nativeSocketAcceptAssembly = (nativeSocketEntry (nativeSocketRequireNonblocking (nativeSocketPoll 1 (nativeSocketAcceptReady (nativeSocketReturn (constructor X86NativeAssembly X86NativeAssemblyEnd)))))) def nativeSocketDescriptorStatusAssembly = nativeDescriptorStatusAssembly def nativeSocketConnectCode = (compiler-native-encode (family X86NativeAssembly) nativeSocketConnectAssembly) def nativeSocketAcceptCode = (compiler-native-encode (family X86NativeAssembly) nativeSocketAcceptAssembly) def nativeSocketDescriptorStatusCode = nativeDescriptorStatusCode