(root)/
strace-6.5/
tests-m32/
so_linger.c
       1  /*
       2   * Check decoding of SO_LINGER socket option.
       3   *
       4   * Copyright (c) 2017-2021 Dmitry V. Levin <ldv@strace.io>
       5   * All rights reserved.
       6   *
       7   * SPDX-License-Identifier: GPL-2.0-or-later
       8   */
       9  
      10  #include "tests.h"
      11  
      12  #include <stddef.h>
      13  #include <stdio.h>
      14  #include <string.h>
      15  #include <sys/socket.h>
      16  #include <unistd.h>
      17  
      18  static const char *errstr;
      19  
      20  static int
      21  get_linger(int fd, void *val, socklen_t *len)
      22  {
      23  	int rc = getsockopt(fd, SOL_SOCKET, SO_LINGER, val, len);
      24  	errstr = sprintrc(rc);
      25  	return rc;
      26  }
      27  
      28  static int
      29  set_linger(int fd, void *val, socklen_t len)
      30  {
      31  	int rc = setsockopt(fd, SOL_SOCKET, SO_LINGER, val, len);
      32  	errstr = sprintrc(rc);
      33  	return rc;
      34  }
      35  
      36  int
      37  main(void)
      38  {
      39  	TAIL_ALLOC_OBJECT_CONST_PTR(struct linger, linger);
      40  	TAIL_ALLOC_OBJECT_CONST_PTR(socklen_t, len);
      41  
      42  	const unsigned int sizeof_l_onoff = sizeof(linger->l_onoff);
      43  	struct linger *const l_onoff = tail_alloc(sizeof_l_onoff);
      44  
      45  	const unsigned int sizeof_l_onoff_truncated = sizeof_l_onoff - 1;
      46  	struct linger *const l_onoff_truncated =
      47  		tail_alloc(sizeof_l_onoff_truncated);
      48  
      49  	const unsigned int sizeof_l_linger_truncated =
      50  		offsetofend(struct linger, l_linger) - 1;
      51  	struct linger *const l_linger_truncated =
      52  		tail_alloc(sizeof_l_linger_truncated);
      53  
      54          int fd = socket(AF_UNIX, SOCK_STREAM, 0);
      55          if (fd < 0)
      56                  perror_msg_and_skip("socket AF_UNIX SOCK_STREAM");
      57  
      58  	/* classic getsockopt */
      59  	*len = sizeof(*linger);
      60  	get_linger(fd, linger, len);
      61  	printf("getsockopt(%d, SOL_SOCKET, SO_LINGER, {l_onoff=%d, l_linger=%d}"
      62  	       ", [%d]) = %s\n",
      63  	       fd, linger->l_onoff, linger->l_linger, *len, errstr);
      64  
      65  	/* classic setsockopt */
      66  	linger->l_onoff = -15;
      67  	linger->l_linger = -42;
      68  	set_linger(fd, linger, sizeof(*linger));
      69  	printf("setsockopt(%d, SOL_SOCKET, SO_LINGER, {l_onoff=%d, l_linger=%d}"
      70  	       ", %d) = %s\n",
      71  	       fd, linger->l_onoff, linger->l_linger,
      72  	       (unsigned int) sizeof(*linger), errstr);
      73  
      74  	/* setsockopt with optlen larger than necessary */
      75  	set_linger(fd, linger, sizeof(*linger) + 1);
      76  	printf("setsockopt(%d, SOL_SOCKET, SO_LINGER, {l_onoff=%d, l_linger=%d}"
      77  	       ", %d) = %s\n",
      78  	       fd, linger->l_onoff, linger->l_linger,
      79  	       (unsigned int) sizeof(*linger) + 1, errstr);
      80  
      81  	/* setsockopt with optlen < 0 - EINVAL */
      82  	set_linger(fd, linger, -1U);
      83  	printf("setsockopt(%d, SOL_SOCKET, SO_LINGER, %p, -1) = %s\n",
      84  	       fd, linger, errstr);
      85  
      86  	/* setsockopt with optlen smaller than necessary - EINVAL */
      87  	set_linger(fd, linger, sizeof(linger->l_onoff));
      88  	printf("setsockopt(%d, SOL_SOCKET, SO_LINGER, %p, %d) = %s\n",
      89  	       fd, linger, (unsigned int) sizeof(linger->l_onoff), errstr);
      90  
      91  	/* setsockopt optval EFAULT */
      92  	set_linger(fd, &linger->l_linger, sizeof(*linger));
      93  	printf("setsockopt(%d, SOL_SOCKET, SO_LINGER, %p, %d) = %s\n",
      94  	       fd, &linger->l_linger, (unsigned int) sizeof(*linger), errstr);
      95  
      96  	/* getsockopt with zero optlen */
      97  	*len = 0;
      98  	get_linger(fd, linger, len);
      99  	printf("getsockopt(%d, SOL_SOCKET, SO_LINGER, %p, [0]) = %s\n",
     100  	       fd, linger, errstr);
     101  
     102  	/* getsockopt with optlen larger than necessary - shortened */
     103  	*len = sizeof(*linger) + 1;
     104  	get_linger(fd, linger, len);
     105  	printf("getsockopt(%d, SOL_SOCKET, SO_LINGER, {l_onoff=%d, l_linger=%d}"
     106  	       ", [%u => %d]) = %s\n",
     107  	       fd, linger->l_onoff, linger->l_linger,
     108  	       (unsigned int) sizeof(*linger) + 1, *len, errstr);
     109  
     110  	/*
     111  	 * getsockopt with optlen less than sizeof(linger->l_onoff):
     112  	 * the part of struct linger.l_onoff is printed in hex.
     113  	 */
     114  	*len = sizeof_l_onoff_truncated;
     115  	get_linger(fd, l_onoff_truncated, len);
     116  	printf("getsockopt(%d, SOL_SOCKET, SO_LINGER, {l_onoff=", fd);
     117  	print_quoted_hex(l_onoff_truncated, *len);
     118  	printf("}, [%d]) = %s\n", *len, errstr);
     119  
     120  	/*
     121  	 * getsockopt with optlen equals to sizeof(struct linger.l_onoff):
     122  	 * struct linger.l_linger is not printed.
     123  	 */
     124  	*len = sizeof_l_onoff;
     125  	get_linger(fd, l_onoff, len);
     126  	printf("getsockopt(%d, SOL_SOCKET, SO_LINGER, {l_onoff=%d}"
     127  	       ", [%d]) = %s\n",
     128  	       fd, l_onoff->l_onoff, *len, errstr);
     129  
     130  	/*
     131  	 * getsockopt with optlen greater than sizeof(struct linger.l_onoff)
     132  	 * but smaller than sizeof(struct linger):
     133  	 * the part of struct linger.l_linger is printed in hex.
     134  	 */
     135  	*len = sizeof_l_linger_truncated;
     136  	get_linger(fd, l_linger_truncated, len);
     137  	/*
     138  	 * Copy to a properly aligned structure to avoid unaligned access
     139  	 * to struct linger.l_onoff field.
     140  	 */
     141  	memcpy(linger, l_linger_truncated, sizeof_l_linger_truncated);
     142  	printf("getsockopt(%d, SOL_SOCKET, SO_LINGER, {l_onoff=%d, l_linger=",
     143  	       fd, linger->l_onoff);
     144  	print_quoted_hex(&linger->l_linger, sizeof_l_linger_truncated -
     145  					    offsetof(struct linger, l_linger));
     146  	printf("}, [%d]) = %s\n", *len, errstr);
     147  
     148  	/* getsockopt optval EFAULT */
     149  	*len = sizeof(*linger);
     150  	get_linger(fd, &linger->l_linger, len);
     151  	printf("getsockopt(%d, SOL_SOCKET, SO_LINGER, %p, [%d]) = %s\n",
     152  	       fd, &linger->l_linger, *len, errstr);
     153  
     154  	/* getsockopt optlen EFAULT */
     155  	get_linger(fd, linger, len + 1);
     156  	printf("getsockopt(%d, SOL_SOCKET, SO_LINGER, %p, %p) = %s\n",
     157  	       fd, linger, len + 1, errstr);
     158  
     159  	puts("+++ exited with 0 +++");
     160  	return 0;
     161  }