Packages
vintage_net
0.10.2
0.13.12
0.13.11
0.13.10
0.13.9
0.13.8
0.13.7
0.13.6
0.13.5
0.13.4
0.13.3
0.13.2
0.13.1
0.13.0
0.12.2
0.12.1
0.12.0
0.11.5
0.11.4
0.11.3
0.11.2
0.11.1
0.11.0
0.10.5
0.10.4
0.10.3
0.10.2
0.10.1
0.10.0
0.9.3
0.9.2
0.9.1
0.9.0
0.8.0
0.7.9
0.7.8
0.7.7
0.7.6
0.7.5
0.7.4
0.7.3
0.7.2
0.7.1
0.7.0
0.6.6
0.6.5
0.6.4
0.6.3
0.6.2
0.6.1
0.6.0
0.5.1
0.5.0
0.4.1
0.4.0
0.3.1
0.3.0
0.2.4
0.2.3
0.2.2
0.2.1
0.2.0
0.1.0
Network configuration and management for Nerves
Current section
Files
Jump to
Current section
Files
src/to_elixir.c
#include <ctype.h>
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <ei.h>
extern char **environ;
#define SOCKET_PATH "/tmp/vintage_net/comms"
static void encode_string(ei_x_buff *buff, const char *str)
{
// Encode strings as binaries so that we get Elixir strings
// NOTE: the strings that we encounter here are expected to be ASCII to
// my knowledge
ei_x_encode_binary(buff, str, strlen(str));
}
static void encode_kv_string(ei_x_buff *buff, const char *key, const char *str)
{
ei_x_encode_atom(buff, key);
encode_string(buff, str);
}
static int count_elements(const char *str)
{
if (*str == '\0')
return 0;
int n = 1;
const char *p = str;
while (*p != '\0') {
if (*p == ' ')
n++;
p++;
}
return n;
}
static void encode_kv_list(ei_x_buff *buff, const char *key, const char *str)
{
ei_x_encode_atom(buff, key);
int n = count_elements(str);
if (n > 0) {
ei_x_encode_list_header(buff, n);
const char *p = str;
while (n > 1) {
const char *end = strchr(p, ' ');
ei_x_encode_binary(buff, p, end - p);
p = end + 1;
n--;
}
ei_x_encode_binary(buff, p, strlen(p));
}
ei_x_encode_empty_list(buff);
}
/*
* Example udhcpc variables:
*
* subnet=255.255.255.0
* router=192.168.9.1
* opt58=0000a8c0
* opt59=00012750
* domain=example.net
* interface=eth0
* siaddr=192.168.9.1
* dns=192.168.9.1
* serverid=192.168.9.1
* broadcast=192.168.9.255
* ip=192.168.9.131
* mask=24
* lease=86400
* opt53=05
*
* See https://git.busybox.net/busybox/tree/networking/udhcp/common.c for more.
*/
static int should_encode(const char *kv)
{
// We want to encode all lower case environment variables. Those are the ones from udhcpc.
// Just check the first character.
return islower(kv[0]);
}
static int count_environ_to_encode()
{
char **p = environ;
int n = 0;
while (*p != NULL) {
if (should_encode(*p))
n++;
p++;
}
return n;
}
static void encode_env_kv(ei_x_buff *buff, const char *kv)
{
char key[32];
const char *equal = strchr(kv, '=');
if (equal == NULL)
return;
size_t keylen = equal - kv;
if (keylen >= sizeof(key))
keylen = sizeof(key) - 1;
memcpy(key, kv, keylen);
key[keylen] = '\0';
const char *value = equal + 1;
// Some parameters are lists, so encode those as lists so that Elixir
// doesn't have to figure it out.
if (strcmp(key, "dns") == 0 ||
strcmp(key, "router") == 0)
encode_kv_list(buff, key, value);
else
encode_kv_string(buff, key, value);
}
static void encode_environ(ei_x_buff *buff)
{
int kv_to_encode = count_environ_to_encode();
ei_x_encode_map_header(buff, kv_to_encode);
char **p = environ;
// We want to encode all lower case environment variables. Those are the ones from udhcpc.
while (*p != NULL) {
const char *kv = *p;
if (should_encode(kv))
encode_env_kv(buff, kv);
p++;
}
}
static void encode_args(ei_x_buff *buff, int argc, char *argv[])
{
ei_x_encode_list_header(buff, argc);
int i;
for (i = 0; i < argc; i++)
encode_string(buff, argv[i]);
ei_x_encode_empty_list(buff);
}
int main(int argc, char *argv[])
{
int fd = socket(AF_UNIX, SOCK_DGRAM, 0);
if (fd < 0)
err(EXIT_FAILURE, "socket");
struct sockaddr_un addr;
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, SOCKET_PATH, sizeof(addr.sun_path) - 1);
if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1)
err(EXIT_FAILURE, "connect");
ei_x_buff buff;
if (ei_x_new_with_version(&buff) < 0)
err(EXIT_FAILURE, "ei_x_new_with_version");
ei_x_encode_tuple_header(&buff, 2);
encode_args(&buff, argc, argv);
encode_environ(&buff);
ssize_t rc = write(fd, buff.buff, buff.index);
if (rc < 0)
err(EXIT_FAILURE, "write");
if (rc != buff.index)
errx(EXIT_FAILURE, "write wasn't able to send %d chars all at once!", buff.index);
close(fd);
return 0;
}