loop.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. /*
  2. * Copyright (c) 1993 W. Richard Stevens. All rights reserved.
  3. * Permission to use or modify this software and its documentation only for
  4. * educational purposes and without fee is hereby granted, provided that
  5. * the above copyright notice appear in all copies. The author makes no
  6. * representations about the suitability of this software for any purpose.
  7. * It is provided "as is" without express or implied warranty.
  8. */
  9. #include "sock.h"
  10. /* Copy everything from stdin to "sockfd",
  11. * and everything from "sockfd" to stdout. */
  12. void tty_atexit(void); /* in library */
  13. void sig_catch(int); /* my function */
  14. void
  15. loop(int sockfd)
  16. {
  17. int maxfdp1, nread, ntowrite, stdineof, clilen;
  18. fd_set rset;
  19. struct sockaddr_in cliaddr; /* for UDP server */
  20. #ifdef MSG_TRUNC /* 4.3BSD Reno and later */
  21. struct iovec iov[1];
  22. struct msghdr msg;
  23. #ifdef IP_RECVDSTADDR /* 4.3BSD Reno and later */
  24. static struct cmsghdr *cmptr = NULL; /* malloc'ed */
  25. struct in_addr dstinaddr; /* for UDP server */
  26. #define CONTROLLEN (sizeof(struct cmsghdr) + sizeof(struct in_addr))
  27. #endif /* IP_RECVDSTADDR */
  28. #endif /* MSG_TRUNC */
  29. #ifdef notdef /* following doesn't appear to work */
  30. /*
  31. * This is an attempt to set stdin to cbreak, so that input characters
  32. * are delivered one at a time, to see Nagle algorithm in effect
  33. * (or disabled).
  34. */
  35. if (cbreak && isatty(STDIN_FILENO)) {
  36. if (tty_cbreak(STDIN_FILENO) < 0)
  37. err_sys("tty_cbreak error");
  38. if (atexit(tty_atexit) < 0)
  39. err_sys("tty_atexit error");
  40. if (signal(SIGINT, sig_catch) == SIG_ERR)
  41. err_sys("signal error");
  42. if (signal(SIGQUIT, sig_catch) == SIG_ERR)
  43. err_sys("signal error");
  44. if (signal(SIGTERM, sig_catch) == SIG_ERR)
  45. err_sys("signal error");
  46. }
  47. #endif
  48. if (pauseinit)
  49. sleep(pauseinit); /* intended for server */
  50. stdineof = 0;
  51. FD_ZERO(&rset);
  52. maxfdp1 = sockfd + 1; /* check descriptors [0..sockfd] */
  53. /* UDP client issues connect(), so read() and write() are used.
  54. Server is harder since cannot issue connect(). We use recvfrom()
  55. or recvmsg(), depending on OS. */
  56. for ( ; ; ) {
  57. if (stdineof == 0)
  58. FD_SET(STDIN_FILENO, &rset);
  59. FD_SET(sockfd, &rset);
  60. if (select(maxfdp1, &rset, NULL, NULL, NULL) < 0)
  61. err_sys("select error");
  62. if (FD_ISSET(STDIN_FILENO, &rset)) { /* data to read on stdin */
  63. if ( (nread = read(STDIN_FILENO, rbuf, readlen)) < 0)
  64. err_sys("read error from stdin");
  65. else if (nread == 0) { /* EOF on stdin */
  66. if (halfclose) {
  67. if (shutdown(sockfd, 1) < 0)
  68. err_sys("shutdown() error");
  69. FD_CLR(STDIN_FILENO, &rset);
  70. stdineof = 1; /* don't read stdin anymore */
  71. continue; /* back to select() */
  72. }
  73. break; /* default: stdin EOF -> done */
  74. }
  75. if (crlf) {
  76. ntowrite = crlf_add(wbuf, writelen, rbuf, nread);
  77. if (write(sockfd, wbuf, ntowrite) != ntowrite)
  78. err_sys("write error");
  79. } else {
  80. if (write(sockfd, rbuf, nread) != nread)
  81. err_sys("write error");
  82. }
  83. }
  84. if (FD_ISSET(sockfd, &rset)) { /* data to read from socket */
  85. if (udp && server) {
  86. clilen = sizeof(cliaddr);
  87. #ifndef MSG_TRUNC /* vanilla BSD sockets */
  88. nread = recvfrom(sockfd, rbuf, readlen, 0,
  89. (struct sockaddr *) &cliaddr, &clilen);
  90. #else /* 4.3BSD Reno and later; use recvmsg() to get at MSG_TRUNC flag */
  91. /* Also lets us get at control information (destination address) */
  92. iov[0].iov_base = rbuf;
  93. iov[0].iov_len = readlen;
  94. msg.msg_iov = iov;
  95. msg.msg_iovlen = 1;
  96. msg.msg_name = (caddr_t) &cliaddr;
  97. msg.msg_namelen = clilen;
  98. #ifdef IP_RECVDSTADDR
  99. if (cmptr == NULL && (cmptr = malloc(CONTROLLEN)) == NULL)
  100. err_sys("malloc error for control buffer");
  101. msg.msg_control = (caddr_t) cmptr; /* for dest address */
  102. msg.msg_controllen = CONTROLLEN;
  103. #else
  104. msg.msg_control = (caddr_t) 0; /* no ancillary data */
  105. msg.msg_controllen = 0;
  106. #endif /* IP_RECVDSTADDR */
  107. msg.msg_flags = 0; /* flags returned here */
  108. nread = recvmsg(sockfd, &msg, 0);
  109. #endif /* MSG_TRUNC */
  110. if (nread < 0)
  111. err_sys("datagram receive error");
  112. if (verbose) {
  113. printf("from %s", INET_NTOA(cliaddr.sin_addr));
  114. #ifdef MSG_TRUNC
  115. #ifdef IP_RECVDSTADDR
  116. if (recvdstaddr) {
  117. if (cmptr->cmsg_level != IPPROTO_IP)
  118. err_quit("control level != IPPROTO_IP");
  119. if (cmptr->cmsg_type != IP_RECVDSTADDR)
  120. err_quit("control type != IP_RECVDSTADDR");
  121. if (cmptr->cmsg_len != CONTROLLEN)
  122. err_quit("control length (%d) != %d",
  123. cmptr->cmsg_len, CONTROLLEN);
  124. memcpy((char *) &dstinaddr, (char *) CMSG_DATA(cmptr),
  125. sizeof(struct in_addr));
  126. printf(", to %s", INET_NTOA(dstinaddr));
  127. }
  128. #endif /* IP_RECVDSTADDR */
  129. #endif /* MSG_TRUNC */
  130. printf(": ");
  131. fflush(stdout);
  132. }
  133. #ifdef MSG_TRUNC
  134. if (msg.msg_flags & MSG_TRUNC)
  135. printf("(datagram truncated)\n");
  136. #endif
  137. } else {
  138. if ( (nread = read(sockfd, rbuf, readlen)) < 0)
  139. err_sys("read error");
  140. else if (nread == 0) {
  141. if (verbose)
  142. fprintf(stderr, "connection closed by peer\n");
  143. break; /* EOF, terminate */
  144. }
  145. }
  146. if (crlf) {
  147. ntowrite = crlf_strip(wbuf, writelen, rbuf, nread);
  148. if (writen(STDOUT_FILENO, wbuf, ntowrite) != ntowrite)
  149. err_sys("writen error to stdout");
  150. } else {
  151. if (writen(STDOUT_FILENO, rbuf, nread) != nread)
  152. err_sys("writen error to stdout");
  153. }
  154. }
  155. }
  156. if (pauseclose) {
  157. if (verbose)
  158. fprintf(stderr, "pausing before close\n");
  159. sleep(pauseclose);
  160. }
  161. if (close(sockfd) < 0)
  162. err_sys("close error"); /* since SO_LINGER may be set */
  163. }
  164. void
  165. sig_catch(int signo)
  166. {
  167. exit(0); /* exit handler will reset tty state */
  168. }