1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
5 -- G N A T . S O C K E T S --
9 -- Copyright (C) 2001-2023, 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 with Ada
.Containers
.Generic_Array_Sort
;
33 with Ada
.Exceptions
; use Ada
.Exceptions
;
34 with Ada
.Finalization
;
35 with Ada
.Streams
; use Ada
.Streams
;
36 with Ada
.Unchecked_Conversion
;
38 with GNAT
.Sockets
.Thin
; use GNAT
.Sockets
.Thin
;
39 with GNAT
.Sockets
.Thin_Common
; use GNAT
.Sockets
.Thin_Common
;
41 with GNAT
.Sockets
.Linker_Options
;
42 pragma Warnings
(Off
, GNAT
.Sockets
.Linker_Options
);
43 -- Need to include pragma Linker_Options which is platform dependent
45 with GNAT
.Sockets
.Poll
;
47 with System
; use System
;
48 with System
.Communication
; use System
.Communication
;
49 with System
.CRTL
; use System
.CRTL
;
50 with System
.Task_Lock
;
52 package body GNAT
.Sockets
is
54 package C
renames Interfaces
.C
;
56 type IPV6_Mreq
is record
57 ipv6mr_multiaddr
: In6_Addr
;
58 ipv6mr_interface
: C
.unsigned
;
59 end record with Convention
=> C
;
60 -- Record to Add/Drop_Membership for multicast in IPv6
62 ENOERROR
: constant := 0;
64 Netdb_Buffer_Size
: constant := SOSC
.Need_Netdb_Buffer
* 1024;
65 Need_Netdb_Lock
: constant Boolean := SOSC
.Need_Netdb_Lock
/= 0;
66 -- The network database functions gethostbyname, gethostbyaddr,
67 -- getservbyname and getservbyport can either be guaranteed task safe by
68 -- the operating system, or else return data through a user-provided buffer
69 -- to ensure concurrent uses do not interfere.
71 -- Correspondence tables
73 Levels
: constant array (Level_Type
) of C
.int
:=
74 [Socket_Level
=> SOSC
.SOL_SOCKET
,
75 IP_Protocol_For_IP_Level
=> SOSC
.IPPROTO_IP
,
76 IP_Protocol_For_IPv6_Level
=> SOSC
.IPPROTO_IPV6
,
77 IP_Protocol_For_UDP_Level
=> SOSC
.IPPROTO_UDP
,
78 IP_Protocol_For_TCP_Level
=> SOSC
.IPPROTO_TCP
,
79 IP_Protocol_For_ICMP_Level
=> SOSC
.IPPROTO_ICMP
,
80 IP_Protocol_For_IGMP_Level
=> SOSC
.IPPROTO_IGMP
,
81 IP_Protocol_For_RAW_Level
=> SOSC
.IPPROTO_RAW
];
83 Modes
: constant array (Mode_Type
) of C
.int
:=
84 [Socket_Stream
=> SOSC
.SOCK_STREAM
,
85 Socket_Datagram
=> SOSC
.SOCK_DGRAM
,
86 Socket_Raw
=> SOSC
.SOCK_RAW
];
88 Shutmodes
: constant array (Shutmode_Type
) of C
.int
:=
89 [Shut_Read
=> SOSC
.SHUT_RD
,
90 Shut_Write
=> SOSC
.SHUT_WR
,
91 Shut_Read_Write
=> SOSC
.SHUT_RDWR
];
93 Requests
: constant array (Request_Name
) of SOSC
.IOCTL_Req_T
:=
94 [Non_Blocking_IO
=> SOSC
.FIONBIO
,
95 N_Bytes_To_Read
=> SOSC
.FIONREAD
];
97 Options
: constant array (Specific_Option_Name
) of C
.int
:=
98 [Keep_Alive
=> SOSC
.SO_KEEPALIVE
,
99 Keep_Alive_Count
=> SOSC
.TCP_KEEPCNT
,
100 Keep_Alive_Idle
=> SOSC
.TCP_KEEPIDLE
,
101 Keep_Alive_Interval
=> SOSC
.TCP_KEEPINTVL
,
102 Reuse_Address
=> SOSC
.SO_REUSEADDR
,
103 Broadcast
=> SOSC
.SO_BROADCAST
,
104 Send_Buffer
=> SOSC
.SO_SNDBUF
,
105 Receive_Buffer
=> SOSC
.SO_RCVBUF
,
106 Linger
=> SOSC
.SO_LINGER
,
107 Error
=> SOSC
.SO_ERROR
,
108 No_Delay
=> SOSC
.TCP_NODELAY
,
109 Add_Membership_V4
=> SOSC
.IP_ADD_MEMBERSHIP
,
110 Drop_Membership_V4
=> SOSC
.IP_DROP_MEMBERSHIP
,
111 Multicast_If_V4
=> SOSC
.IP_MULTICAST_IF
,
112 Multicast_Loop_V4
=> SOSC
.IP_MULTICAST_LOOP
,
113 Receive_Packet_Info
=> SOSC
.IP_PKTINFO
,
114 Multicast_TTL
=> SOSC
.IP_MULTICAST_TTL
,
115 Add_Membership_V6
=> SOSC
.IPV6_ADD_MEMBERSHIP
,
116 Drop_Membership_V6
=> SOSC
.IPV6_DROP_MEMBERSHIP
,
117 Multicast_If_V6
=> SOSC
.IPV6_MULTICAST_IF
,
118 Multicast_Loop_V6
=> SOSC
.IPV6_MULTICAST_LOOP
,
119 Multicast_Hops
=> SOSC
.IPV6_MULTICAST_HOPS
,
120 IPv6_Only
=> SOSC
.IPV6_V6ONLY
,
121 Send_Timeout
=> SOSC
.SO_SNDTIMEO
,
122 Receive_Timeout
=> SOSC
.SO_RCVTIMEO
,
123 Busy_Polling
=> SOSC
.SO_BUSY_POLL
,
124 Bind_To_Device
=> SOSC
.SO_BINDTODEVICE
];
125 -- ??? Note: for OpenSolaris, Receive_Packet_Info should be IP_RECVPKTINFO,
126 -- but for Linux compatibility this constant is the same as IP_PKTINFO.
128 Flags
: constant array (0 .. 3) of C
.int
:=
129 [0 => SOSC
.MSG_OOB
, -- Process_Out_Of_Band_Data
130 1 => SOSC
.MSG_PEEK
, -- Peek_At_Incoming_Data
131 2 => SOSC
.MSG_WAITALL
, -- Wait_For_A_Full_Reception
132 3 => SOSC
.MSG_EOR
]; -- Send_End_Of_Record
134 Socket_Error_Id
: constant Exception_Id
:= Socket_Error
'Identity;
135 Host_Error_Id
: constant Exception_Id
:= Host_Error
'Identity;
137 type In_Addr_Union
(Family
: Family_Inet_4_6
) is record
144 end record with Unchecked_Union
;
146 -----------------------
147 -- Local subprograms --
148 -----------------------
150 function Resolve_Error
151 (Error_Value
: Integer;
152 From_Errno
: Boolean := True) return Error_Type
;
153 -- Associate an enumeration value (error_type) to an error value (errno).
154 -- From_Errno prevents from mixing h_errno with errno.
156 function To_Name
(N
: String) return Name_Type
;
157 function To_String
(HN
: Name_Type
) return String;
158 -- Conversion functions
160 function To_Int
(F
: Request_Flag_Type
) return C
.int
;
161 -- Return the int value corresponding to the specified flags combination
163 function Set_Forced_Flags
(F
: C
.int
) return C
.int
;
164 -- Return F with the bits from SOSC.MSG_Forced_Flags forced set
166 procedure Netdb_Lock
;
167 pragma Inline
(Netdb_Lock
);
168 procedure Netdb_Unlock
;
169 pragma Inline
(Netdb_Unlock
);
170 -- Lock/unlock operation used to protect netdb access for platforms that
171 -- require such protection.
173 function To_Host_Entry
(E
: Hostent_Access
) return Host_Entry_Type
;
174 -- Conversion function
176 function To_Service_Entry
(E
: Servent_Access
) return Service_Entry_Type
;
177 -- Conversion function
179 function Value
(S
: System
.Address
) return String;
180 -- Same as Interfaces.C.Strings.Value but taking a System.Address
182 function To_Timeval
(Val
: Timeval_Duration
) return Timeval
;
183 -- Separate Val in seconds and microseconds
185 function To_Duration
(Val
: Timeval
) return Timeval_Duration
;
186 -- Reconstruct a Duration value from a Timeval record (seconds and
189 function Dedot
(Value
: String) return String
190 is (if Value
/= "" and then Value
(Value
'Last) = '.'
191 then Value
(Value
'First .. Value
'Last - 1)
193 -- Removes dot at the end of error message
195 procedure Raise_Host_Error
(H_Error
: Integer; Name
: String)
197 -- Raise Host_Error exception with message describing error code (note
198 -- hstrerror seems to be obsolete) from h_errno. Name is the name
199 -- or address that was being looked up.
201 procedure Raise_GAI_Error
(RC
: C
.int
; Name
: String)
203 -- Raise Host_Error with exception message in case of errors in
204 -- getaddrinfo and getnameinfo.
206 function Is_Windows
return Boolean with Inline
;
207 -- Returns True on Windows platform
209 procedure Narrow
(Item
: in out Socket_Set_Type
);
210 -- Update Last as it may be greater than the real last socket
212 procedure Check_For_Fd_Set
(Fd
: Socket_Type
);
213 pragma Inline
(Check_For_Fd_Set
);
214 -- Raise Constraint_Error if Fd is less than 0 or greater than or equal to
215 -- FD_SETSIZE, on platforms where fd_set is a bitmap.
217 function Connect_Socket
218 (Socket
: Socket_Type
;
219 Server
: Sock_Addr_Type
) return C
.int
;
220 pragma Inline
(Connect_Socket
);
221 -- Underlying implementation for the Connect_Socket procedures
223 -- Types needed for Datagram_Socket_Stream_Type
225 type Datagram_Socket_Stream_Type
is new Root_Stream_Type
with record
226 Socket
: Socket_Type
;
228 From
: Sock_Addr_Type
;
231 type Datagram_Socket_Stream_Access
is
232 access all Datagram_Socket_Stream_Type
;
235 (Stream
: in out Datagram_Socket_Stream_Type
;
236 Item
: out Ada
.Streams
.Stream_Element_Array
;
237 Last
: out Ada
.Streams
.Stream_Element_Offset
);
240 (Stream
: in out Datagram_Socket_Stream_Type
;
241 Item
: Ada
.Streams
.Stream_Element_Array
);
243 -- Types needed for Stream_Socket_Stream_Type
245 type Stream_Socket_Stream_Type
is new Root_Stream_Type
with record
246 Socket
: Socket_Type
;
249 type Stream_Socket_Stream_Access
is
250 access all Stream_Socket_Stream_Type
;
253 (Stream
: in out Stream_Socket_Stream_Type
;
254 Item
: out Ada
.Streams
.Stream_Element_Array
;
255 Last
: out Ada
.Streams
.Stream_Element_Offset
);
258 (Stream
: in out Stream_Socket_Stream_Type
;
259 Item
: Ada
.Streams
.Stream_Element_Array
);
261 procedure Wait_On_Socket
262 (Socket
: Socket_Type
;
263 Event
: Poll
.Wait_Event_Set
;
264 Timeout
: Selector_Duration
;
265 Selector
: access Selector_Type
:= null;
266 Status
: out Selector_Status
);
267 -- Common code for variants of socket operations supporting a timeout:
268 -- block in Poll.Wait on Socket for at most the indicated timeout.
269 -- Event parameter defines what the Poll.Wait is waiting for.
271 type Sockets_Library_Controller
is new Ada
.Finalization
.Limited_Controlled
273 -- This type is used to generate automatic calls to Initialize and Finalize
274 -- during the elaboration and finalization of this package. A single object
275 -- of this type must exist at library level.
277 function Err_Code_Image
(E
: Integer) return String;
278 -- Return the value of E surrounded with brackets
280 procedure Initialize
(X
: in out Sockets_Library_Controller
);
281 procedure Finalize
(X
: in out Sockets_Library_Controller
);
283 procedure Normalize_Empty_Socket_Set
(S
: in out Socket_Set_Type
);
284 -- If S is the empty set (detected by Last = No_Socket), make sure its
285 -- fd_set component is actually cleared. Note that the case where it is
286 -- not can occur for an uninitialized Socket_Set_Type object.
288 function Is_Open
(S
: Selector_Type
) return Boolean;
289 -- Return True for an "open" Selector_Type object, i.e. one for which
290 -- Create_Selector has been called and Close_Selector has not been called,
291 -- or the null selector.
293 function Create_Address
294 (Family
: Family_Inet_4_6
; Bytes
: Inet_Addr_Bytes
) return Inet_Addr_Type
296 -- Creates address from family and Inet_Addr_Bytes array
298 function Get_Bytes
(Addr
: Inet_Addr_Type
) return Inet_Addr_Bytes
300 -- Extract bytes from address
306 function "+" (L
, R
: Request_Flag_Type
) return Request_Flag_Type
is
315 procedure Abort_Selector
(Selector
: Selector_Type
) is
319 if not Is_Open
(Selector
) then
320 raise Program_Error
with "closed selector";
322 elsif Selector
.Is_Null
then
323 raise Program_Error
with "null selector";
327 -- Send one byte to unblock select system call
329 Res
:= Signalling_Fds
.Write
(C
.int
(Selector
.W_Sig_Socket
));
331 if Res
= Failure
then
332 Raise_Socket_Error
(Socket_Errno
);
340 procedure Accept_Socket
341 (Server
: Socket_Type
;
342 Socket
: out Socket_Type
;
343 Address
: out Sock_Addr_Type
)
346 Sin
: aliased Sockaddr
;
347 Len
: aliased C
.int
:= Sin
'Size / 8;
350 Res
:= C_Accept
(C
.int
(Server
), Sin
'Address, Len
'Access);
352 if Res
= Failure
then
353 Raise_Socket_Error
(Socket_Errno
);
356 Socket
:= Socket_Type
(Res
);
357 Address
:= Get_Address
(Sin
, Len
);
364 procedure Accept_Socket
365 (Server
: Socket_Type
;
366 Socket
: out Socket_Type
;
367 Address
: out Sock_Addr_Type
;
368 Timeout
: Selector_Duration
;
369 Selector
: access Selector_Type
:= null;
370 Status
: out Selector_Status
)
373 if Selector
/= null and then not Is_Open
(Selector
.all) then
374 raise Program_Error
with "closed selector";
377 -- Wait for socket to become available for reading
381 Event
=> Poll
.Input_Event
,
383 Selector
=> Selector
,
386 -- Accept connection if available
388 if Status
= Completed
then
389 Accept_Socket
(Server
, Socket
, Address
);
400 (E
: Host_Entry_Type
;
401 N
: Positive := 1) return Inet_Addr_Type
404 return E
.Addresses
(N
);
407 ----------------------
408 -- Addresses_Length --
409 ----------------------
411 function Addresses_Length
(E
: Host_Entry_Type
) return Natural is
413 return E
.Addresses_Length
;
414 end Addresses_Length
;
421 (E
: Host_Entry_Type
;
422 N
: Positive := 1) return String
425 return To_String
(E
.Aliases
(N
));
433 (S
: Service_Entry_Type
;
434 N
: Positive := 1) return String
437 return To_String
(S
.Aliases
(N
));
444 function Aliases_Length
(E
: Host_Entry_Type
) return Natural is
446 return E
.Aliases_Length
;
453 function Aliases_Length
(S
: Service_Entry_Type
) return Natural is
455 return S
.Aliases_Length
;
462 procedure Bind_Socket
463 (Socket
: Socket_Type
;
464 Address
: Sock_Addr_Type
)
467 Sin
: aliased Sockaddr
;
471 Set_Address
(Sin
'Unchecked_Access, Address
, Len
);
473 Res
:= C_Bind
(C
.int
(Socket
), Sin
'Address, Len
);
475 if Res
= Failure
then
476 Raise_Socket_Error
(Socket_Errno
);
480 ----------------------
481 -- Check_For_Fd_Set --
482 ----------------------
484 procedure Check_For_Fd_Set
(Fd
: Socket_Type
) is
486 -- On Windows, fd_set is a FD_SETSIZE array of socket ids:
487 -- no check required. Warnings suppressed because condition
488 -- is known at compile time.
494 -- On other platforms, fd_set is an FD_SETSIZE bitmap: check
495 -- that Fd is within range (otherwise behavior is undefined).
497 elsif Fd
< 0 or else Fd
>= SOSC
.FD_SETSIZE
then
498 raise Constraint_Error
499 with "invalid value for socket set: " & Image
(Fd
);
501 end Check_For_Fd_Set
;
507 procedure Check_Selector
508 (Selector
: Selector_Type
;
509 R_Socket_Set
: in out Socket_Set_Type
;
510 W_Socket_Set
: in out Socket_Set_Type
;
511 Status
: out Selector_Status
;
512 Timeout
: Selector_Duration
:= Forever
)
514 E_Socket_Set
: Socket_Set_Type
;
517 (Selector
, R_Socket_Set
, W_Socket_Set
, E_Socket_Set
, Status
, Timeout
);
520 procedure Check_Selector
521 (Selector
: Selector_Type
;
522 R_Socket_Set
: in out Socket_Set_Type
;
523 W_Socket_Set
: in out Socket_Set_Type
;
524 E_Socket_Set
: in out Socket_Set_Type
;
525 Status
: out Selector_Status
;
526 Timeout
: Selector_Duration
:= Forever
)
530 RSig
: Socket_Type
:= No_Socket
;
531 TVal
: aliased Timeval
;
532 TPtr
: Timeval_Access
;
535 if not Is_Open
(Selector
) then
536 raise Program_Error
with "closed selector";
541 -- No timeout or Forever is indicated by a null timeval pointer
543 if Timeout
= Forever
then
546 TVal
:= To_Timeval
(Timeout
);
547 TPtr
:= TVal
'Unchecked_Access;
550 -- Add read signalling socket, if present
552 if not Selector
.Is_Null
then
553 RSig
:= Selector
.R_Sig_Socket
;
554 Set
(R_Socket_Set
, RSig
);
557 Last
:= C
.int
'Max (C
.int
'Max (C
.int
(R_Socket_Set
.Last
),
558 C
.int
(W_Socket_Set
.Last
)),
559 C
.int
(E_Socket_Set
.Last
));
561 -- Zero out fd_set for empty Socket_Set_Type objects
563 Normalize_Empty_Socket_Set
(R_Socket_Set
);
564 Normalize_Empty_Socket_Set
(W_Socket_Set
);
565 Normalize_Empty_Socket_Set
(E_Socket_Set
);
570 R_Socket_Set
.Set
'Access,
571 W_Socket_Set
.Set
'Access,
572 E_Socket_Set
.Set
'Access,
575 if Res
= Failure
then
576 Raise_Socket_Error
(Socket_Errno
);
579 -- If Select was resumed because of read signalling socket, read this
580 -- data and remove socket from set.
582 if RSig
/= No_Socket
and then Is_Set
(R_Socket_Set
, RSig
) then
583 Clear
(R_Socket_Set
, RSig
);
585 Res
:= Signalling_Fds
.Read
(C
.int
(RSig
));
587 if Res
= Failure
then
588 Raise_Socket_Error
(Socket_Errno
);
597 -- Update socket sets in regard to their new contents
599 Narrow
(R_Socket_Set
);
600 Narrow
(W_Socket_Set
);
601 Narrow
(E_Socket_Set
);
609 (Item
: in out Socket_Set_Type
;
610 Socket
: Socket_Type
)
612 Last
: aliased C
.int
:= C
.int
(Item
.Last
);
615 Check_For_Fd_Set
(Socket
);
617 if Item
.Last
/= No_Socket
then
618 Remove_Socket_From_Set
(Item
.Set
'Access, C
.int
(Socket
));
619 Last_Socket_In_Set
(Item
.Set
'Access, Last
'Unchecked_Access);
620 Item
.Last
:= Socket_Type
(Last
);
628 procedure Close_Selector
(Selector
: in out Selector_Type
) is
630 -- Nothing to do if selector already in closed state
632 if Selector
.Is_Null
or else not Is_Open
(Selector
) then
636 -- Close the signalling file descriptors used internally for the
637 -- implementation of Abort_Selector.
639 Signalling_Fds
.Close
(C
.int
(Selector
.R_Sig_Socket
));
640 Signalling_Fds
.Close
(C
.int
(Selector
.W_Sig_Socket
));
642 -- Reset R_Sig_Socket and W_Sig_Socket to No_Socket to ensure that any
643 -- (erroneous) subsequent attempt to use this selector properly fails.
645 Selector
.R_Sig_Socket
:= No_Socket
;
646 Selector
.W_Sig_Socket
:= No_Socket
;
653 procedure Close_Socket
(Socket
: Socket_Type
) is
657 Res
:= C_Close
(C
.int
(Socket
));
659 if Res
= Failure
then
660 Raise_Socket_Error
(Socket_Errno
);
668 function Connect_Socket
669 (Socket
: Socket_Type
;
670 Server
: Sock_Addr_Type
) return C
.int
672 Sin
: aliased Sockaddr
;
675 Set_Address
(Sin
'Unchecked_Access, Server
, Len
);
677 return C_Connect
(C
.int
(Socket
), Sin
'Address, Len
);
680 procedure Connect_Socket
681 (Socket
: Socket_Type
;
682 Server
: Sock_Addr_Type
)
685 if Connect_Socket
(Socket
, Server
) = Failure
then
686 Raise_Socket_Error
(Socket_Errno
);
690 procedure Connect_Socket
691 (Socket
: Socket_Type
;
692 Server
: Sock_Addr_Type
;
693 Timeout
: Selector_Duration
;
694 Selector
: access Selector_Type
:= null;
695 Status
: out Selector_Status
)
698 -- Used to set Socket to non-blocking I/O
700 Conn_Err
: aliased Integer;
701 -- Error status of the socket after completion of select(2)
704 Conn_Err_Size
: aliased C
.int
:= Conn_Err
'Size / 8;
705 -- For getsockopt(2) call
708 if Selector
/= null and then not Is_Open
(Selector
.all) then
709 raise Program_Error
with "closed selector";
712 -- Set the socket to non-blocking I/O
714 Req
:= (Name
=> Non_Blocking_IO
, Enabled
=> True);
715 Control_Socket
(Socket
, Request
=> Req
);
717 -- Start operation (non-blocking), will return Failure with errno set
720 Res
:= Connect_Socket
(Socket
, Server
);
721 if Res
= Failure
then
722 Conn_Err
:= Socket_Errno
;
723 if Conn_Err
/= SOSC
.EINPROGRESS
then
724 Raise_Socket_Error
(Conn_Err
);
728 -- Wait for socket to become available for writing (unless the Timeout
729 -- is zero, in which case we consider that it has already expired, and
730 -- we do not need to wait at all).
732 if Timeout
= 0.0 then
738 Event
=> Poll
.Output_Event
,
740 Selector
=> Selector
,
744 -- Check error condition (the asynchronous connect may have terminated
745 -- with an error, e.g. ECONNREFUSED) if select(2) completed.
747 if Status
= Completed
then
749 (C
.int
(Socket
), SOSC
.SOL_SOCKET
, SOSC
.SO_ERROR
,
750 Conn_Err
'Address, Conn_Err_Size
'Access);
753 Conn_Err
:= Socket_Errno
;
760 -- Reset the socket to blocking I/O
762 Req
:= (Name
=> Non_Blocking_IO
, Enabled
=> False);
763 Control_Socket
(Socket
, Request
=> Req
);
765 -- Report error condition if any
767 if Conn_Err
/= 0 then
768 Raise_Socket_Error
(Conn_Err
);
776 procedure Control_Socket
777 (Socket
: Socket_Type
;
778 Request
: in out Request_Type
)
785 when Non_Blocking_IO
=>
786 Arg
:= C
.int
(Boolean'Pos (Request
.Enabled
));
788 when N_Bytes_To_Read
=>
793 (C
.int
(Socket
), Requests
(Request
.Name
), Arg
'Unchecked_Access);
795 if Res
= Failure
then
796 Raise_Socket_Error
(Socket_Errno
);
800 when Non_Blocking_IO
=>
803 when N_Bytes_To_Read
=>
804 Request
.Size
:= Natural (Arg
);
813 (Source
: Socket_Set_Type
;
814 Target
: out Socket_Set_Type
)
820 ---------------------
821 -- Create_Selector --
822 ---------------------
824 procedure Create_Selector
(Selector
: out Selector_Type
) is
825 Two_Fds
: aliased Fd_Pair
;
829 if Is_Open
(Selector
) then
830 -- Raise exception to prevent socket descriptor leak
832 raise Program_Error
with "selector already open";
835 -- We open two signalling file descriptors. One of them is used to send
836 -- data to the other, which is included in a C_Select socket set. The
837 -- communication is used to force a call to C_Select to complete, and
838 -- the waiting task to resume its execution.
840 Res
:= Signalling_Fds
.Create
(Two_Fds
'Access);
841 pragma Annotate
(CodePeer
, Modified
, Two_Fds
);
843 if Res
= Failure
then
844 Raise_Socket_Error
(Socket_Errno
);
847 Selector
.R_Sig_Socket
:= Socket_Type
(Two_Fds
(Read_End
));
848 Selector
.W_Sig_Socket
:= Socket_Type
(Two_Fds
(Write_End
));
855 procedure Create_Socket
856 (Socket
: out Socket_Type
;
857 Family
: Family_Type
:= Family_Inet
;
858 Mode
: Mode_Type
:= Socket_Stream
;
859 Level
: Level_Type
:= IP_Protocol_For_IP_Level
)
864 Res
:= C_Socket
(Families
(Family
), Modes
(Mode
), Levels
(Level
));
866 if Res
= Failure
then
867 Raise_Socket_Error
(Socket_Errno
);
870 Socket
:= Socket_Type
(Res
);
873 ------------------------
874 -- Create_Socket_Pair --
875 ------------------------
877 procedure Create_Socket_Pair
878 (Left
: out Socket_Type
;
879 Right
: out Socket_Type
;
880 Family
: Family_Type
:= Family_Unspec
;
881 Mode
: Mode_Type
:= Socket_Stream
;
882 Level
: Level_Type
:= IP_Protocol_For_IP_Level
)
885 Pair
: aliased Thin_Common
.Fd_Pair
;
889 ((if Family
= Family_Unspec
then Default_Socket_Pair_Family
890 else Families
(Family
)),
891 Modes
(Mode
), Levels
(Level
), Pair
'Access);
892 pragma Annotate
(CodePeer
, Modified
, Pair
);
894 if Res
= Failure
then
895 Raise_Socket_Error
(Socket_Errno
);
898 Left
:= Socket_Type
(Pair
(Pair
'First));
899 Right
:= Socket_Type
(Pair
(Pair
'Last));
900 end Create_Socket_Pair
;
906 procedure Empty
(Item
: out Socket_Set_Type
) is
908 Reset_Socket_Set
(Item
.Set
'Access);
909 Item
.Last
:= No_Socket
;
916 function Err_Code_Image
(E
: Integer) return String is
917 Msg
: String := E
'Img & "] ";
919 Msg
(Msg
'First) := '[';
927 procedure Finalize
(X
: in out Sockets_Library_Controller
) is
928 pragma Unreferenced
(X
);
931 -- Finalization operation for the GNAT.Sockets package
940 procedure Finalize
is
942 -- This is a dummy placeholder for an obsolete API.
943 -- The real finalization actions are in Initialize primitive operation
944 -- of Sockets_Library_Controller.
954 (Item
: in out Socket_Set_Type
;
955 Socket
: out Socket_Type
)
958 L
: aliased C
.int
:= C
.int
(Item
.Last
);
961 if Item
.Last
/= No_Socket
then
963 (Item
.Set
'Access, Last
=> L
'Access, Socket
=> S
'Access);
964 pragma Annotate
(CodePeer
, Modified
, L
);
965 pragma Annotate
(CodePeer
, Modified
, S
);
967 Item
.Last
:= Socket_Type
(L
);
968 Socket
:= Socket_Type
(S
);
980 (Stream
: not null Stream_Access
) return Sock_Addr_Type
983 if Stream
.all in Datagram_Socket_Stream_Type
then
984 return Datagram_Socket_Stream_Type
(Stream
.all).From
;
986 return Get_Peer_Name
(Stream_Socket_Stream_Type
(Stream
.all).Socket
);
990 ---------------------
991 -- Raise_GAI_Error --
992 ---------------------
994 procedure Raise_GAI_Error
(RC
: C
.int
; Name
: String) is
996 if RC
= SOSC
.EAI_SYSTEM
then
998 Errcode
: constant Integer := Socket_Errno
;
1000 raise Host_Error
with Err_Code_Image
(Errcode
)
1001 & Dedot
(Socket_Error_Message
(Errcode
)) & ": " & Name
;
1004 raise Host_Error
with Err_Code_Image
(Integer (RC
))
1005 & Dedot
(CS
.Value
(C_GAI_Strerror
(RC
))) & ": " & Name
;
1007 end Raise_GAI_Error
;
1009 ----------------------
1010 -- Get_Address_Info --
1011 ----------------------
1013 function Get_Address_Info
1016 Family
: Family_Type
:= Family_Unspec
;
1017 Mode
: Mode_Type
:= Socket_Stream
;
1018 Level
: Level_Type
:= IP_Protocol_For_IP_Level
;
1019 Numeric_Host
: Boolean := False;
1020 Passive
: Boolean := False;
1021 Unknown
: access procedure
1022 (Family
, Mode
, Level
, Length
: Integer) := null)
1023 return Address_Info_Array
1025 A
: aliased Addrinfo_Access
;
1026 N
: aliased C
.char_array
:= C
.To_C
(Host
);
1027 S
: aliased C
.char_array
:= C
.To_C
(if Service
= "" then "0"
1029 Hints
: aliased constant Addrinfo
:=
1030 (ai_family
=> Families
(Family
),
1031 ai_socktype
=> Modes
(Mode
),
1032 ai_protocol
=> Levels
(Level
),
1033 ai_flags
=> (if Numeric_Host
then SOSC
.AI_NUMERICHOST
else 0) +
1034 (if Passive
then SOSC
.AI_PASSIVE
else 0),
1039 Iter
: Addrinfo_Access
;
1041 function To_Array
return Address_Info_Array
;
1042 -- Convert taken from OS addrinfo list A into Address_Info_Array
1048 function To_Array
return Address_Info_Array
is
1049 procedure Unsupported
;
1050 -- Calls Unknown callback if defiend
1056 procedure Unsupported
is
1058 if Unknown
/= null then
1060 (Integer (Iter
.ai_family
),
1061 Integer (Iter
.ai_socktype
),
1062 Integer (Iter
.ai_protocol
),
1063 Integer (Iter
.ai_addrlen
));
1068 Result
: Address_Info_Array
(1 .. 8);
1070 -- Start of processing for To_Array
1073 for J
in Result
'Range loop
1074 Look_For_Supported
: loop
1077 (Off
, "may be referenced before it has a value");
1079 return Result
(1 .. J
- 1);
1082 (On
, "may be referenced before it has a value");
1086 Get_Address
(Iter
.ai_addr
.all, C
.int
(Iter
.ai_addrlen
));
1088 if Result
(J
).Addr
.Family
= Family_Unspec
then
1092 for M
in Modes
'Range loop
1093 if Modes
(M
) = Iter
.ai_socktype
then
1094 Result
(J
).Mode
:= M
;
1101 for L
in Levels
'Range loop
1102 if Levels
(L
) = Iter
.ai_protocol
then
1103 Result
(J
).Level
:= L
;
1108 exit Look_For_Supported
;
1114 Iter
:= Iter
.ai_next
;
1115 end loop Look_For_Supported
;
1117 Iter
:= Iter
.ai_next
;
1120 return Result
& To_Array
;
1123 -- Start of processing for Get_Address_Info
1127 (Node
=> (if Host
= "" then null else N
'Unchecked_Access),
1128 Service
=> S
'Unchecked_Access,
1129 Hints
=> Hints
'Unchecked_Access,
1134 (R
, Host
& (if Service
= "" then "" else ':' & Service
));
1139 return Result
: constant Address_Info_Array
:= To_Array
do
1142 end Get_Address_Info
;
1149 (Addr_Info
: in out Address_Info_Array
;
1150 Compare
: access function (Left
, Right
: Address_Info
) return Boolean)
1152 function Comp
(Left
, Right
: Address_Info
) return Boolean is
1153 (Compare
(Left
, Right
));
1154 procedure Sorter
is new Ada
.Containers
.Generic_Array_Sort
1155 (Positive, Address_Info
, Address_Info_Array
, Comp
);
1160 ------------------------
1161 -- IPv6_TCP_Preferred --
1162 ------------------------
1164 function IPv6_TCP_Preferred
(Left
, Right
: Address_Info
) return Boolean is
1166 pragma Assert
(Family_Inet
< Family_Inet6
);
1167 -- To be sure that Family_Type enumeration has appropriate elements
1170 if Left
.Addr
.Family
/= Right
.Addr
.Family
then
1171 return Left
.Addr
.Family
> Right
.Addr
.Family
;
1174 pragma Assert
(Socket_Stream
< Socket_Datagram
);
1175 -- To be sure that Mode_Type enumeration has appropriate elements order
1177 return Left
.Mode
< Right
.Mode
;
1178 end IPv6_TCP_Preferred
;
1184 function Get_Name_Info
1185 (Addr
: Sock_Addr_Type
;
1186 Numeric_Host
: Boolean := False;
1187 Numeric_Serv
: Boolean := False) return Host_Service
1189 SA
: aliased Sockaddr
;
1190 H
: aliased C
.char_array
:= [1 .. SOSC
.NI_MAXHOST
=> C
.nul
];
1191 S
: aliased C
.char_array
:= [1 .. SOSC
.NI_MAXSERV
=> C
.nul
];
1195 Set_Address
(SA
'Unchecked_Access, Addr
, Len
);
1198 (SA
'Unchecked_Access, socklen_t
(Len
),
1199 H
'Unchecked_Access, H
'Length,
1200 S
'Unchecked_Access, S
'Length,
1201 (if Numeric_Host
then SOSC
.NI_NUMERICHOST
else 0) +
1202 (if Numeric_Serv
then SOSC
.NI_NUMERICSERV
else 0));
1205 Raise_GAI_Error
(RC
, Image
(Addr
));
1209 HR
: constant String := C
.To_Ada
(H
);
1210 SR
: constant String := C
.To_Ada
(S
);
1212 return (HR
'Length, SR
'Length, HR
, SR
);
1216 -------------------------
1217 -- Get_Host_By_Address --
1218 -------------------------
1220 function Get_Host_By_Address
1221 (Address
: Inet_Addr_Type
;
1222 Family
: Family_Type
:= Family_Inet
) return Host_Entry_Type
1224 pragma Unreferenced
(Family
);
1226 HA
: aliased In_Addr_Union
(Address
.Family
);
1227 Buflen
: constant C
.size_t
:= Netdb_Buffer_Size
;
1228 Buf
: aliased C
.char_array
(1 .. Netdb_Buffer_Size
);
1229 Res
: aliased Hostent
;
1230 Err
: aliased C
.int
;
1233 case Address
.Family
is
1235 HA
.In4
:= To_In_Addr
(Address
);
1236 when Family_Inet6
=>
1237 HA
.In6
:= To_In6_Addr
(Address
);
1244 (case Address
.Family
is
1245 when Family_Inet
=> HA
.In4
'Size,
1246 when Family_Inet6
=> HA
.In6
'Size) / 8,
1247 Families
(Address
.Family
),
1248 Res
'Access, Buf
'Address, Buflen
, Err
'Access) /= 0
1251 Raise_Host_Error
(Integer (Err
), Image
(Address
));
1255 return H
: constant Host_Entry_Type
:=
1256 To_Host_Entry
(Res
'Unchecked_Access)
1265 end Get_Host_By_Address
;
1267 ----------------------
1268 -- Get_Host_By_Name --
1269 ----------------------
1271 function Get_Host_By_Name
(Name
: String) return Host_Entry_Type
is
1273 -- If the given name actually is the string representation of
1274 -- an IP address, use Get_Host_By_Address instead.
1276 if Is_IPv4_Address
(Name
) or else Is_IPv6_Address
(Name
) then
1277 return Get_Host_By_Address
(Inet_Addr
(Name
));
1281 HN
: constant C
.char_array
:= C
.To_C
(Name
);
1282 Buflen
: constant C
.size_t
:= Netdb_Buffer_Size
;
1283 Buf
: aliased C
.char_array
(1 .. Netdb_Buffer_Size
);
1284 Res
: aliased Hostent
;
1285 Err
: aliased C
.int
;
1291 (HN
, Res
'Access, Buf
'Address, Buflen
, Err
'Access) /= 0
1294 Raise_Host_Error
(Integer (Err
), Name
);
1297 return H
: constant Host_Entry_Type
:=
1298 To_Host_Entry
(Res
'Unchecked_Access)
1303 end Get_Host_By_Name
;
1309 function Get_Peer_Name
(Socket
: Socket_Type
) return Sock_Addr_Type
is
1310 Sin
: aliased Sockaddr
;
1311 Len
: aliased C
.int
:= Sin
'Size / 8;
1313 if C_Getpeername
(C
.int
(Socket
), Sin
'Address, Len
'Access) = Failure
then
1314 Raise_Socket_Error
(Socket_Errno
);
1317 return Get_Address
(Sin
, Len
);
1320 -------------------------
1321 -- Get_Service_By_Name --
1322 -------------------------
1324 function Get_Service_By_Name
1326 Protocol
: String) return Service_Entry_Type
1328 SN
: constant C
.char_array
:= C
.To_C
(Name
);
1329 SP
: constant C
.char_array
:= C
.To_C
(Protocol
);
1330 Buflen
: constant C
.size_t
:= Netdb_Buffer_Size
;
1331 Buf
: aliased C
.char_array
(1 .. Netdb_Buffer_Size
);
1332 Res
: aliased Servent
;
1337 if C_Getservbyname
(SN
, SP
, Res
'Access, Buf
'Address, Buflen
) /= 0 then
1339 raise Service_Error
with "Service not found";
1342 -- Translate from the C format to the API format
1344 return S
: constant Service_Entry_Type
:=
1345 To_Service_Entry
(Res
'Unchecked_Access)
1349 end Get_Service_By_Name
;
1351 -------------------------
1352 -- Get_Service_By_Port --
1353 -------------------------
1355 function Get_Service_By_Port
1357 Protocol
: String) return Service_Entry_Type
1359 SP
: constant C
.char_array
:= C
.To_C
(Protocol
);
1360 Buflen
: constant C
.size_t
:= Netdb_Buffer_Size
;
1361 Buf
: aliased C
.char_array
(1 .. Netdb_Buffer_Size
);
1362 Res
: aliased Servent
;
1368 (C
.int
(Short_To_Network
(C
.unsigned_short
(Port
))), SP
,
1369 Res
'Access, Buf
'Address, Buflen
) /= 0
1372 raise Service_Error
with "Service not found";
1375 -- Translate from the C format to the API format
1377 return S
: constant Service_Entry_Type
:=
1378 To_Service_Entry
(Res
'Unchecked_Access)
1382 end Get_Service_By_Port
;
1384 ---------------------
1385 -- Get_Socket_Name --
1386 ---------------------
1388 function Get_Socket_Name
1389 (Socket
: Socket_Type
) return Sock_Addr_Type
1391 Sin
: aliased Sockaddr
;
1392 Len
: aliased C
.int
:= Sin
'Size / 8;
1395 Res
:= C_Getsockname
(C
.int
(Socket
), Sin
'Address, Len
'Access);
1397 if Res
= Failure
then
1398 return No_Sock_Addr
;
1401 return Get_Address
(Sin
, Len
);
1402 end Get_Socket_Name
;
1404 -----------------------
1405 -- Get_Socket_Option --
1406 -----------------------
1408 function Get_Socket_Option
1409 (Socket
: Socket_Type
;
1412 Optname
: Interfaces
.C
.int
:= -1) return Option_Type
1414 use type C
.unsigned
;
1415 use type C
.unsigned_char
;
1417 -- SOSC.IF_NAMESIZE may be not defined, ensure that we have at least
1418 -- a valid range for VS declared below.
1419 NS
: constant Interfaces
.C
.size_t
:=
1420 (if SOSC
.IF_NAMESIZE
= -1 then 256 else SOSC
.IF_NAMESIZE
);
1421 V8
: aliased Two_Ints
;
1423 U4
: aliased C
.unsigned
;
1424 V1
: aliased C
.unsigned_char
;
1425 VS
: aliased C
.char_array
(1 .. NS
); -- for devices name
1426 VT
: aliased Timeval
;
1427 Len
: aliased C
.int
;
1428 Add
: System
.Address
;
1430 Opt
: Option_Type
(Name
);
1431 Onm
: Interfaces
.C
.int
;
1433 if Name
in Specific_Option_Name
then
1434 Onm
:= Options
(Name
);
1436 elsif Optname
= -1 then
1437 raise Socket_Error
with "optname must be specified";
1445 | Receive_Packet_Info
1457 | Keep_Alive_Interval
1472 when Receive_Timeout
1475 -- The standard argument for SO_RCVTIMEO and SO_SNDTIMEO is a
1476 -- struct timeval, but on Windows it is a milliseconds count in
1487 when Add_Membership_V4
1489 | Drop_Membership_V4
1490 | Drop_Membership_V6
1492 raise Socket_Error
with
1493 "Add/Drop membership valid only for Set_Socket_Option";
1513 if Res
= Failure
then
1514 Raise_Socket_Error
(Socket_Errno
);
1518 when Generic_Option
=>
1530 Opt
.Enabled
:= (V4
/= 0);
1532 when Keep_Alive_Count
=>
1533 Opt
.Count
:= Natural (V4
);
1535 when Keep_Alive_Idle
=>
1536 Opt
.Idle_Seconds
:= Natural (V4
);
1538 when Keep_Alive_Interval
=>
1539 Opt
.Interval_Seconds
:= Natural (V4
);
1541 when Busy_Polling
=>
1542 Opt
.Microseconds
:= Natural (V4
);
1545 Opt
.Enabled
:= (V8
(V8
'First) /= 0);
1546 Opt
.Seconds
:= Natural (V8
(V8
'Last));
1551 Opt
.Size
:= Natural (V4
);
1554 Opt
.Error
:= Resolve_Error
(Integer (V4
));
1556 when Add_Membership_V4
1558 | Drop_Membership_V4
1559 | Drop_Membership_V6
1561 -- No way to be here. Exception raised in the first case Name
1565 when Multicast_If_V4
=>
1566 To_Inet_Addr
(To_In_Addr
(V4
), Opt
.Outgoing_If
);
1568 when Multicast_If_V6
=>
1569 Opt
.Outgoing_If_Index
:= Natural (V4
);
1571 when Multicast_TTL
=>
1572 Opt
.Time_To_Live
:= Integer (V1
);
1574 when Multicast_Hops
=>
1575 Opt
.Hop_Limit
:= Integer (V4
);
1577 when Receive_Packet_Info
1579 Opt
.Enabled
:= (V1
/= 0);
1581 when Receive_Timeout
1589 if Minus_500ms_Windows_Timeout
then
1590 -- Timeout is in milliseconds, actual value is 500 ms +
1591 -- returned value (unless it is 0).
1596 Opt
.Timeout
:= Duration (U4
) / 1000;
1600 Opt
.Timeout
:= To_Duration
(VT
);
1603 when Bind_To_Device
=>
1604 Opt
.Device
:= ASU
.To_Unbounded_String
(C
.To_Ada
(VS
));
1608 end Get_Socket_Option
;
1614 function Host_Name
return String is
1615 Name
: aliased C
.char_array
(1 .. 64);
1619 Res
:= C_Gethostname
(Name
'Address, Name
'Length);
1621 if Res
= Failure
then
1622 Raise_Socket_Error
(Socket_Errno
);
1625 return C
.To_Ada
(Name
);
1632 function Image
(Value
: Inet_Addr_Type
) return String is
1633 use type CS
.char_array_access
;
1634 Size
: constant socklen_t
:=
1635 (case Value
.Family
is
1636 when Family_Inet
=> 4 * Value
.Sin_V4
'Length,
1637 when Family_Inet6
=> 6 * 5 + 4 * 4);
1638 -- 1234:1234:1234:1234:1234:1234:123.123.123.123
1639 Dst
: aliased C
.char_array
:= [1 .. C
.size_t
(Size
) => C
.nul
];
1640 Ia
: aliased In_Addr_Union
(Value
.Family
);
1642 case Value
.Family
is
1643 when Family_Inet6
=>
1644 Ia
.In6
:= To_In6_Addr
(Value
);
1646 Ia
.In4
:= To_In_Addr
(Value
);
1650 (Families
(Value
.Family
), Ia
'Address,
1651 Dst
'Unchecked_Access, Size
) = null
1653 Raise_Socket_Error
(Socket_Errno
);
1656 return C
.To_Ada
(Dst
);
1663 function Image
(Value
: Sock_Addr_Type
) return String is
1664 function Ipv6_Brackets
(S
: String) return String is
1665 (if Value
.Family
= Family_Inet6
then "[" & S
& "]" else S
);
1667 case Value
.Family
is
1669 if ASU
.Length
(Value
.Name
) > 0
1670 and then ASU
.Element
(Value
.Name
, 1) = ASCII
.NUL
1672 return '@' & ASU
.Slice
(Value
.Name
, 2, ASU
.Length
(Value
.Name
));
1674 return ASU
.To_String
(Value
.Name
);
1677 when Family_Inet_4_6
=>
1679 Port
: constant String := Value
.Port
'Img;
1681 return Ipv6_Brackets
(Image
(Value
.Addr
)) & ':'
1682 & Port
(2 .. Port
'Last);
1685 when Family_Unspec
=>
1694 function Image
(Socket
: Socket_Type
) return String is
1703 function Image
(Item
: Socket_Set_Type
) return String is
1704 Socket_Set
: Socket_Set_Type
:= Item
;
1708 Last_Img
: constant String := Socket_Set
.Last
'Img;
1710 (1 .. (Integer (Socket_Set
.Last
) + 1) * Last_Img
'Length);
1711 Index
: Positive := 1;
1712 Socket
: Socket_Type
;
1715 while not Is_Empty
(Socket_Set
) loop
1716 Get
(Socket_Set
, Socket
);
1719 Socket_Img
: constant String := Socket
'Img;
1721 Buffer
(Index
.. Index
+ Socket_Img
'Length - 1) := Socket_Img
;
1722 Index
:= Index
+ Socket_Img
'Length;
1726 return "[" & Last_Img
& "]" & Buffer
(1 .. Index
- 1);
1734 function Inet_Addr
(Image
: String) return Inet_Addr_Type
is
1737 Img
: aliased char_array
:= To_C
(Image
);
1739 Result
: Inet_Addr_Type
;
1740 IPv6
: constant Boolean := Is_IPv6_Address
(Image
);
1741 Ia
: aliased In_Addr_Union
1742 (if IPv6
then Family_Inet6
else Family_Inet
);
1744 -- Special case for an empty Image as on some platforms (e.g. Windows)
1745 -- calling Inet_Addr("") will not return an error.
1748 Raise_Socket_Error
(SOSC
.EINVAL
);
1752 ((if IPv6
then SOSC
.AF_INET6
else SOSC
.AF_INET
), Img
'Address,
1756 Raise_Socket_Error
(Socket_Errno
);
1759 Raise_Socket_Error
(SOSC
.EINVAL
);
1763 To_Inet_Addr
(Ia
.In6
, Result
);
1765 To_Inet_Addr
(Ia
.In4
, Result
);
1775 procedure Initialize
(X
: in out Sockets_Library_Controller
) is
1776 pragma Unreferenced
(X
);
1786 procedure Initialize
(Process_Blocking_IO
: Boolean) is
1787 Expected
: constant Boolean := not SOSC
.Thread_Blocking_IO
;
1790 if Process_Blocking_IO
/= Expected
then
1791 raise Socket_Error
with
1792 "incorrect Process_Blocking_IO setting, expected " & Expected
'Img;
1795 -- This is a dummy placeholder for an obsolete API
1797 -- Real initialization actions are in Initialize primitive operation
1798 -- of Sockets_Library_Controller.
1807 procedure Initialize
is
1809 -- This is a dummy placeholder for an obsolete API
1811 -- Real initialization actions are in Initialize primitive operation
1812 -- of Sockets_Library_Controller.
1821 function Is_Windows
return Boolean is
1824 return Target_OS
= Windows
;
1831 function Is_Empty
(Item
: Socket_Set_Type
) return Boolean is
1833 return Item
.Last
= No_Socket
;
1836 ---------------------
1837 -- Is_IPv6_Address --
1838 ---------------------
1840 function Is_IPv6_Address
(Name
: String) return Boolean is
1841 Prev_Colon
: Natural := 0;
1842 Double_Colon
: Boolean := False;
1843 Colons
: Natural := 0;
1845 for J
in Name
'Range loop
1846 if Name
(J
) = ':' then
1847 Colons
:= Colons
+ 1;
1849 if Prev_Colon
> 0 and then J
= Prev_Colon
+ 1 then
1850 if Double_Colon
then
1851 -- Only one double colon allowed
1855 Double_Colon
:= True;
1857 elsif J
= Name
'Last then
1858 -- Single colon at the end is not allowed
1864 elsif Prev_Colon
= Name
'First then
1865 -- Single colon at start is not allowed
1868 elsif Name
(J
) = '.' then
1869 return Prev_Colon
> 0
1870 and then Is_IPv4_Address
(Name
(Prev_Colon
+ 1 .. Name
'Last));
1872 elsif Name
(J
) not in '0' .. '9' |
'A' .. 'F' |
'a' .. 'f' then
1878 return Colons
in 2 .. 8;
1879 end Is_IPv6_Address
;
1881 ---------------------
1882 -- Is_IPv4_Address --
1883 ---------------------
1885 function Is_IPv4_Address
(Name
: String) return Boolean is
1886 Dots
: Natural := 0;
1889 -- Perform a cursory check for a dotted quad: we must have 1 to 3 dots,
1890 -- and there must be at least one digit around each.
1892 for J
in Name
'Range loop
1893 if Name
(J
) = '.' then
1895 -- Check that the dot is not in first or last position, and that
1896 -- it is followed by a digit. Note that we already know that it is
1897 -- preceded by a digit, or we would have returned earlier on.
1899 if J
in Name
'First + 1 .. Name
'Last - 1
1900 and then Name
(J
+ 1) in '0' .. '9'
1904 -- Definitely not a proper dotted quad
1910 elsif Name
(J
) not in '0' .. '9' then
1915 return Dots
in 1 .. 3;
1916 end Is_IPv4_Address
;
1922 function Is_Open
(S
: Selector_Type
) return Boolean is
1928 -- Either both controlling socket descriptors are valid (case of an
1929 -- open selector) or neither (case of a closed selector).
1931 pragma Assert
((S
.R_Sig_Socket
/= No_Socket
)
1933 (S
.W_Sig_Socket
/= No_Socket
));
1935 return S
.R_Sig_Socket
/= No_Socket
;
1944 (Item
: Socket_Set_Type
;
1945 Socket
: Socket_Type
) return Boolean
1948 Check_For_Fd_Set
(Socket
);
1950 return Item
.Last
/= No_Socket
1951 and then Socket
<= Item
.Last
1952 and then Is_Socket_In_Set
(Item
.Set
'Access, C
.int
(Socket
)) /= 0;
1959 procedure Listen_Socket
1960 (Socket
: Socket_Type
;
1961 Length
: Natural := 15)
1963 Res
: constant C
.int
:= C_Listen
(C
.int
(Socket
), C
.int
(Length
));
1965 if Res
= Failure
then
1966 Raise_Socket_Error
(Socket_Errno
);
1974 procedure Narrow
(Item
: in out Socket_Set_Type
) is
1975 Last
: aliased C
.int
:= C
.int
(Item
.Last
);
1977 if Item
.Last
/= No_Socket
then
1978 Last_Socket_In_Set
(Item
.Set
'Access, Last
'Unchecked_Access);
1979 Item
.Last
:= Socket_Type
(Last
);
1987 procedure Netdb_Lock
is
1989 if Need_Netdb_Lock
then
1990 System
.Task_Lock
.Lock
;
1998 procedure Netdb_Unlock
is
2000 if Need_Netdb_Lock
then
2001 System
.Task_Lock
.Unlock
;
2005 ----------------------------
2006 -- Network_Socket_Address --
2007 ----------------------------
2009 function Network_Socket_Address
2010 (Addr
: Inet_Addr_Type
; Port
: Port_Type
) return Sock_Addr_Type
is
2012 return Result
: Sock_Addr_Type
(Addr
.Family
) do
2013 Result
.Addr
:= Addr
;
2014 Result
.Port
:= Port
;
2016 end Network_Socket_Address
;
2018 --------------------------------
2019 -- Normalize_Empty_Socket_Set --
2020 --------------------------------
2022 procedure Normalize_Empty_Socket_Set
(S
: in out Socket_Set_Type
) is
2024 if S
.Last
= No_Socket
then
2025 Reset_Socket_Set
(S
.Set
'Access);
2027 end Normalize_Empty_Socket_Set
;
2033 function Official_Name
(E
: Host_Entry_Type
) return String is
2035 return To_String
(E
.Official
);
2042 function Official_Name
(S
: Service_Entry_Type
) return String is
2044 return To_String
(S
.Official
);
2047 --------------------
2048 -- Wait_On_Socket --
2049 --------------------
2051 procedure Wait_On_Socket
2052 (Socket
: Socket_Type
;
2053 Event
: Poll
.Wait_Event_Set
;
2054 Timeout
: Selector_Duration
;
2055 Selector
: access Selector_Type
:= null;
2056 Status
: out Selector_Status
)
2058 Fd_Set
: Poll
.Set
:= Poll
.To_Set
(Socket
, Event
, 2);
2059 -- Socket itself and second place for signaling socket if necessary
2062 Index
: Natural := 0;
2065 -- Add signaling socket if selector defined
2067 if Selector
/= null then
2068 Poll
.Append
(Fd_Set
, Selector
.R_Sig_Socket
, Poll
.Input_Event
);
2071 Poll
.Wait
(Fd_Set
, Timeout
, Count
);
2076 Poll
.Next
(Fd_Set
, Index
);
2077 Status
:= (if Index
= 1 then Completed
else Aborted
);
2085 function Port_Number
(S
: Service_Entry_Type
) return Port_Type
is
2094 function Protocol_Name
(S
: Service_Entry_Type
) return String is
2096 return To_String
(S
.Protocol
);
2099 ----------------------
2100 -- Raise_Host_Error --
2101 ----------------------
2103 procedure Raise_Host_Error
(H_Error
: Integer; Name
: String) is
2105 raise Host_Error
with
2106 Err_Code_Image
(H_Error
)
2107 & Dedot
(Host_Error_Messages
.Host_Error_Message
(H_Error
))
2109 end Raise_Host_Error
;
2111 ------------------------
2112 -- Raise_Socket_Error --
2113 ------------------------
2115 procedure Raise_Socket_Error
(Error
: Integer) is
2117 raise Socket_Error
with
2118 Err_Code_Image
(Error
) & Socket_Error_Message
(Error
);
2119 end Raise_Socket_Error
;
2126 (Stream
: in out Datagram_Socket_Stream_Type
;
2127 Item
: out Ada
.Streams
.Stream_Element_Array
;
2128 Last
: out Ada
.Streams
.Stream_Element_Offset
)
2143 (Stream
: in out Stream_Socket_Stream_Type
;
2144 Item
: out Ada
.Streams
.Stream_Element_Array
;
2145 Last
: out Ada
.Streams
.Stream_Element_Offset
)
2147 First
: Ada
.Streams
.Stream_Element_Offset
:= Item
'First;
2148 Index
: Ada
.Streams
.Stream_Element_Offset
:= First
- 1;
2149 Max
: constant Ada
.Streams
.Stream_Element_Offset
:= Item
'Last;
2153 Receive_Socket
(Stream
.Socket
, Item
(First
.. Max
), Index
);
2156 -- Exit when all or zero data received. Zero means that the socket
2159 exit when Index
< First
or else Index
= Max
;
2165 --------------------
2166 -- Receive_Socket --
2167 --------------------
2169 procedure Receive_Socket
2170 (Socket
: Socket_Type
;
2171 Item
: out Ada
.Streams
.Stream_Element_Array
;
2172 Last
: out Ada
.Streams
.Stream_Element_Offset
;
2173 Flags
: Request_Flag_Type
:= No_Request_Flag
)
2179 C_Recv
(C
.int
(Socket
), Item
'Address, Item
'Length, To_Int
(Flags
));
2181 if Res
= Failure
then
2182 Raise_Socket_Error
(Socket_Errno
);
2185 Last
:= Last_Index
(First
=> Item
'First, Count
=> size_t
(Res
));
2188 --------------------
2189 -- Receive_Socket --
2190 --------------------
2192 procedure Receive_Socket
2193 (Socket
: Socket_Type
;
2194 Item
: out Ada
.Streams
.Stream_Element_Array
;
2195 Last
: out Ada
.Streams
.Stream_Element_Offset
;
2196 From
: out Sock_Addr_Type
;
2197 Flags
: Request_Flag_Type
:= No_Request_Flag
)
2200 Sin
: aliased Sockaddr
;
2201 Len
: aliased C
.int
:= Sin
'Size / 8;
2213 if Res
= Failure
then
2214 Raise_Socket_Error
(Socket_Errno
);
2217 Last
:= Last_Index
(First
=> Item
'First, Count
=> size_t
(Res
));
2219 From
:= Get_Address
(Sin
, Len
);
2222 --------------------
2223 -- Receive_Vector --
2224 --------------------
2226 procedure Receive_Vector
2227 (Socket
: Socket_Type
;
2228 Vector
: Vector_Type
;
2229 Count
: out Ada
.Streams
.Stream_Element_Count
;
2230 Flags
: Request_Flag_Type
:= No_Request_Flag
)
2235 (Msg_Name
=> System
.Null_Address
,
2237 Msg_Iov
=> Vector
'Address,
2239 -- recvmsg(2) returns EMSGSIZE on Linux (and probably on other
2240 -- platforms) when the supplied vector is longer than IOV_MAX,
2241 -- so use minimum of the two lengths.
2243 Msg_Iovlen
=> SOSC
.Msg_Iovlen_T
'Min
2244 (Vector
'Length, SOSC
.IOV_MAX
),
2246 Msg_Control
=> System
.Null_Address
,
2247 Msg_Controllen
=> 0,
2257 if Res
= ssize_t
(Failure
) then
2258 Raise_Socket_Error
(Socket_Errno
);
2261 Count
:= Ada
.Streams
.Stream_Element_Count
(Res
);
2268 function Resolve_Error
2269 (Error_Value
: Integer;
2270 From_Errno
: Boolean := True) return Error_Type
2272 use GNAT
.Sockets
.SOSC
;
2275 if not From_Errno
then
2277 when SOSC
.HOST_NOT_FOUND
=> return Unknown_Host
;
2278 when SOSC
.TRY_AGAIN
=> return Host_Name_Lookup_Failure
;
2279 when SOSC
.NO_RECOVERY
=> return Non_Recoverable_Error
;
2280 when SOSC
.NO_DATA
=> return Unknown_Server_Error
;
2281 when others => return Cannot_Resolve_Error
;
2285 -- Special case: EAGAIN may be the same value as EWOULDBLOCK, so we
2286 -- can't include it in the case statement below.
2288 pragma Warnings
(Off
);
2289 -- Condition "EAGAIN /= EWOULDBLOCK" is known at compile time
2291 if EAGAIN
/= EWOULDBLOCK
and then Error_Value
= EAGAIN
then
2292 return Resource_Temporarily_Unavailable
;
2295 -- This is not a case statement because if a particular error
2296 -- number constant is not defined, s-oscons-tmplt.c defines
2297 -- it to -1. If multiple constants are not defined, they
2298 -- would each be -1 and result in a "duplicate value in case" error.
2300 -- But we have to leave warnings off because the compiler is also
2301 -- smart enough to note that when two errnos have the same value,
2302 -- the second if condition is useless.
2303 if Error_Value
= ENOERROR
then
2305 elsif Error_Value
= EACCES
then
2306 return Permission_Denied
;
2307 elsif Error_Value
= EADDRINUSE
then
2308 return Address_Already_In_Use
;
2309 elsif Error_Value
= EADDRNOTAVAIL
then
2310 return Cannot_Assign_Requested_Address
;
2311 elsif Error_Value
= EAFNOSUPPORT
then
2312 return Address_Family_Not_Supported_By_Protocol
;
2313 elsif Error_Value
= EALREADY
then
2314 return Operation_Already_In_Progress
;
2315 elsif Error_Value
= EBADF
then
2316 return Bad_File_Descriptor
;
2317 elsif Error_Value
= ECONNABORTED
then
2318 return Software_Caused_Connection_Abort
;
2319 elsif Error_Value
= ECONNREFUSED
then
2320 return Connection_Refused
;
2321 elsif Error_Value
= ECONNRESET
then
2322 return Connection_Reset_By_Peer
;
2323 elsif Error_Value
= EDESTADDRREQ
then
2324 return Destination_Address_Required
;
2325 elsif Error_Value
= EFAULT
then
2327 elsif Error_Value
= EHOSTDOWN
then
2328 return Host_Is_Down
;
2329 elsif Error_Value
= EHOSTUNREACH
then
2330 return No_Route_To_Host
;
2331 elsif Error_Value
= EINPROGRESS
then
2332 return Operation_Now_In_Progress
;
2333 elsif Error_Value
= EINTR
then
2334 return Interrupted_System_Call
;
2335 elsif Error_Value
= EINVAL
then
2336 return Invalid_Argument
;
2337 elsif Error_Value
= EIO
then
2338 return Input_Output_Error
;
2339 elsif Error_Value
= EISCONN
then
2340 return Transport_Endpoint_Already_Connected
;
2341 elsif Error_Value
= ELOOP
then
2342 return Too_Many_Symbolic_Links
;
2343 elsif Error_Value
= EMFILE
then
2344 return Too_Many_Open_Files
;
2345 elsif Error_Value
= EMSGSIZE
then
2346 return Message_Too_Long
;
2347 elsif Error_Value
= ENAMETOOLONG
then
2348 return File_Name_Too_Long
;
2349 elsif Error_Value
= ENETDOWN
then
2350 return Network_Is_Down
;
2351 elsif Error_Value
= ENETRESET
then
2352 return Network_Dropped_Connection_Because_Of_Reset
;
2353 elsif Error_Value
= ENETUNREACH
then
2354 return Network_Is_Unreachable
;
2355 elsif Error_Value
= ENOBUFS
then
2356 return No_Buffer_Space_Available
;
2357 elsif Error_Value
= ENOPROTOOPT
then
2358 return Protocol_Not_Available
;
2359 elsif Error_Value
= ENOTCONN
then
2360 return Transport_Endpoint_Not_Connected
;
2361 elsif Error_Value
= ENOTSOCK
then
2362 return Socket_Operation_On_Non_Socket
;
2363 elsif Error_Value
= EOPNOTSUPP
then
2364 return Operation_Not_Supported
;
2365 elsif Error_Value
= EPFNOSUPPORT
then
2366 return Protocol_Family_Not_Supported
;
2367 elsif Error_Value
= EPIPE
then
2369 elsif Error_Value
= EPROTONOSUPPORT
then
2370 return Protocol_Not_Supported
;
2371 elsif Error_Value
= EPROTOTYPE
then
2372 return Protocol_Wrong_Type_For_Socket
;
2373 elsif Error_Value
= ESHUTDOWN
then
2374 return Cannot_Send_After_Transport_Endpoint_Shutdown
;
2375 elsif Error_Value
= ESOCKTNOSUPPORT
then
2376 return Socket_Type_Not_Supported
;
2377 elsif Error_Value
= ETIMEDOUT
then
2378 return Connection_Timed_Out
;
2379 elsif Error_Value
= ETOOMANYREFS
then
2380 return Too_Many_References
;
2381 elsif Error_Value
= EWOULDBLOCK
then
2382 return Resource_Temporarily_Unavailable
;
2384 return Cannot_Resolve_Error
;
2386 pragma Warnings
(On
);
2390 -----------------------
2391 -- Resolve_Exception --
2392 -----------------------
2394 function Resolve_Exception
2395 (Occurrence
: Exception_Occurrence
) return Error_Type
2397 Id
: constant Exception_Id
:= Exception_Identity
(Occurrence
);
2398 Msg
: constant String := Exception_Message
(Occurrence
);
2405 while First
<= Msg
'Last
2406 and then Msg
(First
) not in '0' .. '9'
2411 if First
> Msg
'Last then
2412 return Cannot_Resolve_Error
;
2416 while Last
< Msg
'Last
2417 and then Msg
(Last
+ 1) in '0' .. '9'
2422 Val
:= Integer'Value (Msg
(First
.. Last
));
2424 if Id
= Socket_Error_Id
then
2425 return Resolve_Error
(Val
);
2427 elsif Id
= Host_Error_Id
then
2428 return Resolve_Error
(Val
, False);
2431 return Cannot_Resolve_Error
;
2433 end Resolve_Exception
;
2439 procedure Send_Socket
2440 (Socket
: Socket_Type
;
2441 Item
: Ada
.Streams
.Stream_Element_Array
;
2442 Last
: out Ada
.Streams
.Stream_Element_Offset
;
2443 Flags
: Request_Flag_Type
:= No_Request_Flag
)
2446 Send_Socket
(Socket
, Item
, Last
, To
=> null, Flags
=> Flags
);
2453 procedure Send_Socket
2454 (Socket
: Socket_Type
;
2455 Item
: Ada
.Streams
.Stream_Element_Array
;
2456 Last
: out Ada
.Streams
.Stream_Element_Offset
;
2457 To
: Sock_Addr_Type
;
2458 Flags
: Request_Flag_Type
:= No_Request_Flag
)
2462 (Socket
, Item
, Last
, To
=> To
'Unrestricted_Access, Flags
=> Flags
);
2469 procedure Send_Socket
2470 (Socket
: Socket_Type
;
2471 Item
: Ada
.Streams
.Stream_Element_Array
;
2472 Last
: out Ada
.Streams
.Stream_Element_Offset
;
2473 To
: access Sock_Addr_Type
;
2474 Flags
: Request_Flag_Type
:= No_Request_Flag
)
2478 Sin
: aliased Sockaddr
;
2479 C_To
: System
.Address
;
2484 Set_Address
(Sin
'Unchecked_Access, To
.all, Len
);
2485 C_To
:= Sin
'Address;
2488 C_To
:= System
.Null_Address
;
2496 Set_Forced_Flags
(To_Int
(Flags
)),
2500 if Res
= Failure
then
2501 Raise_Socket_Error
(Socket_Errno
);
2504 Last
:= Last_Index
(First
=> Item
'First, Count
=> size_t
(Res
));
2511 procedure Send_Vector
2512 (Socket
: Socket_Type
;
2513 Vector
: Vector_Type
;
2514 Count
: out Ada
.Streams
.Stream_Element_Count
;
2515 Flags
: Request_Flag_Type
:= No_Request_Flag
)
2520 Iov_Count
: SOSC
.Msg_Iovlen_T
;
2521 This_Iov_Count
: SOSC
.Msg_Iovlen_T
;
2527 while Iov_Count
< Vector
'Length loop
2529 pragma Warnings
(Off
);
2530 -- Following test may be compile time known on some targets
2533 (if Vector
'Length - Iov_Count
> SOSC
.IOV_MAX
2535 else Vector
'Length - Iov_Count
);
2537 pragma Warnings
(On
);
2540 (Msg_Name
=> System
.Null_Address
,
2543 (Vector
'First + Integer (Iov_Count
))'Address,
2544 Msg_Iovlen
=> This_Iov_Count
,
2545 Msg_Control
=> System
.Null_Address
,
2546 Msg_Controllen
=> 0,
2553 Set_Forced_Flags
(To_Int
(Flags
)));
2555 if Res
= ssize_t
(Failure
) then
2556 Raise_Socket_Error
(Socket_Errno
);
2559 Count
:= Count
+ Ada
.Streams
.Stream_Element_Count
(Res
);
2560 Iov_Count
:= Iov_Count
+ This_Iov_Count
;
2568 procedure Set
(Item
: in out Socket_Set_Type
; Socket
: Socket_Type
) is
2570 Check_For_Fd_Set
(Socket
);
2572 if Item
.Last
= No_Socket
then
2574 -- Uninitialized socket set, make sure it is properly zeroed out
2576 Reset_Socket_Set
(Item
.Set
'Access);
2577 Item
.Last
:= Socket
;
2579 elsif Item
.Last
< Socket
then
2580 Item
.Last
:= Socket
;
2583 Insert_Socket_In_Set
(Item
.Set
'Access, C
.int
(Socket
));
2586 -----------------------
2587 -- Set_Close_On_Exec --
2588 -----------------------
2590 procedure Set_Close_On_Exec
2591 (Socket
: Socket_Type
;
2592 Close_On_Exec
: Boolean;
2593 Status
: out Boolean)
2595 function C_Set_Close_On_Exec
2596 (Socket
: Socket_Type
; Close_On_Exec
: C
.int
) return C
.int
;
2597 pragma Import
(C
, C_Set_Close_On_Exec
, "__gnat_set_close_on_exec");
2599 Status
:= C_Set_Close_On_Exec
(Socket
, Boolean'Pos (Close_On_Exec
)) = 0;
2600 end Set_Close_On_Exec
;
2602 ----------------------
2603 -- Set_Forced_Flags --
2604 ----------------------
2606 function Set_Forced_Flags
(F
: C
.int
) return C
.int
is
2607 use type C
.unsigned
;
2608 function To_unsigned
is
2609 new Ada
.Unchecked_Conversion
(C
.int
, C
.unsigned
);
2611 new Ada
.Unchecked_Conversion
(C
.unsigned
, C
.int
);
2613 return To_int
(To_unsigned
(F
) or SOSC
.MSG_Forced_Flags
);
2614 end Set_Forced_Flags
;
2616 -----------------------
2617 -- Set_Socket_Option --
2618 -----------------------
2620 procedure Set_Socket_Option
2621 (Socket
: Socket_Type
;
2623 Option
: Option_Type
)
2625 use type C
.unsigned
;
2627 MR
: aliased IPV6_Mreq
;
2628 V8
: aliased Two_Ints
;
2630 U4
: aliased C
.unsigned
;
2631 V1
: aliased C
.unsigned_char
;
2632 VS
: aliased C
.char_array
2633 (1 .. (if Option
.Name
= Bind_To_Device
2634 then C
.size_t
(ASU
.Length
(Option
.Device
) + 1)
2636 VT
: aliased Timeval
;
2638 Add
: System
.Address
:= Null_Address
;
2644 when Generic_Option
=>
2645 V4
:= Option
.Optval
;
2657 V4
:= C
.int
(Boolean'Pos (Option
.Enabled
));
2661 when Keep_Alive_Count
=>
2662 V4
:= C
.int
(Option
.Count
);
2666 when Keep_Alive_Idle
=>
2667 V4
:= C
.int
(Option
.Idle_Seconds
);
2671 when Keep_Alive_Interval
=>
2672 V4
:= C
.int
(Option
.Interval_Seconds
);
2676 when Busy_Polling
=>
2677 V4
:= C
.int
(Option
.Microseconds
);
2682 V8
(V8
'First) := C
.int
(Boolean'Pos (Option
.Enabled
));
2683 V8
(V8
'Last) := C
.int
(Option
.Seconds
);
2690 V4
:= C
.int
(Option
.Size
);
2695 V4
:= C
.int
(Boolean'Pos (True));
2699 when Add_Membership_V4
2700 | Drop_Membership_V4
2702 V8
(V8
'First) := To_Int
(To_In_Addr
(Option
.Multicast_Address
));
2703 V8
(V8
'Last) := To_Int
(To_In_Addr
(Option
.Local_Interface
));
2707 when Add_Membership_V6
2708 | Drop_Membership_V6
=>
2709 MR
.ipv6mr_multiaddr
:= To_In6_Addr
(Option
.Multicast_Address
);
2710 MR
.ipv6mr_interface
:= C
.unsigned
(Option
.Interface_Index
);
2714 when Multicast_If_V4
=>
2715 V4
:= To_Int
(To_In_Addr
(Option
.Outgoing_If
));
2719 when Multicast_If_V6
=>
2720 V4
:= C
.int
(Option
.Outgoing_If_Index
);
2724 when Multicast_TTL
=>
2725 V1
:= C
.unsigned_char
(Option
.Time_To_Live
);
2729 when Multicast_Hops
=>
2730 V4
:= C
.int
(Option
.Hop_Limit
);
2734 when Receive_Packet_Info
2736 V1
:= C
.unsigned_char
(Boolean'Pos (Option
.Enabled
));
2740 when Receive_Timeout
2745 -- On Windows, the timeout is a DWORD in milliseconds
2750 U4
:= C
.unsigned
(Option
.Timeout
* 1000);
2752 if Option
.Timeout
> 0.0 and then U4
= 0 then
2753 -- Avoid round to zero. Zero timeout mean unlimited
2757 -- Old windows versions actual timeout is 500 ms + the given
2758 -- value (unless it is 0).
2760 if Minus_500ms_Windows_Timeout
then
2770 VT
:= To_Timeval
(Option
.Timeout
);
2775 when Bind_To_Device
=>
2776 VS
:= C
.To_C
(ASU
.To_String
(Option
.Device
));
2777 Len
:= C
.int
(VS
'Length);
2781 if Option
.Name
in Specific_Option_Name
then
2782 Onm
:= Options
(Option
.Name
);
2784 elsif Option
.Optname
= -1 then
2785 raise Socket_Error
with "optname must be specified";
2788 Onm
:= Option
.Optname
;
2797 if Res
= Failure
then
2798 Raise_Socket_Error
(Socket_Errno
);
2800 end Set_Socket_Option
;
2802 ---------------------
2803 -- Shutdown_Socket --
2804 ---------------------
2806 procedure Shutdown_Socket
2807 (Socket
: Socket_Type
;
2808 How
: Shutmode_Type
:= Shut_Read_Write
)
2813 Res
:= C_Shutdown
(C
.int
(Socket
), Shutmodes
(How
));
2815 if Res
= Failure
then
2816 Raise_Socket_Error
(Socket_Errno
);
2818 end Shutdown_Socket
;
2825 (Socket
: Socket_Type
;
2826 Send_To
: Sock_Addr_Type
) return Stream_Access
2828 S
: Datagram_Socket_Stream_Access
;
2831 S
:= new Datagram_Socket_Stream_Type
;
2834 S
.From
:= Get_Socket_Name
(Socket
);
2835 return Stream_Access
(S
);
2842 function Stream
(Socket
: Socket_Type
) return Stream_Access
is
2843 S
: Stream_Socket_Stream_Access
;
2845 S
:= new Stream_Socket_Stream_Type
;
2847 return Stream_Access
(S
);
2854 function To_Ada
(Fd
: Integer) return Socket_Type
is
2856 return Socket_Type
(Fd
);
2863 function To_C
(Socket
: Socket_Type
) return Integer is
2865 return Integer (Socket
);
2872 function To_Duration
(Val
: Timeval
) return Timeval_Duration
is
2873 Max_D
: constant Long_Long_Integer := Long_Long_Integer (Forever
- 0.5);
2874 Tv_sec_64
: constant Boolean := SOSC
.SIZEOF_tv_sec
= 8;
2875 -- Need to separate this condition into the constant declaration to
2876 -- avoid GNAT warning about "always true" or "always false".
2879 -- Check for possible Duration overflow when Tv_Sec field is 64 bit
2882 if Val
.Tv_Sec
> time_t
(Max_D
)
2884 (Val
.Tv_Sec
= time_t
(Max_D
)
2886 Val
.Tv_Usec
> suseconds_t
((Forever
- Duration (Max_D
)) * 1E6
))
2892 return Duration (Val
.Tv_Sec
) + Duration (Val
.Tv_Usec
) * 1.0E-6;
2899 function To_Host_Entry
(E
: Hostent_Access
) return Host_Entry_Type
is
2900 Aliases_Count
, Addresses_Count
: Natural;
2902 Family
: constant Family_Type
:=
2903 (case Hostent_H_Addrtype
(E
) is
2904 when SOSC
.AF_INET
=> Family_Inet
,
2905 when SOSC
.AF_INET6
=> Family_Inet6
,
2906 when others => Family_Unspec
);
2908 Addr_Len
: constant C
.size_t
:= C
.size_t
(Hostent_H_Length
(E
));
2911 if Family
= Family_Unspec
then
2912 Raise_Socket_Error
(SOSC
.EPFNOSUPPORT
);
2916 while Hostent_H_Alias
(E
, C
.int
(Aliases_Count
)) /= Null_Address
loop
2917 Aliases_Count
:= Aliases_Count
+ 1;
2920 Addresses_Count
:= 0;
2921 while Hostent_H_Addr
(E
, C
.int
(Addresses_Count
)) /= Null_Address
loop
2922 Addresses_Count
:= Addresses_Count
+ 1;
2925 return Result
: Host_Entry_Type
2926 (Aliases_Length
=> Aliases_Count
,
2927 Addresses_Length
=> Addresses_Count
)
2929 Result
.Official
:= To_Name
(Value
(Hostent_H_Name
(E
)));
2931 for J
in Result
.Aliases
'Range loop
2932 Result
.Aliases
(J
) :=
2933 To_Name
(Value
(Hostent_H_Alias
2934 (E
, C
.int
(J
- Result
.Aliases
'First))));
2937 for J
in Result
.Addresses
'Range loop
2939 Ia
: In_Addr_Union
(Family
);
2941 -- Hostent_H_Addr (E, <index>) may return an address that is
2942 -- not correctly aligned for In_Addr, so we need to use
2943 -- an intermediate copy operation on a type with an alignment
2944 -- of 1 to recover the value.
2946 subtype Addr_Buf_T
is C
.char_array
(1 .. Addr_Len
);
2947 Unaligned_Addr
: Addr_Buf_T
;
2948 for Unaligned_Addr
'Address
2949 use Hostent_H_Addr
(E
, C
.int
(J
- Result
.Addresses
'First));
2950 pragma Import
(Ada
, Unaligned_Addr
);
2952 Aligned_Addr
: Addr_Buf_T
;
2953 for Aligned_Addr
'Address use Ia
'Address;
2954 pragma Import
(Ada
, Aligned_Addr
);
2957 Aligned_Addr
:= Unaligned_Addr
;
2958 if Family
= Family_Inet6
then
2959 To_Inet_Addr
(Ia
.In6
, Result
.Addresses
(J
));
2961 To_Inet_Addr
(Ia
.In4
, Result
.Addresses
(J
));
2972 function To_Int
(F
: Request_Flag_Type
) return C
.int
is
2973 Current
: Request_Flag_Type
:= F
;
2974 Result
: C
.int
:= 0;
2977 for J
in Flags
'Range loop
2978 exit when Current
= 0;
2980 if Current
mod 2 /= 0 then
2981 if Flags
(J
) = -1 then
2983 (CodePeer
, False_Positive
,
2984 "test always false", "self fulfilling prophecy");
2986 Raise_Socket_Error
(SOSC
.EOPNOTSUPP
);
2989 Result
:= Result
+ Flags
(J
);
2992 Current
:= Current
/ 2;
3002 function To_Name
(N
: String) return Name_Type
is
3004 return Name_Type
'(N'Length, N);
3007 ----------------------
3008 -- To_Service_Entry --
3009 ----------------------
3011 function To_Service_Entry (E : Servent_Access) return Service_Entry_Type is
3012 Aliases_Count : Natural;
3016 while Servent_S_Alias (E, C.int (Aliases_Count)) /= Null_Address loop
3017 Aliases_Count := Aliases_Count + 1;
3020 return Result : Service_Entry_Type (Aliases_Length => Aliases_Count) do
3021 Result.Official := To_Name (Value (Servent_S_Name (E)));
3023 for J in Result.Aliases'Range loop
3024 Result.Aliases (J) :=
3025 To_Name (Value (Servent_S_Alias
3026 (E, C.int (J - Result.Aliases'First))));
3029 Result.Protocol := To_Name (Value (Servent_S_Proto (E)));
3031 Port_Type (Network_To_Short (Servent_S_Port (E)));
3033 end To_Service_Entry;
3039 function To_String (HN : Name_Type) return String is
3041 return HN.Name (1 .. HN.Length);
3048 function To_Timeval (Val : Timeval_Duration) return Timeval is
3053 -- If zero, set result as zero (otherwise it gets rounded down to -1)
3059 -- Normal case where we do round down
3062 S := time_t (Val - 0.5);
3063 uS := suseconds_t (1_000_000 * (Val - Selector_Duration (S)) - 0.5);
3066 -- It happen on integer duration
3078 function Value (S : System.Address) return String is
3079 Str : String (1 .. Positive'Last);
3080 for Str'Address use S;
3081 pragma Import (Ada, Str);
3083 Terminator : Positive := Str'First;
3086 while Str (Terminator) /= ASCII.NUL loop
3087 Terminator := Terminator + 1;
3090 return Str (1 .. Terminator - 1);
3098 (Stream : in out Datagram_Socket_Stream_Type;
3099 Item : Ada.Streams.Stream_Element_Array)
3101 Last : Stream_Element_Offset;
3110 -- It is an error if not all of the data has been sent
3112 if Last /= Item'Last then
3113 Raise_Socket_Error (Socket_Errno);
3122 (Stream : in out Stream_Socket_Stream_Type;
3123 Item : Ada.Streams.Stream_Element_Array)
3125 First : Ada.Streams.Stream_Element_Offset;
3126 Index : Ada.Streams.Stream_Element_Offset;
3127 Max : constant Ada.Streams.Stream_Element_Offset := Item'Last;
3130 First := Item'First;
3132 while First <= Max loop
3133 Send_Socket (Stream.Socket, Item (First .. Max), Index, null);
3135 -- Exit when all or zero data sent. Zero means that the socket has
3136 -- been closed by peer.
3138 exit when Index < First or else Index = Max;
3143 -- For an empty array, we have First > Max, and hence Index >= Max (no
3144 -- error, the loop above is never executed). After a successful send,
3145 -- Index = Max. The only remaining case, Index < Max, is therefore
3146 -- always an actual send failure.
3149 Raise_Socket_Error (Socket_Errno);
3153 Sockets_Library_Controller_Object : Sockets_Library_Controller;
3154 pragma Unreferenced (Sockets_Library_Controller_Object);
3155 -- The elaboration and finalization of this object perform the required
3156 -- initialization and cleanup actions for the sockets library.
3158 --------------------
3159 -- Create_Address --
3160 --------------------
3162 function Create_Address
3163 (Family : Family_Inet_4_6; Bytes : Inet_Addr_Bytes) return Inet_Addr_Type
3166 when Family_Inet => (Family_Inet, Bytes),
3167 when Family_Inet6 => (Family_Inet6, Bytes));
3173 function Get_Bytes (Addr : Inet_Addr_Type) return Inet_Addr_Bytes is
3174 (case Addr.Family is
3175 when Family_Inet => Addr.Sin_V4,
3176 when Family_Inet6 => Addr.Sin_V6);
3183 (Family : Family_Inet_4_6;
3185 Host : Boolean := False) return Inet_Addr_Type
3187 Addr_Len : constant Natural := Inet_Addr_Bytes_Length (Family);
3189 if Length > 8 * Addr_Len then
3190 raise Constraint_Error with
3191 "invalid mask length for address family " & Family'Img;
3195 B : Inet_Addr_Bytes (1 .. Addr_Len);
3196 Part : Inet_Addr_Comp_Type;
3198 for J in 1 .. Length / 8 loop
3199 B (J) := (if Host then 0 else 255);
3202 if Length < 8 * Addr_Len then
3203 Part := 2 ** (8 - Length mod 8) - 1;
3204 B (Length / 8 + 1) := (if Host then Part else not Part);
3206 for J in Length / 8 + 2 .. B'Last loop
3207 B (J) := (if Host then 255 else 0);
3211 return Create_Address (Family, B);
3215 -------------------------
3216 -- Unix_Socket_Address --
3217 -------------------------
3219 function Unix_Socket_Address (Addr : String) return Sock_Addr_Type is
3221 return Sock_Addr_Type'(Family_Unix
, ASU
.To_Unbounded_String
(Addr
));
3222 end Unix_Socket_Address
;
3228 function "and" (Addr
, Mask
: Inet_Addr_Type
) return Inet_Addr_Type
is
3230 if Addr
.Family
/= Mask
.Family
then
3231 raise Constraint_Error
with "incompatible address families";
3235 A
: constant Inet_Addr_Bytes
:= Get_Bytes
(Addr
);
3236 M
: constant Inet_Addr_Bytes
:= Get_Bytes
(Mask
);
3237 R
: Inet_Addr_Bytes
(A
'Range);
3240 for J
in A
'Range loop
3241 R
(J
) := A
(J
) and M
(J
);
3243 return Create_Address
(Addr
.Family
, R
);
3251 function "or" (Net
, Host
: Inet_Addr_Type
) return Inet_Addr_Type
is
3253 if Net
.Family
/= Host
.Family
then
3254 raise Constraint_Error
with "incompatible address families";
3258 N
: constant Inet_Addr_Bytes
:= Get_Bytes
(Net
);
3259 H
: constant Inet_Addr_Bytes
:= Get_Bytes
(Host
);
3260 R
: Inet_Addr_Bytes
(N
'Range);
3263 for J
in N
'Range loop
3264 R
(J
) := N
(J
) or H
(J
);
3266 return Create_Address
(Net
.Family
, R
);
3274 function "not" (Mask
: Inet_Addr_Type
) return Inet_Addr_Type
is
3275 M
: constant Inet_Addr_Bytes
:= Get_Bytes
(Mask
);
3276 R
: Inet_Addr_Bytes
(M
'Range);
3278 for J
in R
'Range loop
3281 return Create_Address
(Mask
.Family
, R
);