1 /* 2 * Check decoding of SO_LINGER socket option. 3 * 4 * Copyright (c) 2017 Dmitry V. Levin <ldv@altlinux.org> 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. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #include "tests.h" 31 32 #include <stdio.h> 33 #include <sys/socket.h> 34 #include <unistd.h> 35 36 static const char *errstr; 37 38 static int 39 get_linger(int fd, void *val, socklen_t *len) 40 { 41 int rc = getsockopt(fd, SOL_SOCKET, SO_LINGER, val, len); 42 errstr = sprintrc(rc); 43 return rc; 44 } 45 46 static int 47 set_linger(int fd, void *val, socklen_t len) 48 { 49 int rc = setsockopt(fd, SOL_SOCKET, SO_LINGER, val, len); 50 errstr = sprintrc(rc); 51 return rc; 52 } 53 54 int 55 main(void) 56 { 57 TAIL_ALLOC_OBJECT_CONST_PTR(struct linger, linger); 58 TAIL_ALLOC_OBJECT_CONST_PTR(socklen_t, len); 59 int fd = socket(AF_UNIX, SOCK_STREAM, 0); 60 if (fd < 0) 61 perror_msg_and_skip("socket AF_UNIX SOCK_STREAM"); 62 63 /* classic getsockopt */ 64 *len = sizeof(*linger); 65 get_linger(fd, linger, len); 66 printf("getsockopt(%d, SOL_SOCKET, SO_LINGER, {l_onoff=%d, l_linger=%d}" 67 ", [%d]) = %s\n", 68 fd, linger->l_onoff, linger->l_linger, *len, errstr); 69 70 /* classic setsockopt */ 71 linger->l_onoff = -15; 72 linger->l_linger = -42; 73 set_linger(fd, linger, sizeof(*linger)); 74 printf("setsockopt(%d, SOL_SOCKET, SO_LINGER, {l_onoff=%d, l_linger=%d}" 75 ", %d) = %s\n", 76 fd, linger->l_onoff, linger->l_linger, 77 (unsigned int) sizeof(*linger), errstr); 78 79 /* setsockopt with optlen larger than necessary */ 80 set_linger(fd, linger, sizeof(*linger) + 1); 81 printf("setsockopt(%d, SOL_SOCKET, SO_LINGER, {l_onoff=%d, l_linger=%d}" 82 ", %d) = %s\n", 83 fd, linger->l_onoff, linger->l_linger, 84 (unsigned int) sizeof(*linger) + 1, errstr); 85 86 /* setsockopt with optlen < 0 - EINVAL */ 87 set_linger(fd, linger, -1U); 88 printf("setsockopt(%d, SOL_SOCKET, SO_LINGER, %p, -1) = %s\n", 89 fd, linger, errstr); 90 91 /* setsockopt with optlen smaller than necessary - EINVAL */ 92 set_linger(fd, linger, sizeof(linger->l_onoff)); 93 printf("setsockopt(%d, SOL_SOCKET, SO_LINGER, %p, %d) = %s\n", 94 fd, linger, (unsigned int) sizeof(linger->l_onoff), errstr); 95 96 /* setsockopt optval EFAULT */ 97 set_linger(fd, &linger->l_linger, sizeof(*linger)); 98 printf("setsockopt(%d, SOL_SOCKET, SO_LINGER, %p, %d) = %s\n", 99 fd, &linger->l_linger, (unsigned int) sizeof(*linger), errstr); 100 101 /* getsockopt with optlen larger than necessary - shortened */ 102 *len = sizeof(*linger) + 1; 103 get_linger(fd, linger, len); 104 printf("getsockopt(%d, SOL_SOCKET, SO_LINGER, {l_onoff=%d, l_linger=%d}" 105 ", [%u->%d]) = %s\n", 106 fd, linger->l_onoff, linger->l_linger, 107 (unsigned int) sizeof(*linger) + 1, *len, errstr); 108 109 /* getsockopt with optlen larger than usual - truncated to l_onoff */ 110 *len = sizeof(linger->l_onoff); 111 get_linger(fd, linger, len); 112 printf("getsockopt(%d, SOL_SOCKET, SO_LINGER, {l_onoff=%d}" 113 ", [%d]) = %s\n", 114 fd, linger->l_onoff, *len, errstr); 115 116 /* getsockopt with optlen larger than usual - truncated to raw */ 117 *len = sizeof(*linger) - 1; 118 get_linger(fd, linger, len); 119 printf("getsockopt(%d, SOL_SOCKET, SO_LINGER, ", fd); 120 print_quoted_hex(linger, *len); 121 printf(", [%d]) = %s\n", *len, errstr); 122 123 /* getsockopt optval EFAULT */ 124 *len = sizeof(*linger); 125 get_linger(fd, &linger->l_linger, len); 126 printf("getsockopt(%d, SOL_SOCKET, SO_LINGER, %p, [%d]) = %s\n", 127 fd, &linger->l_linger, *len, errstr); 128 129 /* getsockopt optlen EFAULT */ 130 get_linger(fd, linger, len + 1); 131 printf("getsockopt(%d, SOL_SOCKET, SO_LINGER, %p, %p) = %s\n", 132 fd, linger, len + 1, errstr); 133 134 puts("+++ exited with 0 +++"); 135 return 0; 136 } 137