/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set et sw=2 ts=2: */ /*************************************************************************** * muniad.cc * * Thu Feb 16 15:03:28 CET 2012 * Copyright 2012 Bent Bisballe Nyeng * deva@aasimon.org ****************************************************************************/ /* * This file is part of Munia. * * Munia 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. * * Munia 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 Munia; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ #include #include #include #include #include #include #include #define LWS_NO_FORK static int close_testing; /* * This demo server shows how to use libwebsockets for one or more * websocket protocols in the same server * * It defines the following websocket protocols: * lws-mirror-protocol: copies any received packet to every connection also * using this protocol, including the sender */ enum demo_protocols { /* always first */ PROTOCOL_HTTP = 0, PROTOCOL_LWS_MIRROR, /* always last */ DEMO_PROTOCOL_COUNT }; #define LOCAL_RESOURCE_PATH "." /* 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) { char client_name[128]; char client_ip[128]; switch (reason) { case LWS_CALLBACK_HTTP: fprintf(stderr, "serving HTTP URI %s\n", (char *)in); if(in && strcmp((const char *)in, "/favicon.ico") == 0) { if(libwebsockets_serve_http_file(wsi, LOCAL_RESOURCE_PATH"/favicon.ico", "image/x-icon")) fprintf(stderr, "Failed to send favicon\n"); break; } /* send the script... when it runs it'll start websockets */ if (libwebsockets_serve_http_file(wsi, LOCAL_RESOURCE_PATH"/test.html", "text/html")) fprintf(stderr, "Failed to send HTTP file\n"); break; /* * callback for confirming to continue with client IP appear in * protocol 0 callback since no websocket protocol has been agreed * yet. You can just ignore this if you won't filter on client IP * since the default uhandled callback return is 0 meaning let the * connection continue. */ case LWS_CALLBACK_FILTER_NETWORK_CONNECTION: libwebsockets_get_peer_addresses((int)(long)user, client_name, sizeof(client_name), client_ip, sizeof(client_ip)); fprintf(stderr, "Received network connect from %s (%s)\n", client_name, client_ip); /* if we returned non-zero from here, we kill the connection */ break; default: break; } return 0; } /* * this is just an example of parsing handshake headers, you don't need this * in your code unless you will filter allowing connections by the header * content */ static void dump_handshake_info(struct lws_tokens *lwst) { int n; static const char *token_names[WSI_TOKEN_COUNT] = { /*[WSI_TOKEN_GET_URI] =*/ "GET URI", /*[WSI_TOKEN_HOST] =*/ "Host", /*[WSI_TOKEN_CONNECTION] =*/ "Connection", /*[WSI_TOKEN_KEY1] =*/ "key 1", /*[WSI_TOKEN_KEY2] =*/ "key 2", /*[WSI_TOKEN_PROTOCOL] =*/ "Protocol", /*[WSI_TOKEN_UPGRADE] =*/ "Upgrade", /*[WSI_TOKEN_ORIGIN] =*/ "Origin", /*[WSI_TOKEN_DRAFT] =*/ "Draft", /*[WSI_TOKEN_CHALLENGE] =*/ "Challenge", /* new for 04 */ /*[WSI_TOKEN_KEY] =*/ "Key", /*[WSI_TOKEN_VERSION] =*/ "Version", /*[WSI_TOKEN_SWORIGIN] =*/ "Sworigin", /* new for 05 */ /*[WSI_TOKEN_EXTENSIONS] =*/ "Extensions", /* client receives these */ /*[WSI_TOKEN_ACCEPT] =*/ "Accept", /*[WSI_TOKEN_NONCE] =*/ "Nonce", /*[WSI_TOKEN_HTTP] =*/ "Http", /*[WSI_TOKEN_MUXURL] =*/ "MuxURL", }; for (n = 0; n < WSI_TOKEN_COUNT; n++) { if (lwst[n].token == NULL) continue; fprintf(stderr, " %s = %s\n", token_names[n], lwst[n].token); } } /* lws-mirror_protocol */ #define MAX_MESSAGE_QUEUE 1024 struct per_session_data__lws_mirror { struct libwebsocket *wsi; int ringbuffer_tail; }; struct a_message { void *payload; size_t len; }; #include #include typedef int boxid_t; class Box { public: Box(std::string data) {} Box() {} boxid_t id; std::string title; std::string description; int x, y; }; std::map boxes; /* Protocol: Server -> client: update [id] [title] [description]; move [id] [x] [y]; add [title] [description]; Client -> server: update [id] [title] [description]; move [id] [x] [y]; add [id] [title] [description] [x] [y]; title and description are " encapsulated utf-8 string with " escaped with a backslash. x and y are integers as strings id are an integer as a string */ static struct a_message ringbuffer[MAX_MESSAGE_QUEUE]; static int ringbuffer_head; static int callback_lws_mirror(struct libwebsocket_context * context, struct libwebsocket *wsi, enum libwebsocket_callback_reasons reason, void *user, void *in, size_t len) { int n; struct per_session_data__lws_mirror *pss = (struct per_session_data__lws_mirror *)user; switch (reason) { case LWS_CALLBACK_ESTABLISHED: { fprintf(stderr, "callback_lws_mirror: LWS_CALLBACK_ESTABLISHED\n"); pss->ringbuffer_tail = ringbuffer_head; pss->wsi = wsi; } break; case LWS_CALLBACK_SERVER_WRITEABLE: { printf("LWS_CALLBACK_SERVER_WRITEABLE\n"); if(close_testing) break; if(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++; if(((ringbuffer_head - pss->ringbuffer_tail) % MAX_MESSAGE_QUEUE) < (MAX_MESSAGE_QUEUE - 15)) libwebsocket_rx_flow_control(wsi, 1); libwebsocket_callback_on_writable(context, wsi); } } break; case LWS_CALLBACK_BROADCAST: printf("LWS_CALLBACK_BROADCAST\n"); n = libwebsocket_write(wsi, (unsigned char*)in, len, LWS_WRITE_TEXT); if (n < 0) fprintf(stderr, "mirror write failed\n"); break; case LWS_CALLBACK_RECEIVE: { printf("LWS_CALLBACK_RECEIVE\n"); printf("%s\n", (char*)in); std::string data; data.append((char*)in, len); std::string cmd = data.substr(0, data.find(' ')); printf("Cmd: %s\n", cmd.c_str()); if(cmd == "add") { printf("Add\n"); } else if(cmd == "move") { printf("Move\n"); } else if(cmd == "update") { printf("Update\n"); } else { // unknown command } struct a_message &msg = ringbuffer[ringbuffer_head]; if(msg.payload) { free(msg.payload); msg.payload = NULL; } msg.payload = malloc(LWS_SEND_BUFFER_PRE_PADDING + len + LWS_SEND_BUFFER_POST_PADDING); msg.len = len; memcpy((char *)msg.payload + LWS_SEND_BUFFER_PRE_PADDING, in, len); if(ringbuffer_head == (MAX_MESSAGE_QUEUE - 1)) ringbuffer_head = 0; else ringbuffer_head++; if(((ringbuffer_head - pss->ringbuffer_tail) % MAX_MESSAGE_QUEUE) > (MAX_MESSAGE_QUEUE - 10)) libwebsocket_rx_flow_control(wsi, 0); libwebsocket_callback_on_writable_all_protocol(libwebsockets_get_protocol(wsi)); } break; /* * this just demonstrates how to use the protocol filter. If you won't * study and reject connections based on header content, you don't need * to handle this callback */ case LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION: printf("LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION\n"); dump_handshake_info((struct lws_tokens *)(long)user); /* you could return non-zero here and kill the connection */ break; default: break; } return 0; } /* list of supported protocols and callbacks */ static struct libwebsocket_protocols protocols[] = { /* first protocol must always be HTTP handler */ { "http-only", /* name */ callback_http, /* callback */ 0 /* per_session_data_size */ }, { "lws-mirror-protocol", callback_lws_mirror, sizeof(struct per_session_data__lws_mirror) }, { NULL, NULL, 0 /* End of list */ } }; static struct option options[] = { { "help", no_argument, NULL, 'h' }, { "port", required_argument, NULL, 'p' }, { "ssl", no_argument, NULL, 's' }, { "killmask", no_argument, NULL, 'k' }, { "interface", required_argument, NULL, 'i' }, { "closetest", no_argument, NULL, 'c' }, { NULL, 0, 0, 0 } }; int main(int argc, char **argv) { int n = 0; const char *cert_path = LOCAL_RESOURCE_PATH"/libwebsockets-test-server.pem"; const char *key_path = LOCAL_RESOURCE_PATH"/libwebsockets-test-server.key.pem"; unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 1024 + LWS_SEND_BUFFER_POST_PADDING]; int port = 7681; int use_ssl = 0; struct libwebsocket_context *context; int opts = 0; char interface_name[128] = ""; const char * interface = NULL; #ifdef LWS_NO_FORK unsigned int oldus = 0; #endif fprintf(stderr, "libwebsockets test server\n" "(C) Copyright 2010-2011 Andy Green " "licensed under LGPL2.1\n"); while (n >= 0) { n = getopt_long(argc, argv, "ci:khsp:", options, NULL); if (n < 0) continue; switch (n) { case 's': use_ssl = 1; break; case 'k': opts = LWS_SERVER_OPTION_DEFEAT_CLIENT_MASK; break; case 'p': port = atoi(optarg); break; case 'i': strncpy(interface_name, optarg, sizeof interface_name); interface_name[(sizeof interface_name) - 1] = '\0'; interface = interface_name; break; case 'c': close_testing = 1; fprintf(stderr, " Close testing mode -- closes on " "client after 50 dumb increments" "and suppresses lws_mirror spam\n"); break; case 'h': fprintf(stderr, "Usage: test-server " "[--port=

] [--ssl]\n"); exit(1); } } if (!use_ssl) cert_path = key_path = NULL; context = libwebsocket_create_context(port, interface, protocols, libwebsocket_internal_extensions, cert_path, key_path, -1, -1, opts); if (context == NULL) { fprintf(stderr, "libwebsocket init failed\n"); return -1; } buf[LWS_SEND_BUFFER_PRE_PADDING] = 'x'; #ifdef LWS_NO_FORK /* * This example shows how to work with no forked service loop */ fprintf(stderr, " Using no-fork service loop\n"); while (1) { /* * This example server does not fork or create a thread for * websocket service, it all runs in this single loop. So, * we have to give the websockets an opportunity to service * "manually". * * If no socket is needing service, the call below returns * immediately and quickly. */ libwebsocket_service(context, 50); } #else /* * This example shows how to work with the forked websocket service loop */ fprintf(stderr, " Using forked service loop\n"); /* * This forks the websocket service action into a subprocess so we * don't have to take care about it. */ n = libwebsockets_fork_service_loop(context); if (n < 0) { fprintf(stderr, "Unable to fork service loop %d\n", n); return 1; } while (1) { usleep(50000); /* * This broadcasts to all dumb-increment-protocol connections * at 20Hz. * * We're just sending a character 'x', in these examples the * callbacks send their own per-connection content. * * You have to send something with nonzero length to get the * callback actions delivered. * * We take care of pre-and-post padding allocation. */ libwebsockets_broadcast(&protocols[PROTOCOL_DUMB_INCREMENT], &buf[LWS_SEND_BUFFER_PRE_PADDING], 1); } #endif libwebsocket_context_destroy(context); return 0; } #ifdef TEST_MUNIAD //Additional dependency files //deps: //Required cflags (autoconf vars may be used) //cflags: //Required link options (autoconf vars may be used) //libs: #include "test.h" TEST_BEGIN; // TODO: Put some testcode here (see test.h for usable macros). TEST_TRUE(false, "No tests yet!"); TEST_END; #endif/*TEST_MUNIAD*/