Commit 38c4e50d by Dmitriy Anisimkov Committed by Pierre-Marie de Rodat

[Ada] Support for local unix sockets in GNAT.Sockets API

Sock_Addr_Type has Family_Unix variant now. This variant can be created
with function Unix_Local_Addr call. And this variant is working in
GNAT.Socket routines where it is appropriate.

2019-09-17  Dmitriy Anisimkov  <anisimko@adacore.com>

gcc/ada/

	* gsocket.h: Include sys/un.h.
	* s-oscons-tmplt.c (AF_UNIX): New constant generation.
	(SIZEOF_sockaddr_un): Idem.
	* libgnat/g-socket.ads (Family_Type): New value Family_Unix
	added.
	(Family_Inet_4_6): New subtype only for network families.
	(Sock_Addr_Type): Add Unbounded_String field for Family_Unix
	variant.
	(Unix_Socket_Address): Create Sock_Addr_Type from socket
	pathname.
	(Network_Socket_Address): Create Sock_Addr_Type from
	Inet_Addr_Type and Port_Type parameters.
	* libgnat/g-socket.adb: Support local unix address in socket
	routines.
	(Get_Address_Info): Disable warning about Result may be
	referenced before it has a value. Remove duplicated code to exit
	from Look_For_Supported.
	* libgnat/g-sothco.ads (Unix_Name_Length): New constant defining
	maximum number of characters in local socket address path.
	(Sockaddr): Add variant for Family_Unix address family. Move
	Sin_Port and Sin_Family to Family_Inet section. Add Sin6_Port
	and Sin6_Family to Family_Inet6 section.
	(Set_Address): Add out parameter Length to return valuable
	Sockaddr data length.
	(Get_Address): Add input parameter Length to set valuable
	Sockaddr data length.
	* libgnat/g-sothco.adb: Support local unix address in socket
	routines.

From-SVN: r275770
parent 37915d02
2019-09-17 Dmitriy Anisimkov <anisimko@adacore.com>
* gsocket.h: Include sys/un.h.
* s-oscons-tmplt.c (AF_UNIX): New constant generation.
(SIZEOF_sockaddr_un): Idem.
* libgnat/g-socket.ads (Family_Type): New value Family_Unix
added.
(Family_Inet_4_6): New subtype only for network families.
(Sock_Addr_Type): Add Unbounded_String field for Family_Unix
variant.
(Unix_Socket_Address): Create Sock_Addr_Type from socket
pathname.
(Network_Socket_Address): Create Sock_Addr_Type from
Inet_Addr_Type and Port_Type parameters.
* libgnat/g-socket.adb: Support local unix address in socket
routines.
(Get_Address_Info): Disable warning about Result may be
referenced before it has a value. Remove duplicated code to exit
from Look_For_Supported.
* libgnat/g-sothco.ads (Unix_Name_Length): New constant defining
maximum number of characters in local socket address path.
(Sockaddr): Add variant for Family_Unix address family. Move
Sin_Port and Sin_Family to Family_Inet section. Add Sin6_Port
and Sin6_Family to Family_Inet6 section.
(Set_Address): Add out parameter Length to return valuable
Sockaddr data length.
(Get_Address): Add input parameter Length to set valuable
Sockaddr data length.
* libgnat/g-sothco.adb: Support local unix address in socket
routines.
2019-09-17 Eric Botcazou <ebotcazou@adacore.com> 2019-09-17 Eric Botcazou <ebotcazou@adacore.com>
* exp_attr.adb (Expand_Size_Attribute): Chain the special cases * exp_attr.adb (Expand_Size_Attribute): Chain the special cases
......
...@@ -208,6 +208,7 @@ ...@@ -208,6 +208,7 @@
*/ */
#if !(defined (VMS) || defined (__MINGW32__)) #if !(defined (VMS) || defined (__MINGW32__))
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <netinet/tcp.h> #include <netinet/tcp.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
......
...@@ -128,14 +128,12 @@ package body GNAT.Sockets is ...@@ -128,14 +128,12 @@ package body GNAT.Sockets is
Socket_Error_Id : constant Exception_Id := Socket_Error'Identity; Socket_Error_Id : constant Exception_Id := Socket_Error'Identity;
Host_Error_Id : constant Exception_Id := Host_Error'Identity; Host_Error_Id : constant Exception_Id := Host_Error'Identity;
type In_Addr_Union (Family : Family_Type) is record type In_Addr_Union (Family : Family_Inet_4_6) is record
case Family is case Family is
when Family_Inet => when Family_Inet =>
In4 : In_Addr; In4 : In_Addr;
when Family_Inet6 => when Family_Inet6 =>
In6 : In6_Addr; In6 : In6_Addr;
when Family_Unspec =>
null;
end case; end case;
end record with Unchecked_Union; end record with Unchecked_Union;
...@@ -291,7 +289,7 @@ package body GNAT.Sockets is ...@@ -291,7 +289,7 @@ package body GNAT.Sockets is
-- or the null selector. -- or the null selector.
function Create_Address function Create_Address
(Family : Family_Type; Bytes : Inet_Addr_Bytes) return Inet_Addr_Type (Family : Family_Inet_4_6; Bytes : Inet_Addr_Bytes) return Inet_Addr_Type
with Inline; with Inline;
-- Creates address from family and Inet_Addr_Bytes array. -- Creates address from family and Inet_Addr_Bytes array.
...@@ -354,7 +352,7 @@ package body GNAT.Sockets is ...@@ -354,7 +352,7 @@ package body GNAT.Sockets is
end if; end if;
Socket := Socket_Type (Res); Socket := Socket_Type (Res);
Address := Get_Address (Sin); Address := Get_Address (Sin, Len);
end Accept_Socket; end Accept_Socket;
------------------- -------------------
...@@ -465,12 +463,12 @@ package body GNAT.Sockets is ...@@ -465,12 +463,12 @@ package body GNAT.Sockets is
is is
Res : C.int; Res : C.int;
Sin : aliased Sockaddr; Sin : aliased Sockaddr;
Len : C.int;
begin begin
Set_Address (Sin'Unchecked_Access, Address); Set_Address (Sin'Unchecked_Access, Address, Len);
Res := C_Bind Res := C_Bind (C.int (Socket), Sin'Address, Len);
(C.int (Socket), Sin'Address, C.int (Lengths (Address.Family)));
if Res = Failure then if Res = Failure then
Raise_Socket_Error (Socket_Errno); Raise_Socket_Error (Socket_Errno);
...@@ -670,11 +668,11 @@ package body GNAT.Sockets is ...@@ -670,11 +668,11 @@ package body GNAT.Sockets is
Server : Sock_Addr_Type) return C.int Server : Sock_Addr_Type) return C.int
is is
Sin : aliased Sockaddr; Sin : aliased Sockaddr;
Len : C.int;
begin begin
Set_Address (Sin'Unchecked_Access, Server); Set_Address (Sin'Unchecked_Access, Server, Len);
return C_Connect return C_Connect (C.int (Socket), Sin'Address, Len);
(C.int (Socket), Sin'Address, C.int (Lengths (Server.Family)));
end Connect_Socket; end Connect_Socket;
procedure Connect_Socket procedure Connect_Socket
...@@ -1039,10 +1037,17 @@ package body GNAT.Sockets is ...@@ -1039,10 +1037,17 @@ package body GNAT.Sockets is
for J in Result'Range loop for J in Result'Range loop
Look_For_Supported : loop Look_For_Supported : loop
if Iter = null then if Iter = null then
pragma Warnings
(Off, "may be referenced before it has a value");
return Result (1 .. J - 1); return Result (1 .. J - 1);
pragma Warnings
(On, "may be referenced before it has a value");
end if; end if;
Result (J).Addr := Get_Address (Iter.ai_addr.all); Result (J).Addr :=
Get_Address (Iter.ai_addr.all, C.int (Iter.ai_addrlen));
if Result (J).Addr.Family = Family_Unspec then if Result (J).Addr.Family = Family_Unspec then
Unsupported; Unsupported;
...@@ -1071,10 +1076,6 @@ package body GNAT.Sockets is ...@@ -1071,10 +1076,6 @@ package body GNAT.Sockets is
end if; end if;
Iter := Iter.ai_next; Iter := Iter.ai_next;
if Iter = null then
return Result (1 .. J - 1);
end if;
end loop Look_For_Supported; end loop Look_For_Supported;
Iter := Iter.ai_next; Iter := Iter.ai_next;
...@@ -1149,15 +1150,16 @@ package body GNAT.Sockets is ...@@ -1149,15 +1150,16 @@ package body GNAT.Sockets is
Numeric_Host : Boolean := False; Numeric_Host : Boolean := False;
Numeric_Serv : Boolean := False) return Host_Service Numeric_Serv : Boolean := False) return Host_Service
is is
SA : aliased Sockaddr; SA : aliased Sockaddr;
H : aliased C.char_array := (1 .. SOSC.NI_MAXHOST => C.nul); H : aliased C.char_array := (1 .. SOSC.NI_MAXHOST => C.nul);
S : aliased C.char_array := (1 .. SOSC.NI_MAXSERV => C.nul); S : aliased C.char_array := (1 .. SOSC.NI_MAXSERV => C.nul);
RC : C.int; RC : C.int;
Len : C.int;
begin begin
Set_Address (SA'Unchecked_Access, Addr); Set_Address (SA'Unchecked_Access, Addr, Len);
RC := C_Getnameinfo RC := C_Getnameinfo
(SA'Unchecked_Access, socklen_t (Lengths (Addr.Family)), (SA'Unchecked_Access, socklen_t (Len),
H'Unchecked_Access, H'Length, H'Unchecked_Access, H'Length,
S'Unchecked_Access, S'Length, S'Unchecked_Access, S'Length,
(if Numeric_Host then SOSC.NI_NUMERICHOST else 0) + (if Numeric_Host then SOSC.NI_NUMERICHOST else 0) +
...@@ -1197,9 +1199,6 @@ package body GNAT.Sockets is ...@@ -1197,9 +1199,6 @@ package body GNAT.Sockets is
HA.In4 := To_In_Addr (Address); HA.In4 := To_In_Addr (Address);
when Family_Inet6 => when Family_Inet6 =>
HA.In6 := To_In6_Addr (Address); HA.In6 := To_In6_Addr (Address);
when Family_Unspec =>
return (0, 0, (1, " "), (1 .. 0 => (1, " ")),
(1 .. 0 => No_Inet_Addr));
end case; end case;
Netdb_Lock; Netdb_Lock;
...@@ -1208,8 +1207,7 @@ package body GNAT.Sockets is ...@@ -1208,8 +1207,7 @@ package body GNAT.Sockets is
(HA'Address, (HA'Address,
(case Address.Family is (case Address.Family is
when Family_Inet => HA.In4'Size, when Family_Inet => HA.In4'Size,
when Family_Inet6 => HA.In6'Size, when Family_Inet6 => HA.In6'Size) / 8,
when Family_Unspec => 0) / 8,
Families (Address.Family), Families (Address.Family),
Res'Access, Buf'Address, Buflen, Err'Access) /= 0 Res'Access, Buf'Address, Buflen, Err'Access) /= 0
then then
...@@ -1280,7 +1278,7 @@ package body GNAT.Sockets is ...@@ -1280,7 +1278,7 @@ package body GNAT.Sockets is
Raise_Socket_Error (Socket_Errno); Raise_Socket_Error (Socket_Errno);
end if; end if;
return Get_Address (Sin); return Get_Address (Sin, Len);
end Get_Peer_Name; end Get_Peer_Name;
------------------------- -------------------------
...@@ -1364,7 +1362,7 @@ package body GNAT.Sockets is ...@@ -1364,7 +1362,7 @@ package body GNAT.Sockets is
return No_Sock_Addr; return No_Sock_Addr;
end if; end if;
return Get_Address (Sin); return Get_Address (Sin, Len);
end Get_Socket_Name; end Get_Socket_Name;
----------------------- -----------------------
...@@ -1572,9 +1570,8 @@ package body GNAT.Sockets is ...@@ -1572,9 +1570,8 @@ package body GNAT.Sockets is
Size : constant socklen_t := Size : constant socklen_t :=
(case Value.Family is (case Value.Family is
when Family_Inet => 4 * Value.Sin_V4'Length, when Family_Inet => 4 * Value.Sin_V4'Length,
when Family_Inet6 => 6 * 5 + 4 * 4, when Family_Inet6 => 6 * 5 + 4 * 4);
-- 1234:1234:1234:1234:1234:1234:123.123.123.123 -- 1234:1234:1234:1234:1234:1234:123.123.123.123
when Family_Unspec => 0);
Dst : aliased C.char_array := (1 .. C.size_t (Size) => C.nul); Dst : aliased C.char_array := (1 .. C.size_t (Size) => C.nul);
Ia : aliased In_Addr_Union (Value.Family); Ia : aliased In_Addr_Union (Value.Family);
begin begin
...@@ -1583,8 +1580,6 @@ package body GNAT.Sockets is ...@@ -1583,8 +1580,6 @@ package body GNAT.Sockets is
Ia.In6 := To_In6_Addr (Value); Ia.In6 := To_In6_Addr (Value);
when Family_Inet => when Family_Inet =>
Ia.In4 := To_In_Addr (Value); Ia.In4 := To_In_Addr (Value);
when Family_Unspec =>
return "";
end case; end case;
if Inet_Ntop if Inet_Ntop
...@@ -1602,11 +1597,30 @@ package body GNAT.Sockets is ...@@ -1602,11 +1597,30 @@ package body GNAT.Sockets is
----------- -----------
function Image (Value : Sock_Addr_Type) return String is function Image (Value : Sock_Addr_Type) return String is
Port : constant String := Value.Port'Img;
function Ipv6_Brackets (S : String) return String is function Ipv6_Brackets (S : String) return String is
(if Value.Family = Family_Inet6 then "[" & S & "]" else S); (if Value.Family = Family_Inet6 then "[" & S & "]" else S);
begin begin
return Ipv6_Brackets (Image (Value.Addr)) & ':' & Port (2 .. Port'Last); case Value.Family is
when Family_Unix =>
if ASU.Length (Value.Name) > 0
and then ASU.Element (Value.Name, 1) = ASCII.NUL
then
return '@' & ASU.Slice (Value.Name, 2, ASU.Length (Value.Name));
else
return ASU.To_String (Value.Name);
end if;
when Family_Inet_4_6 =>
declare
Port : constant String := Value.Port'Img;
begin
return Ipv6_Brackets (Image (Value.Addr)) & ':'
& Port (2 .. Port'Last);
end;
when Family_Unspec =>
return "";
end case;
end Image; end Image;
----------- -----------
...@@ -1924,6 +1938,19 @@ package body GNAT.Sockets is ...@@ -1924,6 +1938,19 @@ package body GNAT.Sockets is
end if; end if;
end Netdb_Unlock; end Netdb_Unlock;
----------------------------
-- Network_Socket_Address --
----------------------------
function Network_Socket_Address
(Addr : Inet_Addr_Type; Port : Port_Type) return Sock_Addr_Type is
begin
return Result : Sock_Addr_Type (Addr.Family) do
Result.Addr := Addr;
Result.Port := Port;
end return;
end Network_Socket_Address;
-------------------------------- --------------------------------
-- Normalize_Empty_Socket_Set -- -- Normalize_Empty_Socket_Set --
-------------------------------- --------------------------------
...@@ -2139,7 +2166,7 @@ package body GNAT.Sockets is ...@@ -2139,7 +2166,7 @@ package body GNAT.Sockets is
Last := Last_Index (First => Item'First, Count => size_t (Res)); Last := Last_Index (First => Item'First, Count => size_t (Res));
From := Get_Address (Sin); From := Get_Address (Sin, Len);
end Receive_Socket; end Receive_Socket;
-------------------- --------------------
...@@ -2404,9 +2431,8 @@ package body GNAT.Sockets is ...@@ -2404,9 +2431,8 @@ package body GNAT.Sockets is
begin begin
if To /= null then if To /= null then
Set_Address (Sin'Unchecked_Access, To.all); Set_Address (Sin'Unchecked_Access, To.all, Len);
C_To := Sin'Address; C_To := Sin'Address;
Len := C.int (Thin_Common.Lengths (To.Family));
else else
C_To := System.Null_Address; C_To := System.Null_Address;
...@@ -3055,12 +3081,11 @@ package body GNAT.Sockets is ...@@ -3055,12 +3081,11 @@ package body GNAT.Sockets is
-------------------- --------------------
function Create_Address function Create_Address
(Family : Family_Type; Bytes : Inet_Addr_Bytes) return Inet_Addr_Type (Family : Family_Inet_4_6; Bytes : Inet_Addr_Bytes) return Inet_Addr_Type
is is
(case Family is (case Family is
when Family_Inet => (Family_Inet, Bytes), when Family_Inet => (Family_Inet, Bytes),
when Family_Inet6 => (Family_Inet6, Bytes), when Family_Inet6 => (Family_Inet6, Bytes));
when Family_Unspec => (Family => Family_Unspec));
--------------- ---------------
-- Get_Bytes -- -- Get_Bytes --
...@@ -3069,15 +3094,14 @@ package body GNAT.Sockets is ...@@ -3069,15 +3094,14 @@ package body GNAT.Sockets is
function Get_Bytes (Addr : Inet_Addr_Type) return Inet_Addr_Bytes is function Get_Bytes (Addr : Inet_Addr_Type) return Inet_Addr_Bytes is
(case Addr.Family is (case Addr.Family is
when Family_Inet => Addr.Sin_V4, when Family_Inet => Addr.Sin_V4,
when Family_Inet6 => Addr.Sin_V6, when Family_Inet6 => Addr.Sin_V6);
when Family_Unspec => (1 .. 0 => 0));
---------- ----------
-- Mask -- -- Mask --
---------- ----------
function Mask function Mask
(Family : Family_Type; (Family : Family_Inet_4_6;
Length : Natural; Length : Natural;
Host : Boolean := False) return Inet_Addr_Type Host : Boolean := False) return Inet_Addr_Type
is is
...@@ -3109,6 +3133,15 @@ package body GNAT.Sockets is ...@@ -3109,6 +3133,15 @@ package body GNAT.Sockets is
end; end;
end Mask; end Mask;
-------------------------
-- Unix_Socket_Address --
-------------------------
function Unix_Socket_Address (Addr : String) return Sock_Addr_Type is
begin
return Sock_Addr_Type'(Family_Unix, ASU.To_Unbounded_String (Addr));
end Unix_Socket_Address;
----------- -----------
-- "and" -- -- "and" --
----------- -----------
......
...@@ -45,6 +45,7 @@ ...@@ -45,6 +45,7 @@
with Ada.Exceptions; with Ada.Exceptions;
with Ada.Streams; with Ada.Streams;
with Ada.Strings.Unbounded;
with Ada.Unchecked_Deallocation; with Ada.Unchecked_Deallocation;
with Interfaces.C; with Interfaces.C;
...@@ -469,12 +470,14 @@ package GNAT.Sockets is ...@@ -469,12 +470,14 @@ package GNAT.Sockets is
-- Return a file descriptor to be used by external subprograms. This is -- Return a file descriptor to be used by external subprograms. This is
-- useful for C functions that are not yet interfaced in this package. -- useful for C functions that are not yet interfaced in this package.
type Family_Type is (Family_Inet, Family_Inet6, Family_Unspec); type Family_Type is (Family_Inet, Family_Inet6, Family_Unix, Family_Unspec);
-- Address family (or protocol family) identifies the communication domain -- Address family (or protocol family) identifies the communication domain
-- and groups protocols with similar address formats. -- and groups protocols with similar address formats.
-- The order of the enumeration elements should not be changed unilaterally -- The order of the enumeration elements should not be changed unilaterally
-- because the IPv6_TCP_Preferred routine rely on it. -- because the IPv6_TCP_Preferred routine rely on it.
subtype Family_Inet_4_6 is Family_Type range Family_Inet .. Family_Inet6;
type Mode_Type is (Socket_Stream, Socket_Datagram, Socket_Raw); type Mode_Type is (Socket_Stream, Socket_Datagram, Socket_Raw);
-- Stream sockets provide connection-oriented byte streams. Datagram -- Stream sockets provide connection-oriented byte streams. Datagram
-- sockets support unreliable connectionless message-based communication. -- sockets support unreliable connectionless message-based communication.
...@@ -502,8 +505,8 @@ package GNAT.Sockets is ...@@ -502,8 +505,8 @@ package GNAT.Sockets is
type Inet_Addr_Comp_Type is mod 2 ** 8; type Inet_Addr_Comp_Type is mod 2 ** 8;
-- Octet for Internet address -- Octet for Internet address
Inet_Addr_Bytes_Length : constant array (Family_Type) of Natural := Inet_Addr_Bytes_Length : constant array (Family_Inet_4_6) of Natural :=
(Family_Inet => 4, Family_Inet6 => 16, Family_Unspec => 0); (Family_Inet => 4, Family_Inet6 => 16);
type Inet_Addr_Bytes is array (Natural range <>) of Inet_Addr_Comp_Type; type Inet_Addr_Bytes is array (Natural range <>) of Inet_Addr_Comp_Type;
...@@ -515,7 +518,7 @@ package GNAT.Sockets is ...@@ -515,7 +518,7 @@ package GNAT.Sockets is
subtype Inet_Addr_VN_Type is Inet_Addr_Bytes; subtype Inet_Addr_VN_Type is Inet_Addr_Bytes;
-- For backwards compatibility -- For backwards compatibility
type Inet_Addr_Type (Family : Family_Type := Family_Inet) is record type Inet_Addr_Type (Family : Family_Inet_4_6 := Family_Inet) is record
case Family is case Family is
when Family_Inet => when Family_Inet =>
Sin_V4 : Inet_Addr_V4_Type := (others => 0); Sin_V4 : Inet_Addr_V4_Type := (others => 0);
...@@ -523,9 +526,6 @@ package GNAT.Sockets is ...@@ -523,9 +526,6 @@ package GNAT.Sockets is
when Family_Inet6 => when Family_Inet6 =>
Sin_V6 : Inet_Addr_V6_Type := (others => 0); Sin_V6 : Inet_Addr_V6_Type := (others => 0);
when Family_Unspec =>
null;
end case; end case;
end record; end record;
...@@ -541,10 +541,6 @@ package GNAT.Sockets is ...@@ -541,10 +541,6 @@ package GNAT.Sockets is
No_Inet_Addr : constant Inet_Addr_Type; No_Inet_Addr : constant Inet_Addr_Type;
-- Uninitialized inet address -- Uninitialized inet address
Unspecified_Addr : constant Inet_Addr_Type;
-- Unspecified address. Unlike of No_Inet_Addr the constraint is
-- Family_Unspec for this constant.
Broadcast_Inet_Addr : constant Inet_Addr_Type; Broadcast_Inet_Addr : constant Inet_Addr_Type;
-- Broadcast destination address in the current network -- Broadcast destination address in the current network
...@@ -581,7 +577,7 @@ package GNAT.Sockets is ...@@ -581,7 +577,7 @@ package GNAT.Sockets is
-- Functions to handle masks and prefixes -- Functions to handle masks and prefixes
function Mask function Mask
(Family : Family_Type; (Family : Family_Inet_4_6;
Length : Natural; Length : Natural;
Host : Boolean := False) return Inet_Addr_Type; Host : Boolean := False) return Inet_Addr_Type;
-- Return an address mask of the given family with the given prefix length. -- Return an address mask of the given family with the given prefix length.
...@@ -596,8 +592,15 @@ package GNAT.Sockets is ...@@ -596,8 +592,15 @@ package GNAT.Sockets is
-- same address family). -- same address family).
type Sock_Addr_Type (Family : Family_Type := Family_Inet) is record type Sock_Addr_Type (Family : Family_Type := Family_Inet) is record
Addr : Inet_Addr_Type (Family); case Family is
Port : Port_Type; when Family_Unix =>
Name : Ada.Strings.Unbounded.Unbounded_String;
when Family_Inet_4_6 =>
Addr : Inet_Addr_Type (Family);
Port : Port_Type;
when Family_Unspec =>
null;
end case;
end record; end record;
pragma No_Component_Reordering (Sock_Addr_Type); pragma No_Component_Reordering (Sock_Addr_Type);
-- Socket addresses fully define a socket connection with protocol family, -- Socket addresses fully define a socket connection with protocol family,
...@@ -619,12 +622,20 @@ package GNAT.Sockets is ...@@ -619,12 +622,20 @@ package GNAT.Sockets is
-- 8 hextets in hexadecimal format separated by colons. -- 8 hextets in hexadecimal format separated by colons.
function Image (Value : Sock_Addr_Type) return String; function Image (Value : Sock_Addr_Type) return String;
-- Return inet address image and port image separated by a colon -- Return socket address image. Network socket address image will be with
-- a port image separated by a colon.
function Inet_Addr (Image : String) return Inet_Addr_Type; function Inet_Addr (Image : String) return Inet_Addr_Type;
-- Convert address image from numbers-dots-and-colons notation into an -- Convert address image from numbers-dots-and-colons notation into an
-- inet address. -- inet address.
function Unix_Socket_Address (Addr : String) return Sock_Addr_Type;
-- Convert unix local socket name to Sock_Addr_Type
function Network_Socket_Address
(Addr : Inet_Addr_Type; Port : Port_Type) return Sock_Addr_Type;
-- Create network socket address
-- Host entries provide complete information on a given host: the official -- Host entries provide complete information on a given host: the official
-- name, an array of alternative names or aliases and array of network -- name, an array of alternative names or aliases and array of network
-- addresses. -- addresses.
...@@ -1439,6 +1450,8 @@ package GNAT.Sockets is ...@@ -1439,6 +1450,8 @@ package GNAT.Sockets is
private private
package ASU renames Ada.Strings.Unbounded;
type Socket_Type is new Integer; type Socket_Type is new Integer;
No_Socket : constant Socket_Type := -1; No_Socket : constant Socket_Type := -1;
...@@ -1493,8 +1506,6 @@ private ...@@ -1493,8 +1506,6 @@ private
(Family_Inet6, (others => 0)); (Family_Inet6, (others => 0));
No_Inet_Addr : constant Inet_Addr_Type := No_Inet_Addr : constant Inet_Addr_Type :=
(Family_Inet, (others => 0)); (Family_Inet, (others => 0));
Unspecified_Addr : constant Inet_Addr_Type :=
(Family => Family_Unspec);
Broadcast_Inet_Addr : constant Inet_Addr_Type := Broadcast_Inet_Addr : constant Inet_Addr_Type :=
(Family_Inet, (others => 255)); (Family_Inet, (others => 255));
Loopback_Inet_Addr : constant Inet_Addr_Type := Loopback_Inet_Addr : constant Inet_Addr_Type :=
......
...@@ -37,18 +37,59 @@ package body GNAT.Sockets.Thin_Common is ...@@ -37,18 +37,59 @@ package body GNAT.Sockets.Thin_Common is
procedure Set_Address procedure Set_Address
(Sin : Sockaddr_Access; (Sin : Sockaddr_Access;
Address : Sock_Addr_Type) Address : Sock_Addr_Type;
Length : out C.int)
is is
use type C.char;
function Network_Port return C.unsigned_short is
(Short_To_Network (C.unsigned_short (Address.Port))) with Inline;
begin begin
Set_Family (Sin.Sin_Family, Address.Family); Set_Family (Sin.Sin_Family, Address.Family);
Sin.Sin_Port := Short_To_Network (C.unsigned_short (Address.Port));
Length := C.int (Lengths (Address.Family));
case Address.Family is case Address.Family is
when Family_Inet => when Family_Inet =>
Sin.Sin_Port := Network_Port;
Sin.Sin_Addr := To_In_Addr (Address.Addr); Sin.Sin_Addr := To_In_Addr (Address.Addr);
when Family_Inet6 => when Family_Inet6 =>
Sin.Sin6_Port := Network_Port;
Sin.Sin6_Addr := To_In6_Addr (Address.Addr); Sin.Sin6_Addr := To_In6_Addr (Address.Addr);
Sin.Sin6_Scope_Id := 0; Sin.Sin6_Scope_Id := 0;
when Family_Unix =>
declare
use type C.size_t;
Name_Len : constant C.size_t :=
C.size_t (ASU.Length (Address.Name));
begin
Length := Sockaddr_Length_And_Family'Size / System.Storage_Unit
+ C.int (Name_Len);
if Name_Len > Sin.Sun_Path'Length then
raise Constraint_Error with
"Too big address length for UNIX local communication";
end if;
if Name_Len = 0 then
Sin.Sun_Path (1) := C.nul;
else
Sin.Sun_Path (1 .. Name_Len) :=
C.To_C (ASU.To_String (Address.Name), Append_Nul => False);
if Sin.Sun_Path (1) /= C.nul
and then Name_Len < Sin.Sun_Path'Length
then
Sin.Sun_Path (Name_Len + 1) := C.nul;
Length := Length + 1;
end if;
end if;
end;
when Family_Unspec => when Family_Unspec =>
null; null;
end case; end case;
...@@ -58,26 +99,39 @@ package body GNAT.Sockets.Thin_Common is ...@@ -58,26 +99,39 @@ package body GNAT.Sockets.Thin_Common is
-- Get_Address -- -- Get_Address --
----------------- -----------------
function Get_Address (Sin : Sockaddr) return Sock_Addr_Type is function Get_Address
use type C.unsigned_short; (Sin : Sockaddr; Length : C.int) return Sock_Addr_Type
is
use type C.unsigned_short, C.size_t, C.char, SOSC.OS_Type;
Family : constant C.unsigned_short := Family : constant C.unsigned_short :=
(if SOSC.Has_Sockaddr_Len = 0 then Sin.Sin_Family.Short_Family (if SOSC.Has_Sockaddr_Len = 0 then Sin.Sin_Family.Short_Family
else C.unsigned_short (Sin.Sin_Family.Char_Family)); else C.unsigned_short (Sin.Sin_Family.Char_Family));
AF_INET6_Defined : constant Boolean := SOSC.AF_INET6 > 0;
Result : Sock_Addr_Type Result : Sock_Addr_Type
(if AF_INET6_Defined and then SOSC.AF_INET6 = Family then Family_Inet6 (if SOSC.AF_INET6 > 0 and then SOSC.AF_INET6 = Family then Family_Inet6
elsif SOSC.AF_UNIX > 0 and then SOSC.AF_UNIX = Family then Family_Unix
elsif SOSC.AF_INET = Family then Family_Inet elsif SOSC.AF_INET = Family then Family_Inet
else Family_Unspec); else Family_Unspec);
begin begin
Result.Port := Port_Type (Network_To_Short (Sin.Sin_Port));
case Result.Family is case Result.Family is
when Family_Inet => when Family_Inet =>
Result.Port := Port_Type (Network_To_Short (Sin.Sin_Port));
To_Inet_Addr (Sin.Sin_Addr, Result.Addr); To_Inet_Addr (Sin.Sin_Addr, Result.Addr);
when Family_Inet6 => when Family_Inet6 =>
Result.Port := Port_Type (Network_To_Short (Sin.Sin6_Port));
To_Inet_Addr (Sin.Sin6_Addr, Result.Addr); To_Inet_Addr (Sin.Sin6_Addr, Result.Addr);
when Family_Unix =>
if Length > Sin.Sin_Family'Size / System.Storage_Unit then
Result.Name := ASU.To_Unbounded_String
(C.To_Ada
(Sin.Sun_Path
(1 .. C.size_t (Length)
- Sin.Sin_Family'Size / System.Storage_Unit),
Trim_Nul => Sin.Sun_Path (1) /= C.nul
or else SOSC.Target_OS = SOSC.Windows));
end if;
when Family_Unspec => when Family_Unspec =>
Result.Addr := (Family => Family_Unspec); null;
end case; end case;
return Result; return Result;
......
...@@ -75,11 +75,13 @@ package GNAT.Sockets.Thin_Common is ...@@ -75,11 +75,13 @@ package GNAT.Sockets.Thin_Common is
Families : constant array (Family_Type) of C.int := Families : constant array (Family_Type) of C.int :=
(Family_Unspec => SOSC.AF_UNSPEC, (Family_Unspec => SOSC.AF_UNSPEC,
Family_Unix => SOSC.AF_UNIX,
Family_Inet => SOSC.AF_INET, Family_Inet => SOSC.AF_INET,
Family_Inet6 => SOSC.AF_INET6); Family_Inet6 => SOSC.AF_INET6);
Lengths : constant array (Family_Type) of C.unsigned_char := Lengths : constant array (Family_Type) of C.unsigned_char :=
(Family_Unspec => 0, (Family_Unspec => 0,
Family_Unix => SOSC.SIZEOF_sockaddr_un,
Family_Inet => SOSC.SIZEOF_sockaddr_in, Family_Inet => SOSC.SIZEOF_sockaddr_in,
Family_Inet6 => SOSC.SIZEOF_sockaddr_in6); Family_Inet6 => SOSC.SIZEOF_sockaddr_in6);
...@@ -106,9 +108,7 @@ package GNAT.Sockets.Thin_Common is ...@@ -106,9 +108,7 @@ package GNAT.Sockets.Thin_Common is
when False => when False =>
Short_Family : C.unsigned_short; Short_Family : C.unsigned_short;
end case; end case;
end record; end record with Unchecked_Union, Convention => C;
pragma Unchecked_Union (Sockaddr_Length_And_Family);
pragma Convention (C, Sockaddr_Length_And_Family);
procedure Set_Family procedure Set_Family
(Length_And_Family : out Sockaddr_Length_And_Family; (Length_And_Family : out Sockaddr_Length_And_Family;
...@@ -122,9 +122,7 @@ package GNAT.Sockets.Thin_Common is ...@@ -122,9 +122,7 @@ package GNAT.Sockets.Thin_Common is
type In_Addr is record type In_Addr is record
S_B1, S_B2, S_B3, S_B4 : C.unsigned_char; S_B1, S_B2, S_B3, S_B4 : C.unsigned_char;
end record; end record with Convention => C, Alignment => C.int'Alignment;
for In_Addr'Alignment use C.int'Alignment;
pragma Convention (C, In_Addr);
-- IPv4 address, represented as a network-order C.int. Note that the -- IPv4 address, represented as a network-order C.int. Note that the
-- underlying operating system may assume that values of this type have -- underlying operating system may assume that values of this type have
-- C.int alignment, so we need to provide a suitable alignment clause here. -- C.int alignment, so we need to provide a suitable alignment clause here.
...@@ -138,9 +136,10 @@ package GNAT.Sockets.Thin_Common is ...@@ -138,9 +136,10 @@ package GNAT.Sockets.Thin_Common is
Result : out Inet_Addr_Type); Result : out Inet_Addr_Type);
-- Conversion functions -- Conversion functions
type In6_Addr is array (1 .. 16) of C.unsigned_char; type In6_Addr is array (1 .. 16) of C.unsigned_char with Convention => C;
for In6_Addr'Alignment use C.int'Alignment;
pragma Convention (C, In6_Addr); Unix_Name_Length : constant := 108;
-- Maximum length for local unix socket name
function To_In6_Addr (Addr : Inet_Addr_Type) return In6_Addr; function To_In6_Addr (Addr : Inet_Addr_Type) return In6_Addr;
procedure To_Inet_Addr procedure To_Inet_Addr
...@@ -149,14 +148,14 @@ package GNAT.Sockets.Thin_Common is ...@@ -149,14 +148,14 @@ package GNAT.Sockets.Thin_Common is
-- Conversion functions -- Conversion functions
type Sockaddr (Family : Family_Type := Family_Inet) is record type Sockaddr (Family : Family_Type := Family_Inet) is record
Sin_Family : Sockaddr_Length_And_Family;
-- Address family (and address length on some platforms)
Sin_Port : C.unsigned_short;
-- Port in network byte order
case Family is case Family is
when Family_Inet => when Family_Inet =>
Sin_Family : Sockaddr_Length_And_Family;
-- Address family (and address length on some platforms)
Sin_Port : C.unsigned_short;
-- Port in network byte order
Sin_Addr : In_Addr := (others => 0); Sin_Addr : In_Addr := (others => 0);
-- IPv4 address -- IPv4 address
...@@ -165,16 +164,28 @@ package GNAT.Sockets.Thin_Common is ...@@ -165,16 +164,28 @@ package GNAT.Sockets.Thin_Common is
-- --
-- Note that some platforms require that all unused (reserved) bytes -- Note that some platforms require that all unused (reserved) bytes
-- in addresses be initialized to 0 (e.g. VxWorks). -- in addresses be initialized to 0 (e.g. VxWorks).
when Family_Inet6 => when Family_Inet6 =>
Sin6_Family : Sockaddr_Length_And_Family;
-- Address family (and address length on some platforms)
Sin6_Port : C.unsigned_short;
-- Port in network byte order
Sin6_FlowInfo : Interfaces.Unsigned_32 := 0; Sin6_FlowInfo : Interfaces.Unsigned_32 := 0;
Sin6_Addr : In6_Addr := (others => 0); Sin6_Addr : In6_Addr := (others => 0);
Sin6_Scope_Id : Interfaces.Unsigned_32 := 0; Sin6_Scope_Id : Interfaces.Unsigned_32 := 0;
when Family_Unix =>
Sun_Family : Sockaddr_Length_And_Family;
-- Address family (and address length on some platforms)
Sun_Path : C.char_array (1 .. Unix_Name_Length);
when Family_Unspec => when Family_Unspec =>
null; null;
end case; end case;
end record; end record with Convention => C, Unchecked_Union;
pragma Unchecked_Union (Sockaddr);
pragma Convention (C, Sockaddr);
-- Internet socket address -- Internet socket address
type Sockaddr_Access is access all Sockaddr; type Sockaddr_Access is access all Sockaddr;
...@@ -183,13 +194,15 @@ package GNAT.Sockets.Thin_Common is ...@@ -183,13 +194,15 @@ package GNAT.Sockets.Thin_Common is
procedure Set_Address procedure Set_Address
(Sin : Sockaddr_Access; (Sin : Sockaddr_Access;
Address : Sock_Addr_Type); Address : Sock_Addr_Type;
Length : out C.int);
-- Initialise all necessary fields in Sin from Address. -- Initialise all necessary fields in Sin from Address.
-- Set appropriate Family, Port, and either Sin.Sin_Addr or Sin.Sin6_Addr -- Set appropriate Family, Port, and either Sin.Sin_Addr or Sin.Sin6_Addr
-- depend on family. -- depend on family.
-- Set the Length out parameter to the valuable Sockaddr data length.
function Get_Address (Sin : Sockaddr) return Sock_Addr_Type; function Get_Address (Sin : Sockaddr; Length : C.int) return Sock_Addr_Type;
-- Get Sock_Addr_Type from Sockaddr -- Get Sock_Addr_Type from Sockaddr and its valuable data Length
------------------ ------------------
-- Host entries -- -- Host entries --
......
...@@ -1053,6 +1053,11 @@ CND(AF_INET, "IPv4 address family") ...@@ -1053,6 +1053,11 @@ CND(AF_INET, "IPv4 address family")
#endif #endif
CND(AF_INET6, "IPv6 address family") CND(AF_INET6, "IPv6 address family")
#ifndef AF_UNIX
# define AF_UNIX -1
#endif
CND(AF_UNIX, "Local unix family")
#ifndef AF_UNSPEC #ifndef AF_UNSPEC
# define AF_UNSPEC -1 # define AF_UNSPEC -1
#else #else
...@@ -1701,6 +1706,19 @@ CND(SIZEOF_sockaddr_in, "struct sockaddr_in") ...@@ -1701,6 +1706,19 @@ CND(SIZEOF_sockaddr_in, "struct sockaddr_in")
#endif #endif
CND(SIZEOF_sockaddr_in6, "struct sockaddr_in6") CND(SIZEOF_sockaddr_in6, "struct sockaddr_in6")
/**
** The sockaddr_un structure is not defined in MINGW C headers
** but Windows supports it from build 17063.
**/
#if defined(__MINGW32__)
struct sockaddr_un {
ADDRESS_FAMILY sun_family; /* AF_UNIX */
char sun_path[108]; /* Pathname */
};
#endif
#define SIZEOF_sockaddr_un (sizeof (struct sockaddr_un))
CND(SIZEOF_sockaddr_un, "struct sockaddr_un")
#define SIZEOF_fd_set (sizeof (fd_set)) #define SIZEOF_fd_set (sizeof (fd_set))
CND(SIZEOF_fd_set, "fd_set") CND(SIZEOF_fd_set, "fd_set")
CND(FD_SETSIZE, "Max fd value") CND(FD_SETSIZE, "Max fd value")
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment