-- POSIX_TCP_Garbage - Provide bindings for the disgusting filth POSIX requires to send TCP packets. -- Copyright (C) 2022,2023 Prince Trippy . -- This program is free software: you can redistribute it and/or modify it under the terms of the -- GNU Affero General Public License version 3 as published by the Free Software Foundation. -- This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without -- even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- See the GNU Affero General Public License for more details. -- You should have received a copy of the GNU Affero General Public License along with this program. -- If not, see . -- This library is designed to adhere to the requirements of Ada 1995, due entirely to Interfaces.C. -- This library shares code and basic design principles with POSIX_UDP_Garbage, but is incompatible. -- This library is underdocumented in comparison, and any reader should read POSIX_UDP_Garbage also. with Interfaces.C; use Interfaces.C; package POSIX_TCP_Garbage is -- There's no point in using the Interfaces.C types and it would complicate the real TCP library. -- It's almost unfortunate that my TCP and UDP libraries will have incompatible IP address types. -- Regardless, the port types should be incompatible most certainly and it's a rather tiny issue. type Uint16_T is new Interfaces.Unsigned_16; type Uint32_T is new Interfaces.Unsigned_32; type Sockaddr is private; type Octet_Array is array (Size_T range <>) of Interfaces.Unsigned_8; pragma Pack(Octet_Array); function Make_Sockaddr (Address : in Uint32_T; Port : in Uint16_T) return Sockaddr; function Sockaddr_Address (Socket_Address : in Sockaddr) return Uint32_T; function Sockaddr_Port (Socket_Address : in Sockaddr) return Uint16_T; procedure Socket (Socket : out Int); procedure Bind (Socket : in Int; Socket_Address : in Sockaddr); -- It would make sense to have these be functions rather than procedures, but not too much sense. procedure Send (Socket : in Int; Buffer : in Octet_Array; Length : out Size_T); procedure Recv (Socket : in Int; Buffer : out Octet_Array; Length : out Size_T); -- At the very least, subverting the type system at this level isn't too terribly difficult here. procedure Send (Socket : in Int; Buffer : in String; Length : out Size_T); procedure Recv (Socket : in Int; Buffer : out String; Length : out Size_T); -- Unlike UDP, it makes good sense for there to be ``nonblocking'' versions of these subprograms. -- Whereas UDP has no notion of connections, TCP has protocol support for blocking the other end. -- I'm still designing the interface these variants on Send and Recv use, and will add them soon. -- I forgot accept to be a keyword of Ada, and have carelessly renamed that function with Intake. -- I'm not entirely pleased by that final parameter name of Intake, but it really matters little. procedure Listen (Socket : in Int); procedure Intake (Socket : in Int; Socket_Address : out Sockaddr; Connection : out Int); procedure Connect (Socket : in Int; Socket_Address : in Sockaddr); -- This stupid little function internally uses an entire Int yet supports three different values. type Mode is (Read, Write, Read_Write); procedure Shutdown (Socket : in Int; How : in Mode); -- Know it's unwise to use this parameter's name; I may later name it Socket to match the others. -- Unlike my POSIX_UDP_Garbage implementation, this procedure will be imported and used directly. procedure Close (File_Descriptor : Int); pragma Import(Convention => C, Entity => Close, External_Name => "close"); -- Unlike POSIX_UDP_Garbage, many of these procedures have no associated errors, for good reason. -- POSIX_UDP_Garbage was written in a way where many failure cases were coalesced into one error. -- Furthermore, those coalesced failure cases were inherent to the proper operation in all cases. -- Some failure cases, such as those of shutdown, simply won't happen in any reasonable programs. -- It would be bothersome to require handling of such useless errors and so I won't allow for it. -- This library is named garbage for good reason; it's in no way intended to be generally useful. Socket_Error : exception; Bind_Error : exception; Send_Error : exception; Recv_Error : exception; Accept_Error : exception; Connect_Error : exception; private -- My delightful rant about the dumbfuckery present in this record is found in POSIX_UDP_Garbage. type Sockaddr is record Sa_Family : Uint16_T; Sin_Port : Uint16_T; Sin_Addr : Uint32_T; Sa_Zero : Char_Array(0 .. 7); end record; pragma Convention(Convention => C, Entity => Sockaddr); -- These first two POSIX values appear to be ``standard'' and therefore unlikely to change later. -- I've too noticed MSG_NOSIGNAL to have a consistent value across systems, but not MSG_DONTWAIT. SOCK_STREAM : constant := 1; AF_INET : constant := 2; MSG_NOSIGNAL : constant := 16#0040#; MSG_DONTWAIT : constant := 16#4000#; MSG_WAITALSO : constant := MSG_NOSIGNAL + MSG_DONTWAIT; -- Only modular types get an OR function. -- The main types I need to model are the same for my UDP: Int, Ssize_T, Sockaddr, and Socklen_T. type Ssize_T is new Long; type Socklen_T is new Unsigned; -- The following expression was adapted from the public domain Ada documentation for the purpose. -- The value of Sockaddr_Size is always sixteen in every instance I've checked, unlikely to vary. Sockaddr_Size : constant Socklen_T := Socklen_T(Sockaddr'Size / CHAR_BIT); end POSIX_TCP_Garbage; .