summaryrefslogtreecommitdiff
path: root/src/bind.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/bind.c')
-rw-r--r--src/bind.c138
1 files changed, 138 insertions, 0 deletions
diff --git a/src/bind.c b/src/bind.c
new file mode 100644
index 0000000..2545003
--- /dev/null
+++ b/src/bind.c
@@ -0,0 +1,138 @@
+#include "osm/bind.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <sys/socket.h>
+#include <sys/un.h>
+
+/**
+ * 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
+ int id = 0;
+ while(_need_chars(id) + len < sizeof(name.sun_path) - 1)
+ {
+ // write file name
+ _write_name(id, name.sun_path + len);
+
+ // try to bind
+ int size = offsetof(struct sockaddr_un, sun_path) + strlen(name.sun_path);
+
+ if (bind(sockfd, (struct sockaddr *) &name, size) > 0)
+ {
+ return 0;
+ }
+
+ // 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_DGRAM, 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;
+}
+
+
+
+