-- Multicast is available only on systems which provide support for this
-- feature, so it is not available if Multicast is not supported, or not
--- installed. In particular Multicast is not available with the Windows
--- version.
+-- installed.
-- The VMS implementation was implemented using the DECC RTL Socket API,
-- and is thus subject to limitations in the implementation of this API.
with Ada.Streams;
with Ada.Unchecked_Deallocation;
-with System;
+with System.OS_Constants;
package GNAT.Sockets is
-- Sockets are designed to provide a consistent communication facility
- -- between applications. This package provides an Ada-like interface
- -- similar to that proposed as part of the BSD socket layer.
+ -- between applications. This package provides an Ada binding to the
+ -- the de-facto standard BSD sockets API. The documentation below covers
+ -- only the specific binding provided by this package. It assumes that
+ -- the reader is already familiar with general network programming and
+ -- sockets usage. A useful reference on this matter is W. Richard Stevens'
+ -- "UNIX Network Programming: The Sockets Networking API"
+ -- (ISBN: 0131411551).
-- GNAT.Sockets has been designed with several ideas in mind
-- notification of an asynchronous connect failure is delivered in the
-- write socket set (POSIX) instead of the exception socket set (NT).
- -- Here is a typical example of what you can do:
+ -- The example below demonstrates various features of GNAT.Sockets:
-- with GNAT.Sockets; use GNAT.Sockets;
-- Finalize;
-- end PingPong;
+ package SOSC renames System.OS_Constants;
+ -- Renaming used to provide short-hand notations throughout the sockets
+ -- binding. Note that System.OS_Constants is an internal unit, and the
+ -- entities declared therein are not meant for direct access by users,
+ -- including through this renaming.
+
procedure Initialize;
-- Initialize must be called before using any other socket routines.
-- Note that this operation is a no-op on UNIX platforms, but applications
No_Socket : constant Socket_Type;
+ type Selector_Type is limited private;
+ type Selector_Access is access all Selector_Type;
+ -- Selector objects are used to wait for i/o events to occur on sockets
+
+ -- Timeval_Duration is a subtype of Standard.Duration because the full
+ -- range of Standard.Duration cannot be represented in the equivalent C
+ -- structure. Moreover, negative values are not allowed to avoid system
+ -- incompatibilities.
+
+ Immediate : constant Duration := 0.0;
+
+ Timeval_Forever : constant := 2.0 ** (SOSC.SIZEOF_tv_sec * 8 - 1) - 1.0;
+ Forever : constant Duration :=
+ Duration'Min (Duration'Last, Timeval_Forever);
+
+ subtype Timeval_Duration is Duration range Immediate .. Forever;
+
+ subtype Selector_Duration is Timeval_Duration;
+ -- Timeout value for selector operations
+
+ type Selector_Status is (Completed, Expired, Aborted);
+ -- Completion status of a selector operation, indicated as follows:
+ -- Complete: one of the expected events occurred
+ -- Expired: no event occurred before the expiration of the timeout
+ -- Aborted: an external action cancelled the wait operation before
+ -- any event occurred.
+
Socket_Error : exception;
-- There is only one exception in this package to deal with an error during
-- a socket routine. Once raised, its message contains a string describing
No_Port : constant Port_Type;
type Inet_Addr_Type (Family : Family_Type := Family_Inet) is private;
- -- An Internet address depends on an address family (IPv4 contains 4
- -- octets and Ipv6 contains 16 octets). Any_Inet_Addr is a special value
- -- treated like a wildcard enabling all addresses. No_Inet_Addr provides a
- -- special value to denote uninitialized inet addresses.
+ -- An Internet address depends on an address family (IPv4 contains 4 octets
+ -- and IPv6 contains 16 octets). Any_Inet_Addr is a special value treated
+ -- like a wildcard enabling all addresses. No_Inet_Addr provides a special
+ -- value to denote uninitialized inet addresses.
Any_Inet_Addr : constant Inet_Addr_Type;
No_Inet_Addr : constant Inet_Addr_Type;
function Get_Host_By_Name
(Name : String) return Host_Entry_Type;
-- Return host entry structure for the given host name. Here name is
- -- either a host name, or an IP address. If Name is an IP address, this is
- -- equivalent to Get_Host_By_Address (Inet_Addr (Name)).
+ -- either a host name, or an IP address. If Name is an IP address, this
+ -- is equivalent to Get_Host_By_Address (Inet_Addr (Name)).
function Host_Name return String;
-- Return the name of the current host
Service_Error : exception;
-- Comment required ???
- -- Errors are described by an enumeration type. There is only one
- -- exception Socket_Error in this package to deal with an error during a
- -- socket routine. Once raised, its message contains the error code
- -- between brackets and a string describing the error code.
+ -- Errors are described by an enumeration type. There is only one exception
+ -- Socket_Error in this package to deal with an error during a socket
+ -- routine. Once raised, its message contains the error code between
+ -- brackets and a string describing the error code.
-- The name of the enumeration constant documents the error condition
Unknown_Server_Error,
Cannot_Resolve_Error);
- -- Timeval_Duration is a subtype of Standard.Duration because the full
- -- range of Standard.Duration cannot be represented in the equivalent C
- -- structure. Moreover, negative values are not allowed to avoid system
- -- incompatibilities.
-
- Immediate : constant := 0.0;
- Forever : constant := Duration (Integer'Last) * 1.0;
-
- subtype Timeval_Duration is Duration range Immediate .. Forever;
-
-- Get_Socket_Options and Set_Socket_Options manipulate options associated
-- with a socket. Options may exist at multiple protocol levels in the
-- communication stack. Socket_Level is the uppermost socket level.
-- Socket_Stream).
Peek_At_Incoming_Data : constant Request_Flag_Type;
- -- This flag causes the receive operation to return data from the
- -- beginning of the receive queue without removing that data from the
- -- queue. A subsequent receive call will return the same data.
+ -- This flag causes the receive operation to return data from the beginning
+ -- of the receive queue without removing that data from the queue. A
+ -- subsequent receive call will return the same data.
Wait_For_A_Full_Reception : constant Request_Flag_Type;
-- This flag requests that the operation block until the full request is
-- is filled in with the address of the connection. Raises Socket_Error on
-- error.
+ procedure Accept_Socket
+ (Server : Socket_Type;
+ Socket : out Socket_Type;
+ Address : out Sock_Addr_Type;
+ Timeout : Selector_Duration;
+ Selector : access Selector_Type := null;
+ Status : out Selector_Status);
+ -- Accept a new connection on Server using Accept_Socket, waiting no longer
+ -- than the given timeout duration. Status is set to indicate whether the
+ -- operation completed successfully, timed out, or was aborted. If Selector
+ -- is not null, the designated selector is used to wait for the socket to
+ -- become available, else a private selector object is created by this
+ -- procedure and destroyed before it returns.
+
procedure Bind_Socket
(Socket : Socket_Type;
Address : Sock_Addr_Type);
procedure Connect_Socket
(Socket : Socket_Type;
- Server : in out Sock_Addr_Type);
- -- Make a connection to another socket which has the address of
- -- Server. Raises Socket_Error on error.
+ Server : Sock_Addr_Type);
+ -- Make a connection to another socket which has the address of Server.
+ -- Raises Socket_Error on error.
+
+ procedure Connect_Socket
+ (Socket : Socket_Type;
+ Server : Sock_Addr_Type;
+ Timeout : Selector_Duration;
+ Selector : access Selector_Type := null;
+ Status : out Selector_Status);
+ -- Connect Socket to the given Server address using Connect_Socket, waiting
+ -- no longer than the given timeout duration. Status is set to indicate
+ -- whether the operation completed successfully, timed out, or was aborted.
+ -- If Selector is not null, the designated selector is used to wait for the
+ -- socket to become available, else a private selector object is created
+ -- by this procedure and destroyed before it returns.
procedure Control_Socket
(Socket : Socket_Type;
Request : in out Request_Type);
-- Obtain or set parameter values that control the socket. This control
- -- differs from the socket options in that they are not specific to
- -- sockets but are available for any device.
+ -- differs from the socket options in that they are not specific to sockets
+ -- but are available for any device.
function Get_Peer_Name (Socket : Socket_Type) return Sock_Addr_Type;
-- Return the peer or remote socket address of a socket. Raise
function Get_Socket_Name (Socket : Socket_Type) return Sock_Addr_Type;
-- Return the local or current socket address of a socket. Return
- -- No_Sock_Addr on error (for instance, socket closed or not locally
- -- bound).
+ -- No_Sock_Addr on error (e.g. socket closed or not locally bound).
function Get_Socket_Option
(Socket : Socket_Type;
Level : Level_Type := Socket_Level;
Name : Option_Name) return Option_Type;
- -- Get the options associated with a socket. Raises Socket_Error
- -- on error.
+ -- Get the options associated with a socket. Raises Socket_Error on error
procedure Listen_Socket
(Socket : Socket_Type;
- Length : Positive := 15);
+ Length : Natural := 15);
-- To accept connections, a socket is first created with Create_Socket,
-- a willingness to accept incoming connections and a queue Length for
-- incoming connections are specified. Raise Socket_Error on error.
+ -- The queue length of 15 is an example value that should be appropriate
+ -- in usual cases. It can be adjusted according to each application's
+ -- particular requirements.
procedure Receive_Socket
(Socket : Socket_Type;
-- Create a stream associated with a datagram-based socket that is already
-- bound. Send_To is the socket address to which messages are being sent.
- function Get_Address (Stream : Stream_Access) return Sock_Addr_Type;
+ function Get_Address
+ (Stream : not null Stream_Access) return Sock_Addr_Type;
-- Return the socket address from which the last message was received
procedure Free is new Ada.Unchecked_Deallocation
-- operation is typically to add a socket in one of the socket sets when
-- the timeout is set to forever.
- type Selector_Type is limited private;
- type Selector_Access is access all Selector_Type;
-
- subtype Selector_Duration is Timeval_Duration;
-
procedure Create_Selector (Selector : out Selector_Type);
-- Create a new selector
-- no other task still using Selector (i.e. still executing Check_Selector
-- or Abort_Selector on this Selector).
- type Selector_Status is (Completed, Expired, Aborted);
-
procedure Check_Selector
(Selector : in out Selector_Type;
R_Socket_Set : in out Socket_Set_Type;
procedure Abort_Selector (Selector : Selector_Type);
-- Send an abort signal to the selector
+ type Fd_Set_Access is private;
+ No_Fd_Set_Access : constant Fd_Set_Access;
+ -- ??? This type must not be used directly, it needs to be visible because
+ -- it is used in the visible part of GNAT.Sockets.Thin_Common. This is
+ -- really an inversion of abstraction. The private part of GNAT.Sockets
+ -- needs to have visibility on this type, but since Thin_Common is a child
+ -- of Sockets, the type can't be declared there. The correct fix would
+ -- be to move the thin sockets binding outside of GNAT.Sockets altogether,
+ -- e.g. by renaming it to GNAT.Sockets_Thin.
+
private
type Socket_Type is new Integer;
type Selector_Type is limited record
R_Sig_Socket : Socket_Type := No_Socket;
W_Sig_Socket : Socket_Type := No_Socket;
+ -- Signalling sockets used to abort a select operation
end record;
pragma Volatile (Selector_Type);
- -- The two signalling sockets are used to abort a select operation
-
- subtype Socket_Set_Access is System.Address;
- No_Socket_Set : constant Socket_Set_Access := System.Null_Address;
+ type Fd_Set is null record;
+ type Fd_Set_Access is access all Fd_Set;
+ pragma Convention (C, Fd_Set_Access);
+ No_Fd_Set_Access : constant Fd_Set_Access := null;
type Socket_Set_Type is record
Last : Socket_Type := No_Socket;
- Set : Socket_Set_Access := No_Socket_Set;
+ Set : Fd_Set_Access;
end record;
subtype Inet_Addr_Comp_Type is Natural range 0 .. 255;