comp.lang.ada
 help / color / mirror / Atom feed
From: ahlan@marriott.org
Subject: Gnat Sockets - UDP timeout too short.
Date: Wed, 12 Oct 2016 07:23:37 -0700 (PDT)
Date: 2016-10-12T07:23:37-07:00	[thread overview]
Message-ID: <4a05ca67-2ecc-4907-a817-38071dba832b@googlegroups.com> (raw)

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;


             reply	other threads:[~2016-10-12 14:23 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-10-12 14:23 ahlan [this message]
2016-11-04  8:48 ` Gnat Sockets - UDP timeout too short ahlan.marriott
replies disabled

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox