summaryrefslogtreecommitdiff
path: root/src/bind.c
blob: 786624c79af97fa9b4ac9cd516c7d59b5f7d8d65 (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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
#include "osm/bind.h"

#include <errno.h>
#include <stdio.h>
#include <unistd.h>

#include <sys/socket.h>
#include <sys/un.h>


#define MAX_ID 0xFFFF

/**
 * The required characters to represent an id as a file name
 * id - the id to get translated to a file name
 */
int _need_chars(int id)
{
	int i = 1;

	while (id > 15)
	{
		id /= 16;
		i++;
	}

	return i;
}

/**
 * Write the integer file name after the folder path.
 * id - the id to get translated to a file name
 * start - a pointer to just after the end of the folder path string
 */
void _write_name(int id, char *start)
{
	int i = _need_chars(id);
	while (i > 0)
	{
		// Get current character
		char c = '0';
		if (id % 16 < 10)
			c += id % 16;
		else
			c = 'a' + (id % 16) - 10;
		
		// Put character
		*(start + i - 1) = c;

		// divide id, sub from i
		id /= 16;
		i -= 1;
	}
}

/**
 * Bind to the next available onboard socket in the given directory
 * sock_dir - The directory containing osm sockets (or null for the default)
 */
int osm_bind_local(int sockfd, const char *sock_dir)
{
	struct sockaddr_un name;
	name.sun_family = AF_LOCAL;
	
	strncpy(name.sun_path, sock_dir, sizeof(name.sun_path));
	name.sun_path[sizeof(name.sun_path) - 1] = 0;
	
	// Check for slash at end of path
	int len = strlen(name.sun_path);

	if (name.sun_path[len - 1] != '/')
	{
		name.sun_path[len] = '/';
		len++;
	}

	// check that we won't overflow the buffer
	if (len > sizeof(name.sun_path) - 2)
	{
		return -1;
	}

	// sequentially try to bind
	uint id = 0;
	uint offset = offsetof(struct sockaddr_un, sun_path);
	while(_need_chars(id) + len < sizeof(name.sun_path) - 1)
	{
		if (id > MAX_ID)
			return -1;

		// write file name
		_write_name(id, name.sun_path + len);
		
		// try to bind
		errno = 0;
		int err = bind(sockfd, (struct sockaddr *) &name, offset + strlen(name.sun_path));

		if (err == 0)
		{
			printf("Bound!\n");
			return 0;
		}
		else if (errno != EADDRINUSE)
		{
			// If not bound and it's not due to an address in use error
			// then we have an actual problem
			return -1;
		}

		// inc id
		id++;
	}

	return -1;
}

/**
 * Bind a new onboard socket
 * sock_dir - The directory containing osm sockets (or null for the default)
 * return - a negitve number on error, or the socket fd on success
 */
int osm_open_onboard(char *sock_dir)
{
	int sockfd = socket(AF_LOCAL, SOCK_SEQPACKET, 0);
	if (sockfd < 0)
	{
		perror("socket");
		return sockfd;
	}

	int bound = -1;
	if (sock_dir == NULL)
	{
		bound = osm_bind_local(sockfd, "/run/osm/onboard/");
	}
	else
	{
		bound = osm_bind_local(sockfd, sock_dir);
	}
	
	if (bound != 0)
	{
		perror("bind");
		close(sockfd);
		return bound;
	}

	return sockfd;
}

/**
 * Bind a new network socket
 * Should only be called by one process on the machine.
 *
 * If more than one device needs to be exposed through this system, use a
 * master process to handle internet traffic and export each device as a
 * sub-device.
 *
 * return - a negative number on error, or the 
 */
int osm_open_network()
{
	int sockfd = socket(AF_INET6, SOCK_STREAM, 0);
	return sockfd;
}