1/* $NetBSD: t_tcp.c,v 1.4 2016/03/04 18:52:01 christos Exp $ */ 2 3/*- 4 * Copyright (c) 2013 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the NetBSD 18 * Foundation, Inc. and its contributors. 19 * 4. Neither the name of The NetBSD Foundation nor the names of its 20 * contributors may be used to endorse or promote products derived 21 * from this software without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 24 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 25 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 26 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 27 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 28 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33 * POSSIBILITY OF SUCH DAMAGE. 34 */ 35 36#include <sys/cdefs.h> 37#ifdef __RCSID 38__RCSID("$Id: t_tcp.c,v 1.4 2016/03/04 18:52:01 christos Exp $"); 39#endif 40 41/* Example code. Should block; does with accept not paccept. */ 42/* Original by: Justin Cormack <justin@specialbusrvrervice.com> */ 43 44#include <sys/param.h> 45#include <sys/types.h> 46#include <sys/socket.h> 47#include <netinet/in.h> 48#include <stdio.h> 49#include <stdbool.h> 50#include <unistd.h> 51#include <fcntl.h> 52#include <errno.h> 53#include <err.h> 54#include <stdlib.h> 55#include <signal.h> 56 57#ifdef TEST 58#define FAIL(msg, ...) err(EXIT_FAILURE, msg, ## __VA_ARGS__) 59#else 60#include <atf-c.h> 61#define FAIL(msg, ...) ATF_CHECK_MSG(0, msg, ## __VA_ARGS__); goto fail 62#endif 63 64#ifdef __linux__ 65#define paccept(a, b, c, d, e) accept4((a), (b), (c), (e)) 66#endif 67 68static void 69ding(int al) 70{ 71} 72 73static void 74paccept_block(bool pacceptblock, bool fcntlblock) 75{ 76 int srvr = -1, clnt = -1, as = -1; 77 int ok, fl; 78 ssize_t n; 79 char buf[10]; 80 struct sockaddr_in sin, ba; 81 struct sigaction sa; 82 83 srvr = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); 84 if (srvr == -1) 85 FAIL("socket"); 86 87 memset(&sin, 0, sizeof(sin)); 88 sin.sin_family = AF_INET; 89#ifdef BSD4_4 90 sin.sin_len = sizeof(sin); 91#endif 92 sin.sin_port = htons(0); 93 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 94 ok = bind(srvr, (const struct sockaddr *)&sin, (socklen_t)sizeof(sin)); 95 if (ok == -1) 96 FAIL("bind"); 97 98 socklen_t addrlen = sizeof(struct sockaddr_in); 99 ok = getsockname(srvr, (struct sockaddr *)&ba, &addrlen); 100 if (ok == -1) 101 FAIL("getsockname"); 102 103 ok = listen(srvr, SOMAXCONN); 104 if (ok == -1) 105 FAIL("listen"); 106 107 clnt = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); 108 if (clnt == -1) 109 FAIL("socket"); 110 111 /* may not connect first time */ 112 ok = connect(clnt, (struct sockaddr *) &ba, addrlen); 113 if (ok != -1 || errno != EINPROGRESS) 114 FAIL("expected connect to fail"); 115 as = paccept(srvr, NULL, NULL, NULL, pacceptblock ? 0 : SOCK_NONBLOCK); 116 ok = connect(clnt, (struct sockaddr *) &ba, addrlen); 117 if (ok == -1 && errno != EISCONN) 118 FAIL("connect failed"); 119 120#if 0 121 fl = fcntl(srvr, F_GETFL, 0); 122 if (fl == -1) 123 FAIL("fnctl getfl"); 124 125 ok = fcntl(srvr, F_SETFL, fl & ~O_NONBLOCK); 126 if (ok == -1) 127 FAIL("fnctl setfl"); 128#endif 129 130 if (as == -1) { /* not true under NetBSD */ 131 as = paccept(srvr, NULL, NULL, NULL, pacceptblock ? 0 : SOCK_NONBLOCK); 132 if (as == -1) 133 FAIL("paccept"); 134 } 135 if (fcntlblock) { 136 fl = fcntl(as, F_GETFL, 0); 137 if (fl == -1) 138 FAIL("fnctl"); 139 if (fl != (O_RDWR|O_NONBLOCK)) 140 FAIL("fl 0x%x != 0x%x\n", fl, O_RDWR|O_NONBLOCK); 141 ok = fcntl(as, F_SETFL, fl & ~O_NONBLOCK); 142 if (ok == -1) 143 FAIL("fnctl setfl"); 144 145 fl = fcntl(as, F_GETFL, 0); 146 if (fl & O_NONBLOCK) 147 FAIL("fl non blocking after reset"); 148 } 149 sa.sa_handler = ding; 150 sa.sa_flags = 0; 151 sigemptyset(&sa.sa_mask); 152 sigaction(SIGALRM, &sa, NULL); 153 alarm(1); 154 n = read(as, buf, 10); 155 156 if (pacceptblock || fcntlblock) { 157 if (n == -1 && errno != EINTR) 158 FAIL("read"); 159 } else { 160 if (n != -1 || errno != EWOULDBLOCK) 161 FAIL("read"); 162 } 163 return; 164fail: 165 close(srvr); 166 close(clnt); 167 close(as); 168} 169 170#ifndef TEST 171 172ATF_TC(paccept_reset_nonblock); 173ATF_TC_HEAD(paccept_reset_nonblock, tc) 174{ 175 176 atf_tc_set_md_var(tc, "descr", "Check that paccept(2) resets " 177 "the non-blocking flag on non-blocking sockets"); 178} 179 180ATF_TC_BODY(paccept_reset_nonblock, tc) 181{ 182 paccept_block(true, false); 183} 184 185ATF_TC(fcntl_reset_nonblock); 186ATF_TC_HEAD(fcntl_reset_nonblock, tc) 187{ 188 189 atf_tc_set_md_var(tc, "descr", "Check that fcntl(2) resets " 190 "the non-blocking flag on non-blocking sockets"); 191} 192 193ATF_TC_BODY(fcntl_reset_nonblock, tc) 194{ 195 paccept_block(false, true); 196} 197 198ATF_TC(paccept_nonblock); 199ATF_TC_HEAD(paccept_nonblock, tc) 200{ 201 202 atf_tc_set_md_var(tc, "descr", "Check that fcntl(2) resets " 203 "the non-blocking flag on non-blocking sockets"); 204} 205 206ATF_TC_BODY(paccept_nonblock, tc) 207{ 208 paccept_block(false, false); 209} 210 211ATF_TP_ADD_TCS(tp) 212{ 213 214 ATF_TP_ADD_TC(tp, paccept_reset_nonblock); 215 ATF_TP_ADD_TC(tp, fcntl_reset_nonblock); 216 ATF_TP_ADD_TC(tp, paccept_nonblock); 217 return atf_no_error(); 218} 219#else 220int 221main(int argc, char *argv[]) 222{ 223 paccept_block(false); 224 paccept_block(true); 225 return 0; 226} 227#endif 228