1/*
2 *
3 *   Copyright (c) International Business Machines  Corp., 2001
4 *   07/2001 Ported by Wayne Boyer
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 Foundation,
18 *   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21/*
22 *  Verify that getpeername() returns the proper errno for various failure cases
23 */
24
25#include <stdio.h>
26#include <unistd.h>
27#include <errno.h>
28#include <fcntl.h>
29#include <sys/types.h>
30#include <sys/socket.h>
31#include <sys/signal.h>
32#include <sys/ioctl.h>
33#include <netinet/in.h>
34
35#include "test.h"
36#include "safe_macros.h"
37
38static struct sockaddr_in server_addr;
39static struct sockaddr_in fsin1;
40static socklen_t sinlen;
41static socklen_t invalid_sinlen = -1;
42static int sv[2];
43
44static void setup(void);
45static void setup2(int);
46static void setup3(int);
47static void setup4(int);
48static void cleanup(void);
49static void cleanup2(int);
50static void cleanup4(int);
51
52struct test_case_t {
53	int sockfd;
54	struct sockaddr *sockaddr;
55	socklen_t *addrlen;
56	int expretval;
57	int experrno;
58	void (*setup) (int);
59	void (*cleanup) (int);
60	char *name;
61} test_cases[] = {
62	{-1, (struct sockaddr *)&fsin1, &sinlen, -1, EBADF, NULL, NULL,
63	 "EBADF"},
64	{-1, (struct sockaddr *)&fsin1, &sinlen, -1, ENOTSOCK, setup2, cleanup2,
65	 "ENOTSOCK"},
66	{-1, (struct sockaddr *)&fsin1, &sinlen, -1, ENOTCONN, setup3, cleanup2,
67	 "ENOTCONN"},
68	{-1, (struct sockaddr *)&fsin1, &invalid_sinlen, -1, EINVAL, setup4,
69	 cleanup4, "EINVAL"},
70#ifndef UCLINUX
71	{-1, (struct sockaddr *)-1, &sinlen, -1, EFAULT, setup4, cleanup4,
72	 "EFAULT"},
73	{-1, (struct sockaddr *)&fsin1, NULL, -1, EFAULT, setup4,
74	 cleanup4, "EFAULT"},
75	{-1, (struct sockaddr *)&fsin1, (socklen_t *)1, -1, EFAULT, setup4,
76	 cleanup4, "EFAULT"},
77#endif
78};
79
80char *TCID = "getpeername01";
81int TST_TOTAL = ARRAY_SIZE(test_cases);
82
83int main(int argc, char *argv[])
84{
85	int lc;
86	int i;
87
88	tst_parse_opts(argc, argv, NULL, NULL);
89
90	setup();
91
92	for (lc = 0; TEST_LOOPING(lc); ++lc) {
93
94		tst_count = 0;
95
96		for (i = 0; i < TST_TOTAL; ++i) {
97
98			if (test_cases[i].setup != NULL)
99				test_cases[i].setup(i);
100
101			TEST(getpeername(test_cases[i].sockfd,
102					 test_cases[i].sockaddr,
103					 test_cases[i].addrlen));
104
105			if (TEST_RETURN == test_cases[i].expretval &&
106			    TEST_ERRNO == test_cases[i].experrno) {
107				tst_resm(TPASS,
108					 "test getpeername() %s successful",
109					 test_cases[i].name);
110			} else {
111				tst_resm(TFAIL,
112					 "test getpeername() %s failed; "
113					 "returned %ld (expected %d), errno %d "
114					 "(expected %d)", test_cases[i].name,
115					 TEST_RETURN, test_cases[i].expretval,
116					 TEST_ERRNO, test_cases[i].experrno);
117			}
118
119			if (test_cases[i].cleanup != NULL)
120				test_cases[i].cleanup(i);
121		}
122	}
123
124	cleanup();
125
126	tst_exit();
127}
128
129static void setup(void)
130{
131	TEST_PAUSE;
132
133	server_addr.sin_family = AF_INET;
134	server_addr.sin_port = 0;
135	server_addr.sin_addr.s_addr = INADDR_ANY;
136
137	sinlen = sizeof(fsin1);
138}
139
140static void cleanup(void)
141{
142}
143
144static void setup2(int i)
145{
146	test_cases[i].sockfd = SAFE_OPEN(cleanup, "/dev/null", O_WRONLY, 0666);
147}
148
149static void setup3(int i)
150{
151	test_cases[i].sockfd = socket(PF_INET, SOCK_STREAM, 0);
152	if (test_cases[i].sockfd < 0) {
153		tst_brkm(TBROK | TERRNO, cleanup,
154			 "socket setup failed for getpeername test %d", i);
155	}
156	if (bind(test_cases[i].sockfd, (struct sockaddr *)&server_addr,
157		 sizeof(server_addr)) < 0) {
158		tst_brkm(TBROK | TERRNO, cleanup,
159			 "socket bind failed for getpeername test %d", i);
160	}
161}
162
163static void setup4(int i)
164{
165	if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) < 0) {
166		tst_brkm(TBROK | TERRNO, cleanup,
167			 "socketpair failed for getpeername test %d", i);
168	}
169	test_cases[i].sockfd = sv[0];
170}
171
172static void cleanup2(int i)
173{
174	SAFE_CLOSE(cleanup, test_cases[i].sockfd);
175}
176
177static void cleanup4(int i)
178{
179	SAFE_CLOSE(cleanup, sv[0]);
180	SAFE_CLOSE(cleanup, sv[1]);
181}
182