1/* -*- c-basic-offset: 8; -*- 2 * 3 * Copyright (c) 1993 W. Richard Stevens. All rights reserved. 4 * Permission to use or modify this software and its documentation only for 5 * educational purposes and without fee is hereby granted, provided that 6 * the above copyright notice appear in all copies. The author makes no 7 * representations about the suitability of this software for any purpose. 8 * It is provided "as is" without express or implied warranty. 9 */ 10 11#include <stdio.h> 12#include <netdb.h> 13#include <sys/types.h> 14#include <netinet/in.h> 15#include <arpa/inet.h> 16#include "sock.h" 17 18/* Copy everything from stdin to "sockfd", 19 * and everything from "sockfd" to stdout. */ 20 21void 22loop_udp(int sockfd) 23{ 24 int maxfdp1, nread, ntowrite, stdineof, clilen, servlen, flags; 25 fd_set rset; 26 struct sockaddr_in cliaddr; /* for UDP server */ 27 struct sockaddr_in servaddr; /* for UDP client */ 28 29#ifdef HAVE_MSGHDR_MSG_CONTROL 30 struct iovec iov[1]; 31 struct msghdr msg; 32 33#ifdef IP_RECVDSTADDR /* 4.3BSD Reno and later */ 34 static struct cmsghdr *cmptr = NULL; /* malloc'ed */ 35 struct in_addr dstinaddr; /* for UDP server */ 36#define CONTROLLEN (sizeof(struct cmsghdr) + sizeof(struct in_addr)) 37#endif /* IP_RECVDSTADDR */ 38 39#endif /* MSG_TRUNC */ 40 41 if (pauseinit) 42 sleep_us(pauseinit*1000); /* intended for server */ 43 44 flags = 0; 45 stdineof = 0; 46 FD_ZERO(&rset); 47 maxfdp1 = sockfd + 1; /* check descriptors [0..sockfd] */ 48 49 /* If UDP client issues connect(), recv() and write() are used. 50 Server is harder since cannot issue connect(). We use recvfrom() 51 or recvmsg(), depending on OS. */ 52 53 for ( ; ; ) { 54 if (stdineof == 0) 55 FD_SET(STDIN_FILENO, &rset); 56 FD_SET(sockfd, &rset); 57 58 if (select(maxfdp1, &rset, NULL, NULL, NULL) < 0) 59 err_sys("select error"); 60 61 if (FD_ISSET(STDIN_FILENO, &rset)) { 62 /* 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) { 66 /* EOF on stdin */ 67 if (halfclose) { 68 if (shutdown(sockfd, SHUT_WR) < 0) 69 err_sys("shutdown() error"); 70 71 FD_CLR(STDIN_FILENO, &rset); 72 stdineof = 1; /* don't read stdin anymore */ 73 continue; /* back to select() */ 74 } 75 break; /* default: stdin EOF -> done */ 76 } 77 78 if (crlf) { 79 ntowrite = crlf_add(wbuf, writelen, rbuf, nread); 80 if (connectudp) { 81 if (write(sockfd, wbuf, ntowrite) != ntowrite) 82 err_sys("write error"); 83 } else { 84 if (sendto(sockfd, wbuf, ntowrite, 0, 85 (struct sockaddr *) &servaddr, sizeof(servaddr)) 86 != ntowrite) 87 err_sys("sendto error"); 88 } 89 } else { 90 if (connectudp) { 91 if (write(sockfd, rbuf, nread) != nread) 92 err_sys("write error"); 93 } else { 94 if (sendto(sockfd, rbuf, nread, 0, 95 (struct sockaddr *) &servaddr, sizeof(servaddr)) 96 != nread) 97 err_sys("sendto error"); 98 } 99 } 100 } 101 102 if (FD_ISSET(sockfd, &rset)) { 103 /* data to read from socket */ 104 if (server) { 105 clilen = sizeof(cliaddr); 106#ifndef MSG_TRUNC /* vanilla BSD sockets */ 107 nread = recvfrom(sockfd, rbuf, readlen, 0, 108 (struct sockaddr *) &cliaddr, &clilen); 109 110#else /* 4.3BSD Reno and later; use recvmsg() to get at MSG_TRUNC flag */ 111 /* Also lets us get at control information (destination address) */ 112 113 iov[0].iov_base = rbuf; 114 iov[0].iov_len = readlen; 115 msg.msg_iov = iov; 116 msg.msg_iovlen = 1; 117 msg.msg_name = (caddr_t) &cliaddr; 118 msg.msg_namelen = clilen; 119 120#ifdef IP_RECVDSTADDR 121 if (cmptr == NULL && (cmptr = malloc(CONTROLLEN)) == NULL) 122 err_sys("malloc error for control buffer"); 123 124 msg.msg_control = (caddr_t) cmptr; /* for dest address */ 125 msg.msg_controllen = CONTROLLEN; 126#else 127 msg.msg_control = (caddr_t) 0; /* no ancillary data */ 128 msg.msg_controllen = 0; 129#endif /* IP_RECVDSTADDR */ 130 msg.msg_flags = 0; /* flags returned here */ 131 132 nread = recvmsg(sockfd, &msg, 0); 133#endif /* HAVE_MSGHDR_MSG_CONTROL */ 134 if (nread < 0) 135 err_sys("datagram receive error"); 136 137 if (verbose) { 138 printf("from %s", INET_NTOA(cliaddr.sin_addr)); 139#ifdef HAVE_MSGHDR_MSG_CONTROL 140#ifdef IP_RECVDSTADDR 141 if (recvdstaddr) { 142 if (cmptr->cmsg_len != CONTROLLEN) 143 err_quit("control length (%d) != %d", 144 cmptr->cmsg_len, CONTROLLEN); 145 if (cmptr->cmsg_level != IPPROTO_IP) 146 err_quit("control level != IPPROTO_IP"); 147 if (cmptr->cmsg_type != IP_RECVDSTADDR) 148 err_quit("control type != IP_RECVDSTADDR"); 149 bcopy(CMSG_DATA(cmptr), &dstinaddr, 150 sizeof(struct in_addr)); 151 bzero(cmptr, CONTROLLEN); 152 153 printf(", to %s", INET_NTOA(dstinaddr)); 154 } 155#endif /* IP_RECVDSTADDR */ 156#endif /* HAVE_MSGHDR_MSG_CONTROL */ 157 printf(": "); 158 fflush(stdout); 159 } 160 161#ifdef MSG_TRUNC 162 if (msg.msg_flags & MSG_TRUNC) 163 printf("(datagram truncated)\n"); 164#endif 165 166 } else if (connectudp) { 167 /* msgpeek = 0 or MSG_PEEK */ 168 flags = msgpeek; 169 oncemore: 170 if ( (nread = recv(sockfd, rbuf, readlen, flags)) < 0) 171 err_sys("recv error"); 172 else if (nread == 0) { 173 if (verbose) 174 fprintf(stderr, "connection closed by peer\n"); 175 break; /* EOF, terminate */ 176 } 177 178 } else { 179 /* Must use recvfrom() for unconnected UDP client */ 180 servlen = sizeof(servaddr); 181 nread = recvfrom(sockfd, rbuf, readlen, 0, 182 (struct sockaddr *) &servaddr, &servlen); 183 if (nread < 0) 184 err_sys("datagram recvfrom() error"); 185 186 if (verbose) { 187 printf("from %s", INET_NTOA(servaddr.sin_addr)); 188 printf(": "); 189 fflush(stdout); 190 } 191 } 192 193 if (crlf) { 194 ntowrite = crlf_strip(wbuf, writelen, rbuf, nread); 195 if (writen(STDOUT_FILENO, wbuf, ntowrite) != ntowrite) 196 err_sys("writen error to stdout"); 197 } else { 198 if (writen(STDOUT_FILENO, rbuf, nread) != nread) 199 err_sys("writen error to stdout"); 200 } 201 202 if (flags != 0) { 203 flags = 0; /* no infinite loop */ 204 goto oncemore; /* read the message again */ 205 } 206 } 207 } 208 209 if (pauseclose) { 210 if (verbose) 211 fprintf(stderr, "pausing before close\n"); 212 sleep_us(pauseclose*1000); 213 } 214 215 if (close(sockfd) < 0) 216 err_sys("close error"); /* since SO_LINGER may be set */ 217} 218