diff options
author | tedu <> | 2014-10-30 16:06:07 +0000 |
---|---|---|
committer | tedu <> | 2014-10-30 16:06:07 +0000 |
commit | 56e63b7a9edf56693944d3b05ae76e1d2be27991 (patch) | |
tree | a772cfa5cc001f902fc25e12569c3c562b6ad18d /src | |
parent | a0b4b08aa4811ef730e76a9ffc401a5293770f92 (diff) | |
download | openbsd-56e63b7a9edf56693944d3b05ae76e1d2be27991.tar.gz openbsd-56e63b7a9edf56693944d3b05ae76e1d2be27991.tar.bz2 openbsd-56e63b7a9edf56693944d3b05ae76e1d2be27991.zip |
rework the poll loop to poll in both directions so it doesn't get stuck
if one pipe stalls out. from a diff by Arne Becker.
(buffer size left alone for now)
Diffstat (limited to 'src')
-rw-r--r-- | src/usr.bin/nc/netcat.c | 258 |
1 files changed, 211 insertions, 47 deletions
diff --git a/src/usr.bin/nc/netcat.c b/src/usr.bin/nc/netcat.c index e6ec97ed0f..a8e90186e9 100644 --- a/src/usr.bin/nc/netcat.c +++ b/src/usr.bin/nc/netcat.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: netcat.c,v 1.124 2014/10/26 13:59:30 millert Exp $ */ | 1 | /* $OpenBSD: netcat.c,v 1.125 2014/10/30 16:06:07 tedu Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2001 Eric Jackson <ericj@monkey.org> | 3 | * Copyright (c) 2001 Eric Jackson <ericj@monkey.org> |
4 | * | 4 | * |
@@ -64,6 +64,12 @@ | |||
64 | #define PORT_MAX_LEN 6 | 64 | #define PORT_MAX_LEN 6 |
65 | #define UNIX_DG_TMP_SOCKET_SIZE 19 | 65 | #define UNIX_DG_TMP_SOCKET_SIZE 19 |
66 | 66 | ||
67 | #define POLL_STDIN 0 | ||
68 | #define POLL_NETOUT 1 | ||
69 | #define POLL_NETIN 2 | ||
70 | #define POLL_STDOUT 3 | ||
71 | #define BUFSIZE 2048 | ||
72 | |||
67 | /* Command Line Options */ | 73 | /* Command Line Options */ |
68 | int dflag; /* detached, no stdin */ | 74 | int dflag; /* detached, no stdin */ |
69 | int Fflag; /* fdpass sock to stdout */ | 75 | int Fflag; /* fdpass sock to stdout */ |
@@ -111,6 +117,8 @@ void set_common_sockopts(int); | |||
111 | int map_tos(char *, int *); | 117 | int map_tos(char *, int *); |
112 | void report_connect(const struct sockaddr *, socklen_t); | 118 | void report_connect(const struct sockaddr *, socklen_t); |
113 | void usage(int); | 119 | void usage(int); |
120 | ssize_t drainbuf(int, unsigned char *, size_t *); | ||
121 | ssize_t fillbuf(int, unsigned char *, size_t *); | ||
114 | 122 | ||
115 | int | 123 | int |
116 | main(int argc, char *argv[]) | 124 | main(int argc, char *argv[]) |
@@ -390,7 +398,7 @@ main(int argc, char *argv[]) | |||
390 | &len); | 398 | &len); |
391 | if (connfd == -1) { | 399 | if (connfd == -1) { |
392 | /* For now, all errnos are fatal */ | 400 | /* For now, all errnos are fatal */ |
393 | err(1, "accept"); | 401 | err(1, "accept"); |
394 | } | 402 | } |
395 | if (vflag) | 403 | if (vflag) |
396 | report_connect((struct sockaddr *)&cliaddr, len); | 404 | report_connect((struct sockaddr *)&cliaddr, len); |
@@ -729,68 +737,224 @@ local_listen(char *host, char *port, struct addrinfo hints) | |||
729 | * Loop that polls on the network file descriptor and stdin. | 737 | * Loop that polls on the network file descriptor and stdin. |
730 | */ | 738 | */ |
731 | void | 739 | void |
732 | readwrite(int nfd) | 740 | readwrite(int net_fd) |
733 | { | 741 | { |
734 | struct pollfd pfd[2]; | 742 | struct pollfd pfd[4]; |
735 | unsigned char buf[16 * 1024]; | 743 | int stdin_fd = STDIN_FILENO; |
736 | int n, wfd = fileno(stdin); | 744 | int stdout_fd = STDOUT_FILENO; |
737 | int lfd = fileno(stdout); | 745 | unsigned char netinbuf[BUFSIZE]; |
738 | int plen; | 746 | size_t netinbufpos = 0; |
739 | 747 | unsigned char stdinbuf[BUFSIZE]; | |
740 | plen = sizeof(buf); | 748 | size_t stdinbufpos = 0; |
741 | 749 | int n, num_fds, flags; | |
742 | /* Setup Network FD */ | 750 | ssize_t ret; |
743 | pfd[0].fd = nfd; | 751 | |
744 | pfd[0].events = POLLIN; | 752 | /* don't read from stdin if requested */ |
745 | 753 | if (dflag) | |
746 | /* Set up STDIN FD. */ | 754 | stdin_fd = -1; |
747 | pfd[1].fd = wfd; | 755 | |
748 | pfd[1].events = POLLIN; | 756 | /* stdin */ |
757 | pfd[POLL_STDIN].fd = stdin_fd; | ||
758 | pfd[POLL_STDIN].events = POLLIN; | ||
759 | |||
760 | /* network out */ | ||
761 | pfd[POLL_NETOUT].fd = net_fd; | ||
762 | pfd[POLL_NETOUT].events = 0; | ||
763 | |||
764 | /* network in */ | ||
765 | pfd[POLL_NETIN].fd = net_fd; | ||
766 | pfd[POLL_NETIN].events = POLLIN; | ||
767 | |||
768 | /* stdout */ | ||
769 | pfd[POLL_STDOUT].fd = stdout_fd; | ||
770 | pfd[POLL_STDOUT].events = 0; | ||
771 | |||
772 | while (1) { | ||
773 | /* both inputs are gone, buffers are empty, we are done */ | ||
774 | if (pfd[POLL_STDIN].fd == -1 && pfd[POLL_NETIN].fd == -1 | ||
775 | && stdinbufpos == 0 && netinbufpos == 0) { | ||
776 | close(net_fd); | ||
777 | return; | ||
778 | } | ||
779 | /* both outputs are gone, we can't continue */ | ||
780 | if (pfd[POLL_NETOUT].fd == -1 && pfd[POLL_STDOUT].fd == -1) { | ||
781 | close(net_fd); | ||
782 | return; | ||
783 | } | ||
784 | /* listen and net in gone, queues empty, done */ | ||
785 | if (lflag && pfd[POLL_NETIN].fd == -1 | ||
786 | && stdinbufpos == 0 && netinbufpos == 0) { | ||
787 | close(net_fd); | ||
788 | return; | ||
789 | } | ||
749 | 790 | ||
750 | while (pfd[0].fd != -1) { | 791 | /* help says -i is for "wait between lines sent". We read and |
792 | * write arbitrary amounts of data, and we don't want to start | ||
793 | * scanning for newlines, so this is as good as it gets */ | ||
751 | if (iflag) | 794 | if (iflag) |
752 | sleep(iflag); | 795 | sleep(iflag); |
753 | 796 | ||
754 | if ((n = poll(pfd, 2 - dflag, timeout)) < 0) { | 797 | /* poll */ |
755 | int saved_errno = errno; | 798 | num_fds = poll(pfd, 4, timeout); |
756 | close(nfd); | 799 | |
757 | errc(1, saved_errno, "Polling Error"); | 800 | /* treat poll errors */ |
801 | if (num_fds == -1) { | ||
802 | close(net_fd); | ||
803 | err(1, "polling error"); | ||
758 | } | 804 | } |
759 | 805 | ||
760 | if (n == 0) | 806 | /* timeout happened */ |
807 | if (num_fds == 0) | ||
761 | return; | 808 | return; |
762 | 809 | ||
763 | if (pfd[0].revents & (POLLIN|POLLHUP)) { | 810 | /* treat socket error conditions */ |
764 | if ((n = read(nfd, buf, plen)) < 0) | 811 | for (n = 0; n < 4; n++) { |
765 | return; | 812 | if (pfd[n].revents & (POLLERR|POLLNVAL)) { |
766 | else if (n == 0) { | 813 | pfd[n].fd = -1; |
767 | shutdown(nfd, SHUT_RD); | ||
768 | pfd[0].fd = -1; | ||
769 | pfd[0].events = 0; | ||
770 | } else { | ||
771 | if (tflag) | ||
772 | atelnet(nfd, buf, n); | ||
773 | if (atomicio(vwrite, lfd, buf, n) != n) | ||
774 | return; | ||
775 | } | 814 | } |
776 | } | 815 | } |
816 | /* reading is possible after HUP */ | ||
817 | if (pfd[POLL_STDIN].events & POLLIN && | ||
818 | pfd[POLL_STDIN].revents & POLLHUP && | ||
819 | ! (pfd[POLL_STDIN].revents & POLLIN)) | ||
820 | pfd[POLL_STDIN].fd = -1; | ||
821 | |||
822 | if (pfd[POLL_NETIN].events & POLLIN && | ||
823 | pfd[POLL_NETIN].revents & POLLHUP && | ||
824 | ! (pfd[POLL_NETIN].revents & POLLIN)) | ||
825 | pfd[POLL_NETIN].fd = -1; | ||
826 | |||
827 | if (pfd[POLL_NETOUT].revents & POLLHUP) { | ||
828 | if (Nflag) | ||
829 | shutdown(pfd[POLL_NETOUT].fd, SHUT_WR); | ||
830 | pfd[POLL_NETOUT].fd = -1; | ||
831 | } | ||
832 | /* if HUP, stop watching stdout */ | ||
833 | if (pfd[POLL_STDOUT].revents & POLLHUP) | ||
834 | pfd[POLL_STDOUT].fd = -1; | ||
835 | /* if no net out, stop watching stdin */ | ||
836 | if (pfd[POLL_NETOUT].fd == -1) | ||
837 | pfd[POLL_STDIN].fd = -1; | ||
838 | /* if no stdout, stop watching net in */ | ||
839 | if (pfd[POLL_STDOUT].fd == -1) { | ||
840 | if (pfd[POLL_NETIN].fd != -1) | ||
841 | shutdown(pfd[POLL_NETIN].fd, SHUT_RD); | ||
842 | pfd[POLL_NETIN].fd = -1; | ||
843 | } | ||
777 | 844 | ||
778 | if (!dflag && pfd[1].revents & (POLLIN|POLLHUP)) { | 845 | /* try to read from stdin */ |
779 | if ((n = read(wfd, buf, plen)) < 0) | 846 | if (pfd[POLL_STDIN].revents & POLLIN && stdinbufpos < BUFSIZE) { |
780 | return; | 847 | ret = fillbuf(pfd[POLL_STDIN].fd, stdinbuf, |
781 | else if (n == 0) { | 848 | &stdinbufpos); |
782 | if (Nflag) | 849 | /* error or eof on stdin - remove from pfd */ |
783 | shutdown(nfd, SHUT_WR); | 850 | if (ret == 0 || ret == -1) |
784 | pfd[1].fd = -1; | 851 | pfd[POLL_STDIN].fd = -1; |
785 | pfd[1].events = 0; | 852 | /* read something - poll net out */ |
786 | } else { | 853 | if (stdinbufpos > 0) |
787 | if (atomicio(vwrite, nfd, buf, n) != n) | 854 | pfd[POLL_NETOUT].events = POLLOUT; |
788 | return; | 855 | /* filled buffer - remove self from polling */ |
856 | if (stdinbufpos == BUFSIZE) | ||
857 | pfd[POLL_STDIN].events = 0; | ||
858 | } | ||
859 | /* try to write to network */ | ||
860 | if (pfd[POLL_NETOUT].revents & POLLOUT && stdinbufpos > 0) { | ||
861 | ret = drainbuf(pfd[POLL_NETOUT].fd, stdinbuf, | ||
862 | &stdinbufpos); | ||
863 | if (ret == -1) | ||
864 | pfd[POLL_NETOUT].fd = -1; | ||
865 | /* buffer empty - remove self from polling */ | ||
866 | if (stdinbufpos == 0) | ||
867 | pfd[POLL_NETOUT].events = 0; | ||
868 | /* buffer no longer full - poll stdin again */ | ||
869 | if (stdinbufpos < BUFSIZE) | ||
870 | pfd[POLL_STDIN].events = POLLIN; | ||
871 | } | ||
872 | /* try to read from network */ | ||
873 | if (pfd[POLL_NETIN].revents & POLLIN && netinbufpos < BUFSIZE) { | ||
874 | ret = fillbuf(pfd[POLL_NETIN].fd, netinbuf, | ||
875 | &netinbufpos); | ||
876 | if (ret == -1) | ||
877 | pfd[POLL_NETIN].fd = -1; | ||
878 | /* eof on net in - remove from pfd */ | ||
879 | if (ret == 0) { | ||
880 | shutdown(pfd[POLL_NETIN].fd, SHUT_RD); | ||
881 | pfd[POLL_NETIN].fd = -1; | ||
789 | } | 882 | } |
883 | /* read something - poll stdout */ | ||
884 | if (netinbufpos > 0) | ||
885 | pfd[POLL_STDOUT].events = POLLOUT; | ||
886 | /* filled buffer - remove self from polling */ | ||
887 | if (netinbufpos == BUFSIZE) | ||
888 | pfd[POLL_NETIN].events = 0; | ||
889 | /* handle telnet */ | ||
890 | if (tflag) | ||
891 | atelnet(pfd[POLL_NETIN].fd, netinbuf, | ||
892 | netinbufpos); | ||
893 | } | ||
894 | /* try to write to stdout */ | ||
895 | if (pfd[POLL_STDOUT].revents & POLLOUT && netinbufpos > 0) { | ||
896 | ret = drainbuf(pfd[POLL_STDOUT].fd, netinbuf, | ||
897 | &netinbufpos); | ||
898 | if (ret == -1) | ||
899 | pfd[POLL_STDOUT].fd = -1; | ||
900 | /* buffer empty - remove self from polling */ | ||
901 | if (netinbufpos == 0) | ||
902 | pfd[POLL_STDOUT].events = 0; | ||
903 | /* buffer no longer full - poll net in again */ | ||
904 | if (netinbufpos < BUFSIZE) | ||
905 | pfd[POLL_NETIN].events = POLLIN; | ||
906 | } | ||
907 | |||
908 | /* stdin gone and queue empty? */ | ||
909 | if (pfd[POLL_STDIN].fd == -1 && stdinbufpos == 0) { | ||
910 | if (pfd[POLL_NETOUT].fd != -1 && Nflag) | ||
911 | shutdown(pfd[POLL_NETOUT].fd, SHUT_WR); | ||
912 | pfd[POLL_NETOUT].fd = -1; | ||
913 | } | ||
914 | /* net in gone and queue empty? */ | ||
915 | if (pfd[POLL_NETIN].fd == -1 && netinbufpos == 0) { | ||
916 | pfd[POLL_STDOUT].fd = -1; | ||
790 | } | 917 | } |
791 | } | 918 | } |
792 | } | 919 | } |
793 | 920 | ||
921 | ssize_t | ||
922 | drainbuf(int fd, unsigned char *buf, size_t *bufpos) | ||
923 | { | ||
924 | ssize_t n; | ||
925 | ssize_t adjust; | ||
926 | |||
927 | n = write(fd, buf, *bufpos); | ||
928 | /* don't treat EAGAIN, EINTR as error */ | ||
929 | if (n == -1 && (errno == EAGAIN || errno == EINTR)) | ||
930 | n = -2; | ||
931 | if (n <= 0) | ||
932 | return n; | ||
933 | /* adjust buffer */ | ||
934 | adjust = *bufpos - n; | ||
935 | if (adjust > 0) | ||
936 | memmove(buf, buf + n, adjust); | ||
937 | *bufpos -= n; | ||
938 | return n; | ||
939 | } | ||
940 | |||
941 | |||
942 | ssize_t | ||
943 | fillbuf(int fd, unsigned char *buf, size_t *bufpos) | ||
944 | { | ||
945 | size_t num = BUFSIZE - *bufpos; | ||
946 | ssize_t n; | ||
947 | |||
948 | n = read(fd, buf + *bufpos, num); | ||
949 | /* don't treat EAGAIN, EINTR as error */ | ||
950 | if (n == -1 && (errno == EAGAIN || errno == EINTR)) | ||
951 | n = -2; | ||
952 | if (n <= 0) | ||
953 | return n; | ||
954 | *bufpos += n; | ||
955 | return n; | ||
956 | } | ||
957 | |||
794 | /* | 958 | /* |
795 | * fdpass() | 959 | * fdpass() |
796 | * Pass the connected file descriptor to stdout and exit. | 960 | * Pass the connected file descriptor to stdout and exit. |