Mercurial > vim
comparison src/channel.c @ 8330:ec940c11f749 v7.4.1457
commit https://github.com/vim/vim/commit/d42119fff228434fe57e88d501c744de0a9fb1b1
Author: Bram Moolenaar <Bram@vim.org>
Date: Sun Feb 28 20:51:49 2016 +0100
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)
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Sun, 28 Feb 2016 21:00:04 +0100 |
parents | e2021d6feeda |
children | 07713b8243ac |
comparison
equal
deleted
inserted
replaced
8329:105cfd08008e | 8330:ec940c11f749 |
---|---|
26 # define SOCK_ERRNO errno = WSAGetLastError() | 26 # define SOCK_ERRNO errno = WSAGetLastError() |
27 # undef ECONNREFUSED | 27 # undef ECONNREFUSED |
28 # define ECONNREFUSED WSAECONNREFUSED | 28 # define ECONNREFUSED WSAECONNREFUSED |
29 # undef EWOULDBLOCK | 29 # undef EWOULDBLOCK |
30 # define EWOULDBLOCK WSAEWOULDBLOCK | 30 # define EWOULDBLOCK WSAEWOULDBLOCK |
31 # undef EINPROGRESS | |
32 # define EINPROGRESS WSAEINPROGRESS | |
31 # ifdef EINTR | 33 # ifdef EINTR |
32 # undef EINTR | 34 # undef EINTR |
33 # endif | 35 # endif |
34 # define EINTR WSAEINTR | 36 # define EINTR WSAEINTR |
35 # define sock_write(sd, buf, len) send((SOCKET)sd, buf, len, 0) | 37 # define sock_write(sd, buf, len) send((SOCKET)sd, buf, len, 0) |
548 u_short port = port_in; | 550 u_short port = port_in; |
549 u_long val = 1; | 551 u_long val = 1; |
550 #else | 552 #else |
551 int port = port_in; | 553 int port = port_in; |
552 struct timeval start_tv; | 554 struct timeval start_tv; |
553 int so_error; | |
554 socklen_t so_error_len = sizeof(so_error); | |
555 #endif | 555 #endif |
556 channel_T *channel; | 556 channel_T *channel; |
557 int ret; | 557 int ret; |
558 | 558 |
559 #ifdef WIN32 | 559 #ifdef WIN32 |
631 SOCK_ERRNO; | 631 SOCK_ERRNO; |
632 if (ret < 0) | 632 if (ret < 0) |
633 { | 633 { |
634 if (errno != EWOULDBLOCK | 634 if (errno != EWOULDBLOCK |
635 && errno != ECONNREFUSED | 635 && errno != ECONNREFUSED |
636 | |
637 #ifdef EINPROGRESS | 636 #ifdef EINPROGRESS |
638 && errno != EINPROGRESS | 637 && errno != EINPROGRESS |
639 #endif | 638 #endif |
640 ) | 639 ) |
641 { | 640 { |
651 /* If we don't block and connect() failed then try using select() to | 650 /* If we don't block and connect() failed then try using select() to |
652 * wait for the connection to be made. */ | 651 * wait for the connection to be made. */ |
653 if (waittime >= 0 && ret < 0) | 652 if (waittime >= 0 && ret < 0) |
654 { | 653 { |
655 struct timeval tv; | 654 struct timeval tv; |
655 fd_set rfds; | |
656 fd_set wfds; | 656 fd_set wfds; |
657 #if defined(__APPLE__) && __APPLE__ == 1 | 657 int so_error = 0; |
658 # define PASS_RFDS | 658 socklen_t so_error_len = sizeof(so_error); |
659 fd_set rfds; | |
660 | 659 |
661 FD_ZERO(&rfds); | 660 FD_ZERO(&rfds); |
662 FD_SET(sd, &rfds); | 661 FD_SET(sd, &rfds); |
663 #endif | |
664 FD_ZERO(&wfds); | 662 FD_ZERO(&wfds); |
665 FD_SET(sd, &wfds); | 663 FD_SET(sd, &wfds); |
666 | 664 |
667 tv.tv_sec = waittime / 1000; | 665 tv.tv_sec = waittime / 1000; |
668 tv.tv_usec = (waittime % 1000) * 1000; | 666 tv.tv_usec = (waittime % 1000) * 1000; |
669 #ifndef WIN32 | 667 #ifndef WIN32 |
670 gettimeofday(&start_tv, NULL); | 668 gettimeofday(&start_tv, NULL); |
671 #endif | 669 #endif |
672 ch_logn(channel, | 670 ch_logn(channel, |
673 "Waiting for connection (waittime %d msec)...", waittime); | 671 "Waiting for connection (waittime %d msec)...", waittime); |
674 ret = select((int)sd + 1, | 672 ret = select((int)sd + 1, &rfds, &wfds, NULL, &tv); |
675 #ifdef PASS_RFDS | |
676 &rfds, | |
677 #else | |
678 NULL, | |
679 #endif | |
680 &wfds, NULL, &tv); | |
681 | 673 |
682 if (ret < 0) | 674 if (ret < 0) |
683 { | 675 { |
684 SOCK_ERRNO; | 676 SOCK_ERRNO; |
685 ch_errorn(channel, | 677 ch_errorn(channel, |
687 PERROR(_(e_cannot_connect)); | 679 PERROR(_(e_cannot_connect)); |
688 sock_close(sd); | 680 sock_close(sd); |
689 channel_free(channel); | 681 channel_free(channel); |
690 return NULL; | 682 return NULL; |
691 } | 683 } |
692 #ifdef PASS_RFDS | 684 |
693 if (ret == 0 && FD_ISSET(sd, &rfds) && FD_ISSET(sd, &wfds)) | 685 /* On Win32: select() is expected to work and wait for up to the |
694 { | 686 * waittime for the socket to be open. |
695 /* For OS X, this implies error. See tcp(4). */ | 687 * On Linux-like systems: See socket(7) for the behavior |
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: | |
709 * After putting the socket in non-blocking mode, connect() will | 688 * After putting the socket in non-blocking mode, connect() will |
710 * return EINPROGRESS, select() will not wait (as if writing is | 689 * return EINPROGRESS, select() will not wait (as if writing is |
711 * possible), need to use getsockopt() to check if the socket is | 690 * possible), need to use getsockopt() to check if the socket is |
712 * actually open. */ | 691 * actually connect. |
713 getsockopt(sd, SOL_SOCKET, SO_ERROR, &so_error, &so_error_len); | 692 * We detect an failure to connect when both read and write fds |
714 if (!FD_ISSET(sd, &wfds) || ret == 0 || so_error != 0) | 693 * are set. Use getsockopt() to find out what kind of failure. */ |
715 #endif | 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 | |
703 #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) | |
716 { | 717 { |
717 #ifndef WIN32 | 718 #ifndef WIN32 |
718 struct timeval end_tv; | 719 struct timeval end_tv; |
719 long elapsed_msec; | 720 long elapsed_msec; |
720 | 721 |