plugin standalone example for oot build
authorAndy Green <andy@warmcat.com>
Sun, 1 May 2016 23:43:04 +0000 (07:43 +0800)
committerAndy Green <andy@warmcat.com>
Sun, 1 May 2016 23:49:29 +0000 (07:49 +0800)
Signed-off-by: Andy Green <andy@warmcat.com>
README.build.md
plugin-standalone/CMakeLists.txt [new file with mode: 0644]
plugin-standalone/protocol_example_standalone.c [new file with mode: 0644]

index 5ddd4ec..0b8a90b 100644 (file)
@@ -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 (file)
index 0000000..c5e92a0
--- /dev/null
@@ -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 (file)
index 0000000..003afc5
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * ws protocol handler plugin for "dumb increment"
+ *
+ * Copyright (C) 2010-2016 Andy Green <andy@warmcat.com>
+ *
+ * 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 <string.h>
+
+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;
+}