-- Usable_Datagram_Package - Provide a UDP interface that should satisfy most any underlying system. -- 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, as with POSIX_UDP_Garbage, carefully adheres to but those requirements of Ada 1995. -- The exceptions raised in the procedure Initialize would benefit from Ada 2005 exception messages. -- This isn't an ultimate UDP interface design and neither is it even adequate for certain purposes. -- Instead, this package targets a very narrow and simple usage of UDP I'm able to match, perfectly. -- This package is fine for a program which needs a lone port of its choice, from the local machine, -- to send datagrams from the same port, and without power over checksum generation and like things. with Interfaces; -- I considered an approach which would have this package specification identical across all bodies. -- Though, this only becomes sensible with more than one body, so this will suffice until that time. with Ada.Finalization, POSIX_UDP_Garbage, Interfaces.C; -- In no way may such be assumed to be here. package Usable_Datagram_Package is -- I suggest renaming this package to just UDP whenever using it. -- The Interfaces types are nice, for they solve a particular woe of strong typing: dependencies. type Port is new Interfaces.Unsigned_16; -- An IP address should clearly be an array, as this makes it so easy to specify a literal value. -- I see no issue with starting this array from one; I don't expect the indices to be used, much. -- I believe array sliding and the like will solve most possible such woes, however rare they're. type Address is array (Integer range 1 .. 4) of Interfaces.Unsigned_8; pragma Pack(Address); -- I utterly loathe initialization requirements in library design, and take pains to avoid these. -- My previous design used a protected object for this, but it, unfortunately, made little sense. -- I want not hits and gets to quarrel; why then would protected object be used for the resource? -- Changing the port was the only operation which should stop the others, so it has been removed. -- Using port zero to obtain a random port offers no way to learn the port number with my design. type System_Resource(Where : Port) is limited private; -- I could have Interfaces.Unsigned_16, but it's most useful for this to be a subtype of Integer. -- The smallest IP header is twenty octets and the UDP header is always eight; this is the limit. -- Originally, I based this on the largest IP header at sixty octets, but that could cause error. -- It's inconvenient that I may not use the name Length for both the type and parameters thereof. -- I don't suggest using this name in any situation but also see no reason I'd need to change it. subtype Data_Length is Integer range 0 .. 65_507; -- This is largely identical to the POSIX_UDP_Garbage array type with the exception of the index. -- The array sliding rules of Ada should make it pleasant to convert between them without copies. -- Until 2023, this had aliased elements, to ensure an address, but apparently this isn't needed. type Octet_Array is array (Data_Length range <>) of Interfaces.Unsigned_8; pragma Pack(Octet_Array); -- This isn't the ultimate interface to UDP, considering what can't be controlled, but it's fine. -- Rather than Send and Receive, I use names which have the same number of letters and syllables. -- The name I've chosen for that System_Resource parameter is unfortunate, but I see none better. -- Try to avoid using the name I've chosen for the System_Resource parameter, although it makes a -- nice sentence if one were to read it like so: Hit by system, data mine, to him, at port there. procedure Hit (By : in System_Resource; -- I originally named it Resource, but By is better. Data : in Octet_Array; To : in Address; At_Port : in Port); -- Perhaps this should stay as To_Port, for symmetry with Get. -- The Fit type commands one of the Get procedures to react in one of four ways to size mismatch. -- The default fit requires the got data to match the size of the Octet_Array exactly; the second -- allows larger sizes; the third allows lesser sizes; and the last ignores mismatching entirely. -- The remainder of the Octet_Array will be unmolested in cases where all octets wouldn't be hit. -- I considered the following names of seven letters instead: Require, Greater, Smaller, Dismiss. type Fit is (Equals, Larger, Lesser, Ignore); procedure Get (By : in System_Resource; Data : out Octet_Array; From : out Address; From_Port : out Port; Fitting : in Fit := Equals); -- This variant of Get returns the length of the got data, which may be greater than Data'Length. procedure Get (By : in System_Resource; Data : out Octet_Array; From : out Address; From_Port : out Port; Length : out Data_Length); -- Lastly, but least, is a variant which simply pads any octets of Data not used by the got data. procedure Get (By : in System_Resource; Data : out Octet_Array; From : out Address; From_Port : out Port; Padding : in Interfaces.Unsigned_8); -- What follows are variants of Hit and Get which work in terms of String instead of Octet_Array. procedure Hit (By : in System_Resource; Data : in String; To : in Address; At_Port : in Port); procedure Get (By : in System_Resource; Data : out String; From : out Address; From_Port : out Port; Fitting : in Fit := Equals); procedure Get (By : in System_Resource; Data : out String; From : out Address; From_Port : out Port; Length : out Data_Length); procedure Get (By : in System_Resource; Data : out String; From : out Address; From_Port : out Port; Padding : in Character); -- These exception names are finished, sans that last, for which I couldn't find a suitable word. -- I dislike the last name, originally it was System_Resource_Error, but Sys_Error is much nicer. -- It occurred to me it could be read as Cis_Error to mean error on the library's side of things. -- That would have an error on that other side of the network be Trans_Error, an unfixable error. Hit_Error : exception; Get_Error : exception; Fit_Error : exception; Sys_Error : exception; private type System_Resource(Where : Port) is new Ada.Finalization.Limited_Controlled with record Socket_Nonsense : Interfaces.C.Int; end record; procedure Initialize (Object : in out System_Resource); procedure Finalize (Object : in out System_Resource); end Usable_Datagram_Package; .