1 /*
2  *
3  * Copyright (C) 2008, Linux Foundation,
4  * written by Michael Kerrisk <mtk.manpages@gmail.com>
5  * Initial Porting to LTP by Subrata <subrata@linux.vnet.ibm.com>
6  *
7  * Licensed under the GNU GPLv2 or later.
8  * This program is free software;  you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY;  without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
16  * the GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program;  if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22 
23 #define _GNU_SOURCE
24 #include <unistd.h>
25 #include <sys/syscall.h>
26 #include <sys/socket.h>
27 #include <netinet/in.h>
28 #include <stdlib.h>
29 #include <fcntl.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <errno.h>
33 
34 #include "test.h"
35 #include "lapi/fcntl.h"
36 #include "lapi/syscalls.h"
37 
38 #define PORT_NUM 33333
39 
40 #define die(msg)	tst_brkm(TBROK|TERRNO, cleanup, msg)
41 
42 #ifndef SOCK_CLOEXEC
43 #define SOCK_CLOEXEC    O_CLOEXEC
44 #endif
45 #ifndef SOCK_NONBLOCK
46 #define SOCK_NONBLOCK   O_NONBLOCK
47 #endif
48 
49 #if defined(SYS_ACCEPT4)	/* the socketcall() number */
50 #define USE_SOCKETCALL 1
51 #endif
52 
53 char *TCID = "accept04_01";
54 int TST_TOTAL = 1;
55 
setup(void)56 static void setup(void)
57 {
58 	TEST_PAUSE;
59 	tst_tmpdir();
60 }
61 
cleanup(void)62 static void cleanup(void)
63 {
64 	tst_rmdir();
65 }
66 
67 #if !(__GLIBC_PREREQ(2, 10))
68 static int
accept4_01(int fd,struct sockaddr * sockaddr,socklen_t * addrlen,int flags)69 accept4_01(int fd, struct sockaddr *sockaddr, socklen_t *addrlen, int flags)
70 {
71 #ifdef DEBUG
72 	tst_resm(TINFO, "Calling accept4(): flags = %x", flags);
73 	if (flags != 0) {
74 		tst_resm(TINFO, " (");
75 		if (flags & SOCK_CLOEXEC)
76 			tst_resm(TINFO, "SOCK_CLOEXEC");
77 		if ((flags & SOCK_CLOEXEC) && (flags & SOCK_NONBLOCK))
78 			tst_resm(TINFO, " ");
79 		if (flags & SOCK_NONBLOCK)
80 			tst_resm(TINFO, "SOCK_NONBLOCK");
81 		tst_resm(TINFO, ")");
82 	}
83 	tst_resm(TINFO, "\n");
84 #endif
85 
86 #if USE_SOCKETCALL
87 	long args[6];
88 
89 	args[0] = fd;
90 	args[1] = (long)sockaddr;
91 	args[2] = (long)addrlen;
92 	args[3] = flags;
93 
94 	return ltp_syscall(__NR_socketcall, SYS_ACCEPT4, args);
95 #else
96 	return ltp_syscall(__NR_accept4, fd, sockaddr, addrlen, flags);
97 #endif
98 }
99 #endif
100 
101 static void
do_test(int lfd,struct sockaddr_in * conn_addr,int closeonexec_flag,int nonblock_flag)102 do_test(int lfd, struct sockaddr_in *conn_addr,
103 	int closeonexec_flag, int nonblock_flag)
104 {
105 	int connfd, acceptfd;
106 	int fdf, flf, fdf_pass, flf_pass;
107 	struct sockaddr_in claddr;
108 	socklen_t addrlen;
109 
110 #ifdef DEBUG
111 	tst_resm(TINFO, "=======================================\n");
112 #endif
113 
114 	connfd = socket(AF_INET, SOCK_STREAM, 0);
115 	if (connfd == -1)
116 		die("Socket Error");
117 	if (connect(connfd, (struct sockaddr *)conn_addr,
118 		    sizeof(struct sockaddr_in)) == -1)
119 		die("Connect Error");
120 
121 	addrlen = sizeof(struct sockaddr_in);
122 #if !(__GLIBC_PREREQ(2, 10))
123 	acceptfd = accept4_01(lfd, (struct sockaddr *)&claddr, &addrlen,
124 			      closeonexec_flag | nonblock_flag);
125 #else
126 	acceptfd = accept4(lfd, (struct sockaddr *)&claddr, &addrlen,
127 			   closeonexec_flag | nonblock_flag);
128 #endif
129 	if (acceptfd == -1) {
130 		if (errno == ENOSYS) {
131 			tst_brkm(TCONF, cleanup,
132 			         "syscall __NR_accept4 not supported");
133 		} else {
134 			tst_brkm(TBROK | TERRNO, cleanup, "accept4 failed");
135 		}
136 	}
137 
138 	fdf = fcntl(acceptfd, F_GETFD);
139 	if (fdf == -1)
140 		die("fcntl:F_GETFD");
141 	fdf_pass = ((fdf & FD_CLOEXEC) != 0) ==
142 	    ((closeonexec_flag & SOCK_CLOEXEC) != 0);
143 #ifdef DEBUG
144 	tst_resm(TINFO, "Close-on-exec flag is %sset (%s); ",
145 		 (fdf & FD_CLOEXEC) ? "" : "not ", fdf_pass ? "OK" : "failed");
146 #endif
147 	if (!fdf_pass)
148 		tst_resm(TFAIL,
149 			 "Close-on-exec flag mismatch, should be %x, actual %x",
150 			 fdf & FD_CLOEXEC, closeonexec_flag & SOCK_CLOEXEC);
151 
152 	flf = fcntl(acceptfd, F_GETFL);
153 	if (flf == -1)
154 		die("fcntl:F_GETFD");
155 	flf_pass = ((flf & O_NONBLOCK) != 0) ==
156 	    ((nonblock_flag & SOCK_NONBLOCK) != 0);
157 #ifdef DEBUG
158 	tst_resm(TINFO, "nonblock flag is %sset (%s)\n",
159 		 (flf & O_NONBLOCK) ? "" : "not ", flf_pass ? "OK" : "failed");
160 #endif
161 	if (!flf_pass)
162 		tst_resm(TFAIL,
163 			 "nonblock flag mismatch, should be %x, actual %x",
164 			 fdf & O_NONBLOCK, nonblock_flag & SOCK_NONBLOCK);
165 
166 	close(acceptfd);
167 	close(connfd);
168 
169 	if (fdf_pass && flf_pass)
170 		tst_resm(TPASS, "Test passed");
171 }
172 
create_listening_socket(int port_num)173 static int create_listening_socket(int port_num)
174 {
175 	struct sockaddr_in svaddr;
176 	int lfd;
177 	int optval;
178 
179 	memset(&svaddr, 0, sizeof(struct sockaddr_in));
180 	svaddr.sin_family = AF_INET;
181 	svaddr.sin_addr.s_addr = htonl(INADDR_ANY);
182 	svaddr.sin_port = htons(port_num);
183 
184 	lfd = socket(AF_INET, SOCK_STREAM, 0);
185 	if (lfd == -1)
186 		die("Socket Error");
187 
188 	optval = 1;
189 	if (setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &optval,
190 		       sizeof(optval)) == -1)
191 		die("Setsockopt Error");
192 
193 	if (bind(lfd, (struct sockaddr *)&svaddr,
194 		 sizeof(struct sockaddr_in)) == -1)
195 		die("Bind Error");
196 
197 	if (listen(lfd, 5) == -1)
198 		die("Listen Error");
199 
200 	return lfd;
201 }
202 
203 static char *opt_port;
204 
205 static option_t options[] = {
206 	{"p:", NULL, &opt_port},
207 	{NULL, NULL, NULL}
208 };
209 
usage(void)210 static void usage(void)
211 {
212 	printf("  -p      Port\n");
213 }
214 
main(int argc,char * argv[])215 int main(int argc, char *argv[])
216 {
217 	struct sockaddr_in conn_addr;
218 	int lfd;
219 	int port_num = PORT_NUM;
220 
221 	tst_parse_opts(argc, argv, options, usage);
222 
223 	if (opt_port)
224 		port_num = atoi(opt_port);
225 
226 	setup();
227 
228 	memset(&conn_addr, 0, sizeof(struct sockaddr_in));
229 	conn_addr.sin_family = AF_INET;
230 	conn_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
231 	conn_addr.sin_port = htons(port_num);
232 
233 	lfd = create_listening_socket(port_num);
234 
235 	do_test(lfd, &conn_addr, 0, 0);
236 	do_test(lfd, &conn_addr, SOCK_CLOEXEC, 0);
237 	do_test(lfd, &conn_addr, 0, SOCK_NONBLOCK);
238 	do_test(lfd, &conn_addr, SOCK_CLOEXEC, SOCK_NONBLOCK);
239 
240 	close(lfd);
241 	cleanup();
242 	tst_exit();
243 }
244