-- --
-- S p e c --
-- --
--- Copyright (C) 2001-2007, AdaCore --
+-- Copyright (C) 2001-2008, AdaCore --
-- --
-- GNAT is free software; you can redistribute it and/or modify it under --
-- terms of the GNU General Public License as published by the Free Soft- --
-- 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;
-- Socket_Level,
-- (Reuse_Address, True));
- -- -- Join a multicast group
-
- -- Set_Socket_Option
- -- (Socket,
- -- IP_Protocol_For_IP_Level,
- -- (Add_Membership, Inet_Addr (Group), Any_Inet_Addr));
-
-- -- Controls the live time of the datagram to avoid it being
-- -- looped forever due to routing errors. Routers decrement
-- -- the TTL of every datagram as it traverses from one network
-- Bind_Socket (Socket, Address);
+ -- -- Join a multicast group
+
+ -- -- Portability note: On Windows, this option may be set only
+ -- -- on a bound socket.
+
+ -- Set_Socket_Option
+ -- (Socket,
+ -- IP_Protocol_For_IP_Level,
+ -- (Add_Membership, Inet_Addr (Group), Any_Inet_Addr));
+
-- -- If this socket is intended to send messages, provide the
-- -- receiver socket address.
-- Set_Socket_Option
-- (Socket,
-- IP_Protocol_For_IP_Level,
- -- (Add_Membership, Inet_Addr (Group), Any_Inet_Addr));
-
- -- Set_Socket_Option
- -- (Socket,
- -- IP_Protocol_For_IP_Level,
-- (Multicast_TTL, 1));
-- Set_Socket_Option
-- Bind_Socket (Socket, Address);
+ -- Set_Socket_Option
+ -- (Socket,
+ -- IP_Protocol_For_IP_Level,
+ -- (Add_Membership, Inet_Addr (Group), Any_Inet_Addr));
+
-- Address.Addr := Inet_Addr (Group);
-- Address.Port := 55505;
-- 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.
-- a boolean to enable or disable this option.
type Option_Name is (
- Keep_Alive, -- Enable sending of keep-alive messages
- Reuse_Address, -- Allow bind to reuse local address
- Broadcast, -- Enable datagram sockets to recv/send broadcasts
- Send_Buffer, -- Set/get the maximum socket send buffer in bytes
- Receive_Buffer, -- Set/get the maximum socket recv buffer in bytes
- Linger, -- Shutdown wait for msg to be sent or timeout occur
- Error, -- Get and clear the pending socket error
- No_Delay, -- Do not delay send to coalesce packets (TCP_NODELAY)
- Add_Membership, -- Join a multicast group
- Drop_Membership, -- Leave a multicast group
- Multicast_If, -- Set default outgoing interface for multicast packets
- Multicast_TTL, -- Indicate the time-to-live of sent multicast packets
- Multicast_Loop, -- Sent multicast packets are looped to local socket
- Send_Timeout, -- Set timeout value for output
- Receive_Timeout); -- Set timeout value for input
+ Keep_Alive, -- Enable sending of keep-alive messages
+ Reuse_Address, -- Allow bind to reuse local address
+ Broadcast, -- Enable datagram sockets to recv/send broadcasts
+ Send_Buffer, -- Set/get the maximum socket send buffer in bytes
+ Receive_Buffer, -- Set/get the maximum socket recv buffer in bytes
+ Linger, -- Shutdown wait for msg to be sent or timeout occur
+ Error, -- Get and clear the pending socket error
+ No_Delay, -- Do not delay send to coalesce data (TCP_NODELAY)
+ Add_Membership, -- Join a multicast group
+ Drop_Membership, -- Leave a multicast group
+ Multicast_If, -- Set default out interface for multicast packets
+ Multicast_TTL, -- Set the time-to-live of sent multicast packets
+ Multicast_Loop, -- Sent multicast packets are looped to local socket
+ Receive_Packet_Info, -- Receive low level packet info as ancillary data
+ Send_Timeout, -- Set timeout value for output
+ Receive_Timeout); -- Set timeout value for input
type Option_Type (Name : Option_Name := Keep_Alive) is record
case Name is
- when Keep_Alive |
- Reuse_Address |
- Broadcast |
- Linger |
- No_Delay |
- Multicast_Loop =>
+ when Keep_Alive |
+ Reuse_Address |
+ Broadcast |
+ Linger |
+ No_Delay |
+ Receive_Packet_Info |
+ Multicast_Loop =>
Enabled : Boolean;
case Name is
-- 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;