summaryrefslogtreecommitdiff
path: root/network.c
blob: c5ae7778b8f0806a65d6b51b1949a13be692991a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include "macros.h"
#include "network.h"

const char *addr_to_str(struct sockaddr *sa, socklen_t len) {
	const int family = sa->sa_family;
	static char ip[INET6_ADDRSTRLEN];
	char *str = ip;

	switch (family) {
		case AF_INET6	: inet_ntop(family, &((struct sockaddr_in6 *)sa)->sin6_addr, ip, len); break;
		case AF_INET	: inet_ntop(family, &((struct sockaddr_in *)sa)->sin_addr, ip, len); break;
		case AF_UNIX	: str = ((struct sockaddr_un *)sa)->sun_path; break;
	}
	return str;
}

struct sockaddr *get_sock_addr(int socket) {
	struct sockaddr *sa;
	socklen_t sock_len = sizeof(struct sockaddr);
	getsockname(socket, NULL, &sock_len);
	sa = calloc(1, sock_len);
	getsockname(socket, sa, &sock_len);
	return sa;
}

int create_socket(struct sockaddr *sa, size_t sock_len) {
	const int one = 1;
	/* Create a new listen socket. */
	const int fd = socket(sa->sa_family, SOCK_SEQPACKET, IPPROTO_SCTP);
	const char *addr_str = addr_to_str(sa, sock_len);
	int ret = fd;

	/* Did we fail to create the listen socket? */
	if (fd < 0) {
		log_reason(LOG_ERR, "Failed to create listen socket for addresss \"%s\".", addr_str, strerror(errno));
		return -1;
	}

	/* Do we have an IPv6 socket? */
	if (sa->sa_family == AF_INET6) {
		int set = 1;
		setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &set, sizeof(set));
	}

	/* Did we fail to enable SO_REUSEADDR? */
	if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0) {
		log_reason(LOG_ERR, "Failed to enable SO_REUSEADDR for socket %i.", fd, strerror(errno));
		ret = -1;
	}


	/* Did we fail to bind the listen socket? */
	if (ret >= 0 && bind(fd, sa, sock_len) < 0) {
		log_reason(LOG_ERR, "Failed to bind listen socket %i with address \"%s\".", fd, addr_str, strerror(errno));
		ret = -1;
	}

	/* Did we fail to listen to the socket? */
	if (ret >= 0 && listen(fd, 20) < 0) {
		log_reason(LOG_ERR, "Failed to listen to socket %i.", fd, strerror(errno));
		ret = -1;
	}

	/* Did we get an error? */
	if (ret < 0) {
		/* Close the socket. */
		close(fd);
		/* Is this a unix domain socket? */
		if (sa->sa_family == AF_UNIX) {
			struct sockaddr_un *sa_un = (struct sockaddr_un *)sa;
			/* Unlink the path. */
			unlink(sa_un->sun_path);
		}
		log_reason(LOG_ERR, "Failed to create socket for address \"%s\".", addr_str, strerror(errno));
	} else {
		log(LOG_INFO, "Successfully created socket descriptor %i for address \"%s\".", fd, addr_str);
	}

	return ret;
}