Home | History | Annotate | Download | only in sendto
      1 /*
      2  *
      3  *   Copyright (c) International Business Machines  Corp., 2001
      4  *   Copyright (c) Cyril Hrubis <chrubis (at) 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: sendto01
     23  *
     24  * Test Description:
     25  *  Verify that sendto() returns the proper errno for various failure cases
     26  *
     27  * HISTORY
     28  *	07/2001 Ported by Wayne Boyer
     29  */
     30 
     31 #include <stdio.h>
     32 #include <unistd.h>
     33 #include <errno.h>
     34 #include <fcntl.h>
     35 
     36 #include <sys/types.h>
     37 #include <sys/socket.h>
     38 #include <sys/signal.h>
     39 #include <sys/un.h>
     40 
     41 #include <netinet/in.h>
     42 
     43 #include "test.h"
     44 #include "safe_macros.h"
     45 
     46 char *TCID = "sendto01";
     47 int testno;
     48 
     49 static char buf[1024], bigbuf[128 * 1024];
     50 static int s;
     51 static struct sockaddr_in sin1, sin2;
     52 static int sfd;
     53 
     54 struct test_case_t {		/* test case structure */
     55 	int domain;		/* PF_INET, PF_UNIX, ... */
     56 	int type;		/* SOCK_STREAM, SOCK_DGRAM ... */
     57 	int proto;		/* protocol number (usually 0 = default) */
     58 	void *buf;		/* send data buffer */
     59 	int buflen;		/* send's 3rd argument */
     60 	unsigned flags;		/* send's 4th argument */
     61 	struct sockaddr_in *to;	/* destination */
     62 	int tolen;		/* length of "to" buffer */
     63 	int retval;
     64 	int experrno;
     65 	void (*setup) (void);
     66 	void (*cleanup) (void);
     67 	char *desc;
     68 };
     69 
     70 static void setup(void);
     71 static void setup0(void);
     72 static void setup1(void);
     73 static void setup2(void);
     74 static void setup3(void);
     75 static void cleanup(void);
     76 static void cleanup0(void);
     77 static void cleanup1(void);
     78 static void do_child(void);
     79 
     80 struct test_case_t tdat[] = {
     81 	{.domain = PF_INET,
     82 	 .type = SOCK_STREAM,
     83 	 .proto = 0,
     84 	 .buf = buf,
     85 	 .buflen = sizeof(buf),
     86 	 .flags = 0,
     87 	 .to = &sin1,
     88 	 .tolen = sizeof(sin1),
     89 	 .retval = -1,
     90 	 .experrno = EBADF,
     91 	 .setup = setup0,
     92 	 .cleanup = cleanup0,
     93 	 .desc = "bad file descriptor"}
     94 	,
     95 	{.domain = 0,
     96 	 .type = 0,
     97 	 .proto = 0,
     98 	 .buf = buf,
     99 	 .buflen = sizeof(buf),
    100 	 .flags = 0,
    101 	 .to = &sin1,
    102 	 .tolen = sizeof(sin1),
    103 	 .retval = -1,
    104 	 .experrno = ENOTSOCK,
    105 	 .setup = setup0,
    106 	 .cleanup = cleanup0,
    107 	 .desc = "invalid socket"}
    108 	,
    109 #ifndef UCLINUX
    110 	/* Skip since uClinux does not implement memory protection */
    111 	{.domain = PF_INET,
    112 	 .type = SOCK_DGRAM,
    113 	 .proto = 0,
    114 	 .buf = (void *)-1,
    115 	 .buflen = sizeof(buf),
    116 	 .flags = 0,
    117 	 .to = &sin1,
    118 	 .tolen = sizeof(sin1),
    119 	 .retval = -1,
    120 	 .experrno = EFAULT,
    121 	 .setup = setup1,
    122 	 .cleanup = cleanup1,
    123 	 .desc = "invalid send buffer"}
    124 	,
    125 #endif
    126 	{.domain = PF_INET,
    127 	 .type = SOCK_STREAM,
    128 	 .proto = 0,
    129 	 .buf = buf,
    130 	 .buflen = sizeof(buf),
    131 	 .flags = 0,
    132 	 .to = &sin2,
    133 	 .tolen = sizeof(sin2),
    134 	 .retval = 0,
    135 	 .experrno = EFAULT,
    136 	 .setup = setup1,
    137 	 .cleanup = cleanup1,
    138 	 .desc = "connected TCP"}
    139 	,
    140 	{.domain = PF_INET,
    141 	 .type = SOCK_STREAM,
    142 	 .proto = 0,
    143 	 .buf = buf,
    144 	 .buflen = sizeof(buf),
    145 	 .flags = 0,
    146 	 .to = &sin1,
    147 	 .tolen = sizeof(sin1),
    148 	 .retval = -1,
    149 	 .experrno = EPIPE,
    150 	 .setup = setup3,
    151 	 .cleanup = cleanup1,
    152 	 .desc = "not connected TCP"}
    153 	,
    154 	{.domain = PF_INET,
    155 	 .type = SOCK_DGRAM,
    156 	 .proto = 0,
    157 	 .buf = buf,
    158 	 .buflen = sizeof(buf),
    159 	 .flags = 0,
    160 	 .to = &sin1,
    161 	 .tolen = -1,
    162 	 .retval = -1,
    163 	 .experrno = EINVAL,
    164 	 .setup = setup1,
    165 	 .cleanup = cleanup1,
    166 	 .desc = "invalid to buffer length"}
    167 	,
    168 #ifndef UCLINUX
    169 	/* Skip since uClinux does not implement memory protection */
    170 	{.domain = PF_INET,
    171 	 .type = SOCK_DGRAM,
    172 	 .proto = 0,
    173 	 .buf = buf,
    174 	 .buflen = sizeof(buf),
    175 	 .flags = 0,
    176 	 .to = (struct sockaddr_in *)-1,
    177 	 .tolen = sizeof(sin1),
    178 	 .retval = -1,
    179 	 .experrno = EFAULT,
    180 	 .setup = setup1,
    181 	 .cleanup = cleanup1,
    182 	 .desc = "invalid to buffer"}
    183 	,
    184 #endif
    185 	{.domain = PF_INET,
    186 	 .type = SOCK_DGRAM,
    187 	 .proto = 0,
    188 	 .buf = bigbuf,
    189 	 .buflen = sizeof(bigbuf),
    190 	 .flags = 0,
    191 	 .to = &sin1,
    192 	 .tolen = sizeof(sin1),
    193 	 .retval = -1,
    194 	 .experrno = EMSGSIZE,
    195 	 .setup = setup1,
    196 	 .cleanup = cleanup1,
    197 	 .desc = "UDP message too big"}
    198 	,
    199 	{.domain = PF_INET,
    200 	 .type = SOCK_STREAM,
    201 	 .proto = 0,
    202 	 .buf = buf,
    203 	 .buflen = sizeof(buf),
    204 	 .flags = 0,
    205 	 .to = &sin1,
    206 	 .tolen = sizeof(sin1),
    207 	 .retval = -1,
    208 	 .experrno = EPIPE,
    209 	 .setup = setup2,
    210 	 .cleanup = cleanup1,
    211 	 .desc = "local endpoint shutdown"}
    212 	,
    213 	{.domain = PF_INET,
    214 	 .type = SOCK_DGRAM,
    215 	 .proto = 0,
    216 	 .buf = buf,
    217 	 .buflen = sizeof(buf),
    218 	 .flags = MSG_OOB,
    219 	 .to = &sin1,
    220 	 .tolen = sizeof(sin1),
    221 	 .retval = -1,
    222 	 .experrno = EOPNOTSUPP,
    223 	 .setup = setup1,
    224 	 .cleanup = cleanup1,
    225 	 .desc = "invalid flags set"}
    226 };
    227 
    228 int TST_TOTAL = sizeof(tdat) / sizeof(tdat[0]);
    229 
    230 #ifdef UCLINUX
    231 static char *argv0;
    232 #endif
    233 
    234 static pid_t start_server(struct sockaddr_in *sin0)
    235 {
    236 	pid_t pid;
    237 	socklen_t slen = sizeof(*sin0);
    238 
    239 	sin0->sin_family = AF_INET;
    240 	sin0->sin_port = 0; /* pick random free port */
    241 	sin0->sin_addr.s_addr = INADDR_ANY;
    242 
    243 	sfd = socket(PF_INET, SOCK_STREAM, 0);
    244 	if (sfd < 0) {
    245 		tst_brkm(TBROK | TERRNO, cleanup, "server socket failed");
    246 		return -1;
    247 	}
    248 	if (bind(sfd, (struct sockaddr *)sin0, sizeof(*sin0)) < 0) {
    249 		tst_brkm(TBROK | TERRNO, cleanup, "server bind failed");
    250 		return -1;
    251 	}
    252 	if (listen(sfd, 10) < 0) {
    253 		tst_brkm(TBROK | TERRNO, cleanup, "server listen failed");
    254 		return -1;
    255 	}
    256 	SAFE_GETSOCKNAME(cleanup, sfd, (struct sockaddr *)sin0, &slen);
    257 
    258 	switch ((pid = FORK_OR_VFORK())) {
    259 	case 0:
    260 #ifdef UCLINUX
    261 		if (self_exec(argv0, "d", sfd) < 0)
    262 			tst_brkm(TBROK | TERRNO, cleanup,
    263 				 "server self_exec failed");
    264 #else
    265 		do_child();
    266 #endif
    267 		break;
    268 	case -1:
    269 		tst_brkm(TBROK | TERRNO, cleanup, "server fork failed");
    270 	default:
    271 		(void)close(sfd);
    272 		return pid;
    273 	}
    274 
    275 	exit(1);
    276 }
    277 
    278 static void do_child(void)
    279 {
    280 	struct sockaddr_in fsin;
    281 	fd_set afds, rfds;
    282 	int nfds, cc, fd;
    283 
    284 	FD_ZERO(&afds);
    285 	FD_SET(sfd, &afds);
    286 
    287 	nfds = sfd + 1;
    288 
    289 	/* accept connections until killed */
    290 	while (1) {
    291 		socklen_t fromlen;
    292 
    293 		memcpy(&rfds, &afds, sizeof(rfds));
    294 
    295 		if (select(nfds, &rfds, NULL, NULL, NULL) < 0 && errno != EINTR)
    296 			exit(1);
    297 
    298 		if (FD_ISSET(sfd, &rfds)) {
    299 			int newfd;
    300 
    301 			fromlen = sizeof(fsin);
    302 			newfd = accept(sfd, (struct sockaddr *)&fsin, &fromlen);
    303 			if (newfd >= 0) {
    304 				FD_SET(newfd, &afds);
    305 				nfds = MAX(nfds, newfd + 1);
    306 			}
    307 		}
    308 		for (fd = 0; fd < nfds; ++fd) {
    309 			if (fd != sfd && FD_ISSET(fd, &rfds)) {
    310 				cc = read(fd, buf, sizeof(buf));
    311 				if (cc == 0 || (cc < 0 && errno != EINTR)) {
    312 					(void)close(fd);
    313 					FD_CLR(fd, &afds);
    314 				}
    315 			}
    316 		}
    317 	}
    318 }
    319 
    320 int main(int ac, char *av[])
    321 {
    322 	int lc;
    323 
    324 	tst_parse_opts(ac, av, NULL, NULL);
    325 
    326 #ifdef UCLINUX
    327 	argv0 = av[0];
    328 	maybe_run_child(&do_child, "d", &sfd);
    329 #endif
    330 
    331 	setup();
    332 
    333 	for (lc = 0; TEST_LOOPING(lc); ++lc) {
    334 
    335 		tst_count = 0;
    336 		for (testno = 0; testno < TST_TOTAL; ++testno) {
    337 			tdat[testno].setup();
    338 
    339 			TEST(sendto(s, tdat[testno].buf, tdat[testno].buflen,
    340 				    tdat[testno].flags,
    341 				    (const struct sockaddr *)tdat[testno].to,
    342 				    tdat[testno].tolen));
    343 
    344 			if (TEST_RETURN > 0)
    345 				TEST_RETURN = 0;
    346 
    347 			if (TEST_RETURN != tdat[testno].retval ||
    348 			    (TEST_RETURN < 0 &&
    349 			     TEST_ERRNO != tdat[testno].experrno)) {
    350 				tst_resm(TFAIL, "%s ; returned"
    351 					 " %ld (expected %d), errno %d (expected"
    352 					 " %d)", tdat[testno].desc,
    353 					 TEST_RETURN, tdat[testno].retval,
    354 					 TEST_ERRNO, tdat[testno].experrno);
    355 			} else {
    356 				tst_resm(TPASS, "%s successful",
    357 					 tdat[testno].desc);
    358 			}
    359 			tdat[testno].cleanup();
    360 		}
    361 	}
    362 	cleanup();
    363 
    364 	tst_exit();
    365 }
    366 
    367 static pid_t server_pid;
    368 
    369 static void setup(void)
    370 {
    371 	TEST_PAUSE;
    372 
    373 	server_pid = start_server(&sin1);
    374 
    375 	signal(SIGPIPE, SIG_IGN);
    376 }
    377 
    378 static void cleanup(void)
    379 {
    380 	kill(server_pid, SIGKILL);
    381 }
    382 
    383 static void setup0(void)
    384 {
    385 	if (tdat[testno].experrno == EBADF)
    386 		s = 400;
    387 	else if ((s = open("/dev/null", O_WRONLY)) == -1)
    388 		tst_brkm(TBROK | TERRNO, cleanup, "open(/dev/null) failed");
    389 }
    390 
    391 static void cleanup0(void)
    392 {
    393 	s = -1;
    394 }
    395 
    396 static void setup1(void)
    397 {
    398 	s = SAFE_SOCKET(cleanup, tdat[testno].domain, tdat[testno].type,
    399 			tdat[testno].proto);
    400 	SAFE_CONNECT(cleanup, s, (const struct sockaddr *)&sin1, sizeof(sin1));
    401 }
    402 
    403 static void cleanup1(void)
    404 {
    405 	(void)close(s);
    406 	s = -1;
    407 }
    408 
    409 static void setup2(void)
    410 {
    411 	setup1();
    412 	if (shutdown(s, 1) < 0)
    413 		tst_brkm(TBROK | TERRNO, cleanup, "socket setup failed connect "
    414 			 "test %d", testno);
    415 }
    416 
    417 static void setup3(void)
    418 {
    419 	s = SAFE_SOCKET(cleanup, tdat[testno].domain, tdat[testno].type,
    420 		        tdat[testno].proto);
    421 }
    422