This change adds a special case to Get_Socket_Option and Set_Socket_Option
to account for a deviation of Windows' behaviour with respect to the
standard sockets API: on that target, SO_RCVTIMEO and SO_SNDTIMEO expect
a DWORD containing a milliseconds count, not a struct timeval, and furthermore
if this milliseconds count is non-zero, then the actual timeout is 500 ms
greater.
No test (timing issue).
Tested on x86_64-pc-linux-gnu, committed on trunk
2012-07-30 Thomas Quinot <[email protected]>
* g-socket.adb (Get_Socket_Option, Set_Socket_Option): On Windows, the
value is a milliseconds count in a DWORD, not a struct timeval.
Index: g-socket.adb
===================================================================
--- g-socket.adb (revision 189974)
+++ g-socket.adb (working copy)
@@ -6,7 +6,7 @@
-- --
-- B o d y --
-- --
--- Copyright (C) 2001-2011, AdaCore --
+-- Copyright (C) 2001-2012, AdaCore --
-- --
-- GNAT is free software; you can redistribute it and/or modify it under --
-- terms of the GNU General Public License as published by the Free Soft- --
@@ -1112,6 +1112,7 @@
Level : Level_Type := Socket_Level;
Name : Option_Name) return Option_Type
is
+ use SOSC;
use type C.unsigned_char;
V8 : aliased Two_Ints;
@@ -1144,9 +1145,23 @@
when Send_Timeout |
Receive_Timeout =>
- Len := VT'Size / 8;
- Add := VT'Address;
+ -- The standard argument for SO_RCVTIMEO and SO_SNDTIMEO is a
+ -- struct timeval, but on Windows it is a milliseconds count in
+ -- a DWORD.
+
+ pragma Warnings (Off);
+ if Target_OS = Windows then
+ pragma Warnings (On);
+
+ Len := V4'Size / 8;
+ Add := V4'Address;
+
+ else
+ Len := VT'Size / 8;
+ Add := VT'Address;
+ end if;
+
when Linger |
Add_Membership |
Drop_Membership =>
@@ -1201,7 +1216,23 @@
when Send_Timeout |
Receive_Timeout =>
- Opt.Timeout := To_Duration (VT);
+
+ pragma Warnings (Off);
+ if Target_OS = Windows then
+ pragma Warnings (On);
+
+ -- Timeout is in milliseconds, actual value is 500 ms +
+ -- returned value (unless it is 0).
+
+ if V4 = 0 then
+ Opt.Timeout := 0.0;
+ else
+ Opt.Timeout := Natural (V4) * 0.001 + 0.500;
+ end if;
+
+ else
+ Opt.Timeout := To_Duration (VT);
+ end if;
end case;
return Opt;
@@ -2176,6 +2207,8 @@
Level : Level_Type := Socket_Level;
Option : Option_Type)
is
+ use SOSC;
+
V8 : aliased Two_Ints;
V4 : aliased C.int;
V1 : aliased C.unsigned_char;
@@ -2236,10 +2269,33 @@
when Send_Timeout |
Receive_Timeout =>
- VT := To_Timeval (Option.Timeout);
- Len := VT'Size / 8;
- Add := VT'Address;
+ pragma Warnings (Off);
+ if Target_OS = Windows then
+ pragma Warnings (On);
+
+ -- On Windows, the timeout is a DWORD in milliseconds, and
+ -- the actual timeout is 500 ms + the given value (unless it
+ -- is 0).
+
+ V4 := C.int (Option.Timeout / 0.001);
+
+ if V4 > 500 then
+ V4 := V4 - 500;
+
+ elsif V4 > 0 then
+ V4 := 1;
+ end if;
+
+ Len := V4'Size / 8;
+ Add := V4'Address;
+
+ else
+ VT := To_Timeval (Option.Timeout);
+ Len := VT'Size / 8;
+ Add := VT'Address;
+ end if;
+
end case;
Res := C_Setsockopt