From 68d6c70d6b330941a5f22a35269d63d9d920064a Mon Sep 17 00:00:00 2001 From: Andy Green Date: Sat, 6 Oct 2012 20:04:42 +0800 Subject: introduce aepd Signed-off-by: Andy Green --- aepd/websocket-protocol.c | 218 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 218 insertions(+) create mode 100644 aepd/websocket-protocol.c (limited to 'aepd/websocket-protocol.c') 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 + * Copyright (C) 2012 Linaro, LTD + * Libwebsocket demo code (C) 2010-2012 Andy Green + * + * 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 */ + } +}; + -- cgit v1.2.3