introduce-mirror-test-protocol.patch

Signed-off-by: Andy Green <andy@warmcat.com>
diff --git a/test-server/test-server.c b/test-server/test-server.c
index 50a4975..d35e826 100644
--- a/test-server/test-server.c
+++ b/test-server/test-server.c
@@ -27,6 +27,20 @@
 
 #include "../lib/libwebsockets.h"
 
+/*
+ * This demo server shows how to use libwebsockets for one or more
+ * websocket protocols in the same server
+ *
+ * It defines the following websocket protocols:
+ *
+ *  dumb-increment-protocol:  once the socket is opened, an incrementing
+ *				ascii string is sent down it every 50ms.
+ * 				If you send "reset\n" on the websocket, then
+ * 				the incrementing number is reset to 0.
+ * 
+ */
+
+
 #define LOCAL_RESOURCE_PATH "/usr/share/libwebsockets-test-server"
 static int port = 7681;
 static int use_ssl = 0;
@@ -95,6 +109,7 @@
 		break;
 
 	case LWS_CALLBACK_RECEIVE:
+		fprintf(stderr, "rx %d\n", len);
 		if (len < 6)
 			break;
 		if (strcmp(in, "reset\n") == 0)
@@ -109,6 +124,91 @@
 }
 
 
+/* lws-mirror_protocol */
+
+#define MAX_MESSAGE_QUEUE 64
+const int MAX_COMMUNE_MEMBERS = 20;
+
+struct per_session_data__lws_mirror {
+	struct libwebsocket * wsi;
+	int ringbuffer_tail;
+};
+
+struct a_message {
+	struct per_session_data * sender;
+	void * payload;
+	size_t len;
+};
+
+static struct a_message ringbuffer[MAX_MESSAGE_QUEUE];
+static int ringbuffer_head;
+
+
+struct per_session_data * all_members;
+
+
+static int
+callback_lws_mirror(struct libwebsocket * wsi,
+			enum libwebsocket_callback_reasons reason,
+			void * user, void *in, size_t len)
+{
+	int n;
+	char buf[LWS_SEND_BUFFER_PRE_PADDING + 512 +
+						  LWS_SEND_BUFFER_POST_PADDING];
+	unsigned char *p = (unsigned char *)&buf[LWS_SEND_BUFFER_PRE_PADDING];
+	struct per_session_data__lws_mirror * pss = user;
+	
+	switch (reason) {
+
+	case LWS_CALLBACK_ESTABLISHED:
+		pss->wsi = wsi;
+		pss->ringbuffer_tail = ringbuffer_head;
+		break;
+
+	case LWS_CALLBACK_SEND:	
+		/* send everything that's pending */
+		while (pss->ringbuffer_tail != ringbuffer_head) {
+
+			n = libwebsocket_write(wsi,
+				(unsigned char *)ringbuffer[pss->ringbuffer_tail].payload +
+					LWS_SEND_BUFFER_PRE_PADDING,
+				   ringbuffer[pss->ringbuffer_tail].len,
+							LWS_WRITE_TEXT);
+			if (n < 0) {
+				fprintf(stderr, "ERROR writing to socket");
+				exit(1);
+			}
+
+			if (pss->ringbuffer_tail == (MAX_MESSAGE_QUEUE - 1))
+				pss->ringbuffer_tail = 0;
+			else
+				pss->ringbuffer_tail++;
+		}
+		break;
+
+	case LWS_CALLBACK_RECEIVE:
+//		fprintf(stderr, "Received %d bytes payload\n", (int)len);
+		ringbuffer[ringbuffer_head].payload =
+				malloc(LWS_SEND_BUFFER_PRE_PADDING + len +
+						  LWS_SEND_BUFFER_POST_PADDING);
+		ringbuffer[ringbuffer_head].len = len;
+		ringbuffer[ringbuffer_head].sender = pss;
+		memcpy(ringbuffer[ringbuffer_head].payload +
+					  LWS_SEND_BUFFER_PRE_PADDING, in, len);
+		if (ringbuffer_head == (MAX_MESSAGE_QUEUE - 1))
+			ringbuffer_head = 0;
+		else
+			ringbuffer_head++;
+		break;
+
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+
 /* list of supported protocols and callbacks */
 
 static const struct libwebsocket_protocols protocols[] = {
@@ -123,6 +223,12 @@
 		.per_session_data_size =
 				sizeof(struct per_session_data__dumb_increment),
 	},
+	{
+		.name = "lws-mirror-protocol",
+		.callback = callback_lws_mirror,
+		.per_session_data_size =
+				sizeof(struct per_session_data__lws_mirror),
+	},
 	{  /* end of list */
 		.callback = NULL
 	}
diff --git a/test-server/test.html b/test-server/test.html
index 1539209..e2c9934 100644
--- a/test-server/test.html
+++ b/test-server/test.html
@@ -15,48 +15,161 @@
 	<tr>
 		<td align=center><input type=button id=offset value="Reset counter" onclick="reset();" ></td>
 		<td width=100 align=center><div id=number> </div></td>
-		<td id=statustd align=center><div id=wsstatus>Not initialized</div></td>
+		<td id=wsdi_statustd align=center><div id=wsdi_status>Not initialized</div></td>
+	</tr>
+</table>
+
+<h2>libwebsockets "lws-mirror-protocol" test applet</h2>
+Use the mouse to draw on the canvas below -- all other browser windows open
+on this page see your drawing in realtime and you can see any of theirs as
+well.
+<p>
+The lws-mirror protocol doesn't interpret what is being sent to it, it just
+re-sends it to every other websocket it has a connection with using that
+protocol, including the guy who sent the packet.
+<br><br>
+
+<table>
+	<tr>
+		<td>Drawing color:
+		<select id="color" onchange="update_color();">
+			<option value=#000000>Black</option>
+			<option value=#0000ff>Blue</option>
+			<option value=#20ff20>Green</option>
+			<option value=#802020>Dark Red</option>
+		</select>
+		</td>
+		<td id=wslm_statustd align=center><div id=wslm_status>Not initialized</div></td>
+	</tr>
+	<tr>
+		<td colspan=2 width=500 align=center style="background-color: #e0e0e0;"><div id=wslm_drawing> </div></td>
 	</tr>
 </table>
 
 <script>
 	var pos = 0;
-	var websocket_ads;
 
+function get_appropriate_ws_url(ads)
+{
 	/*
 	 * We open the websocket encrypted if this page came on an
 	 * https:// url itself, otherwise unencrypted
 	 */
 
 	if (document.URL.substring(0, 5) == "https")
-		websocket_ads = "wss://127.0.0.1:7681";
+		return "wss://"+ads;
 	else
-		websocket_ads = "ws://127.0.0.1:7681"
+		return "ws://"+ads;
+}
+
+/* dumb increment protocol */
 	
-	var socket = new WebSocket(websocket_ads, "dumb-increment-protocol");  
+	var socket_di = new WebSocket(get_appropriate_ws_url("127.0.0.1:7681"),
+				   "dumb-increment-protocol");  
 
 	try {
-		socket.onopen = function() {
-			statustd.style.backgroundColor = "#40ff40";
-			wsstatus.textContent = " websocket connection opened ";
+		socket_di.onopen = function() {
+			wsdi_statustd.style.backgroundColor = "#40ff40";
+			wsdi_status.textContent = " websocket connection opened ";
 		} 
 
-		socket.onmessage =function got_packet(msg) {
+		socket_di.onmessage =function got_packet(msg) {
 			number.textContent = msg.data + "\n";
 		} 
 
-		socket.onclose = function(){
-			statustd.style.backgroundColor = "#ff4040";
-			wsstatus.textContent = " websocket connection closed ";
+		socket_di.onclose = function(){
+			wsdi_statustd.style.backgroundColor = "#ff4040";
+			wsdi_status.textContent = " websocket connection closed ";
 		}
 	} catch(exception) {
-		alert('<p>Error'+exception);  
+		alert('<p>Error' + exception);  
 	}
 
 function reset() {
-	socket.send("reset\n");
+	socket_di.send("reset\n");
 }
 
+
+/* lws-mirror protocol */
+
+	var down = 0;
+	var no_last = 1;
+	var last_x, last_y;
+	var ctx;
+	var socket_lm = new WebSocket(get_appropriate_ws_url("127.0.0.1:7681"),
+				   "lws-mirror-protocol");
+	var color = "#000000";
+
+	try {
+		socket_lm.onopen = function() {
+			wslm_statustd.style.backgroundColor = "#40ff40";
+			wslm_status.textContent = " websocket connection opened ";
+		} 
+
+		socket_lm.onmessage =function got_packet(msg) {
+			i = msg.data.split(' ');
+			if (i[0] == 'd') {
+				ctx.strokeStyle = i[1];
+				ctx.beginPath();
+				ctx.moveTo(i[2], i[3]);
+				ctx.lineTo(i[4], i[5]);
+				ctx.stroke();
+			}
+		}
+
+		socket_lm.onclose = function(){
+			wslm_statustd.style.backgroundColor = "#ff4040";
+			wslm_status.textContent = " websocket connection closed ";
+		}
+	} catch(exception) {
+		alert('<p>Error' + exception);  
+	}
+
+	var canvas = document.createElement('canvas');
+	canvas.height = 300;
+	canvas.width = 480;
+	ctx = canvas.getContext("2d");
+
+	document.getElementById('wslm_drawing').appendChild(canvas);
+
+	canvas.addEventListener('mousemove', ev_mousemove, false);
+	canvas.addEventListener('mousedown', ev_mousedown, false);
+	canvas.addEventListener('mouseup', ev_mouseup, false);
+
+function update_color() {
+	color = document.getElementById("color").value;
+}
+
+function ev_mousedown (ev) {
+	down = 1;
+}
+
+function ev_mouseup(ev) {
+	down = 0;
+	no_last = 1;
+}
+
+function ev_mousemove (ev) {
+	var x, y;
+
+	x = ev.offsetX;
+	y = ev.offsetY;
+
+	if (!down)
+		return;
+	if (no_last) {
+		no_last = 0;
+		last_x = x;
+		last_y = y;
+		return;
+	}
+	socket_lm.send("d " + color + " " + last_x + " " + last_y + " " + x + ' ' + y);
+
+	last_x = x;
+	last_y = y;
+}
+
+
 </script>
 
 </body>