aboutsummaryrefslogtreecommitdiff
path: root/aepd/websocket-protocol.c
diff options
context:
space:
mode:
authorAndy Green <andy.green@linaro.org>2012-10-06 20:04:42 +0800
committerAndy Green <andy.green@linaro.org>2012-10-15 07:37:49 +0800
commit68d6c70d6b330941a5f22a35269d63d9d920064a (patch)
treeae26a7615239a3a67b30bb7d80e99dbee8e33a92 /aepd/websocket-protocol.c
parente1d63c1dfceef029bff15eda57fce6255bd159eb (diff)
introduce aepd
Signed-off-by: Andy Green <andy.green@linaro.org>
Diffstat (limited to 'aepd/websocket-protocol.c')
-rw-r--r--aepd/websocket-protocol.c218
1 files changed, 218 insertions, 0 deletions
diff --git a/aepd/websocket-protocol.c b/aepd/websocket-protocol.c
new file mode 100644
index 0000000..cd81512
--- /dev/null
+++ b/aepd/websocket-protocol.c
@@ -0,0 +1,218 @@
+/*
+ * Author: Andy Green <andy.green@linaro.org>
+ * Copyright (C) 2012 Linaro, LTD
+ * Libwebsocket demo code (C) 2010-2012 Andy Green <andy@warmcat.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#include "aepd.h"
+
+/*
+ * We take a strict whitelist approach to stop ../ attacks
+ */
+
+struct serveable {
+ const char *urlpath;
+ const char *mimetype;
+};
+
+static struct serveable whitelist[] = {
+ { "/favicon.ico", "image/x-icon" },
+ { "/linaro-logo-32.png", "image/png" },
+
+ /* last one is the default served if no match */
+ { "/aepscope.html", "text/html" },
+};
+
+/* this protocol server (always the first one) just knows how to do HTTP */
+
+static int callback_http(struct libwebsocket_context *context,
+ struct libwebsocket *wsi,
+ enum libwebsocket_callback_reasons reason, void *user,
+ void *in, size_t len)
+{
+ int n;
+ char buf[512];
+
+ switch (reason) {
+ case LWS_CALLBACK_HTTP:
+
+ for (n = 0; n < (sizeof(whitelist) / sizeof(whitelist[0]) - 1); n++)
+ if (in && strcmp(in, whitelist[n].urlpath) == 0)
+ break;
+
+ sprintf(buf, LOCAL_RESOURCE_PATH"%s", whitelist[n].urlpath);
+
+ if (libwebsockets_serve_http_file(wsi, buf, whitelist[n].mimetype))
+ fprintf(stderr, "Failed to send HTTP file\n");
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+
+
+/* linaro_aepd_protocol */
+
+struct per_session_data__linaro_aepd {
+ struct libwebsocket *wsi;
+ unsigned long ringbuffer_tail;
+ double sam[MAX_PROBES * CHANNELS_PER_PROBE * 3];
+ int sam_valid;
+ int stride;
+};
+
+
+static int
+callback_linaro_aepd(struct libwebsocket_context *context,
+ struct libwebsocket *wsi,
+ enum libwebsocket_callback_reasons reason,
+ void *user, void *in, size_t len)
+{
+ int n, m;
+ struct per_session_data__linaro_aepd *pss = user;
+ double sam[MAX_PROBES * CHANNELS_PER_PROBE * 3];
+ double d[10];
+ char buf[LWS_SEND_BUFFER_PRE_PADDING + 16384 + LWS_SEND_BUFFER_POST_PADDING];
+ char *p = &buf[LWS_SEND_BUFFER_PRE_PADDING];
+ int budget = 10;
+ unsigned long extent;
+
+ switch (reason) {
+
+ case LWS_CALLBACK_ESTABLISHED:
+ pss->ringbuffer_tail = aepd_shared->fifo_pos;
+ pss->sam_valid = 0;
+ pss->wsi = wsi;
+ pss->stride = 100;
+ break;
+
+ case LWS_CALLBACK_SERVER_WRITEABLE:
+
+ /*
+ * aggregate up to 'budget' results in one websocket message
+ */
+
+ while (budget--) {
+
+ if (pss->ringbuffer_tail <= aepd_shared->fifo_pos)
+ extent = aepd_shared->fifo_pos - pss->ringbuffer_tail;
+ else
+ extent = (aepd_shared->modulo_integer_chan_size - pss->ringbuffer_tail) + aepd_shared->fifo_pos;
+
+ if (extent < (pss->stride * aepd_shared->chans * sizeof(double) * 3)) {
+ budget = 0;
+ continue;
+ }
+
+ lseek(aepd_shared->fd_fifo_read, pss->ringbuffer_tail, SEEK_SET);
+ if (read(aepd_shared->fd_fifo_read, &sam[0], aepd_shared->chans * sizeof(double) * 3) < 0)
+ fprintf(stderr, "fifo read fail\n");
+
+ pss->ringbuffer_tail += (pss->stride * aepd_shared->chans * sizeof(double) * 3 );
+ if (pss->ringbuffer_tail > aepd_shared->modulo_integer_chan_size)
+ pss->ringbuffer_tail -= aepd_shared->modulo_integer_chan_size;
+
+ if (pss->sam_valid) {
+
+ /*
+ * Javascript can't cope with binary, so we must ascii-fy it
+ */
+
+ m = 0;
+ for (n = 0; n < aepd_shared->chans; n++) {
+ p += sprintf(p, "%f %f %f",
+ (sam[m] - pss->sam[m]) / (double)pss->stride,
+ (sam[m + 1] - pss->sam[m + 1]) / (double)pss->stride,
+ (sam[m + 2] - pss->sam[m + 2]) / (double)pss->stride
+ );
+
+ if (n + 1 != aepd_shared->chans) {
+ *p++ = ',';
+ *p = '\0';
+ }
+ m += 3;
+ }
+
+ *p++ = ';';
+ *p = '\0';
+ }
+
+ memcpy(&pss->sam[0], &sam[0], aepd_shared->chans * sizeof(double) * 3);
+ pss->sam_valid = 1;
+ }
+
+ /*
+ * if we generated something, send it. We are guaranteed not to block
+ * because we got here by POLLOUT seen on the socket
+ */
+
+ if (p != &buf[LWS_SEND_BUFFER_PRE_PADDING]) {
+ n = libwebsocket_write(wsi, (unsigned char *)
+ &buf[LWS_SEND_BUFFER_PRE_PADDING],
+ p - &buf[LWS_SEND_BUFFER_PRE_PADDING], LWS_WRITE_TEXT);
+ if (n < 0) {
+ fprintf(stderr, "ERROR writing to socket");
+ return 1;
+ }
+ libwebsocket_callback_on_writable(context, wsi);
+ }
+
+ break;
+
+ case LWS_CALLBACK_RECEIVE:
+
+ switch (*(char *)in) {
+ case 'r':
+ if (sscanf(((char *)in) + 1, "%lf\n", &d[0]) == 1)
+ pss->stride = (int)d[0];
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/* list of supported protocols and callbacks */
+
+struct libwebsocket_protocols protocols[] = {
+ /* first protocol must always be HTTP handler */
+
+ {
+ "http-only", /* name */
+ callback_http, /* callback */
+ 0 /* per_session_data_size */
+ },
+ {
+ "linaro.aepd",
+ callback_linaro_aepd,
+ sizeof(struct per_session_data__linaro_aepd),
+ },
+ {
+ NULL, NULL, 0 /* End of list */
+ }
+};
+