/* * libwebsockets-test-echo - libwebsockets echo test implementation * * This implements both the client and server sides. It defaults to * serving, use --client to connect as client. * * Copyright (C) 2010-2013 Andy Green * * 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 */ #include #include #include #include #include #include #include #include #include #ifdef CMAKE_BUILD #include "lws_config.h" #endif #include int force_exit = 0; #define MAX_ECHO_PAYLOAD 1400 struct per_session_data__echo { unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + MAX_ECHO_PAYLOAD + LWS_SEND_BUFFER_POST_PADDING]; unsigned int len; unsigned int index; int counter; }; void scramble(unsigned char* str, unsigned int len){ unsigned int i = rand() % (len-1); unsigned int j = i+1; char t = str[i]; str[i] = str[j]; str[j] = t; } static int callback_echo(struct libwebsocket_context *context, struct libwebsocket *wsi, enum libwebsocket_callback_reasons reason, void *user, void *in, size_t len){ struct per_session_data__echo *pss = (struct per_session_data__echo *)user; int n; switch (reason) { case LWS_CALLBACK_SERVER_WRITEABLE: pss->counter++; scramble(&pss->buf[LWS_SEND_BUFFER_PRE_PADDING], pss->len); n = libwebsocket_write(wsi, &pss->buf[LWS_SEND_BUFFER_PRE_PADDING], pss->len, LWS_WRITE_TEXT); if (n < 0) { lwsl_err("ERROR %d writing to socket, hanging up\n", n); return 1; } if (n < pss->len) { lwsl_err("Partial write\n"); return -1; } break; case LWS_CALLBACK_RECEIVE: if (len > MAX_ECHO_PAYLOAD) { lwsl_err("Server received packet bigger than %u, hanging up\n", MAX_ECHO_PAYLOAD); return 1; } memcpy(&pss->buf[LWS_SEND_BUFFER_PRE_PADDING], in, len); pss->len = len; libwebsocket_callback_on_writable(context, wsi); break; case LWS_CALLBACK_CLIENT_ESTABLISHED: case LWS_CALLBACK_CLIENT_RECEIVE: case LWS_CALLBACK_CLIENT_WRITEABLE: default: break; } return 0; } static struct libwebsocket_protocols protocols[] = { /* first protocol must always be HTTP handler */ { "default", /* name */ callback_echo, /* callback */ sizeof(struct per_session_data__echo) /* per_session_data_size */ }, { NULL, NULL, 0 /* End of list */ } }; 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' }, #ifndef LWS_NO_DAEMONIZE { "daemonize", no_argument, NULL, 'D' }, #endif { NULL, 0, 0, 0 } }; int main(int argc, char **argv){ int n = 0; int port = 7681; int use_ssl = 0; struct libwebsocket_context *context; int opts = 0; char interface_name[128] = ""; const char *interface = NULL; int syslog_options = LOG_PID | LOG_PERROR; int client = 0; int listen_port; struct lws_context_creation_info info; int debug_level = 7; #ifndef LWS_NO_DAEMONIZE int daemonize = 0; #endif memset(&info, 0, sizeof info); #ifndef LWS_NO_SERVER lwsl_notice("Built to support server operations\n"); #endif while (n >= 0) { n = getopt_long(argc, argv, "i:hsp:d:D" , options, NULL); if (n < 0) continue; switch (n) { #ifndef LWS_NO_DAEMONIZE case 'D': daemonize = 1; syslog_options &= ~LOG_PERROR; break; #endif case 'd': debug_level = atoi(optarg); break; case 's': use_ssl = 1; /* 1 = take care about cert verification, 2 = allow anything */ 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 '?': case 'h': fprintf(stderr, "Usage: libwebsockets-test-echo " "[--ssl] " "[--port=

] " "[-d ]\n"); exit(1); } } #ifndef LWS_NO_DAEMONIZE /* * 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 (!client && daemonize && lws_daemonize("/tmp/.lwstecho-lock")) { fprintf(stderr, "Failed to daemonize\n"); return 1; } #endif /* 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("libwebsockets echo test - " "(C) Copyright 2010-2013 Andy Green - " "licensed under LGPL2.1\n"); #ifndef LWS_NO_SERVER lwsl_notice("Running in server mode\n"); listen_port = port; #endif info.port = listen_port; info.iface = interface; info.protocols = protocols; #ifndef LWS_NO_EXTENSIONS info.extensions = libwebsocket_get_internal_extensions(); #endif if (use_ssl && !client) { info.ssl_cert_filepath = "libwebsockets-test-server.pem"; info.ssl_private_key_filepath = "libwebsockets-test-server.key.pem"; } 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; } signal(SIGINT, sighandler); n = 0; while (n >= 0 && !force_exit) { n = libwebsocket_service(context, 10); } libwebsocket_context_destroy(context); lwsl_notice("libwebsockets-test-echo exited cleanly\n"); closelog(); return 0; }