vfs: check userland buffers before reading them.
[haiku.git] / src / tests / kits / net / sock / loopudp.c
blob4a68465e403aa8e5dedb6f8d5d1caf649edd790f
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.
9 */
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"
18 /* Copy everything from stdin to "sockfd",
19 * and everything from "sockfd" to stdout. */
21 void
22 loop_udp(int sockfd)
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 */
29 #ifdef HAVE_MSGHDR_MSG_CONTROL
30 struct iovec iov[1];
31 struct msghdr msg;
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 */
41 if (pauseinit)
42 sleep_us(pauseinit*1000); /* intended for server */
44 flags = 0;
45 stdineof = 0;
46 FD_ZERO(&rset);
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. */
53 for ( ; ; ) {
54 if (stdineof == 0)
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) {
66 /* EOF on stdin */
67 if (halfclose) {
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 */
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");
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");
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);
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;
115 msg.msg_iov = iov;
116 msg.msg_iovlen = 1;
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;
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 */
132 nread = recvmsg(sockfd, &msg, 0);
133 #endif /* HAVE_MSGHDR_MSG_CONTROL */
134 if (nread < 0)
135 err_sys("datagram receive error");
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);
153 printf(", to %s", INET_NTOA(dstinaddr));
155 #endif /* IP_RECVDSTADDR */
156 #endif /* HAVE_MSGHDR_MSG_CONTROL */
157 printf(": ");
158 fflush(stdout);
161 #ifdef MSG_TRUNC
162 if (msg.msg_flags & MSG_TRUNC)
163 printf("(datagram truncated)\n");
164 #endif
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 */
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");
186 if (verbose) {
187 printf("from %s", INET_NTOA(servaddr.sin_addr));
188 printf(": ");
189 fflush(stdout);
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");
202 if (flags != 0) {
203 flags = 0; /* no infinite loop */
204 goto oncemore; /* read the message again */
209 if (pauseclose) {
210 if (verbose)
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 */