I'm using lws-minimal-ws-broker example to make a broker over websocket. I'm facing few issues I cannot find answers to:
Firstly, callback_minimal is never called with reason LWS_CALLBACK_PROTOCOL_INIT. Thos results protocol init related code is never executed.
Secondly, after lws_ring_consume_and_update_oldest_tail() is called the __minimal_destroy_message is newer called. So, after data gets published to subscribes the ring buffer indexes does not get updated, and the buffer decrements until reaches zero.
Maybe, someone could help me with these?
#include <libwebsockets.h>
#include <signal.h>
#include <string.h>
/* Protocol for subscribers */
#define LWS_PLUGIN_PROTOCOL_MINIMAL \
{ \
"broker", callback_minimal, sizeof(struct per_session_data__minimal), 128, \
0, NULL, 0 \
}
#define LWS_PLUGIN_STATIC
static struct lws_protocols protocols[] = {
LWS_PLUGIN_PROTOCOL_MINIMAL,
LWS_PROTOCOL_LIST_TERM};
static int interrupted;
struct msg {
void *payload; /* is malloc'd */
size_t len;
};
/* one of these is created for each client connecting to us */
struct per_session_data__minimal {
struct per_session_data__minimal *pss_list;
struct lws *wsi;
uint32_t tail;
char publishing; /* nonzero: peer is publishing to us */
};
/* one of these is created for each vhost our protocol is used with */
struct per_vhost_data__minimal {
struct lws_context *context;
struct lws_vhost *vhost;
const struct lws_protocols *protocol;
struct per_session_data__minimal *pss_list; /* linked-list of live pss*/
struct lws_ring *ring; /* ringbuffer holding unsent messages */
};
/* destroys the message when everyone has had a copy of it */
static void __minimal_destroy_message(void *_msg) {
struct msg *msg = _msg;
free(msg->payload);
msg->payload = NULL;
msg->len = 0;
}
static int callback_minimal(struct lws *wsi, enum lws_callback_reasons reason,
void *user, void *in, size_t len) {
struct per_session_data__minimal *pss =
(struct per_session_data__minimal *)user;
struct per_vhost_data__minimal *vhd =
(struct per_vhost_data__minimal *)lws_protocol_vh_priv_get(
lws_get_vhost(wsi), lws_get_protocol(wsi));
const struct msg *pmsg;
struct msg amsg;
char buf[32];
int n, m;
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);
vhd->ring =
lws_ring_create(sizeof(struct msg), 8, __minimal_destroy_message);
if (!vhd->ring) return 1;
break;
case LWS_CALLBACK_PROTOCOL_DESTROY:
lws_ring_destroy(vhd->ring);
break;
case LWS_CALLBACK_ESTABLISHED:
pss->tail = lws_ring_get_oldest_tail(vhd->ring);
pss->wsi = wsi;
if (lws_hdr_copy(wsi, buf, sizeof(buf), WSI_TOKEN_GET_URI) > 0)
pss->publishing = !strcmp(buf, "/publisher");
if (pss->publishing)
/* add subscribers to the list of live pss held in the vhd */
lws_ll_fwd_insert(pss, pss_list, vhd->pss_list);
break;
case LWS_CALLBACK_CLOSED:
lws_ll_fwd_remove(struct per_session_data__minimal, pss_list, pss,
vhd->pss_list);
break;
case LWS_CALLBACK_SERVER_WRITEABLE:
if (pss->publishing) break;
pmsg = lws_ring_get_element(vhd->ring, &pss->tail);
if (!pmsg) break;
/* notice we allowed for LWS_PRE in the payload already */
m = lws_write(wsi, ((unsigned char *)pmsg->payload) + LWS_PRE, pmsg->len,
LWS_WRITE_TEXT);
if (m < (int)pmsg->len) return -1;
lws_ring_consume_and_update_oldest_tail(
vhd->ring, /* lws_ring object */
struct per_session_data__minimal, /* type of objects with tails */
&pss->tail, /* tail of guy doing the consuming */
1, /* number of payload objects being consumed */
vhd->pss_list, /* head of list of objects with tails */
tail, /* member name of tail in objects with tails */
pss_list /* member name of next object in objects with tails */
);
lws_ring_consume(vhd->ring, &pss->tail, NULL, 1);
/* more to do? */
if (lws_ring_get_element(vhd->ring, &pss->tail))
lws_callback_on_writable(pss->wsi);
break;
case LWS_CALLBACK_RECEIVE:
if (!pss->publishing) break;
if (!vhd->pss_list) break;
n = (int)lws_ring_get_count_free_elements(vhd->ring);
if (!n) {
lwsl_user("dropping!\n");
break;
}
amsg.len = len;
/* notice we over-allocate by LWS_PRE */
amsg.payload = malloc(LWS_PRE + len);
if (!amsg.payload) {
lwsl_user("OOM: dropping\n");
break;
}
memcpy((char *)amsg.payload + LWS_PRE, in, len);
if (!lws_ring_insert(vhd->ring, &amsg, 1)) {
__minimal_destroy_message(&amsg);
lwsl_user("dropping 2!\n");
break;
}
lws_start_foreach_llp(struct per_session_data__minimal **, ppss,
vhd->pss_list) {
if (!(*ppss)->publishing) lws_callback_on_writable((*ppss)->wsi);
}
lws_end_foreach_llp(ppss, pss_list);
break;
default:
break;
}
return 0;
}
int ss_broker_start() {
struct lws_context_creation_info info;
struct lws_context *context;
const char *p;
int n = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE | LLL_DEBUG |
LLL_INFO | LLL_EXT | LLL_LATENCY
/* for LLL_ verbosity above NOTICE to be built into lws,
* lws must have been configured and built with
* -DCMAKE_BUILD_TYPE=DEBUG instead of =RELEASE */
/* | LLL_INFO */ /* | LLL_PARSER */ /* | LLL_HEADER */
/* | LLL_EXT */ /* | LLL_CLIENT */ /* | LLL_LATENCY */
/* | LLL_DEBUG */;
lws_set_log_level(logs, NULL);
memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
info.port = 8081;
info.protocols = protocols;
context = lws_create_context(&info);
if (!context) {
lwsl_err("lws init failed\n");
return 1;
}
while (n >= 0 && !interrupted) n = lws_service(context, 0);
lws_context_destroy(context);
return 0;
}