Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add local unix socket support #86

Merged
merged 1 commit into from
Oct 2, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
130 changes: 92 additions & 38 deletions src/hyperion_client.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,14 @@
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
#include <unistd.h>

#include "hyperion_reply_reader.h"
#include "hyperion_request_builder.h"

static int _connect_unix_socket(const char* hostname);
static int _connect_inet_socket(const char* hostname, int port);
static int _send_message(const void* buffer, size_t size);
static bool _parse_reply(hyperionnet_Reply_table_t reply);

Expand All @@ -25,53 +28,20 @@ static const char* _origin = NULL;
static bool _connected = false;
unsigned char recvBuff[1024];

int hyperion_client(const char* origin, const char* hostname, int port, int priority)
int hyperion_client(const char* origin, const char* hostname, int port, bool unix_socket, int priority)
{
_origin = origin;
_priority = priority;
_connected = false;
_registered = false;
sockfd = 0;
struct sockaddr_in serv_addr;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add checking for /tmp/hyperhdr-domain here. Iterate over constant array of possible filelocations, in case Hyperion.NG implements local unix socket support too.

If such unix socket handle is found, use it as parameter to _connect_unix_socket.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this mean we should remove the command line option?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, the cmdline is fine and useful in this case. Just when it knows that a "local unix domain socket" is desired, it should check and use such, if available.

Case 1: No unix domain socket desired

  • Supplied IP and Port is used as-is

Case 2: Unix domain socket is desired

  • Hardcode ddress to 127.0.0.1 for HTTP RPC JSON communication to the daemon
  • Before connecting the socket for flatbuffer data, check if known unix domain sockets exist and use them - otherwise fall back to 127.0.0.1.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not convinced this is the best option. This tightly couples hyperion-webos to a list of unix sockets which are provided by external software and might change in future. As you pointed out if hyperion.ng were to add a local socket this means that hyperion-webos needs changes as well.

if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
WARN("Could not create socket: %s", strerror(errno));
return 1;
}
struct timeval timeout;
timeout.tv_sec = 1;
timeout.tv_usec = 0;

if (setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, (char*)&timeout,
sizeof(timeout))
< 0) {
WARN("setsockopt(SO_SNDTIMEO) failed: %s", strerror(errno));
return 1;
}

if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout,
sizeof(timeout))
< 0) {
WARN("setsockopt(SO_RCVTIMEO) failed: %s", strerror(errno));
return 1;
}

memset(&serv_addr, '0', sizeof(serv_addr));

serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(port);

if (inet_pton(AF_INET, hostname, &serv_addr.sin_addr) <= 0) {
WARN("inet_pton error occured (hostname: %s): %s", hostname, strerror(errno));
return 1;
}

if (connect(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
WARN("connect() to %s:%d failed: %s", hostname, port, strerror(errno));
return 1;
if (unix_socket) {
return _connect_unix_socket(hostname);
} else {
return _connect_inet_socket(hostname, port);
}
_connected = true;

return 0;
}

int hyperion_read()
Expand Down Expand Up @@ -197,3 +167,87 @@ bool _parse_reply(hyperionnet_Reply_table_t reply)

return false;
}

int _connect_inet_socket(const char* hostname, int port)
{
struct sockaddr_in serv_addr_in;

if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
WARN("Could not create socket: %s", strerror(errno));
return 1;
}
struct timeval timeout;
timeout.tv_sec = 1;
timeout.tv_usec = 0;

if (setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, (char*)&timeout,
sizeof(timeout))
< 0) {
WARN("setsockopt(SO_SNDTIMEO) failed: %s", strerror(errno));
return 1;
}

if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout,
sizeof(timeout))
< 0) {
WARN("setsockopt(SO_RCVTIMEO) failed: %s", strerror(errno));
return 1;
}

memset(&serv_addr_in, 0, sizeof(serv_addr_in));

serv_addr_in.sin_family = AF_INET;
serv_addr_in.sin_port = htons(port);

if (inet_pton(AF_INET, hostname, &serv_addr_in.sin_addr) <= 0) {
WARN("inet_pton error occured (hostname: %s): %s", hostname, strerror(errno));
return 1;
}

if (connect(sockfd, (struct sockaddr*)&serv_addr_in, sizeof(serv_addr_in)) < 0) {
WARN("connect() to %s:%d failed: %s", hostname, port, strerror(errno));
return 1;
}
_connected = true;

return 0;
}

int _connect_unix_socket(const char* hostname)
{
struct sockaddr_un serv_addr_un;

if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
WARN("Could not create socket: %s", strerror(errno));
return 1;
}
struct timeval timeout;
timeout.tv_sec = 1;
timeout.tv_usec = 0;

if (setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, (char*)&timeout,
sizeof(timeout))
< 0) {
WARN("setsockopt(SO_SNDTIMEO) failed: %s", strerror(errno));
return 1;
}

if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout,
sizeof(timeout)) < 0) {
WARN("setsockopt(SO_RCVTIMEO) failed: %s", strerror(errno));
return 1;
}

memset(&serv_addr_un, 0, sizeof(serv_addr_un));

serv_addr_un.sun_family = AF_LOCAL;
strcpy(serv_addr_un.sun_path, hostname);

if (connect(sockfd, (struct sockaddr*)&serv_addr_un, sizeof(serv_addr_un)) < 0) {
WARN("connect() to unix socket %s failed: %s", hostname, strerror(errno));
return 1;
}
_connected = true;

return 0;
}
3 changes: 2 additions & 1 deletion src/hyperion_client.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once
#include <stdbool.h>

int hyperion_client(const char* origin, const char* hostname, int port, int priority);
int hyperion_client(const char* origin, const char* hostname, int port, bool unix_socket, int priority);
int hyperion_read();
int hyperion_destroy();
int hyperion_set_image(const unsigned char* image, int width, int height);
Expand Down
7 changes: 6 additions & 1 deletion src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ static struct option long_options[] = {
{ "height", required_argument, 0, 'y' },
{ "address", required_argument, 0, 'a' },
{ "port", required_argument, 0, 'p' },
{ "unix-socket", no_argument, 0, 'l' },
{ "fps", required_argument, 0, 'f' },
{ "no-video", no_argument, 0, 'V' },
{ "no-gui", no_argument, 0, 'G' },
Expand All @@ -50,6 +51,7 @@ static void print_usage()
printf(" -y, --height=HEIGHT Height of video frame (default 108)\n");
printf(" -a, --address=ADDR IP address of Hyperion server\n");
printf(" -p, --port=PORT Port of Hyperion flatbuffers server (default 19400)\n");
printf(" -l, --unix-socket Connect through unix socket\n");
printf(" -f, --fps=FPS Framerate for sending video frames (default 0 = unlimited)\n");
printf(" -b, --backend=BE Use specific video capture backend (default auto)\n");
printf(" -u, --ui-backend=BE Use specific ui capture backend (default auto)\n");
Expand All @@ -70,7 +72,7 @@ static int parse_options(int argc, char* argv[])
int opt, longindex;
int ret;

while ((opt = getopt_long(argc, argv, "x:y:a:p:f:b:u:q:c:vnhdVG", long_options, &longindex)) != -1) {
while ((opt = getopt_long(argc, argv, "x:y:a:p:f:b:u:q:c:lvnhdVG", long_options, &longindex)) != -1) {
switch (opt) {
case 'x':
settings.width = atoi(optarg);
Expand All @@ -85,6 +87,9 @@ static int parse_options(int argc, char* argv[])
case 'p':
settings.port = atol(optarg);
break;
case 'l':
settings.unix_socket = true;
break;
case 'f':
settings.fps = atoi(optarg);
break;
Expand Down
7 changes: 4 additions & 3 deletions src/service.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ void* connection_loop(void* data)
DBG("Starting connection loop");
while (service->connection_loop_running) {
INFO("Connecting hyperion-client..");
if ((hyperion_client("webos", service->settings->address, service->settings->port, service->settings->priority)) != 0) {
if ((hyperion_client("webos", service->settings->address, service->settings->port,
service->settings->unix_socket, service->settings->priority)) != 0) {
ERR("Error! hyperion_client.");
} else {
INFO("hyperion-client connected!");
Expand Down Expand Up @@ -407,7 +408,7 @@ static bool videooutput_callback(LSHandle* sh __attribute__((unused)), LSMessage
hdr_enabled = true;
}

int ret = set_hdr_state(service->settings->address, RPC_PORT, hdr_enabled);
int ret = set_hdr_state(service->settings->unix_socket ? "127.0.0.1" : service->settings->address, RPC_PORT, hdr_enabled);
if (ret != 0) {
ERR("videooutput_callback: set_hdr_state failed, ret: %d", ret);
}
Expand Down Expand Up @@ -459,7 +460,7 @@ static bool picture_callback(LSHandle* sh __attribute__((unused)), LSMessage* ms
hdr_enabled = true;
}

int ret = set_hdr_state(service->settings->address, RPC_PORT, hdr_enabled);
int ret = set_hdr_state(service->settings->unix_socket ? "127.0.0.1" : service->settings->address, RPC_PORT, hdr_enabled);
if (ret != 0) {
ERR("videooutput_callback: set_hdr_state failed, ret: %d", ret);
}
Expand Down
4 changes: 4 additions & 0 deletions src/settings.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ void settings_init(settings_t* settings)
settings->address = strdup("");
settings->port = 19400;
settings->priority = 150;
settings->unix_socket = false;

settings->fps = 30;
settings->width = 320;
Expand Down Expand Up @@ -51,6 +52,8 @@ int settings_load_json(settings_t* settings, jvalue_ref source)
jnumber_get_i32(value, &settings->port);
if ((value = jobject_get(source, j_cstr_to_buffer("priority"))) && jis_number(value))
jnumber_get_i32(value, &settings->priority);
if ((value = jobject_get(source, j_cstr_to_buffer("unix-socket"))) && jis_boolean(value))
jboolean_get(value, &settings->unix_socket);

if ((value = jobject_get(source, j_cstr_to_buffer("fps"))) && jis_number(value))
jnumber_get_i32(value, &settings->fps);
Expand Down Expand Up @@ -81,6 +84,7 @@ int settings_save_json(settings_t* settings, jvalue_ref target)
jobject_set(target, j_cstr_to_buffer("address"), jstring_create(settings->address));
jobject_set(target, j_cstr_to_buffer("port"), jnumber_create_i32(settings->port));
jobject_set(target, j_cstr_to_buffer("priority"), jnumber_create_i32(settings->priority));
jobject_set(target, j_cstr_to_buffer("unix-socket"), jboolean_create(settings->unix_socket));

jobject_set(target, j_cstr_to_buffer("fps"), jnumber_create_i32(settings->fps));
jobject_set(target, j_cstr_to_buffer("width"), jnumber_create_i32(settings->width));
Expand Down
1 change: 1 addition & 0 deletions src/settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ typedef struct _settings_t {
char* address;
int port;
int priority;
bool unix_socket;

int fps;
int width;
Expand Down