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