From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00 autolearn=unavailable autolearn_force=no version=3.4.4 X-Received: by 10.176.2.231 with SMTP id 94mr338945uah.0.1476282218125; Wed, 12 Oct 2016 07:23:38 -0700 (PDT) X-Received: by 10.157.60.144 with SMTP id z16mr166788otc.10.1476282218080; Wed, 12 Oct 2016 07:23:38 -0700 (PDT) Path: eternal-september.org!reader01.eternal-september.org!reader02.eternal-september.org!news.eternal-september.org!news.eternal-september.org!feeder.eternal-september.org!news.glorb.com!g45no206859qte.1!news-out.google.com!w143ni773itb.0!nntp.google.com!o19no304478ito.0!postnews.google.com!glegroupsg2000goo.googlegroups.com!not-for-mail Newsgroups: comp.lang.ada Date: Wed, 12 Oct 2016 07:23:37 -0700 (PDT) Complaints-To: groups-abuse@google.com Injection-Info: glegroupsg2000goo.googlegroups.com; posting-host=2a02:120b:c3ee:e540:f806:212b:2dfc:b2eb; posting-account=DQbqYQoAAACn8hHn2LmG2aF7Mhbxl_Lf NNTP-Posting-Host: 2a02:120b:c3ee:e540:f806:212b:2dfc:b2eb User-Agent: G2/1.0 MIME-Version: 1.0 Message-ID: <4a05ca67-2ecc-4907-a817-38071dba832b@googlegroups.com> Subject: Gnat Sockets - UDP timeout too short. From: ahlan@marriott.org Injection-Date: Wed, 12 Oct 2016 14:23:38 +0000 Content-Type: text/plain; charset=UTF-8 Xref: news.eternal-september.org comp.lang.ada:32075 Date: 2016-10-12T07:23:37-07:00 List-Id: Under Microsoft Windows 8.1 (and later) Gnat.Sockets.Receive_Socket returns too early whilst waiting for a UDP datagram. In our test program (below) we create a UDP socket, set the timeout for one second, bind it to a port and then call receive on the socket. We catch and resolve the Socket_Error exception and process the expected Connection_Timed_Out. We note the time before issuing Receive_Socket and the time when we catch the exception and then compare the elapsed time with the receive timeout. On Window systems prior to Win8.1 this seems to work as expected, the elapsed time is always greater than the receive timeout. However under Win8.1 (and later) the call to Receive_Socket returns approximately half a second too early! Curiously, if I write the same thing using the Win32.WinSock API then it works as expected. Which I find odd because I would have thought that Gnat.Sockets would simply be a series of wrappers around a few WinApi calls. But then what do I know? The effect of this bug is that programs using UDP protocols timeout earlier than they should do - which often leads to curious behaviour. We have tested this on a couple of PCs running a variety of flavours of Ms-Windows. So far it seems that XP & Win7 work as expected whereas Win8 and Win10 fail. Has anyone any idea what might cause this problem and how we might go about fixing it? Best wishes, MfG Ahlan ------------------------------ with Ada.Text_IO; with Ada.Exceptions; with Ada.Real_Time; with Ada.Streams; with GNAT.Sockets; package body Test is package Io renames Ada.Text_IO; package Net renames GNAT.Sockets; Receive_Timeout : constant Duration := 1.0; Receive_Timeout_Span : constant Ada.Real_Time.Time_Span := Ada.Real_Time.To_Time_Span (Receive_Timeout); procedure Work is The_Datagram : Ada.Streams.Stream_Element_Array (1..20); The_Last : Ada.Streams.Stream_Element_Offset; The_Socket : Net.Socket_Type; Start_Time : Ada.Real_Time.Time; End_Time : Ada.Real_Time.Time; use type Ada.Real_Time.Time; begin Net.Create_Socket (Socket => The_Socket, Family => Net.Family_Inet, Mode => Net.Socket_Datagram); Net.Set_Socket_Option (Socket => The_Socket, Option => (Net.Receive_Timeout, Timeout => Receive_Timeout)); Net.Bind_Socket (The_Socket, (Family => Net.Family_Inet, Addr => Net.Any_Inet_Addr, Port => 11154)); loop begin Start_Time := Ada.Real_Time.Clock; Net.Receive_Socket (Socket => The_Socket, Item => The_Datagram, Last => The_Last); Io.New_Line; Io.Put_Line ("Unexpected reply!"); exit; exception when Occurrence: Net.Socket_Error => End_Time := Ada.Real_Time.Clock; declare Error : constant Net.Error_Type := Net.Resolve_Exception (Occurrence); use type Net.Error_Type; begin if Error = Net.Connection_Timed_Out then if End_Time >= (Start_Time + Receive_Timeout_Span) then Io.Put ("."); else Io.New_Line; declare use type Ada.Real_Time.Time_Span; Shortfall : constant Ada.Real_Time.Time_Span := Receive_Timeout_Span - (End_Time - Start_Time); begin Io.Put_Line ("Timeout too short by" & Ada.Real_Time.To_Duration (Shortfall)'img & "seconds"); end; end if; else Io.Put_Line ("Socket_Error : Unexpected error=" & Error'img); exit; end if; end; when Event : others => Io.Put_Line ("Unexpected exception: " & Ada.Exceptions.Exception_Name (Event)); end; end loop; exception when Event : others => Io.Put_Line ("Internal Error: " & Ada.Exceptions.Exception_Name (Event)); end Work;