summaryrefslogtreecommitdiff
path: root/network.c
blob: 9b9557e25074e29c91d33fb874f637d8d3befda7 (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
#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;
}

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);
	int ret = fd;

	/* Did we fail to create the listen socket? */
	if (fd < 0) {
		log_reason(LOG_ERR, "Failed to create listen socket.", 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.", 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.", 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.", 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(LOG_ERR, "Failed to create socket for address \"%s\".", addr_to_str(sa, sock_len));
	} else {
		log(LOG_INFO, "Successfully created socket descriptor %i for address \"%s\".", fd, addr_to_str(sa, sock_len));
	}

	return ret;
}