2013-01-20 11:28:06 +08:00
|
|
|
Daemonization
|
|
|
|
-------------
|
|
|
|
|
|
|
|
There's a helper api lws_daemonize built by default that does everything you
|
|
|
|
need to daemonize well, including creating a lock file. If you're making
|
|
|
|
what's basically a daemon, just call this early in your init to fork to a
|
|
|
|
headless background process and exit the starting process.
|
|
|
|
|
|
|
|
Notice stdout, stderr, stdin are all redirected to /dev/null to enforce your
|
|
|
|
daemon is headless, so you'll need to sort out alternative logging, by, eg,
|
|
|
|
syslog.
|
|
|
|
|
|
|
|
|
|
|
|
Maximum number of connections
|
|
|
|
-----------------------------
|
|
|
|
|
|
|
|
The maximum number of connections the library can deal with is decided when
|
|
|
|
it starts by querying the OS to find out how many file descriptors it is
|
|
|
|
allowed to open (1024 on Fedora for example). It then allocates arrays that
|
|
|
|
allow up to that many connections, minus whatever other file descriptors are
|
|
|
|
in use by the user code.
|
|
|
|
|
|
|
|
If you want to restrict that allocation, or increase it, you can use ulimit or
|
|
|
|
similar to change the avaiable number of file descriptors, and when restarted
|
|
|
|
libwebsockets will adapt accordingly.
|
|
|
|
|
|
|
|
|
2013-01-29 17:57:39 +08:00
|
|
|
Libwebsockets is singlethreaded
|
|
|
|
-------------------------------
|
|
|
|
|
|
|
|
Directly performing websocket actions from other threads is not allowed.
|
|
|
|
Aside from the internal data being inconsistent in forked() processes,
|
|
|
|
the scope of a wsi (struct websocket) can end at any time during service
|
|
|
|
with the socket closing and the wsi freed.
|
|
|
|
|
|
|
|
Websocket write activities should only take place in the
|
|
|
|
"LWS_CALLBACK_SERVER_WRITEABLE" callback as described below.
|
|
|
|
|
|
|
|
Only live connections appear in the user callbacks, so this removes any
|
|
|
|
possibility of trying to used closed and freed wsis.
|
|
|
|
|
|
|
|
If you need to service other socket or file descriptors as well as the
|
|
|
|
websocket ones, you can combine them together with the websocket ones
|
|
|
|
in one poll loop, see "External Polling Loop support" below, and
|
|
|
|
still do it all in one thread / process context.
|
|
|
|
|
|
|
|
|
|
|
|
Only send data when socket writeable
|
|
|
|
------------------------------------
|
|
|
|
|
|
|
|
You should only send data on a websocket connection from the user callback
|
|
|
|
"LWS_CALLBACK_SERVER_WRITEABLE" (or "LWS_CALLBACK_CLIENT_WRITEABLE" for
|
|
|
|
clients).
|
|
|
|
|
|
|
|
If you want to send something, do not just send it but request a callback
|
|
|
|
when the socket is writeable using
|
|
|
|
|
|
|
|
- libwebsocket_callback_on_writable(context, wsi) for a specific wsi, or
|
|
|
|
- libwebsocket_callback_on_writable_all_protocol(protocol) for all connections
|
|
|
|
using that protocol to get a callback when next writeable.
|
|
|
|
|
|
|
|
Usually you will get called back immediately next time around the service
|
|
|
|
loop, but if your peer is slow or temporarily inactive the callback will be
|
|
|
|
delayed accordingly. Generating what to write and sending it should be done
|
|
|
|
in the ...WRITEABLE callback.
|
|
|
|
|
|
|
|
See the test server code for an example of how to do this.
|
2013-01-25 17:34:15 +08:00
|
|
|
|
|
|
|
|
2013-01-20 11:28:06 +08:00
|
|
|
Fragmented messages
|
|
|
|
-------------------
|
|
|
|
|
|
|
|
To support fragmented messages you need to check for the final
|
|
|
|
frame of a message with libwebsocket_is_final_fragment. This
|
|
|
|
check can be combined with libwebsockets_remaining_packet_payload
|
|
|
|
to gather the whole contents of a message, eg:
|
|
|
|
|
|
|
|
case LWS_CALLBACK_RECEIVE:
|
|
|
|
{
|
|
|
|
Client * const client = (Client *)user;
|
|
|
|
const size_t remaining = libwebsockets_remaining_packet_payload(wsi);
|
|
|
|
|
|
|
|
if (!remaining && libwebsocket_is_final_fragment(wsi)) {
|
|
|
|
if (client->HasFragments()) {
|
|
|
|
client->AppendMessageFragment(in, len, 0);
|
|
|
|
in = (void *)client->GetMessage();
|
|
|
|
len = client->GetMessageLength();
|
|
|
|
}
|
|
|
|
|
|
|
|
client->ProcessMessage((char *)in, len, wsi);
|
|
|
|
client->ResetMessage();
|
|
|
|
} else
|
|
|
|
client->AppendMessageFragment(in, len, remaining);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
The test app llibwebsockets-test-fraggle sources also show how to
|
|
|
|
deal with fragmented messages.
|
|
|
|
|
2013-01-25 17:34:15 +08:00
|
|
|
|
2013-01-20 11:28:06 +08:00
|
|
|
Debug Logging
|
|
|
|
-------------
|
|
|
|
|
|
|
|
Also using lws_set_log_level api you may provide a custom callback to actually
|
|
|
|
emit the log string. By default, this points to an internal emit function
|
|
|
|
that sends to stderr. Setting it to NULL leaves it as it is instead.
|
|
|
|
|
|
|
|
A helper function lwsl_emit_syslog() is exported from the library to simplify
|
|
|
|
logging to syslog. You still need to use setlogmask, openlog and closelog
|
|
|
|
in your user code.
|
|
|
|
|
|
|
|
The logging apis are made available for user code.
|
|
|
|
|
|
|
|
lwsl_err(...)
|
|
|
|
lwsl_warn(...)
|
|
|
|
lwsl_notice(...)
|
|
|
|
lwsl_info(...)
|
|
|
|
lwsl_debug(...)
|
|
|
|
|
|
|
|
The difference between notice and info is that notice will be logged by default
|
|
|
|
whereas info is ignored by default.
|
|
|
|
|
|
|
|
|
|
|
|
External Polling Loop support
|
|
|
|
-----------------------------
|
|
|
|
|
|
|
|
libwebsockets maintains an internal poll() array for all of its
|
|
|
|
sockets, but you can instead integrate the sockets into an
|
|
|
|
external polling array. That's needed if libwebsockets will
|
|
|
|
cooperate with an existing poll array maintained by another
|
|
|
|
server.
|
|
|
|
|
|
|
|
Four callbacks LWS_CALLBACK_ADD_POLL_FD, LWS_CALLBACK_DEL_POLL_FD,
|
|
|
|
LWS_CALLBACK_SET_MODE_POLL_FD and LWS_CALLBACK_CLEAR_MODE_POLL_FD
|
|
|
|
appear in the callback for protocol 0 and allow interface code to
|
|
|
|
manage socket descriptors in other poll loops.
|
|
|
|
|
|
|
|
|