OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [gcc/] [ada/] [g-socket.adb] - Blame information for rev 749

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 706 jeremybenn
------------------------------------------------------------------------------
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-2011, 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.Finalization;
35
with Ada.Unchecked_Conversion;
36
 
37
with Interfaces.C.Strings;
38
 
39
with GNAT.Sockets.Thin_Common; use GNAT.Sockets.Thin_Common;
40
with GNAT.Sockets.Thin;        use GNAT.Sockets.Thin;
41
 
42
with GNAT.Sockets.Linker_Options;
43
pragma Warnings (Off, GNAT.Sockets.Linker_Options);
44
--  Need to include pragma Linker_Options which is platform dependent
45
 
46
with System;               use System;
47
with System.Communication; use System.Communication;
48
with System.CRTL;          use System.CRTL;
49
with System.Task_Lock;
50
 
51
package body GNAT.Sockets is
52
 
53
   package C renames Interfaces.C;
54
 
55
   use type C.int;
56
 
57
   ENOERROR : constant := 0;
58
 
59
   Netdb_Buffer_Size : constant := SOSC.Need_Netdb_Buffer * 1024;
60
   Need_Netdb_Lock   : constant Boolean := SOSC.Need_Netdb_Lock /= 0;
61
   --  The network database functions gethostbyname, gethostbyaddr,
62
   --  getservbyname and getservbyport can either be guaranteed task safe by
63
   --  the operating system, or else return data through a user-provided buffer
64
   --  to ensure concurrent uses do not interfere.
65
 
66
   --  Correspondence tables
67
 
68
   Levels : constant array (Level_Type) of C.int :=
69
              (Socket_Level              => SOSC.SOL_SOCKET,
70
               IP_Protocol_For_IP_Level  => SOSC.IPPROTO_IP,
71
               IP_Protocol_For_UDP_Level => SOSC.IPPROTO_UDP,
72
               IP_Protocol_For_TCP_Level => SOSC.IPPROTO_TCP);
73
 
74
   Modes : constant array (Mode_Type) of C.int :=
75
             (Socket_Stream   => SOSC.SOCK_STREAM,
76
              Socket_Datagram => SOSC.SOCK_DGRAM);
77
 
78
   Shutmodes : constant array (Shutmode_Type) of C.int :=
79
                 (Shut_Read       => SOSC.SHUT_RD,
80
                  Shut_Write      => SOSC.SHUT_WR,
81
                  Shut_Read_Write => SOSC.SHUT_RDWR);
82
 
83
   Requests : constant array (Request_Name) of C.int :=
84
                (Non_Blocking_IO => SOSC.FIONBIO,
85
                 N_Bytes_To_Read => SOSC.FIONREAD);
86
 
87
   Options : constant array (Option_Name) of C.int :=
88
               (Keep_Alive          => SOSC.SO_KEEPALIVE,
89
                Reuse_Address       => SOSC.SO_REUSEADDR,
90
                Broadcast           => SOSC.SO_BROADCAST,
91
                Send_Buffer         => SOSC.SO_SNDBUF,
92
                Receive_Buffer      => SOSC.SO_RCVBUF,
93
                Linger              => SOSC.SO_LINGER,
94
                Error               => SOSC.SO_ERROR,
95
                No_Delay            => SOSC.TCP_NODELAY,
96
                Add_Membership      => SOSC.IP_ADD_MEMBERSHIP,
97
                Drop_Membership     => SOSC.IP_DROP_MEMBERSHIP,
98
                Multicast_If        => SOSC.IP_MULTICAST_IF,
99
                Multicast_TTL       => SOSC.IP_MULTICAST_TTL,
100
                Multicast_Loop      => SOSC.IP_MULTICAST_LOOP,
101
                Receive_Packet_Info => SOSC.IP_PKTINFO,
102
                Send_Timeout        => SOSC.SO_SNDTIMEO,
103
                Receive_Timeout     => SOSC.SO_RCVTIMEO);
104
   --  ??? Note: for OpenSolaris, Receive_Packet_Info should be IP_RECVPKTINFO,
105
   --  but for Linux compatibility this constant is the same as IP_PKTINFO.
106
 
107
   Flags : constant array (0 .. 3) of C.int :=
108
             (0 => SOSC.MSG_OOB,     --  Process_Out_Of_Band_Data
109
              1 => SOSC.MSG_PEEK,    --  Peek_At_Incoming_Data
110
              2 => SOSC.MSG_WAITALL, --  Wait_For_A_Full_Reception
111
              3 => SOSC.MSG_EOR);    --  Send_End_Of_Record
112
 
113
   Socket_Error_Id : constant Exception_Id := Socket_Error'Identity;
114
   Host_Error_Id   : constant Exception_Id := Host_Error'Identity;
115
 
116
   Hex_To_Char : constant String (1 .. 16) := "0123456789ABCDEF";
117
   --  Use to print in hexadecimal format
118
 
119
   -----------------------
120
   -- Local subprograms --
121
   -----------------------
122
 
123
   function Resolve_Error
124
     (Error_Value : Integer;
125
      From_Errno  : Boolean := True) return Error_Type;
126
   --  Associate an enumeration value (error_type) to en error value (errno).
127
   --  From_Errno prevents from mixing h_errno with errno.
128
 
129
   function To_Name   (N  : String) return Name_Type;
130
   function To_String (HN : Name_Type) return String;
131
   --  Conversion functions
132
 
133
   function To_Int (F : Request_Flag_Type) return C.int;
134
   --  Return the int value corresponding to the specified flags combination
135
 
136
   function Set_Forced_Flags (F : C.int) return C.int;
137
   --  Return F with the bits from SOSC.MSG_Forced_Flags forced set
138
 
139
   function Short_To_Network
140
     (S : C.unsigned_short) return C.unsigned_short;
141
   pragma Inline (Short_To_Network);
142
   --  Convert a port number into a network port number
143
 
144
   function Network_To_Short
145
     (S : C.unsigned_short) return C.unsigned_short
146
   renames Short_To_Network;
147
   --  Symmetric operation
148
 
149
   function Image
150
     (Val :  Inet_Addr_VN_Type;
151
      Hex :  Boolean := False) return String;
152
   --  Output an array of inet address components in hex or decimal mode
153
 
154
   function Is_IP_Address (Name : String) return Boolean;
155
   --  Return true when Name is an IP address in standard dot notation
156
 
157
   procedure Netdb_Lock;
158
   pragma Inline (Netdb_Lock);
159
   procedure Netdb_Unlock;
160
   pragma Inline (Netdb_Unlock);
161
   --  Lock/unlock operation used to protect netdb access for platforms that
162
   --  require such protection.
163
 
164
   function To_In_Addr (Addr : Inet_Addr_Type) return In_Addr;
165
   procedure To_Inet_Addr
166
     (Addr   : In_Addr;
167
      Result : out Inet_Addr_Type);
168
   --  Conversion functions
169
 
170
   function To_Host_Entry (E : Hostent_Access) return Host_Entry_Type;
171
   --  Conversion function
172
 
173
   function To_Service_Entry (E : Servent_Access) return Service_Entry_Type;
174
   --  Conversion function
175
 
176
   function Value (S : System.Address) return String;
177
   --  Same as Interfaces.C.Strings.Value but taking a System.Address (on VMS,
178
   --  chars_ptr is a 32-bit pointer, and here we need a 64-bit version).
179
 
180
   function To_Timeval (Val : Timeval_Duration) return Timeval;
181
   --  Separate Val in seconds and microseconds
182
 
183
   function To_Duration (Val : Timeval) return Timeval_Duration;
184
   --  Reconstruct a Duration value from a Timeval record (seconds and
185
   --  microseconds).
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);
192
   --  Raise Host_Error exception with message describing error code (note
193
   --  hstrerror seems to be obsolete) from h_errno.
194
 
195
   procedure Narrow (Item : in out Socket_Set_Type);
196
   --  Update Last as it may be greater than the real last socket
197
 
198
   procedure Check_For_Fd_Set (Fd : Socket_Type);
199
   pragma Inline (Check_For_Fd_Set);
200
   --  Raise Constraint_Error if Fd is less than 0 or greater than or equal to
201
   --  FD_SETSIZE, on platforms where fd_set is a bitmap.
202
 
203
   --  Types needed for Datagram_Socket_Stream_Type
204
 
205
   type Datagram_Socket_Stream_Type is new Root_Stream_Type with record
206
      Socket : Socket_Type;
207
      To     : Sock_Addr_Type;
208
      From   : Sock_Addr_Type;
209
   end record;
210
 
211
   type Datagram_Socket_Stream_Access is
212
     access all Datagram_Socket_Stream_Type;
213
 
214
   procedure Read
215
     (Stream : in out Datagram_Socket_Stream_Type;
216
      Item   : out Ada.Streams.Stream_Element_Array;
217
      Last   : out Ada.Streams.Stream_Element_Offset);
218
 
219
   procedure Write
220
     (Stream : in out Datagram_Socket_Stream_Type;
221
      Item   : Ada.Streams.Stream_Element_Array);
222
 
223
   --  Types needed for Stream_Socket_Stream_Type
224
 
225
   type Stream_Socket_Stream_Type is new Root_Stream_Type with record
226
      Socket : Socket_Type;
227
   end record;
228
 
229
   type Stream_Socket_Stream_Access is
230
     access all Stream_Socket_Stream_Type;
231
 
232
   procedure Read
233
     (Stream : in out Stream_Socket_Stream_Type;
234
      Item   : out Ada.Streams.Stream_Element_Array;
235
      Last   : out Ada.Streams.Stream_Element_Offset);
236
 
237
   procedure Write
238
     (Stream : in out Stream_Socket_Stream_Type;
239
      Item   : Ada.Streams.Stream_Element_Array);
240
 
241
   procedure Stream_Write
242
     (Socket : Socket_Type;
243
      Item   : Ada.Streams.Stream_Element_Array;
244
      To     : access Sock_Addr_Type);
245
   --  Common implementation for the Write operation of Datagram_Socket_Stream_
246
   --  Type and Stream_Socket_Stream_Type.
247
 
248
   procedure Wait_On_Socket
249
     (Socket   : Socket_Type;
250
      For_Read : Boolean;
251
      Timeout  : Selector_Duration;
252
      Selector : access Selector_Type := null;
253
      Status   : out Selector_Status);
254
   --  Common code for variants of socket operations supporting a timeout:
255
   --  block in Check_Selector on Socket for at most the indicated timeout.
256
   --  If For_Read is True, Socket is added to the read set for this call, else
257
   --  it is added to the write set. If no selector is provided, a local one is
258
   --  created for this call and destroyed prior to returning.
259
 
260
   type Sockets_Library_Controller is new Ada.Finalization.Limited_Controlled
261
     with null record;
262
   --  This type is used to generate automatic calls to Initialize and Finalize
263
   --  during the elaboration and finalization of this package. A single object
264
   --  of this type must exist at library level.
265
 
266
   function Err_Code_Image (E : Integer) return String;
267
   --  Return the value of E surrounded with brackets
268
 
269
   procedure Initialize (X : in out Sockets_Library_Controller);
270
   procedure Finalize   (X : in out Sockets_Library_Controller);
271
 
272
   procedure Normalize_Empty_Socket_Set (S : in out Socket_Set_Type);
273
   --  If S is the empty set (detected by Last = No_Socket), make sure its
274
   --  fd_set component is actually cleared. Note that the case where it is
275
   --  not can occur for an uninitialized Socket_Set_Type object.
276
 
277
   function Is_Open (S : Selector_Type) return Boolean;
278
   --  Return True for an "open" Selector_Type object, i.e. one for which
279
   --  Create_Selector has been called and Close_Selector has not been called,
280
   --  or the null selector.
281
 
282
   ---------
283
   -- "+" --
284
   ---------
285
 
286
   function "+" (L, R : Request_Flag_Type) return Request_Flag_Type is
287
   begin
288
      return L or R;
289
   end "+";
290
 
291
   --------------------
292
   -- Abort_Selector --
293
   --------------------
294
 
295
   procedure Abort_Selector (Selector : Selector_Type) is
296
      Res : C.int;
297
 
298
   begin
299
      if not Is_Open (Selector) then
300
         raise Program_Error with "closed selector";
301
 
302
      elsif Selector.Is_Null then
303
         raise Program_Error with "null selector";
304
 
305
      end if;
306
 
307
      --  Send one byte to unblock select system call
308
 
309
      Res := Signalling_Fds.Write (C.int (Selector.W_Sig_Socket));
310
 
311
      if Res = Failure then
312
         Raise_Socket_Error (Socket_Errno);
313
      end if;
314
   end Abort_Selector;
315
 
316
   -------------------
317
   -- Accept_Socket --
318
   -------------------
319
 
320
   procedure Accept_Socket
321
     (Server  : Socket_Type;
322
      Socket  : out Socket_Type;
323
      Address : out Sock_Addr_Type)
324
   is
325
      Res : C.int;
326
      Sin : aliased Sockaddr_In;
327
      Len : aliased C.int := Sin'Size / 8;
328
 
329
   begin
330
      Res := C_Accept (C.int (Server), Sin'Address, Len'Access);
331
 
332
      if Res = Failure then
333
         Raise_Socket_Error (Socket_Errno);
334
      end if;
335
 
336
      Socket := Socket_Type (Res);
337
 
338
      To_Inet_Addr (Sin.Sin_Addr, Address.Addr);
339
      Address.Port := Port_Type (Network_To_Short (Sin.Sin_Port));
340
   end Accept_Socket;
341
 
342
   -------------------
343
   -- Accept_Socket --
344
   -------------------
345
 
346
   procedure Accept_Socket
347
     (Server   : Socket_Type;
348
      Socket   : out Socket_Type;
349
      Address  : out Sock_Addr_Type;
350
      Timeout  : Selector_Duration;
351
      Selector : access Selector_Type := null;
352
      Status   : out Selector_Status)
353
   is
354
   begin
355
      if Selector /= null and then not Is_Open (Selector.all) then
356
         raise Program_Error with "closed selector";
357
      end if;
358
 
359
      --  Wait for socket to become available for reading
360
 
361
      Wait_On_Socket
362
        (Socket    => Server,
363
         For_Read  => True,
364
         Timeout   => Timeout,
365
         Selector  => Selector,
366
         Status    => Status);
367
 
368
      --  Accept connection if available
369
 
370
      if Status = Completed then
371
         Accept_Socket (Server, Socket, Address);
372
      else
373
         Socket := No_Socket;
374
      end if;
375
   end Accept_Socket;
376
 
377
   ---------------
378
   -- Addresses --
379
   ---------------
380
 
381
   function Addresses
382
     (E : Host_Entry_Type;
383
      N : Positive := 1) return Inet_Addr_Type
384
   is
385
   begin
386
      return E.Addresses (N);
387
   end Addresses;
388
 
389
   ----------------------
390
   -- Addresses_Length --
391
   ----------------------
392
 
393
   function Addresses_Length (E : Host_Entry_Type) return Natural is
394
   begin
395
      return E.Addresses_Length;
396
   end Addresses_Length;
397
 
398
   -------------
399
   -- Aliases --
400
   -------------
401
 
402
   function Aliases
403
     (E : Host_Entry_Type;
404
      N : Positive := 1) return String
405
   is
406
   begin
407
      return To_String (E.Aliases (N));
408
   end Aliases;
409
 
410
   -------------
411
   -- Aliases --
412
   -------------
413
 
414
   function Aliases
415
     (S : Service_Entry_Type;
416
      N : Positive := 1) return String
417
   is
418
   begin
419
      return To_String (S.Aliases (N));
420
   end Aliases;
421
 
422
   --------------------
423
   -- Aliases_Length --
424
   --------------------
425
 
426
   function Aliases_Length (E : Host_Entry_Type) return Natural is
427
   begin
428
      return E.Aliases_Length;
429
   end Aliases_Length;
430
 
431
   --------------------
432
   -- Aliases_Length --
433
   --------------------
434
 
435
   function Aliases_Length (S : Service_Entry_Type) return Natural is
436
   begin
437
      return S.Aliases_Length;
438
   end Aliases_Length;
439
 
440
   -----------------
441
   -- Bind_Socket --
442
   -----------------
443
 
444
   procedure Bind_Socket
445
     (Socket  : Socket_Type;
446
      Address : Sock_Addr_Type)
447
   is
448
      Res : C.int;
449
      Sin : aliased Sockaddr_In;
450
      Len : constant C.int := Sin'Size / 8;
451
      --  This assumes that Address.Family = Family_Inet???
452
 
453
   begin
454
      if Address.Family = Family_Inet6 then
455
         raise Socket_Error with "IPv6 not supported";
456
      end if;
457
 
458
      Set_Family  (Sin.Sin_Family, Address.Family);
459
      Set_Address (Sin'Unchecked_Access, To_In_Addr (Address.Addr));
460
      Set_Port
461
        (Sin'Unchecked_Access,
462
         Short_To_Network (C.unsigned_short (Address.Port)));
463
 
464
      Res := C_Bind (C.int (Socket), Sin'Address, Len);
465
 
466
      if Res = Failure then
467
         Raise_Socket_Error (Socket_Errno);
468
      end if;
469
   end Bind_Socket;
470
 
471
   ----------------------
472
   -- Check_For_Fd_Set --
473
   ----------------------
474
 
475
   procedure Check_For_Fd_Set (Fd : Socket_Type) is
476
      use SOSC;
477
 
478
   begin
479
      --  On Windows, fd_set is a FD_SETSIZE array of socket ids:
480
      --  no check required. Warnings suppressed because condition
481
      --  is known at compile time.
482
 
483
      pragma Warnings (Off);
484
      if Target_OS = Windows then
485
         pragma Warnings (On);
486
 
487
         return;
488
 
489
      --  On other platforms, fd_set is an FD_SETSIZE bitmap: check
490
      --  that Fd is within range (otherwise behaviour is undefined).
491
 
492
      elsif Fd < 0 or else Fd >= SOSC.FD_SETSIZE then
493
         raise Constraint_Error
494
           with "invalid value for socket set: " & Image (Fd);
495
      end if;
496
   end Check_For_Fd_Set;
497
 
498
   --------------------
499
   -- Check_Selector --
500
   --------------------
501
 
502
   procedure Check_Selector
503
     (Selector     : Selector_Type;
504
      R_Socket_Set : in out Socket_Set_Type;
505
      W_Socket_Set : in out Socket_Set_Type;
506
      Status       : out Selector_Status;
507
      Timeout      : Selector_Duration := Forever)
508
   is
509
      E_Socket_Set : Socket_Set_Type;
510
   begin
511
      Check_Selector
512
        (Selector, R_Socket_Set, W_Socket_Set, E_Socket_Set, Status, Timeout);
513
   end Check_Selector;
514
 
515
   --------------------
516
   -- Check_Selector --
517
   --------------------
518
 
519
   procedure Check_Selector
520
     (Selector     : Selector_Type;
521
      R_Socket_Set : in out Socket_Set_Type;
522
      W_Socket_Set : in out Socket_Set_Type;
523
      E_Socket_Set : in out Socket_Set_Type;
524
      Status       : out Selector_Status;
525
      Timeout      : Selector_Duration := Forever)
526
   is
527
      Res  : C.int;
528
      Last : C.int;
529
      RSig : Socket_Type := No_Socket;
530
      TVal : aliased Timeval;
531
      TPtr : Timeval_Access;
532
 
533
   begin
534
      if not Is_Open (Selector) then
535
         raise Program_Error with "closed selector";
536
      end if;
537
 
538
      Status := Completed;
539
 
540
      --  No timeout or Forever is indicated by a null timeval pointer
541
 
542
      if Timeout = Forever then
543
         TPtr := null;
544
      else
545
         TVal := To_Timeval (Timeout);
546
         TPtr := TVal'Unchecked_Access;
547
      end if;
548
 
549
      --  Add read signalling socket, if present
550
 
551
      if not Selector.Is_Null then
552
         RSig := Selector.R_Sig_Socket;
553
         Set (R_Socket_Set, RSig);
554
      end if;
555
 
556
      Last := C.int'Max (C.int'Max (C.int (R_Socket_Set.Last),
557
                                    C.int (W_Socket_Set.Last)),
558
                                    C.int (E_Socket_Set.Last));
559
 
560
      --  Zero out fd_set for empty Socket_Set_Type objects
561
 
562
      Normalize_Empty_Socket_Set (R_Socket_Set);
563
      Normalize_Empty_Socket_Set (W_Socket_Set);
564
      Normalize_Empty_Socket_Set (E_Socket_Set);
565
 
566
      Res :=
567
        C_Select
568
         (Last + 1,
569
          R_Socket_Set.Set'Access,
570
          W_Socket_Set.Set'Access,
571
          E_Socket_Set.Set'Access,
572
          TPtr);
573
 
574
      if Res = Failure then
575
         Raise_Socket_Error (Socket_Errno);
576
      end if;
577
 
578
      --  If Select was resumed because of read signalling socket, read this
579
      --  data and remove socket from set.
580
 
581
      if RSig /= No_Socket and then Is_Set (R_Socket_Set, RSig) then
582
         Clear (R_Socket_Set, RSig);
583
 
584
         Res := Signalling_Fds.Read (C.int (RSig));
585
 
586
         if Res = Failure then
587
            Raise_Socket_Error (Socket_Errno);
588
         end if;
589
 
590
         Status := Aborted;
591
 
592
      elsif Res = 0 then
593
         Status := Expired;
594
      end if;
595
 
596
      --  Update socket sets in regard to their new contents
597
 
598
      Narrow (R_Socket_Set);
599
      Narrow (W_Socket_Set);
600
      Narrow (E_Socket_Set);
601
   end Check_Selector;
602
 
603
   -----------
604
   -- Clear --
605
   -----------
606
 
607
   procedure Clear
608
     (Item   : in out Socket_Set_Type;
609
      Socket : Socket_Type)
610
   is
611
      Last : aliased C.int := C.int (Item.Last);
612
 
613
   begin
614
      Check_For_Fd_Set (Socket);
615
 
616
      if Item.Last /= No_Socket then
617
         Remove_Socket_From_Set (Item.Set'Access, C.int (Socket));
618
         Last_Socket_In_Set (Item.Set'Access, Last'Unchecked_Access);
619
         Item.Last := Socket_Type (Last);
620
      end if;
621
   end Clear;
622
 
623
   --------------------
624
   -- Close_Selector --
625
   --------------------
626
 
627
   procedure Close_Selector (Selector : in out Selector_Type) is
628
   begin
629
      --  Nothing to do if selector already in closed state
630
 
631
      if Selector.Is_Null or else not Is_Open (Selector) then
632
         return;
633
      end if;
634
 
635
      --  Close the signalling file descriptors used internally for the
636
      --  implementation of Abort_Selector.
637
 
638
      Signalling_Fds.Close (C.int (Selector.R_Sig_Socket));
639
      Signalling_Fds.Close (C.int (Selector.W_Sig_Socket));
640
 
641
      --  Reset R_Sig_Socket and W_Sig_Socket to No_Socket to ensure that any
642
      --  (erroneous) subsequent attempt to use this selector properly fails.
643
 
644
      Selector.R_Sig_Socket := No_Socket;
645
      Selector.W_Sig_Socket := No_Socket;
646
   end Close_Selector;
647
 
648
   ------------------
649
   -- Close_Socket --
650
   ------------------
651
 
652
   procedure Close_Socket (Socket : Socket_Type) is
653
      Res : C.int;
654
 
655
   begin
656
      Res := C_Close (C.int (Socket));
657
 
658
      if Res = Failure then
659
         Raise_Socket_Error (Socket_Errno);
660
      end if;
661
   end Close_Socket;
662
 
663
   --------------------
664
   -- Connect_Socket --
665
   --------------------
666
 
667
   procedure Connect_Socket
668
     (Socket : Socket_Type;
669
      Server : Sock_Addr_Type)
670
   is
671
      Res : C.int;
672
      Sin : aliased Sockaddr_In;
673
      Len : constant C.int := Sin'Size / 8;
674
 
675
   begin
676
      if Server.Family = Family_Inet6 then
677
         raise Socket_Error with "IPv6 not supported";
678
      end if;
679
 
680
      Set_Family  (Sin.Sin_Family, Server.Family);
681
      Set_Address (Sin'Unchecked_Access, To_In_Addr (Server.Addr));
682
      Set_Port
683
        (Sin'Unchecked_Access,
684
         Short_To_Network (C.unsigned_short (Server.Port)));
685
 
686
      Res := C_Connect (C.int (Socket), Sin'Address, Len);
687
 
688
      if Res = Failure then
689
         Raise_Socket_Error (Socket_Errno);
690
      end if;
691
   end Connect_Socket;
692
 
693
   --------------------
694
   -- Connect_Socket --
695
   --------------------
696
 
697
   procedure Connect_Socket
698
     (Socket   : Socket_Type;
699
      Server   : Sock_Addr_Type;
700
      Timeout  : Selector_Duration;
701
      Selector : access Selector_Type := null;
702
      Status   : out Selector_Status)
703
   is
704
      Req : Request_Type;
705
      --  Used to set Socket to non-blocking I/O
706
 
707
   begin
708
      if Selector /= null and then not Is_Open (Selector.all) then
709
         raise Program_Error with "closed selector";
710
      end if;
711
 
712
      --  Set the socket to non-blocking I/O
713
 
714
      Req := (Name => Non_Blocking_IO, Enabled => True);
715
      Control_Socket (Socket, Request => Req);
716
 
717
      --  Start operation (non-blocking), will raise Socket_Error with
718
      --  EINPROGRESS.
719
 
720
      begin
721
         Connect_Socket (Socket, Server);
722
      exception
723
         when E : Socket_Error =>
724
            if Resolve_Exception (E) = Operation_Now_In_Progress then
725
               null;
726
            else
727
               raise;
728
            end if;
729
      end;
730
 
731
      --  Wait for socket to become available for writing
732
 
733
      Wait_On_Socket
734
        (Socket   => Socket,
735
         For_Read => False,
736
         Timeout  => Timeout,
737
         Selector => Selector,
738
         Status   => Status);
739
 
740
      --  Reset the socket to blocking I/O
741
 
742
      Req := (Name => Non_Blocking_IO, Enabled => False);
743
      Control_Socket (Socket, Request => Req);
744
   end Connect_Socket;
745
 
746
   --------------------
747
   -- Control_Socket --
748
   --------------------
749
 
750
   procedure Control_Socket
751
     (Socket  : Socket_Type;
752
      Request : in out Request_Type)
753
   is
754
      Arg : aliased C.int;
755
      Res : C.int;
756
 
757
   begin
758
      case Request.Name is
759
         when Non_Blocking_IO =>
760
            Arg := C.int (Boolean'Pos (Request.Enabled));
761
 
762
         when N_Bytes_To_Read =>
763
            null;
764
      end case;
765
 
766
      Res := Socket_Ioctl
767
               (C.int (Socket), Requests (Request.Name), Arg'Unchecked_Access);
768
 
769
      if Res = Failure then
770
         Raise_Socket_Error (Socket_Errno);
771
      end if;
772
 
773
      case Request.Name is
774
         when Non_Blocking_IO =>
775
            null;
776
 
777
         when N_Bytes_To_Read =>
778
            Request.Size := Natural (Arg);
779
      end case;
780
   end Control_Socket;
781
 
782
   ----------
783
   -- Copy --
784
   ----------
785
 
786
   procedure Copy
787
     (Source : Socket_Set_Type;
788
      Target : out Socket_Set_Type)
789
   is
790
   begin
791
      Target := Source;
792
   end Copy;
793
 
794
   ---------------------
795
   -- Create_Selector --
796
   ---------------------
797
 
798
   procedure Create_Selector (Selector : out Selector_Type) is
799
      Two_Fds : aliased Fd_Pair;
800
      Res     : C.int;
801
 
802
   begin
803
      if Is_Open (Selector) then
804
         --  Raise exception to prevent socket descriptor leak
805
 
806
         raise Program_Error with "selector already open";
807
      end if;
808
 
809
      --  We open two signalling file descriptors. One of them is used to send
810
      --  data to the other, which is included in a C_Select socket set. The
811
      --  communication is used to force a call to C_Select to complete, and
812
      --  the waiting task to resume its execution.
813
 
814
      Res := Signalling_Fds.Create (Two_Fds'Access);
815
 
816
      if Res = Failure then
817
         Raise_Socket_Error (Socket_Errno);
818
      end if;
819
 
820
      Selector.R_Sig_Socket := Socket_Type (Two_Fds (Read_End));
821
      Selector.W_Sig_Socket := Socket_Type (Two_Fds (Write_End));
822
   end Create_Selector;
823
 
824
   -------------------
825
   -- Create_Socket --
826
   -------------------
827
 
828
   procedure Create_Socket
829
     (Socket : out Socket_Type;
830
      Family : Family_Type := Family_Inet;
831
      Mode   : Mode_Type   := Socket_Stream)
832
   is
833
      Res : C.int;
834
 
835
   begin
836
      Res := C_Socket (Families (Family), Modes (Mode), 0);
837
 
838
      if Res = Failure then
839
         Raise_Socket_Error (Socket_Errno);
840
      end if;
841
 
842
      Socket := Socket_Type (Res);
843
   end Create_Socket;
844
 
845
   -----------
846
   -- Empty --
847
   -----------
848
 
849
   procedure Empty (Item : out Socket_Set_Type) is
850
   begin
851
      Reset_Socket_Set (Item.Set'Access);
852
      Item.Last := No_Socket;
853
   end Empty;
854
 
855
   --------------------
856
   -- Err_Code_Image --
857
   --------------------
858
 
859
   function Err_Code_Image (E : Integer) return String is
860
      Msg : String := E'Img & "] ";
861
   begin
862
      Msg (Msg'First) := '[';
863
      return Msg;
864
   end Err_Code_Image;
865
 
866
   --------------
867
   -- Finalize --
868
   --------------
869
 
870
   procedure Finalize (X : in out Sockets_Library_Controller) is
871
      pragma Unreferenced (X);
872
 
873
   begin
874
      --  Finalization operation for the GNAT.Sockets package
875
 
876
      Thin.Finalize;
877
   end Finalize;
878
 
879
   --------------
880
   -- Finalize --
881
   --------------
882
 
883
   procedure Finalize is
884
   begin
885
      --  This is a dummy placeholder for an obsolete API.
886
      --  The real finalization actions are in Initialize primitive operation
887
      --  of Sockets_Library_Controller.
888
 
889
      null;
890
   end Finalize;
891
 
892
   ---------
893
   -- Get --
894
   ---------
895
 
896
   procedure Get
897
     (Item   : in out Socket_Set_Type;
898
      Socket : out Socket_Type)
899
   is
900
      S : aliased C.int;
901
      L : aliased C.int := C.int (Item.Last);
902
 
903
   begin
904
      if Item.Last /= No_Socket then
905
         Get_Socket_From_Set
906
           (Item.Set'Access, Last => L'Access, Socket => S'Access);
907
         Item.Last := Socket_Type (L);
908
         Socket    := Socket_Type (S);
909
      else
910
         Socket := No_Socket;
911
      end if;
912
   end Get;
913
 
914
   -----------------
915
   -- Get_Address --
916
   -----------------
917
 
918
   function Get_Address
919
     (Stream : not null Stream_Access) return Sock_Addr_Type
920
   is
921
   begin
922
      if Stream.all in Datagram_Socket_Stream_Type then
923
         return Datagram_Socket_Stream_Type (Stream.all).From;
924
      else
925
         return Get_Peer_Name (Stream_Socket_Stream_Type (Stream.all).Socket);
926
      end if;
927
   end Get_Address;
928
 
929
   -------------------------
930
   -- Get_Host_By_Address --
931
   -------------------------
932
 
933
   function Get_Host_By_Address
934
     (Address : Inet_Addr_Type;
935
      Family  : Family_Type := Family_Inet) return Host_Entry_Type
936
   is
937
      pragma Unreferenced (Family);
938
 
939
      HA     : aliased In_Addr := To_In_Addr (Address);
940
      Buflen : constant C.int := Netdb_Buffer_Size;
941
      Buf    : aliased C.char_array (1 .. Netdb_Buffer_Size);
942
      Res    : aliased Hostent;
943
      Err    : aliased C.int;
944
 
945
   begin
946
      Netdb_Lock;
947
 
948
      if C_Gethostbyaddr (HA'Address, HA'Size / 8, SOSC.AF_INET,
949
                             Res'Access, Buf'Address, Buflen, Err'Access) /= 0
950
      then
951
         Netdb_Unlock;
952
         Raise_Host_Error (Integer (Err));
953
      end if;
954
 
955
      return H : constant Host_Entry_Type :=
956
                   To_Host_Entry (Res'Unchecked_Access)
957
      do
958
         Netdb_Unlock;
959
      end return;
960
   end Get_Host_By_Address;
961
 
962
   ----------------------
963
   -- Get_Host_By_Name --
964
   ----------------------
965
 
966
   function Get_Host_By_Name (Name : String) return Host_Entry_Type is
967
   begin
968
      --  Detect IP address name and redirect to Inet_Addr
969
 
970
      if Is_IP_Address (Name) then
971
         return Get_Host_By_Address (Inet_Addr (Name));
972
      end if;
973
 
974
      declare
975
         HN     : constant C.char_array := C.To_C (Name);
976
         Buflen : constant C.int := Netdb_Buffer_Size;
977
         Buf    : aliased C.char_array (1 .. Netdb_Buffer_Size);
978
         Res    : aliased Hostent;
979
         Err    : aliased C.int;
980
 
981
      begin
982
         Netdb_Lock;
983
 
984
         if C_Gethostbyname
985
           (HN, Res'Access, Buf'Address, Buflen, Err'Access) /= 0
986
         then
987
            Netdb_Unlock;
988
            Raise_Host_Error (Integer (Err));
989
         end if;
990
 
991
         return H : constant Host_Entry_Type :=
992
                      To_Host_Entry (Res'Unchecked_Access)
993
         do
994
            Netdb_Unlock;
995
         end return;
996
      end;
997
   end Get_Host_By_Name;
998
 
999
   -------------------
1000
   -- Get_Peer_Name --
1001
   -------------------
1002
 
1003
   function Get_Peer_Name (Socket : Socket_Type) return Sock_Addr_Type is
1004
      Sin : aliased Sockaddr_In;
1005
      Len : aliased C.int := Sin'Size / 8;
1006
      Res : Sock_Addr_Type (Family_Inet);
1007
 
1008
   begin
1009
      if C_Getpeername (C.int (Socket), Sin'Address, Len'Access) = Failure then
1010
         Raise_Socket_Error (Socket_Errno);
1011
      end if;
1012
 
1013
      To_Inet_Addr (Sin.Sin_Addr, Res.Addr);
1014
      Res.Port := Port_Type (Network_To_Short (Sin.Sin_Port));
1015
 
1016
      return Res;
1017
   end Get_Peer_Name;
1018
 
1019
   -------------------------
1020
   -- Get_Service_By_Name --
1021
   -------------------------
1022
 
1023
   function Get_Service_By_Name
1024
     (Name     : String;
1025
      Protocol : String) return Service_Entry_Type
1026
   is
1027
      SN     : constant C.char_array := C.To_C (Name);
1028
      SP     : constant C.char_array := C.To_C (Protocol);
1029
      Buflen : constant C.int := Netdb_Buffer_Size;
1030
      Buf    : aliased C.char_array (1 .. Netdb_Buffer_Size);
1031
      Res    : aliased Servent;
1032
 
1033
   begin
1034
      Netdb_Lock;
1035
 
1036
      if C_Getservbyname (SN, SP, Res'Access, Buf'Address, Buflen) /= 0 then
1037
         Netdb_Unlock;
1038
         raise Service_Error with "Service not found";
1039
      end if;
1040
 
1041
      --  Translate from the C format to the API format
1042
 
1043
      return S : constant Service_Entry_Type :=
1044
                   To_Service_Entry (Res'Unchecked_Access)
1045
      do
1046
         Netdb_Unlock;
1047
      end return;
1048
   end Get_Service_By_Name;
1049
 
1050
   -------------------------
1051
   -- Get_Service_By_Port --
1052
   -------------------------
1053
 
1054
   function Get_Service_By_Port
1055
     (Port     : Port_Type;
1056
      Protocol : String) return Service_Entry_Type
1057
   is
1058
      SP     : constant C.char_array := C.To_C (Protocol);
1059
      Buflen : constant C.int := Netdb_Buffer_Size;
1060
      Buf    : aliased C.char_array (1 .. Netdb_Buffer_Size);
1061
      Res    : aliased Servent;
1062
 
1063
   begin
1064
      Netdb_Lock;
1065
 
1066
      if C_Getservbyport
1067
        (C.int (Short_To_Network (C.unsigned_short (Port))), SP,
1068
         Res'Access, Buf'Address, Buflen) /= 0
1069
      then
1070
         Netdb_Unlock;
1071
         raise Service_Error with "Service not found";
1072
      end if;
1073
 
1074
      --  Translate from the C format to the API format
1075
 
1076
      return S : constant Service_Entry_Type :=
1077
                   To_Service_Entry (Res'Unchecked_Access)
1078
      do
1079
         Netdb_Unlock;
1080
      end return;
1081
   end Get_Service_By_Port;
1082
 
1083
   ---------------------
1084
   -- Get_Socket_Name --
1085
   ---------------------
1086
 
1087
   function Get_Socket_Name
1088
     (Socket : Socket_Type) return Sock_Addr_Type
1089
   is
1090
      Sin  : aliased Sockaddr_In;
1091
      Len  : aliased C.int := Sin'Size / 8;
1092
      Res  : C.int;
1093
      Addr : Sock_Addr_Type := No_Sock_Addr;
1094
 
1095
   begin
1096
      Res := C_Getsockname (C.int (Socket), Sin'Address, Len'Access);
1097
 
1098
      if Res /= Failure then
1099
         To_Inet_Addr (Sin.Sin_Addr, Addr.Addr);
1100
         Addr.Port := Port_Type (Network_To_Short (Sin.Sin_Port));
1101
      end if;
1102
 
1103
      return Addr;
1104
   end Get_Socket_Name;
1105
 
1106
   -----------------------
1107
   -- Get_Socket_Option --
1108
   -----------------------
1109
 
1110
   function Get_Socket_Option
1111
     (Socket : Socket_Type;
1112
      Level  : Level_Type := Socket_Level;
1113
      Name   : Option_Name) return Option_Type
1114
   is
1115
      use type C.unsigned_char;
1116
 
1117
      V8  : aliased Two_Ints;
1118
      V4  : aliased C.int;
1119
      V1  : aliased C.unsigned_char;
1120
      VT  : aliased Timeval;
1121
      Len : aliased C.int;
1122
      Add : System.Address;
1123
      Res : C.int;
1124
      Opt : Option_Type (Name);
1125
 
1126
   begin
1127
      case Name is
1128
         when Multicast_Loop      |
1129
              Multicast_TTL       |
1130
              Receive_Packet_Info =>
1131
            Len := V1'Size / 8;
1132
            Add := V1'Address;
1133
 
1134
         when Keep_Alive      |
1135
              Reuse_Address   |
1136
              Broadcast       |
1137
              No_Delay        |
1138
              Send_Buffer     |
1139
              Receive_Buffer  |
1140
              Multicast_If    |
1141
              Error           =>
1142
            Len := V4'Size / 8;
1143
            Add := V4'Address;
1144
 
1145
         when Send_Timeout    |
1146
              Receive_Timeout =>
1147
            Len := VT'Size / 8;
1148
            Add := VT'Address;
1149
 
1150
         when Linger          |
1151
              Add_Membership  |
1152
              Drop_Membership =>
1153
            Len := V8'Size / 8;
1154
            Add := V8'Address;
1155
 
1156
      end case;
1157
 
1158
      Res :=
1159
        C_Getsockopt
1160
          (C.int (Socket),
1161
           Levels (Level),
1162
           Options (Name),
1163
           Add, Len'Access);
1164
 
1165
      if Res = Failure then
1166
         Raise_Socket_Error (Socket_Errno);
1167
      end if;
1168
 
1169
      case Name is
1170
         when Keep_Alive      |
1171
              Reuse_Address   |
1172
              Broadcast       |
1173
              No_Delay        =>
1174
            Opt.Enabled := (V4 /= 0);
1175
 
1176
         when Linger          =>
1177
            Opt.Enabled := (V8 (V8'First) /= 0);
1178
            Opt.Seconds := Natural (V8 (V8'Last));
1179
 
1180
         when Send_Buffer     |
1181
              Receive_Buffer  =>
1182
            Opt.Size := Natural (V4);
1183
 
1184
         when Error           =>
1185
            Opt.Error := Resolve_Error (Integer (V4));
1186
 
1187
         when Add_Membership  |
1188
              Drop_Membership =>
1189
            To_Inet_Addr (To_In_Addr (V8 (V8'First)), Opt.Multicast_Address);
1190
            To_Inet_Addr (To_In_Addr (V8 (V8'Last)), Opt.Local_Interface);
1191
 
1192
         when Multicast_If    =>
1193
            To_Inet_Addr (To_In_Addr (V4), Opt.Outgoing_If);
1194
 
1195
         when Multicast_TTL   =>
1196
            Opt.Time_To_Live := Integer (V1);
1197
 
1198
         when Multicast_Loop      |
1199
              Receive_Packet_Info =>
1200
            Opt.Enabled := (V1 /= 0);
1201
 
1202
         when Send_Timeout    |
1203
              Receive_Timeout =>
1204
            Opt.Timeout := To_Duration (VT);
1205
      end case;
1206
 
1207
      return Opt;
1208
   end Get_Socket_Option;
1209
 
1210
   ---------------
1211
   -- Host_Name --
1212
   ---------------
1213
 
1214
   function Host_Name return String is
1215
      Name : aliased C.char_array (1 .. 64);
1216
      Res  : C.int;
1217
 
1218
   begin
1219
      Res := C_Gethostname (Name'Address, Name'Length);
1220
 
1221
      if Res = Failure then
1222
         Raise_Socket_Error (Socket_Errno);
1223
      end if;
1224
 
1225
      return C.To_Ada (Name);
1226
   end Host_Name;
1227
 
1228
   -----------
1229
   -- Image --
1230
   -----------
1231
 
1232
   function Image
1233
     (Val : Inet_Addr_VN_Type;
1234
      Hex : Boolean := False) return String
1235
   is
1236
      --  The largest Inet_Addr_Comp_Type image occurs with IPv4. It
1237
      --  has at most a length of 3 plus one '.' character.
1238
 
1239
      Buffer    : String (1 .. 4 * Val'Length);
1240
      Length    : Natural := 1;
1241
      Separator : Character;
1242
 
1243
      procedure Img10 (V : Inet_Addr_Comp_Type);
1244
      --  Append to Buffer image of V in decimal format
1245
 
1246
      procedure Img16 (V : Inet_Addr_Comp_Type);
1247
      --  Append to Buffer image of V in hexadecimal format
1248
 
1249
      -----------
1250
      -- Img10 --
1251
      -----------
1252
 
1253
      procedure Img10 (V : Inet_Addr_Comp_Type) is
1254
         Img : constant String := V'Img;
1255
         Len : constant Natural := Img'Length - 1;
1256
      begin
1257
         Buffer (Length .. Length + Len - 1) := Img (2 .. Img'Last);
1258
         Length := Length + Len;
1259
      end Img10;
1260
 
1261
      -----------
1262
      -- Img16 --
1263
      -----------
1264
 
1265
      procedure Img16 (V : Inet_Addr_Comp_Type) is
1266
      begin
1267
         Buffer (Length)     := Hex_To_Char (Natural (V / 16) + 1);
1268
         Buffer (Length + 1) := Hex_To_Char (Natural (V mod 16) + 1);
1269
         Length := Length + 2;
1270
      end Img16;
1271
 
1272
   --  Start of processing for Image
1273
 
1274
   begin
1275
      Separator := (if Hex then ':' else '.');
1276
 
1277
      for J in Val'Range loop
1278
         if Hex then
1279
            Img16 (Val (J));
1280
         else
1281
            Img10 (Val (J));
1282
         end if;
1283
 
1284
         if J /= Val'Last then
1285
            Buffer (Length) := Separator;
1286
            Length := Length + 1;
1287
         end if;
1288
      end loop;
1289
 
1290
      return Buffer (1 .. Length - 1);
1291
   end Image;
1292
 
1293
   -----------
1294
   -- Image --
1295
   -----------
1296
 
1297
   function Image (Value : Inet_Addr_Type) return String is
1298
   begin
1299
      if Value.Family = Family_Inet then
1300
         return Image (Inet_Addr_VN_Type (Value.Sin_V4), Hex => False);
1301
      else
1302
         return Image (Inet_Addr_VN_Type (Value.Sin_V6), Hex => True);
1303
      end if;
1304
   end Image;
1305
 
1306
   -----------
1307
   -- Image --
1308
   -----------
1309
 
1310
   function Image (Value : Sock_Addr_Type) return String is
1311
      Port : constant String := Value.Port'Img;
1312
   begin
1313
      return Image (Value.Addr) & ':' & Port (2 .. Port'Last);
1314
   end Image;
1315
 
1316
   -----------
1317
   -- Image --
1318
   -----------
1319
 
1320
   function Image (Socket : Socket_Type) return String is
1321
   begin
1322
      return Socket'Img;
1323
   end Image;
1324
 
1325
   -----------
1326
   -- Image --
1327
   -----------
1328
 
1329
   function Image (Item : Socket_Set_Type) return String is
1330
      Socket_Set : Socket_Set_Type := Item;
1331
 
1332
   begin
1333
      declare
1334
         Last_Img : constant String := Socket_Set.Last'Img;
1335
         Buffer   : String
1336
                      (1 .. (Integer (Socket_Set.Last) + 1) * Last_Img'Length);
1337
         Index    : Positive := 1;
1338
         Socket   : Socket_Type;
1339
 
1340
      begin
1341
         while not Is_Empty (Socket_Set) loop
1342
            Get (Socket_Set, Socket);
1343
 
1344
            declare
1345
               Socket_Img : constant String := Socket'Img;
1346
            begin
1347
               Buffer (Index .. Index + Socket_Img'Length - 1) := Socket_Img;
1348
               Index := Index + Socket_Img'Length;
1349
            end;
1350
         end loop;
1351
 
1352
         return "[" & Last_Img & "]" & Buffer (1 .. Index - 1);
1353
      end;
1354
   end Image;
1355
 
1356
   ---------------
1357
   -- Inet_Addr --
1358
   ---------------
1359
 
1360
   function Inet_Addr (Image : String) return Inet_Addr_Type is
1361
      use Interfaces.C;
1362
      use Interfaces.C.Strings;
1363
 
1364
      Img    : aliased char_array := To_C (Image);
1365
      Addr   : aliased C.int;
1366
      Res    : C.int;
1367
      Result : Inet_Addr_Type;
1368
 
1369
   begin
1370
      --  Special case for an empty Image as on some platforms (e.g. Windows)
1371
      --  calling Inet_Addr("") will not return an error.
1372
 
1373
      if Image = "" then
1374
         Raise_Socket_Error (SOSC.EINVAL);
1375
      end if;
1376
 
1377
      Res := Inet_Pton (SOSC.AF_INET, Img'Address, Addr'Address);
1378
 
1379
      if Res < 0 then
1380
         Raise_Socket_Error (Socket_Errno);
1381
 
1382
      elsif Res = 0 then
1383
         Raise_Socket_Error (SOSC.EINVAL);
1384
      end if;
1385
 
1386
      To_Inet_Addr (To_In_Addr (Addr), Result);
1387
      return Result;
1388
   end Inet_Addr;
1389
 
1390
   ----------------
1391
   -- Initialize --
1392
   ----------------
1393
 
1394
   procedure Initialize (X : in out Sockets_Library_Controller) is
1395
      pragma Unreferenced (X);
1396
 
1397
   begin
1398
      Thin.Initialize;
1399
   end Initialize;
1400
 
1401
   ----------------
1402
   -- Initialize --
1403
   ----------------
1404
 
1405
   procedure Initialize (Process_Blocking_IO : Boolean) is
1406
      Expected : constant Boolean := not SOSC.Thread_Blocking_IO;
1407
 
1408
   begin
1409
      if Process_Blocking_IO /= Expected then
1410
         raise Socket_Error with
1411
           "incorrect Process_Blocking_IO setting, expected " & Expected'Img;
1412
      end if;
1413
 
1414
      --  This is a dummy placeholder for an obsolete API
1415
 
1416
      --  Real initialization actions are in Initialize primitive operation
1417
      --  of Sockets_Library_Controller.
1418
 
1419
      null;
1420
   end Initialize;
1421
 
1422
   ----------------
1423
   -- Initialize --
1424
   ----------------
1425
 
1426
   procedure Initialize is
1427
   begin
1428
      --  This is a dummy placeholder for an obsolete API
1429
 
1430
      --  Real initialization actions are in Initialize primitive operation
1431
      --  of Sockets_Library_Controller.
1432
 
1433
      null;
1434
   end Initialize;
1435
 
1436
   --------------
1437
   -- Is_Empty --
1438
   --------------
1439
 
1440
   function Is_Empty (Item : Socket_Set_Type) return Boolean is
1441
   begin
1442
      return Item.Last = No_Socket;
1443
   end Is_Empty;
1444
 
1445
   -------------------
1446
   -- Is_IP_Address --
1447
   -------------------
1448
 
1449
   function Is_IP_Address (Name : String) return Boolean is
1450
   begin
1451
      for J in Name'Range loop
1452
         if Name (J) /= '.'
1453
           and then Name (J) not in '0' .. '9'
1454
         then
1455
            return False;
1456
         end if;
1457
      end loop;
1458
 
1459
      return True;
1460
   end Is_IP_Address;
1461
 
1462
   -------------
1463
   -- Is_Open --
1464
   -------------
1465
 
1466
   function Is_Open (S : Selector_Type) return Boolean is
1467
   begin
1468
      if S.Is_Null then
1469
         return True;
1470
 
1471
      else
1472
         --  Either both controlling socket descriptors are valid (case of an
1473
         --  open selector) or neither (case of a closed selector).
1474
 
1475
         pragma Assert ((S.R_Sig_Socket /= No_Socket)
1476
                          =
1477
                        (S.W_Sig_Socket /= No_Socket));
1478
 
1479
         return S.R_Sig_Socket /= No_Socket;
1480
      end if;
1481
   end Is_Open;
1482
 
1483
   ------------
1484
   -- Is_Set --
1485
   ------------
1486
 
1487
   function Is_Set
1488
     (Item   : Socket_Set_Type;
1489
      Socket : Socket_Type) return Boolean
1490
   is
1491
   begin
1492
      Check_For_Fd_Set (Socket);
1493
 
1494
      return Item.Last /= No_Socket
1495
        and then Socket <= Item.Last
1496
        and then Is_Socket_In_Set (Item.Set'Access, C.int (Socket)) /= 0;
1497
   end Is_Set;
1498
 
1499
   -------------------
1500
   -- Listen_Socket --
1501
   -------------------
1502
 
1503
   procedure Listen_Socket
1504
     (Socket : Socket_Type;
1505
      Length : Natural := 15)
1506
   is
1507
      Res : constant C.int := C_Listen (C.int (Socket), C.int (Length));
1508
   begin
1509
      if Res = Failure then
1510
         Raise_Socket_Error (Socket_Errno);
1511
      end if;
1512
   end Listen_Socket;
1513
 
1514
   ------------
1515
   -- Narrow --
1516
   ------------
1517
 
1518
   procedure Narrow (Item : in out Socket_Set_Type) is
1519
      Last : aliased C.int := C.int (Item.Last);
1520
   begin
1521
      if Item.Last /= No_Socket then
1522
         Last_Socket_In_Set (Item.Set'Access, Last'Unchecked_Access);
1523
         Item.Last := Socket_Type (Last);
1524
      end if;
1525
   end Narrow;
1526
 
1527
   ----------------
1528
   -- Netdb_Lock --
1529
   ----------------
1530
 
1531
   procedure Netdb_Lock is
1532
   begin
1533
      if Need_Netdb_Lock then
1534
         System.Task_Lock.Lock;
1535
      end if;
1536
   end Netdb_Lock;
1537
 
1538
   ------------------
1539
   -- Netdb_Unlock --
1540
   ------------------
1541
 
1542
   procedure Netdb_Unlock is
1543
   begin
1544
      if Need_Netdb_Lock then
1545
         System.Task_Lock.Unlock;
1546
      end if;
1547
   end Netdb_Unlock;
1548
 
1549
   --------------------------------
1550
   -- Normalize_Empty_Socket_Set --
1551
   --------------------------------
1552
 
1553
   procedure Normalize_Empty_Socket_Set (S : in out Socket_Set_Type) is
1554
   begin
1555
      if S.Last = No_Socket then
1556
         Reset_Socket_Set (S.Set'Access);
1557
      end if;
1558
   end Normalize_Empty_Socket_Set;
1559
 
1560
   -------------------
1561
   -- Official_Name --
1562
   -------------------
1563
 
1564
   function Official_Name (E : Host_Entry_Type) return String is
1565
   begin
1566
      return To_String (E.Official);
1567
   end Official_Name;
1568
 
1569
   -------------------
1570
   -- Official_Name --
1571
   -------------------
1572
 
1573
   function Official_Name (S : Service_Entry_Type) return String is
1574
   begin
1575
      return To_String (S.Official);
1576
   end Official_Name;
1577
 
1578
   --------------------
1579
   -- Wait_On_Socket --
1580
   --------------------
1581
 
1582
   procedure Wait_On_Socket
1583
     (Socket   : Socket_Type;
1584
      For_Read : Boolean;
1585
      Timeout  : Selector_Duration;
1586
      Selector : access Selector_Type := null;
1587
      Status   : out Selector_Status)
1588
   is
1589
      type Local_Selector_Access is access Selector_Type;
1590
      for Local_Selector_Access'Storage_Size use Selector_Type'Size;
1591
 
1592
      S : Selector_Access;
1593
      --  Selector to use for waiting
1594
 
1595
      R_Fd_Set : Socket_Set_Type;
1596
      W_Fd_Set : Socket_Set_Type;
1597
 
1598
   begin
1599
      --  Create selector if not provided by the user
1600
 
1601
      if Selector = null then
1602
         declare
1603
            Local_S : constant Local_Selector_Access := new Selector_Type;
1604
         begin
1605
            S := Local_S.all'Unchecked_Access;
1606
            Create_Selector (S.all);
1607
         end;
1608
 
1609
      else
1610
         S := Selector.all'Access;
1611
      end if;
1612
 
1613
      if For_Read then
1614
         Set (R_Fd_Set, Socket);
1615
      else
1616
         Set (W_Fd_Set, Socket);
1617
      end if;
1618
 
1619
      Check_Selector (S.all, R_Fd_Set, W_Fd_Set, Status, Timeout);
1620
 
1621
      if Selector = null then
1622
         Close_Selector (S.all);
1623
      end if;
1624
   end Wait_On_Socket;
1625
 
1626
   -----------------
1627
   -- Port_Number --
1628
   -----------------
1629
 
1630
   function Port_Number (S : Service_Entry_Type) return Port_Type is
1631
   begin
1632
      return S.Port;
1633
   end Port_Number;
1634
 
1635
   -------------------
1636
   -- Protocol_Name --
1637
   -------------------
1638
 
1639
   function Protocol_Name (S : Service_Entry_Type) return String is
1640
   begin
1641
      return To_String (S.Protocol);
1642
   end Protocol_Name;
1643
 
1644
   ----------------------
1645
   -- Raise_Host_Error --
1646
   ----------------------
1647
 
1648
   procedure Raise_Host_Error (H_Error : Integer) is
1649
   begin
1650
      raise Host_Error with
1651
        Err_Code_Image (H_Error)
1652
        & C.Strings.Value (Host_Error_Messages.Host_Error_Message (H_Error));
1653
   end Raise_Host_Error;
1654
 
1655
   ------------------------
1656
   -- Raise_Socket_Error --
1657
   ------------------------
1658
 
1659
   procedure Raise_Socket_Error (Error : Integer) is
1660
      use type C.Strings.chars_ptr;
1661
   begin
1662
      raise Socket_Error with
1663
        Err_Code_Image (Error)
1664
        & C.Strings.Value (Socket_Error_Message (Error));
1665
   end Raise_Socket_Error;
1666
 
1667
   ----------
1668
   -- Read --
1669
   ----------
1670
 
1671
   procedure Read
1672
     (Stream : in out Datagram_Socket_Stream_Type;
1673
      Item   : out Ada.Streams.Stream_Element_Array;
1674
      Last   : out Ada.Streams.Stream_Element_Offset)
1675
   is
1676
      First : Ada.Streams.Stream_Element_Offset          := Item'First;
1677
      Index : Ada.Streams.Stream_Element_Offset          := First - 1;
1678
      Max   : constant Ada.Streams.Stream_Element_Offset := Item'Last;
1679
 
1680
   begin
1681
      loop
1682
         Receive_Socket
1683
           (Stream.Socket,
1684
            Item (First .. Max),
1685
            Index,
1686
            Stream.From);
1687
 
1688
         Last := Index;
1689
 
1690
         --  Exit when all or zero data received. Zero means that the socket
1691
         --  peer is closed.
1692
 
1693
         exit when Index < First or else Index = Max;
1694
 
1695
         First := Index + 1;
1696
      end loop;
1697
   end Read;
1698
 
1699
   ----------
1700
   -- Read --
1701
   ----------
1702
 
1703
   procedure Read
1704
     (Stream : in out Stream_Socket_Stream_Type;
1705
      Item   : out Ada.Streams.Stream_Element_Array;
1706
      Last   : out Ada.Streams.Stream_Element_Offset)
1707
   is
1708
      pragma Warnings (Off, Stream);
1709
 
1710
      First : Ada.Streams.Stream_Element_Offset          := Item'First;
1711
      Index : Ada.Streams.Stream_Element_Offset          := First - 1;
1712
      Max   : constant Ada.Streams.Stream_Element_Offset := Item'Last;
1713
 
1714
   begin
1715
      loop
1716
         Receive_Socket (Stream.Socket, Item (First .. Max), Index);
1717
         Last  := Index;
1718
 
1719
         --  Exit when all or zero data received. Zero means that the socket
1720
         --  peer is closed.
1721
 
1722
         exit when Index < First or else Index = Max;
1723
 
1724
         First := Index + 1;
1725
      end loop;
1726
   end Read;
1727
 
1728
   --------------------
1729
   -- Receive_Socket --
1730
   --------------------
1731
 
1732
   procedure Receive_Socket
1733
     (Socket : Socket_Type;
1734
      Item   : out Ada.Streams.Stream_Element_Array;
1735
      Last   : out Ada.Streams.Stream_Element_Offset;
1736
      Flags  : Request_Flag_Type := No_Request_Flag)
1737
   is
1738
      Res : C.int;
1739
 
1740
   begin
1741
      Res :=
1742
        C_Recv (C.int (Socket), Item'Address, Item'Length, To_Int (Flags));
1743
 
1744
      if Res = Failure then
1745
         Raise_Socket_Error (Socket_Errno);
1746
      end if;
1747
 
1748
      Last := Last_Index (First => Item'First, Count => size_t (Res));
1749
   end Receive_Socket;
1750
 
1751
   --------------------
1752
   -- Receive_Socket --
1753
   --------------------
1754
 
1755
   procedure Receive_Socket
1756
     (Socket : Socket_Type;
1757
      Item   : out Ada.Streams.Stream_Element_Array;
1758
      Last   : out Ada.Streams.Stream_Element_Offset;
1759
      From   : out Sock_Addr_Type;
1760
      Flags  : Request_Flag_Type := No_Request_Flag)
1761
   is
1762
      Res : C.int;
1763
      Sin : aliased Sockaddr_In;
1764
      Len : aliased C.int := Sin'Size / 8;
1765
 
1766
   begin
1767
      Res :=
1768
        C_Recvfrom
1769
          (C.int (Socket),
1770
           Item'Address,
1771
           Item'Length,
1772
           To_Int (Flags),
1773
           Sin'Address,
1774
           Len'Access);
1775
 
1776
      if Res = Failure then
1777
         Raise_Socket_Error (Socket_Errno);
1778
      end if;
1779
 
1780
      Last := Last_Index (First => Item'First, Count => size_t (Res));
1781
 
1782
      To_Inet_Addr (Sin.Sin_Addr, From.Addr);
1783
      From.Port := Port_Type (Network_To_Short (Sin.Sin_Port));
1784
   end Receive_Socket;
1785
 
1786
   --------------------
1787
   -- Receive_Vector --
1788
   --------------------
1789
 
1790
   procedure Receive_Vector
1791
     (Socket : Socket_Type;
1792
      Vector : Vector_Type;
1793
      Count  : out Ada.Streams.Stream_Element_Count;
1794
      Flags  : Request_Flag_Type := No_Request_Flag)
1795
   is
1796
      Res : ssize_t;
1797
 
1798
      Msg : Msghdr :=
1799
              (Msg_Name       => System.Null_Address,
1800
               Msg_Namelen    => 0,
1801
               Msg_Iov        => Vector'Address,
1802
 
1803
               --  recvmsg(2) returns EMSGSIZE on Linux (and probably on other
1804
               --  platforms) when the supplied vector is longer than IOV_MAX,
1805
               --  so use minimum of the two lengths.
1806
 
1807
               Msg_Iovlen     => SOSC.Msg_Iovlen_T'Min
1808
                                   (Vector'Length, SOSC.IOV_MAX),
1809
 
1810
               Msg_Control    => System.Null_Address,
1811
               Msg_Controllen => 0,
1812
               Msg_Flags      => 0);
1813
 
1814
   begin
1815
      Res :=
1816
        C_Recvmsg
1817
          (C.int (Socket),
1818
           Msg'Address,
1819
           To_Int (Flags));
1820
 
1821
      if Res = ssize_t (Failure) then
1822
         Raise_Socket_Error (Socket_Errno);
1823
      end if;
1824
 
1825
      Count := Ada.Streams.Stream_Element_Count (Res);
1826
   end Receive_Vector;
1827
 
1828
   -------------------
1829
   -- Resolve_Error --
1830
   -------------------
1831
 
1832
   function Resolve_Error
1833
     (Error_Value : Integer;
1834
      From_Errno  : Boolean := True) return Error_Type
1835
   is
1836
      use GNAT.Sockets.SOSC;
1837
 
1838
   begin
1839
      if not From_Errno then
1840
         case Error_Value is
1841
            when SOSC.HOST_NOT_FOUND => return Unknown_Host;
1842
            when SOSC.TRY_AGAIN      => return Host_Name_Lookup_Failure;
1843
            when SOSC.NO_RECOVERY    => return Non_Recoverable_Error;
1844
            when SOSC.NO_DATA        => return Unknown_Server_Error;
1845
            when others              => return Cannot_Resolve_Error;
1846
         end case;
1847
      end if;
1848
 
1849
      --  Special case: EAGAIN may be the same value as EWOULDBLOCK, so we
1850
      --  can't include it in the case statement below.
1851
 
1852
      pragma Warnings (Off);
1853
      --  Condition "EAGAIN /= EWOULDBLOCK" is known at compile time
1854
 
1855
      if EAGAIN /= EWOULDBLOCK and then Error_Value = EAGAIN then
1856
         return Resource_Temporarily_Unavailable;
1857
      end if;
1858
 
1859
      --  This is not a case statement because if a particular error
1860
      --  number constant is not defined, s-oscons-tmplt.c defines
1861
      --  it to -1.  If multiple constants are not defined, they
1862
      --  would each be -1 and result in a "duplicate value in case" error.
1863
      --
1864
      --  But we have to leave warnings off because the compiler is also
1865
      --  smart enough to note that when two errnos have the same value,
1866
      --  the second if condition is useless.
1867
      if Error_Value = ENOERROR then
1868
         return Success;
1869
      elsif Error_Value = EACCES then
1870
         return Permission_Denied;
1871
      elsif Error_Value = EADDRINUSE then
1872
         return Address_Already_In_Use;
1873
      elsif Error_Value = EADDRNOTAVAIL then
1874
         return Cannot_Assign_Requested_Address;
1875
      elsif Error_Value = EAFNOSUPPORT then
1876
         return Address_Family_Not_Supported_By_Protocol;
1877
      elsif Error_Value = EALREADY then
1878
         return Operation_Already_In_Progress;
1879
      elsif Error_Value = EBADF then
1880
         return Bad_File_Descriptor;
1881
      elsif Error_Value = ECONNABORTED then
1882
         return Software_Caused_Connection_Abort;
1883
      elsif Error_Value = ECONNREFUSED then
1884
         return Connection_Refused;
1885
      elsif Error_Value = ECONNRESET then
1886
         return Connection_Reset_By_Peer;
1887
      elsif Error_Value = EDESTADDRREQ then
1888
         return Destination_Address_Required;
1889
      elsif Error_Value = EFAULT then
1890
         return Bad_Address;
1891
      elsif Error_Value = EHOSTDOWN then
1892
         return Host_Is_Down;
1893
      elsif Error_Value = EHOSTUNREACH then
1894
         return No_Route_To_Host;
1895
      elsif Error_Value = EINPROGRESS then
1896
         return Operation_Now_In_Progress;
1897
      elsif Error_Value = EINTR then
1898
         return Interrupted_System_Call;
1899
      elsif Error_Value = EINVAL then
1900
         return Invalid_Argument;
1901
      elsif Error_Value = EIO then
1902
         return Input_Output_Error;
1903
      elsif Error_Value = EISCONN then
1904
         return Transport_Endpoint_Already_Connected;
1905
      elsif Error_Value = ELOOP then
1906
         return Too_Many_Symbolic_Links;
1907
      elsif Error_Value = EMFILE then
1908
         return Too_Many_Open_Files;
1909
      elsif Error_Value = EMSGSIZE then
1910
         return Message_Too_Long;
1911
      elsif Error_Value = ENAMETOOLONG then
1912
         return File_Name_Too_Long;
1913
      elsif Error_Value = ENETDOWN then
1914
         return Network_Is_Down;
1915
      elsif Error_Value = ENETRESET then
1916
         return Network_Dropped_Connection_Because_Of_Reset;
1917
      elsif Error_Value = ENETUNREACH then
1918
         return Network_Is_Unreachable;
1919
      elsif Error_Value = ENOBUFS then
1920
         return No_Buffer_Space_Available;
1921
      elsif Error_Value = ENOPROTOOPT then
1922
         return Protocol_Not_Available;
1923
      elsif Error_Value = ENOTCONN then
1924
         return Transport_Endpoint_Not_Connected;
1925
      elsif Error_Value = ENOTSOCK then
1926
         return Socket_Operation_On_Non_Socket;
1927
      elsif Error_Value = EOPNOTSUPP then
1928
         return Operation_Not_Supported;
1929
      elsif Error_Value = EPFNOSUPPORT then
1930
         return Protocol_Family_Not_Supported;
1931
      elsif Error_Value = EPIPE then
1932
         return Broken_Pipe;
1933
      elsif Error_Value = EPROTONOSUPPORT then
1934
         return Protocol_Not_Supported;
1935
      elsif Error_Value = EPROTOTYPE then
1936
         return Protocol_Wrong_Type_For_Socket;
1937
      elsif Error_Value = ESHUTDOWN then
1938
         return Cannot_Send_After_Transport_Endpoint_Shutdown;
1939
      elsif Error_Value = ESOCKTNOSUPPORT then
1940
         return Socket_Type_Not_Supported;
1941
      elsif Error_Value = ETIMEDOUT then
1942
         return Connection_Timed_Out;
1943
      elsif Error_Value = ETOOMANYREFS then
1944
         return Too_Many_References;
1945
      elsif Error_Value = EWOULDBLOCK then
1946
         return Resource_Temporarily_Unavailable;
1947
      else
1948
         return Cannot_Resolve_Error;
1949
      end if;
1950
      pragma Warnings (On);
1951
 
1952
   end Resolve_Error;
1953
 
1954
   -----------------------
1955
   -- Resolve_Exception --
1956
   -----------------------
1957
 
1958
   function Resolve_Exception
1959
     (Occurrence : Exception_Occurrence) return Error_Type
1960
   is
1961
      Id    : constant Exception_Id := Exception_Identity (Occurrence);
1962
      Msg   : constant String       := Exception_Message (Occurrence);
1963
      First : Natural;
1964
      Last  : Natural;
1965
      Val   : Integer;
1966
 
1967
   begin
1968
      First := Msg'First;
1969
      while First <= Msg'Last
1970
        and then Msg (First) not in '0' .. '9'
1971
      loop
1972
         First := First + 1;
1973
      end loop;
1974
 
1975
      if First > Msg'Last then
1976
         return Cannot_Resolve_Error;
1977
      end if;
1978
 
1979
      Last := First;
1980
      while Last < Msg'Last
1981
        and then Msg (Last + 1) in '0' .. '9'
1982
      loop
1983
         Last := Last + 1;
1984
      end loop;
1985
 
1986
      Val := Integer'Value (Msg (First .. Last));
1987
 
1988
      if Id = Socket_Error_Id then
1989
         return Resolve_Error (Val);
1990
 
1991
      elsif Id = Host_Error_Id then
1992
         return Resolve_Error (Val, False);
1993
 
1994
      else
1995
         return Cannot_Resolve_Error;
1996
      end if;
1997
   end Resolve_Exception;
1998
 
1999
   -----------------
2000
   -- Send_Socket --
2001
   -----------------
2002
 
2003
   procedure Send_Socket
2004
     (Socket : Socket_Type;
2005
      Item   : Ada.Streams.Stream_Element_Array;
2006
      Last   : out Ada.Streams.Stream_Element_Offset;
2007
      Flags  : Request_Flag_Type := No_Request_Flag)
2008
   is
2009
   begin
2010
      Send_Socket (Socket, Item, Last, To => null, Flags => Flags);
2011
   end Send_Socket;
2012
 
2013
   -----------------
2014
   -- Send_Socket --
2015
   -----------------
2016
 
2017
   procedure Send_Socket
2018
     (Socket : Socket_Type;
2019
      Item   : Ada.Streams.Stream_Element_Array;
2020
      Last   : out Ada.Streams.Stream_Element_Offset;
2021
      To     : Sock_Addr_Type;
2022
      Flags  : Request_Flag_Type := No_Request_Flag)
2023
   is
2024
   begin
2025
      Send_Socket
2026
        (Socket, Item, Last, To => To'Unrestricted_Access, Flags => Flags);
2027
   end Send_Socket;
2028
 
2029
   -----------------
2030
   -- Send_Socket --
2031
   -----------------
2032
 
2033
   procedure Send_Socket
2034
     (Socket : Socket_Type;
2035
      Item   : Ada.Streams.Stream_Element_Array;
2036
      Last   : out Ada.Streams.Stream_Element_Offset;
2037
      To     : access Sock_Addr_Type;
2038
      Flags  : Request_Flag_Type := No_Request_Flag)
2039
   is
2040
      Res  : C.int;
2041
 
2042
      Sin  : aliased Sockaddr_In;
2043
      C_To : System.Address;
2044
      Len  : C.int;
2045
 
2046
   begin
2047
      if To /= null then
2048
         Set_Family  (Sin.Sin_Family, To.Family);
2049
         Set_Address (Sin'Unchecked_Access, To_In_Addr (To.Addr));
2050
         Set_Port
2051
           (Sin'Unchecked_Access,
2052
            Short_To_Network (C.unsigned_short (To.Port)));
2053
         C_To := Sin'Address;
2054
         Len := Sin'Size / 8;
2055
 
2056
      else
2057
         C_To := System.Null_Address;
2058
         Len := 0;
2059
      end if;
2060
 
2061
      Res := C_Sendto
2062
        (C.int (Socket),
2063
         Item'Address,
2064
         Item'Length,
2065
         Set_Forced_Flags (To_Int (Flags)),
2066
         C_To,
2067
         Len);
2068
 
2069
      if Res = Failure then
2070
         Raise_Socket_Error (Socket_Errno);
2071
      end if;
2072
 
2073
      Last := Last_Index (First => Item'First, Count => size_t (Res));
2074
   end Send_Socket;
2075
 
2076
   -----------------
2077
   -- Send_Vector --
2078
   -----------------
2079
 
2080
   procedure Send_Vector
2081
     (Socket : Socket_Type;
2082
      Vector : Vector_Type;
2083
      Count  : out Ada.Streams.Stream_Element_Count;
2084
      Flags  : Request_Flag_Type := No_Request_Flag)
2085
   is
2086
      use SOSC;
2087
      use Interfaces.C;
2088
 
2089
      Res            : ssize_t;
2090
      Iov_Count      : SOSC.Msg_Iovlen_T;
2091
      This_Iov_Count : SOSC.Msg_Iovlen_T;
2092
      Msg            : Msghdr;
2093
 
2094
   begin
2095
      Count := 0;
2096
      Iov_Count := 0;
2097
      while Iov_Count < Vector'Length loop
2098
 
2099
         pragma Warnings (Off);
2100
         --  Following test may be compile time known on some targets
2101
 
2102
         This_Iov_Count :=
2103
           (if Vector'Length - Iov_Count > SOSC.IOV_MAX
2104
            then SOSC.IOV_MAX
2105
            else Vector'Length - Iov_Count);
2106
 
2107
         pragma Warnings (On);
2108
 
2109
         Msg :=
2110
           (Msg_Name       => System.Null_Address,
2111
            Msg_Namelen    => 0,
2112
            Msg_Iov        => Vector
2113
                                (Vector'First + Integer (Iov_Count))'Address,
2114
            Msg_Iovlen     => This_Iov_Count,
2115
            Msg_Control    => System.Null_Address,
2116
            Msg_Controllen => 0,
2117
            Msg_Flags      => 0);
2118
 
2119
         Res :=
2120
           C_Sendmsg
2121
             (C.int (Socket),
2122
              Msg'Address,
2123
              Set_Forced_Flags (To_Int (Flags)));
2124
 
2125
         if Res = ssize_t (Failure) then
2126
            Raise_Socket_Error (Socket_Errno);
2127
         end if;
2128
 
2129
         Count := Count + Ada.Streams.Stream_Element_Count (Res);
2130
         Iov_Count := Iov_Count + This_Iov_Count;
2131
      end loop;
2132
   end Send_Vector;
2133
 
2134
   ---------
2135
   -- Set --
2136
   ---------
2137
 
2138
   procedure Set (Item : in out Socket_Set_Type; Socket : Socket_Type) is
2139
   begin
2140
      Check_For_Fd_Set (Socket);
2141
 
2142
      if Item.Last = No_Socket then
2143
 
2144
         --  Uninitialized socket set, make sure it is properly zeroed out
2145
 
2146
         Reset_Socket_Set (Item.Set'Access);
2147
         Item.Last := Socket;
2148
 
2149
      elsif Item.Last < Socket then
2150
         Item.Last := Socket;
2151
      end if;
2152
 
2153
      Insert_Socket_In_Set (Item.Set'Access, C.int (Socket));
2154
   end Set;
2155
 
2156
   ----------------------
2157
   -- Set_Forced_Flags --
2158
   ----------------------
2159
 
2160
   function Set_Forced_Flags (F : C.int) return C.int is
2161
      use type C.unsigned;
2162
      function To_unsigned is
2163
        new Ada.Unchecked_Conversion (C.int, C.unsigned);
2164
      function To_int is
2165
        new Ada.Unchecked_Conversion (C.unsigned, C.int);
2166
   begin
2167
      return To_int (To_unsigned (F) or SOSC.MSG_Forced_Flags);
2168
   end Set_Forced_Flags;
2169
 
2170
   -----------------------
2171
   -- Set_Socket_Option --
2172
   -----------------------
2173
 
2174
   procedure Set_Socket_Option
2175
     (Socket : Socket_Type;
2176
      Level  : Level_Type := Socket_Level;
2177
      Option : Option_Type)
2178
   is
2179
      V8  : aliased Two_Ints;
2180
      V4  : aliased C.int;
2181
      V1  : aliased C.unsigned_char;
2182
      VT  : aliased Timeval;
2183
      Len : C.int;
2184
      Add : System.Address := Null_Address;
2185
      Res : C.int;
2186
 
2187
   begin
2188
      case Option.Name is
2189
         when Keep_Alive      |
2190
              Reuse_Address   |
2191
              Broadcast       |
2192
              No_Delay        =>
2193
            V4  := C.int (Boolean'Pos (Option.Enabled));
2194
            Len := V4'Size / 8;
2195
            Add := V4'Address;
2196
 
2197
         when Linger          =>
2198
            V8 (V8'First) := C.int (Boolean'Pos (Option.Enabled));
2199
            V8 (V8'Last)  := C.int (Option.Seconds);
2200
            Len := V8'Size / 8;
2201
            Add := V8'Address;
2202
 
2203
         when Send_Buffer     |
2204
              Receive_Buffer  =>
2205
            V4  := C.int (Option.Size);
2206
            Len := V4'Size / 8;
2207
            Add := V4'Address;
2208
 
2209
         when Error           =>
2210
            V4  := C.int (Boolean'Pos (True));
2211
            Len := V4'Size / 8;
2212
            Add := V4'Address;
2213
 
2214
         when Add_Membership  |
2215
              Drop_Membership =>
2216
            V8 (V8'First) := To_Int (To_In_Addr (Option.Multicast_Address));
2217
            V8 (V8'Last)  := To_Int (To_In_Addr (Option.Local_Interface));
2218
            Len := V8'Size / 8;
2219
            Add := V8'Address;
2220
 
2221
         when Multicast_If    =>
2222
            V4  := To_Int (To_In_Addr (Option.Outgoing_If));
2223
            Len := V4'Size / 8;
2224
            Add := V4'Address;
2225
 
2226
         when Multicast_TTL   =>
2227
            V1  := C.unsigned_char (Option.Time_To_Live);
2228
            Len := V1'Size / 8;
2229
            Add := V1'Address;
2230
 
2231
         when Multicast_Loop      |
2232
              Receive_Packet_Info =>
2233
            V1  := C.unsigned_char (Boolean'Pos (Option.Enabled));
2234
            Len := V1'Size / 8;
2235
            Add := V1'Address;
2236
 
2237
         when Send_Timeout    |
2238
              Receive_Timeout =>
2239
            VT  := To_Timeval (Option.Timeout);
2240
            Len := VT'Size / 8;
2241
            Add := VT'Address;
2242
 
2243
      end case;
2244
 
2245
      Res := C_Setsockopt
2246
        (C.int (Socket),
2247
         Levels (Level),
2248
         Options (Option.Name),
2249
         Add, Len);
2250
 
2251
      if Res = Failure then
2252
         Raise_Socket_Error (Socket_Errno);
2253
      end if;
2254
   end Set_Socket_Option;
2255
 
2256
   ----------------------
2257
   -- Short_To_Network --
2258
   ----------------------
2259
 
2260
   function Short_To_Network (S : C.unsigned_short) return C.unsigned_short is
2261
      use type C.unsigned_short;
2262
 
2263
   begin
2264
      --  Big-endian case. No conversion needed. On these platforms,
2265
      --  htons() defaults to a null procedure.
2266
 
2267
      pragma Warnings (Off);
2268
      --  Since the test can generate "always True/False" warning
2269
 
2270
      if Default_Bit_Order = High_Order_First then
2271
         return S;
2272
 
2273
         pragma Warnings (On);
2274
 
2275
      --  Little-endian case. We must swap the high and low bytes of this
2276
      --  short to make the port number network compliant.
2277
 
2278
      else
2279
         return (S / 256) + (S mod 256) * 256;
2280
      end if;
2281
   end Short_To_Network;
2282
 
2283
   ---------------------
2284
   -- Shutdown_Socket --
2285
   ---------------------
2286
 
2287
   procedure Shutdown_Socket
2288
     (Socket : Socket_Type;
2289
      How    : Shutmode_Type := Shut_Read_Write)
2290
   is
2291
      Res : C.int;
2292
 
2293
   begin
2294
      Res := C_Shutdown (C.int (Socket), Shutmodes (How));
2295
 
2296
      if Res = Failure then
2297
         Raise_Socket_Error (Socket_Errno);
2298
      end if;
2299
   end Shutdown_Socket;
2300
 
2301
   ------------
2302
   -- Stream --
2303
   ------------
2304
 
2305
   function Stream
2306
     (Socket  : Socket_Type;
2307
      Send_To : Sock_Addr_Type) return Stream_Access
2308
   is
2309
      S : Datagram_Socket_Stream_Access;
2310
 
2311
   begin
2312
      S        := new Datagram_Socket_Stream_Type;
2313
      S.Socket := Socket;
2314
      S.To     := Send_To;
2315
      S.From   := Get_Socket_Name (Socket);
2316
      return Stream_Access (S);
2317
   end Stream;
2318
 
2319
   ------------
2320
   -- Stream --
2321
   ------------
2322
 
2323
   function Stream (Socket : Socket_Type) return Stream_Access is
2324
      S : Stream_Socket_Stream_Access;
2325
   begin
2326
      S := new Stream_Socket_Stream_Type;
2327
      S.Socket := Socket;
2328
      return Stream_Access (S);
2329
   end Stream;
2330
 
2331
   ------------------
2332
   -- Stream_Write --
2333
   ------------------
2334
 
2335
   procedure Stream_Write
2336
     (Socket : Socket_Type;
2337
      Item   : Ada.Streams.Stream_Element_Array;
2338
      To     : access Sock_Addr_Type)
2339
   is
2340
      First : Ada.Streams.Stream_Element_Offset;
2341
      Index : Ada.Streams.Stream_Element_Offset;
2342
      Max   : constant Ada.Streams.Stream_Element_Offset := Item'Last;
2343
 
2344
   begin
2345
      First := Item'First;
2346
      Index := First - 1;
2347
      while First <= Max loop
2348
         Send_Socket (Socket, Item (First .. Max), Index, To);
2349
 
2350
         --  Exit when all or zero data sent. Zero means that the socket has
2351
         --  been closed by peer.
2352
 
2353
         exit when Index < First or else Index = Max;
2354
 
2355
         First := Index + 1;
2356
      end loop;
2357
 
2358
      --  For an empty array, we have First > Max, and hence Index >= Max (no
2359
      --  error, the loop above is never executed). After a successful send,
2360
      --  Index = Max. The only remaining case, Index < Max, is therefore
2361
      --  always an actual send failure.
2362
 
2363
      if Index < Max then
2364
         Raise_Socket_Error (Socket_Errno);
2365
      end if;
2366
   end Stream_Write;
2367
 
2368
   ----------
2369
   -- To_C --
2370
   ----------
2371
 
2372
   function To_C (Socket : Socket_Type) return Integer is
2373
   begin
2374
      return Integer (Socket);
2375
   end To_C;
2376
 
2377
   -----------------
2378
   -- To_Duration --
2379
   -----------------
2380
 
2381
   function To_Duration (Val : Timeval) return Timeval_Duration is
2382
   begin
2383
      return Natural (Val.Tv_Sec) * 1.0 + Natural (Val.Tv_Usec) * 1.0E-6;
2384
   end To_Duration;
2385
 
2386
   -------------------
2387
   -- To_Host_Entry --
2388
   -------------------
2389
 
2390
   function To_Host_Entry (E : Hostent_Access) return Host_Entry_Type is
2391
      use type C.size_t;
2392
      use C.Strings;
2393
 
2394
      Aliases_Count, Addresses_Count : Natural;
2395
 
2396
      --  H_Length is not used because it is currently only set to 4
2397
      --  H_Addrtype is always AF_INET
2398
 
2399
   begin
2400
      Aliases_Count := 0;
2401
      while Hostent_H_Alias (E, C.int (Aliases_Count)) /= Null_Address loop
2402
         Aliases_Count := Aliases_Count + 1;
2403
      end loop;
2404
 
2405
      Addresses_Count := 0;
2406
      while Hostent_H_Addr (E, C.int (Addresses_Count)) /= Null_Address loop
2407
         Addresses_Count := Addresses_Count + 1;
2408
      end loop;
2409
 
2410
      return Result : Host_Entry_Type
2411
                        (Aliases_Length   => Aliases_Count,
2412
                         Addresses_Length => Addresses_Count)
2413
      do
2414
         Result.Official := To_Name (Value (Hostent_H_Name (E)));
2415
 
2416
         for J in Result.Aliases'Range loop
2417
            Result.Aliases (J) :=
2418
              To_Name (Value (Hostent_H_Alias
2419
                                (E, C.int (J - Result.Aliases'First))));
2420
         end loop;
2421
 
2422
         for J in Result.Addresses'Range loop
2423
            declare
2424
               Addr : In_Addr;
2425
               for Addr'Address use
2426
                 Hostent_H_Addr (E, C.int (J - Result.Addresses'First));
2427
               pragma Import (Ada, Addr);
2428
            begin
2429
               To_Inet_Addr (Addr, Result.Addresses (J));
2430
            end;
2431
         end loop;
2432
      end return;
2433
   end To_Host_Entry;
2434
 
2435
   ----------------
2436
   -- To_In_Addr --
2437
   ----------------
2438
 
2439
   function To_In_Addr (Addr : Inet_Addr_Type) return In_Addr is
2440
   begin
2441
      if Addr.Family = Family_Inet then
2442
         return (S_B1 => C.unsigned_char (Addr.Sin_V4 (1)),
2443
                 S_B2 => C.unsigned_char (Addr.Sin_V4 (2)),
2444
                 S_B3 => C.unsigned_char (Addr.Sin_V4 (3)),
2445
                 S_B4 => C.unsigned_char (Addr.Sin_V4 (4)));
2446
      end if;
2447
 
2448
      raise Socket_Error with "IPv6 not supported";
2449
   end To_In_Addr;
2450
 
2451
   ------------------
2452
   -- To_Inet_Addr --
2453
   ------------------
2454
 
2455
   procedure To_Inet_Addr
2456
     (Addr   : In_Addr;
2457
      Result : out Inet_Addr_Type) is
2458
   begin
2459
      Result.Sin_V4 (1) := Inet_Addr_Comp_Type (Addr.S_B1);
2460
      Result.Sin_V4 (2) := Inet_Addr_Comp_Type (Addr.S_B2);
2461
      Result.Sin_V4 (3) := Inet_Addr_Comp_Type (Addr.S_B3);
2462
      Result.Sin_V4 (4) := Inet_Addr_Comp_Type (Addr.S_B4);
2463
   end To_Inet_Addr;
2464
 
2465
   ------------
2466
   -- To_Int --
2467
   ------------
2468
 
2469
   function To_Int (F : Request_Flag_Type) return C.int
2470
   is
2471
      Current : Request_Flag_Type := F;
2472
      Result  : C.int := 0;
2473
 
2474
   begin
2475
      for J in Flags'Range loop
2476
         exit when Current = 0;
2477
 
2478
         if Current mod 2 /= 0 then
2479
            if Flags (J) = -1 then
2480
               Raise_Socket_Error (SOSC.EOPNOTSUPP);
2481
            end if;
2482
 
2483
            Result := Result + Flags (J);
2484
         end if;
2485
 
2486
         Current := Current / 2;
2487
      end loop;
2488
 
2489
      return Result;
2490
   end To_Int;
2491
 
2492
   -------------
2493
   -- To_Name --
2494
   -------------
2495
 
2496
   function To_Name (N : String) return Name_Type is
2497
   begin
2498
      return Name_Type'(N'Length, N);
2499
   end To_Name;
2500
 
2501
   ----------------------
2502
   -- To_Service_Entry --
2503
   ----------------------
2504
 
2505
   function To_Service_Entry (E : Servent_Access) return Service_Entry_Type is
2506
      use C.Strings;
2507
      use type C.size_t;
2508
 
2509
      Aliases_Count : Natural;
2510
 
2511
   begin
2512
      Aliases_Count := 0;
2513
      while Servent_S_Alias (E, C.int (Aliases_Count)) /= Null_Address loop
2514
         Aliases_Count := Aliases_Count + 1;
2515
      end loop;
2516
 
2517
      return Result : Service_Entry_Type (Aliases_Length   => Aliases_Count) do
2518
         Result.Official := To_Name (Value (Servent_S_Name (E)));
2519
 
2520
         for J in Result.Aliases'Range loop
2521
            Result.Aliases (J) :=
2522
              To_Name (Value (Servent_S_Alias
2523
                                (E, C.int (J - Result.Aliases'First))));
2524
         end loop;
2525
 
2526
         Result.Protocol := To_Name (Value (Servent_S_Proto (E)));
2527
         Result.Port :=
2528
           Port_Type (Network_To_Short (Servent_S_Port (E)));
2529
      end return;
2530
   end To_Service_Entry;
2531
 
2532
   ---------------
2533
   -- To_String --
2534
   ---------------
2535
 
2536
   function To_String (HN : Name_Type) return String is
2537
   begin
2538
      return HN.Name (1 .. HN.Length);
2539
   end To_String;
2540
 
2541
   ----------------
2542
   -- To_Timeval --
2543
   ----------------
2544
 
2545
   function To_Timeval (Val : Timeval_Duration) return Timeval is
2546
      S  : time_t;
2547
      uS : suseconds_t;
2548
 
2549
   begin
2550
      --  If zero, set result as zero (otherwise it gets rounded down to -1)
2551
 
2552
      if Val = 0.0 then
2553
         S  := 0;
2554
         uS := 0;
2555
 
2556
      --  Normal case where we do round down
2557
 
2558
      else
2559
         S  := time_t (Val - 0.5);
2560
         uS := suseconds_t (1_000_000 * (Val - Selector_Duration (S)));
2561
      end if;
2562
 
2563
      return (S, uS);
2564
   end To_Timeval;
2565
 
2566
   -----------
2567
   -- Value --
2568
   -----------
2569
 
2570
   function Value (S : System.Address) return String is
2571
      Str : String (1 .. Positive'Last);
2572
      for Str'Address use S;
2573
      pragma Import (Ada, Str);
2574
 
2575
      Terminator : Positive := Str'First;
2576
 
2577
   begin
2578
      while Str (Terminator) /= ASCII.NUL loop
2579
         Terminator := Terminator + 1;
2580
      end loop;
2581
 
2582
      return Str (1 .. Terminator - 1);
2583
   end Value;
2584
 
2585
   -----------
2586
   -- Write --
2587
   -----------
2588
 
2589
   procedure Write
2590
     (Stream : in out Datagram_Socket_Stream_Type;
2591
      Item   : Ada.Streams.Stream_Element_Array)
2592
   is
2593
   begin
2594
      Stream_Write (Stream.Socket, Item, To => Stream.To'Unrestricted_Access);
2595
   end Write;
2596
 
2597
   -----------
2598
   -- Write --
2599
   -----------
2600
 
2601
   procedure Write
2602
     (Stream : in out Stream_Socket_Stream_Type;
2603
      Item   : Ada.Streams.Stream_Element_Array)
2604
   is
2605
   begin
2606
      Stream_Write (Stream.Socket, Item, To => null);
2607
   end Write;
2608
 
2609
   Sockets_Library_Controller_Object : Sockets_Library_Controller;
2610
   pragma Unreferenced (Sockets_Library_Controller_Object);
2611
   --  The elaboration and finalization of this object perform the required
2612
   --  initialization and cleanup actions for the sockets library.
2613
 
2614
end GNAT.Sockets;

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.