From patchwork Wed Oct 3 08:04:37 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arnaud Charlet X-Patchwork-Id: 188724 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id 41A032C00B4 for ; Wed, 3 Oct 2012 18:04:55 +1000 (EST) Comment: DKIM? See http://www.dkim.org DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=gcc.gnu.org; s=default; x=1349856296; h=Comment: DomainKey-Signature:Received:Received:Received:Received:Received: Received:Received:Date:From:To:Cc:Subject:Message-ID: MIME-Version:Content-Type:Content-Disposition:User-Agent: Mailing-List:Precedence:List-Id:List-Unsubscribe:List-Archive: List-Post:List-Help:Sender:Delivered-To; bh=0zC75maUWekVsNYlOAae FAoIqr4=; b=XXT3PMl+FuY8shTStRanm0V5F5BPMaF6xeQf0Qlf7kRzy4MYynUp HaCs3iK7at+0Wnth6TE8Egm8hiWB1tbrAs+0U0Ul86ofpEyy9NdGygt/+IHCLVvx J+aGr+eFP42TM57bpn+Q1TciYUDkfpeyZ/bLDW4k3ulpxfZSv8QxZyM= Comment: DomainKeys? See http://antispam.yahoo.com/domainkeys DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=default; d=gcc.gnu.org; h=Received:Received:X-SWARE-Spam-Status:X-Spam-Check-By:Received:Received:Received:Received:Received:Date:From:To:Cc:Subject:Message-ID:MIME-Version:Content-Type:Content-Disposition:User-Agent:Mailing-List:Precedence:List-Id:List-Unsubscribe:List-Archive:List-Post:List-Help:Sender:Delivered-To; b=PnSTleDU03mMQqs5nwkT0HH+txdTh0ph/n4y8y8QMxSXHoS6WkPCZV+w2TVC76 DL48VN9FH/f5Dcq030cxSVN+9MgJeqatNzWGj6atE9IwAr+X4q5DeNwSmFhhHlqZ asBUY83Wtaa6tgmydERy84oeFBz5bwHS0im680PdCSMCc=; Received: (qmail 27909 invoked by alias); 3 Oct 2012 08:04:45 -0000 Received: (qmail 27888 invoked by uid 22791); 3 Oct 2012 08:04:42 -0000 X-SWARE-Spam-Status: No, hits=-1.9 required=5.0 tests=AWL, BAYES_00, RCVD_IN_HOSTKARMA_NO X-Spam-Check-By: sourceware.org Received: from rock.gnat.com (HELO rock.gnat.com) (205.232.38.15) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Wed, 03 Oct 2012 08:04:37 +0000 Received: from localhost (localhost.localdomain [127.0.0.1]) by filtered-rock.gnat.com (Postfix) with ESMTP id 5D7281C7CB7; Wed, 3 Oct 2012 04:04:37 -0400 (EDT) Received: from rock.gnat.com ([127.0.0.1]) by localhost (rock.gnat.com [127.0.0.1]) (amavisd-new, port 10024) with LMTP id h4HaWsMgG6es; Wed, 3 Oct 2012 04:04:37 -0400 (EDT) Received: from kwai.gnat.com (kwai.gnat.com [205.232.38.4]) by rock.gnat.com (Postfix) with ESMTP id 394A61C7A88; Wed, 3 Oct 2012 04:04:37 -0400 (EDT) Received: by kwai.gnat.com (Postfix, from userid 4192) id 395B33FF09; Wed, 3 Oct 2012 04:04:37 -0400 (EDT) Date: Wed, 3 Oct 2012 04:04:37 -0400 From: Arnaud Charlet To: gcc-patches@gcc.gnu.org Cc: Thomas Quinot Subject: [Ada] Connect_Socket with timeout does not report failure correctly Message-ID: <20121003080437.GA23077@adacore.com> MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.20 (2009-06-14) Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org This change fixes an oversight in the Connect_Socket variant that includes a timeout check. The connection is initiated asynchronously, and a select(2) call is performed to wait for it to complete, with a timeout. When that call returns however, the connection is not always succsefully established. It may also happen that an error occurred during the connection attempt (typically, connection refused by the remote host), which needs to be reported through the raising of an exception. This change adds the missing error check. The following test case should report: Client is trying to connect to Port: 11552 Expected exception raised with Text_IO;use Text_IO; with Gnat.Sockets; use Gnat.Sockets; with Ada.Command_Line; with Ada.Exceptions; use Ada.Exceptions; procedure Timed_Conn_Error is Port : constant Port_Type := 11552; -- There should be no listening server on this port Socket : Socket_Type := No_Socket; Address : Sock_Addr_Type; Host : constant String := Host_Name; Status : Selector_Status; begin Address.Addr := Addresses (Get_Host_By_Name (Host), 1); Address.Port := Port; Create_Socket (Socket); Set_Socket_Option (Socket, Socket_Level, (Reuse_Address, True)); Put_Line ("Client is trying to connect to Port:" & Port'Img & " "); Connect_Socket (Socket => Socket, Server => Address, Timeout => Forever, Status => Status); begin String'Output (Stream (Socket), "Hello"); exception when E : others => Put_Line ("Unexpected exception, should not reach this point"); Put_Line ("Info: " & Exception_Information (E)); end; exception when E : others => Put_Line ("Expected exception raised"); Put_Line ("Info: " & Exception_Information (E)); end Timed_Conn_Error; Tested on x86_64-pc-linux-gnu, committed on trunk 2012-10-03 Thomas Quinot * g-socket.adb (Connect_Socket, version with timeout): When the newly-connected socket is reported as available for writing, check whether it has a pending asynchronous error prior to returning. Index: g-socket.adb =================================================================== --- g-socket.adb (revision 192025) +++ g-socket.adb (working copy) @@ -123,7 +123,7 @@ function Resolve_Error (Error_Value : Integer; From_Errno : Boolean := True) return Error_Type; - -- Associate an enumeration value (error_type) to en error value (errno). + -- Associate an enumeration value (error_type) to an error value (errno). -- From_Errno prevents from mixing h_errno with errno. function To_Name (N : String) return Name_Type; @@ -702,6 +702,13 @@ Req : Request_Type; -- Used to set Socket to non-blocking I/O + Conn_Err : aliased Integer; + -- Error status of the socket after completion of select(2) + + Res : C.int; + Conn_Err_Size : aliased C.int := Conn_Err'Size / 8; + -- For getsockopt(2) call + begin if Selector /= null and then not Is_Open (Selector.all) then raise Program_Error with "closed selector"; @@ -735,10 +742,32 @@ Selector => Selector, Status => Status); + -- Check error condition (the asynchronous connect may have terminated + -- with an error, e.g. ECONNREFUSED) if select(2) completed. + + if Status = Completed then + Res := C_Getsockopt + (C.int (Socket), SOSC.SOL_SOCKET, SOSC.SO_ERROR, + Conn_Err'Address, Conn_Err_Size'Access); + + if Res /= 0 then + Conn_Err := Socket_Errno; + end if; + + else + Conn_Err := 0; + end if; + -- Reset the socket to blocking I/O Req := (Name => Non_Blocking_IO, Enabled => False); Control_Socket (Socket, Request => Req); + + -- Report error condition if any + + if Conn_Err /= 0 then + Raise_Socket_Error (Conn_Err); + end if; end Connect_Socket; --------------------