From 4d5ac9c910554259d919ed41b006cc05f2f1e916 Mon Sep 17 00:00:00 2001 From: Andy Green Date: Mon, 2 May 2016 07:43:04 +0800 Subject: [PATCH] plugin standalone example for oot build Signed-off-by: Andy Green --- README.build.md | 37 ++++++ plugin-standalone/CMakeLists.txt | 78 +++++++++++++ plugin-standalone/protocol_example_standalone.c | 148 ++++++++++++++++++++++++ 3 files changed, 263 insertions(+) create mode 100644 plugin-standalone/CMakeLists.txt create mode 100644 plugin-standalone/protocol_example_standalone.c diff --git a/README.build.md b/README.build.md index 5ddd4ec..0b8a90b 100644 --- a/README.build.md +++ b/README.build.md @@ -339,6 +339,43 @@ Example config for this case is cmake .. -DLWS_USE_POLARSSL=1 -DLWS_POLARSSL_LIBRARIES=/usr/lib64/libmbedtls.so \ -DLWS_POLARSSL_INCLUDE_DIRS=/usr/include/polarssl/ + + +Building plugins outside of lws itself +-------------------------------------- + +The directory ./plugin-standalone/ shows how easy it is to create plugins +outside of lws itself. First build lws itself with -DLWS_WITH_PLUGINS, +then use the same flow to build the standalone plugin + +``` +cd ./plugin-standalone +mkdir build +cd build +cmake .. +make && sudo make install +``` + +if you changed the default plugin directory when you built lws, you must +also give the same arguments to cmake here (eg, +` -DCMAKE_INSTALL_PREFIX:PATH=/usr/something/else...` ) + +Otherwise if you run lwsws or libwebsockets-test-server-v2.0, it will now +find the additional plugin "libprotocol_example_standalone.so" + +``` +lwsts[21257]: Plugins: +lwsts[21257]: libprotocol_dumb_increment.so +lwsts[21257]: libprotocol_example_standalone.so +lwsts[21257]: libprotocol_lws_mirror.so +lwsts[21257]: libprotocol_lws_server_status.so +lwsts[21257]: libprotocol_lws_status.so +``` + +If you have multiple vhosts, you must enable plugins at the vhost +additionally, discovered plugins are not enabled automatically for security +reasons. You do this using info->pvo or for lwsws, in the JSON config. + Reproducing HTTP2.0 tests ------------------------- diff --git a/plugin-standalone/CMakeLists.txt b/plugin-standalone/CMakeLists.txt new file mode 100644 index 0000000..c5e92a0 --- /dev/null +++ b/plugin-standalone/CMakeLists.txt @@ -0,0 +1,78 @@ +cmake_minimum_required(VERSION 2.8) + +if(NOT DEFINED CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type") +endif() + +# This shows one way to build a standalone plugin +# outside of lws itself + +project(lws-protocol-plugin-example C) + +set(PACKAGE "lws-protocol-plugin-example") +set(CPACK_PACKAGE_NAME "${PACKAGE}") +set(CPACK_PACKAGE_VERSION "0.1") +set(CPACK_PACKAGE_VENDOR "andy@warmcat.com") +set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "${PACKAGE} ${PACKAGE_VERSION}") +set(SOVERSION "1") +set(VERSION "0.1") + + +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake/") + +message(STATUS "CMAKE_TOOLCHAIN_FILE='${CMAKE_TOOLCHAIN_FILE}'") + +# Try to find the current Git hash. +find_package(Git) +if(GIT_EXECUTABLE) + execute_process( + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + COMMAND "${GIT_EXECUTABLE}" describe + OUTPUT_VARIABLE GIT_HASH + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + execute_process( + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + COMMAND "whoami" + OUTPUT_VARIABLE GIT_USER + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + execute_process( + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + COMMAND "hostname" + OUTPUT_VARIABLE GIT_HOST + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + string(REGEX REPLACE "([^\\])[\\]([^\\])" "\\1\\\\\\\\\\2" GIT_USER ${GIT_USER}) + set(LWS_BUILD_HASH ${GIT_USER}@${GIT_HOST}-${GIT_HASH}) + message("Git commit hash: ${LWS_BUILD_HASH}") +endif() + +set(CMAKE_C_FLAGS "-fPIC ${CMAKE_C_FLAGS}") + +macro(create_plugin PLUGIN_NAME MAIN_SRC) + set(PLUGIN_SRCS ${MAIN_SRC}) + + source_group("Headers Private" FILES ${PLUGIN_HDR}) + source_group("Sources" FILES ${PLUGIN_SRCS}) + add_library(${PLUGIN_NAME} SHARED ${PLUGIN_SRCS} ${PLUGIN_HDR}) + + target_link_libraries(${PLUGIN_NAME} -lwebsockets) + + # Set test app specific defines. + set_property(TARGET ${PLUGIN_NAME} + PROPERTY COMPILE_DEFINITIONS + INSTALL_DATADIR="${CMAKE_INSTALL_PREFIX}/plugins" + ) + + list(APPEND PLUGINS_LIST ${PLUGIN_NAME}) +endmacro() + + +create_plugin(protocol_example_standalone + "protocol_example_standalone.c") + +install(TARGETS ${PLUGINS_LIST} + PERMISSIONS OWNER_WRITE OWNER_EXECUTE GROUP_EXECUTE WORLD_EXECUTE OWNER_READ GROUP_READ WORLD_READ + DESTINATION share/libwebsockets-test-server/plugins + COMPONENT plugins) \ No newline at end of file diff --git a/plugin-standalone/protocol_example_standalone.c b/plugin-standalone/protocol_example_standalone.c new file mode 100644 index 0000000..003afc5 --- /dev/null +++ b/plugin-standalone/protocol_example_standalone.c @@ -0,0 +1,148 @@ +/* + * ws protocol handler plugin for "dumb increment" + * + * Copyright (C) 2010-2016 Andy Green + * + * This file is made available under the Creative Commons CC0 1.0 + * Universal Public Domain Dedication. + * + * The person who associated a work with this deed has dedicated + * the work to the public domain by waiving all of his or her rights + * to the work worldwide under copyright law, including all related + * and neighboring rights, to the extent allowed by law. You can copy, + * modify, distribute and perform the work, even for commercial purposes, + * all without asking permission. + * + * These test plugins are intended to be adapted for use in your code, which + * may be proprietary. So unlike the library itself, they are licensed + * Public Domain. + * + * This is a copy of dumb_increment adapted slightly to serve as the + * "example-standalone-protocol", to show how to build protocol plugins + * outside the library easily. + */ +#include "../lib/libwebsockets.h" +#include + +struct per_vhost_data__dumb_increment { + uv_timer_t timeout_watcher; + struct lws_context *context; + struct lws_vhost *vhost; + const struct lws_protocols *protocol; +}; + +struct per_session_data__dumb_increment { + int number; +}; + +static void +uv_timeout_cb_dumb_increment(uv_timer_t *w +#if UV_VERSION_MAJOR == 0 + , int status +#endif +) +{ + struct per_vhost_data__dumb_increment *vhd = lws_container_of(w, + struct per_vhost_data__dumb_increment, timeout_watcher); + lws_callback_on_writable_all_protocol_vhost(vhd->vhost, vhd->protocol); +} + +static int +callback_dumb_increment(struct lws *wsi, enum lws_callback_reasons reason, + void *user, void *in, size_t len) +{ + struct per_session_data__dumb_increment *pss = + (struct per_session_data__dumb_increment *)user; + struct per_vhost_data__dumb_increment *vhd = + (struct per_vhost_data__dumb_increment *) + lws_protocol_vh_priv_get(lws_vhost_get(wsi), + lws_protocol_get(wsi)); + unsigned char buf[LWS_PRE + 512]; + unsigned char *p = &buf[LWS_PRE]; + int n, m; + + switch (reason) { + case LWS_CALLBACK_PROTOCOL_INIT: + vhd = lws_protocol_vh_priv_zalloc(lws_vhost_get(wsi), + lws_protocol_get(wsi), + sizeof(struct per_vhost_data__dumb_increment)); + vhd->context = lws_get_context(wsi); + vhd->protocol = lws_protocol_get(wsi); + vhd->vhost = lws_vhost_get(wsi); + uv_timer_init(lws_uv_getloop(vhd->context, 0), + &vhd->timeout_watcher); + uv_timer_start(&vhd->timeout_watcher, + uv_timeout_cb_dumb_increment, 50, 50); + break; + + case LWS_CALLBACK_PROTOCOL_DESTROY: + if (!vhd) + break; + uv_timer_stop(&vhd->timeout_watcher); + break; + + case LWS_CALLBACK_ESTABLISHED: + pss->number = 0; + break; + + case LWS_CALLBACK_SERVER_WRITEABLE: + n = sprintf((char *)p, "%d", pss->number++); + m = lws_write(wsi, p, n, LWS_WRITE_TEXT); + if (m < n) { + lwsl_err("ERROR %d writing to di socket\n", n); + return -1; + } + break; + + case LWS_CALLBACK_RECEIVE: + if (len < 6) + break; + if (strcmp((const char *)in, "reset\n") == 0) + pss->number = 0; + if (strcmp((const char *)in, "closeme\n") == 0) { + lwsl_notice("dumb_inc: closing as requested\n"); + lws_close_reason(wsi, LWS_CLOSE_STATUS_GOINGAWAY, + (unsigned char *)"seeya", 5); + return -1; + } + break; + + default: + break; + } + + return 0; +} + +static const struct lws_protocols protocols[] = { + { + "example-standalone-protocol", + callback_dumb_increment, + sizeof(struct per_session_data__dumb_increment), + 10, /* rx buf size must be >= permessage-deflate rx size */ + }, +}; + +LWS_VISIBLE int +init_protocol_example_standalone(struct lws_context *context, + struct lws_plugin_capability *c) +{ + if (c->api_magic != LWS_PLUGIN_API_MAGIC) { + lwsl_err("Plugin API %d, library API %d", LWS_PLUGIN_API_MAGIC, + c->api_magic); + return 1; + } + + c->protocols = protocols; + c->count_protocols = ARRAY_SIZE(protocols); + c->extensions = NULL; + c->count_extensions = 0; + + return 0; +} + +LWS_VISIBLE int +destroy_protocol_example_standalone(struct lws_context *context) +{ + return 0; +} -- 2.7.4