Skip to content

Commit

Permalink
hosted: support network connections on unix
Browse files Browse the repository at this point in the history
If a device is specified as 'hostname:service', try connecting to it via
TCP if we fail to connect to a real device.

This enables using BMDA over a network connection.

Signed-off-by: Sean Cross <[email protected]>
  • Loading branch information
xobs committed Sep 27, 2024
1 parent cb089bf commit 5db787b
Showing 1 changed file with 76 additions and 0 deletions.
76 changes: 76 additions & 0 deletions src/platforms/hosted/serial_unix.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@
#include <unistd.h>
#endif

#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>

#include "general.h"
#include "remote.h"
#include "bmp_hosted.h"
Expand All @@ -43,6 +47,72 @@ static uint8_t read_buffer[READ_BUFFER_LENGTH];
static size_t read_buffer_fullness = 0U;
static size_t read_buffer_offset = 0U;

/* Socket code taken from https://beej.us/guide/bgnet/ */
static bool try_opening_network_device(const char *const name)
{
// Maximum legal length of a hostname
char hostname[256];

// The service name or port number
char *service_name;

struct addrinfo addr_hints = {
.ai_family = AF_UNSPEC,
.ai_socktype = SOCK_STREAM,
.ai_protocol = IPPROTO_TCP,
.ai_flags = AI_ADDRCONFIG | AI_V4MAPPED,
};
struct addrinfo *server_info;

if (!name) {
return false;
}

// Copy the hostname to an internal array. We need to modify it
// to separate the hostname from the service name.
strncpy(hostname, name, sizeof(hostname) - 1U);

service_name = strstr(hostname, ":");
if (service_name == NULL) {
return false;
}

// Separate the service name / port number from the hostname
*service_name = '\0';
service_name += 1;

if (*service_name == '\0') {
return false;
}

if (getaddrinfo(hostname, service_name, &addr_hints, &server_info) != 0) {
return false;
}

// Loop through all the results and connect to the first we can.
struct addrinfo *p;
for (p = server_info; p != NULL; p = p->ai_next) {
if ((fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) {
continue;
}

if (connect(fd, p->ai_addr, p->ai_addrlen) == -1) {
close(fd);
continue;
}

// If we get here, we must have connected successfully
break;
}
freeaddrinfo(server_info);

if (p == NULL) {
return false;
}

return true;
}

/* A nice routine grabbed from
* https://stackoverflow.com/questions/6947413/how-to-open-read-and-write-from-serial-port-in-c
*/
Expand Down Expand Up @@ -97,6 +167,9 @@ bool serial_open(const bmda_cli_options_s *cl_opts, const char *serial)
}
fd = open(name, O_RDWR | O_SYNC | O_NOCTTY);
if (fd < 0) {
if (try_opening_network_device(name)) {
return true;
}
DEBUG_ERROR("Couldn't open serial port %s\n", name);
return false;
}
Expand Down Expand Up @@ -202,6 +275,9 @@ bool serial_open(const bmda_cli_options_s *const cl_opts, const char *const seri
read_buffer_offset = 0U;
fd = open(name, O_RDWR | O_SYNC | O_NOCTTY);
if (fd < 0) {
if (try_opening_network_device(name)) {
return true;
}
DEBUG_ERROR("Couldn't open serial port %s\n", name);
return false;
}
Expand Down

0 comments on commit 5db787b

Please sign in to comment.