From owner-svn-src-head@FreeBSD.ORG Thu Apr 29 21:55:21 2010 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id 43433106566B; Thu, 29 Apr 2010 21:55:21 +0000 (UTC) (envelope-from pjd@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [69.147.83.44]) by mx1.freebsd.org (Postfix) with ESMTP id 31F578FC0A; Thu, 29 Apr 2010 21:55:21 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id o3TLtLQs069599; Thu, 29 Apr 2010 21:55:21 GMT (envelope-from pjd@svn.freebsd.org) Received: (from pjd@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id o3TLtLH7069598; Thu, 29 Apr 2010 21:55:21 GMT (envelope-from pjd@svn.freebsd.org) Message-Id: <201004292155.o3TLtLH7069598@svn.freebsd.org> From: Pawel Jakub Dawidek Date: Thu, 29 Apr 2010 21:55:20 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r207390 - head/sbin/hastd X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 29 Apr 2010 21:55:21 -0000 Author: pjd Date: Thu Apr 29 21:55:20 2010 New Revision: 207390 URL: http://svn.freebsd.org/changeset/base/207390 Log: Default connection timeout is way too long. To make it shorter we have to make socket non-blocking, connect() and if we get EINPROGRESS, we have to wait using select(). Very complex, but I know no other way to define connection timeout for a given socket. Reported by: hiroshi@soupacific.com MFC after: 3 days Modified: head/sbin/hastd/proto_tcp4.c Modified: head/sbin/hastd/proto_tcp4.c ============================================================================== --- head/sbin/hastd/proto_tcp4.c Thu Apr 29 21:22:21 2010 (r207389) +++ head/sbin/hastd/proto_tcp4.c Thu Apr 29 21:55:20 2010 (r207390) @@ -37,6 +37,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include #include @@ -47,6 +48,7 @@ __FBSDID("$FreeBSD$"); #include "hast.h" #include "pjdlog.h" #include "proto_impl.h" +#include "subr.h" #define TCP4_CTX_MAGIC 0x7c441c struct tcp4_ctx { @@ -222,18 +224,88 @@ static int tcp4_connect(void *ctx) { struct tcp4_ctx *tctx = ctx; + struct timeval tv; + fd_set fdset; + socklen_t esize; + int error, flags, ret; assert(tctx != NULL); assert(tctx->tc_magic == TCP4_CTX_MAGIC); assert(tctx->tc_side == TCP4_SIDE_CLIENT); assert(tctx->tc_fd >= 0); - if (connect(tctx->tc_fd, (struct sockaddr *)&tctx->tc_sin, - sizeof(tctx->tc_sin)) < 0) { + flags = fcntl(tctx->tc_fd, F_GETFL); + if (flags == -1) { + KEEP_ERRNO(pjdlog_common(LOG_DEBUG, 1, errno, + "fcntl(F_GETFL) failed")); + return (errno); + } + /* + * We make socket non-blocking so we have decided about connection + * timeout. + */ + flags |= O_NONBLOCK; + if (fcntl(tctx->tc_fd, F_SETFL, flags) == -1) { + KEEP_ERRNO(pjdlog_common(LOG_DEBUG, 1, errno, + "fcntl(F_SETFL, O_NONBLOCK) failed")); return (errno); } - return (0); + if (connect(tctx->tc_fd, (struct sockaddr *)&tctx->tc_sin, + sizeof(tctx->tc_sin)) == 0) { + error = 0; + goto done; + } + if (errno != EINPROGRESS) { + error = errno; + pjdlog_common(LOG_DEBUG, 1, errno, "connect() failed"); + goto done; + } + /* + * Connection can't be established immediately, let's wait + * for HAST_TIMEOUT seconds. + */ + tv.tv_sec = HAST_TIMEOUT; + tv.tv_usec = 0; +again: + FD_ZERO(&fdset); + FD_SET(tctx->tc_fd, &fdset); + ret = select(tctx->tc_fd + 1, NULL, &fdset, NULL, &tv); + if (ret == 0) { + error = ETIMEDOUT; + goto done; + } else if (ret == -1) { + if (errno == EINTR) + goto again; + error = errno; + pjdlog_common(LOG_DEBUG, 1, errno, "select() failed"); + goto done; + } + assert(ret > 0); + assert(FD_ISSET(tctx->tc_fd, &fdset)); + esize = sizeof(error); + if (getsockopt(tctx->tc_fd, SOL_SOCKET, SO_ERROR, &error, + &esize) == -1) { + error = errno; + pjdlog_common(LOG_DEBUG, 1, errno, + "getsockopt(SO_ERROR) failed"); + goto done; + } + if (error != 0) { + pjdlog_common(LOG_DEBUG, 1, error, + "getsockopt(SO_ERROR) returned error"); + goto done; + } + error = 0; +done: + flags &= ~O_NONBLOCK; + if (fcntl(tctx->tc_fd, F_SETFL, flags) == -1) { + if (error == 0) + error = errno; + pjdlog_common(LOG_DEBUG, 1, errno, + "fcntl(F_SETFL, ~O_NONBLOCK) failed"); + } + return (error); } static int