mirror of
https://github.com/warmcat/libwebsockets.git
synced 2025-03-09 00:00:04 +01:00
minimal: smp + foreign: libuv foreign loops
AG: various fixes and adaptation of test protocol to use ring lock to protect global wsi list against modifications from other threads while in use
This commit is contained in:
parent
4f0545cc54
commit
dbc3acd5eb
9 changed files with 792 additions and 0 deletions
|
@ -0,0 +1,44 @@
|
|||
project(lws-minimal-ws-server-threads-foreign-smp C)
|
||||
cmake_minimum_required(VERSION 2.8)
|
||||
find_package(libwebsockets CONFIG REQUIRED)
|
||||
list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
|
||||
include(CheckIncludeFile)
|
||||
include(CheckCSourceCompiles)
|
||||
include(LwsCheckRequirements)
|
||||
|
||||
set(SAMP lws-minimal-ws-server-threads-foreign-smp)
|
||||
set(SRCS minimal-ws-server.c)
|
||||
|
||||
set(requirements 1)
|
||||
require_pthreads(requirements)
|
||||
require_lws_config(LWS_ROLE_WS 1 requirements)
|
||||
require_lws_config(LWS_WITH_SERVER 1 requirements)
|
||||
require_lws_config(LWS_WITH_TLS 1 requirements)
|
||||
require_lws_config(LWS_WITH_LIBUV 1 requirements)
|
||||
|
||||
CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(LWS_WITH_LIBUV)\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" LWS_WITH_LIBUV)
|
||||
|
||||
if (NOT LWS_WITH_LIBUV)
|
||||
set(requirements 0)
|
||||
endif()
|
||||
|
||||
|
||||
if (requirements)
|
||||
add_executable(${SAMP} ${SRCS})
|
||||
|
||||
find_path(LIBUV_INCLUDE_DIRS NAMES uv.h)
|
||||
find_library(LIBUV_LIBRARIES NAMES uv)
|
||||
message("libuv include dir: ${LIBUV_INCLUDE_DIRS}")
|
||||
message("libuv libraries: ${LIBUV_LIBRARIES}")
|
||||
include_directories("${LIBUV_INCLUDE_DIRS}")
|
||||
set(extralibs ${extralibs} ${LIBUV_LIBRARIES})
|
||||
|
||||
message("Extra libs: ${extralibs}")
|
||||
|
||||
if (websockets_shared)
|
||||
target_link_libraries(${SAMP} websockets_shared ${extralibs} ${PTHREAD_LIB} ${LIBWEBSOCKETS_DEP_LIBS})
|
||||
add_dependencies(${SAMP} websockets_shared)
|
||||
else()
|
||||
target_link_libraries(${SAMP} websockets ${extralibs} ${PTHREAD_LIB} ${LIBWEBSOCKETS_DEP_LIBS})
|
||||
endif()
|
||||
endif()
|
|
@ -0,0 +1,39 @@
|
|||
# lws minimal ws server (threads) + SMP
|
||||
|
||||
This demonstrates both independent threads creating content as in the
|
||||
-threads example, multiple service threads as in the http-server-smp
|
||||
example (but with ws), and using the foreign libuv loop.
|
||||
|
||||
## build
|
||||
|
||||
You must first build libwebsockets itself with cmake `-DLWS_MAX_SMP=8`
|
||||
or some other number greater than one, as well as `-DLWS_WITH_LIBUV=1`
|
||||
|
||||
```
|
||||
$ cmake . && make
|
||||
```
|
||||
|
||||
Pthreads is required on your system.
|
||||
|
||||
## usage
|
||||
|
||||
```
|
||||
$ ./lws-minimal-ws-server-threads-smp
|
||||
[2019/01/28 06:59:17:4217] USER: LWS minimal ws server + threads + smp | visit http://localhost:7681
|
||||
[2019/01/28 06:59:17:4219] NOTICE: Service threads: 2
|
||||
[2019/01/28 06:59:17:4220] NOTICE: LWS_CALLBACK_EVENT_WAIT_CANCELLED in svc tid 0x7fec48af8700
|
||||
[2019/01/28 06:59:17:4220] NOTICE: LWS_CALLBACK_EVENT_WAIT_CANCELLED in svc tid 0x7fec48af8700
|
||||
...
|
||||
```
|
||||
|
||||
Visit http://localhost:7681 on multiple browser windows. You may need to open
|
||||
4 before the second service thread is used (check "svc tid" in the browser output).
|
||||
|
||||
Two lws service threads are started.
|
||||
|
||||
Two separate asynchronous threads generate strings and add them to a ringbuffer,
|
||||
signalling all lws service threads to send new entries to all the browser windows.
|
||||
|
||||
This demonstrates how to safely manage asynchronously generated content
|
||||
and hook it up to the lws service threads.
|
||||
|
|
@ -0,0 +1,182 @@
|
|||
/*
|
||||
* lws-minimal-ws-server
|
||||
*
|
||||
* Written in 2010-2020 by Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This file is made available under the Creative Commons CC0 1.0
|
||||
* Universal Public Domain Dedication.
|
||||
*
|
||||
* This demonstrates a minimal ws server that can cooperate with
|
||||
* other threads cleanly. Two other threads are started, which fill
|
||||
* a ringbuffer with strings at 10Hz.
|
||||
*
|
||||
* The actual work and thread spawning etc are done in the protocol
|
||||
* implementation in protocol_lws_minimal.c.
|
||||
*
|
||||
* To keep it simple, it serves stuff in the subdirectory "./mount-origin" of
|
||||
* the directory it was started in.
|
||||
* You can change that by changing mount.origin.
|
||||
*/
|
||||
|
||||
#include <libwebsockets.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#if defined(WIN32)
|
||||
#define HAVE_STRUCT_TIMESPEC
|
||||
#if defined(pid_t)
|
||||
#undef pid_t
|
||||
#endif
|
||||
#endif
|
||||
#include <pthread.h>
|
||||
#include <uv.h>
|
||||
|
||||
#define COUNT_THREADS 5
|
||||
|
||||
#define LWS_PLUGIN_STATIC
|
||||
#include "protocol_lws_minimal.c"
|
||||
|
||||
static struct lws_protocols protocols[] = {
|
||||
{ "http", lws_callback_http_dummy, 0, 0 },
|
||||
LWS_PLUGIN_PROTOCOL_MINIMAL,
|
||||
{ NULL, NULL, 0, 0 } /* terminator */
|
||||
};
|
||||
|
||||
static struct lws_context *context;
|
||||
static int interrupted;
|
||||
static uv_loop_t loop[COUNT_THREADS];
|
||||
|
||||
static const struct lws_http_mount mount = {
|
||||
/* .mount_next */ NULL, /* linked-list "next" */
|
||||
/* .mountpoint */ "/", /* mountpoint URL */
|
||||
/* .origin */ "./mount-origin", /* serve from dir */
|
||||
/* .def */ "index.html", /* default filename */
|
||||
/* .protocol */ NULL,
|
||||
/* .cgienv */ NULL,
|
||||
/* .extra_mimetypes */ NULL,
|
||||
/* .interpret */ NULL,
|
||||
/* .cgi_timeout */ 0,
|
||||
/* .cache_max_age */ 0,
|
||||
/* .auth_mask */ 0,
|
||||
/* .cache_reusable */ 0,
|
||||
/* .cache_revalidate */ 0,
|
||||
/* .cache_intermediaries */ 0,
|
||||
/* .origin_protocol */ LWSMPRO_FILE, /* files in a dir */
|
||||
/* .mountpoint_len */ 1, /* char count */
|
||||
/* .basic_auth_login_file */ NULL,
|
||||
};
|
||||
|
||||
/*
|
||||
* This demonstrates how to pass a pointer into a specific protocol handler
|
||||
* running on a specific vhost. In this case, it's our default vhost and
|
||||
* we pass the pvo named "config" with the value a const char * "myconfig".
|
||||
*
|
||||
* This is the preferred way to pass configuration into a specific vhost +
|
||||
* protocol instance.
|
||||
*/
|
||||
|
||||
static const struct lws_protocol_vhost_options pvo_ops = {
|
||||
NULL,
|
||||
NULL,
|
||||
"config", /* pvo name */
|
||||
(void *)"myconfig" /* pvo value */
|
||||
};
|
||||
|
||||
static const struct lws_protocol_vhost_options pvo = {
|
||||
NULL, /* "next" pvo linked-list */
|
||||
&pvo_ops, /* "child" pvo linked-list */
|
||||
"lws-minimal", /* protocol name we belong to on this vhost */
|
||||
"" /* ignored */
|
||||
};
|
||||
|
||||
void *thread_service(void *threadid)
|
||||
{
|
||||
while (lws_service_tsi(context, 0,
|
||||
(int)(lws_intptr_t)threadid) >= 0 &&
|
||||
!interrupted)
|
||||
lwsl_notice("%s\n", __func__);
|
||||
|
||||
pthread_exit(NULL);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void signal_cb(uv_signal_t *watcher, int signum)
|
||||
{
|
||||
int n;
|
||||
|
||||
if (interrupted)
|
||||
return;
|
||||
|
||||
lwsl_notice("signal_cb: signal %d caught\n", watcher->signum);
|
||||
interrupted = 1;
|
||||
uv_signal_stop(watcher);
|
||||
lws_context_destroy(context);
|
||||
for (n = 0; n < COUNT_THREADS; n++)
|
||||
uv_stop(&loop[n]);
|
||||
}
|
||||
|
||||
int main(int argc, const char **argv)
|
||||
{
|
||||
int n, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE;
|
||||
uv_signal_t *s, signal_outer[3 * COUNT_THREADS];
|
||||
pthread_t pthread_service[COUNT_THREADS];
|
||||
struct lws_context_creation_info info;
|
||||
void *foreign_loops[COUNT_THREADS];
|
||||
const char *p;
|
||||
void *retval;
|
||||
|
||||
if ((p = lws_cmdline_option(argc, argv, "-d")))
|
||||
logs = atoi(p);
|
||||
|
||||
lws_set_log_level(logs, NULL);
|
||||
lwsl_user("LWS minimal ws server + threads + smp | visit http://localhost:7681\n");
|
||||
|
||||
for (n = 0; n < COUNT_THREADS; n++) {
|
||||
int m;
|
||||
|
||||
uv_loop_init(&loop[n]);
|
||||
|
||||
for (m = 0; m < 3; m++) {
|
||||
s = &signal_outer[n * 3 + m];
|
||||
uv_signal_init(&loop[n], s);
|
||||
uv_signal_start(s, signal_cb, SIGINT);
|
||||
}
|
||||
|
||||
foreign_loops[n] = &loop[n];
|
||||
}
|
||||
|
||||
memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
|
||||
info.port = 7681;
|
||||
info.mounts = &mount;
|
||||
info.pcontext = &context;
|
||||
info.protocols = protocols;
|
||||
info.pvo = &pvo; /* per-vhost options */
|
||||
info.foreign_loops = foreign_loops;
|
||||
info.count_threads = COUNT_THREADS;
|
||||
info.options = LWS_SERVER_OPTION_LIBUV |
|
||||
LWS_SERVER_OPTION_HTTP_HEADERS_SECURITY_BEST_PRACTICES_ENFORCE;
|
||||
|
||||
context = lws_create_context(&info);
|
||||
if (!context) {
|
||||
lwsl_err("lws init failed\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
lwsl_notice(" Service threads: %d\n", lws_get_count_threads(context));
|
||||
|
||||
/* start all the service threads */
|
||||
|
||||
for (n = 0; n < lws_get_count_threads(context); n++)
|
||||
if (pthread_create(&pthread_service[n], NULL, thread_service,
|
||||
(void *)(lws_intptr_t)n))
|
||||
lwsl_err("Failed to start service thread\n");
|
||||
|
||||
/* wait for all the service threads to exit */
|
||||
|
||||
while ((--n) >= 0)
|
||||
pthread_join(pthread_service[n], &retval);
|
||||
|
||||
lws_context_destroy(context);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
var head = 0, tail = 0, ring = new Array();
|
||||
|
||||
function get_appropriate_ws_url(extra_url)
|
||||
{
|
||||
var pcol;
|
||||
var u = document.URL;
|
||||
|
||||
/*
|
||||
* We open the websocket encrypted if this page came on an
|
||||
* https:// url itself, otherwise unencrypted
|
||||
*/
|
||||
|
||||
if (u.substring(0, 5) === "https") {
|
||||
pcol = "wss://";
|
||||
u = u.substr(8);
|
||||
} else {
|
||||
pcol = "ws://";
|
||||
if (u.substring(0, 4) === "http")
|
||||
u = u.substr(7);
|
||||
}
|
||||
|
||||
u = u.split("/");
|
||||
|
||||
/* + "/xxx" bit is for IE10 workaround */
|
||||
|
||||
return pcol + u[0] + "/" + extra_url;
|
||||
}
|
||||
|
||||
function new_ws(urlpath, protocol)
|
||||
{
|
||||
return new WebSocket(urlpath, protocol);
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
|
||||
var ws = new_ws(get_appropriate_ws_url(""), "lws-minimal");
|
||||
try {
|
||||
ws.onopen = function() {
|
||||
document.getElementById("r").disabled = 0;
|
||||
};
|
||||
|
||||
ws.onmessage =function got_packet(msg) {
|
||||
var n, s = "";
|
||||
|
||||
ring[head] = msg.data + "\n";
|
||||
head = (head + 1) % 50;
|
||||
if (tail === head)
|
||||
tail = (tail + 1) % 50;
|
||||
|
||||
n = tail;
|
||||
do {
|
||||
s = s + ring[n];
|
||||
n = (n + 1) % 50;
|
||||
} while (n !== head);
|
||||
|
||||
document.getElementById("r").value = s;
|
||||
document.getElementById("r").scrollTop =
|
||||
document.getElementById("r").scrollHeight;
|
||||
};
|
||||
|
||||
ws.onclose = function(){
|
||||
document.getElementById("r").disabled = 1;
|
||||
};
|
||||
} catch(exception) {
|
||||
alert("<p>Error " + exception);
|
||||
}
|
||||
|
||||
}, false);
|
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
|
@ -0,0 +1,19 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta charset=utf-8 http-equiv="Content-Language" content="en"/>
|
||||
<script src="/example.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<img src="libwebsockets.org-logo.svg">
|
||||
<img src="strict-csp.svg"><br>
|
||||
|
||||
<b>Minimal ws server threads SMP example</b>.<br>
|
||||
Strings generated by server threads are sent to
|
||||
all browsers open on this page.<br>
|
||||
The textarea show the last 50 lines received.
|
||||
<br>
|
||||
<br>
|
||||
<textarea id=r readonly cols=80 rows=50></textarea><br>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="117.26mm" height="19.676mm" version="1.1" viewBox="0 0 117.26 19.677" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
|
||||
<metadata>
|
||||
<rdf:RDF>
|
||||
<cc:Work rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
|
||||
<dc:title/>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<path d="m0-2.6715e-4h117.26v19.677h-117.26z" fill="none"/>
|
||||
<g transform="matrix(.63895 0 0 .63895 2.5477 3.6562)">
|
||||
<g transform="matrix(.9517 0 0 .9517 3.2398 -93.904)">
|
||||
<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
|
||||
<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
|
||||
<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
|
||||
</g>
|
||||
<path d="m12.174 13.987a1.2015 1.2015 0 0 1-1.2024 1.2024 1.2015 1.2015 0 0 1-1.2006-1.2024 1.2015 1.2015 0 0 1 1.2006-1.2005 1.2015 1.2015 0 0 1 1.2024 1.2005" stroke-linecap="round" stroke-width=".98647"/>
|
||||
<path d="m8.2754 5.0474h2.468v5.6755h-2.468z"/>
|
||||
<path d="m16.25 13.965a1.2015 1.2015 0 0 1-1.2027 1.2005 1.2015 1.2015 0 0 1-1.2004-1.2005 1.2015 1.2015 0 0 1 1.2004-1.2025 1.2015 1.2015 0 0 1 1.2027 1.2025" stroke-linecap="round" stroke-width=".98647"/>
|
||||
<path d="m19.545 13.928a1.2015 1.2015 0 0 1-1.2025 1.2026 1.2015 1.2015 0 0 1-1.2003-1.2026 1.2015 1.2015 0 0 1 1.2003-1.2005 1.2015 1.2015 0 0 1 1.2025 1.2005" stroke-linecap="round" stroke-width=".98647"/>
|
||||
<path d="m23.75 13.902a1.2015 1.2015 0 0 1-1.2005 1.2024 1.2015 1.2015 0 0 1-1.2025-1.2024 1.2015 1.2015 0 0 1 1.2025-1.2005 1.2015 1.2015 0 0 1 1.2005 1.2005" stroke-linecap="round" stroke-width=".98647"/>
|
||||
<path d="m26.249 5.0292a1.2015 1.2015 0 0 1-1.2027 1.2004 1.2015 1.2015 0 0 1-1.2004-1.2004 1.2015 1.2015 0 0 1 1.2004-1.2026 1.2015 1.2015 0 0 1 1.2027 1.2026" stroke-linecap="round" stroke-width=".98647"/>
|
||||
<g transform="matrix(.9517 0 0 .9517 6.3252 -93.961)">
|
||||
<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
|
||||
<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
|
||||
<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
|
||||
</g>
|
||||
<g transform="matrix(.9517 0 0 .9517 9.3806 -93.988)">
|
||||
<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
|
||||
<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
|
||||
<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
|
||||
</g>
|
||||
<g transform="matrix(.9517 0 0 .9517 13.506 -94.006)">
|
||||
<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
|
||||
<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
|
||||
<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
|
||||
</g>
|
||||
<g transform="matrix(.9517 0 0 .9517 -.82062 -93.74)">
|
||||
<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
|
||||
<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
|
||||
<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
|
||||
</g>
|
||||
<path d="m10.703 5.0413a1.2015 1.2015 0 0 1-1.2006 1.2025 1.2015 1.2015 0 0 1-1.2025-1.2025 1.2015 1.2015 0 0 1 1.2025-1.2004 1.2015 1.2015 0 0 1 1.2006 1.2004" stroke-linecap="round" stroke-width=".98647"/>
|
||||
</g>
|
||||
<g transform="matrix(2.6825 0 0 2.6825 -289.72 -275.57)" dominant-baseline="auto" stroke-width=".29098" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal" aria-label="libwebsockets.org">
|
||||
<path d="m117.05 105.01v2.752h0.224v-2.752z"/>
|
||||
<path d="m117.95 105.71v2.057h0.223v-2.057zm-0.04-0.695v0.318h0.297v-0.318z"/>
|
||||
<path d="m118.8 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.594 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.15-0.855 0.625-0.855z"/>
|
||||
<path d="m120.79 105.71 0.555 2.057h0.314l0.479-1.858 0.482 1.858h0.314l0.551-2.057h-0.23l-0.482 1.879-0.482-1.879h-0.303l-0.486 1.879-0.478-1.879z"/>
|
||||
<path d="m125.54 106.8v-0.157c0-0.433-0.06-0.964-0.869-0.964-0.824 0-0.891 0.566-0.891 1.079 0 0.688 0.196 1.034 0.926 1.034 0.495 0 0.792-0.178 0.831-0.663h-0.224c-0.01 0.377-0.262 0.464-0.628 0.464-0.611 0-0.688-0.314-0.685-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.493 0 0.653 0.21 0.65 0.727z"/>
|
||||
<path d="m126.04 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.593 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.151-0.855 0.625-0.855z"/>
|
||||
<path d="m129.86 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.273 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
|
||||
<path d="m130.35 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.584 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
|
||||
<path d="m134.12 107.03c0 0.471-0.22 0.565-0.656 0.565-0.496 0-0.667-0.181-0.667-0.838 0-0.782 0.272-0.869 0.677-0.869 0.283 0 0.625 0.06 0.625 0.531h0.22c0.01-0.734-0.639-0.734-0.845-0.734-0.632 0-0.897 0.245-0.897 1.058 0 0.793 0.248 1.055 0.908 1.055 0.468 0 0.834-0.115 0.859-0.768z"/>
|
||||
<path d="m135.05 106.64v-1.624h-0.22v2.752h0.22v-1.072l1.076 1.072h0.321l-1.149-1.1 1.041-0.957h-0.318z"/>
|
||||
<path d="m138.48 106.8v-0.157c0-0.433-0.06-0.964-0.87-0.964-0.824 0-0.89 0.566-0.89 1.079 0 0.688 0.195 1.034 0.925 1.034 0.496 0 0.793-0.178 0.831-0.663h-0.223c-0.01 0.377-0.262 0.464-0.629 0.464-0.611 0-0.688-0.314-0.684-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.492 0 0.653 0.21 0.649 0.727z"/>
|
||||
<path d="m139.29 105.71h-0.457v0.206h0.457v1.348c0 0.335 0.07 0.531 0.664 0.531 0.09 0 0.139 0 0.181-0.01v-0.209c-0.06 0-0.136 0.01-0.251 0.01-0.374 0-0.374-0.129-0.374-0.381v-1.292h0.541v-0.206h-0.541v-0.488h-0.22z"/>
|
||||
<path d="m142.15 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.272 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
|
||||
<path d="m142.76 107.44v0.321h0.293v-0.321z"/>
|
||||
<path d="m143.54 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.583 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
|
||||
<path d="m145.81 105.71v2.057h0.22v-1.337c0-0.542 0.419-0.542 0.569-0.542h0.206v-0.213c-0.37 0-0.576 0-0.775 0.259l-0.01-0.231z"/>
|
||||
<path d="m149.11 105.62c-0.331 0.01-0.391 0.136-0.429 0.217-0.143-0.14-0.44-0.158-0.646-0.158-0.503 0-0.821 0.14-0.821 0.601 0 0.119 0.02 0.272 0.126 0.398-0.175 0.02-0.265 0.157-0.265 0.325 0 0.1 0.04 0.258 0.22 0.311-0.07 0.03-0.245 0.132-0.245 0.408 0 0.412 0.374 0.51 1.006 0.51 0.593 0 0.971-0.09 0.971-0.541 0-0.297-0.175-0.465-0.601-0.489l-0.922-0.06c-0.105 0-0.223-0.05-0.223-0.182 0-0.08 0.04-0.132 0.153-0.195 0.123 0.09 0.322 0.126 0.629 0.126 0.384 0 0.82-0.05 0.82-0.625 0-0.172-0.04-0.227-0.08-0.297 0.06-0.112 0.108-0.133 0.307-0.143zm-1.065 0.258c0.535 0 0.622 0.182 0.622 0.388 0 0.339-0.178 0.426-0.611 0.426-0.423 0-0.622-0.07-0.622-0.384 0-0.356 0.192-0.43 0.611-0.43zm0.206 1.512c0.36 0.02 0.556 0.06 0.556 0.308 0 0.216-0.147 0.331-0.751 0.331-0.674 0-0.8-0.1-0.8-0.345 0-0.304 0.318-0.336 0.328-0.336z"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 9.4 KiB |
|
@ -0,0 +1,53 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="24.78mm" height="24.78mm" version="1.1" viewBox="0 0 24.780247 24.780247" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<defs>
|
||||
<linearGradient id="linearGradient955" x1="66.618" x2="82.588" y1="81.176" y2="64.828" gradientTransform="matrix(.82538 0 0 .82538 -392 -92.399)" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#0aa70b" offset="0"/>
|
||||
<stop stop-color="#3bff39" offset="1"/>
|
||||
</linearGradient>
|
||||
<filter id="filter945" x="-.0516" y="-.0516" width="1.1032" height="1.1032" color-interpolation-filters="sRGB">
|
||||
<feGaussianBlur stdDeviation="0.58510713"/>
|
||||
</filter>
|
||||
</defs>
|
||||
<g transform="translate(342.15 43.638)">
|
||||
<circle transform="matrix(.82538 0 0 .82538 -392 -92.399)" cx="75.406" cy="74.089" r="13.607" filter="url(#filter945)" stroke="#000" stroke-linecap="round" stroke-width="1.565"/>
|
||||
<circle cx="-330.23" cy="-31.716" r="11.231" fill="url(#linearGradient955)" stroke="#000" stroke-linecap="round" stroke-width="1.2917"/>
|
||||
<g transform="matrix(.70929 0 0 .70929 -99.465 -12.686)" stroke-width=".51676px" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="Strict">
|
||||
<path d="m-330.78-33.775q0 0.73996-0.53676 1.154-0.53676 0.41407-1.4569 0.41407-0.99684 0-1.5336-0.25688v-0.62878q0.34506 0.14569 0.75147 0.23004 0.4064 0.08435 0.80514 0.08435 0.65177 0 0.9815-0.24538 0.32972-0.24921 0.32972-0.69012 0-0.29138-0.11885-0.47542-0.11502-0.18787-0.39107-0.34506-0.27221-0.15719-0.83198-0.35656-0.78213-0.27988-1.1195-0.66328-0.33356-0.3834-0.33356-1.0007 0-0.64794 0.48692-1.0313 0.48691-0.3834 1.2882-0.3834 0.83581 0 1.5374 0.30672l-0.2032 0.56743q-0.69395-0.29138-1.3496-0.29138-0.51759 0-0.80897 0.22237t-0.29138 0.61727q0 0.29138 0.10735 0.47925 0.10735 0.18403 0.36039 0.34123 0.25688 0.15336 0.78214 0.34122 0.88182 0.31439 1.2115 0.67478 0.33356 0.3604 0.33356 0.93549z"/>
|
||||
<path d="m-328.37-32.732q0.16869 0 0.32589-0.023 0.15719-0.02684 0.24921-0.05368v0.48692q-0.10352 0.04984-0.30672 0.08051-0.19937 0.03451-0.3604 0.03451-1.2192 0-1.2192-1.2844v-2.4998h-0.60194v-0.30672l0.60194-0.26455 0.26838-0.89716h0.36807v0.97384h1.2192v0.49458h-1.2192v2.4729q0 0.37957 0.18019 0.58277 0.1802 0.2032 0.49459 0.2032z"/>
|
||||
<path d="m-325.04-36.562q0.27989 0 0.50226 0.04601l-0.0882 0.59044q-0.26072-0.05751-0.46008-0.05751-0.50993 0-0.87415 0.41407-0.3604 0.41407-0.3604 1.0313v2.2544h-0.63644v-4.2021h0.52525l0.0729 0.7783h0.0307q0.23388-0.41024 0.5636-0.63261 0.32972-0.22237 0.72462-0.22237z"/>
|
||||
<path d="m-323.11-32.284h-0.63644v-4.2021h0.63644zm-0.69012-5.3408q0-0.21854 0.10735-0.31822 0.10735-0.10352 0.26838-0.10352 0.15336 0 0.26455 0.10352 0.11118 0.10352 0.11118 0.31822 0 0.2147-0.11118 0.32206-0.11119 0.10352-0.26455 0.10352-0.16103 0-0.26838-0.10352-0.10735-0.10735-0.10735-0.32206z"/>
|
||||
<path d="m-320.07-32.207q-0.91249 0-1.4147-0.55976-0.49842-0.5636-0.49842-1.5911 0-1.0543 0.50609-1.6294 0.50992-0.5751 1.4492-0.5751 0.30288 0 0.60577 0.06518 0.30288 0.06518 0.47541 0.15336l-0.19553 0.54059q-0.21087-0.08435-0.46008-0.13802-0.24921-0.05751-0.44091-0.05751-1.2806 0-1.2806 1.6333 0 0.77447 0.31055 1.1885 0.31439 0.41407 0.92783 0.41407 0.52526 0 1.0774-0.22621v0.5636q-0.42174 0.21854-1.062 0.21854z"/>
|
||||
<path d="m-316.65-32.732q0.16869 0 0.32589-0.023 0.15719-0.02684 0.24921-0.05368v0.48692q-0.10352 0.04984-0.30672 0.08051-0.19937 0.03451-0.3604 0.03451-1.2192 0-1.2192-1.2844v-2.4998h-0.60194v-0.30672l0.60194-0.26455 0.26838-0.89716h0.36806v0.97384h1.2192v0.49458h-1.2192v2.4729q0 0.37957 0.1802 0.58277 0.1802 0.2032 0.49459 0.2032z"/>
|
||||
</g>
|
||||
<g fill="#fff">
|
||||
<g transform="matrix(.70929 0 0 .70929 -99.465 -12.686)" stroke-width=".3317px" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="Content">
|
||||
<path d="m-332.67-30.173q-0.5931 0-0.93764 0.39622-0.34208 0.39376-0.34208 1.0804 0 0.70631 0.32977 1.0927 0.33224 0.38392 0.94503 0.38392 0.37653 0 0.85889-0.13536v0.36669q-0.37407 0.14028-0.92288 0.14028-0.7949 0-1.228-0.48236-0.43067-0.48236-0.43067-1.3708 0-0.55619 0.20672-0.97456 0.20919-0.41837 0.60049-0.64478 0.39376-0.22641 0.92533-0.22641 0.56603 0 0.98933 0.20672l-0.1772 0.35931q-0.40852-0.19196-0.81705-0.19196z"/>
|
||||
<path d="m-328.77-28.248q0 0.65955-0.33224 1.0312-0.33223 0.36915-0.91795 0.36915-0.36177 0-0.64233-0.16981-0.28055-0.16981-0.43313-0.48728-0.15259-0.31747-0.15259-0.74322 0-0.65955 0.32978-1.0262 0.32977-0.36915 0.91549-0.36915 0.56603 0 0.89827 0.37653 0.3347 0.37653 0.3347 1.0189zm-2.0549 0q0 0.51681 0.20672 0.78752 0.20673 0.27071 0.60787 0.27071t0.60787-0.26825q0.20918-0.27071 0.20918-0.78998 0-0.51435-0.20918-0.78014-0.20673-0.26825-0.61279-0.26825-0.40115 0-0.60541 0.26333-0.20426 0.26333-0.20426 0.78506z"/>
|
||||
<path d="m-326.21-26.897v-1.7449q0-0.32978-0.15012-0.4922-0.15012-0.16243-0.47005-0.16243-0.42329 0-0.62017 0.22887-0.19688 0.22887-0.19688 0.75553v1.4151h-0.40853v-2.6973h0.33223l0.0664 0.36915h0.0197q0.12551-0.19934 0.35192-0.30762 0.22642-0.11075 0.50451-0.11075 0.48728 0 0.73338 0.23626 0.2461 0.2338 0.2461 0.75061v1.7596z"/>
|
||||
<path d="m-324.09-27.185q0.10828 0 0.20918-0.01477 0.1009-0.01723 0.15997-0.03445v0.31255q-0.0665 0.03199-0.19688 0.05168-0.12797 0.02215-0.23134 0.02215-0.7826 0-0.7826-0.82444v-1.6046h-0.38637v-0.19688l0.38637-0.16981 0.17227-0.57588h0.23626v0.6251h0.7826v0.31747h-0.7826v1.5873q0 0.24364 0.11567 0.37407 0.11566 0.13043 0.31747 0.13043z"/>
|
||||
<path d="m-322.04-26.848q-0.59802 0-0.94502-0.36423-0.34454-0.36423-0.34454-1.0115 0-0.65217 0.31993-1.0361 0.32239-0.38392 0.86381-0.38392 0.50697 0 0.80229 0.3347 0.29532 0.33224 0.29532 0.87858v0.25841h-1.8581q0.0123 0.47497 0.23872 0.72107 0.22887 0.2461 0.64232 0.2461 0.4356 0 0.86135-0.18212v0.36423q-0.21657 0.09352-0.41099 0.13289-0.19195 0.04184-0.46513 0.04184zm-0.11074-2.4536q-0.32485 0-0.51927 0.21165-0.19196 0.21165-0.22642 0.58572h1.4102q0-0.38638-0.17227-0.59064-0.17227-0.20672-0.4922-0.20672z"/>
|
||||
<path d="m-318.51-26.897v-1.7449q0-0.32978-0.15012-0.4922-0.15013-0.16243-0.47006-0.16243-0.42329 0-0.62017 0.22887-0.19688 0.22887-0.19688 0.75553v1.4151h-0.40853v-2.6973h0.33224l0.0664 0.36915h0.0197q0.12552-0.19934 0.35193-0.30762 0.22641-0.11075 0.5045-0.11075 0.48728 0 0.73338 0.23626 0.2461 0.2338 0.2461 0.75061v1.7596z"/>
|
||||
<path d="m-316.4-27.185q0.10829 0 0.20919-0.01477 0.1009-0.01723 0.15996-0.03445v0.31255q-0.0664 0.03199-0.19688 0.05168-0.12797 0.02215-0.23133 0.02215-0.7826 0-0.7826-0.82444v-1.6046h-0.38638v-0.19688l0.38638-0.16981 0.17227-0.57588h0.23625v0.6251h0.7826v0.31747h-0.7826v1.5873q0 0.24364 0.11567 0.37407 0.11567 0.13043 0.31747 0.13043z"/>
|
||||
</g>
|
||||
<g transform="matrix(.70929 0 0 .70929 -99.465 -12.686)" stroke-width=".32428px" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="Security">
|
||||
<path d="m-332.03-22.859q0 0.46434-0.33683 0.72417-0.33682 0.25984-0.91423 0.25984-0.62553 0-0.96236-0.1612v-0.39456q0.21653 0.09142 0.47155 0.14435 0.25503 0.05293 0.50524 0.05293 0.409 0 0.61591-0.15398 0.20691-0.15638 0.20691-0.43306 0-0.18285-0.0746-0.29833-0.0722-0.11789-0.2454-0.21653-0.17082-0.09864-0.52208-0.22375-0.4908-0.17563-0.70252-0.41622-0.20931-0.24059-0.20931-0.62794 0-0.4066 0.30555-0.64718t0.80838-0.24059q0.52448 0 0.96476 0.19247l-0.12751 0.35607q-0.43547-0.18285-0.84687-0.18285-0.3248 0-0.50765 0.13954-0.18284 0.13954-0.18284 0.38735 0 0.18285 0.0674 0.30074 0.0674 0.11548 0.22615 0.21412 0.1612 0.09624 0.4908 0.21412 0.55336 0.19728 0.76027 0.42344 0.20931 0.22615 0.20931 0.58704z"/>
|
||||
<path d="m-330.26-21.875q-0.58463 0-0.92386-0.35607-0.33683-0.35607-0.33683-0.98882 0-0.63756 0.31277-1.0129 0.31517-0.37532 0.84446-0.37532 0.49562 0 0.78432 0.3272 0.28871 0.3248 0.28871 0.8589v0.25262h-1.8164q0.012 0.46434 0.23338 0.70492 0.22374 0.24059 0.62793 0.24059 0.42584 0 0.84206-0.17804v0.35607q-0.21171 0.09142-0.40178 0.12992-0.18766 0.0409-0.45471 0.0409zm-0.10827-2.3987q-0.31757 0-0.50764 0.20691-0.18766 0.20691-0.22134 0.5726h1.3786q0-0.37772-0.16841-0.57741-0.16841-0.2021-0.48118-0.2021z"/>
|
||||
<path d="m-327.56-21.875q-0.5726 0-0.88777-0.35126-0.31277-0.35366-0.31277-0.99844 0-0.66162 0.31758-1.0225 0.31998-0.36088 0.90942-0.36088 0.19007 0 0.38013 0.0409 0.19007 0.0409 0.29833 0.09624l-0.1227 0.33923q-0.13232-0.05293-0.2887-0.08661-0.15639-0.03609-0.27668-0.03609-0.80357 0-0.80357 1.0249 0 0.48599 0.19488 0.74582 0.19728 0.25984 0.58223 0.25984 0.3296 0 0.67605-0.14195v0.35366q-0.26465 0.13714-0.66643 0.13714z"/>
|
||||
<path d="m-325.89-24.56v1.7106q0 0.32239 0.14676 0.48118 0.14675 0.15879 0.45952 0.15879 0.41381 0 0.60388-0.22615 0.19247-0.22615 0.19247-0.73861v-1.3858h0.39938v2.6369h-0.32961l-0.0577-0.35367h-0.0217q-0.1227 0.19488-0.34163 0.29833-0.21653 0.10345-0.49561 0.10345-0.48118 0-0.72177-0.22856-0.23818-0.22856-0.23818-0.73139v-1.725z"/>
|
||||
<path d="m-322.04-24.608q0.17563 0 0.31517 0.02887l-0.0553 0.37051q-0.1636-0.03609-0.2887-0.03609-0.31999 0-0.54855 0.25984-0.22615 0.25984-0.22615 0.64718v1.4147h-0.39938v-2.6369h0.32961l0.0457 0.4884h0.0192q0.14676-0.25743 0.35366-0.39697 0.20691-0.13954 0.45472-0.13954z"/>
|
||||
<path d="m-320.83-21.923h-0.39938v-2.6369h0.39938zm-0.43306-3.3514q0-0.13714 0.0674-0.19969 0.0674-0.06496 0.16841-0.06496 0.0962 0 0.16601 0.06496 0.0698 0.06496 0.0698 0.19969 0 0.13473-0.0698 0.2021-0.0698 0.06496-0.16601 0.06496-0.10105 0-0.16841-0.06496-0.0674-0.06736-0.0674-0.2021z"/>
|
||||
<path d="m-319.13-22.205q0.10586 0 0.2045-0.01443 0.0986-0.01684 0.15638-0.03368v0.30555q-0.065 0.03128-0.19247 0.05052-0.1251 0.02165-0.22615 0.02165-0.76507 0-0.76507-0.80597v-1.5686h-0.37773v-0.19247l0.37773-0.16601 0.16841-0.56298h0.23096v0.6111h0.76508v0.31036h-0.76508v1.5518q0 0.23818 0.11308 0.3657t0.31036 0.12751z"/>
|
||||
<path d="m-318.66-24.56h0.42825l0.57742 1.5037q0.19006 0.51486 0.23577 0.74342h0.0192q0.0313-0.1227 0.12992-0.41862 0.10105-0.29833 0.6544-1.8285h0.42825l-1.1332 3.0025q-0.16841 0.44509-0.39456 0.63034-0.22375 0.18766-0.55095 0.18766-0.18285 0-0.36088-0.0409v-0.31998q0.13232 0.02887 0.29592 0.02887 0.41141 0 0.58704-0.46193l0.14676-0.37532z"/>
|
||||
</g>
|
||||
<g transform="matrix(.70929 0 0 .70929 -99.465 -12.686)" stroke-width=".32334px" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="Policy">
|
||||
<path d="m-329.37-19.254q0 0.53256-0.36464 0.82043-0.36224 0.28547-1.0387 0.28547h-0.41261v1.3794h-0.40782v-3.5072h0.90919q1.3146 0 1.3146 1.0219zm-1.816 0.75566h0.36703q0.54215 0 0.78445-0.17512 0.24229-0.17512 0.24229-0.56135 0-0.34784-0.2279-0.51817t-0.71008-0.17032h-0.45579z"/>
|
||||
<path d="m-326.43-18.086q0 0.64291-0.32386 1.0051-0.32385 0.35984-0.89479 0.35984-0.35264 0-0.62612-0.16552t-0.42221-0.47498q-0.14873-0.30946-0.14873-0.72447 0-0.64291 0.32145-1.0003 0.32146-0.35984 0.8924-0.35984 0.55175 0 0.8756 0.36703 0.32626 0.36704 0.32626 0.99315zm-2.0031 0q0 0.50377 0.20151 0.76765t0.59253 0.26388q0.39103 0 0.59254-0.26148 0.2039-0.26388 0.2039-0.77005 0-0.50137-0.2039-0.76046-0.20151-0.26148-0.59733-0.26148-0.39103 0-0.59014 0.25668-0.19911 0.25668-0.19911 0.76525z"/>
|
||||
<path d="m-325.33-16.769h-0.39822v-3.7327h0.39822z"/>
|
||||
<path d="m-324.09-16.769h-0.39822v-2.6292h0.39822zm-0.43181-3.3417q0-0.13674 0.0672-0.19911 0.0672-0.06477 0.16793-0.06477 0.0959 0 0.16552 0.06477 0.0696 0.06477 0.0696 0.19911t-0.0696 0.20151q-0.0696 0.06477-0.16552 0.06477-0.10076 0-0.16793-0.06477-0.0672-0.06717-0.0672-0.20151z"/>
|
||||
<path d="m-322.19-16.721q-0.57094 0-0.8852-0.35024-0.31186-0.35264-0.31186-0.99555 0-0.6597 0.31666-1.0195 0.31906-0.35984 0.90679-0.35984 0.18951 0 0.37903 0.04078 0.18951 0.04078 0.29746 0.09596l-0.12234 0.33825q-0.13194-0.05278-0.28787-0.08636-0.15593-0.03598-0.27588-0.03598-0.80123 0-0.80123 1.0219 0 0.48458 0.19431 0.74366 0.19671 0.25908 0.58054 0.25908 0.32865 0 0.67409-0.14154v0.35264q-0.26388 0.13674-0.6645 0.13674z"/>
|
||||
<path d="m-321.31-19.398h0.427l0.57574 1.4993q0.18952 0.51337 0.2351 0.74127h0.0192q0.0312-0.12234 0.12954-0.41741 0.10076-0.29747 0.65251-1.8232h0.427l-1.1299 2.9938q-0.16792 0.4438-0.39342 0.62852-0.2231 0.18712-0.54935 0.18712-0.18232 0-0.35984-0.04078v-0.31906q0.13194 0.02879 0.29507 0.02879 0.41021 0 0.58533-0.46059l0.14634-0.37423z"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 12 KiB |
|
@ -0,0 +1,321 @@
|
|||
/*
|
||||
* ws protocol handler plugin for "lws-minimal" demonstrating multithread
|
||||
*
|
||||
* Written in 2010-2019 by Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This file is made available under the Creative Commons CC0 1.0
|
||||
* Universal Public Domain Dedication.
|
||||
*/
|
||||
|
||||
#if !defined (LWS_PLUGIN_STATIC)
|
||||
#define LWS_DLL
|
||||
#define LWS_INTERNAL
|
||||
#include <libwebsockets.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
/* one of these created for each message in the ringbuffer */
|
||||
|
||||
struct msg {
|
||||
void *payload; /* is malloc'd */
|
||||
size_t len;
|
||||
};
|
||||
|
||||
/*
|
||||
* One of these is created for each client connecting to us.
|
||||
*
|
||||
* It is ONLY read or written from the lws service thread context.
|
||||
*/
|
||||
|
||||
struct per_session_data__minimal {
|
||||
struct per_session_data__minimal *pss_list;
|
||||
struct lws *wsi;
|
||||
uint32_t tail;
|
||||
};
|
||||
|
||||
/*
|
||||
* One of these is created for each vhost our protocol is used with, that
|
||||
* means it is a shared resource between the SMP threads and must be locked.
|
||||
*/
|
||||
|
||||
struct per_vhost_data__minimal {
|
||||
struct lws_context *context;
|
||||
struct lws_vhost *vhost;
|
||||
const struct lws_protocols *protocol;
|
||||
|
||||
struct per_session_data__minimal *pss_list; /* linked-list of live pss*/
|
||||
pthread_t pthread_spam[2];
|
||||
|
||||
pthread_mutex_t lock_ring; /* serialize access to the ring buffer */
|
||||
struct lws_ring *ring; /* {lock_ring} ringbuffer holding unsent content */
|
||||
|
||||
const char *config;
|
||||
char finished;
|
||||
};
|
||||
|
||||
#if defined(WIN32)
|
||||
static void usleep(unsigned long l) { Sleep(l / 1000); }
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This runs under both lws service and "spam threads" contexts.
|
||||
* Access is serialized by vhd->lock_ring.
|
||||
*/
|
||||
|
||||
static void
|
||||
__minimal_destroy_message(void *_msg)
|
||||
{
|
||||
struct msg *msg = _msg;
|
||||
|
||||
free(msg->payload);
|
||||
msg->payload = NULL;
|
||||
msg->len = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This runs under the "spam thread" thread context only.
|
||||
*
|
||||
* We spawn two threads that generate messages with this.
|
||||
*
|
||||
*/
|
||||
|
||||
static void *
|
||||
thread_spam(void *d)
|
||||
{
|
||||
struct per_vhost_data__minimal *vhd =
|
||||
(struct per_vhost_data__minimal *)d;
|
||||
struct msg amsg;
|
||||
int len = 128, index = 1, n, whoami = 0;
|
||||
|
||||
for (n = 0; n < (int)LWS_ARRAY_SIZE(vhd->pthread_spam); n++)
|
||||
if (pthread_equal(pthread_self(), vhd->pthread_spam[n]))
|
||||
whoami = n + 1;
|
||||
|
||||
do {
|
||||
pthread_mutex_lock(&vhd->lock_ring); /* --------- ring lock { */
|
||||
|
||||
/* don't generate output if nobody connected */
|
||||
if (!vhd->pss_list)
|
||||
goto wait_unlock;
|
||||
|
||||
/* only create if space in ringbuffer */
|
||||
n = (int)lws_ring_get_count_free_elements(vhd->ring);
|
||||
if (!n) {
|
||||
// lwsl_user("dropping!\n");
|
||||
goto wait_unlock;
|
||||
}
|
||||
|
||||
amsg.payload = malloc(LWS_PRE + len);
|
||||
if (!amsg.payload) {
|
||||
lwsl_user("OOM: dropping\n");
|
||||
goto wait_unlock;
|
||||
}
|
||||
n = lws_snprintf((char *)amsg.payload + LWS_PRE, len,
|
||||
"%s: spam tid: %d, msg: %d", vhd->config,
|
||||
whoami, index++);
|
||||
amsg.len = n;
|
||||
n = (int)lws_ring_insert(vhd->ring, &amsg, 1);
|
||||
if (n != 1) {
|
||||
__minimal_destroy_message(&amsg);
|
||||
// lwsl_user("dropping!\n");
|
||||
} else
|
||||
/*
|
||||
* This will cause a LWS_CALLBACK_EVENT_WAIT_CANCELLED
|
||||
* in the lws service thread context.
|
||||
*/
|
||||
lws_cancel_service(vhd->context);
|
||||
|
||||
wait_unlock:
|
||||
pthread_mutex_unlock(&vhd->lock_ring); /* } ring lock ------- */
|
||||
|
||||
usleep(100000);
|
||||
|
||||
} while (!vhd->finished);
|
||||
|
||||
lwsl_notice("thread_spam %d exiting\n", whoami);
|
||||
|
||||
pthread_exit(NULL);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* this runs under the lws service thread context only */
|
||||
|
||||
static int
|
||||
callback_minimal(struct lws *wsi, enum lws_callback_reasons reason,
|
||||
void *user, void *in, size_t len)
|
||||
{
|
||||
struct per_session_data__minimal *pss =
|
||||
(struct per_session_data__minimal *)user;
|
||||
struct per_vhost_data__minimal *vhd =
|
||||
(struct per_vhost_data__minimal *)
|
||||
lws_protocol_vh_priv_get(lws_get_vhost(wsi),
|
||||
lws_get_protocol(wsi));
|
||||
const struct lws_protocol_vhost_options *pvo;
|
||||
const struct msg *pmsg;
|
||||
char temp[LWS_PRE + 256];
|
||||
void *retval;
|
||||
int n, m, r = 0;
|
||||
|
||||
switch (reason) {
|
||||
case LWS_CALLBACK_PROTOCOL_INIT:
|
||||
/* create our per-vhost struct */
|
||||
vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),
|
||||
lws_get_protocol(wsi),
|
||||
sizeof(struct per_vhost_data__minimal));
|
||||
if (!vhd)
|
||||
return 1;
|
||||
|
||||
pthread_mutex_init(&vhd->lock_ring, NULL);
|
||||
|
||||
/* recover the pointer to the globals struct */
|
||||
pvo = lws_pvo_search(
|
||||
(const struct lws_protocol_vhost_options *)in,
|
||||
"config");
|
||||
if (!pvo || !pvo->value) {
|
||||
lwsl_err("%s: Can't find \"config\" pvo\n", __func__);
|
||||
return 1;
|
||||
}
|
||||
vhd->config = pvo->value;
|
||||
|
||||
vhd->context = lws_get_context(wsi);
|
||||
vhd->protocol = lws_get_protocol(wsi);
|
||||
vhd->vhost = lws_get_vhost(wsi);
|
||||
|
||||
vhd->ring = lws_ring_create(sizeof(struct msg), 8,
|
||||
__minimal_destroy_message);
|
||||
if (!vhd->ring) {
|
||||
lwsl_err("%s: failed to create ring\n", __func__);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* start the content-creating threads */
|
||||
|
||||
for (n = 0; n < (int)LWS_ARRAY_SIZE(vhd->pthread_spam); n++)
|
||||
if (pthread_create(&vhd->pthread_spam[n], NULL,
|
||||
thread_spam, vhd)) {
|
||||
lwsl_err("thread creation failed\n");
|
||||
r = 1;
|
||||
goto init_fail;
|
||||
}
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_PROTOCOL_DESTROY:
|
||||
init_fail:
|
||||
vhd->finished = 1;
|
||||
for (n = 0; n < (int)LWS_ARRAY_SIZE(vhd->pthread_spam); n++)
|
||||
pthread_join(vhd->pthread_spam[n], &retval);
|
||||
|
||||
if (vhd->ring)
|
||||
lws_ring_destroy(vhd->ring);
|
||||
|
||||
pthread_mutex_destroy(&vhd->lock_ring);
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_ESTABLISHED:
|
||||
/* add ourselves to the list of live pss held in the vhd */
|
||||
pthread_mutex_lock(&vhd->lock_ring);
|
||||
lws_ll_fwd_insert(pss, pss_list, vhd->pss_list);
|
||||
pss->tail = lws_ring_get_oldest_tail(vhd->ring);
|
||||
pss->wsi = wsi;
|
||||
pthread_mutex_unlock(&vhd->lock_ring);
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_CLOSED:
|
||||
/* doesn't reference ring */
|
||||
pthread_mutex_lock(&vhd->lock_ring);
|
||||
/* remove our closing pss from the list of live pss */
|
||||
lws_ll_fwd_remove(struct per_session_data__minimal, pss_list,
|
||||
pss, vhd->pss_list);
|
||||
pthread_mutex_unlock(&vhd->lock_ring);
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_SERVER_WRITEABLE:
|
||||
pthread_mutex_lock(&vhd->lock_ring); /* --------- ring lock { */
|
||||
|
||||
pmsg = lws_ring_get_element(vhd->ring, &pss->tail);
|
||||
if (!pmsg) {
|
||||
pthread_mutex_unlock(&vhd->lock_ring); /* } ring lock ------- */
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
assert(pmsg->payload);
|
||||
|
||||
n = lws_snprintf(temp + LWS_PRE, sizeof(temp) - LWS_PRE,
|
||||
"svc, %s",
|
||||
(char *)pmsg->payload + LWS_PRE);
|
||||
|
||||
/* notice we allowed for LWS_PRE in the payload already */
|
||||
m = lws_write(wsi, (unsigned char *)temp + LWS_PRE, n,
|
||||
LWS_WRITE_TEXT);
|
||||
if (m < n) {
|
||||
pthread_mutex_unlock(&vhd->lock_ring); /* } ring lock ------- */
|
||||
|
||||
lwsl_err("ERROR %d writing to ws socket\n", m);
|
||||
return -1;
|
||||
}
|
||||
|
||||
lws_ring_consume_and_update_oldest_tail(
|
||||
vhd->ring, /* lws_ring object */
|
||||
struct per_session_data__minimal, /* type of objects with tails */
|
||||
&pss->tail, /* tail of guy doing the consuming */
|
||||
1, /* number of payload objects being consumed */
|
||||
vhd->pss_list, /* head of list of objects with tails */
|
||||
tail, /* member name of tail in objects with tails */
|
||||
pss_list /* member name of next object in objects with tails */
|
||||
);
|
||||
|
||||
/* more to do? */
|
||||
if (lws_ring_get_element(vhd->ring, &pss->tail))
|
||||
/* come back as soon as we can write more */
|
||||
lws_callback_on_writable(pss->wsi);
|
||||
|
||||
pthread_mutex_unlock(&vhd->lock_ring); /* } ring lock ------- */
|
||||
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_RECEIVE:
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_EVENT_WAIT_CANCELLED:
|
||||
// lwsl_notice("EVENT_WAIT_CANCELLED tsi %d\n", lws_wsi_tsi(wsi));
|
||||
if (!vhd)
|
||||
break;
|
||||
/*
|
||||
* When the "spam" threads add a message to the ringbuffer,
|
||||
* they create this event in the lws service thread context
|
||||
* using lws_cancel_service().
|
||||
*
|
||||
* We respond by scheduling a writable callback for all
|
||||
* connected clients.
|
||||
*/
|
||||
|
||||
pthread_mutex_lock(&vhd->lock_ring); /* --------- ring lock { */
|
||||
|
||||
lws_start_foreach_llp(struct per_session_data__minimal **,
|
||||
ppss, vhd->pss_list) {
|
||||
if (lws_wsi_tsi((*ppss)->wsi) == lws_wsi_tsi(wsi))
|
||||
lws_callback_on_writable((*ppss)->wsi);
|
||||
} lws_end_foreach_llp(ppss, pss_list);
|
||||
|
||||
pthread_mutex_unlock(&vhd->lock_ring); /* } ring lock ------- */
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
#define LWS_PLUGIN_PROTOCOL_MINIMAL \
|
||||
{ \
|
||||
"lws-minimal", \
|
||||
callback_minimal, \
|
||||
sizeof(struct per_session_data__minimal), \
|
||||
128, \
|
||||
0, NULL, 0 \
|
||||
}
|
Loading…
Add table
Reference in a new issue