]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/ada/libgnat/g-socket.adb
[Ada] GNAT.Sockets: fix recent regressions
[thirdparty/gcc.git] / gcc / ada / libgnat / g-socket.adb
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT COMPILER COMPONENTS --
4 -- --
5 -- G N A T . S O C K E T S --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 2001-2019, AdaCore --
10 -- --
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. --
17 -- --
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. --
21 -- --
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/>. --
26 -- --
27 -- GNAT was originally developed by the GNAT team at New York University. --
28 -- Extensive contributions were provided by Ada Core Technologies Inc. --
29 -- --
30 ------------------------------------------------------------------------------
31
32 with Ada.Streams; use Ada.Streams;
33 with Ada.Exceptions; use Ada.Exceptions;
34 with Ada.Containers.Generic_Array_Sort;
35 with Ada.Finalization;
36 with Ada.Unchecked_Conversion;
37
38 with GNAT.Sockets.Thin_Common; use GNAT.Sockets.Thin_Common;
39 with GNAT.Sockets.Thin; use GNAT.Sockets.Thin;
40
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
44
45 with System; use System;
46 with System.Communication; use System.Communication;
47 with System.CRTL; use System.CRTL;
48 with System.Task_Lock;
49
50 package body GNAT.Sockets is
51
52 package C renames Interfaces.C;
53
54 type IPV6_Mreq is record
55 ipv6mr_multiaddr : In6_Addr;
56 ipv6mr_interface : C.unsigned;
57 end record with Convention => C;
58 -- Record to Add/Drop_Membership for multicast in IPv6
59
60 ENOERROR : constant := 0;
61
62 Netdb_Buffer_Size : constant := SOSC.Need_Netdb_Buffer * 1024;
63 Need_Netdb_Lock : constant Boolean := SOSC.Need_Netdb_Lock /= 0;
64 -- The network database functions gethostbyname, gethostbyaddr,
65 -- getservbyname and getservbyport can either be guaranteed task safe by
66 -- the operating system, or else return data through a user-provided buffer
67 -- to ensure concurrent uses do not interfere.
68
69 -- Correspondence tables
70
71 Levels : constant array (Level_Type) of C.int :=
72 (Socket_Level => SOSC.SOL_SOCKET,
73 IP_Protocol_For_IP_Level => SOSC.IPPROTO_IP,
74 IP_Protocol_For_IPv6_Level => SOSC.IPPROTO_IPV6,
75 IP_Protocol_For_UDP_Level => SOSC.IPPROTO_UDP,
76 IP_Protocol_For_TCP_Level => SOSC.IPPROTO_TCP);
77
78 Modes : constant array (Mode_Type) of C.int :=
79 (Socket_Stream => SOSC.SOCK_STREAM,
80 Socket_Datagram => SOSC.SOCK_DGRAM);
81
82 Shutmodes : constant array (Shutmode_Type) of C.int :=
83 (Shut_Read => SOSC.SHUT_RD,
84 Shut_Write => SOSC.SHUT_WR,
85 Shut_Read_Write => SOSC.SHUT_RDWR);
86
87 Requests : constant array (Request_Name) of SOSC.IOCTL_Req_T :=
88 (Non_Blocking_IO => SOSC.FIONBIO,
89 N_Bytes_To_Read => SOSC.FIONREAD);
90
91 Options : constant array (Specific_Option_Name) of C.int :=
92 (Keep_Alive => SOSC.SO_KEEPALIVE,
93 Reuse_Address => SOSC.SO_REUSEADDR,
94 Broadcast => SOSC.SO_BROADCAST,
95 Send_Buffer => SOSC.SO_SNDBUF,
96 Receive_Buffer => SOSC.SO_RCVBUF,
97 Linger => SOSC.SO_LINGER,
98 Error => SOSC.SO_ERROR,
99 No_Delay => SOSC.TCP_NODELAY,
100 Add_Membership_V4 => SOSC.IP_ADD_MEMBERSHIP,
101 Drop_Membership_V4 => SOSC.IP_DROP_MEMBERSHIP,
102 Multicast_If_V4 => SOSC.IP_MULTICAST_IF,
103 Multicast_Loop_V4 => SOSC.IP_MULTICAST_LOOP,
104 Receive_Packet_Info => SOSC.IP_PKTINFO,
105 Multicast_TTL => SOSC.IP_MULTICAST_TTL,
106 Add_Membership_V6 => SOSC.IPV6_ADD_MEMBERSHIP,
107 Drop_Membership_V6 => SOSC.IPV6_DROP_MEMBERSHIP,
108 Multicast_If_V6 => SOSC.IPV6_MULTICAST_IF,
109 Multicast_Loop_V6 => SOSC.IPV6_MULTICAST_LOOP,
110 Multicast_Hops => SOSC.IPV6_MULTICAST_HOPS,
111 IPv6_Only => SOSC.IPV6_V6ONLY,
112 Send_Timeout => SOSC.SO_SNDTIMEO,
113 Receive_Timeout => SOSC.SO_RCVTIMEO,
114 Busy_Polling => SOSC.SO_BUSY_POLL);
115 -- ??? Note: for OpenSolaris, Receive_Packet_Info should be IP_RECVPKTINFO,
116 -- but for Linux compatibility this constant is the same as IP_PKTINFO.
117
118 Flags : constant array (0 .. 3) of C.int :=
119 (0 => SOSC.MSG_OOB, -- Process_Out_Of_Band_Data
120 1 => SOSC.MSG_PEEK, -- Peek_At_Incoming_Data
121 2 => SOSC.MSG_WAITALL, -- Wait_For_A_Full_Reception
122 3 => SOSC.MSG_EOR); -- Send_End_Of_Record
123
124 Socket_Error_Id : constant Exception_Id := Socket_Error'Identity;
125 Host_Error_Id : constant Exception_Id := Host_Error'Identity;
126
127 type In_Addr_Union (Family : Family_Type) is record
128 case Family is
129 when Family_Inet =>
130 In4 : In_Addr;
131 when Family_Inet6 =>
132 In6 : In6_Addr;
133 when Family_Unspec =>
134 null;
135 end case;
136 end record with Unchecked_Union;
137
138 -----------------------
139 -- Local subprograms --
140 -----------------------
141
142 function Resolve_Error
143 (Error_Value : Integer;
144 From_Errno : Boolean := True) return Error_Type;
145 -- Associate an enumeration value (error_type) to an error value (errno).
146 -- From_Errno prevents from mixing h_errno with errno.
147
148 function To_Name (N : String) return Name_Type;
149 function To_String (HN : Name_Type) return String;
150 -- Conversion functions
151
152 function To_Int (F : Request_Flag_Type) return C.int;
153 -- Return the int value corresponding to the specified flags combination
154
155 function Set_Forced_Flags (F : C.int) return C.int;
156 -- Return F with the bits from SOSC.MSG_Forced_Flags forced set
157
158 procedure Netdb_Lock;
159 pragma Inline (Netdb_Lock);
160 procedure Netdb_Unlock;
161 pragma Inline (Netdb_Unlock);
162 -- Lock/unlock operation used to protect netdb access for platforms that
163 -- require such protection.
164
165 function To_Host_Entry (E : Hostent_Access) return Host_Entry_Type;
166 -- Conversion function
167
168 function To_Service_Entry (E : Servent_Access) return Service_Entry_Type;
169 -- Conversion function
170
171 function Value (S : System.Address) return String;
172 -- Same as Interfaces.C.Strings.Value but taking a System.Address
173
174 function To_Timeval (Val : Timeval_Duration) return Timeval;
175 -- Separate Val in seconds and microseconds
176
177 function To_Duration (Val : Timeval) return Timeval_Duration;
178 -- Reconstruct a Duration value from a Timeval record (seconds and
179 -- microseconds).
180
181 function Dedot (Value : String) return String
182 is (if Value /= "" and then Value (Value'Last) = '.'
183 then Value (Value'First .. Value'Last - 1)
184 else Value);
185 -- Removes dot at the end of error message
186
187 procedure Raise_Socket_Error (Error : Integer);
188 -- Raise Socket_Error with an exception message describing the error code
189 -- from errno.
190
191 procedure Raise_Host_Error (H_Error : Integer; Name : String);
192 -- Raise Host_Error exception with message describing error code (note
193 -- hstrerror seems to be obsolete) from h_errno. Name is the name
194 -- or address that was being looked up.
195
196 procedure Raise_GAI_Error (RC : C.int; Name : String);
197 -- Raise Host_Error with exception message in case of errors in
198 -- getaddrinfo and getnameinfo.
199
200 function Is_Windows return Boolean with Inline;
201 -- Returns True on Windows platform
202
203 procedure Narrow (Item : in out Socket_Set_Type);
204 -- Update Last as it may be greater than the real last socket
205
206 procedure Check_For_Fd_Set (Fd : Socket_Type);
207 pragma Inline (Check_For_Fd_Set);
208 -- Raise Constraint_Error if Fd is less than 0 or greater than or equal to
209 -- FD_SETSIZE, on platforms where fd_set is a bitmap.
210
211 function Connect_Socket
212 (Socket : Socket_Type;
213 Server : Sock_Addr_Type) return C.int;
214 pragma Inline (Connect_Socket);
215 -- Underlying implementation for the Connect_Socket procedures
216
217 -- Types needed for Datagram_Socket_Stream_Type
218
219 type Datagram_Socket_Stream_Type is new Root_Stream_Type with record
220 Socket : Socket_Type;
221 To : Sock_Addr_Type;
222 From : Sock_Addr_Type;
223 end record;
224
225 type Datagram_Socket_Stream_Access is
226 access all Datagram_Socket_Stream_Type;
227
228 procedure Read
229 (Stream : in out Datagram_Socket_Stream_Type;
230 Item : out Ada.Streams.Stream_Element_Array;
231 Last : out Ada.Streams.Stream_Element_Offset);
232
233 procedure Write
234 (Stream : in out Datagram_Socket_Stream_Type;
235 Item : Ada.Streams.Stream_Element_Array);
236
237 -- Types needed for Stream_Socket_Stream_Type
238
239 type Stream_Socket_Stream_Type is new Root_Stream_Type with record
240 Socket : Socket_Type;
241 end record;
242
243 type Stream_Socket_Stream_Access is
244 access all Stream_Socket_Stream_Type;
245
246 procedure Read
247 (Stream : in out Stream_Socket_Stream_Type;
248 Item : out Ada.Streams.Stream_Element_Array;
249 Last : out Ada.Streams.Stream_Element_Offset);
250
251 procedure Write
252 (Stream : in out Stream_Socket_Stream_Type;
253 Item : Ada.Streams.Stream_Element_Array);
254
255 procedure Wait_On_Socket
256 (Socket : Socket_Type;
257 For_Read : Boolean;
258 Timeout : Selector_Duration;
259 Selector : access Selector_Type := null;
260 Status : out Selector_Status);
261 -- Common code for variants of socket operations supporting a timeout:
262 -- block in Check_Selector on Socket for at most the indicated timeout.
263 -- If For_Read is True, Socket is added to the read set for this call, else
264 -- it is added to the write set. If no selector is provided, a local one is
265 -- created for this call and destroyed prior to returning.
266
267 type Sockets_Library_Controller is new Ada.Finalization.Limited_Controlled
268 with null record;
269 -- This type is used to generate automatic calls to Initialize and Finalize
270 -- during the elaboration and finalization of this package. A single object
271 -- of this type must exist at library level.
272
273 function Err_Code_Image (E : Integer) return String;
274 -- Return the value of E surrounded with brackets
275
276 procedure Initialize (X : in out Sockets_Library_Controller);
277 procedure Finalize (X : in out Sockets_Library_Controller);
278
279 procedure Normalize_Empty_Socket_Set (S : in out Socket_Set_Type);
280 -- If S is the empty set (detected by Last = No_Socket), make sure its
281 -- fd_set component is actually cleared. Note that the case where it is
282 -- not can occur for an uninitialized Socket_Set_Type object.
283
284 function Is_Open (S : Selector_Type) return Boolean;
285 -- Return True for an "open" Selector_Type object, i.e. one for which
286 -- Create_Selector has been called and Close_Selector has not been called,
287 -- or the null selector.
288
289 function Create_Address
290 (Family : Family_Type; Bytes : Inet_Addr_Bytes) return Inet_Addr_Type
291 with Inline;
292 -- Creates address from family and Inet_Addr_Bytes array.
293
294 function Get_Bytes (Addr : Inet_Addr_Type) return Inet_Addr_Bytes
295 with Inline;
296 -- Extract bytes from address
297
298 ---------
299 -- "+" --
300 ---------
301
302 function "+" (L, R : Request_Flag_Type) return Request_Flag_Type is
303 begin
304 return L or R;
305 end "+";
306
307 --------------------
308 -- Abort_Selector --
309 --------------------
310
311 procedure Abort_Selector (Selector : Selector_Type) is
312 Res : C.int;
313
314 begin
315 if not Is_Open (Selector) then
316 raise Program_Error with "closed selector";
317
318 elsif Selector.Is_Null then
319 raise Program_Error with "null selector";
320
321 end if;
322
323 -- Send one byte to unblock select system call
324
325 Res := Signalling_Fds.Write (C.int (Selector.W_Sig_Socket));
326
327 if Res = Failure then
328 Raise_Socket_Error (Socket_Errno);
329 end if;
330 end Abort_Selector;
331
332 -------------------
333 -- Accept_Socket --
334 -------------------
335
336 procedure Accept_Socket
337 (Server : Socket_Type;
338 Socket : out Socket_Type;
339 Address : out Sock_Addr_Type)
340 is
341 Res : C.int;
342 Sin : aliased Sockaddr;
343 Len : aliased C.int := Sin'Size / 8;
344
345 begin
346 Res := C_Accept (C.int (Server), Sin'Address, Len'Access);
347
348 if Res = Failure then
349 Raise_Socket_Error (Socket_Errno);
350 end if;
351
352 Socket := Socket_Type (Res);
353 Address := Get_Address (Sin);
354 end Accept_Socket;
355
356 -------------------
357 -- Accept_Socket --
358 -------------------
359
360 procedure Accept_Socket
361 (Server : Socket_Type;
362 Socket : out Socket_Type;
363 Address : out Sock_Addr_Type;
364 Timeout : Selector_Duration;
365 Selector : access Selector_Type := null;
366 Status : out Selector_Status)
367 is
368 begin
369 if Selector /= null and then not Is_Open (Selector.all) then
370 raise Program_Error with "closed selector";
371 end if;
372
373 -- Wait for socket to become available for reading
374
375 Wait_On_Socket
376 (Socket => Server,
377 For_Read => True,
378 Timeout => Timeout,
379 Selector => Selector,
380 Status => Status);
381
382 -- Accept connection if available
383
384 if Status = Completed then
385 Accept_Socket (Server, Socket, Address);
386 else
387 Socket := No_Socket;
388 end if;
389 end Accept_Socket;
390
391 ---------------
392 -- Addresses --
393 ---------------
394
395 function Addresses
396 (E : Host_Entry_Type;
397 N : Positive := 1) return Inet_Addr_Type
398 is
399 begin
400 return E.Addresses (N);
401 end Addresses;
402
403 ----------------------
404 -- Addresses_Length --
405 ----------------------
406
407 function Addresses_Length (E : Host_Entry_Type) return Natural is
408 begin
409 return E.Addresses_Length;
410 end Addresses_Length;
411
412 -------------
413 -- Aliases --
414 -------------
415
416 function Aliases
417 (E : Host_Entry_Type;
418 N : Positive := 1) return String
419 is
420 begin
421 return To_String (E.Aliases (N));
422 end Aliases;
423
424 -------------
425 -- Aliases --
426 -------------
427
428 function Aliases
429 (S : Service_Entry_Type;
430 N : Positive := 1) return String
431 is
432 begin
433 return To_String (S.Aliases (N));
434 end Aliases;
435
436 --------------------
437 -- Aliases_Length --
438 --------------------
439
440 function Aliases_Length (E : Host_Entry_Type) return Natural is
441 begin
442 return E.Aliases_Length;
443 end Aliases_Length;
444
445 --------------------
446 -- Aliases_Length --
447 --------------------
448
449 function Aliases_Length (S : Service_Entry_Type) return Natural is
450 begin
451 return S.Aliases_Length;
452 end Aliases_Length;
453
454 -----------------
455 -- Bind_Socket --
456 -----------------
457
458 procedure Bind_Socket
459 (Socket : Socket_Type;
460 Address : Sock_Addr_Type)
461 is
462 Res : C.int;
463 Sin : aliased Sockaddr;
464
465 begin
466 Set_Address (Sin'Unchecked_Access, Address);
467
468 Res := C_Bind
469 (C.int (Socket), Sin'Address, C.int (Lengths (Address.Family)));
470
471 if Res = Failure then
472 Raise_Socket_Error (Socket_Errno);
473 end if;
474 end Bind_Socket;
475
476 ----------------------
477 -- Check_For_Fd_Set --
478 ----------------------
479
480 procedure Check_For_Fd_Set (Fd : Socket_Type) is
481 begin
482 -- On Windows, fd_set is a FD_SETSIZE array of socket ids:
483 -- no check required. Warnings suppressed because condition
484 -- is known at compile time.
485
486 if Is_Windows then
487
488 return;
489
490 -- On other platforms, fd_set is an FD_SETSIZE bitmap: check
491 -- that Fd is within range (otherwise behavior is undefined).
492
493 elsif Fd < 0 or else Fd >= SOSC.FD_SETSIZE then
494 raise Constraint_Error
495 with "invalid value for socket set: " & Image (Fd);
496 end if;
497 end Check_For_Fd_Set;
498
499 --------------------
500 -- Check_Selector --
501 --------------------
502
503 procedure Check_Selector
504 (Selector : Selector_Type;
505 R_Socket_Set : in out Socket_Set_Type;
506 W_Socket_Set : in out Socket_Set_Type;
507 Status : out Selector_Status;
508 Timeout : Selector_Duration := Forever)
509 is
510 E_Socket_Set : Socket_Set_Type;
511 begin
512 Check_Selector
513 (Selector, R_Socket_Set, W_Socket_Set, E_Socket_Set, Status, Timeout);
514 end Check_Selector;
515
516 procedure Check_Selector
517 (Selector : Selector_Type;
518 R_Socket_Set : in out Socket_Set_Type;
519 W_Socket_Set : in out Socket_Set_Type;
520 E_Socket_Set : in out Socket_Set_Type;
521 Status : out Selector_Status;
522 Timeout : Selector_Duration := Forever)
523 is
524 Res : C.int;
525 Last : C.int;
526 RSig : Socket_Type := No_Socket;
527 TVal : aliased Timeval;
528 TPtr : Timeval_Access;
529
530 begin
531 if not Is_Open (Selector) then
532 raise Program_Error with "closed selector";
533 end if;
534
535 Status := Completed;
536
537 -- No timeout or Forever is indicated by a null timeval pointer
538
539 if Timeout = Forever then
540 TPtr := null;
541 else
542 TVal := To_Timeval (Timeout);
543 TPtr := TVal'Unchecked_Access;
544 end if;
545
546 -- Add read signalling socket, if present
547
548 if not Selector.Is_Null then
549 RSig := Selector.R_Sig_Socket;
550 Set (R_Socket_Set, RSig);
551 end if;
552
553 Last := C.int'Max (C.int'Max (C.int (R_Socket_Set.Last),
554 C.int (W_Socket_Set.Last)),
555 C.int (E_Socket_Set.Last));
556
557 -- Zero out fd_set for empty Socket_Set_Type objects
558
559 Normalize_Empty_Socket_Set (R_Socket_Set);
560 Normalize_Empty_Socket_Set (W_Socket_Set);
561 Normalize_Empty_Socket_Set (E_Socket_Set);
562
563 Res :=
564 C_Select
565 (Last + 1,
566 R_Socket_Set.Set'Access,
567 W_Socket_Set.Set'Access,
568 E_Socket_Set.Set'Access,
569 TPtr);
570
571 if Res = Failure then
572 Raise_Socket_Error (Socket_Errno);
573 end if;
574
575 -- If Select was resumed because of read signalling socket, read this
576 -- data and remove socket from set.
577
578 if RSig /= No_Socket and then Is_Set (R_Socket_Set, RSig) then
579 Clear (R_Socket_Set, RSig);
580
581 Res := Signalling_Fds.Read (C.int (RSig));
582
583 if Res = Failure then
584 Raise_Socket_Error (Socket_Errno);
585 end if;
586
587 Status := Aborted;
588
589 elsif Res = 0 then
590 Status := Expired;
591 end if;
592
593 -- Update socket sets in regard to their new contents
594
595 Narrow (R_Socket_Set);
596 Narrow (W_Socket_Set);
597 Narrow (E_Socket_Set);
598 end Check_Selector;
599
600 -----------
601 -- Clear --
602 -----------
603
604 procedure Clear
605 (Item : in out Socket_Set_Type;
606 Socket : Socket_Type)
607 is
608 Last : aliased C.int := C.int (Item.Last);
609
610 begin
611 Check_For_Fd_Set (Socket);
612
613 if Item.Last /= No_Socket then
614 Remove_Socket_From_Set (Item.Set'Access, C.int (Socket));
615 Last_Socket_In_Set (Item.Set'Access, Last'Unchecked_Access);
616 Item.Last := Socket_Type (Last);
617 end if;
618 end Clear;
619
620 --------------------
621 -- Close_Selector --
622 --------------------
623
624 procedure Close_Selector (Selector : in out Selector_Type) is
625 begin
626 -- Nothing to do if selector already in closed state
627
628 if Selector.Is_Null or else not Is_Open (Selector) then
629 return;
630 end if;
631
632 -- Close the signalling file descriptors used internally for the
633 -- implementation of Abort_Selector.
634
635 Signalling_Fds.Close (C.int (Selector.R_Sig_Socket));
636 Signalling_Fds.Close (C.int (Selector.W_Sig_Socket));
637
638 -- Reset R_Sig_Socket and W_Sig_Socket to No_Socket to ensure that any
639 -- (erroneous) subsequent attempt to use this selector properly fails.
640
641 Selector.R_Sig_Socket := No_Socket;
642 Selector.W_Sig_Socket := No_Socket;
643 end Close_Selector;
644
645 ------------------
646 -- Close_Socket --
647 ------------------
648
649 procedure Close_Socket (Socket : Socket_Type) is
650 Res : C.int;
651
652 begin
653 Res := C_Close (C.int (Socket));
654
655 if Res = Failure then
656 Raise_Socket_Error (Socket_Errno);
657 end if;
658 end Close_Socket;
659
660 --------------------
661 -- Connect_Socket --
662 --------------------
663
664 function Connect_Socket
665 (Socket : Socket_Type;
666 Server : Sock_Addr_Type) return C.int
667 is
668 Sin : aliased Sockaddr;
669 begin
670 Set_Address (Sin'Unchecked_Access, Server);
671
672 return C_Connect
673 (C.int (Socket), Sin'Address, C.int (Lengths (Server.Family)));
674 end Connect_Socket;
675
676 procedure Connect_Socket
677 (Socket : Socket_Type;
678 Server : Sock_Addr_Type)
679 is
680 begin
681 if Connect_Socket (Socket, Server) = Failure then
682 Raise_Socket_Error (Socket_Errno);
683 end if;
684 end Connect_Socket;
685
686 procedure Connect_Socket
687 (Socket : Socket_Type;
688 Server : Sock_Addr_Type;
689 Timeout : Selector_Duration;
690 Selector : access Selector_Type := null;
691 Status : out Selector_Status)
692 is
693 Req : Request_Type;
694 -- Used to set Socket to non-blocking I/O
695
696 Conn_Err : aliased Integer;
697 -- Error status of the socket after completion of select(2)
698
699 Res : C.int;
700 Conn_Err_Size : aliased C.int := Conn_Err'Size / 8;
701 -- For getsockopt(2) call
702
703 begin
704 if Selector /= null and then not Is_Open (Selector.all) then
705 raise Program_Error with "closed selector";
706 end if;
707
708 -- Set the socket to non-blocking I/O
709
710 Req := (Name => Non_Blocking_IO, Enabled => True);
711 Control_Socket (Socket, Request => Req);
712
713 -- Start operation (non-blocking), will return Failure with errno set
714 -- to EINPROGRESS.
715
716 Res := Connect_Socket (Socket, Server);
717 if Res = Failure then
718 Conn_Err := Socket_Errno;
719 if Conn_Err /= SOSC.EINPROGRESS then
720 Raise_Socket_Error (Conn_Err);
721 end if;
722 end if;
723
724 -- Wait for socket to become available for writing (unless the Timeout
725 -- is zero, in which case we consider that it has already expired, and
726 -- we do not need to wait at all).
727
728 if Timeout = 0.0 then
729 Status := Expired;
730
731 else
732 Wait_On_Socket
733 (Socket => Socket,
734 For_Read => False,
735 Timeout => Timeout,
736 Selector => Selector,
737 Status => Status);
738 end if;
739
740 -- Check error condition (the asynchronous connect may have terminated
741 -- with an error, e.g. ECONNREFUSED) if select(2) completed.
742
743 if Status = Completed then
744 Res := C_Getsockopt
745 (C.int (Socket), SOSC.SOL_SOCKET, SOSC.SO_ERROR,
746 Conn_Err'Address, Conn_Err_Size'Access);
747
748 if Res /= 0 then
749 Conn_Err := Socket_Errno;
750 end if;
751
752 else
753 Conn_Err := 0;
754 end if;
755
756 -- Reset the socket to blocking I/O
757
758 Req := (Name => Non_Blocking_IO, Enabled => False);
759 Control_Socket (Socket, Request => Req);
760
761 -- Report error condition if any
762
763 if Conn_Err /= 0 then
764 Raise_Socket_Error (Conn_Err);
765 end if;
766 end Connect_Socket;
767
768 --------------------
769 -- Control_Socket --
770 --------------------
771
772 procedure Control_Socket
773 (Socket : Socket_Type;
774 Request : in out Request_Type)
775 is
776 Arg : aliased C.int;
777 Res : C.int;
778
779 begin
780 case Request.Name is
781 when Non_Blocking_IO =>
782 Arg := C.int (Boolean'Pos (Request.Enabled));
783
784 when N_Bytes_To_Read =>
785 null;
786 end case;
787
788 Res := Socket_Ioctl
789 (C.int (Socket), Requests (Request.Name), Arg'Unchecked_Access);
790
791 if Res = Failure then
792 Raise_Socket_Error (Socket_Errno);
793 end if;
794
795 case Request.Name is
796 when Non_Blocking_IO =>
797 null;
798
799 when N_Bytes_To_Read =>
800 Request.Size := Natural (Arg);
801 end case;
802 end Control_Socket;
803
804 ----------
805 -- Copy --
806 ----------
807
808 procedure Copy
809 (Source : Socket_Set_Type;
810 Target : out Socket_Set_Type)
811 is
812 begin
813 Target := Source;
814 end Copy;
815
816 ---------------------
817 -- Create_Selector --
818 ---------------------
819
820 procedure Create_Selector (Selector : out Selector_Type) is
821 Two_Fds : aliased Fd_Pair;
822 Res : C.int;
823
824 begin
825 if Is_Open (Selector) then
826 -- Raise exception to prevent socket descriptor leak
827
828 raise Program_Error with "selector already open";
829 end if;
830
831 -- We open two signalling file descriptors. One of them is used to send
832 -- data to the other, which is included in a C_Select socket set. The
833 -- communication is used to force a call to C_Select to complete, and
834 -- the waiting task to resume its execution.
835
836 Res := Signalling_Fds.Create (Two_Fds'Access);
837
838 if Res = Failure then
839 Raise_Socket_Error (Socket_Errno);
840 end if;
841
842 Selector.R_Sig_Socket := Socket_Type (Two_Fds (Read_End));
843 Selector.W_Sig_Socket := Socket_Type (Two_Fds (Write_End));
844 end Create_Selector;
845
846 -------------------
847 -- Create_Socket --
848 -------------------
849
850 procedure Create_Socket
851 (Socket : out Socket_Type;
852 Family : Family_Type := Family_Inet;
853 Mode : Mode_Type := Socket_Stream;
854 Level : Level_Type := IP_Protocol_For_IP_Level)
855 is
856 Res : C.int;
857
858 begin
859 Res := C_Socket (Families (Family), Modes (Mode), Levels (Level));
860
861 if Res = Failure then
862 Raise_Socket_Error (Socket_Errno);
863 end if;
864
865 Socket := Socket_Type (Res);
866 end Create_Socket;
867
868 -----------
869 -- Empty --
870 -----------
871
872 procedure Empty (Item : out Socket_Set_Type) is
873 begin
874 Reset_Socket_Set (Item.Set'Access);
875 Item.Last := No_Socket;
876 end Empty;
877
878 --------------------
879 -- Err_Code_Image --
880 --------------------
881
882 function Err_Code_Image (E : Integer) return String is
883 Msg : String := E'Img & "] ";
884 begin
885 Msg (Msg'First) := '[';
886 return Msg;
887 end Err_Code_Image;
888
889 --------------
890 -- Finalize --
891 --------------
892
893 procedure Finalize (X : in out Sockets_Library_Controller) is
894 pragma Unreferenced (X);
895
896 begin
897 -- Finalization operation for the GNAT.Sockets package
898
899 Thin.Finalize;
900 end Finalize;
901
902 --------------
903 -- Finalize --
904 --------------
905
906 procedure Finalize is
907 begin
908 -- This is a dummy placeholder for an obsolete API.
909 -- The real finalization actions are in Initialize primitive operation
910 -- of Sockets_Library_Controller.
911
912 null;
913 end Finalize;
914
915 ---------
916 -- Get --
917 ---------
918
919 procedure Get
920 (Item : in out Socket_Set_Type;
921 Socket : out Socket_Type)
922 is
923 S : aliased C.int;
924 L : aliased C.int := C.int (Item.Last);
925
926 begin
927 if Item.Last /= No_Socket then
928 Get_Socket_From_Set
929 (Item.Set'Access, Last => L'Access, Socket => S'Access);
930 Item.Last := Socket_Type (L);
931 Socket := Socket_Type (S);
932 else
933 Socket := No_Socket;
934 end if;
935 end Get;
936
937 -----------------
938 -- Get_Address --
939 -----------------
940
941 function Get_Address
942 (Stream : not null Stream_Access) return Sock_Addr_Type
943 is
944 begin
945 if Stream.all in Datagram_Socket_Stream_Type then
946 return Datagram_Socket_Stream_Type (Stream.all).From;
947 else
948 return Get_Peer_Name (Stream_Socket_Stream_Type (Stream.all).Socket);
949 end if;
950 end Get_Address;
951
952 ---------------------
953 -- Raise_GAI_Error --
954 ---------------------
955
956 procedure Raise_GAI_Error (RC : C.int; Name : String) is
957 begin
958 if RC = SOSC.EAI_SYSTEM then
959 declare
960 Errcode : constant Integer := Socket_Errno;
961 begin
962 raise Host_Error with Err_Code_Image (Errcode)
963 & Dedot (Socket_Error_Message (Errcode)) & ": " & Name;
964 end;
965 else
966 raise Host_Error with Err_Code_Image (Integer (RC))
967 & Dedot (CS.Value (C_GAI_Strerror (RC))) & ": " & Name;
968 end if;
969 end Raise_GAI_Error;
970
971 ----------------------
972 -- Get_Address_Info --
973 ----------------------
974
975 function Get_Address_Info
976 (Host : String;
977 Service : String;
978 Family : Family_Type := Family_Unspec;
979 Mode : Mode_Type := Socket_Stream;
980 Level : Level_Type := IP_Protocol_For_IP_Level;
981 Numeric_Host : Boolean := False;
982 Passive : Boolean := False;
983 Unknown : access procedure
984 (Family, Mode, Level, Length : Integer) := null)
985 return Address_Info_Array
986 is
987 A : aliased Addrinfo_Access;
988 N : aliased C.char_array := C.To_C (Host);
989 S : aliased C.char_array := C.To_C (if Service = "" then "0"
990 else Service);
991 Hints : aliased constant Addrinfo :=
992 (ai_family => Families (Family),
993 ai_socktype => Modes (Mode),
994 ai_protocol => Levels (Level),
995 ai_flags => (if Numeric_Host then SOSC.AI_NUMERICHOST else 0) +
996 (if Passive then SOSC.AI_PASSIVE else 0),
997 ai_addrlen => 0,
998 others => <>);
999
1000 R : C.int;
1001 Iter : Addrinfo_Access;
1002 Found : Boolean;
1003
1004 function To_Array return Address_Info_Array;
1005 -- Convert taken from OS addrinfo list A into Address_Info_Array
1006
1007 --------------
1008 -- To_Array --
1009 --------------
1010
1011 function To_Array return Address_Info_Array is
1012 Result : Address_Info_Array (1 .. 8);
1013
1014 procedure Unsupported;
1015 -- Calls Unknown callback if defiend
1016
1017 -----------------
1018 -- Unsupported --
1019 -----------------
1020
1021 procedure Unsupported is
1022 begin
1023 if Unknown /= null then
1024 Unknown
1025 (Integer (Iter.ai_family),
1026 Integer (Iter.ai_socktype),
1027 Integer (Iter.ai_protocol),
1028 Integer (Iter.ai_addrlen));
1029 end if;
1030 end Unsupported;
1031
1032 -- Start of processing for To_Array
1033
1034 begin
1035 for J in Result'Range loop
1036 Look_For_Supported : loop
1037 if Iter = null then
1038 return Result (1 .. J - 1);
1039 end if;
1040
1041 Result (J).Addr := Get_Address (Iter.ai_addr.all);
1042
1043 if Result (J).Addr.Family = Family_Unspec then
1044 Unsupported;
1045 else
1046 for M in Modes'Range loop
1047 Found := False;
1048 if Modes (M) = Iter.ai_socktype then
1049 Result (J).Mode := M;
1050 Found := True;
1051 exit;
1052 end if;
1053 end loop;
1054
1055 if Found then
1056 for L in Levels'Range loop
1057 if Levels (L) = Iter.ai_protocol then
1058 Result (J).Level := L;
1059 exit;
1060 end if;
1061 end loop;
1062
1063 exit Look_For_Supported;
1064 else
1065 Unsupported;
1066 end if;
1067 end if;
1068
1069 Iter := Iter.ai_next;
1070
1071 if Iter = null then
1072 return Result (1 .. J - 1);
1073 end if;
1074 end loop Look_For_Supported;
1075
1076 Iter := Iter.ai_next;
1077 end loop;
1078
1079 return Result & To_Array;
1080 end To_Array;
1081
1082 -- Start of processing for Get_Address_Info
1083
1084 begin
1085 R := C_Getaddrinfo
1086 (Node => (if Host = "" then null else N'Unchecked_Access),
1087 Service => S'Unchecked_Access,
1088 Hints => Hints'Unchecked_Access,
1089 Res => A'Access);
1090
1091 if R /= 0 then
1092 Raise_GAI_Error
1093 (R, Host & (if Service = "" then "" else ':' & Service));
1094 end if;
1095
1096 Iter := A;
1097
1098 return Result : constant Address_Info_Array := To_Array do
1099 C_Freeaddrinfo (A);
1100 end return;
1101 end Get_Address_Info;
1102
1103 ----------
1104 -- Sort --
1105 ----------
1106
1107 procedure Sort
1108 (Addr_Info : in out Address_Info_Array;
1109 Compare : access function (Left, Right : Address_Info) return Boolean)
1110 is
1111 function Comp (Left, Right : Address_Info) return Boolean is
1112 (Compare (Left, Right));
1113 procedure Sorter is new Ada.Containers.Generic_Array_Sort
1114 (Positive, Address_Info, Address_Info_Array, Comp);
1115 begin
1116 Sorter (Addr_Info);
1117 end Sort;
1118
1119 ------------------------
1120 -- IPv6_TCP_Preferred --
1121 ------------------------
1122
1123 function IPv6_TCP_Preferred (Left, Right : Address_Info) return Boolean is
1124 begin
1125 pragma Assert (Family_Inet < Family_Inet6);
1126 -- To be sure that Family_Type enumeration has appropriate elements
1127 -- order
1128
1129 if Left.Addr.Family /= Right.Addr.Family then
1130 return Left.Addr.Family > Right.Addr.Family;
1131 end if;
1132
1133 pragma Assert (Socket_Stream < Socket_Datagram);
1134 -- To be sure that Mode_Type enumeration has appropriate elements order
1135
1136 return Left.Mode < Right.Mode;
1137 end IPv6_TCP_Preferred;
1138
1139 -------------------
1140 -- Get_Name_Info --
1141 -------------------
1142
1143 function Get_Name_Info
1144 (Addr : Sock_Addr_Type;
1145 Numeric_Host : Boolean := False;
1146 Numeric_Serv : Boolean := False) return Host_Service
1147 is
1148 SA : aliased Sockaddr;
1149 H : aliased C.char_array := (1 .. SOSC.NI_MAXHOST => C.nul);
1150 S : aliased C.char_array := (1 .. SOSC.NI_MAXSERV => C.nul);
1151 RC : C.int;
1152 begin
1153 Set_Address (SA'Unchecked_Access, Addr);
1154
1155 RC := C_Getnameinfo
1156 (SA'Unchecked_Access, socklen_t (Lengths (Addr.Family)),
1157 H'Unchecked_Access, H'Length,
1158 S'Unchecked_Access, S'Length,
1159 (if Numeric_Host then SOSC.NI_NUMERICHOST else 0) +
1160 (if Numeric_Serv then SOSC.NI_NUMERICSERV else 0));
1161
1162 if RC /= 0 then
1163 Raise_GAI_Error (RC, Image (Addr));
1164 end if;
1165
1166 declare
1167 HR : constant String := C.To_Ada (H);
1168 SR : constant String := C.To_Ada (S);
1169 begin
1170 return (HR'Length, SR'Length, HR, SR);
1171 end;
1172 end Get_Name_Info;
1173
1174 -------------------------
1175 -- Get_Host_By_Address --
1176 -------------------------
1177
1178 function Get_Host_By_Address
1179 (Address : Inet_Addr_Type;
1180 Family : Family_Type := Family_Inet) return Host_Entry_Type
1181 is
1182 pragma Unreferenced (Family);
1183
1184 HA : aliased In_Addr_Union (Address.Family);
1185 Buflen : constant C.int := Netdb_Buffer_Size;
1186 Buf : aliased C.char_array (1 .. Netdb_Buffer_Size);
1187 Res : aliased Hostent;
1188 Err : aliased C.int;
1189
1190 begin
1191 case Address.Family is
1192 when Family_Inet =>
1193 HA.In4 := To_In_Addr (Address);
1194 when Family_Inet6 =>
1195 HA.In6 := To_In6_Addr (Address);
1196 when Family_Unspec =>
1197 return (0, 0, (1, " "), (1 .. 0 => (1, " ")),
1198 (1 .. 0 => No_Inet_Addr));
1199 end case;
1200
1201 Netdb_Lock;
1202
1203 if C_Gethostbyaddr
1204 (HA'Address,
1205 (case Address.Family is
1206 when Family_Inet => HA.In4'Size,
1207 when Family_Inet6 => HA.In6'Size,
1208 when Family_Unspec => 0) / 8,
1209 Families (Address.Family),
1210 Res'Access, Buf'Address, Buflen, Err'Access) /= 0
1211 then
1212 Netdb_Unlock;
1213 Raise_Host_Error (Integer (Err), Image (Address));
1214 end if;
1215
1216 begin
1217 return H : constant Host_Entry_Type :=
1218 To_Host_Entry (Res'Unchecked_Access)
1219 do
1220 Netdb_Unlock;
1221 end return;
1222 exception
1223 when others =>
1224 Netdb_Unlock;
1225 raise;
1226 end;
1227 end Get_Host_By_Address;
1228
1229 ----------------------
1230 -- Get_Host_By_Name --
1231 ----------------------
1232
1233 function Get_Host_By_Name (Name : String) return Host_Entry_Type is
1234 begin
1235 -- If the given name actually is the string representation of
1236 -- an IP address, use Get_Host_By_Address instead.
1237
1238 if Is_IPv4_Address (Name) or else Is_IPv6_Address (Name) then
1239 return Get_Host_By_Address (Inet_Addr (Name));
1240 end if;
1241
1242 declare
1243 HN : constant C.char_array := C.To_C (Name);
1244 Buflen : constant C.int := Netdb_Buffer_Size;
1245 Buf : aliased C.char_array (1 .. Netdb_Buffer_Size);
1246 Res : aliased Hostent;
1247 Err : aliased C.int;
1248
1249 begin
1250 Netdb_Lock;
1251
1252 if C_Gethostbyname
1253 (HN, Res'Access, Buf'Address, Buflen, Err'Access) /= 0
1254 then
1255 Netdb_Unlock;
1256 Raise_Host_Error (Integer (Err), Name);
1257 end if;
1258
1259 return H : constant Host_Entry_Type :=
1260 To_Host_Entry (Res'Unchecked_Access)
1261 do
1262 Netdb_Unlock;
1263 end return;
1264 end;
1265 end Get_Host_By_Name;
1266
1267 -------------------
1268 -- Get_Peer_Name --
1269 -------------------
1270
1271 function Get_Peer_Name (Socket : Socket_Type) return Sock_Addr_Type is
1272 Sin : aliased Sockaddr;
1273 Len : aliased C.int := Sin'Size / 8;
1274 begin
1275 if C_Getpeername (C.int (Socket), Sin'Address, Len'Access) = Failure then
1276 Raise_Socket_Error (Socket_Errno);
1277 end if;
1278
1279 return Get_Address (Sin);
1280 end Get_Peer_Name;
1281
1282 -------------------------
1283 -- Get_Service_By_Name --
1284 -------------------------
1285
1286 function Get_Service_By_Name
1287 (Name : String;
1288 Protocol : String) return Service_Entry_Type
1289 is
1290 SN : constant C.char_array := C.To_C (Name);
1291 SP : constant C.char_array := C.To_C (Protocol);
1292 Buflen : constant C.int := Netdb_Buffer_Size;
1293 Buf : aliased C.char_array (1 .. Netdb_Buffer_Size);
1294 Res : aliased Servent;
1295
1296 begin
1297 Netdb_Lock;
1298
1299 if C_Getservbyname (SN, SP, Res'Access, Buf'Address, Buflen) /= 0 then
1300 Netdb_Unlock;
1301 raise Service_Error with "Service not found";
1302 end if;
1303
1304 -- Translate from the C format to the API format
1305
1306 return S : constant Service_Entry_Type :=
1307 To_Service_Entry (Res'Unchecked_Access)
1308 do
1309 Netdb_Unlock;
1310 end return;
1311 end Get_Service_By_Name;
1312
1313 -------------------------
1314 -- Get_Service_By_Port --
1315 -------------------------
1316
1317 function Get_Service_By_Port
1318 (Port : Port_Type;
1319 Protocol : String) return Service_Entry_Type
1320 is
1321 SP : constant C.char_array := C.To_C (Protocol);
1322 Buflen : constant C.int := Netdb_Buffer_Size;
1323 Buf : aliased C.char_array (1 .. Netdb_Buffer_Size);
1324 Res : aliased Servent;
1325
1326 begin
1327 Netdb_Lock;
1328
1329 if C_Getservbyport
1330 (C.int (Short_To_Network (C.unsigned_short (Port))), SP,
1331 Res'Access, Buf'Address, Buflen) /= 0
1332 then
1333 Netdb_Unlock;
1334 raise Service_Error with "Service not found";
1335 end if;
1336
1337 -- Translate from the C format to the API format
1338
1339 return S : constant Service_Entry_Type :=
1340 To_Service_Entry (Res'Unchecked_Access)
1341 do
1342 Netdb_Unlock;
1343 end return;
1344 end Get_Service_By_Port;
1345
1346 ---------------------
1347 -- Get_Socket_Name --
1348 ---------------------
1349
1350 function Get_Socket_Name
1351 (Socket : Socket_Type) return Sock_Addr_Type
1352 is
1353 Sin : aliased Sockaddr;
1354 Len : aliased C.int := Sin'Size / 8;
1355 Res : C.int;
1356 begin
1357 Res := C_Getsockname (C.int (Socket), Sin'Address, Len'Access);
1358
1359 if Res = Failure then
1360 return No_Sock_Addr;
1361 end if;
1362
1363 return Get_Address (Sin);
1364 end Get_Socket_Name;
1365
1366 -----------------------
1367 -- Get_Socket_Option --
1368 -----------------------
1369
1370 function Get_Socket_Option
1371 (Socket : Socket_Type;
1372 Level : Level_Type := Socket_Level;
1373 Name : Option_Name;
1374 Optname : Interfaces.C.int := -1) return Option_Type
1375 is
1376 use type C.unsigned;
1377 use type C.unsigned_char;
1378
1379 V8 : aliased Two_Ints;
1380 V4 : aliased C.int;
1381 U4 : aliased C.unsigned;
1382 V1 : aliased C.unsigned_char;
1383 VT : aliased Timeval;
1384 Len : aliased C.int;
1385 Add : System.Address;
1386 Res : C.int;
1387 Opt : Option_Type (Name);
1388 Onm : Interfaces.C.int;
1389
1390 begin
1391 if Name in Specific_Option_Name then
1392 Onm := Options (Name);
1393
1394 elsif Optname = -1 then
1395 raise Socket_Error with "optname must be specified";
1396
1397 else
1398 Onm := Optname;
1399 end if;
1400
1401 case Name is
1402 when Multicast_TTL
1403 | Receive_Packet_Info
1404 =>
1405 Len := V1'Size / 8;
1406 Add := V1'Address;
1407
1408 when Broadcast
1409 | Busy_Polling
1410 | Error
1411 | Generic_Option
1412 | Keep_Alive
1413 | Multicast_If_V4
1414 | Multicast_If_V6
1415 | Multicast_Loop_V4
1416 | Multicast_Loop_V6
1417 | Multicast_Hops
1418 | No_Delay
1419 | Receive_Buffer
1420 | Reuse_Address
1421 | Send_Buffer
1422 | IPv6_Only
1423 =>
1424 Len := V4'Size / 8;
1425 Add := V4'Address;
1426
1427 when Receive_Timeout
1428 | Send_Timeout
1429 =>
1430 -- The standard argument for SO_RCVTIMEO and SO_SNDTIMEO is a
1431 -- struct timeval, but on Windows it is a milliseconds count in
1432 -- a DWORD.
1433
1434 if Is_Windows then
1435 Len := U4'Size / 8;
1436 Add := U4'Address;
1437 else
1438 Len := VT'Size / 8;
1439 Add := VT'Address;
1440 end if;
1441
1442 when Add_Membership_V4
1443 | Add_Membership_V6
1444 | Drop_Membership_V4
1445 | Drop_Membership_V6
1446 =>
1447 raise Socket_Error with
1448 "Add/Drop membership valid only for Set_Socket_Option";
1449
1450 when Linger
1451 =>
1452 Len := V8'Size / 8;
1453 Add := V8'Address;
1454 end case;
1455
1456 Res :=
1457 C_Getsockopt
1458 (C.int (Socket),
1459 Levels (Level),
1460 Onm,
1461 Add, Len'Access);
1462
1463 if Res = Failure then
1464 Raise_Socket_Error (Socket_Errno);
1465 end if;
1466
1467 case Name is
1468 when Generic_Option =>
1469 Opt.Optname := Onm;
1470 Opt.Optval := V4;
1471
1472 when Broadcast
1473 | Keep_Alive
1474 | No_Delay
1475 | Reuse_Address
1476 | Multicast_Loop_V4
1477 | Multicast_Loop_V6
1478 | IPv6_Only
1479 =>
1480 Opt.Enabled := (V4 /= 0);
1481
1482 when Busy_Polling =>
1483 Opt.Microseconds := Natural (V4);
1484
1485 when Linger =>
1486 Opt.Enabled := (V8 (V8'First) /= 0);
1487 Opt.Seconds := Natural (V8 (V8'Last));
1488
1489 when Receive_Buffer
1490 | Send_Buffer
1491 =>
1492 Opt.Size := Natural (V4);
1493
1494 when Error =>
1495 Opt.Error := Resolve_Error (Integer (V4));
1496
1497 when Add_Membership_V4
1498 | Add_Membership_V6
1499 | Drop_Membership_V4
1500 | Drop_Membership_V6
1501 =>
1502 -- No way to be here. Exception raised in the first case Name
1503 -- expression.
1504 null;
1505
1506 when Multicast_If_V4 =>
1507 To_Inet_Addr (To_In_Addr (V4), Opt.Outgoing_If);
1508
1509 when Multicast_If_V6 =>
1510 Opt.Outgoing_If_Index := Natural (V4);
1511
1512 when Multicast_TTL =>
1513 Opt.Time_To_Live := Integer (V1);
1514
1515 when Multicast_Hops =>
1516 Opt.Hop_Limit := Integer (V4);
1517
1518 when Receive_Packet_Info
1519 =>
1520 Opt.Enabled := (V1 /= 0);
1521
1522 when Receive_Timeout
1523 | Send_Timeout
1524 =>
1525 if Is_Windows then
1526
1527 -- Timeout is in milliseconds, actual value is 500 ms +
1528 -- returned value (unless it is 0).
1529
1530 if U4 = 0 then
1531 Opt.Timeout := 0.0;
1532 else
1533 Opt.Timeout := Duration (U4) / 1000 + 0.500;
1534 end if;
1535
1536 else
1537 Opt.Timeout := To_Duration (VT);
1538 end if;
1539 end case;
1540
1541 return Opt;
1542 end Get_Socket_Option;
1543
1544 ---------------
1545 -- Host_Name --
1546 ---------------
1547
1548 function Host_Name return String is
1549 Name : aliased C.char_array (1 .. 64);
1550 Res : C.int;
1551
1552 begin
1553 Res := C_Gethostname (Name'Address, Name'Length);
1554
1555 if Res = Failure then
1556 Raise_Socket_Error (Socket_Errno);
1557 end if;
1558
1559 return C.To_Ada (Name);
1560 end Host_Name;
1561
1562 -----------
1563 -- Image --
1564 -----------
1565
1566 function Image (Value : Inet_Addr_Type) return String is
1567 use type CS.char_array_access;
1568 Size : constant socklen_t :=
1569 (case Value.Family is
1570 when Family_Inet => 4 * Value.Sin_V4'Length,
1571 when Family_Inet6 => 6 * 5 + 4 * 4,
1572 -- 1234:1234:1234:1234:1234:1234:123.123.123.123
1573 when Family_Unspec => 0);
1574 Dst : aliased C.char_array := (1 .. C.size_t (Size) => C.nul);
1575 Ia : aliased In_Addr_Union (Value.Family);
1576 begin
1577 case Value.Family is
1578 when Family_Inet6 =>
1579 Ia.In6 := To_In6_Addr (Value);
1580 when Family_Inet =>
1581 Ia.In4 := To_In_Addr (Value);
1582 when Family_Unspec =>
1583 return "";
1584 end case;
1585
1586 if Inet_Ntop
1587 (Families (Value.Family), Ia'Address,
1588 Dst'Unchecked_Access, Size) = null
1589 then
1590 Raise_Socket_Error (Socket_Errno);
1591 end if;
1592
1593 return C.To_Ada (Dst);
1594 end Image;
1595
1596 -----------
1597 -- Image --
1598 -----------
1599
1600 function Image (Value : Sock_Addr_Type) return String is
1601 Port : constant String := Value.Port'Img;
1602 function Ipv6_Brackets (S : String) return String is
1603 (if Value.Family = Family_Inet6 then "[" & S & "]" else S);
1604 begin
1605 return Ipv6_Brackets (Image (Value.Addr)) & ':' & Port (2 .. Port'Last);
1606 end Image;
1607
1608 -----------
1609 -- Image --
1610 -----------
1611
1612 function Image (Socket : Socket_Type) return String is
1613 begin
1614 return Socket'Img;
1615 end Image;
1616
1617 -----------
1618 -- Image --
1619 -----------
1620
1621 function Image (Item : Socket_Set_Type) return String is
1622 Socket_Set : Socket_Set_Type := Item;
1623
1624 begin
1625 declare
1626 Last_Img : constant String := Socket_Set.Last'Img;
1627 Buffer : String
1628 (1 .. (Integer (Socket_Set.Last) + 1) * Last_Img'Length);
1629 Index : Positive := 1;
1630 Socket : Socket_Type;
1631
1632 begin
1633 while not Is_Empty (Socket_Set) loop
1634 Get (Socket_Set, Socket);
1635
1636 declare
1637 Socket_Img : constant String := Socket'Img;
1638 begin
1639 Buffer (Index .. Index + Socket_Img'Length - 1) := Socket_Img;
1640 Index := Index + Socket_Img'Length;
1641 end;
1642 end loop;
1643
1644 return "[" & Last_Img & "]" & Buffer (1 .. Index - 1);
1645 end;
1646 end Image;
1647
1648 ---------------
1649 -- Inet_Addr --
1650 ---------------
1651
1652 function Inet_Addr (Image : String) return Inet_Addr_Type is
1653 use Interfaces.C;
1654
1655 Img : aliased char_array := To_C (Image);
1656 Res : C.int;
1657 Result : Inet_Addr_Type;
1658 IPv6 : constant Boolean := Is_IPv6_Address (Image);
1659 Ia : aliased In_Addr_Union
1660 (if IPv6 then Family_Inet6 else Family_Inet);
1661 begin
1662 -- Special case for an empty Image as on some platforms (e.g. Windows)
1663 -- calling Inet_Addr("") will not return an error.
1664
1665 if Image = "" then
1666 Raise_Socket_Error (SOSC.EINVAL);
1667 end if;
1668
1669 Res := Inet_Pton
1670 ((if IPv6 then SOSC.AF_INET6 else SOSC.AF_INET), Img'Address,
1671 Ia'Address);
1672
1673 if Res < 0 then
1674 Raise_Socket_Error (Socket_Errno);
1675
1676 elsif Res = 0 then
1677 Raise_Socket_Error (SOSC.EINVAL);
1678 end if;
1679
1680 if IPv6 then
1681 To_Inet_Addr (Ia.In6, Result);
1682 else
1683 To_Inet_Addr (Ia.In4, Result);
1684 end if;
1685
1686 return Result;
1687 end Inet_Addr;
1688
1689 ----------------
1690 -- Initialize --
1691 ----------------
1692
1693 procedure Initialize (X : in out Sockets_Library_Controller) is
1694 pragma Unreferenced (X);
1695
1696 begin
1697 Thin.Initialize;
1698 end Initialize;
1699
1700 ----------------
1701 -- Initialize --
1702 ----------------
1703
1704 procedure Initialize (Process_Blocking_IO : Boolean) is
1705 Expected : constant Boolean := not SOSC.Thread_Blocking_IO;
1706
1707 begin
1708 if Process_Blocking_IO /= Expected then
1709 raise Socket_Error with
1710 "incorrect Process_Blocking_IO setting, expected " & Expected'Img;
1711 end if;
1712
1713 -- This is a dummy placeholder for an obsolete API
1714
1715 -- Real initialization actions are in Initialize primitive operation
1716 -- of Sockets_Library_Controller.
1717
1718 null;
1719 end Initialize;
1720
1721 ----------------
1722 -- Initialize --
1723 ----------------
1724
1725 procedure Initialize is
1726 begin
1727 -- This is a dummy placeholder for an obsolete API
1728
1729 -- Real initialization actions are in Initialize primitive operation
1730 -- of Sockets_Library_Controller.
1731
1732 null;
1733 end Initialize;
1734
1735 ----------------
1736 -- Is_Windows --
1737 ----------------
1738
1739 function Is_Windows return Boolean is
1740 use SOSC;
1741 begin
1742 return Target_OS = Windows;
1743 end Is_Windows;
1744
1745 --------------
1746 -- Is_Empty --
1747 --------------
1748
1749 function Is_Empty (Item : Socket_Set_Type) return Boolean is
1750 begin
1751 return Item.Last = No_Socket;
1752 end Is_Empty;
1753
1754 ---------------------
1755 -- Is_IPv6_Address --
1756 ---------------------
1757
1758 function Is_IPv6_Address (Name : String) return Boolean is
1759 Prev_Colon : Natural := 0;
1760 Double_Colon : Boolean := False;
1761 Colons : Natural := 0;
1762 begin
1763 for J in Name'Range loop
1764 if Name (J) = ':' then
1765 Colons := Colons + 1;
1766
1767 if Prev_Colon > 0 and then J = Prev_Colon + 1 then
1768 if Double_Colon then
1769 -- Only one double colon allowed
1770 return False;
1771 end if;
1772
1773 Double_Colon := True;
1774
1775 elsif J = Name'Last then
1776 -- Single colon at the end is not allowed
1777 return False;
1778 end if;
1779
1780 Prev_Colon := J;
1781
1782 elsif Prev_Colon = Name'First then
1783 -- Single colon at start is not allowed
1784 return False;
1785
1786 elsif Name (J) = '.' then
1787 return Prev_Colon > 0
1788 and then Is_IPv4_Address (Name (Prev_Colon + 1 .. Name'Last));
1789
1790 elsif Name (J) not in '0' .. '9' | 'A' .. 'F' | 'a' .. 'f' then
1791 return False;
1792
1793 end if;
1794 end loop;
1795
1796 return Colons <= 8;
1797 end Is_IPv6_Address;
1798
1799 ---------------------
1800 -- Is_IPv4_Address --
1801 ---------------------
1802
1803 function Is_IPv4_Address (Name : String) return Boolean is
1804 Dots : Natural := 0;
1805
1806 begin
1807 -- Perform a cursory check for a dotted quad: we must have 1 to 3 dots,
1808 -- and there must be at least one digit around each.
1809
1810 for J in Name'Range loop
1811 if Name (J) = '.' then
1812
1813 -- Check that the dot is not in first or last position, and that
1814 -- it is followed by a digit. Note that we already know that it is
1815 -- preceded by a digit, or we would have returned earlier on.
1816
1817 if J in Name'First + 1 .. Name'Last - 1
1818 and then Name (J + 1) in '0' .. '9'
1819 then
1820 Dots := Dots + 1;
1821
1822 -- Definitely not a proper dotted quad
1823
1824 else
1825 return False;
1826 end if;
1827
1828 elsif Name (J) not in '0' .. '9' then
1829 return False;
1830 end if;
1831 end loop;
1832
1833 return Dots in 1 .. 3;
1834 end Is_IPv4_Address;
1835
1836 -------------
1837 -- Is_Open --
1838 -------------
1839
1840 function Is_Open (S : Selector_Type) return Boolean is
1841 begin
1842 if S.Is_Null then
1843 return True;
1844
1845 else
1846 -- Either both controlling socket descriptors are valid (case of an
1847 -- open selector) or neither (case of a closed selector).
1848
1849 pragma Assert ((S.R_Sig_Socket /= No_Socket)
1850 =
1851 (S.W_Sig_Socket /= No_Socket));
1852
1853 return S.R_Sig_Socket /= No_Socket;
1854 end if;
1855 end Is_Open;
1856
1857 ------------
1858 -- Is_Set --
1859 ------------
1860
1861 function Is_Set
1862 (Item : Socket_Set_Type;
1863 Socket : Socket_Type) return Boolean
1864 is
1865 begin
1866 Check_For_Fd_Set (Socket);
1867
1868 return Item.Last /= No_Socket
1869 and then Socket <= Item.Last
1870 and then Is_Socket_In_Set (Item.Set'Access, C.int (Socket)) /= 0;
1871 end Is_Set;
1872
1873 -------------------
1874 -- Listen_Socket --
1875 -------------------
1876
1877 procedure Listen_Socket
1878 (Socket : Socket_Type;
1879 Length : Natural := 15)
1880 is
1881 Res : constant C.int := C_Listen (C.int (Socket), C.int (Length));
1882 begin
1883 if Res = Failure then
1884 Raise_Socket_Error (Socket_Errno);
1885 end if;
1886 end Listen_Socket;
1887
1888 ------------
1889 -- Narrow --
1890 ------------
1891
1892 procedure Narrow (Item : in out Socket_Set_Type) is
1893 Last : aliased C.int := C.int (Item.Last);
1894 begin
1895 if Item.Last /= No_Socket then
1896 Last_Socket_In_Set (Item.Set'Access, Last'Unchecked_Access);
1897 Item.Last := Socket_Type (Last);
1898 end if;
1899 end Narrow;
1900
1901 ----------------
1902 -- Netdb_Lock --
1903 ----------------
1904
1905 procedure Netdb_Lock is
1906 begin
1907 if Need_Netdb_Lock then
1908 System.Task_Lock.Lock;
1909 end if;
1910 end Netdb_Lock;
1911
1912 ------------------
1913 -- Netdb_Unlock --
1914 ------------------
1915
1916 procedure Netdb_Unlock is
1917 begin
1918 if Need_Netdb_Lock then
1919 System.Task_Lock.Unlock;
1920 end if;
1921 end Netdb_Unlock;
1922
1923 --------------------------------
1924 -- Normalize_Empty_Socket_Set --
1925 --------------------------------
1926
1927 procedure Normalize_Empty_Socket_Set (S : in out Socket_Set_Type) is
1928 begin
1929 if S.Last = No_Socket then
1930 Reset_Socket_Set (S.Set'Access);
1931 end if;
1932 end Normalize_Empty_Socket_Set;
1933
1934 -------------------
1935 -- Official_Name --
1936 -------------------
1937
1938 function Official_Name (E : Host_Entry_Type) return String is
1939 begin
1940 return To_String (E.Official);
1941 end Official_Name;
1942
1943 -------------------
1944 -- Official_Name --
1945 -------------------
1946
1947 function Official_Name (S : Service_Entry_Type) return String is
1948 begin
1949 return To_String (S.Official);
1950 end Official_Name;
1951
1952 --------------------
1953 -- Wait_On_Socket --
1954 --------------------
1955
1956 procedure Wait_On_Socket
1957 (Socket : Socket_Type;
1958 For_Read : Boolean;
1959 Timeout : Selector_Duration;
1960 Selector : access Selector_Type := null;
1961 Status : out Selector_Status)
1962 is
1963 type Local_Selector_Access is access Selector_Type;
1964 for Local_Selector_Access'Storage_Size use Selector_Type'Size;
1965
1966 S : Selector_Access;
1967 -- Selector to use for waiting
1968
1969 R_Fd_Set : Socket_Set_Type;
1970 W_Fd_Set : Socket_Set_Type;
1971
1972 begin
1973 -- Create selector if not provided by the user
1974
1975 if Selector = null then
1976 declare
1977 Local_S : constant Local_Selector_Access := new Selector_Type;
1978 begin
1979 S := Local_S.all'Unchecked_Access;
1980 Create_Selector (S.all);
1981 end;
1982
1983 else
1984 S := Selector.all'Access;
1985 end if;
1986
1987 if For_Read then
1988 Set (R_Fd_Set, Socket);
1989 else
1990 Set (W_Fd_Set, Socket);
1991 end if;
1992
1993 Check_Selector (S.all, R_Fd_Set, W_Fd_Set, Status, Timeout);
1994
1995 if Selector = null then
1996 Close_Selector (S.all);
1997 end if;
1998 end Wait_On_Socket;
1999
2000 -----------------
2001 -- Port_Number --
2002 -----------------
2003
2004 function Port_Number (S : Service_Entry_Type) return Port_Type is
2005 begin
2006 return S.Port;
2007 end Port_Number;
2008
2009 -------------------
2010 -- Protocol_Name --
2011 -------------------
2012
2013 function Protocol_Name (S : Service_Entry_Type) return String is
2014 begin
2015 return To_String (S.Protocol);
2016 end Protocol_Name;
2017
2018 ----------------------
2019 -- Raise_Host_Error --
2020 ----------------------
2021
2022 procedure Raise_Host_Error (H_Error : Integer; Name : String) is
2023 begin
2024 raise Host_Error with
2025 Err_Code_Image (H_Error)
2026 & Dedot (Host_Error_Messages.Host_Error_Message (H_Error))
2027 & ": " & Name;
2028 end Raise_Host_Error;
2029
2030 ------------------------
2031 -- Raise_Socket_Error --
2032 ------------------------
2033
2034 procedure Raise_Socket_Error (Error : Integer) is
2035 begin
2036 raise Socket_Error with
2037 Err_Code_Image (Error) & Socket_Error_Message (Error);
2038 end Raise_Socket_Error;
2039
2040 ----------
2041 -- Read --
2042 ----------
2043
2044 procedure Read
2045 (Stream : in out Datagram_Socket_Stream_Type;
2046 Item : out Ada.Streams.Stream_Element_Array;
2047 Last : out Ada.Streams.Stream_Element_Offset)
2048 is
2049 begin
2050 Receive_Socket
2051 (Stream.Socket,
2052 Item,
2053 Last,
2054 Stream.From);
2055 end Read;
2056
2057 ----------
2058 -- Read --
2059 ----------
2060
2061 procedure Read
2062 (Stream : in out Stream_Socket_Stream_Type;
2063 Item : out Ada.Streams.Stream_Element_Array;
2064 Last : out Ada.Streams.Stream_Element_Offset)
2065 is
2066 First : Ada.Streams.Stream_Element_Offset := Item'First;
2067 Index : Ada.Streams.Stream_Element_Offset := First - 1;
2068 Max : constant Ada.Streams.Stream_Element_Offset := Item'Last;
2069
2070 begin
2071 loop
2072 Receive_Socket (Stream.Socket, Item (First .. Max), Index);
2073 Last := Index;
2074
2075 -- Exit when all or zero data received. Zero means that the socket
2076 -- peer is closed.
2077
2078 exit when Index < First or else Index = Max;
2079
2080 First := Index + 1;
2081 end loop;
2082 end Read;
2083
2084 --------------------
2085 -- Receive_Socket --
2086 --------------------
2087
2088 procedure Receive_Socket
2089 (Socket : Socket_Type;
2090 Item : out Ada.Streams.Stream_Element_Array;
2091 Last : out Ada.Streams.Stream_Element_Offset;
2092 Flags : Request_Flag_Type := No_Request_Flag)
2093 is
2094 Res : C.int;
2095
2096 begin
2097 Res :=
2098 C_Recv (C.int (Socket), Item'Address, Item'Length, To_Int (Flags));
2099
2100 if Res = Failure then
2101 Raise_Socket_Error (Socket_Errno);
2102 end if;
2103
2104 Last := Last_Index (First => Item'First, Count => size_t (Res));
2105 end Receive_Socket;
2106
2107 --------------------
2108 -- Receive_Socket --
2109 --------------------
2110
2111 procedure Receive_Socket
2112 (Socket : Socket_Type;
2113 Item : out Ada.Streams.Stream_Element_Array;
2114 Last : out Ada.Streams.Stream_Element_Offset;
2115 From : out Sock_Addr_Type;
2116 Flags : Request_Flag_Type := No_Request_Flag)
2117 is
2118 Res : C.int;
2119 Sin : aliased Sockaddr;
2120 Len : aliased C.int := Sin'Size / 8;
2121
2122 begin
2123 Res :=
2124 C_Recvfrom
2125 (C.int (Socket),
2126 Item'Address,
2127 Item'Length,
2128 To_Int (Flags),
2129 Sin'Address,
2130 Len'Access);
2131
2132 if Res = Failure then
2133 Raise_Socket_Error (Socket_Errno);
2134 end if;
2135
2136 Last := Last_Index (First => Item'First, Count => size_t (Res));
2137
2138 From := Get_Address (Sin);
2139 end Receive_Socket;
2140
2141 --------------------
2142 -- Receive_Vector --
2143 --------------------
2144
2145 procedure Receive_Vector
2146 (Socket : Socket_Type;
2147 Vector : Vector_Type;
2148 Count : out Ada.Streams.Stream_Element_Count;
2149 Flags : Request_Flag_Type := No_Request_Flag)
2150 is
2151 Res : ssize_t;
2152
2153 Msg : Msghdr :=
2154 (Msg_Name => System.Null_Address,
2155 Msg_Namelen => 0,
2156 Msg_Iov => Vector'Address,
2157
2158 -- recvmsg(2) returns EMSGSIZE on Linux (and probably on other
2159 -- platforms) when the supplied vector is longer than IOV_MAX,
2160 -- so use minimum of the two lengths.
2161
2162 Msg_Iovlen => SOSC.Msg_Iovlen_T'Min
2163 (Vector'Length, SOSC.IOV_MAX),
2164
2165 Msg_Control => System.Null_Address,
2166 Msg_Controllen => 0,
2167 Msg_Flags => 0);
2168
2169 begin
2170 Res :=
2171 C_Recvmsg
2172 (C.int (Socket),
2173 Msg'Address,
2174 To_Int (Flags));
2175
2176 if Res = ssize_t (Failure) then
2177 Raise_Socket_Error (Socket_Errno);
2178 end if;
2179
2180 Count := Ada.Streams.Stream_Element_Count (Res);
2181 end Receive_Vector;
2182
2183 -------------------
2184 -- Resolve_Error --
2185 -------------------
2186
2187 function Resolve_Error
2188 (Error_Value : Integer;
2189 From_Errno : Boolean := True) return Error_Type
2190 is
2191 use GNAT.Sockets.SOSC;
2192
2193 begin
2194 if not From_Errno then
2195 case Error_Value is
2196 when SOSC.HOST_NOT_FOUND => return Unknown_Host;
2197 when SOSC.TRY_AGAIN => return Host_Name_Lookup_Failure;
2198 when SOSC.NO_RECOVERY => return Non_Recoverable_Error;
2199 when SOSC.NO_DATA => return Unknown_Server_Error;
2200 when others => return Cannot_Resolve_Error;
2201 end case;
2202 end if;
2203
2204 -- Special case: EAGAIN may be the same value as EWOULDBLOCK, so we
2205 -- can't include it in the case statement below.
2206
2207 pragma Warnings (Off);
2208 -- Condition "EAGAIN /= EWOULDBLOCK" is known at compile time
2209
2210 if EAGAIN /= EWOULDBLOCK and then Error_Value = EAGAIN then
2211 return Resource_Temporarily_Unavailable;
2212 end if;
2213
2214 -- This is not a case statement because if a particular error
2215 -- number constant is not defined, s-oscons-tmplt.c defines
2216 -- it to -1. If multiple constants are not defined, they
2217 -- would each be -1 and result in a "duplicate value in case" error.
2218 --
2219 -- But we have to leave warnings off because the compiler is also
2220 -- smart enough to note that when two errnos have the same value,
2221 -- the second if condition is useless.
2222 if Error_Value = ENOERROR then
2223 return Success;
2224 elsif Error_Value = EACCES then
2225 return Permission_Denied;
2226 elsif Error_Value = EADDRINUSE then
2227 return Address_Already_In_Use;
2228 elsif Error_Value = EADDRNOTAVAIL then
2229 return Cannot_Assign_Requested_Address;
2230 elsif Error_Value = EAFNOSUPPORT then
2231 return Address_Family_Not_Supported_By_Protocol;
2232 elsif Error_Value = EALREADY then
2233 return Operation_Already_In_Progress;
2234 elsif Error_Value = EBADF then
2235 return Bad_File_Descriptor;
2236 elsif Error_Value = ECONNABORTED then
2237 return Software_Caused_Connection_Abort;
2238 elsif Error_Value = ECONNREFUSED then
2239 return Connection_Refused;
2240 elsif Error_Value = ECONNRESET then
2241 return Connection_Reset_By_Peer;
2242 elsif Error_Value = EDESTADDRREQ then
2243 return Destination_Address_Required;
2244 elsif Error_Value = EFAULT then
2245 return Bad_Address;
2246 elsif Error_Value = EHOSTDOWN then
2247 return Host_Is_Down;
2248 elsif Error_Value = EHOSTUNREACH then
2249 return No_Route_To_Host;
2250 elsif Error_Value = EINPROGRESS then
2251 return Operation_Now_In_Progress;
2252 elsif Error_Value = EINTR then
2253 return Interrupted_System_Call;
2254 elsif Error_Value = EINVAL then
2255 return Invalid_Argument;
2256 elsif Error_Value = EIO then
2257 return Input_Output_Error;
2258 elsif Error_Value = EISCONN then
2259 return Transport_Endpoint_Already_Connected;
2260 elsif Error_Value = ELOOP then
2261 return Too_Many_Symbolic_Links;
2262 elsif Error_Value = EMFILE then
2263 return Too_Many_Open_Files;
2264 elsif Error_Value = EMSGSIZE then
2265 return Message_Too_Long;
2266 elsif Error_Value = ENAMETOOLONG then
2267 return File_Name_Too_Long;
2268 elsif Error_Value = ENETDOWN then
2269 return Network_Is_Down;
2270 elsif Error_Value = ENETRESET then
2271 return Network_Dropped_Connection_Because_Of_Reset;
2272 elsif Error_Value = ENETUNREACH then
2273 return Network_Is_Unreachable;
2274 elsif Error_Value = ENOBUFS then
2275 return No_Buffer_Space_Available;
2276 elsif Error_Value = ENOPROTOOPT then
2277 return Protocol_Not_Available;
2278 elsif Error_Value = ENOTCONN then
2279 return Transport_Endpoint_Not_Connected;
2280 elsif Error_Value = ENOTSOCK then
2281 return Socket_Operation_On_Non_Socket;
2282 elsif Error_Value = EOPNOTSUPP then
2283 return Operation_Not_Supported;
2284 elsif Error_Value = EPFNOSUPPORT then
2285 return Protocol_Family_Not_Supported;
2286 elsif Error_Value = EPIPE then
2287 return Broken_Pipe;
2288 elsif Error_Value = EPROTONOSUPPORT then
2289 return Protocol_Not_Supported;
2290 elsif Error_Value = EPROTOTYPE then
2291 return Protocol_Wrong_Type_For_Socket;
2292 elsif Error_Value = ESHUTDOWN then
2293 return Cannot_Send_After_Transport_Endpoint_Shutdown;
2294 elsif Error_Value = ESOCKTNOSUPPORT then
2295 return Socket_Type_Not_Supported;
2296 elsif Error_Value = ETIMEDOUT then
2297 return Connection_Timed_Out;
2298 elsif Error_Value = ETOOMANYREFS then
2299 return Too_Many_References;
2300 elsif Error_Value = EWOULDBLOCK then
2301 return Resource_Temporarily_Unavailable;
2302 else
2303 return Cannot_Resolve_Error;
2304 end if;
2305 pragma Warnings (On);
2306
2307 end Resolve_Error;
2308
2309 -----------------------
2310 -- Resolve_Exception --
2311 -----------------------
2312
2313 function Resolve_Exception
2314 (Occurrence : Exception_Occurrence) return Error_Type
2315 is
2316 Id : constant Exception_Id := Exception_Identity (Occurrence);
2317 Msg : constant String := Exception_Message (Occurrence);
2318 First : Natural;
2319 Last : Natural;
2320 Val : Integer;
2321
2322 begin
2323 First := Msg'First;
2324 while First <= Msg'Last
2325 and then Msg (First) not in '0' .. '9'
2326 loop
2327 First := First + 1;
2328 end loop;
2329
2330 if First > Msg'Last then
2331 return Cannot_Resolve_Error;
2332 end if;
2333
2334 Last := First;
2335 while Last < Msg'Last
2336 and then Msg (Last + 1) in '0' .. '9'
2337 loop
2338 Last := Last + 1;
2339 end loop;
2340
2341 Val := Integer'Value (Msg (First .. Last));
2342
2343 if Id = Socket_Error_Id then
2344 return Resolve_Error (Val);
2345
2346 elsif Id = Host_Error_Id then
2347 return Resolve_Error (Val, False);
2348
2349 else
2350 return Cannot_Resolve_Error;
2351 end if;
2352 end Resolve_Exception;
2353
2354 -----------------
2355 -- Send_Socket --
2356 -----------------
2357
2358 procedure Send_Socket
2359 (Socket : Socket_Type;
2360 Item : Ada.Streams.Stream_Element_Array;
2361 Last : out Ada.Streams.Stream_Element_Offset;
2362 Flags : Request_Flag_Type := No_Request_Flag)
2363 is
2364 begin
2365 Send_Socket (Socket, Item, Last, To => null, Flags => Flags);
2366 end Send_Socket;
2367
2368 -----------------
2369 -- Send_Socket --
2370 -----------------
2371
2372 procedure Send_Socket
2373 (Socket : Socket_Type;
2374 Item : Ada.Streams.Stream_Element_Array;
2375 Last : out Ada.Streams.Stream_Element_Offset;
2376 To : Sock_Addr_Type;
2377 Flags : Request_Flag_Type := No_Request_Flag)
2378 is
2379 begin
2380 Send_Socket
2381 (Socket, Item, Last, To => To'Unrestricted_Access, Flags => Flags);
2382 end Send_Socket;
2383
2384 -----------------
2385 -- Send_Socket --
2386 -----------------
2387
2388 procedure Send_Socket
2389 (Socket : Socket_Type;
2390 Item : Ada.Streams.Stream_Element_Array;
2391 Last : out Ada.Streams.Stream_Element_Offset;
2392 To : access Sock_Addr_Type;
2393 Flags : Request_Flag_Type := No_Request_Flag)
2394 is
2395 Res : C.int;
2396
2397 Sin : aliased Sockaddr;
2398 C_To : System.Address;
2399 Len : C.int;
2400
2401 begin
2402 if To /= null then
2403 Set_Address (Sin'Unchecked_Access, To.all);
2404 C_To := Sin'Address;
2405 Len := C.int (Thin_Common.Lengths (To.Family));
2406
2407 else
2408 C_To := System.Null_Address;
2409 Len := 0;
2410 end if;
2411
2412 Res := C_Sendto
2413 (C.int (Socket),
2414 Item'Address,
2415 Item'Length,
2416 Set_Forced_Flags (To_Int (Flags)),
2417 C_To,
2418 Len);
2419
2420 if Res = Failure then
2421 Raise_Socket_Error (Socket_Errno);
2422 end if;
2423
2424 Last := Last_Index (First => Item'First, Count => size_t (Res));
2425 end Send_Socket;
2426
2427 -----------------
2428 -- Send_Vector --
2429 -----------------
2430
2431 procedure Send_Vector
2432 (Socket : Socket_Type;
2433 Vector : Vector_Type;
2434 Count : out Ada.Streams.Stream_Element_Count;
2435 Flags : Request_Flag_Type := No_Request_Flag)
2436 is
2437 use Interfaces.C;
2438
2439 Res : ssize_t;
2440 Iov_Count : SOSC.Msg_Iovlen_T;
2441 This_Iov_Count : SOSC.Msg_Iovlen_T;
2442 Msg : Msghdr;
2443
2444 begin
2445 Count := 0;
2446 Iov_Count := 0;
2447 while Iov_Count < Vector'Length loop
2448
2449 pragma Warnings (Off);
2450 -- Following test may be compile time known on some targets
2451
2452 This_Iov_Count :=
2453 (if Vector'Length - Iov_Count > SOSC.IOV_MAX
2454 then SOSC.IOV_MAX
2455 else Vector'Length - Iov_Count);
2456
2457 pragma Warnings (On);
2458
2459 Msg :=
2460 (Msg_Name => System.Null_Address,
2461 Msg_Namelen => 0,
2462 Msg_Iov => Vector
2463 (Vector'First + Integer (Iov_Count))'Address,
2464 Msg_Iovlen => This_Iov_Count,
2465 Msg_Control => System.Null_Address,
2466 Msg_Controllen => 0,
2467 Msg_Flags => 0);
2468
2469 Res :=
2470 C_Sendmsg
2471 (C.int (Socket),
2472 Msg'Address,
2473 Set_Forced_Flags (To_Int (Flags)));
2474
2475 if Res = ssize_t (Failure) then
2476 Raise_Socket_Error (Socket_Errno);
2477 end if;
2478
2479 Count := Count + Ada.Streams.Stream_Element_Count (Res);
2480 Iov_Count := Iov_Count + This_Iov_Count;
2481 end loop;
2482 end Send_Vector;
2483
2484 ---------
2485 -- Set --
2486 ---------
2487
2488 procedure Set (Item : in out Socket_Set_Type; Socket : Socket_Type) is
2489 begin
2490 Check_For_Fd_Set (Socket);
2491
2492 if Item.Last = No_Socket then
2493
2494 -- Uninitialized socket set, make sure it is properly zeroed out
2495
2496 Reset_Socket_Set (Item.Set'Access);
2497 Item.Last := Socket;
2498
2499 elsif Item.Last < Socket then
2500 Item.Last := Socket;
2501 end if;
2502
2503 Insert_Socket_In_Set (Item.Set'Access, C.int (Socket));
2504 end Set;
2505
2506 -----------------------
2507 -- Set_Close_On_Exec --
2508 -----------------------
2509
2510 procedure Set_Close_On_Exec
2511 (Socket : Socket_Type;
2512 Close_On_Exec : Boolean;
2513 Status : out Boolean)
2514 is
2515 function C_Set_Close_On_Exec
2516 (Socket : Socket_Type; Close_On_Exec : C.int) return C.int;
2517 pragma Import (C, C_Set_Close_On_Exec, "__gnat_set_close_on_exec");
2518 begin
2519 Status := C_Set_Close_On_Exec (Socket, Boolean'Pos (Close_On_Exec)) = 0;
2520 end Set_Close_On_Exec;
2521
2522 ----------------------
2523 -- Set_Forced_Flags --
2524 ----------------------
2525
2526 function Set_Forced_Flags (F : C.int) return C.int is
2527 use type C.unsigned;
2528 function To_unsigned is
2529 new Ada.Unchecked_Conversion (C.int, C.unsigned);
2530 function To_int is
2531 new Ada.Unchecked_Conversion (C.unsigned, C.int);
2532 begin
2533 return To_int (To_unsigned (F) or SOSC.MSG_Forced_Flags);
2534 end Set_Forced_Flags;
2535
2536 -----------------------
2537 -- Set_Socket_Option --
2538 -----------------------
2539
2540 procedure Set_Socket_Option
2541 (Socket : Socket_Type;
2542 Level : Level_Type := Socket_Level;
2543 Option : Option_Type)
2544 is
2545 use type C.unsigned;
2546
2547 MR : aliased IPV6_Mreq;
2548 V8 : aliased Two_Ints;
2549 V4 : aliased C.int;
2550 U4 : aliased C.unsigned;
2551 V1 : aliased C.unsigned_char;
2552 VT : aliased Timeval;
2553 Len : C.int;
2554 Add : System.Address := Null_Address;
2555 Res : C.int;
2556 Onm : C.int;
2557
2558 begin
2559 case Option.Name is
2560 when Generic_Option =>
2561 V4 := Option.Optval;
2562 Len := V4'Size / 8;
2563 Add := V4'Address;
2564
2565 when Broadcast
2566 | Keep_Alive
2567 | No_Delay
2568 | Reuse_Address
2569 | Multicast_Loop_V4
2570 | Multicast_Loop_V6
2571 | IPv6_Only
2572 =>
2573 V4 := C.int (Boolean'Pos (Option.Enabled));
2574 Len := V4'Size / 8;
2575 Add := V4'Address;
2576
2577 when Busy_Polling =>
2578 V4 := C.int (Option.Microseconds);
2579 Len := V4'Size / 8;
2580 Add := V4'Address;
2581
2582 when Linger =>
2583 V8 (V8'First) := C.int (Boolean'Pos (Option.Enabled));
2584 V8 (V8'Last) := C.int (Option.Seconds);
2585 Len := V8'Size / 8;
2586 Add := V8'Address;
2587
2588 when Receive_Buffer
2589 | Send_Buffer
2590 =>
2591 V4 := C.int (Option.Size);
2592 Len := V4'Size / 8;
2593 Add := V4'Address;
2594
2595 when Error =>
2596 V4 := C.int (Boolean'Pos (True));
2597 Len := V4'Size / 8;
2598 Add := V4'Address;
2599
2600 when Add_Membership_V4
2601 | Drop_Membership_V4
2602 =>
2603 V8 (V8'First) := To_Int (To_In_Addr (Option.Multicast_Address));
2604 V8 (V8'Last) := To_Int (To_In_Addr (Option.Local_Interface));
2605 Len := V8'Size / 8;
2606 Add := V8'Address;
2607
2608 when Add_Membership_V6
2609 | Drop_Membership_V6 =>
2610 MR.ipv6mr_multiaddr := To_In6_Addr (Option.Multicast_Address);
2611 MR.ipv6mr_interface := C.unsigned (Option.Interface_Index);
2612 Len := MR'Size / 8;
2613 Add := MR'Address;
2614
2615 when Multicast_If_V4 =>
2616 V4 := To_Int (To_In_Addr (Option.Outgoing_If));
2617 Len := V4'Size / 8;
2618 Add := V4'Address;
2619
2620 when Multicast_If_V6 =>
2621 V4 := C.int (Option.Outgoing_If_Index);
2622 Len := V4'Size / 8;
2623 Add := V4'Address;
2624
2625 when Multicast_TTL =>
2626 V1 := C.unsigned_char (Option.Time_To_Live);
2627 Len := V1'Size / 8;
2628 Add := V1'Address;
2629
2630 when Multicast_Hops =>
2631 V4 := C.int (Option.Hop_Limit);
2632 Len := V4'Size / 8;
2633 Add := V4'Address;
2634
2635 when Receive_Packet_Info
2636 =>
2637 V1 := C.unsigned_char (Boolean'Pos (Option.Enabled));
2638 Len := V1'Size / 8;
2639 Add := V1'Address;
2640
2641 when Receive_Timeout
2642 | Send_Timeout
2643 =>
2644 if Is_Windows then
2645
2646 -- On Windows, the timeout is a DWORD in milliseconds, and
2647 -- the actual timeout is 500 ms + the given value (unless it
2648 -- is 0).
2649
2650 U4 := C.unsigned (Option.Timeout / 0.001);
2651
2652 if U4 > 500 then
2653 U4 := U4 - 500;
2654
2655 elsif U4 > 0 then
2656 U4 := 1;
2657 end if;
2658
2659 Len := U4'Size / 8;
2660 Add := U4'Address;
2661
2662 else
2663 VT := To_Timeval (Option.Timeout);
2664 Len := VT'Size / 8;
2665 Add := VT'Address;
2666 end if;
2667 end case;
2668
2669 if Option.Name in Specific_Option_Name then
2670 Onm := Options (Option.Name);
2671
2672 elsif Option.Optname = -1 then
2673 raise Socket_Error with "optname must be specified";
2674
2675 else
2676 Onm := Option.Optname;
2677 end if;
2678
2679 Res := C_Setsockopt
2680 (C.int (Socket),
2681 Levels (Level),
2682 Onm,
2683 Add, Len);
2684
2685 if Res = Failure then
2686 Raise_Socket_Error (Socket_Errno);
2687 end if;
2688 end Set_Socket_Option;
2689
2690 ---------------------
2691 -- Shutdown_Socket --
2692 ---------------------
2693
2694 procedure Shutdown_Socket
2695 (Socket : Socket_Type;
2696 How : Shutmode_Type := Shut_Read_Write)
2697 is
2698 Res : C.int;
2699
2700 begin
2701 Res := C_Shutdown (C.int (Socket), Shutmodes (How));
2702
2703 if Res = Failure then
2704 Raise_Socket_Error (Socket_Errno);
2705 end if;
2706 end Shutdown_Socket;
2707
2708 ------------
2709 -- Stream --
2710 ------------
2711
2712 function Stream
2713 (Socket : Socket_Type;
2714 Send_To : Sock_Addr_Type) return Stream_Access
2715 is
2716 S : Datagram_Socket_Stream_Access;
2717
2718 begin
2719 S := new Datagram_Socket_Stream_Type;
2720 S.Socket := Socket;
2721 S.To := Send_To;
2722 S.From := Get_Socket_Name (Socket);
2723 return Stream_Access (S);
2724 end Stream;
2725
2726 ------------
2727 -- Stream --
2728 ------------
2729
2730 function Stream (Socket : Socket_Type) return Stream_Access is
2731 S : Stream_Socket_Stream_Access;
2732 begin
2733 S := new Stream_Socket_Stream_Type;
2734 S.Socket := Socket;
2735 return Stream_Access (S);
2736 end Stream;
2737
2738 ------------
2739 -- To_Ada --
2740 ------------
2741
2742 function To_Ada (Fd : Integer) return Socket_Type is
2743 begin
2744 return Socket_Type (Fd);
2745 end To_Ada;
2746
2747 ----------
2748 -- To_C --
2749 ----------
2750
2751 function To_C (Socket : Socket_Type) return Integer is
2752 begin
2753 return Integer (Socket);
2754 end To_C;
2755
2756 -----------------
2757 -- To_Duration --
2758 -----------------
2759
2760 function To_Duration (Val : Timeval) return Timeval_Duration is
2761 Max_D : constant Long_Long_Integer := Long_Long_Integer (Forever - 0.5);
2762 Tv_sec_64 : constant Boolean := SOSC.SIZEOF_tv_sec = 8;
2763 -- Need to separate this condition into the constant declaration to
2764 -- avoid GNAT warning about "always true" or "always false".
2765 begin
2766 if Tv_sec_64 then
2767 -- Check for possible Duration overflow when Tv_Sec field is 64 bit
2768 -- integer.
2769
2770 if Val.Tv_Sec > time_t (Max_D) or else
2771 (Val.Tv_Sec = time_t (Max_D) and then
2772 Val.Tv_Usec > suseconds_t ((Forever - Duration (Max_D)) * 1E6))
2773 then
2774 return Forever;
2775 end if;
2776 end if;
2777
2778 return Duration (Val.Tv_Sec) + Duration (Val.Tv_Usec) * 1.0E-6;
2779 end To_Duration;
2780
2781 -------------------
2782 -- To_Host_Entry --
2783 -------------------
2784
2785 function To_Host_Entry (E : Hostent_Access) return Host_Entry_Type is
2786 Aliases_Count, Addresses_Count : Natural;
2787
2788 Family : constant Family_Type :=
2789 (case Hostent_H_Addrtype (E) is
2790 when SOSC.AF_INET => Family_Inet,
2791 when SOSC.AF_INET6 => Family_Inet6,
2792 when others => Family_Unspec);
2793
2794 Addr_Len : constant C.size_t := C.size_t (Hostent_H_Length (E));
2795
2796 begin
2797 if Family = Family_Unspec then
2798 Raise_Socket_Error (SOSC.EPFNOSUPPORT);
2799 end if;
2800
2801 Aliases_Count := 0;
2802 while Hostent_H_Alias (E, C.int (Aliases_Count)) /= Null_Address loop
2803 Aliases_Count := Aliases_Count + 1;
2804 end loop;
2805
2806 Addresses_Count := 0;
2807 while Hostent_H_Addr (E, C.int (Addresses_Count)) /= Null_Address loop
2808 Addresses_Count := Addresses_Count + 1;
2809 end loop;
2810
2811 return Result : Host_Entry_Type
2812 (Aliases_Length => Aliases_Count,
2813 Addresses_Length => Addresses_Count)
2814 do
2815 Result.Official := To_Name (Value (Hostent_H_Name (E)));
2816
2817 for J in Result.Aliases'Range loop
2818 Result.Aliases (J) :=
2819 To_Name (Value (Hostent_H_Alias
2820 (E, C.int (J - Result.Aliases'First))));
2821 end loop;
2822
2823 for J in Result.Addresses'Range loop
2824 declare
2825 Ia : In_Addr_Union (Family);
2826
2827 -- Hostent_H_Addr (E, <index>) may return an address that is
2828 -- not correctly aligned for In_Addr, so we need to use
2829 -- an intermediate copy operation on a type with an alignment
2830 -- of 1 to recover the value.
2831
2832 subtype Addr_Buf_T is C.char_array (1 .. Addr_Len);
2833 Unaligned_Addr : Addr_Buf_T;
2834 for Unaligned_Addr'Address
2835 use Hostent_H_Addr (E, C.int (J - Result.Addresses'First));
2836 pragma Import (Ada, Unaligned_Addr);
2837
2838 Aligned_Addr : Addr_Buf_T;
2839 for Aligned_Addr'Address use Ia'Address;
2840 pragma Import (Ada, Aligned_Addr);
2841
2842 begin
2843 Aligned_Addr := Unaligned_Addr;
2844 if Family = Family_Inet6 then
2845 To_Inet_Addr (Ia.In6, Result.Addresses (J));
2846 else
2847 To_Inet_Addr (Ia.In4, Result.Addresses (J));
2848 end if;
2849 end;
2850 end loop;
2851 end return;
2852 end To_Host_Entry;
2853
2854 ------------
2855 -- To_Int --
2856 ------------
2857
2858 function To_Int (F : Request_Flag_Type) return C.int
2859 is
2860 Current : Request_Flag_Type := F;
2861 Result : C.int := 0;
2862
2863 begin
2864 for J in Flags'Range loop
2865 exit when Current = 0;
2866
2867 if Current mod 2 /= 0 then
2868 if Flags (J) = -1 then
2869 Raise_Socket_Error (SOSC.EOPNOTSUPP);
2870 end if;
2871
2872 Result := Result + Flags (J);
2873 end if;
2874
2875 Current := Current / 2;
2876 end loop;
2877
2878 return Result;
2879 end To_Int;
2880
2881 -------------
2882 -- To_Name --
2883 -------------
2884
2885 function To_Name (N : String) return Name_Type is
2886 begin
2887 return Name_Type'(N'Length, N);
2888 end To_Name;
2889
2890 ----------------------
2891 -- To_Service_Entry --
2892 ----------------------
2893
2894 function To_Service_Entry (E : Servent_Access) return Service_Entry_Type is
2895 Aliases_Count : Natural;
2896
2897 begin
2898 Aliases_Count := 0;
2899 while Servent_S_Alias (E, C.int (Aliases_Count)) /= Null_Address loop
2900 Aliases_Count := Aliases_Count + 1;
2901 end loop;
2902
2903 return Result : Service_Entry_Type (Aliases_Length => Aliases_Count) do
2904 Result.Official := To_Name (Value (Servent_S_Name (E)));
2905
2906 for J in Result.Aliases'Range loop
2907 Result.Aliases (J) :=
2908 To_Name (Value (Servent_S_Alias
2909 (E, C.int (J - Result.Aliases'First))));
2910 end loop;
2911
2912 Result.Protocol := To_Name (Value (Servent_S_Proto (E)));
2913 Result.Port :=
2914 Port_Type (Network_To_Short (Servent_S_Port (E)));
2915 end return;
2916 end To_Service_Entry;
2917
2918 ---------------
2919 -- To_String --
2920 ---------------
2921
2922 function To_String (HN : Name_Type) return String is
2923 begin
2924 return HN.Name (1 .. HN.Length);
2925 end To_String;
2926
2927 ----------------
2928 -- To_Timeval --
2929 ----------------
2930
2931 function To_Timeval (Val : Timeval_Duration) return Timeval is
2932 S : time_t;
2933 uS : suseconds_t;
2934
2935 begin
2936 -- If zero, set result as zero (otherwise it gets rounded down to -1)
2937
2938 if Val = 0.0 then
2939 S := 0;
2940 uS := 0;
2941
2942 -- Normal case where we do round down
2943
2944 else
2945 S := time_t (Val - 0.5);
2946 uS := suseconds_t (1_000_000 * (Val - Selector_Duration (S)) - 0.5);
2947
2948 if uS = -1 then
2949 -- It happen on integer duration
2950 uS := 0;
2951 end if;
2952 end if;
2953
2954 return (S, uS);
2955 end To_Timeval;
2956
2957 -----------
2958 -- Value --
2959 -----------
2960
2961 function Value (S : System.Address) return String is
2962 Str : String (1 .. Positive'Last);
2963 for Str'Address use S;
2964 pragma Import (Ada, Str);
2965
2966 Terminator : Positive := Str'First;
2967
2968 begin
2969 while Str (Terminator) /= ASCII.NUL loop
2970 Terminator := Terminator + 1;
2971 end loop;
2972
2973 return Str (1 .. Terminator - 1);
2974 end Value;
2975
2976 -----------
2977 -- Write --
2978 -----------
2979
2980 procedure Write
2981 (Stream : in out Datagram_Socket_Stream_Type;
2982 Item : Ada.Streams.Stream_Element_Array)
2983 is
2984 Last : Stream_Element_Offset;
2985
2986 begin
2987 Send_Socket
2988 (Stream.Socket,
2989 Item,
2990 Last,
2991 Stream.To);
2992
2993 -- It is an error if not all of the data has been sent
2994
2995 if Last /= Item'Last then
2996 Raise_Socket_Error (Socket_Errno);
2997 end if;
2998 end Write;
2999
3000 -----------
3001 -- Write --
3002 -----------
3003
3004 procedure Write
3005 (Stream : in out Stream_Socket_Stream_Type;
3006 Item : Ada.Streams.Stream_Element_Array)
3007 is
3008 First : Ada.Streams.Stream_Element_Offset;
3009 Index : Ada.Streams.Stream_Element_Offset;
3010 Max : constant Ada.Streams.Stream_Element_Offset := Item'Last;
3011
3012 begin
3013 First := Item'First;
3014 Index := First - 1;
3015 while First <= Max loop
3016 Send_Socket (Stream.Socket, Item (First .. Max), Index, null);
3017
3018 -- Exit when all or zero data sent. Zero means that the socket has
3019 -- been closed by peer.
3020
3021 exit when Index < First or else Index = Max;
3022
3023 First := Index + 1;
3024 end loop;
3025
3026 -- For an empty array, we have First > Max, and hence Index >= Max (no
3027 -- error, the loop above is never executed). After a successful send,
3028 -- Index = Max. The only remaining case, Index < Max, is therefore
3029 -- always an actual send failure.
3030
3031 if Index < Max then
3032 Raise_Socket_Error (Socket_Errno);
3033 end if;
3034 end Write;
3035
3036 Sockets_Library_Controller_Object : Sockets_Library_Controller;
3037 pragma Unreferenced (Sockets_Library_Controller_Object);
3038 -- The elaboration and finalization of this object perform the required
3039 -- initialization and cleanup actions for the sockets library.
3040
3041 --------------------
3042 -- Create_Address --
3043 --------------------
3044
3045 function Create_Address
3046 (Family : Family_Type; Bytes : Inet_Addr_Bytes) return Inet_Addr_Type
3047 is
3048 (case Family is
3049 when Family_Inet => (Family_Inet, Bytes),
3050 when Family_Inet6 => (Family_Inet6, Bytes),
3051 when Family_Unspec => (Family => Family_Unspec));
3052
3053 ---------------
3054 -- Get_Bytes --
3055 ---------------
3056
3057 function Get_Bytes (Addr : Inet_Addr_Type) return Inet_Addr_Bytes is
3058 (case Addr.Family is
3059 when Family_Inet => Addr.Sin_V4,
3060 when Family_Inet6 => Addr.Sin_V6,
3061 when Family_Unspec => (1 .. 0 => 0));
3062
3063 ----------
3064 -- Mask --
3065 ----------
3066
3067 function Mask
3068 (Family : Family_Type;
3069 Length : Natural;
3070 Host : Boolean := False) return Inet_Addr_Type
3071 is
3072 Addr_Len : constant Natural := Inet_Addr_Bytes_Length (Family);
3073 begin
3074 if Length > 8 * Addr_Len then
3075 raise Constraint_Error with
3076 "invalid mask length for address family " & Family'Img;
3077 end if;
3078
3079 declare
3080 B : Inet_Addr_Bytes (1 .. Addr_Len);
3081 Part : Inet_Addr_Comp_Type;
3082 begin
3083 for J in 1 .. Length / 8 loop
3084 B (J) := (if Host then 0 else 255);
3085 end loop;
3086
3087 if Length < 8 * Addr_Len then
3088 Part := 2 ** (8 - Length mod 8) - 1;
3089 B (Length / 8 + 1) := (if Host then Part else not Part);
3090
3091 for J in Length / 8 + 2 .. B'Last loop
3092 B (J) := (if Host then 255 else 0);
3093 end loop;
3094 end if;
3095
3096 return Create_Address (Family, B);
3097 end;
3098 end Mask;
3099
3100 -----------
3101 -- "and" --
3102 -----------
3103
3104 function "and" (Addr, Mask : Inet_Addr_Type) return Inet_Addr_Type is
3105 begin
3106 if Addr.Family /= Mask.Family then
3107 raise Constraint_Error with "incompatible address families";
3108 end if;
3109
3110 declare
3111 A : constant Inet_Addr_Bytes := Get_Bytes (Addr);
3112 M : constant Inet_Addr_Bytes := Get_Bytes (Mask);
3113 R : Inet_Addr_Bytes (A'Range);
3114
3115 begin
3116 for J in A'Range loop
3117 R (J) := A (J) and M (J);
3118 end loop;
3119 return Create_Address (Addr.Family, R);
3120 end;
3121 end "and";
3122
3123 ----------
3124 -- "or" --
3125 ----------
3126
3127 function "or" (Net, Host : Inet_Addr_Type) return Inet_Addr_Type is
3128 begin
3129 if Net.Family /= Host.Family then
3130 raise Constraint_Error with "incompatible address families";
3131 end if;
3132
3133 declare
3134 N : constant Inet_Addr_Bytes := Get_Bytes (Net);
3135 H : constant Inet_Addr_Bytes := Get_Bytes (Host);
3136 R : Inet_Addr_Bytes (N'Range);
3137
3138 begin
3139 for J in N'Range loop
3140 R (J) := N (J) or H (J);
3141 end loop;
3142 return Create_Address (Net.Family, R);
3143 end;
3144 end "or";
3145
3146 -----------
3147 -- "not" --
3148 -----------
3149
3150 function "not" (Mask : Inet_Addr_Type) return Inet_Addr_Type is
3151 M : constant Inet_Addr_Bytes := Get_Bytes (Mask);
3152 R : Inet_Addr_Bytes (M'Range);
3153 begin
3154 for J in R'Range loop
3155 R (J) := not M (J);
3156 end loop;
3157 return Create_Address (Mask.Family, R);
3158 end "not";
3159
3160 end GNAT.Sockets;