1 /* 2 * 3 * Copyright (C) 2008, Linux Foundation, 4 * written by Michael Kerrisk <mtk.manpages (at) gmail.com> 5 * Initial Porting to LTP by Subrata <subrata (at) 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 56 static void setup(void) 57 { 58 TEST_PAUSE; 59 tst_tmpdir(); 60 } 61 62 static void cleanup(void) 63 { 64 tst_rmdir(); 65 } 66 67 #if !(__GLIBC_PREREQ(2, 10)) 68 static int 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 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 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 210 static void usage(void) 211 { 212 printf(" -p Port\n"); 213 } 214 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