Skip to content

Commit d42119f

Browse files
committed
patch 7.4.1457
Problem: Opening a channel with select() is not done properly. Solution: Also used read-fds. Use getsockopt() to check for errors. (Ozaki Kiichi)
1 parent 29e1951 commit d42119f

File tree

2 files changed

+37
-34
lines changed

2 files changed

+37
-34
lines changed

src/channel.c

Lines changed: 35 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
# define ECONNREFUSED WSAECONNREFUSED
2929
# undef EWOULDBLOCK
3030
# define EWOULDBLOCK WSAEWOULDBLOCK
31+
# undef EINPROGRESS
32+
# define EINPROGRESS WSAEINPROGRESS
3133
# ifdef EINTR
3234
# undef EINTR
3335
# endif
@@ -550,8 +552,6 @@ channel_open(
550552
#else
551553
int port = port_in;
552554
struct timeval start_tv;
553-
int so_error;
554-
socklen_t so_error_len = sizeof(so_error);
555555
#endif
556556
channel_T *channel;
557557
int ret;
@@ -633,7 +633,6 @@ channel_open(
633633
{
634634
if (errno != EWOULDBLOCK
635635
&& errno != ECONNREFUSED
636-
637636
#ifdef EINPROGRESS
638637
&& errno != EINPROGRESS
639638
#endif
@@ -653,14 +652,13 @@ channel_open(
653652
if (waittime >= 0 && ret < 0)
654653
{
655654
struct timeval tv;
655+
fd_set rfds;
656656
fd_set wfds;
657-
#if defined(__APPLE__) && __APPLE__ == 1
658-
# define PASS_RFDS
659-
fd_set rfds;
657+
int so_error = 0;
658+
socklen_t so_error_len = sizeof(so_error);
660659

661660
FD_ZERO(&rfds);
662661
FD_SET(sd, &rfds);
663-
#endif
664662
FD_ZERO(&wfds);
665663
FD_SET(sd, &wfds);
666664

@@ -671,13 +669,7 @@ channel_open(
671669
#endif
672670
ch_logn(channel,
673671
"Waiting for connection (waittime %d msec)...", waittime);
674-
ret = select((int)sd + 1,
675-
#ifdef PASS_RFDS
676-
&rfds,
677-
#else
678-
NULL,
679-
#endif
680-
&wfds, NULL, &tv);
672+
ret = select((int)sd + 1, &rfds, &wfds, NULL, &tv);
681673

682674
if (ret < 0)
683675
{
@@ -689,30 +681,39 @@ channel_open(
689681
channel_free(channel);
690682
return NULL;
691683
}
692-
#ifdef PASS_RFDS
693-
if (ret == 0 && FD_ISSET(sd, &rfds) && FD_ISSET(sd, &wfds))
694-
{
695-
/* For OS X, this implies error. See tcp(4). */
696-
ch_error(channel, "channel_open: Connect failed");
697-
EMSG(_(e_cannot_connect));
698-
sock_close(sd);
699-
channel_free(channel);
700-
return NULL;
701-
}
702-
#endif
703-
#ifdef WIN32
704-
/* On Win32 select() is expected to work and wait for up to the
705-
* waittime for the socket to be open. */
706-
if (!FD_ISSET(sd, &wfds) || ret == 0)
707-
#else
708-
/* See socket(7) for the behavior on Linux-like systems:
684+
685+
/* On Win32: select() is expected to work and wait for up to the
686+
* waittime for the socket to be open.
687+
* On Linux-like systems: See socket(7) for the behavior
709688
* After putting the socket in non-blocking mode, connect() will
710689
* return EINPROGRESS, select() will not wait (as if writing is
711690
* possible), need to use getsockopt() to check if the socket is
712-
* actually open. */
713-
getsockopt(sd, SOL_SOCKET, SO_ERROR, &so_error, &so_error_len);
714-
if (!FD_ISSET(sd, &wfds) || ret == 0 || so_error != 0)
691+
* actually connect.
692+
* We detect an failure to connect when both read and write fds
693+
* are set. Use getsockopt() to find out what kind of failure. */
694+
if (FD_ISSET(sd, &rfds) && FD_ISSET(sd, &wfds))
695+
{
696+
ret = getsockopt(sd,
697+
SOL_SOCKET, SO_ERROR, &so_error, &so_error_len);
698+
if (ret < 0 || (so_error != 0
699+
&& so_error != EWOULDBLOCK
700+
&& so_error != ECONNREFUSED
701+
#ifdef EINPROGRESS
702+
&& so_error != EINPROGRESS
715703
#endif
704+
))
705+
{
706+
ch_errorn(channel,
707+
"channel_open: Connect failed with errno %d",
708+
so_error);
709+
PERROR(_(e_cannot_connect));
710+
sock_close(sd);
711+
channel_free(channel);
712+
return NULL;
713+
}
714+
}
715+
716+
if (!FD_ISSET(sd, &wfds) || so_error != 0)
716717
{
717718
#ifndef WIN32
718719
struct timeval end_tv;

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -743,6 +743,8 @@ static char *(features[]) =
743743

744744
static int included_patches[] =
745745
{ /* Add new patch number below this line */
746+
/**/
747+
1457,
746748
/**/
747749
1456,
748750
/**/

0 commit comments

Comments
 (0)