From 05d74e45dc181e40d84af5a0e5c1fd31ed201949 Mon Sep 17 00:00:00 2001 From: Andy Green Date: Sat, 8 Jul 2017 15:58:40 +0800 Subject: [PATCH] mirror: multiple mirror contexts by mirror= url arg By default mirror acts the same as before. However if you access the test server with a url containing "?mirror=", the session will bind to a mirror instance private to "?mirror=". Only sessions that used the same 'mirror=' name can share the drawings, mirror instances with a different name (including the default "" name) are unaffected. --- plugins/protocol_lws_mirror.c | 173 +++++++++++++++++++++++++++++++++++------- test-server/test.html | 28 +++++-- 2 files changed, 168 insertions(+), 33 deletions(-) diff --git a/plugins/protocol_lws_mirror.c b/plugins/protocol_lws_mirror.c index 2806820..33af7ce 100644 --- a/plugins/protocol_lws_mirror.c +++ b/plugins/protocol_lws_mirror.c @@ -34,8 +34,15 @@ #else #define MAX_MESSAGE_QUEUE 512 #endif + +#define MAX_MIRROR_INSTANCES 10 + +struct lws_mirror_instance; + struct per_session_data__lws_mirror { struct lws *wsi; + struct lws_mirror_instance *mi; + struct per_session_data__lws_mirror *same_mi_pss_list; int ringbuffer_tail; }; @@ -44,29 +51,139 @@ struct a_message { size_t len; }; -struct per_vhost_data__lws_mirror { +struct lws_mirror_instance { + struct lws_mirror_instance *next; + struct per_session_data__lws_mirror *same_mi_pss_list; + char name[30]; struct a_message ringbuffer[MAX_MESSAGE_QUEUE]; int ringbuffer_head; }; +struct per_vhost_data__lws_mirror { + struct lws_mirror_instance *mi_list; +}; + static int callback_lws_mirror(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) { struct per_session_data__lws_mirror *pss = - (struct per_session_data__lws_mirror *)user; + (struct per_session_data__lws_mirror *)user, **ppss, + *pss1; struct per_vhost_data__lws_mirror *v = (struct per_vhost_data__lws_mirror *) lws_protocol_vh_priv_get(lws_get_vhost(wsi), lws_get_protocol(wsi)); - int n, m; + struct lws_mirror_instance *mi, **pmi; + char name[30]; + int n, m, count_mi = 0; switch (reason) { case LWS_CALLBACK_ESTABLISHED: lwsl_info("%s: LWS_CALLBACK_ESTABLISHED\n", __func__); - pss->ringbuffer_tail = v->ringbuffer_head; + + /* + * mirror instance name... defaults to "", but if URL includes + * "?mirror=xxx", will be "xxx" + */ + + name[0] = '\0'; + lws_get_urlarg_by_name(wsi, "mirror", name, sizeof(name) - 1); + + lwsl_notice("mirror %s\n", name); + + /* is there already a mirror instance of this name? */ + + mi = v->mi_list; + while (mi) { + if (!strcmp(name, mi->name)) { + lwsl_notice("Joining existing mi %p '%s'\n", + mi, name); + /* yes... we will join it */ + break; + } + count_mi++; + mi = mi->next; + } + + if (!mi) { + + /* no existing mirror instance for name */ + + if (count_mi == MAX_MIRROR_INSTANCES) + return -1; + + /* create one with this name, and join it */ + + mi = malloc(sizeof(*mi)); + memset(mi, 0, sizeof(*mi)); + mi->next = v->mi_list; + v->mi_list = mi; + strcpy(mi->name, name); + mi->ringbuffer_head = 0; + + + lwsl_notice("Created new mi %p '%s'\n", mi, name); + } + + /* add our pss to list of guys bound to this mi */ + + pss->same_mi_pss_list = mi->same_mi_pss_list; + mi->same_mi_pss_list = pss; + + /* init the pss */ + + pss->mi = mi; + pss->ringbuffer_tail = mi->ringbuffer_head; pss->wsi = wsi; + + break; + + case LWS_CALLBACK_CLOSED: + + /* detach our pss from the mirror instance */ + + mi = pss->mi; + if (!mi) + break; + ppss = &mi->same_mi_pss_list; + + while (*ppss) { + if (*ppss == pss) { + *ppss = pss->same_mi_pss_list; + break; + } + + ppss = &(*ppss)->same_mi_pss_list; + } + + if (!mi->same_mi_pss_list) { + + /* last pss unbound from mi... delete mi */ + + pmi = &v->mi_list; + while (*pmi) { + if (*pmi == mi) { + *pmi = (*pmi)->next; + + if (!pss->mi) + break; + lwsl_info("%s: mirror protocol cleaning up %p\n", __func__, v); + for (n = 0; n < ARRAY_SIZE(pss->mi->ringbuffer); n++) + if (pss->mi->ringbuffer[n].payload) { + free(pss->mi->ringbuffer[n].payload); + pss->mi->ringbuffer[n].payload = NULL; + } + + free(mi); + break; + } + count_mi++; + pmi = &(*pmi)->next; + } + } + break; case LWS_CALLBACK_PROTOCOL_INIT: /* per vhost */ @@ -76,21 +193,13 @@ callback_lws_mirror(struct lws *wsi, enum lws_callback_reasons reason, break; case LWS_CALLBACK_PROTOCOL_DESTROY: /* per vhost */ - if (!v) - break; - lwsl_info("%s: mirror protocol cleaning up %p\n", __func__, v); - for (n = 0; n < ARRAY_SIZE(v->ringbuffer); n++) - if (v->ringbuffer[n].payload) { - free(v->ringbuffer[n].payload); - v->ringbuffer[n].payload = NULL; - } break; case LWS_CALLBACK_SERVER_WRITEABLE: - while (pss->ringbuffer_tail != v->ringbuffer_head) { - m = v->ringbuffer[pss->ringbuffer_tail].len; + while (pss->ringbuffer_tail != pss->mi->ringbuffer_head) { + m = pss->mi->ringbuffer[pss->ringbuffer_tail].len; n = lws_write(wsi, (unsigned char *) - v->ringbuffer[pss->ringbuffer_tail].payload + + pss->mi->ringbuffer[pss->ringbuffer_tail].payload + LWS_PRE, m, LWS_WRITE_TEXT); if (n < 0) { lwsl_err("ERROR %d writing to mirror socket\n", n); @@ -104,7 +213,7 @@ callback_lws_mirror(struct lws *wsi, enum lws_callback_reasons reason, else pss->ringbuffer_tail++; - if (((v->ringbuffer_head - pss->ringbuffer_tail) & + if (((pss->mi->ringbuffer_head - pss->ringbuffer_tail) & (MAX_MESSAGE_QUEUE - 1)) == (MAX_MESSAGE_QUEUE - 15)) lws_rx_flow_allow_all_protocol(lws_get_context(wsi), lws_get_protocol(wsi)); @@ -117,25 +226,25 @@ callback_lws_mirror(struct lws *wsi, enum lws_callback_reasons reason, break; case LWS_CALLBACK_RECEIVE: - if (((v->ringbuffer_head - pss->ringbuffer_tail) & + if (((pss->mi->ringbuffer_head - pss->ringbuffer_tail) & (MAX_MESSAGE_QUEUE - 1)) == (MAX_MESSAGE_QUEUE - 1)) { lwsl_err("dropping!\n"); goto choke; } - if (v->ringbuffer[v->ringbuffer_head].payload) - free(v->ringbuffer[v->ringbuffer_head].payload); + if (pss->mi->ringbuffer[pss->mi->ringbuffer_head].payload) + free(pss->mi->ringbuffer[pss->mi->ringbuffer_head].payload); - v->ringbuffer[v->ringbuffer_head].payload = malloc(LWS_PRE + len); - v->ringbuffer[v->ringbuffer_head].len = len; - memcpy((char *)v->ringbuffer[v->ringbuffer_head].payload + + pss->mi->ringbuffer[pss->mi->ringbuffer_head].payload = malloc(LWS_PRE + len); + pss->mi->ringbuffer[pss->mi->ringbuffer_head].len = len; + memcpy((char *)pss->mi->ringbuffer[pss->mi->ringbuffer_head].payload + LWS_PRE, in, len); - if (v->ringbuffer_head == (MAX_MESSAGE_QUEUE - 1)) - v->ringbuffer_head = 0; + if (pss->mi->ringbuffer_head == (MAX_MESSAGE_QUEUE - 1)) + pss->mi->ringbuffer_head = 0; else - v->ringbuffer_head++; + pss->mi->ringbuffer_head++; - if (((v->ringbuffer_head - pss->ringbuffer_tail) & + if (((pss->mi->ringbuffer_head - pss->ringbuffer_tail) & (MAX_MESSAGE_QUEUE - 1)) != (MAX_MESSAGE_QUEUE - 2)) goto done; @@ -144,8 +253,16 @@ choke: lws_rx_flow_control(wsi, 0); done: - lws_callback_on_writable_all_protocol(lws_get_context(wsi), - lws_get_protocol(wsi)); + /* + * ask for WRITABLE callback for every wsi bound to this + * mirror instance + */ + + pss1 = pss->mi->same_mi_pss_list; + while (pss1) { + lws_callback_on_writable(pss1->wsi); + pss1 = pss1->same_mi_pss_list; + } break; default: diff --git a/test-server/test.html b/test-server/test.html index b014d6a..e75483e 100644 --- a/test-server/test.html +++ b/test-server/test.html @@ -490,7 +490,7 @@ document.getElementById("brow").textContent = " " + BrowserDetect.browser + " " var pos = 0; -function get_appropriate_ws_url() +function get_appropriate_ws_url(extra_url) { var pcol; var u = document.URL; @@ -513,11 +513,29 @@ function get_appropriate_ws_url() /* + "/xxx" bit is for IE10 workaround */ - return pcol + u[0] + "/xxx"; + return pcol + u[0] + "/" + extra_url; } +var params = {}; -document.getElementById("number").textContent = get_appropriate_ws_url(); +if (location.search) { + var parts = location.search.substring(1).split('&'); + + for (var i = 0; i < parts.length; i++) { + var nv = parts[i].split('='); + if (!nv[0]) continue; + params[nv[0]] = nv[1] || true; + } +} + +var mirror_name = ""; +if (params.mirror) + mirror_name = params.mirror; + + console.log(mirror_name); + + +document.getElementById("number").textContent = get_appropriate_ws_url(mirror_name); /* dumb increment protocol */ @@ -674,10 +692,10 @@ function ot_req_close() { var color = "#000000"; if (typeof MozWebSocket != "undefined") { - socket_lm = new MozWebSocket(get_appropriate_ws_url(), + socket_lm = new MozWebSocket(get_appropriate_ws_url("?mirror=" + mirror_name), "lws-mirror-protocol"); } else { - socket_lm = new WebSocket(get_appropriate_ws_url(), + socket_lm = new WebSocket(get_appropriate_ws_url("?mirror=" + mirror_name), "lws-mirror-protocol"); } -- 2.7.4