mirror of
https://github.com/Telecominfraproject/wlan-ucentral-client.git
synced 2026-01-27 10:23:38 +00:00
296 lines
6.2 KiB
C
296 lines
6.2 KiB
C
/* SPDX-License-Identifier: BSD-3-Clause */
|
|
|
|
#include <string.h>
|
|
#include <signal.h>
|
|
#include <getopt.h>
|
|
|
|
#include <libubox/uloop.h>
|
|
|
|
#include "ucentral.h"
|
|
|
|
static int reconnect_timeout;
|
|
static struct lws_context *context;
|
|
|
|
static struct uloop_timeout periodic;
|
|
static struct uloop_fd sock;
|
|
struct lws *websocket = NULL;
|
|
time_t conn_time;
|
|
struct runqueue runqueue;
|
|
|
|
struct per_vhost_data__minimal {
|
|
struct lws_context *context;
|
|
struct lws_vhost *vhost;
|
|
const struct lws_protocols *protocol;
|
|
|
|
lws_sorted_usec_list_t sul;
|
|
struct lws_client_connect_info i;
|
|
struct lws *client_wsi;
|
|
};
|
|
|
|
struct client_config client = {
|
|
.server = "localhost",
|
|
.port = 11783,
|
|
.path = "/",
|
|
.serial = "00:11:22:33:44:55",
|
|
.firmware = "v1.0",
|
|
.debug = 0,
|
|
};
|
|
|
|
static int
|
|
get_reconnect_timeout(void)
|
|
{
|
|
#define MAX_RECONNECT (60 * 15)
|
|
int ret = reconnect_timeout++;
|
|
|
|
ret *= 30;
|
|
if (ret >= MAX_RECONNECT)
|
|
ret = MAX_RECONNECT;
|
|
|
|
ULOG_INFO("next reconnect in %ds\n", ret);
|
|
|
|
return ret * LWS_US_PER_SEC;
|
|
}
|
|
|
|
static void
|
|
sul_connect_attempt(struct lws_sorted_usec_list *sul)
|
|
{
|
|
struct per_vhost_data__minimal *vhd;
|
|
|
|
vhd = lws_container_of(sul, struct per_vhost_data__minimal, sul);
|
|
|
|
vhd->i.context = vhd->context;
|
|
vhd->i.port = client.port;
|
|
vhd->i.address = client.server;
|
|
vhd->i.path = client.path;
|
|
vhd->i.host = vhd->i.address;
|
|
vhd->i.origin = vhd->i.address;
|
|
vhd->i.ssl_connection = LCCSCF_USE_SSL;
|
|
if (client.selfsigned)
|
|
vhd->i.ssl_connection |=
|
|
LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK |
|
|
LCCSCF_ALLOW_SELFSIGNED;
|
|
|
|
vhd->i.protocol = "ucentral-broker";
|
|
vhd->i.pwsi = &vhd->client_wsi;
|
|
|
|
if (!lws_client_connect_via_info(&vhd->i))
|
|
lws_sul_schedule(vhd->context, 0, &vhd->sul,
|
|
sul_connect_attempt, 10 * LWS_US_PER_SEC);
|
|
}
|
|
|
|
static unsigned int
|
|
uloop_event_to_pfd(unsigned int e)
|
|
{
|
|
int ret = 0;
|
|
|
|
if (e & ULOOP_READ)
|
|
ret |= POLLIN;
|
|
if (e & ULOOP_WRITE)
|
|
ret |= POLLOUT;
|
|
return ret;
|
|
}
|
|
|
|
static void
|
|
sock_cb(struct uloop_fd *fd, unsigned int revents)
|
|
{
|
|
struct pollfd pfd;
|
|
|
|
pfd.events = uloop_event_to_pfd(fd->flags);
|
|
pfd.revents = uloop_event_to_pfd(revents);
|
|
pfd.fd = fd->fd;
|
|
|
|
if (fd->eof)
|
|
pfd.revents |= POLLHUP;
|
|
if (fd->error)
|
|
pfd.revents |= LWS_POLLHUP;
|
|
lws_service_fd(context, &pfd);
|
|
|
|
for (int count = 30; count && !lws_service_adjust_timeout(context, 1, 0); --count)
|
|
lws_plat_service_tsi(context, -1, 0);
|
|
}
|
|
|
|
static int
|
|
callback_broker(struct lws *wsi, enum lws_callback_reasons reason,
|
|
void *user, void *in, size_t len)
|
|
{
|
|
struct per_vhost_data__minimal *vhd =
|
|
(struct per_vhost_data__minimal *)
|
|
lws_protocol_vh_priv_get(lws_get_vhost(wsi),
|
|
lws_get_protocol(wsi));
|
|
int r = 0;
|
|
|
|
struct lws_pollargs *in_pollargs = (struct lws_pollargs *)in;
|
|
|
|
switch (reason) {
|
|
case LWS_CALLBACK_PROTOCOL_INIT:
|
|
vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),
|
|
lws_get_protocol(wsi),
|
|
sizeof(struct per_vhost_data__minimal));
|
|
vhd->context = lws_get_context(wsi);
|
|
vhd->protocol = lws_get_protocol(wsi);
|
|
vhd->vhost = lws_get_vhost(wsi);
|
|
|
|
sul_connect_attempt(&vhd->sul);
|
|
break;
|
|
|
|
case LWS_CALLBACK_PROTOCOL_DESTROY:
|
|
lws_sul_cancel(&vhd->sul);
|
|
return r;
|
|
|
|
case LWS_CALLBACK_ADD_POLL_FD:
|
|
case LWS_CALLBACK_CHANGE_MODE_POLL_FD: {
|
|
int event = 0;
|
|
|
|
if (in_pollargs->events & POLLIN)
|
|
event |= ULOOP_READ;
|
|
if (in_pollargs->events & POLLOUT)
|
|
event |= ULOOP_WRITE;
|
|
sock.fd = in_pollargs->fd;
|
|
sock.cb = sock_cb;
|
|
uloop_fd_add(&sock, event);
|
|
return 0;
|
|
}
|
|
|
|
case LWS_CALLBACK_DEL_POLL_FD:
|
|
uloop_fd_delete(&sock);
|
|
return 0;
|
|
|
|
case LWS_CALLBACK_CLIENT_ESTABLISHED:
|
|
ULOG_INFO("connection established\n");
|
|
reconnect_timeout = 1;
|
|
conn_time = time(NULL);
|
|
websocket = wsi;
|
|
connect_send();
|
|
crashlog_init();
|
|
break;
|
|
|
|
case LWS_CALLBACK_CLIENT_RECEIVE:
|
|
proto_handle((char *) in);
|
|
break;
|
|
|
|
case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
|
|
ULOG_ERR("connection error: %s\n",
|
|
in ? (char *)in : "(null)");
|
|
case LWS_CALLBACK_CLIENT_CLOSED:
|
|
ULOG_INFO("connection closed\n");
|
|
websocket = NULL;
|
|
conn_time = time(NULL);
|
|
vhd->client_wsi = NULL;
|
|
lws_sul_schedule(vhd->context, 0, &vhd->sul,
|
|
sul_connect_attempt, get_reconnect_timeout());
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return lws_callback_http_dummy(wsi, reason, user, in, len);
|
|
}
|
|
|
|
static const struct
|
|
lws_protocols protocols[] = {
|
|
{ "ucentral-broker", callback_broker, 0, 32 * 1024, 0, NULL, 0},
|
|
{ }
|
|
};
|
|
|
|
static void
|
|
periodic_cb(struct uloop_timeout *t)
|
|
{
|
|
struct pollfd pfd = { .events = POLLIN | POLLOUT };
|
|
|
|
lws_service_fd(context, &pfd);
|
|
lws_service_tsi(context, -1, 0);
|
|
uloop_timeout_set(t, 100);
|
|
}
|
|
|
|
static int print_usage(const char *daemon)
|
|
{
|
|
fprintf(stderr, "Usage: %s [options]\n"
|
|
"\t-i <insecure/selfsigned>\n"
|
|
"\t-S <serial>\n"
|
|
"\t-s <server>\n"
|
|
"\t-P <port>\n"
|
|
"\t-d <debug>\n"
|
|
"\t-f <firmware>\n"
|
|
"\t-v <venue>\n", daemon);
|
|
return -1;
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
struct lws_context_creation_info info;
|
|
int logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE;
|
|
int ch;
|
|
|
|
while ((ch = getopt(argc, argv, "S:s:P:v:f:di")) != -1) {
|
|
switch (ch) {
|
|
case 's':
|
|
client.server = optarg;
|
|
break;
|
|
case 'f':
|
|
client.firmware = optarg;
|
|
break;
|
|
case 'P':
|
|
client.port = atoi(optarg);
|
|
break;
|
|
case 'd':
|
|
client.debug = 1;
|
|
break;
|
|
case 'v':
|
|
client.path = optarg;
|
|
break;
|
|
case 'S':
|
|
client.serial = optarg;
|
|
break;
|
|
case 'i':
|
|
client.selfsigned = 1;
|
|
break;
|
|
case 'h':
|
|
default:
|
|
return print_usage(*argv);
|
|
}
|
|
}
|
|
|
|
ulog_open(ULOG_STDIO | ULOG_SYSLOG, LOG_DAEMON, "ucentral");
|
|
if (!client.debug)
|
|
ulog_threshold(LOG_INFO);
|
|
|
|
runqueue_init(&runqueue);
|
|
runqueue.max_running_tasks = 1;
|
|
config_init(1, 0);
|
|
|
|
lws_set_log_level(logs, NULL);
|
|
|
|
memset(&info, 0, sizeof info);
|
|
info.port = CONTEXT_PORT_NO_LISTEN;
|
|
info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
|
|
info.ssl_cert_filepath = USYNC_CERT;
|
|
info.protocols = protocols;
|
|
info.fd_limit_per_thread = 1 + 1 + 1;
|
|
|
|
conn_time = time(NULL);
|
|
context = lws_create_context(&info);
|
|
if (!context) {
|
|
ULOG_INFO("failed to start LWS context\n");
|
|
return -1;
|
|
}
|
|
|
|
uloop_init();
|
|
ubus_init();
|
|
periodic.cb = periodic_cb;
|
|
uloop_timeout_set(&periodic, 100);
|
|
lws_service(context, 0);
|
|
|
|
uloop_run();
|
|
|
|
uloop_done();
|
|
proto_free();
|
|
runqueue_kill(&runqueue);
|
|
lws_context_destroy(context);
|
|
ubus_deinit();
|
|
config_deinit();
|
|
health_deinit();
|
|
|
|
return 0;
|
|
}
|