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