From ed11a02201b53a6f72d60efcaa5ef726e4ece9ec Mon Sep 17 00:00:00 2001 From: Andy Green Date: Thu, 20 Jan 2011 10:23:50 +0000 Subject: [PATCH] add-enable-nofork-config-option.patch Signed-off-by: Andy Green --- README-test-server | 26 ++++++- configure | 175 ++++++++++++++++++++++++-------------------- configure.ac | 13 +++- lib/libwebsockets.c | 53 +++++++++----- lib/private-libwebsockets.h | 2 + test-server/test-server.c | 57 +++++++++++++-- 6 files changed, 217 insertions(+), 109 deletions(-) diff --git a/README-test-server b/README-test-server index 2f14e17..4b30fab 100644 --- a/README-test-server +++ b/README-test-server @@ -15,6 +15,9 @@ $ libwebsockets-test-server should be enough to get a test server listening on port 7861. +Testing +------- + If you point your browser (eg, Chrome) to http://127.0.0.1:7681 @@ -23,6 +26,9 @@ It will fetch a script in the form of test.html, and then run the script in there on the browser to open a websocket connection. Incrementing numbers should appear in the browser display. +Using SSL +--------- + To test it using SSL/WSS, just run the test server with $ libwebsockets-test-server --ssl @@ -41,5 +47,23 @@ same. test-server.c is all that is needed to use libwebsockets for serving both the script html over http and websockets. -2010-11-08 Andy Green +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. + + +Websocket version supported +--------------------------- + +Right now this is tested and working on websockets protocol 76/00 +Untested code is in for 04 support, there is no browser support +available yet to test it with. Libwebsockets should autoselect +between the supported versions according to what the browser +asks for. + +2011-01-20 Andy Green diff --git a/configure b/configure index 03e9e84..123de5b 100755 --- a/configure +++ b/configure @@ -735,6 +735,7 @@ with_gnu_ld with_sysroot enable_libtool_lock enable_openssl +enable_nofork ' ac_precious_vars='build_alias host_alias @@ -1378,6 +1379,7 @@ Optional Features: --enable-dependency-tracking do not reject slow dependency extractors --disable-libtool-lock avoid locking (might break parallel builds) --enable-openssl Enables https support and needs openssl libs + --enable-nofork Disables fork-related options Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] @@ -1739,6 +1741,60 @@ $as_echo "$ac_res" >&6; } } # ac_fn_c_check_func +# ac_fn_c_check_type LINENO TYPE VAR INCLUDES +# ------------------------------------------- +# Tests whether TYPE exists after having included INCLUDES, setting cache +# variable VAR accordingly. +ac_fn_c_check_type () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=no" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +if (sizeof ($2)) + return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +if (sizeof (($2))) + return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + eval "$3=yes" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_type + # ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists, giving a warning if it cannot be compiled using @@ -1829,60 +1885,6 @@ fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_mongrel - -# ac_fn_c_check_type LINENO TYPE VAR INCLUDES -# ------------------------------------------- -# Tests whether TYPE exists after having included INCLUDES, setting cache -# variable VAR accordingly. -ac_fn_c_check_type () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else - eval "$3=no" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -int -main () -{ -if (sizeof ($2)) - return 0; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -int -main () -{ -if (sizeof (($2))) - return 0; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - -else - eval "$3=yes" -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} # ac_fn_c_check_type cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. @@ -12014,37 +12016,16 @@ fi CFLAGS="$CFLAGS -DLWS_OPENSSL_SUPPORT" fi - - -# Checks for header files. -for ac_header in fcntl.h netinet/in.h stdlib.h string.h sys/socket.h unistd.h -do : - as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` -ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" -if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 -_ACEOF +# Check whether --enable-nofork was given. +if test "${enable_nofork+set}" = set; then : + enableval=$enable_nofork; nofork=yes fi -done - - -# Checks for typedefs, structures, and compiler characteristics. -ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" -if test "x$ac_cv_type_size_t" = xyes; then : +if test "x$nofork" = "xyes" ; then +CFLAGS="$CFLAGS -DLWS_NO_FORK" else - -cat >>confdefs.h <<_ACEOF -#define size_t unsigned int -_ACEOF - -fi - - -# Checks for library functions. ac_fn_c_check_type "$LINENO" "pid_t" "ac_cv_type_pid_t" "$ac_includes_default" if test "x$ac_cv_type_pid_t" = xyes; then : @@ -12269,6 +12250,40 @@ $as_echo "#define HAVE_WORKING_FORK 1" >>confdefs.h fi +fi + + + +# Checks for header files. +for ac_header in fcntl.h netinet/in.h stdlib.h string.h sys/socket.h unistd.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +# Checks for typedefs, structures, and compiler characteristics. +ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" +if test "x$ac_cv_type_size_t" = xyes; then : + +else + +cat >>confdefs.h <<_ACEOF +#define size_t unsigned int +_ACEOF + +fi + + +# Checks for library functions. + for ac_header in stdlib.h do : ac_fn_c_check_header_mongrel "$LINENO" "stdlib.h" "ac_cv_header_stdlib_h" "$ac_includes_default" diff --git a/configure.ac b/configure.ac index d3a407b..2ccdd68 100644 --- a/configure.ac +++ b/configure.ac @@ -28,6 +28,17 @@ 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 + # Checks for header files. @@ -37,7 +48,7 @@ AC_CHECK_HEADERS([fcntl.h netinet/in.h stdlib.h string.h sys/socket.h unistd.h]) AC_TYPE_SIZE_T # Checks for library functions. -AC_FUNC_FORK + AC_FUNC_MALLOC AC_FUNC_REALLOC AC_CHECK_FUNCS([bzero memset socket strerror]) diff --git a/lib/libwebsockets.c b/lib/libwebsockets.c index 1ba4410..5aa7c26 100644 --- a/lib/libwebsockets.c +++ b/lib/libwebsockets.c @@ -617,6 +617,8 @@ libwebsocket_create_server(int port, return this; } +#ifndef LWS_NO_FORK + /** * libwebsockets_fork_service_loop() - Optional helper function forks off * a process for the websocket server loop. @@ -635,29 +637,38 @@ libwebsockets_fork_service_loop(struct libwebsocket_context *this) struct sockaddr_in cli_addr; int n; - if (fork()) - return 0; + n = fork(); + if (n < 0) + return n; - for (client = 1; client < this->count_protocols + 1; client++) { - fd = socket(AF_INET, SOCK_STREAM, 0); - if (fd < 0) { - fprintf(stderr, "Unable to create socket\n"); - return -1; - } - cli_addr.sin_family = AF_INET; - cli_addr.sin_port = htons( - this->protocols[client - 1].broadcast_socket_port); - cli_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); - n = connect(fd, (struct sockaddr *)&cli_addr, - sizeof cli_addr); - if (n < 0) { - fprintf(stderr, "Unable to connect to " - "broadcast socket %d, %s\n", - client, strerror(errno)); - return -1; + if (!n) { + + /* main process context */ + + for (client = 1; client < this->count_protocols + 1; client++) { + fd = socket(AF_INET, SOCK_STREAM, 0); + if (fd < 0) { + fprintf(stderr, "Unable to create socket\n"); + return -1; + } + cli_addr.sin_family = AF_INET; + cli_addr.sin_port = htons( + this->protocols[client - 1].broadcast_socket_port); + cli_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); + n = connect(fd, (struct sockaddr *)&cli_addr, + sizeof cli_addr); + if (n < 0) { + fprintf(stderr, "Unable to connect to " + "broadcast socket %d, %s\n", + client, strerror(errno)); + return -1; + } + + this->protocols[client - 1].broadcast_socket_user_fd = fd; } - this->protocols[client - 1].broadcast_socket_user_fd = fd; + + return 0; } /* we want a SIGHUP when our parent goes down */ @@ -672,6 +683,8 @@ libwebsockets_fork_service_loop(struct libwebsocket_context *this) return 0; } +#endif + /** * libwebsockets_get_protocol() - Returns a protocol pointer from a websocket * connection. diff --git a/lib/private-libwebsockets.h b/lib/private-libwebsockets.h index 327e09c..a63d902 100644 --- a/lib/private-libwebsockets.h +++ b/lib/private-libwebsockets.h @@ -32,7 +32,9 @@ #include #include #include +#ifndef LWS_NO_FORK #include +#endif #include #include diff --git a/test-server/test-server.c b/test-server/test-server.c index 3365c0f..36a1978 100644 --- a/test-server/test-server.c +++ b/test-server/test-server.c @@ -264,12 +264,15 @@ int main(int argc, char **argv) return -1; } + buf[LWS_SEND_BUFFER_PRE_PADDING] = 'x'; + +#ifdef LWS_NO_FORK + /* - * After initializing and creating the websocket server in its own fork - * we return to the main process here + * This example shows how to work with no forked service loop */ - buf[LWS_SEND_BUFFER_PRE_PADDING] = 'x'; + fprintf(stderr, " Using no-fork service loop\n"); while (1) { @@ -297,14 +300,54 @@ int main(int argc, char **argv) * we have to give the websockets an opportunity to service * "manually". * - * There's an optional call libwebsockets_fork_service_loop() - * we could have used before this while loop, then the - * websockets would have been serviced in a forked process - * and we would not have to do the call below inside our loop. + * If no socket is needing service, the call below returns + * immediately and quickly. */ libwebsocket_service(server, 0); } +#else + + /* + * This example shows how to work with the forked websocket service loop + */ + + fprintf(stderr, " Using forked service loop\n"); + + /* + * This forks the websocket service action into a subprocess so we + * don't have to take care about it. + */ + + n = libwebsockets_fork_service_loop(server); + if (n < 0) { + fprintf(stderr, "Unable to fork service loop %d\n", n); + return 1; + } + + while (1) { + + usleep(50000); + + /* + * This broadcasts to all dumb-increment-protocol connections + * at 20Hz. + * + * We're just sending a character 'x', in these examples the + * callbacks send their own per-connection content. + * + * You have to send something with nonzero length to get the + * callback actions delivered. + * + * We take care of pre-and-post padding allocation. + */ + + libwebsockets_broadcast(&protocols[PROTOCOL_DUMB_INCREMENT], + &buf[LWS_SEND_BUFFER_PRE_PADDING], 1); + } + +#endif + return 0; } -- 2.7.4