Skip to content

Commit

Permalink
evict all broadcast support
Browse files Browse the repository at this point in the history
Libwebsockets is fundamentally singlethreaded... the existence of the
fork and broadcast support, especially in the sample server is
giving the wrong idea about how to use it.

This replaces broadcast in the sample server with
libwebsocket_callback_on_writable_all_protocol().  The whole idea of
'broadcast' is removed.

All of the broadcast proxy stuff is removed: data must now be sent
from the callback only.  Doing othherwise is not reliable since the
service loop may close the socket and free the wsi at any time,
invalidating a wsi pointer held by another thread (don't do that!)

Likewise the confirm_legit_wsi api added recently does not help the
other thread case, since if the wsi has been freed dereferencing the
wsi to study if it is legit or not will segfault in that case.  So
this is removed too.

The overall effect is to push user code to only operate inside the
protocol callbacks or external poll loops, ie, single thread context.

Signed-off-by: Andy Green <[email protected]>
  • Loading branch information
Andy Green committed Jan 29, 2013
1 parent 5e1b7ff commit 6f520a5
Show file tree
Hide file tree
Showing 12 changed files with 59 additions and 703 deletions.
5 changes: 0 additions & 5 deletions README.build
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,6 @@ Configure script options

There are several other possible configure options

--enable-nofork disables the fork into the background API
and removes all references to fork() and
pr_ctl() from the sources. Use it if your
platform doesn't support forking.

--enable-libcrypto by default libwebsockets uses its own
built-in md5 and sha-1 implementation for
simplicity. However the libcrypto ones
Expand Down
58 changes: 40 additions & 18 deletions README.coding
Original file line number Diff line number Diff line change
Expand Up @@ -25,24 +25,46 @@ similar to change the avaiable number of file descriptors, and when restarted
libwebsockets will adapt accordingly.


Procedure for sending data from other threads or process contexts
-----------------------------------------------------------------

Libwebsockets is carefully designed to work with no blocking in a single thread.
In some cases where you will add libwebsockets to something else that uses the
same single thread approach, you can so a safe implementation by combining the
poll() loops as described in "External Polling loop support" below.

In other cases, you find you have asynchronous events coming from other thread
or process contexts and there's not much you can do about it. If you just try
to randomly send, or broadcast using libwebsockets_broadcast() from these other
places things will blow up either quickly or when the events on the two threads
interefere with each other. It's not legal to do this.

For those situations, you can use libwebsockets_broadcast_foreign(). This
serializes the data you're sending using a private, per-protocol socket, so the
service thread picks it up when it's ready, and it is serviced from the service
thread context only.
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.


Fragmented messages
Expand Down
11 changes: 0 additions & 11 deletions README.test-apps
Original file line number Diff line number Diff line change
Expand Up @@ -58,17 +58,6 @@ test-server.c is all that is needed to use libwebsockets for
serving both the script html over http and websockets.


Forkless operation
------------------

If your target device does not offer fork(), you can use
libwebsockets from your own main loop instead. Use the
configure option --nofork and simply call libwebsocket_service()
from your own main loop as shown in the test app sources.




Testing websocket client support
--------------------------------

Expand Down
14 changes: 0 additions & 14 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -31,20 +31,6 @@ AC_CHECK_LIB([ssl], [SSL_library_init])
CFLAGS="$CFLAGS -DLWS_OPENSSL_SUPPORT"
fi

#
#
#
AC_ARG_ENABLE(nofork,
[ --enable-nofork Disables fork-related options],
[ nofork=yes
])

if test "x$nofork" = "xyes" ; then
CFLAGS="$CFLAGS -DLWS_NO_FORK"
else
AC_FUNC_FORK
fi

#
#
#
Expand Down
2 changes: 1 addition & 1 deletion lib/client.c
Original file line number Diff line number Diff line change
Expand Up @@ -627,7 +627,7 @@ libwebsockets_generate_client_handshake(struct libwebsocket_context *context,
int ext_count = 0;
#endif
unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 1 +
MAX_BROADCAST_PAYLOAD + LWS_SEND_BUFFER_POST_PADDING];
MAX_USER_RX_BUFFER + LWS_SEND_BUFFER_POST_PADDING];
static const char magic_websocket_guid[] =
"258EAFA5-E914-47DA-95CA-C5AB0DC85B11";

Expand Down
Loading

0 comments on commit 6f520a5

Please sign in to comment.