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
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
|
#include "osm/bind.h"
#include "osm/utils.h"
#include <errno.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stddef.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <threads.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
unsigned int id = 0;
unsigned int 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 == -1)
{
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)
{
close(sockfd);
return -1;
}
listen(sockfd, 3);
return sockfd;
}
/**
* Listen for and return connections for a socket
* return - a vector containing all the threads which this function started
*/
Vector osm_listen_and_accept(int sockfd, thrd_start_t callback)
{
Vector out = vect_init(sizeof(thrd_t));
thrd_t thread;
while(1)
{
// Try to accept a connection
errno = 0;
int fd = accept(sockfd, NULL, NULL);
if (fd == -1)
{
if (errno != ECONNABORTED && errno != EINTR)
{
break;
}
else
continue;
}
// Create and store the connection thread
errno = 0;
int ret = thrd_create(&thread, callback, (void*)(uintptr_t)fd);
if(ret == thrd_success)
{
vect_push(&out, &thread);
}
else
{
if (ret == thrd_error)
{
perror("Error creating thread");
}
else if (ret == thrd_nomem)
{
fprintf(stderr, "Thread out of memory. Shutting down.\n");
}
break;
}
}
return out;
}
/**
* 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;
}
|