[Ada] Support for local unix sockets in GNAT.Sockets API
authorDmitriy Anisimkov <anisimko@adacore.com>
Tue, 17 Sep 2019 07:59:23 +0000 (07:59 +0000)
committerPierre-Marie de Rodat <pmderodat@gcc.gnu.org>
Tue, 17 Sep 2019 07:59:23 +0000 (07:59 +0000)
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

gcc/ada/ChangeLog
gcc/ada/gsocket.h
gcc/ada/libgnat/g-socket.adb
gcc/ada/libgnat/g-socket.ads
gcc/ada/libgnat/g-sothco.adb
gcc/ada/libgnat/g-sothco.ads
gcc/ada/s-oscons-tmplt.c

index ee7945cff06158cf73276b97378b451c075b5cd9..f5b72a085616da3b56e51673c61facec28eebb26 100644 (file)
@@ -1,3 +1,34 @@
+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>
 
        * exp_attr.adb (Expand_Size_Attribute): Chain the special cases
index c44e134165c1bb9237632f60c9e4f299d1937866..91a06b8197b76fa1a8142bf875ef81f06faab8fb 100644 (file)
  */
 #if !(defined (VMS) || defined (__MINGW32__))
 #include <sys/socket.h>
+#include <sys/un.h>
 #include <netinet/in.h>
 #include <netinet/tcp.h>
 #include <sys/ioctl.h>
index 51817ea94d55e684d26db8df6fbcc5574b6eade5..8565ccff53562b43d3e4186d5e256de663ec7132 100644 (file)
@@ -128,14 +128,12 @@ package body GNAT.Sockets is
    Socket_Error_Id : constant Exception_Id := Socket_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
          when Family_Inet =>
             In4 : In_Addr;
          when Family_Inet6 =>
             In6 : In6_Addr;
-         when Family_Unspec =>
-            null;
       end case;
    end record with Unchecked_Union;
 
@@ -291,7 +289,7 @@ package body GNAT.Sockets is
    --  or the null selector.
 
    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;
    --  Creates address from family and Inet_Addr_Bytes array.
 
@@ -354,7 +352,7 @@ package body GNAT.Sockets is
       end if;
 
       Socket := Socket_Type (Res);
-      Address := Get_Address (Sin);
+      Address := Get_Address (Sin, Len);
    end Accept_Socket;
 
    -------------------
@@ -465,12 +463,12 @@ package body GNAT.Sockets is
    is
       Res : C.int;
       Sin : aliased Sockaddr;
+      Len : C.int;
 
    begin
-      Set_Address (Sin'Unchecked_Access, Address);
+      Set_Address (Sin'Unchecked_Access, Address, Len);
 
-      Res := C_Bind
-        (C.int (Socket), Sin'Address, C.int (Lengths (Address.Family)));
+      Res := C_Bind (C.int (Socket), Sin'Address, Len);
 
       if Res = Failure then
          Raise_Socket_Error (Socket_Errno);
@@ -670,11 +668,11 @@ package body GNAT.Sockets is
       Server : Sock_Addr_Type) return C.int
    is
       Sin : aliased Sockaddr;
+      Len : C.int;
    begin
-      Set_Address (Sin'Unchecked_Access, Server);
+      Set_Address (Sin'Unchecked_Access, Server, Len);
 
-      return C_Connect
-        (C.int (Socket), Sin'Address, C.int (Lengths (Server.Family)));
+      return C_Connect (C.int (Socket), Sin'Address, Len);
    end Connect_Socket;
 
    procedure Connect_Socket
@@ -1039,10 +1037,17 @@ package body GNAT.Sockets is
          for J in Result'Range loop
             Look_For_Supported : loop
                if Iter = null then
+                  pragma Warnings
+                    (Off, "may be referenced before it has a value");
+
                   return Result (1 .. J - 1);
+
+                  pragma Warnings
+                    (On, "may be referenced before it has a value");
                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
                   Unsupported;
@@ -1071,10 +1076,6 @@ package body GNAT.Sockets is
                end if;
 
                Iter := Iter.ai_next;
-
-               if Iter = null then
-                  return Result (1 .. J - 1);
-               end if;
             end loop Look_For_Supported;
 
             Iter := Iter.ai_next;
@@ -1149,15 +1150,16 @@ package body GNAT.Sockets is
       Numeric_Host : Boolean := False;
       Numeric_Serv : Boolean := False) return Host_Service
    is
-      SA : aliased Sockaddr;
-      H  : aliased C.char_array := (1 .. SOSC.NI_MAXHOST => C.nul);
-      S  : aliased C.char_array := (1 .. SOSC.NI_MAXSERV => C.nul);
-      RC : C.int;
+      SA  : aliased Sockaddr;
+      H   : aliased C.char_array := (1 .. SOSC.NI_MAXHOST => C.nul);
+      S   : aliased C.char_array := (1 .. SOSC.NI_MAXSERV => C.nul);
+      RC  : C.int;
+      Len : C.int;
    begin
-      Set_Address (SA'Unchecked_Access, Addr);
+      Set_Address (SA'Unchecked_Access, Addr, Len);
 
       RC := C_Getnameinfo
-        (SA'Unchecked_Access, socklen_t (Lengths (Addr.Family)),
+        (SA'Unchecked_Access, socklen_t (Len),
          H'Unchecked_Access, H'Length,
          S'Unchecked_Access, S'Length,
          (if Numeric_Host then SOSC.NI_NUMERICHOST else 0) +
@@ -1197,9 +1199,6 @@ package body GNAT.Sockets is
             HA.In4 := To_In_Addr (Address);
          when Family_Inet6 =>
             HA.In6 := To_In6_Addr (Address);
-         when Family_Unspec =>
-            return (0, 0, (1, " "), (1 .. 0 => (1, " ")),
-                    (1 .. 0 => No_Inet_Addr));
       end case;
 
       Netdb_Lock;
@@ -1208,8 +1207,7 @@ package body GNAT.Sockets is
         (HA'Address,
          (case Address.Family is
              when Family_Inet => HA.In4'Size,
-             when Family_Inet6 => HA.In6'Size,
-             when Family_Unspec => 0) / 8,
+             when Family_Inet6 => HA.In6'Size) / 8,
          Families (Address.Family),
          Res'Access, Buf'Address, Buflen, Err'Access) /= 0
       then
@@ -1280,7 +1278,7 @@ package body GNAT.Sockets is
          Raise_Socket_Error (Socket_Errno);
       end if;
 
-      return Get_Address (Sin);
+      return Get_Address (Sin, Len);
    end Get_Peer_Name;
 
    -------------------------
@@ -1364,7 +1362,7 @@ package body GNAT.Sockets is
          return No_Sock_Addr;
       end if;
 
-      return Get_Address (Sin);
+      return Get_Address (Sin, Len);
    end Get_Socket_Name;
 
    -----------------------
@@ -1572,9 +1570,8 @@ package body GNAT.Sockets is
       Size : constant socklen_t :=
         (case Value.Family is
             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
-            when Family_Unspec => 0);
       Dst : aliased C.char_array := (1 .. C.size_t (Size) => C.nul);
       Ia  : aliased In_Addr_Union (Value.Family);
    begin
@@ -1583,8 +1580,6 @@ package body GNAT.Sockets is
             Ia.In6 := To_In6_Addr (Value);
          when Family_Inet =>
             Ia.In4 := To_In_Addr (Value);
-         when Family_Unspec =>
-            return "";
       end case;
 
       if Inet_Ntop
@@ -1602,11 +1597,30 @@ package body GNAT.Sockets is
    -----------
 
    function Image (Value : Sock_Addr_Type) return String is
-      Port : constant String := Value.Port'Img;
       function Ipv6_Brackets (S : String) return String is
         (if Value.Family = Family_Inet6 then "[" & S & "]" else S);
    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;
 
    -----------
@@ -1924,6 +1938,19 @@ package body GNAT.Sockets is
       end if;
    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 --
    --------------------------------
@@ -2139,7 +2166,7 @@ package body GNAT.Sockets is
 
       Last := Last_Index (First => Item'First, Count => size_t (Res));
 
-      From := Get_Address (Sin);
+      From := Get_Address (Sin, Len);
    end Receive_Socket;
 
    --------------------
@@ -2404,9 +2431,8 @@ package body GNAT.Sockets is
 
    begin
       if To /= null then
-         Set_Address (Sin'Unchecked_Access, To.all);
+         Set_Address (Sin'Unchecked_Access, To.all, Len);
          C_To := Sin'Address;
-         Len := C.int (Thin_Common.Lengths (To.Family));
 
       else
          C_To := System.Null_Address;
@@ -3055,12 +3081,11 @@ package body GNAT.Sockets is
    --------------------
 
    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
      (case Family is
          when Family_Inet => (Family_Inet, Bytes),
-         when Family_Inet6 => (Family_Inet6, Bytes),
-         when Family_Unspec => (Family => Family_Unspec));
+         when Family_Inet6 => (Family_Inet6, Bytes));
 
    ---------------
    -- Get_Bytes --
@@ -3069,15 +3094,14 @@ package body GNAT.Sockets is
    function Get_Bytes (Addr : Inet_Addr_Type) return Inet_Addr_Bytes is
      (case Addr.Family is
          when Family_Inet => Addr.Sin_V4,
-         when Family_Inet6 => Addr.Sin_V6,
-         when Family_Unspec => (1 .. 0 => 0));
+         when Family_Inet6 => Addr.Sin_V6);
 
    ----------
    -- Mask --
    ----------
 
    function Mask
-     (Family : Family_Type;
+     (Family : Family_Inet_4_6;
       Length : Natural;
       Host   : Boolean := False) return Inet_Addr_Type
    is
@@ -3109,6 +3133,15 @@ package body GNAT.Sockets is
       end;
    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" --
    -----------
index acd72f1e6502715695f21099ddc8d174f530786b..38d10784fc7440313efdd6a05b131093f1a791a8 100644 (file)
@@ -45,6 +45,7 @@
 
 with Ada.Exceptions;
 with Ada.Streams;
+with Ada.Strings.Unbounded;
 with Ada.Unchecked_Deallocation;
 
 with Interfaces.C;
@@ -469,12 +470,14 @@ package GNAT.Sockets 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.
 
-   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
    --  and groups protocols with similar address formats.
    --  The order of the enumeration elements should not be changed unilaterally
    --  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);
    --  Stream sockets provide connection-oriented byte streams. Datagram
    --  sockets support unreliable connectionless message-based communication.
@@ -502,8 +505,8 @@ package GNAT.Sockets is
    type Inet_Addr_Comp_Type is mod 2 ** 8;
    --  Octet for Internet address
 
-   Inet_Addr_Bytes_Length : constant array (Family_Type) of Natural :=
-     (Family_Inet => 4, Family_Inet6 => 16, Family_Unspec => 0);
+   Inet_Addr_Bytes_Length : constant array (Family_Inet_4_6) of Natural :=
+     (Family_Inet => 4, Family_Inet6 => 16);
 
    type Inet_Addr_Bytes is array (Natural range <>) of Inet_Addr_Comp_Type;
 
@@ -515,7 +518,7 @@ package GNAT.Sockets is
    subtype Inet_Addr_VN_Type is Inet_Addr_Bytes;
    --  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
          when Family_Inet =>
             Sin_V4 : Inet_Addr_V4_Type := (others => 0);
@@ -523,9 +526,6 @@ package GNAT.Sockets is
          when Family_Inet6 =>
             Sin_V6 : Inet_Addr_V6_Type := (others => 0);
 
-         when Family_Unspec =>
-            null;
-
       end case;
    end record;
 
@@ -541,10 +541,6 @@ package GNAT.Sockets is
    No_Inet_Addr        : constant Inet_Addr_Type;
    --  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 destination address in the current network
 
@@ -581,7 +577,7 @@ package GNAT.Sockets is
    --  Functions to handle masks and prefixes
 
    function Mask
-     (Family : Family_Type;
+     (Family : Family_Inet_4_6;
       Length : Natural;
       Host   : Boolean := False) return Inet_Addr_Type;
    --  Return an address mask of the given family with the given prefix length.
@@ -596,8 +592,15 @@ package GNAT.Sockets is
    --  same address family).
 
    type Sock_Addr_Type (Family : Family_Type := Family_Inet) is record
-      Addr : Inet_Addr_Type (Family);
-      Port : Port_Type;
+      case Family is
+         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;
    pragma No_Component_Reordering (Sock_Addr_Type);
    --  Socket addresses fully define a socket connection with protocol family,
@@ -619,12 +622,20 @@ package GNAT.Sockets is
    --  8 hextets in hexadecimal format separated by colons.
 
    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;
    --  Convert address image from numbers-dots-and-colons notation into an
    --  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
    --  name, an array of alternative names or aliases and array of network
    --  addresses.
@@ -1439,6 +1450,8 @@ package GNAT.Sockets is
 
 private
 
+   package ASU renames Ada.Strings.Unbounded;
+
    type Socket_Type is new Integer;
    No_Socket : constant Socket_Type := -1;
 
@@ -1493,8 +1506,6 @@ private
                            (Family_Inet6, (others => 0));
    No_Inet_Addr        : constant Inet_Addr_Type :=
                            (Family_Inet, (others => 0));
-   Unspecified_Addr    : constant Inet_Addr_Type :=
-                           (Family => Family_Unspec);
    Broadcast_Inet_Addr : constant Inet_Addr_Type :=
                            (Family_Inet, (others => 255));
    Loopback_Inet_Addr  : constant Inet_Addr_Type :=
index eb15ac2e8429fb38eb4bd1b8a083e31f6efb8462..9794d8b0ea18c69f3459529d993a3f046f23ebab 100644 (file)
@@ -37,18 +37,59 @@ package body GNAT.Sockets.Thin_Common is
 
    procedure Set_Address
      (Sin     : Sockaddr_Access;
-      Address : Sock_Addr_Type)
+      Address : Sock_Addr_Type;
+      Length  : out C.int)
    is
+      use type C.char;
+
+      function Network_Port return C.unsigned_short is
+        (Short_To_Network (C.unsigned_short (Address.Port))) with Inline;
+
    begin
       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
          when Family_Inet =>
+            Sin.Sin_Port := Network_Port;
             Sin.Sin_Addr := To_In_Addr (Address.Addr);
+
          when Family_Inet6 =>
+            Sin.Sin6_Port := Network_Port;
             Sin.Sin6_Addr := To_In6_Addr (Address.Addr);
             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 =>
             null;
       end case;
@@ -58,26 +99,39 @@ package body GNAT.Sockets.Thin_Common is
    -- Get_Address --
    -----------------
 
-   function Get_Address (Sin : Sockaddr) return Sock_Addr_Type is
-      use type C.unsigned_short;
+   function Get_Address
+     (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 :=
         (if SOSC.Has_Sockaddr_Len = 0 then Sin.Sin_Family.Short_Family
          else C.unsigned_short (Sin.Sin_Family.Char_Family));
-      AF_INET6_Defined : constant Boolean := SOSC.AF_INET6 > 0;
       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
          else Family_Unspec);
    begin
-      Result.Port := Port_Type (Network_To_Short (Sin.Sin_Port));
-
       case Result.Family is
          when Family_Inet =>
+            Result.Port := Port_Type (Network_To_Short (Sin.Sin_Port));
             To_Inet_Addr (Sin.Sin_Addr, Result.Addr);
          when Family_Inet6 =>
+            Result.Port := Port_Type (Network_To_Short (Sin.Sin6_Port));
             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 =>
-            Result.Addr := (Family => Family_Unspec);
+            null;
       end case;
 
       return Result;
index c62161d78570c9b5b30d2da6a63689ff6b6e9624..a68019c5125f67934682785d9542a27a32edd62c 100644 (file)
@@ -75,11 +75,13 @@ package GNAT.Sockets.Thin_Common is
 
    Families : constant array (Family_Type) of C.int :=
                 (Family_Unspec => SOSC.AF_UNSPEC,
+                 Family_Unix   => SOSC.AF_UNIX,
                  Family_Inet   => SOSC.AF_INET,
                  Family_Inet6  => SOSC.AF_INET6);
 
    Lengths  : constant array (Family_Type) of C.unsigned_char :=
                 (Family_Unspec => 0,
+                 Family_Unix   => SOSC.SIZEOF_sockaddr_un,
                  Family_Inet   => SOSC.SIZEOF_sockaddr_in,
                  Family_Inet6  => SOSC.SIZEOF_sockaddr_in6);
 
@@ -106,9 +108,7 @@ package GNAT.Sockets.Thin_Common is
          when False =>
             Short_Family : C.unsigned_short;
       end case;
-   end record;
-   pragma Unchecked_Union (Sockaddr_Length_And_Family);
-   pragma Convention (C, Sockaddr_Length_And_Family);
+   end record with Unchecked_Union, Convention => C;
 
    procedure Set_Family
      (Length_And_Family : out Sockaddr_Length_And_Family;
@@ -122,9 +122,7 @@ package GNAT.Sockets.Thin_Common is
 
    type In_Addr is record
       S_B1, S_B2, S_B3, S_B4 : C.unsigned_char;
-   end record;
-   for In_Addr'Alignment use C.int'Alignment;
-   pragma Convention (C, In_Addr);
+   end record with Convention => C, Alignment => C.int'Alignment;
    --  IPv4 address, represented as a network-order C.int. Note that the
    --  underlying operating system may assume that values of this type have
    --  C.int alignment, so we need to provide a suitable alignment clause here.
@@ -138,9 +136,10 @@ package GNAT.Sockets.Thin_Common is
       Result : out Inet_Addr_Type);
    --  Conversion functions
 
-   type In6_Addr is array (1 .. 16) of C.unsigned_char;
-   for In6_Addr'Alignment use C.int'Alignment;
-   pragma Convention (C, In6_Addr);
+   type In6_Addr is array (1 .. 16) of C.unsigned_char with Convention => C;
+
+   Unix_Name_Length : constant := 108;
+   --  Maximum length for local unix socket name
 
    function To_In6_Addr (Addr : Inet_Addr_Type) return In6_Addr;
    procedure To_Inet_Addr
@@ -149,14 +148,14 @@ package GNAT.Sockets.Thin_Common is
    --  Conversion functions
 
    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
       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);
          --  IPv4 address
 
@@ -165,16 +164,28 @@ package GNAT.Sockets.Thin_Common is
          --
          --  Note that some platforms require that all unused (reserved) bytes
          --  in addresses be initialized to 0 (e.g. VxWorks).
+
       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_Addr     : In6_Addr := (others => 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 =>
          null;
       end case;
-   end record;
-   pragma Unchecked_Union (Sockaddr);
-   pragma Convention (C, Sockaddr);
+   end record with Convention => C, Unchecked_Union;
    --  Internet socket address
 
    type Sockaddr_Access is access all Sockaddr;
@@ -183,13 +194,15 @@ package GNAT.Sockets.Thin_Common is
 
    procedure Set_Address
      (Sin     : Sockaddr_Access;
-      Address : Sock_Addr_Type);
+      Address : Sock_Addr_Type;
+      Length  : out C.int);
    --  Initialise all necessary fields in Sin from Address.
    --  Set appropriate Family, Port, and either Sin.Sin_Addr or Sin.Sin6_Addr
    --  depend on family.
+   --  Set the Length out parameter to the valuable Sockaddr data length.
 
-   function Get_Address (Sin : Sockaddr) return Sock_Addr_Type;
-   --  Get Sock_Addr_Type from Sockaddr
+   function Get_Address (Sin : Sockaddr; Length : C.int) return Sock_Addr_Type;
+   --  Get Sock_Addr_Type from Sockaddr and its valuable data Length
 
    ------------------
    -- Host entries --
index 655d68a79f2a9b96886532e9766c6cc88d72aadc..4c3ecc605729bab69729153c316ebc66194aefe4 100644 (file)
@@ -1053,6 +1053,11 @@ CND(AF_INET, "IPv4 address family")
 #endif
 CND(AF_INET6, "IPv6 address family")
 
+#ifndef AF_UNIX
+# define AF_UNIX -1
+#endif
+CND(AF_UNIX, "Local unix family")
+
 #ifndef AF_UNSPEC
 # define AF_UNSPEC -1
 #else
@@ -1701,6 +1706,19 @@ CND(SIZEOF_sockaddr_in, "struct sockaddr_in")
 #endif
 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))
 CND(SIZEOF_fd_set, "fd_set")
 CND(FD_SETSIZE, "Max fd value")