X-Git-Url: http://git.code-monkey.de/?a=blobdiff_plain;f=shm_utils%2Fumurmurd-websocket%2Fsrc%2FuMurmurd_Websocket.c;fp=shm_utils%2Fumurmurd-websocket%2Fsrc%2FuMurmurd_Websocket.c;h=0000000000000000000000000000000000000000;hb=1fbc5db2d0c6168e10b116cb474174d165192530;hp=d532a1e4fec4dda7be84d3d342cdcfcec8d8a6e6;hpb=a738ff892738e239ad74f5aa686108298efa7cea;p=umurmur.git diff --git a/shm_utils/umurmurd-websocket/src/uMurmurd_Websocket.c b/shm_utils/umurmurd-websocket/src/uMurmurd_Websocket.c deleted file mode 100644 index d532a1e..0000000 --- a/shm_utils/umurmurd-websocket/src/uMurmurd_Websocket.c +++ /dev/null @@ -1,632 +0,0 @@ -/* - * uMurmurd Websocket - HTTP/JSON server example - * - * Copyright (C) 2014 Michael P. Pounders <> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation: - * version 2.1 of the License. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301 USA - */ -#ifdef CMAKE_BUILD -#include "lws_config.h" -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include "../../../src/sharedmemory.h" - -struct pollfd *pollfds; -char *resource_path = "../web"; -int max_poll_elements, *fd_lookup, count_pollfds, force_exit = 0, autoupdate = 0; - -enum demo_protocols { - /* always first */ - PROTOCOL_HTTP = 0, - PROTOCOL_JSON_UMURMURD, - /* always last */ - DEMO_PROTOCOL_COUNT -}; - -/* - * We take a strict whitelist approach to stop ../ attacks - */ - -struct serveable { - const char *urlpath; - const char *mimetype; -}; - -static const struct serveable whitelist[] = { - { "/favicon.ico", "image/x-icon" }, - { "/css/mon_umurmurd.css", "text/css" }, - { "/css/json.human.css", "text/css" }, - { "/js/crel.js", "text/javascript" }, - { "/js/json.human.js", "text/javascript" }, - { "/js/jquery.min.js", "text/javascript" }, - - /* last one is the default served if no match */ - { "/mon_umurmurd.html", "text/html" }, -}; - -struct per_session_data__http { - int fd; -}; - -/* 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) -{ -#if 0 - char client_name[128]; - char client_ip[128]; -#endif - char buf[256]; - char leaf_path[1024]; - int n, m; - unsigned char *p; - static unsigned char buffer[4096]; - struct stat stat_buf; - struct per_session_data__http *pss = - (struct per_session_data__http *)user; - - switch (reason) { - case LWS_CALLBACK_HTTP: - - /* check for the "send a big file by hand" example case */ - - if (!strcmp((const char *)in, "/leaf.jpg")) { - if (strlen(resource_path) > sizeof(leaf_path) - 10) - return -1; - sprintf(leaf_path, "%s/leaf.jpg", resource_path); - - /* well, let's demonstrate how to send the hard way */ - - p = buffer; - - pss->fd = open(leaf_path, O_RDONLY); - - if (pss->fd < 0) - return -1; - - fstat(pss->fd, &stat_buf); - - /* - * we will send a big jpeg file, but it could be - * anything. Set the Content-Type: appropriately - * so the browser knows what to do with it. - */ - - p += sprintf((char *)p, - "HTTP/1.0 200 OK\x0d\x0a" - "Server: libwebsockets\x0d\x0a" - "Content-Type: image/jpeg\x0d\x0a" - "Content-Length: %u\x0d\x0a\x0d\x0a", - (unsigned int)stat_buf.st_size); - - /* - * send the http headers... - * this won't block since it's the first payload sent - * on the connection since it was established - * (too small for partial) - */ - - n = libwebsocket_write(wsi, buffer, - p - buffer, LWS_WRITE_HTTP); - - if (n < 0) { - close(pss->fd); - return -1; - } - /* - * book us a LWS_CALLBACK_HTTP_WRITEABLE callback - */ - libwebsocket_callback_on_writable(context, wsi); - break; - } - - /* if not, send a file the easy way */ - - for (n = 0; n < (sizeof(whitelist) / sizeof(whitelist[0]) - 1); n++) - if (in && strcmp((const char *)in, whitelist[n].urlpath) == 0) - break; - - sprintf(buf, "%s%s", resource_path, whitelist[n].urlpath); - - if (libwebsockets_serve_http_file(context, wsi, buf, whitelist[n].mimetype)) - return -1; /* through completion or error, close the socket */ - - /* - * notice that the sending of the file completes asynchronously, - * we'll get a LWS_CALLBACK_HTTP_FILE_COMPLETION callback when - * it's done - */ - - break; - - case LWS_CALLBACK_HTTP_FILE_COMPLETION: -// lwsl_info("LWS_CALLBACK_HTTP_FILE_COMPLETION seen\n"); - /* kill the connection after we sent one file */ - return -1; - - case LWS_CALLBACK_HTTP_WRITEABLE: - /* - * we can send more of whatever it is we were sending - */ - - do { - n = read(pss->fd, buffer, sizeof buffer); - /* problem reading, close conn */ - if (n < 0) - goto bail; - /* sent it all, close conn */ - if (n == 0) - goto bail; - /* - * because it's HTTP and not websocket, don't need to take - * care about pre and postamble - */ - m = libwebsocket_write(wsi, buffer, n, LWS_WRITE_HTTP); - if (m < 0) - /* write failed, close conn */ - goto bail; - if (m != n) - /* partial write, adjust */ - lseek(pss->fd, m - n, SEEK_CUR); - - } while (!lws_send_pipe_choked(wsi)); - libwebsocket_callback_on_writable(context, wsi); - break; - -bail: - close(pss->fd); - return -1; - - /* - * 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: -#if 0 - libwebsockets_get_peer_addresses(context, wsi, (int)(long)in, client_name, - sizeof(client_name), client_ip, sizeof(client_ip)); - - fprintf(stderr, "Received network connect from %s (%s)\n", - client_name, client_ip); -#endif - /* 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 libwebsocket *wsi) -{ - 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", - }; - char buf[256]; - - for (n = 0; n < WSI_TOKEN_COUNT; n++) { - if (!lws_hdr_total_length(wsi, n)) - continue; - - lws_hdr_copy(wsi, buf, sizeof buf, n); - - fprintf(stderr, " %s = %s\n", token_names[n], buf); - } -} - -void *getJsonData( unsigned char * buf, int *n ) -{ - -int cc; -json_t *jarr1; -char *result = NULL; - -json_t *root = NULL, *server = NULL, *client, *clients; - - root = json_object(); - clients = json_object(); - - - server = json_pack( "{s:{:s:i,s:i}}", - "server", - "clients_max", shmptr->server_max_clients, - "clients_connected", shmptr->clientcount ); - - json_object_update( root, server ); - - if( shmptr->clientcount ) - { - jarr1 = json_array(); - - for( cc = 0 ; cc < shmptr->server_max_clients ; cc++ ) - { - - if( !shmptr->client[cc].authenticated ) - continue; - - client = json_pack( "{:s:s,s:s,s:i,s:s,s:i,s:i}", - "username", - shmptr->client[cc].username, - "ipaddress", - shmptr->client[cc].ipaddress, - "udp_port", - shmptr->client[cc].udp_port, - "channel", - shmptr->client[cc].channel, - "online_secs", - shmptr->client[cc].online_secs, - "idle_secs", - shmptr->client[cc].idle_secs - ); - json_array_append_new( jarr1, client ); - - } - json_object_set_new( clients, "clients", jarr1 ); - json_object_update( root, clients ); - -} - //json_dump_file(root, "json.txt", JSON_PRESERVE_ORDER | JSON_INDENT(4) ); - result = json_dumps(root, JSON_PRESERVE_ORDER | JSON_COMPACT ); - - *n = sprintf( (char *)&buf[LWS_SEND_BUFFER_PRE_PADDING], "%s", result ); - - - if( result ) - free( result ); - - - - json_decref(root); - return 0; -} - -struct per_session_data__umurmurd_json { - int test; -}; - -static int -callback_umurmurd_json( struct libwebsocket_context *context, - struct libwebsocket *wsi, - enum libwebsocket_callback_reasons reason, - void *user, void *in, size_t len) -{ - int m, n; - - unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 4096 + - LWS_SEND_BUFFER_POST_PADDING]; - - //struct per_session_data__umurmurd_json *pss = (struct per_session_data__umurmurd_json *)user; - - switch (reason) { - - case LWS_CALLBACK_ESTABLISHED: - lwsl_info("callback_umurmurd_json: LWS_CALLBACK_ESTABLISHED\n"); - break; - - case LWS_CALLBACK_SERVER_WRITEABLE: - getJsonData( buf, &n ); - m = libwebsocket_write(wsi, &buf[LWS_SEND_BUFFER_PRE_PADDING], n, LWS_WRITE_TEXT); //printf("N: %d M: %d\n", n, m ); - - if( m == n ) - return 1; - break; - - case LWS_CALLBACK_RECEIVE: - //fprintf(stderr, "rx %d\n", (int)len); -// if (len < 6) -// break; - if( strcmp((const char *)in, "update\n") == 0 ) - { - libwebsocket_callback_on_writable_all_protocol(libwebsockets_get_protocol( wsi )); - break; - } - else if( strcmp((const char *)in, "autoupdate\n") == 0 ) - { - autoupdate = !autoupdate; //toggle - 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: - dump_handshake_info(wsi); - /* 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 */ - sizeof (struct per_session_data__http), /* per_session_data_size */ - 0, /* max frame size / rx buffer */ - }, - { - "umurmurd-json-protocol", - callback_umurmurd_json, - sizeof(struct per_session_data__umurmurd_json), - 128, - }, - { NULL, NULL, 0, 0 } /* terminator */ -}; - -void sighandler(int sig) -{ - force_exit = 1; -} - -static struct option options[] = { - { "help", no_argument, NULL, 'h' }, - { "debug", required_argument, NULL, 'd' }, - { "port", required_argument, NULL, 'p' }, - { "ssl", no_argument, NULL, 's' }, - { "interface", required_argument, NULL, 'i' }, - { "daemonize", no_argument, NULL, 'D' }, - { "resource_path", required_argument, NULL, 'r' }, - { NULL, 0, 0, 0 } -}; - -int main(int argc, char **argv) -{ - char cert_path[1024]; - char key_path[1024]; - int n = 0; - int use_ssl = 0; - struct libwebsocket_context *context; - int opts = 0; - char interface_name[128] = ""; - const char *iface = NULL; - uint64_t oldus = 0; - struct lws_context_creation_info info; - - int syslog_options = LOG_PID | LOG_PERROR; - - int debug_level = 7; - - int daemonize = 0; - - - memset(&info, 0, sizeof info); - info.port = 7681; - - while (n >= 0) { - n = getopt_long(argc, argv, "i:hsp:d:Dr:", options, NULL); - if (n < 0) - continue; - switch (n) { - case 'D': - daemonize = 1; - syslog_options &= ~LOG_PERROR; - break; - - case 'd': - debug_level = atoi(optarg); - break; - case 's': - use_ssl = 1; - break; - case 'p': - info.port = atoi(optarg); - break; - case 'i': - strncpy(interface_name, optarg, sizeof interface_name); - interface_name[(sizeof interface_name) - 1] = '\0'; - iface = interface_name; - break; - case 'r': - resource_path = optarg; - printf("Setting resource path to \"%s\"\n", resource_path); - break; - case 'h': - fprintf(stderr, "Usage: test-server " - "[--port=

] [--ssl] " - "[-d ] " - "[--resource_path ]\n"); - exit(1); - } - } - -key_t key = 0x53021d79; - - if( ( shmid = shmget( key, 0, 0) ) == -1 ) - { - perror("shmget"); - printf( "umurmurd doesn't seem to be running\n\r" ); - exit(EXIT_FAILURE); - } - - - if( ( shmptr = shmat( shmid,0, 0 ) ) == (void *) -1 ) - { - perror("shmat"); - exit(EXIT_FAILURE); - } - - - /* - * normally lock path would be /var/lock/lwsts or similar, to - * simplify getting started without having to take care about - * permissions or running as root, set to /tmp/.lwsts-lock - */ - if (daemonize && lws_daemonize("/tmp/.lwsts-lock")) { - fprintf(stderr, "Failed to daemonize\n"); - return 1; - } - - - signal(SIGINT, sighandler); - - - /* we will only try to log things according to our debug_level */ - setlogmask(LOG_UPTO (LOG_DEBUG)); - openlog("lwsts", syslog_options, LOG_DAEMON); - - - /* tell the library what debug level to emit and to send it to syslog */ - lws_set_log_level(debug_level, lwsl_emit_syslog); - - lwsl_notice("uMurmurd Websocket server - " - "(C) Copyright 2014 Michael J. Pounders <> - " - "licensed under LGPL2.1\n"); - - info.iface = iface; - info.protocols = protocols; - - info.extensions = libwebsocket_get_internal_extensions(); - - if (!use_ssl) { - info.ssl_cert_filepath = NULL; - info.ssl_private_key_filepath = NULL; - } else { - if (strlen(resource_path) > sizeof(cert_path) - 32) { - lwsl_err("resource path too long\n"); - return -1; - } - sprintf(cert_path, "%s/ssl/umurmurd_websocket.pem", - resource_path); - if (strlen(resource_path) > sizeof(key_path) - 32) { - lwsl_err("resource path too long\n"); - return -1; - } - sprintf(key_path, "%s/ssl/umurmurd_websocket.key.pem", - resource_path); - - info.ssl_cert_filepath = cert_path; - info.ssl_private_key_filepath = key_path; - } - info.gid = -1; - info.uid = -1; - info.options = opts; - - context = libwebsocket_create_context(&info); - if (context == NULL) { - lwsl_err("libwebsocket init failed\n"); - return -1; - } - - n = 0; - while (n >= 0 && !force_exit) { - struct timeval tv; - - gettimeofday(&tv, NULL); - - /* - * This provokes the LWS_CALLBACK_SERVER_WRITEABLE for every - * live websocket connection using the DUMB_INCREMENT protocol, - * as soon as it can take more packets (usually immediately) - */ - if( autoupdate ) - { - if(((unsigned int)tv.tv_sec - oldus) > 1 ) - { - libwebsocket_callback_on_writable_all_protocol(&protocols[PROTOCOL_JSON_UMURMURD]); - oldus = tv.tv_sec; - } - } - - /* - * If libwebsockets sockets are all we care about, - * you can use this api which takes care of the poll() - * and looping through finding who needed service. - * - * If no socket needs service, it'll return anyway after - * the number of ms in the second argument. - */ - - n = libwebsocket_service(context, 50); - - } - - - libwebsocket_context_destroy(context); - - lwsl_notice("uMurmurd Websocket server exited cleanly\n"); - - shmdt( shmptr ); - closelog(); - - return 0; -}