177c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes/*
277c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes * Check decoding of SO_LINGER socket option.
377c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes *
477c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes * Copyright (c) 2017 Dmitry V. Levin <ldv@altlinux.org>
577c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes * All rights reserved.
677c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes *
777c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes * Redistribution and use in source and binary forms, with or without
877c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes * modification, are permitted provided that the following conditions
977c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes * are met:
1077c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes * 1. Redistributions of source code must retain the above copyright
1177c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes *    notice, this list of conditions and the following disclaimer.
1277c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes * 2. Redistributions in binary form must reproduce the above copyright
1377c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes *    notice, this list of conditions and the following disclaimer in the
1477c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes *    documentation and/or other materials provided with the distribution.
1577c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes * 3. The name of the author may not be used to endorse or promote products
1677c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes *    derived from this software without specific prior written permission.
1777c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes *
1877c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1977c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2077c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2177c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2277c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2377c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2477c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2577c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2677c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2777c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2877c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes */
2977c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes
3077c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes#include "tests.h"
3177c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes
3277c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes#include <stdio.h>
3377c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes#include <sys/socket.h>
3477c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes#include <unistd.h>
3577c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes
3677c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughesstatic const char *errstr;
3777c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes
3877c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughesstatic int
3977c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughesget_linger(int fd, void *val, socklen_t *len)
4077c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes{
4177c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	int rc = getsockopt(fd, SOL_SOCKET, SO_LINGER, val, len);
4277c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	errstr = sprintrc(rc);
4377c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	return rc;
4477c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes}
4577c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes
4677c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughesstatic int
4777c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughesset_linger(int fd, void *val, socklen_t len)
4877c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes{
4977c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	int rc = setsockopt(fd, SOL_SOCKET, SO_LINGER, val, len);
5077c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	errstr = sprintrc(rc);
5177c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	return rc;
5277c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes}
5377c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes
5477c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughesint
5577c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughesmain(void)
5677c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes{
5777c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	TAIL_ALLOC_OBJECT_CONST_PTR(struct linger, linger);
5877c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	TAIL_ALLOC_OBJECT_CONST_PTR(socklen_t, len);
5977c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes        int fd = socket(AF_UNIX, SOCK_STREAM, 0);
6077c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes        if (fd < 0)
6177c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes                perror_msg_and_skip("socket AF_UNIX SOCK_STREAM");
6277c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes
6377c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	/* classic getsockopt */
6477c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	*len = sizeof(*linger);
6577c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	get_linger(fd, linger, len);
6677c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	printf("getsockopt(%d, SOL_SOCKET, SO_LINGER, {l_onoff=%d, l_linger=%d}"
6777c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	       ", [%d]) = %s\n",
6877c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	       fd, linger->l_onoff, linger->l_linger, *len, errstr);
6977c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes
7077c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	/* classic setsockopt */
7177c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	linger->l_onoff = -15;
7277c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	linger->l_linger = -42;
7377c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	set_linger(fd, linger, sizeof(*linger));
7477c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	printf("setsockopt(%d, SOL_SOCKET, SO_LINGER, {l_onoff=%d, l_linger=%d}"
7577c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	       ", %d) = %s\n",
7677c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	       fd, linger->l_onoff, linger->l_linger,
7777c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	       (unsigned int) sizeof(*linger), errstr);
7877c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes
7977c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	/* setsockopt with optlen larger than necessary */
8077c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	set_linger(fd, linger, sizeof(*linger) + 1);
8177c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	printf("setsockopt(%d, SOL_SOCKET, SO_LINGER, {l_onoff=%d, l_linger=%d}"
8277c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	       ", %d) = %s\n",
8377c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	       fd, linger->l_onoff, linger->l_linger,
8477c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	       (unsigned int) sizeof(*linger) + 1, errstr);
8577c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes
8677c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	/* setsockopt with optlen < 0 - EINVAL */
8777c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	set_linger(fd, linger, -1U);
8877c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	printf("setsockopt(%d, SOL_SOCKET, SO_LINGER, %p, -1) = %s\n",
8977c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	       fd, linger, errstr);
9077c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes
9177c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	/* setsockopt with optlen smaller than necessary - EINVAL */
9277c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	set_linger(fd, linger, sizeof(linger->l_onoff));
9377c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	printf("setsockopt(%d, SOL_SOCKET, SO_LINGER, %p, %d) = %s\n",
9477c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	       fd, linger, (unsigned int) sizeof(linger->l_onoff), errstr);
9577c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes
9677c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	/* setsockopt optval EFAULT */
9777c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	set_linger(fd, &linger->l_linger, sizeof(*linger));
9877c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	printf("setsockopt(%d, SOL_SOCKET, SO_LINGER, %p, %d) = %s\n",
9977c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	       fd, &linger->l_linger, (unsigned int) sizeof(*linger), errstr);
10077c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes
10177c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	/* getsockopt with optlen larger than necessary - shortened */
10277c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	*len = sizeof(*linger) + 1;
10377c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	get_linger(fd, linger, len);
10477c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	printf("getsockopt(%d, SOL_SOCKET, SO_LINGER, {l_onoff=%d, l_linger=%d}"
10577c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	       ", [%u->%d]) = %s\n",
10677c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	       fd, linger->l_onoff, linger->l_linger,
10777c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	       (unsigned int) sizeof(*linger) + 1, *len, errstr);
10877c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes
10977c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	/* getsockopt with optlen larger than usual - truncated to l_onoff */
11077c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	*len = sizeof(linger->l_onoff);
11177c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	get_linger(fd, linger, len);
11277c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	printf("getsockopt(%d, SOL_SOCKET, SO_LINGER, {l_onoff=%d}"
11377c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	       ", [%d]) = %s\n",
11477c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	       fd, linger->l_onoff, *len, errstr);
11577c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes
11677c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	/* getsockopt with optlen larger than usual - truncated to raw */
11777c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	*len = sizeof(*linger) - 1;
11877c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	get_linger(fd, linger, len);
11977c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	printf("getsockopt(%d, SOL_SOCKET, SO_LINGER, ", fd);
12077c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	print_quoted_hex(linger, *len);
12177c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	printf(", [%d]) = %s\n", *len, errstr);
12277c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes
12377c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	/* getsockopt optval EFAULT */
12477c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	*len = sizeof(*linger);
12577c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	get_linger(fd, &linger->l_linger, len);
12677c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	printf("getsockopt(%d, SOL_SOCKET, SO_LINGER, %p, [%d]) = %s\n",
12777c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	       fd, &linger->l_linger, *len, errstr);
12877c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes
12977c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	/* getsockopt optlen EFAULT */
13077c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	get_linger(fd, linger, len + 1);
13177c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	printf("getsockopt(%d, SOL_SOCKET, SO_LINGER, %p, %p) = %s\n",
13277c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	       fd, linger, len + 1, errstr);
13377c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes
13477c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	puts("+++ exited with 0 +++");
13577c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	return 0;
13677c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes}
137