1 /* -*- c-basic-offset: 8; -*-
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.
13 #include <sys/types.h>
14 #include <netinet/in.h>
15 #include <arpa/inet.h>
18 /* Copy everything from stdin to "sockfd",
19 * and everything from "sockfd" to stdout. */
24 int maxfdp1
, nread
, ntowrite
, stdineof
, clilen
, servlen
, flags
;
26 struct sockaddr_in cliaddr
; /* for UDP server */
27 struct sockaddr_in servaddr
; /* for UDP client */
29 #ifdef HAVE_MSGHDR_MSG_CONTROL
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 */
39 #endif /* MSG_TRUNC */
42 sleep_us(pauseinit
*1000); /* intended for server */
47 maxfdp1
= sockfd
+ 1; /* check descriptors [0..sockfd] */
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. */
55 FD_SET(STDIN_FILENO
, &rset
);
56 FD_SET(sockfd
, &rset
);
58 if (select(maxfdp1
, &rset
, NULL
, NULL
, NULL
) < 0)
59 err_sys("select error");
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) {
68 if (shutdown(sockfd
, SHUT_WR
) < 0)
69 err_sys("shutdown() error");
71 FD_CLR(STDIN_FILENO
, &rset
);
72 stdineof
= 1; /* don't read stdin anymore */
73 continue; /* back to select() */
75 break; /* default: stdin EOF -> done */
79 ntowrite
= crlf_add(wbuf
, writelen
, rbuf
, nread
);
81 if (write(sockfd
, wbuf
, ntowrite
) != ntowrite
)
82 err_sys("write error");
84 if (sendto(sockfd
, wbuf
, ntowrite
, 0,
85 (struct sockaddr
*) &servaddr
, sizeof(servaddr
))
87 err_sys("sendto error");
91 if (write(sockfd
, rbuf
, nread
) != nread
)
92 err_sys("write error");
94 if (sendto(sockfd
, rbuf
, nread
, 0,
95 (struct sockaddr
*) &servaddr
, sizeof(servaddr
))
97 err_sys("sendto error");
102 if (FD_ISSET(sockfd
, &rset
)) {
103 /* data to read from socket */
105 clilen
= sizeof(cliaddr
);
106 #ifndef MSG_TRUNC /* vanilla BSD sockets */
107 nread
= recvfrom(sockfd
, rbuf
, readlen
, 0,
108 (struct sockaddr
*) &cliaddr
, &clilen
);
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) */
113 iov
[0].iov_base
= rbuf
;
114 iov
[0].iov_len
= readlen
;
117 msg
.msg_name
= (caddr_t
) &cliaddr
;
118 msg
.msg_namelen
= clilen
;
120 #ifdef IP_RECVDSTADDR
121 if (cmptr
== NULL
&& (cmptr
= malloc(CONTROLLEN
)) == NULL
)
122 err_sys("malloc error for control buffer");
124 msg
.msg_control
= (caddr_t
) cmptr
; /* for dest address */
125 msg
.msg_controllen
= CONTROLLEN
;
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 */
132 nread
= recvmsg(sockfd
, &msg
, 0);
133 #endif /* HAVE_MSGHDR_MSG_CONTROL */
135 err_sys("datagram receive error");
138 printf("from %s", INET_NTOA(cliaddr
.sin_addr
));
139 #ifdef HAVE_MSGHDR_MSG_CONTROL
140 #ifdef IP_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
);
153 printf(", to %s", INET_NTOA(dstinaddr
));
155 #endif /* IP_RECVDSTADDR */
156 #endif /* HAVE_MSGHDR_MSG_CONTROL */
162 if (msg
.msg_flags
& MSG_TRUNC
)
163 printf("(datagram truncated)\n");
166 } else if (connectudp
) {
167 /* msgpeek = 0 or MSG_PEEK */
170 if ( (nread
= recv(sockfd
, rbuf
, readlen
, flags
)) < 0)
171 err_sys("recv error");
172 else if (nread
== 0) {
174 fprintf(stderr
, "connection closed by peer\n");
175 break; /* EOF, terminate */
179 /* Must use recvfrom() for unconnected UDP client */
180 servlen
= sizeof(servaddr
);
181 nread
= recvfrom(sockfd
, rbuf
, readlen
, 0,
182 (struct sockaddr
*) &servaddr
, &servlen
);
184 err_sys("datagram recvfrom() error");
187 printf("from %s", INET_NTOA(servaddr
.sin_addr
));
194 ntowrite
= crlf_strip(wbuf
, writelen
, rbuf
, nread
);
195 if (writen(STDOUT_FILENO
, wbuf
, ntowrite
) != ntowrite
)
196 err_sys("writen error to stdout");
198 if (writen(STDOUT_FILENO
, rbuf
, nread
) != nread
)
199 err_sys("writen error to stdout");
203 flags
= 0; /* no infinite loop */
204 goto oncemore
; /* read the message again */
211 fprintf(stderr
, "pausing before close\n");
212 sleep_us(pauseclose
*1000);
215 if (close(sockfd
) < 0)
216 err_sys("close error"); /* since SO_LINGER may be set */