1 /* 2 * Check decoding of SO_LINGER socket option. 3 * 4 * Copyright (c) 2017-2018 Dmitry V. Levin <ldv (at) 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 <stddef.h> 33 #include <stdio.h> 34 #include <string.h> 35 #include <sys/socket.h> 36 #include <unistd.h> 37 38 static const char *errstr; 39 40 static int 41 get_linger(int fd, void *val, socklen_t *len) 42 { 43 int rc = getsockopt(fd, SOL_SOCKET, SO_LINGER, val, len); 44 errstr = sprintrc(rc); 45 return rc; 46 } 47 48 static int 49 set_linger(int fd, void *val, socklen_t len) 50 { 51 int rc = setsockopt(fd, SOL_SOCKET, SO_LINGER, val, len); 52 errstr = sprintrc(rc); 53 return rc; 54 } 55 56 int 57 main(void) 58 { 59 TAIL_ALLOC_OBJECT_CONST_PTR(struct linger, linger); 60 TAIL_ALLOC_OBJECT_CONST_PTR(socklen_t, len); 61 62 const unsigned int sizeof_l_onoff = sizeof(linger->l_onoff); 63 struct linger *const l_onoff = tail_alloc(sizeof_l_onoff); 64 65 const unsigned int sizeof_l_onoff_truncated = sizeof_l_onoff - 1; 66 struct linger *const l_onoff_truncated = 67 tail_alloc(sizeof_l_onoff_truncated); 68 69 const unsigned int sizeof_l_linger_truncated = 70 offsetofend(struct linger, l_linger) - 1; 71 struct linger *const l_linger_truncated = 72 tail_alloc(sizeof_l_linger_truncated); 73 74 int fd = socket(AF_UNIX, SOCK_STREAM, 0); 75 if (fd < 0) 76 perror_msg_and_skip("socket AF_UNIX SOCK_STREAM"); 77 78 /* classic getsockopt */ 79 *len = sizeof(*linger); 80 get_linger(fd, linger, len); 81 printf("getsockopt(%d, SOL_SOCKET, SO_LINGER, {l_onoff=%d, l_linger=%d}" 82 ", [%d]) = %s\n", 83 fd, linger->l_onoff, linger->l_linger, *len, errstr); 84 85 /* classic setsockopt */ 86 linger->l_onoff = -15; 87 linger->l_linger = -42; 88 set_linger(fd, linger, sizeof(*linger)); 89 printf("setsockopt(%d, SOL_SOCKET, SO_LINGER, {l_onoff=%d, l_linger=%d}" 90 ", %d) = %s\n", 91 fd, linger->l_onoff, linger->l_linger, 92 (unsigned int) sizeof(*linger), errstr); 93 94 /* setsockopt with optlen larger than necessary */ 95 set_linger(fd, linger, sizeof(*linger) + 1); 96 printf("setsockopt(%d, SOL_SOCKET, SO_LINGER, {l_onoff=%d, l_linger=%d}" 97 ", %d) = %s\n", 98 fd, linger->l_onoff, linger->l_linger, 99 (unsigned int) sizeof(*linger) + 1, errstr); 100 101 /* setsockopt with optlen < 0 - EINVAL */ 102 set_linger(fd, linger, -1U); 103 printf("setsockopt(%d, SOL_SOCKET, SO_LINGER, %p, -1) = %s\n", 104 fd, linger, errstr); 105 106 /* setsockopt with optlen smaller than necessary - EINVAL */ 107 set_linger(fd, linger, sizeof(linger->l_onoff)); 108 printf("setsockopt(%d, SOL_SOCKET, SO_LINGER, %p, %d) = %s\n", 109 fd, linger, (unsigned int) sizeof(linger->l_onoff), errstr); 110 111 /* setsockopt optval EFAULT */ 112 set_linger(fd, &linger->l_linger, sizeof(*linger)); 113 printf("setsockopt(%d, SOL_SOCKET, SO_LINGER, %p, %d) = %s\n", 114 fd, &linger->l_linger, (unsigned int) sizeof(*linger), errstr); 115 116 /* getsockopt with zero optlen */ 117 *len = 0; 118 get_linger(fd, linger, len); 119 printf("getsockopt(%d, SOL_SOCKET, SO_LINGER, %p, [0]) = %s\n", 120 fd, linger, errstr); 121 122 /* getsockopt with optlen larger than necessary - shortened */ 123 *len = sizeof(*linger) + 1; 124 get_linger(fd, linger, len); 125 printf("getsockopt(%d, SOL_SOCKET, SO_LINGER, {l_onoff=%d, l_linger=%d}" 126 ", [%u->%d]) = %s\n", 127 fd, linger->l_onoff, linger->l_linger, 128 (unsigned int) sizeof(*linger) + 1, *len, errstr); 129 130 /* 131 * getsockopt with optlen less than sizeof(linger->l_onoff): 132 * the part of struct linger.l_onoff is printed in hex. 133 */ 134 *len = sizeof_l_onoff_truncated; 135 get_linger(fd, l_onoff_truncated, len); 136 printf("getsockopt(%d, SOL_SOCKET, SO_LINGER, {l_onoff=", fd); 137 print_quoted_hex(l_onoff_truncated, *len); 138 printf("}, [%d]) = %s\n", *len, errstr); 139 140 /* 141 * getsockopt with optlen equals to sizeof(struct linger.l_onoff): 142 * struct linger.l_linger is not printed. 143 */ 144 *len = sizeof_l_onoff; 145 get_linger(fd, l_onoff, len); 146 printf("getsockopt(%d, SOL_SOCKET, SO_LINGER, {l_onoff=%d}" 147 ", [%d]) = %s\n", 148 fd, l_onoff->l_onoff, *len, errstr); 149 150 /* 151 * getsockopt with optlen greater than sizeof(struct linger.l_onoff) 152 * but smaller than sizeof(struct linger): 153 * the part of struct linger.l_linger is printed in hex. 154 */ 155 *len = sizeof_l_linger_truncated; 156 get_linger(fd, l_linger_truncated, len); 157 /* 158 * Copy to a properly aligned structure to avoid unaligned access 159 * to struct linger.l_onoff field. 160 */ 161 memcpy(linger, l_linger_truncated, sizeof_l_linger_truncated); 162 printf("getsockopt(%d, SOL_SOCKET, SO_LINGER, {l_onoff=%d, l_linger=", 163 fd, linger->l_onoff); 164 print_quoted_hex(&linger->l_linger, sizeof_l_linger_truncated - 165 offsetof(struct linger, l_linger)); 166 printf("}, [%d]) = %s\n", *len, errstr); 167 168 /* getsockopt optval EFAULT */ 169 *len = sizeof(*linger); 170 get_linger(fd, &linger->l_linger, len); 171 printf("getsockopt(%d, SOL_SOCKET, SO_LINGER, %p, [%d]) = %s\n", 172 fd, &linger->l_linger, *len, errstr); 173 174 /* getsockopt optlen EFAULT */ 175 get_linger(fd, linger, len + 1); 176 printf("getsockopt(%d, SOL_SOCKET, SO_LINGER, %p, %p) = %s\n", 177 fd, linger, len + 1, errstr); 178 179 puts("+++ exited with 0 +++"); 180 return 0; 181 } 182