1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
5 -- G N A T . S O C K E T S . T H I N _ C O M M O N --
9 -- Copyright (C) 2008-2024, AdaCore --
11 -- GNAT is free software; you can redistribute it and/or modify it under --
12 -- terms of the GNU General Public License as published by the Free Soft- --
13 -- ware Foundation; either version 3, or (at your option) any later ver- --
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE. --
18 -- As a special exception under Section 7 of GPL version 3, you are granted --
19 -- additional permissions described in the GCC Runtime Library Exception, --
20 -- version 3.1, as published by the Free Software Foundation. --
22 -- You should have received a copy of the GNU General Public License and --
23 -- a copy of the GCC Runtime Library Exception along with this program; --
24 -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
25 -- <http://www.gnu.org/licenses/>. --
27 -- GNAT was originally developed by the GNAT team at New York University. --
28 -- Extensive contributions were provided by Ada Core Technologies Inc. --
30 ------------------------------------------------------------------------------
32 package body GNAT
.Sockets
.Thin_Common
is
39 (Sin
: Sockaddr_Access
;
40 Address
: Sock_Addr_Type
;
45 function Network_Port
return C
.unsigned_short
is
46 (Short_To_Network
(C
.unsigned_short
(Address
.Port
))) with Inline
;
49 Set_Family
(Sin
.Sin_Family
, Address
.Family
);
51 Length
:= C
.int
(Lengths
(Address
.Family
));
53 case Address
.Family
is
55 Sin
.Sin_Port
:= Network_Port
;
56 Sin
.Sin_Addr
:= To_In_Addr
(Address
.Addr
);
59 Sin
.Sin6_Port
:= Network_Port
;
60 Sin
.Sin6_Addr
:= To_In6_Addr
(Address
.Addr
);
61 Sin
.Sin6_Scope_Id
:= 0;
66 Name_Len
: constant C
.size_t
:=
67 C
.size_t
(ASU
.Length
(Address
.Name
));
69 Length
:= Sockaddr_Length_And_Family
'Size / System
.Storage_Unit
72 if Name_Len
> Sin
.Sun_Path
'Length then
73 raise Constraint_Error
with
74 "Too big address length for UNIX local communication";
78 Sin
.Sun_Path
(1) := C
.nul
;
81 Sin
.Sun_Path
(1 .. Name_Len
) :=
82 C
.To_C
(ASU
.To_String
(Address
.Name
), Append_Nul
=> False);
84 if Sin
.Sun_Path
(1) /= C
.nul
85 and then Name_Len
< Sin
.Sun_Path
'Length
87 Sin
.Sun_Path
(Name_Len
+ 1) := C
.nul
;
103 (Sin
: Sockaddr
; Length
: C
.int
) return Sock_Addr_Type
105 use type C
.unsigned_short
, C
.size_t
, C
.char
, SOSC
.OS_Type
;
106 Family
: constant C
.unsigned_short
:=
107 (if SOSC
.Has_Sockaddr_Len
= 0 then Sin
.Sin_Family
.Short_Family
108 else C
.unsigned_short
(Sin
.Sin_Family
.Char_Family
));
109 Result
: Sock_Addr_Type
110 (if SOSC
.AF_INET6
> 0 and then SOSC
.AF_INET6
= Family
then Family_Inet6
111 elsif SOSC
.AF_UNIX
> 0 and then SOSC
.AF_UNIX
= Family
then Family_Unix
112 elsif SOSC
.AF_INET
= Family
then Family_Inet
115 case Result
.Family
is
117 Result
.Port
:= Port_Type
(Network_To_Short
(Sin
.Sin_Port
));
118 To_Inet_Addr
(Sin
.Sin_Addr
, Result
.Addr
);
120 Result
.Port
:= Port_Type
(Network_To_Short
(Sin
.Sin6_Port
));
121 To_Inet_Addr
(Sin
.Sin6_Addr
, Result
.Addr
);
123 if Length
> Sin
.Sin_Family
'Size / System
.Storage_Unit
then
124 Result
.Name
:= ASU
.To_Unbounded_String
127 (1 .. C
.size_t
(Length
)
128 - Sin
.Sin_Family
'Size / System
.Storage_Unit
),
129 Trim_Nul
=> Sin
.Sun_Path
(1) /= C
.nul
130 or else SOSC
.Target_OS
= SOSC
.Windows
));
133 when Family_Unspec
=>
145 (Length_And_Family
: out Sockaddr_Length_And_Family
;
146 Family
: Family_Type
)
148 C_Family
: C
.int
renames Families
(Family
);
149 Has_Sockaddr_Len
: constant Boolean := SOSC
.Has_Sockaddr_Len
/= 0;
151 if Has_Sockaddr_Len
then
152 Length_And_Family
.Length
:= Lengths
(Family
);
153 Length_And_Family
.Char_Family
:= C
.unsigned_char
(C_Family
);
155 Length_And_Family
.Short_Family
:= C
.unsigned_short
(C_Family
);
163 function To_In_Addr
(Addr
: Inet_Addr_Type
) return In_Addr
is
165 if Addr
.Family
= Family_Inet
then
166 return (S_B1
=> C
.unsigned_char
(Addr
.Sin_V4
(1)),
167 S_B2
=> C
.unsigned_char
(Addr
.Sin_V4
(2)),
168 S_B3
=> C
.unsigned_char
(Addr
.Sin_V4
(3)),
169 S_B4
=> C
.unsigned_char
(Addr
.Sin_V4
(4)));
172 raise Socket_Error
with "IPv6 not supported";
179 procedure To_Inet_Addr
181 Result
: out Inet_Addr_Type
) is
183 Result
.Sin_V4
(1) := Inet_Addr_Comp_Type
(Addr
.S_B1
);
184 Result
.Sin_V4
(2) := Inet_Addr_Comp_Type
(Addr
.S_B2
);
185 Result
.Sin_V4
(3) := Inet_Addr_Comp_Type
(Addr
.S_B3
);
186 Result
.Sin_V4
(4) := Inet_Addr_Comp_Type
(Addr
.S_B4
);
193 procedure To_Inet_Addr
195 Result
: out Inet_Addr_Type
)
197 Sin_V6
: Inet_Addr_V6_Type
;
199 for J
in Addr
'Range loop
200 Sin_V6
(J
) := Inet_Addr_Comp_Type
(Addr
(J
));
203 Result
:= (Family
=> Family_Inet6
, Sin_V6
=> Sin_V6
);
210 function To_In6_Addr
(Addr
: Inet_Addr_Type
) return In6_Addr
is
213 for J
in Addr
.Sin_V6
'Range loop
214 Result
(J
) := C
.unsigned_char
(Addr
.Sin_V6
(J
));
220 ----------------------
221 -- Short_To_Network --
222 ----------------------
224 function Short_To_Network
(S
: C
.unsigned_short
) return C
.unsigned_short
is
229 -- Big-endian case. No conversion needed. On these platforms, htons()
230 -- defaults to a null procedure.
232 if Default_Bit_Order
= High_Order_First
then
235 -- Little-endian case. We must swap the high and low bytes of this
236 -- short to make the port number network compliant.
239 return C
.unsigned_short
(Rotate_Left
(Unsigned_16
(S
), 8));
241 end Short_To_Network
;
243 end GNAT
.Sockets
.Thin_Common
;