-- POSIX_UDP_Garbage - Provide bindings for the disgusting filth POSIX requires to send UDP 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 would have a Pure pragma, but that allows omitting library calls, which is too much. -- I wanted this library to have a nonlinear story in its comments but it wound up too short for it. with Interfaces.C; use Interfaces.C; -- I must settle with my parody of ``The Raven'' and only that. package POSIX_UDP_Garbage is -- While I could use the Interfaces.C types, they will always actually be these types internally. type Uint16_T is new Interfaces.Unsigned_16; type Uint32_T is new Interfaces.Unsigned_32; -- This pernicious nonsense is what I allowed to stop my previous attempt at binding the garbage. type Sockaddr is private; -- If I don't create this type now, Char_Array will infect all things which this binding touches. -- The packing here should suffice to give what I obviously need without a Component_Size needed. -- Until 2023, this had aliased elements, to ensure an address, but apparently this isn't needed. 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); procedure Sendto (Socket : in Int; Buffer : in Octet_Array; Socket_Address : in Sockaddr); procedure Recvfrom (Socket : in Int; Buffer : out Octet_Array; Socket_Address : in out Sockaddr; Length : out Size_T; Truncate_Length : in Boolean := True); -- Know it's unwise to use this parameter's name; I may later name it Socket to match the others. procedure Close (File_Descriptor : Int); -- I've so wanted to provide String variants of Sendto and Recvfrom, for purposes of convenience. -- Until 2023, I was unaware that an array is apparently, inherently aliased, which permits this. -- Beforehand, I'd thought myself to need an Ada 2005 variant of this library, to force aliasing. procedure Sendto (Socket : in Int; Buffer : in String; Socket_Address : in Sockaddr); procedure Recvfrom (Socket : in Int; Buffer : out String; Socket_Address : in out Sockaddr; Length : out Size_T; Truncate_Length : in Boolean := True); Socket_Error : exception; Bind_Error : exception; Sendto_Error : exception; Recvfrom_Error : exception; private -- Look at that foresight of the Sockaddr struct, and how it has trailing data for later systems. -- Of course, the Sa_Data field happened to be a tad too small to contain what's needed for IPv6. -- So, in the end, space is unnecessarily wasted, and new structs were added for supporting IPv6. -- That struct truly needed here is Sockaddr_In, and the characters of Sa_Data correspond to its. -- Notice how this is so similar to that WWW, in that it started by using vague, imprecise types. -- However the types get confusingly constrained and begin to have expectations placed upon them. -- The end result is wanting precise and unchanging results while using vague and shifting terms. -- This is caused entirely by a simple fact: The modelling skills of mental midgets are middling. 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); -- It's not worthwhile to provide constants representing the POSIX values, since they can change. -- Though, it may help someone change them at some later point, so it's not completely worthless. -- These particular constants are used with the Linux kernel, and also likely to be ``standard''. -- The values of these constants will likely be constant across UNIXen, but there's no guarantee. -- Yes, that C language is an excellent base language, so long as everything bends to make it so. -- These constants have no real type, being universal integer, as they must be used in many ways. -- Further skulking around has shown to me that SOCK_DGRAM and AF_INET always have the value two. -- OpenBSD lacks MSG_TRUNC, as of the last time I've checked, however it can be ignored for this. -- Due to the idiotic way the C language fakes having optional parameters, it may be set to zero. -- Alternatively, an OpenBSD version could use a buffer of the largest size to then copy from it. SOCK_DGRAM : constant := 2; AF_INET : constant := 2; MSG_TRUNC : constant := 32; -- These type definitions were in the body, but are now moved in interest of keeping it constant. -- The main types which need to be modelled for these are: Int, Ssize_T, Sockaddr, and Socklen_T. -- The Interfaces.C provides the former, and I've noticed the last only ever differs by the sign. -- Modelling that struct is very burdensome, however, so I've decided that I won't be doing this. -- It almost goes unwritten that Ssize_T must be a superset of Size_T for this code to be proper. 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_UDP_Garbage; .