Home | History | Annotate | Download | only in accept4
      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