1 /*
2 *
3 * Copyright (c) International Business Machines Corp., 2001
4 * Copyright (c) Cyril Hrubis <chrubis@suse.cz> 2012
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
14 * the GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 /*
22 * Test Name: send01
23 *
24 * Test Description:
25 * Verify that send() returns the proper errno for various failure cases
26 *
27 * HISTORY
28 * 07/2001 Ported by Wayne Boyer
29 *
30 */
31
32 #include <stdio.h>
33 #include <unistd.h>
34 #include <errno.h>
35 #include <fcntl.h>
36
37 #include <sys/types.h>
38 #include <sys/socket.h>
39 #include <sys/signal.h>
40 #include <sys/un.h>
41
42 #include <netinet/in.h>
43
44 #include "test.h"
45 #include "safe_macros.h"
46
47 char *TCID = "send01";
48 int testno;
49
50 static char buf[1024], bigbuf[128 * 1024];
51 static int s;
52 static struct sockaddr_in sin1;
53 static int sfd; /* shared between do_child and start_server */
54
55 struct test_case_t { /* test case structure */
56 int domain; /* PF_INET, PF_UNIX, ... */
57 int type; /* SOCK_STREAM, SOCK_DGRAM ... */
58 int proto; /* protocol number (usually 0 = default) */
59 void *buf; /* send data buffer */
60 int buflen; /* send's 3rd argument */
61 unsigned flags; /* send's 4th argument */
62 int retval;
63 int experrno;
64 void (*setup) (void);
65 void (*cleanup) (void);
66 char *desc;
67 };
68
69 static void cleanup(void);
70 static void do_child(void);
71 static void setup(void);
72 static void setup0(void);
73 static void setup1(void);
74 static void setup2(void);
75 static void cleanup0(void);
76 static void cleanup1(void);
77
78 static struct test_case_t tdat[] = {
79 {.domain = PF_INET,
80 .type = SOCK_STREAM,
81 .proto = 0,
82 .buf = buf,
83 .buflen = sizeof(buf),
84 .flags = 0,
85 .retval = -1,
86 .experrno = EBADF,
87 .setup = setup0,
88 .cleanup = cleanup0,
89 .desc = "bad file descriptor"}
90 ,
91 {.domain = 0,
92 .type = 0,
93 .proto = 0,
94 .buf = buf,
95 .buflen = sizeof(buf),
96 .flags = 0,
97 .retval = -1,
98 .experrno = ENOTSOCK,
99 .setup = setup0,
100 .cleanup = cleanup0,
101 .desc = "invalid socket"}
102 ,
103 #ifndef UCLINUX
104 /* Skip since uClinux does not implement memory protection */
105 {.domain = PF_INET,
106 .type = SOCK_STREAM,
107 .proto = 0,
108 .buf = (void *)-1,
109 .buflen = sizeof(buf),
110 .flags = 0,
111 .retval = -1,
112 .experrno = EFAULT,
113 .setup = setup1,
114 .cleanup = cleanup1,
115 .desc = "invalid send buffer"}
116 ,
117 #endif
118 {.domain = PF_INET,
119 .type = SOCK_DGRAM,
120 .proto = 0,
121 .buf = bigbuf,
122 .buflen = sizeof(bigbuf),
123 .flags = 0,
124 .retval = -1,
125 .experrno = EMSGSIZE,
126 .setup = setup1,
127 .cleanup = cleanup1,
128 .desc = "UDP message too big"}
129 ,
130 {.domain = PF_INET,
131 .type = SOCK_STREAM,
132 .proto = 0,
133 .buf = buf,
134 .buflen = sizeof(buf),
135 .flags = 0,
136 .retval = -1,
137 .experrno = EPIPE,
138 .setup = setup2,
139 .cleanup = cleanup1,
140 .desc = "local endpoint shutdown"}
141 ,
142 #ifndef UCLINUX
143 /* Skip since uClinux does not implement memory protection */
144 {.domain = PF_INET,
145 .type = SOCK_DGRAM,
146 .proto = 0,
147 .buf = buf,
148 .buflen = sizeof(buf),
149 .flags = MSG_OOB,
150 .retval = -1,
151 .experrno = EOPNOTSUPP,
152 .setup = setup1,
153 .cleanup = cleanup1,
154 .desc = "invalid flags set"}
155 #endif
156 };
157
158 int TST_TOTAL = sizeof(tdat) / sizeof(tdat[0]);
159
160 #ifdef UCLINUX
161 static char *argv0;
162 #endif
163
start_server(struct sockaddr_in * sin0)164 static pid_t start_server(struct sockaddr_in *sin0)
165 {
166 pid_t pid;
167 socklen_t slen = sizeof(*sin0);
168
169 sin0->sin_family = AF_INET;
170 sin0->sin_port = 0; /* pick random free port */
171 sin0->sin_addr.s_addr = INADDR_ANY;
172
173 sfd = socket(PF_INET, SOCK_STREAM, 0);
174 if (sfd < 0) {
175 tst_brkm(TBROK | TERRNO, cleanup, "server socket failed");
176 return -1;
177 }
178 if (bind(sfd, (struct sockaddr *)sin0, sizeof(*sin0)) < 0) {
179 tst_brkm(TBROK | TERRNO, cleanup, "server bind failed");
180 return -1;
181 }
182 if (listen(sfd, 10) < 0) {
183 tst_brkm(TBROK | TERRNO, cleanup, "server listen failed");
184 return -1;
185 }
186 SAFE_GETSOCKNAME(cleanup, sfd, (struct sockaddr *)sin0, &slen);
187
188 switch ((pid = FORK_OR_VFORK())) {
189 case 0:
190 #ifdef UCLINUX
191 if (self_exec(argv0, "d", sfd) < 0)
192 tst_brkm(TBROK | TERRNO, cleanup,
193 "server self_exec failed");
194 #else
195 do_child();
196 #endif
197 break;
198 case -1:
199 tst_brkm(TBROK | TERRNO, cleanup, "server fork failed");
200 default:
201 close(sfd);
202 return pid;
203 }
204
205 exit(1);
206 }
207
do_child(void)208 static void do_child(void)
209 {
210 fd_set afds, rfds;
211 int nfds, cc, fd;
212 struct sockaddr_in fsin;
213
214 FD_ZERO(&afds);
215 FD_SET(sfd, &afds);
216
217 nfds = sfd + 1;
218
219 /* accept connections until killed */
220 while (1) {
221 socklen_t fromlen;
222
223 memcpy(&rfds, &afds, sizeof(rfds));
224
225 if (select(nfds, &rfds, NULL, NULL, NULL) < 0)
226 if (errno != EINTR)
227 exit(1);
228 if (FD_ISSET(sfd, &rfds)) {
229 int newfd;
230
231 fromlen = sizeof(fsin);
232 newfd = accept(sfd, (struct sockaddr *)&fsin, &fromlen);
233 if (newfd >= 0) {
234 FD_SET(newfd, &afds);
235 nfds = MAX(nfds, newfd + 1);
236 }
237 }
238 for (fd = 0; fd < nfds; ++fd) {
239 if (fd != sfd && FD_ISSET(fd, &rfds)) {
240 cc = read(fd, buf, sizeof(buf));
241 if (cc == 0 || (cc < 0 && errno != EINTR)) {
242 close(fd);
243 FD_CLR(fd, &afds);
244 }
245 }
246 }
247 }
248 }
249
main(int ac,char * av[])250 int main(int ac, char *av[])
251 {
252 int lc;
253
254 tst_parse_opts(ac, av, NULL, NULL);
255
256 #ifdef UCLINUX
257 argv0 = av[0];
258 maybe_run_child(&do_child, "d", &sfd);
259 #endif
260
261 setup();
262
263 for (lc = 0; TEST_LOOPING(lc); ++lc) {
264
265 tst_count = 0;
266
267 for (testno = 0; testno < TST_TOTAL; ++testno) {
268 tdat[testno].setup();
269
270 TEST(send(s, tdat[testno].buf, tdat[testno].buflen,
271 tdat[testno].flags));
272
273 if (TEST_RETURN != -1) {
274 tst_resm(TFAIL, "call succeeded unexpectedly");
275 continue;
276 }
277
278 if (TEST_ERRNO != tdat[testno].experrno) {
279 tst_resm(TFAIL, "%s ; returned"
280 " %ld (expected %d), errno %d (expected"
281 " %d)", tdat[testno].desc,
282 TEST_RETURN, tdat[testno].retval,
283 TEST_ERRNO, tdat[testno].experrno);
284 } else {
285 tst_resm(TPASS, "%s successful",
286 tdat[testno].desc);
287 }
288 tdat[testno].cleanup();
289 }
290 }
291 cleanup();
292
293 tst_exit();
294 }
295
296 static pid_t server_pid;
297
setup(void)298 static void setup(void)
299 {
300 TEST_PAUSE;
301
302 server_pid = start_server(&sin1);
303
304 signal(SIGPIPE, SIG_IGN);
305 }
306
cleanup(void)307 static void cleanup(void)
308 {
309 kill(server_pid, SIGKILL);
310
311 }
312
setup0(void)313 static void setup0(void)
314 {
315 if (tdat[testno].experrno == EBADF)
316 s = 400; /* anything not an open file */
317 else if ((s = open("/dev/null", O_WRONLY)) == -1)
318 tst_brkm(TBROK | TERRNO, cleanup, "open(/dev/null) failed");
319 }
320
cleanup0(void)321 static void cleanup0(void)
322 {
323 s = -1;
324 }
325
setup1(void)326 static void setup1(void)
327 {
328 s = SAFE_SOCKET(cleanup, tdat[testno].domain, tdat[testno].type,
329 tdat[testno].proto);
330 SAFE_CONNECT(cleanup, s, (const struct sockaddr *)&sin1, sizeof(sin1));
331 }
332
cleanup1(void)333 static void cleanup1(void)
334 {
335 close(s);
336 s = -1;
337 }
338
setup2(void)339 static void setup2(void)
340 {
341 setup1();
342
343 if (shutdown(s, 1) < 0)
344 tst_brkm(TBROK | TERRNO, cleanup, "socket setup failed connect "
345 "test %d", testno);
346 }
347