/*
 * Test if bind() works through a dangling symlink with SO_REUSEADDR set.
 */

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
#include <unistd.h>

#define SOCKET_PATH "/tmp/original_socket"
#define SYMLINK_PATH "/tmp/symlink_socket"

int main()
{
	int sockfd;
	struct sockaddr_un addr;
	int optval = 1;

	// Remove any existing file at SOCKET_PATH and SYMLINK_PATH
	unlink(SOCKET_PATH);
	unlink(SYMLINK_PATH);

	// Create a dangling symbolic link
	if (symlink(SOCKET_PATH, SYMLINK_PATH) == -1) {
		perror("symlink");
		exit(EXIT_FAILURE);
	}

	// Create a Unix domain socket
	if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
		perror("socket");
		exit(EXIT_FAILURE);
	}

	// Set the SO_REUSEADDR option
	if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optval,
	               sizeof(optval)) == -1) {
		perror("setsockopt");
		close(sockfd);
		exit(EXIT_FAILURE);
	}

	// Set up the address structure
	memset(&addr, 0, sizeof(struct sockaddr_un));
	addr.sun_family = AF_UNIX;
	strncpy(addr.sun_path, SYMLINK_PATH, sizeof(addr.sun_path) - 1);

	// Attempt to bind the socket to the symlink path
	if (bind(sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) == -1) {
		perror("bind");
		close(sockfd);
		exit(EXIT_FAILURE);
	}

	printf("Socket bound to %s\n", SYMLINK_PATH);

	// Clean up
	close(sockfd);
	unlink(SOCKET_PATH);
	unlink(SYMLINK_PATH);

	return 0;
}
