diff --git a/examples/websocket_chat/websocket_chat.c b/examples/websocket_chat/websocket_chat.c
index a9bf9d87002f37a587942ab4cea144053849b6ff..d2ea624a72cdc5598489bc4a1b9c028529b699b4 100644
--- a/examples/websocket_chat/websocket_chat.c
+++ b/examples/websocket_chat/websocket_chat.c
@@ -18,42 +18,42 @@ static int is_websocket(const struct mg_connection *nc) {
   return nc->flags & MG_F_IS_WEBSOCKET;
 }
 
-static void broadcast(struct mg_connection *nc, const char *msg, size_t len) {
+static void broadcast(struct mg_connection *nc, const struct mg_str msg) {
   struct mg_connection *c;
   char buf[500];
+  char addr[32];
+  mg_sock_addr_to_str(&nc->sa, addr, sizeof(addr),
+                      MG_SOCK_STRINGIFY_IP | MG_SOCK_STRINGIFY_PORT);
 
-  snprintf(buf, sizeof(buf), "%p %.*s", nc, (int) len, msg);
+  snprintf(buf, sizeof(buf), "%s %.*s", addr, (int) msg.len, msg.p);
+  printf("%s\n", buf); /* Local echo. */
   for (c = mg_next(nc->mgr, NULL); c != NULL; c = mg_next(nc->mgr, c)) {
+    if (c == nc) continue; /* Don't send to the sender. */
     mg_send_websocket_frame(c, WEBSOCKET_OP_TEXT, buf, strlen(buf));
   }
 }
 
 static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
-  struct http_message *hm = (struct http_message *) ev_data;
-  struct websocket_message *wm = (struct websocket_message *) ev_data;
-
   switch (ev) {
-    case MG_EV_HTTP_REQUEST:
-      /* Usual HTTP request - serve static files */
-      mg_serve_http(nc, hm, s_http_server_opts);
-      nc->flags |= MG_F_SEND_AND_CLOSE;
-      break;
-    case MG_EV_WEBSOCKET_HANDSHAKE_DONE:
+    case MG_EV_WEBSOCKET_HANDSHAKE_DONE: {
       /* New websocket connection. Tell everybody. */
-      broadcast(nc, "joined", 6);
+      broadcast(nc, mg_mk_str("++ joined"));
       break;
-    case MG_EV_WEBSOCKET_FRAME:
+    }
+    case MG_EV_WEBSOCKET_FRAME: {
+      struct websocket_message *wm = (struct websocket_message *) ev_data;
       /* New websocket message. Tell everybody. */
-      broadcast(nc, (char *) wm->data, wm->size);
+      struct mg_str d = {(char *) wm->data, wm->size};
+      broadcast(nc, d);
       break;
-    case MG_EV_CLOSE:
+    }
+    case MG_EV_CLOSE: {
       /* Disconnect. Tell everybody. */
       if (is_websocket(nc)) {
-        broadcast(nc, "left", 4);
+        broadcast(nc, mg_mk_str("-- left"));
       }
       break;
-    default:
-      break;
+    }
   }
 }
 
@@ -63,6 +63,8 @@ int main(void) {
 
   signal(SIGTERM, signal_handler);
   signal(SIGINT, signal_handler);
+  setvbuf(stdout, NULL, _IOLBF, 0);
+  setvbuf(stderr, NULL, _IOLBF, 0);
 
   mg_mgr_init(&mgr, NULL);
 
diff --git a/examples/websocket_chat_client/Makefile b/examples/websocket_chat_client/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..5758a41d21f25208c1023afcec18af908e912c27
--- /dev/null
+++ b/examples/websocket_chat_client/Makefile
@@ -0,0 +1,2 @@
+PROG = websocket_chat_client
+include ../examples.mk
diff --git a/examples/websocket_chat_client/websocket_chat_client.c b/examples/websocket_chat_client/websocket_chat_client.c
new file mode 100644
index 0000000000000000000000000000000000000000..8191b4bf364e72b131229758e9c60f589610b25e
--- /dev/null
+++ b/examples/websocket_chat_client/websocket_chat_client.c
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2016 Cesanta Software Limited
+ * All rights reserved
+ */
+
+/*
+ * This is a WebSocket client example.
+ * Prints WS frames to stdout and forwards stdin to server.
+ */
+
+#include "mongoose.h"
+
+static int s_done = 0;
+static int s_is_connected = 0;
+
+static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
+  struct websocket_message *wm = (struct websocket_message *) ev_data;
+  (void) nc;
+
+  switch (ev) {
+    case MG_EV_CONNECT: {
+      int status = *((int *) ev_data);
+      if (status != 0) {
+        printf("-- Connection error: %d\n", status);
+      }
+      break;
+    }
+    case MG_EV_WEBSOCKET_HANDSHAKE_DONE: {
+      printf("-- Connected\n");
+      s_is_connected = 1;
+      break;
+    }
+    case MG_EV_POLL: {
+      char msg[500];
+      int n = 0;
+#ifdef _WIN32 /* Windows console input is special. */
+      INPUT_RECORD inp[100];
+      HANDLE h = GetStdHandle(STD_INPUT_HANDLE);
+      DWORD i, num;
+      if (!PeekConsoleInput(h, inp, sizeof(inp) / sizeof(*inp), &num)) break;
+      for (i = 0; i < num; i++) {
+        if (inp[i].EventType == KEY_EVENT &&
+            inp[i].Event.KeyEvent.wVirtualKeyCode == VK_RETURN) {
+          break;
+        }
+      }
+      if (i == num) break;
+      if (!ReadConsole(h, msg, sizeof(msg), &num, NULL)) break;
+      /* Un-unicode. This is totally not the right way to do it. */
+      for (i = 0; i < num * 2; i += 2) msg[i / 2] = msg[i];
+      n = (int) num;
+#else /* For everybody else, we just read() stdin. */
+      fd_set read_set, write_set, err_set;
+      struct timeval timeout = {0, 0};
+      FD_ZERO(&read_set);
+      FD_ZERO(&write_set);
+      FD_ZERO(&err_set);
+      FD_SET(0 /* stdin */, &read_set);
+      if (select(1, &read_set, &write_set, &err_set, &timeout) == 1) {
+        n = read(0, msg, sizeof(msg));
+      }
+#endif
+      if (n <= 0) break;
+      while (msg[n - 1] == '\r' || msg[n - 1] == '\n') n--;
+      mg_send_websocket_frame(nc, WEBSOCKET_OP_TEXT, msg, n);
+      break;
+    }
+    case MG_EV_WEBSOCKET_FRAME: {
+      printf("%.*s\n", (int) wm->size, wm->data);
+      break;
+    }
+    case MG_EV_CLOSE: {
+      if (s_is_connected) printf("-- Disconnected\n");
+      s_done = 1;
+      break;
+    }
+  }
+}
+
+int main(int argc, char **argv) {
+  struct mg_mgr mgr;
+  struct mg_connection *nc;
+  const char *chat_server_url = argc > 1 ? argv[1] : "ws://127.0.0.1:8000";
+
+  mg_mgr_init(&mgr, NULL);
+
+  nc = mg_connect_ws(&mgr, ev_handler, chat_server_url, "ws_chat", NULL);
+  if (nc == NULL) {
+    fprintf(stderr, "Invalid address\n");
+    return 1;
+  }
+
+  while (!s_done) {
+    mg_mgr_poll(&mgr, 100);
+  }
+  mg_mgr_free(&mgr);
+
+  return 0;
+}
diff --git a/mongoose.h b/mongoose.h
index 1dce271e6481676106abf8a9acbfb1e02f50cb3f..e92be6a813c0a8312e7a39c9ffc3c45c00b70c32 100644
--- a/mongoose.h
+++ b/mongoose.h
@@ -315,7 +315,10 @@ typedef struct stat cs_stat_t;
 #define to64(x) strtoll(x, NULL, 10)
 #define INT64_FMT PRId64
 #define INT64_X_FMT PRIx64
+
+#ifndef __cdecl
 #define __cdecl
+#endif
 
 #ifndef va_copy
 #ifdef __va_copy