1
0
Fork 0
mirror of https://github.com/warmcat/libwebsockets.git synced 2025-03-09 00:00:04 +01:00

introduce-ssl-client-connections--flow-control.patch

Signed-off-by: Andy Green <andy@warmcat.com>
This commit is contained in:
Andy Green 2011-01-27 06:26:52 +00:00
parent 9293b05703
commit 90c7cbcc00
20 changed files with 758 additions and 351 deletions

View file

@ -1,2 +1,2 @@
SUBDIRS=lib test-server
SUBDIRS=lib test-server

View file

@ -181,6 +181,7 @@ build_cpu = @build_cpu@
build_os = @build_os@
build_vendor = @build_vendor@
builddir = @builddir@
clientcertdir = @clientcertdir@
datadir = @datadir@
datarootdir = @datarootdir@
docdir = @docdir@
@ -214,7 +215,7 @@ target_alias = @target_alias@
top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
SUBDIRS = lib test-server
SUBDIRS = lib test-server
all: config.h
$(MAKE) $(AM_MAKEFLAGS) all-recursive

View file

@ -33,6 +33,10 @@ There are a couple of other possible configure options
to disable the built-in ones and force use
of the libcrypto (part of openssl) ones.
--with-client-cert-dir=dir tells the client ssl support where to
look for trust certificates to validate
the remote certificate against.
Testing server with a browser
-----------------------------
@ -44,11 +48,8 @@ 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
---------
The client side operation does not support SSL yet, but the
server side does.
Using SSL on the server side
----------------------------
To test it using SSL/WSS, just run the test server with
@ -68,6 +69,7 @@ same.
test-server.c is all that is needed to use libwebsockets for
serving both the script html over http and websockets.
Forkless operation
------------------
@ -76,6 +78,7 @@ 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
--------------------------------
@ -91,6 +94,19 @@ if you connect to the test server using a browser at the
same time you will be able to see the circles being drawn.
Testing SSL on the client side
------------------------------
To test SSL/WSS client action, just run the client test with
$ libwebsockets-test-client localhost --ssl
By default the client test applet is set to accept selfsigned
certificates used by the test server, this is indicated by the
use_ssl var being set to 2. Set it to 1 to reject any server
certificate that it doesn't have a trusted CA cert for.
Websocket version supported
---------------------------

24
configure vendored
View file

@ -616,6 +616,7 @@ ac_subst_vars='am__EXEEXT_FALSE
am__EXEEXT_TRUE
LTLIBOBJS
LIBOBJS
clientcertdir
LIBCRYPTO_FALSE
LIBCRYPTO_TRUE
CPP
@ -739,6 +740,7 @@ enable_libtool_lock
enable_openssl
enable_nofork
enable_libcrypto
with_client_cert_dir
'
ac_precious_vars='build_alias
host_alias
@ -1383,7 +1385,7 @@ Optional Features:
--disable-libtool-lock avoid locking (might break parallel builds)
--enable-openssl Enables https support and needs openssl libs
--enable-nofork Disables fork-related options
--enable-libcrypto Use libcrypto MD5 and SHA1 implemntations
--enable-libcrypto Use libcrypto MD5 and SHA1 implementations
Optional Packages:
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
@ -1393,6 +1395,8 @@ Optional Packages:
--with-gnu-ld assume the C compiler uses GNU ld [default=no]
--with-sysroot=DIR Search for dependent libraries within DIR
(or the compiler's sysroot if not specified).
--with-client-cert-dir directory containing client certs, defaults to
/etc/pki/tls/certs/
Some influential environment variables:
CC C compiler command
@ -11963,6 +11967,7 @@ fi
#
#
#
@ -12285,6 +12290,23 @@ fi
#
#
#
# Check whether --with-client-cert-dir was given.
if test "${with_client_cert_dir+set}" = set; then :
withval=$with_client_cert_dir; clientcertdir=$withval
else
clientcertdir=/etc/pki/tls/certs/
fi
# Checks for header files.
for ac_header in fcntl.h netinet/in.h stdlib.h string.h sys/socket.h unistd.h

View file

@ -17,6 +17,7 @@ AC_PROG_INSTALL
AC_PROG_MAKE_SET
AC_CONFIG_MACRO_DIR([m4])
#
#
#
@ -48,7 +49,7 @@ fi
#
#
AC_ARG_ENABLE(libcrypto,
[ --enable-libcrypto Use libcrypto MD5 and SHA1 implemntations],
[ --enable-libcrypto Use libcrypto MD5 and SHA1 implementations],
[ libcrypto=yes
])
@ -59,6 +60,19 @@ fi
AM_CONDITIONAL(LIBCRYPTO, test x$libcrypto = xyes)
#
#
#
AC_ARG_WITH([client-cert-dir],
[AS_HELP_STRING([--with-client-cert-dir],[directory containing client certs, defaults to /etc/pki/tls/certs/])],
[clientcertdir=$withval],
[clientcertdir=/etc/pki/tls/certs/]
)
AC_SUBST([clientcertdir])
AC_SUBST([CFLAGS])
# Checks for header files.
AC_CHECK_HEADERS([fcntl.h netinet/in.h stdlib.h string.h sys/socket.h unistd.h])

View file

@ -12,7 +12,7 @@ else
dist_libwebsockets_la_SOURCES += md5.c sha-1.c
endif
libwebsockets_la_CFLAGS=-Wall -Werror -std=gnu99 -pedantic -rdynamic -fPIC -c
libwebsockets_la_CFLAGS:=-rdynamic -fPIC -Wall -Werror -std=gnu99 -pedantic -c -DDATADIR=\"@datadir@\" -DLWS_OPENSSL_CLIENT_CERTS=\"@clientcertdir@\"
libwebsockets_la_LDFLAGS=-version-info 0:2
all-local:

View file

@ -183,6 +183,7 @@ build_cpu = @build_cpu@
build_os = @build_os@
build_vendor = @build_vendor@
builddir = @builddir@
clientcertdir = @clientcertdir@
datadir = @datadir@
datarootdir = @datarootdir@
docdir = @docdir@
@ -221,7 +222,7 @@ include_HEADERS = libwebsockets.h
dist_libwebsockets_la_SOURCES = libwebsockets.c handshake.c parsers.c \
libwebsockets.h base64-decode.c client-handshake.c \
private-libwebsockets.h $(am__append_1)
libwebsockets_la_CFLAGS = -Wall -Werror -std=gnu99 -pedantic -rdynamic -fPIC -c
libwebsockets_la_CFLAGS := -rdynamic -fPIC -Wall -Werror -std=gnu99 -pedantic -c -DDATADIR=\"@datadir@\" -DLWS_OPENSSL_CLIENT_CERTS=\"@clientcertdir@\"
libwebsockets_la_LDFLAGS = -version-info 0:2
all: all-am

View file

@ -9,8 +9,10 @@
void
strtolower(char *s)
{
while (*s)
*s++ = tolower(*s);
while (*s) {
*s = tolower(*s);
s++;
}
}
void
@ -53,7 +55,7 @@ libwebsocket_client_close(struct libwebsocket *wsi)
/* shut down reasonably cleanly */
#ifdef LWS_OPENSSL_SUPPORT
if (use_ssl) {
if (wsi->ssl) {
n = SSL_get_fd(wsi->ssl);
SSL_shutdown(wsi->ssl);
close(n);
@ -67,10 +69,29 @@ libwebsocket_client_close(struct libwebsocket *wsi)
#endif
}
/**
* libwebsocket_client_connect() - Connect to another websocket server
* @this: Websocket context
* @address: Remote server address, eg, "myserver.com"
* @port: Port to connect to on the remote server, eg, 80
* @ssl_connection: 0 = ws://, 1 = wss:// encrypted, 2 = wss:// allow self
* signed certs
* @path: Websocket path on server
* @host: Hostname on server
* @origin: Socket origin name
* @protocol: Comma-separated list of protocols being asked for from
* the server, or just one. The server will pick the one it
* likes best.
*
* This function creates a connection to a remote server
*/
struct libwebsocket *
libwebsocket_client_connect(struct libwebsocket_context *clients,
libwebsocket_client_connect(struct libwebsocket_context *this,
const char *address,
int port,
int ssl_connection,
const char *path,
const char *host,
const char *origin,
@ -94,12 +115,22 @@ libwebsocket_client_connect(struct libwebsocket_context *clients,
int okay = 0;
struct libwebsocket *wsi;
int n;
#ifdef LWS_OPENSSL_SUPPORT
char ssl_err_buf[512];
#else
if (ssl_connection) {
fprintf(stderr, "libwebsockets not configured for ssl\n");
return NULL;
}
#endif
wsi = malloc(sizeof(struct libwebsocket));
if (wsi == NULL)
if (wsi == NULL) {
fprintf(stderr, "Out of memort allocing new connection\n");
return NULL;
}
clients->wsi[clients->fds_count] = wsi;
this->wsi[this->fds_count] = wsi;
wsi->ietf_spec_revision = 4;
wsi->name_buffer_pos = 0;
@ -137,10 +168,36 @@ libwebsocket_client_connect(struct libwebsocket_context *clients,
if (connect(wsi->sock, (struct sockaddr *)&server_addr,
sizeof(struct sockaddr)) == -1) {
fprintf(stderr, "Connect failed");
fprintf(stderr, "Connect failed\n");
goto bail1;
}
#ifdef LWS_OPENSSL_SUPPORT
if (ssl_connection) {
wsi->ssl = SSL_new(this->ssl_client_ctx);
wsi->client_bio = BIO_new_socket(wsi->sock, BIO_NOCLOSE);
SSL_set_bio(wsi->ssl, wsi->client_bio, wsi->client_bio);
if (SSL_connect(wsi->ssl) <= 0) {
fprintf(stderr, "SSL connect error %s\n",
ERR_error_string(ERR_get_error(), ssl_err_buf));
goto bail2;
}
n = SSL_get_verify_result(wsi->ssl);
if (n != X509_V_OK) {
if (n == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT &&
ssl_connection == 2)
goto cert_okay;
fprintf(stderr, "server's cert didn't look good %d\n", n);
goto bail2;
}
} else
wsi->ssl = NULL;
cert_okay:
#endif
/*
* create the random key
*/
@ -199,7 +256,17 @@ libwebsocket_client_connect(struct libwebsocket_context *clients,
/* send our request to the server */
n = send(wsi->sock, pkt, p - pkt, 0);
#ifdef LWS_OPENSSL_SUPPORT
if (ssl_connection)
n = SSL_write(wsi->ssl, pkt, p - pkt);
else
#endif
n = send(wsi->sock, pkt, p - pkt, 0);
if (n < 0) {
fprintf(stderr, "ERROR writing to client socket\n");
goto bail2;
}
wsi->parser_state = WSI_TOKEN_NAME_PART;
@ -230,7 +297,13 @@ libwebsocket_client_connect(struct libwebsocket_context *clients,
* Sec-WebSocket-Protocol: chat
*/
len = recv(wsi->sock, pkt, sizeof pkt, 0);
#ifdef LWS_OPENSSL_SUPPORT
if (ssl_connection)
len = SSL_read(wsi->ssl, pkt, sizeof pkt);
else
#endif
len = recv(wsi->sock, pkt, sizeof pkt, 0);
if (len < 0) {
fprintf(stderr, "libwebsocket_client_handshake read error\n");
goto bail2;
@ -300,7 +373,7 @@ libwebsocket_client_connect(struct libwebsocket_context *clients,
if (!wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len) {
/* no protocol name to work from, default to first protocol */
wsi->protocol = &clients->protocols[0];
wsi->protocol = &this->protocols[0];
goto check_accept;
}
@ -331,10 +404,10 @@ libwebsocket_client_connect(struct libwebsocket_context *clients,
*/
n = 0;
wsi->protocol = NULL;
while (clients->protocols[n].callback) {
while (this->protocols[n].callback) {
if (strcmp(wsi->utf8_token[WSI_TOKEN_PROTOCOL].token,
clients->protocols[n].name) == 0)
wsi->protocol = &clients->protocols[n];
this->protocols[n].name) == 0)
wsi->protocol = &this->protocols[n];
n++;
}
@ -373,15 +446,21 @@ check_accept:
/* okay he is good to go */
clients->fds[clients->fds_count].fd = wsi->sock;
clients->fds[clients->fds_count].revents = 0;
clients->fds[clients->fds_count++].events = POLLIN;
this->fds[this->fds_count].fd = wsi->sock;
this->fds[this->fds_count].revents = 0;
this->fds[this->fds_count++].events = POLLIN;
wsi->state = WSI_STATE_ESTABLISHED;
wsi->client_mode = 1;
fprintf(stderr, "handshake OK for protocol %s\n", wsi->protocol->name);
/* call him back to inform him he is up */
wsi->protocol->callback(wsi,
LWS_CALLBACK_CLIENT_ESTABLISHED,
wsi->user_space,
NULL, 0);
return wsi;

View file

@ -131,7 +131,7 @@ handshake_00(struct libwebsocket *wsi)
strcpy(p, wsi->utf8_token[WSI_TOKEN_ORIGIN].token);
p += wsi->utf8_token[WSI_TOKEN_ORIGIN].token_len;
#ifdef LWS_OPENSSL_SUPPORT
if (use_ssl) {
if (wsi->ssl) {
strcpy(p, "\x0d\x0aSec-WebSocket-Location: wss://");
p += strlen("\x0d\x0aSec-WebSocket-Location: wss://");
} else {

View file

@ -21,11 +21,6 @@
#include "private-libwebsockets.h"
#ifdef LWS_OPENSSL_SUPPORT
SSL_CTX *ssl_ctx;
int use_ssl;
#endif
void
libwebsocket_close_and_free_session(struct libwebsocket *wsi)
{
@ -49,7 +44,7 @@ libwebsocket_close_and_free_session(struct libwebsocket *wsi)
/* fprintf(stderr, "closing fd=%d\n", wsi->sock); */
#ifdef LWS_OPENSSL_SUPPORT
if (use_ssl) {
if (wsi->ssl) {
n = SSL_get_fd(wsi->ssl);
SSL_shutdown(wsi->ssl);
close(n);
@ -93,6 +88,19 @@ libwebsocket_poll_connections(struct libwebsocket_context *this)
goto nuke_this;
}
/* the guy requested a callback when it was OK to write */
if ((unsigned long)this->wsi[client] > LWS_MAX_PROTOCOLS &&
this->fds[client].revents & POLLOUT) {
this->fds[client].events &= ~POLLOUT;
this->wsi[client]->protocol->callback(this->wsi[client],
LWS_CALLBACK_CLIENT_WRITEABLE,
this->wsi[client]->user_space,
NULL, 0);
}
/* any incoming data ready? */
if (!(this->fds[client].revents & POLLIN))
@ -158,7 +166,7 @@ libwebsocket_poll_connections(struct libwebsocket_context *this)
}
#ifdef LWS_OPENSSL_SUPPORT
if (this->use_ssl)
if (this->wsi[client]->ssl)
n = SSL_read(this->wsi[client]->ssl, buf, sizeof buf);
else
#endif
@ -218,8 +226,8 @@ libwebsocket_context_destroy(struct libwebsocket_context *this)
libwebsocket_close_and_free_session(this->wsi[client]);
#ifdef LWS_OPENSSL_SUPPORT
if (ssl_ctx)
SSL_CTX_free(ssl_ctx);
if (this->ssl_ctx)
SSL_CTX_free(this->ssl_ctx);
#endif
if (this)
@ -336,9 +344,12 @@ libwebsocket_service(struct libwebsocket_context *this, int timeout_ms)
}
#ifdef LWS_OPENSSL_SUPPORT
this->wsi[this->fds_count]->ssl = NULL;
if (this->use_ssl) {
this->wsi[this->fds_count]->ssl = SSL_new(ssl_ctx);
this->wsi[this->fds_count]->ssl =
SSL_new(this->ssl_ctx);
if (this->wsi[this->fds_count]->ssl == NULL) {
fprintf(stderr, "SSL_new failed: %s\n",
ERR_error_string(SSL_get_error(
@ -440,7 +451,8 @@ fatal:
close(this->fds[0].fd);
#ifdef LWS_OPENSSL_SUPPORT
SSL_CTX_free(ssl_ctx);
if (this->ssl_ctx)
SSL_CTX_free(this->ssl_ctx);
#endif
if (this)
@ -453,6 +465,91 @@ fatal:
return 1;
}
/**
* libwebsocket_callback_on_writable() - Request a callback when this socket
* becomes able to be written to without
* blocking
*
* @wsi: Websocket connection instance to get callback for
*/
int
libwebsocket_callback_on_writable(struct libwebsocket *wsi)
{
struct libwebsocket_context *this = wsi->protocol->owning_server;
int n;
for (n = this->count_protocols + 1; n < this->fds_count; n++)
if (this->wsi[n] == wsi) {
this->fds[n].events |= POLLOUT;
return 0;
}
fprintf(stderr, "libwebsocket_callback_on_writable "
"didn't find socket\n");
return 1;
}
/**
* libwebsocket_callback_on_writable_all_protocol() - Request a callback for
* all connections using the given protocol when it
* becomes possible to write to each socket without
* blocking in turn.
*
* @protocol: Protocol whose connections will get callbacks
*/
int
libwebsocket_callback_on_writable_all_protocol(
const struct libwebsocket_protocols *protocol)
{
struct libwebsocket_context *this = protocol->owning_server;
int n;
for (n = this->count_protocols + 1; n < this->fds_count; n++)
if ((unsigned long)this->wsi[n] > LWS_MAX_PROTOCOLS)
if (this->wsi[n]->protocol == protocol)
this->fds[n].events |= POLLOUT;
return 0;
}
/**
* libwebsocket_rx_flow_control() - Enable and disable socket servicing for
* receieved packets.
*
* If the output side of a server process becomes choked, this allows flow
* control for the input side.
*
* @wsi: Websocket connection instance to get callback for
* @enable: 0 = disable read servicing for this connection, 1 = enable
*/
int
libwebsocket_rx_flow_control(struct libwebsocket *wsi, int enable)
{
struct libwebsocket_context *this = wsi->protocol->owning_server;
int n;
for (n = this->count_protocols + 1; n < this->fds_count; n++)
if (this->wsi[n] == wsi) {
if (enable)
this->fds[n].events |= POLLIN;
else
this->fds[n].events &= ~POLLIN;
return 0;
}
fprintf(stderr, "libwebsocket_callback_on_writable "
"unable to find socket\n");
return 1;
}
static void sigpipe_handler(int x)
{
}
/**
* libwebsocket_create_context() - Create the websocket handler
@ -515,47 +612,103 @@ libwebsocket_create_context(int port,
#ifdef LWS_OPENSSL_SUPPORT
SSL_METHOD *method;
char ssl_err_buf[512];
use_ssl = ssl_cert_filepath != NULL && ssl_private_key_filepath != NULL;
if (use_ssl)
fprintf(stderr, " Compiled with SSL support, using it\n");
else
fprintf(stderr, " Compiled with SSL support, not using it\n");
#else
if (ssl_cert_filepath != NULL && ssl_private_key_filepath != NULL) {
fprintf(stderr, " Not compiled for OpenSSl support!\n");
return NULL;
}
fprintf(stderr, " Compiled without SSL support, serving unencrypted\n");
#endif
this = malloc(sizeof(struct libwebsocket_context));
if (!this) {
fprintf(stderr, "No memory for websocket context\n");
return NULL;
}
this->protocols = protocols;
this->listen_port = port;
if (port) {
#ifdef LWS_OPENSSL_SUPPORT
if (use_ssl) {
SSL_library_init();
this->use_ssl = ssl_cert_filepath != NULL &&
ssl_private_key_filepath != NULL;
if (this->use_ssl)
fprintf(stderr, " Compiled with SSL support, "
"using it\n");
else
fprintf(stderr, " Compiled with SSL support, "
"not using it\n");
OpenSSL_add_all_algorithms();
SSL_load_error_strings();
/*
* Firefox insists on SSLv23 not SSLv3
* Konq disables SSLv2 by default now, SSLv23 works
*/
method = (SSL_METHOD *)SSLv23_server_method();
if (!method) {
fprintf(stderr, "problem creating ssl method: %s\n",
ERR_error_string(ERR_get_error(), ssl_err_buf));
return NULL;
}
ssl_ctx = SSL_CTX_new(method); /* create context */
if (!ssl_ctx) {
printf("problem creating ssl context: %s\n",
ERR_error_string(ERR_get_error(), ssl_err_buf));
#else
if (ssl_cert_filepath != NULL &&
ssl_private_key_filepath != NULL) {
fprintf(stderr, " Not compiled for OpenSSl support!\n");
return NULL;
}
fprintf(stderr, " Compiled without SSL support, "
"serving unencrypted\n");
#endif
}
/* ignore SIGPIPE */
signal(SIGPIPE, sigpipe_handler);
#ifdef LWS_OPENSSL_SUPPORT
/* basic openssl init */
SSL_library_init();
OpenSSL_add_all_algorithms();
SSL_load_error_strings();
/*
* Firefox insists on SSLv23 not SSLv3
* Konq disables SSLv2 by default now, SSLv23 works
*/
method = (SSL_METHOD *)SSLv23_server_method();
if (!method) {
fprintf(stderr, "problem creating ssl method: %s\n",
ERR_error_string(ERR_get_error(), ssl_err_buf));
return NULL;
}
this->ssl_ctx = SSL_CTX_new(method); /* create context */
if (!this->ssl_ctx) {
fprintf(stderr, "problem creating ssl context: %s\n",
ERR_error_string(ERR_get_error(), ssl_err_buf));
return NULL;
}
/* client context */
method = (SSL_METHOD *)SSLv23_client_method();
if (!method) {
fprintf(stderr, "problem creating ssl method: %s\n",
ERR_error_string(ERR_get_error(), ssl_err_buf));
return NULL;
}
this->ssl_client_ctx = SSL_CTX_new(method); /* create context */
if (!this->ssl_client_ctx) {
fprintf(stderr, "problem creating ssl context: %s\n",
ERR_error_string(ERR_get_error(), ssl_err_buf));
return NULL;
}
/* openssl init for cert verification (used with client sockets) */
if (!SSL_CTX_load_verify_locations(this->ssl_client_ctx, NULL,
LWS_OPENSSL_CLIENT_CERTS)) {
fprintf(stderr, "Unable to load SSL Client certs from %s "
"(set by --with-client-cert-dir= in configure) -- "
" client ssl isn't going to work",
LWS_OPENSSL_CLIENT_CERTS);
}
if (this->use_ssl) {
/* openssl init for server sockets */
/* set the local certificate from CertFile */
n = SSL_CTX_use_certificate_file(ssl_ctx,
n = SSL_CTX_use_certificate_file(this->ssl_ctx,
ssl_cert_filepath, SSL_FILETYPE_PEM);
if (n != 1) {
fprintf(stderr, "problem getting cert '%s': %s\n",
@ -564,7 +717,7 @@ libwebsocket_create_context(int port,
return NULL;
}
/* set the private key from KeyFile */
if (SSL_CTX_use_PrivateKey_file(ssl_ctx,
if (SSL_CTX_use_PrivateKey_file(this->ssl_ctx,
ssl_private_key_filepath,
SSL_FILETYPE_PEM) != 1) {
fprintf(stderr, "ssl problem getting key '%s': %s\n",
@ -573,7 +726,7 @@ libwebsocket_create_context(int port,
return NULL;
}
/* verify private key */
if (!SSL_CTX_check_private_key(ssl_ctx)) {
if (!SSL_CTX_check_private_key(this->ssl_ctx)) {
fprintf(stderr, "Private SSL key doesn't match cert\n");
return NULL;
}
@ -587,12 +740,6 @@ libwebsocket_create_context(int port,
if (lws_b64_selftest())
return NULL;
this = malloc(sizeof(struct libwebsocket_context));
this->protocols = protocols;
this->listen_port = port;
/* set up our external listening socket we serve on */
if (port) {
@ -641,9 +788,6 @@ libwebsocket_create_context(int port,
this->fds[0].fd = sockfd;
this->fds[0].events = POLLIN;
this->count_protocols = 0;
#ifdef LWS_OPENSSL_SUPPORT
this->use_ssl = use_ssl;
#endif
if (port) {
listen(sockfd, 5);

View file

@ -26,9 +26,11 @@
enum libwebsocket_callback_reasons {
LWS_CALLBACK_ESTABLISHED,
LWS_CALLBACK_CLIENT_ESTABLISHED,
LWS_CALLBACK_CLOSED,
LWS_CALLBACK_RECEIVE,
LWS_CALLBACK_CLIENT_RECEIVE,
LWS_CALLBACK_CLIENT_WRITEABLE,
LWS_CALLBACK_HTTP,
LWS_CALLBACK_BROADCAST
};
@ -42,7 +44,9 @@ enum libwebsocket_write_protocol {
LWS_WRITE_CLOSE,
LWS_WRITE_PING,
LWS_WRITE_PONG
LWS_WRITE_PONG,
LWS_WRITE_NO_FIN = 0x40
};
struct libwebsocket;
@ -67,15 +71,25 @@ struct libwebsocket_context;
* You get an opportunity to initialize user data when called back with
* LWS_CALLBACK_ESTABLISHED reason.
*
* LWS_CALLBACK_ESTABLISHED: after successful websocket handshake
* LWS_CALLBACK_ESTABLISHED: after the server completes a handshake with
* an incoming client
*
* LWS_CALLBACK_CLIENT_ESTABLISHED: after your client connection completed
* a handshake with the remote server
*
* LWS_CALLBACK_CLOSED: when the websocket session ends
*
* LWS_CALLBACK_BROADCAST: signal to send to client (you would use
* libwebsocket_write() taking care about the
* special buffer requirements
* LWS_CALLBACK_RECEIVE: data has appeared for the server, it can be
* found at *in and is len bytes long
*
* LWS_CALLBACK_RECEIVE: data has appeared for this server endpoint from a
* remote client, it can be found at *in and is
* len bytes long
*
* LWS_CALLBACK_CLIENT_RECEIVE: data has appeared from the server for the
* client connection, it can be found at *in and
* is len bytes long
*
* LWS_CALLBACK_HTTP: an http request has come from a client that is not
* asking to upgrade the connection to a websocket
@ -85,6 +99,13 @@ struct libwebsocket_context;
* @in points to the URI path requested and
* libwebsockets_serve_http_file() makes it very
* simple to send back a file to the client.
*
* LWS_CALLBACK_CLIENT_WRITEABLE: if you call
* libwebsocket_callback_on_writable() on a connection, you will
* get this callback coming when the connection socket is able to
* accept another write packet without blocking. If it already
* was able to take another packet without blocking, you'll get
* this callback at the next call to the service loop function.
*/
extern int callback(struct libwebsocket *wsi,
enum libwebsocket_callback_reasons reason, void *user,
@ -197,6 +218,17 @@ libwebsockets_broadcast(const struct libwebsocket_protocols *protocol,
extern const struct libwebsocket_protocols *
libwebsockets_get_protocol(struct libwebsocket *wsi);
extern int
libwebsocket_callback_on_writable(struct libwebsocket *wsi);
extern int
libwebsocket_callback_on_writable_all_protocol(
const struct libwebsocket_protocols *protocol);
extern int
libwebsocket_rx_flow_control(struct libwebsocket *wsi, int enable);
extern size_t
libwebsockets_remaining_packet_payload(struct libwebsocket *wsi);
@ -204,6 +236,7 @@ extern struct libwebsocket *
libwebsocket_client_connect(struct libwebsocket_context *clients,
const char *address,
int port,
int ssl_connection,
const char *path,
const char *host,
const char *origin,

View file

@ -977,8 +977,6 @@ libwebsocket_04_frame_mask_generate(struct libwebsocket *wsi)
* packet while not burdening the user code with any protocol knowledge.
*/
/* FIXME FIN bit */
int libwebsocket_write(struct libwebsocket *wsi, unsigned char *buf,
size_t len, enum libwebsocket_write_protocol protocol)
{
@ -987,6 +985,11 @@ int libwebsocket_write(struct libwebsocket *wsi, unsigned char *buf,
int post = 0;
unsigned int shift = 7;
if (len == 0) {
fprintf(stderr, "zero length libwebsocket_write attempt\n");
return 0;
}
if (protocol == LWS_WRITE_HTTP)
goto send_raw;
@ -999,7 +1002,7 @@ int libwebsocket_write(struct libwebsocket *wsi, unsigned char *buf,
/* chrome likes this as of 30 Oct */
/* Firefox 4.0b6 likes this as of 30 Oct */
case 0:
if (protocol == LWS_WRITE_BINARY) {
if ((protocol & 0xf) == LWS_WRITE_BINARY) {
/* in binary mode we send 7-bit used length blocks */
pre = 1;
while (len & (127 << shift)) {
@ -1031,7 +1034,7 @@ int libwebsocket_write(struct libwebsocket *wsi, unsigned char *buf,
case 4:
switch (protocol) {
switch (protocol & 0xf) {
case LWS_WRITE_TEXT:
n = LWS_WS_OPCODE_04__TEXT_FRAME;
break;
@ -1054,12 +1057,8 @@ int libwebsocket_write(struct libwebsocket *wsi, unsigned char *buf,
return -1;
}
/*
* We don't really support the metaframe concept with FIN.
* Just set FIN on every packet for now
*/
n |= 1 << 7;
if (!(protocol & LWS_WRITE_NO_FIN))
n |= 1 << 7;
if (len < 126) {
buf[-2] = n;
@ -1130,10 +1129,9 @@ int libwebsocket_write(struct libwebsocket *wsi, unsigned char *buf,
memcpy(&buf[0 - pre], wsi->frame_masking_nonce_04, 4);
}
send_raw:
#ifdef LWS_OPENSSL_SUPPORT
if (use_ssl) {
if (wsi->ssl) {
n = SSL_write(wsi->ssl, buf - pre, len + pre + post);
if (n < 0) {
fprintf(stderr, "ERROR writing to socket\n");
@ -1149,6 +1147,7 @@ send_raw:
#ifdef LWS_OPENSSL_SUPPORT
}
#endif
debug("written %d bytes to client\n", (int)len);
return 0;
@ -1199,6 +1198,8 @@ int libwebsockets_serve_http_file(struct libwebsocket *wsi, const char *file,
n = 1;
while (n > 0) {
n = read(fd, buf, 512);
if (n <= 0)
continue;
libwebsocket_write(wsi, (unsigned char *)buf, n,
LWS_WRITE_HTTP);
}

View file

@ -67,11 +67,6 @@ static inline void debug(const char *format, ...)
}
#endif
#ifdef LWS_OPENSSL_SUPPORT
extern SSL_CTX *ssl_ctx;
extern int use_ssl;
#endif
#define MAX_CLIENTS 100
#define LWS_MAX_HEADER_NAME_LENGTH 64
@ -79,7 +74,7 @@ extern int use_ssl;
#define LWS_INITIAL_HDR_ALLOC 256
#define LWS_ADDITIONAL_HDR_ALLOC 64
#define MAX_USER_RX_BUFFER 512
#define MAX_BROADCAST_PAYLOAD 1024
#define MAX_BROADCAST_PAYLOAD 2048
#define LWS_MAX_PROTOCOLS 10
#define MAX_WEBSOCKET_04_KEY_LEN 128
@ -175,6 +170,8 @@ struct libwebsocket_context {
int listen_port;
#ifdef LWS_OPENSSL_SUPPORT
int use_ssl;
SSL_CTX *ssl_ctx;
SSL_CTX *ssl_client_ctx;
#endif
struct libwebsocket_protocols *protocols;
int count_protocols;
@ -224,6 +221,7 @@ struct libwebsocket {
#ifdef LWS_OPENSSL_SUPPORT
SSL *ssl;
BIO *client_bio;
#endif
void *user_space;

View file

@ -146,27 +146,31 @@ sha1_step(struct sha1_ctxt *ctxt)
for (t = 0; t < 20; t++) {
s = t & 0x0f;
if (t >= 16) {
W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^ W((s+2) & 0x0f) ^ W(s));
}
if (t >= 16)
W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^
W((s+2) & 0x0f) ^ W(s));
tmp = S(5, a) + F0(b, c, d) + e + W(s) + K(t);
e = d; d = c; c = S(30, b); b = a; a = tmp;
}
for (t = 20; t < 40; t++) {
s = t & 0x0f;
W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^ W((s+2) & 0x0f) ^ W(s));
W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^
W((s+2) & 0x0f) ^ W(s));
tmp = S(5, a) + F1(b, c, d) + e + W(s) + K(t);
e = d; d = c; c = S(30, b); b = a; a = tmp;
}
for (t = 40; t < 60; t++) {
s = t & 0x0f;
W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^ W((s+2) & 0x0f) ^ W(s));
W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^
W((s+2) & 0x0f) ^ W(s));
tmp = S(5, a) + F2(b, c, d) + e + W(s) + K(t);
e = d; d = c; c = S(30, b); b = a; a = tmp;
}
for (t = 60; t < 80; t++) {
s = t & 0x0f;
W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^ W((s+2) & 0x0f) ^ W(s));
W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^
W((s+2) & 0x0f) ^ W(s));
tmp = S(5, a) + F3(b, c, d) + e + W(s) + K(t);
e = d; d = c; c = S(30, b); b = a; a = tmp;
}

View file

@ -58,6 +58,45 @@ would call it with a timeout_ms of 0, so it returns immediately if
nothing is pending, or as soon as it services whatever was pending.
</blockquote>
<hr>
<h2>libwebsocket_callback_on_writable - Request a callback when this socket becomes able to be written to without blocking</h2>
<i>int</i>
<b>libwebsocket_callback_on_writable</b>
(<i>struct libwebsocket *</i> <b>wsi</b>)
<h3>Arguments</h3>
<dl>
<dt><b>wsi</b>
<dd>Websocket connection instance to get callback for
</dl>
<hr>
<h2>libwebsocket_callback_on_writable_all_protocol - Request a callback for all connections using the given protocol when it becomes possible to write to each socket without blocking in turn.</h2>
<i>int</i>
<b>libwebsocket_callback_on_writable_all_protocol</b>
(<i>const struct libwebsocket_protocols *</i> <b>protocol</b>)
<h3>Arguments</h3>
<dl>
<dt><b>protocol</b>
<dd>Protocol whose connections will get callbacks
</dl>
<hr>
<h2>libwebsocket_rx_flow_control - Enable and disable socket servicing for receieved packets.</h2>
<i>int</i>
<b>libwebsocket_rx_flow_control</b>
(<i>struct libwebsocket *</i> <b>wsi</b>,
<i>int</i> <b>enable</b>)
<h3>Arguments</h3>
<dl>
<dt><b>wsi</b>
<dd>Websocket connection instance to get callback for
<dt><b>enable</b>
<dd>0 = disable read servicing for this connection, 1 = enable
</dl>
<h3>Description</h3>
<blockquote>
<p>
If the output side of a server process becomes choked, this allows flow
control for the input side.
</blockquote>
<hr>
<h2>libwebsocket_create_context - Create the websocket handler</h2>
<i>struct libwebsocket_context *</i>
<b>libwebsocket_create_context</b>
@ -258,6 +297,44 @@ when that is the case <b>libwebsockets_remaining_packet_payload</b> will return
Many protocols won't care becuse their packets are always small.
</blockquote>
<hr>
<h2>libwebsocket_client_connect - Connect to another websocket server</h2>
<i>struct libwebsocket *</i>
<b>libwebsocket_client_connect</b>
(<i>struct libwebsocket_context *</i> <b>this</b>,
<i>const char *</i> <b>address</b>,
<i>int</i> <b>port</b>,
<i>int</i> <b>ssl_connection</b>,
<i>const char *</i> <b>path</b>,
<i>const char *</i> <b>host</b>,
<i>const char *</i> <b>origin</b>,
<i>const char *</i> <b>protocol</b>)
<h3>Arguments</h3>
<dl>
<dt><b>this</b>
<dd>Websocket context
<dt><b>address</b>
<dd>Remote server address, eg, "myserver.com"
<dt><b>port</b>
<dd>Port to connect to on the remote server, eg, 80
<dt><b>ssl_connection</b>
<dd>0 = ws://, 1 = wss:// encrypted, 2 = wss:// allow self
signed certs
<dt><b>path</b>
<dd>Websocket path on server
<dt><b>host</b>
<dd>Hostname on server
<dt><b>origin</b>
<dd>Socket origin name
<dt><b>protocol</b>
<dd>Comma-separated list of protocols being asked for from
the server, or just one. The server will pick the one it
likes best.
</dl>
<h3>Description</h3>
<blockquote>
This function creates a connection to a remote server
</blockquote>
<hr>
<h2>callback - User server actions</h2>
<i>int</i>
<b>callback</b>
@ -293,7 +370,13 @@ LWS_CALLBACK_ESTABLISHED reason.
</blockquote>
<h3>LWS_CALLBACK_ESTABLISHED</h3>
<blockquote>
after successful websocket handshake
after the server completes a handshake with
an incoming client
</blockquote>
<h3>LWS_CALLBACK_CLIENT_ESTABLISHED</h3>
<blockquote>
after your client connection completed
a handshake with the remote server
</blockquote>
<h3>LWS_CALLBACK_CLOSED</h3>
<blockquote>
@ -307,8 +390,15 @@ special buffer requirements
</blockquote>
<h3>LWS_CALLBACK_RECEIVE</h3>
<blockquote>
data has appeared for the server, it can be
found at *in and is len bytes long
data has appeared for this server endpoint from a
remote client, it can be found at *in and is
len bytes long
</blockquote>
<h3>LWS_CALLBACK_CLIENT_RECEIVE</h3>
<blockquote>
data has appeared from the server for the
client connection, it can be found at *in and
is len bytes long
</blockquote>
<h3>LWS_CALLBACK_HTTP</h3>
<blockquote>
@ -321,6 +411,15 @@ which will then open the websockets connection.
<b>libwebsockets_serve_http_file</b> makes it very
simple to send back a file to the client.
</blockquote>
<h3>LWS_CALLBACK_CLIENT_WRITEABLE</h3>
<blockquote>
if you call
<b>libwebsocket_callback_on_writable</b> on a connection, you will
get this callback coming when the connection socket is able to
accept another write packet without blocking. If it already
was able to take another packet without blocking, you'll get
this callback at the next call to the service loop function.
</blockquote>
<hr>
<h2>struct libwebsocket_protocols - List of protocols and handlers server supports.</h2>
<b>struct libwebsocket_protocols</b> {<br>

View file

@ -3,6 +3,12 @@ libwebsockets_test_server_SOURCES=test-server.c
libwebsockets_test_server_LDADD=-L../lib -lwebsockets
libwebsockets_test_client_SOURCES=test-client.c
libwebsockets_test_client_LDADD=-L../lib -lwebsockets
libwebsockets_test_server_CFLAGS:= -Wall -Werror -std=gnu99 -pedantic -DDATADIR=\"@datadir@\" -DLWS_OPENSSL_CLIENT_CERTS=\"@clientcertdir@\"
libwebsockets_test_client_CFLAGS:= -Wall -Werror -std=gnu99 -pedantic -DDATADIR=\"@datadir@\" -DLWS_OPENSSL_CLIENT_CERTS=\"@clientcertdir@\"
#
# cook a random test cert and key
# notice your real cert and key will want to be 0600 permissions

View file

@ -48,14 +48,24 @@ CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
am__installdirs = "$(DESTDIR)$(bindir)"
PROGRAMS = $(bin_PROGRAMS)
am_libwebsockets_test_client_OBJECTS = test-client.$(OBJEXT)
am_libwebsockets_test_client_OBJECTS = \
libwebsockets_test_client-test-client.$(OBJEXT)
libwebsockets_test_client_OBJECTS = \
$(am_libwebsockets_test_client_OBJECTS)
libwebsockets_test_client_DEPENDENCIES =
am_libwebsockets_test_server_OBJECTS = test-server.$(OBJEXT)
libwebsockets_test_client_LINK = $(LIBTOOL) --tag=CC \
$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
$(libwebsockets_test_client_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
$(LDFLAGS) -o $@
am_libwebsockets_test_server_OBJECTS = \
libwebsockets_test_server-test-server.$(OBJEXT)
libwebsockets_test_server_OBJECTS = \
$(am_libwebsockets_test_server_OBJECTS)
libwebsockets_test_server_DEPENDENCIES =
libwebsockets_test_server_LINK = $(LIBTOOL) --tag=CC \
$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
$(libwebsockets_test_server_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
$(LDFLAGS) -o $@
DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__depfiles_maybe = depfiles
@ -156,6 +166,7 @@ build_cpu = @build_cpu@
build_os = @build_os@
build_vendor = @build_vendor@
builddir = @builddir@
clientcertdir = @clientcertdir@
datadir = @datadir@
datarootdir = @datarootdir@
docdir = @docdir@
@ -193,6 +204,8 @@ libwebsockets_test_server_SOURCES = test-server.c
libwebsockets_test_server_LDADD = -L../lib -lwebsockets
libwebsockets_test_client_SOURCES = test-client.c
libwebsockets_test_client_LDADD = -L../lib -lwebsockets
libwebsockets_test_server_CFLAGS := -Wall -Werror -std=gnu99 -pedantic -DDATADIR=\"@datadir@\" -DLWS_OPENSSL_CLIENT_CERTS=\"@clientcertdir@\"
libwebsockets_test_client_CFLAGS := -Wall -Werror -std=gnu99 -pedantic -DDATADIR=\"@datadir@\" -DLWS_OPENSSL_CLIENT_CERTS=\"@clientcertdir@\"
all: all-am
.SUFFIXES:
@ -272,10 +285,10 @@ clean-binPROGRAMS:
rm -f $$list
libwebsockets-test-client$(EXEEXT): $(libwebsockets_test_client_OBJECTS) $(libwebsockets_test_client_DEPENDENCIES)
@rm -f libwebsockets-test-client$(EXEEXT)
$(LINK) $(libwebsockets_test_client_OBJECTS) $(libwebsockets_test_client_LDADD) $(LIBS)
$(libwebsockets_test_client_LINK) $(libwebsockets_test_client_OBJECTS) $(libwebsockets_test_client_LDADD) $(LIBS)
libwebsockets-test-server$(EXEEXT): $(libwebsockets_test_server_OBJECTS) $(libwebsockets_test_server_DEPENDENCIES)
@rm -f libwebsockets-test-server$(EXEEXT)
$(LINK) $(libwebsockets_test_server_OBJECTS) $(libwebsockets_test_server_LDADD) $(LIBS)
$(libwebsockets_test_server_LINK) $(libwebsockets_test_server_OBJECTS) $(libwebsockets_test_server_LDADD) $(LIBS)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
@ -283,8 +296,8 @@ mostlyclean-compile:
distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-client.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-server.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwebsockets_test_client-test-client.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwebsockets_test_server-test-server.Po@am__quote@
.c.o:
@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@ -307,6 +320,34 @@ distclean-compile:
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
libwebsockets_test_client-test-client.o: test-client.c
@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwebsockets_test_client_CFLAGS) $(CFLAGS) -MT libwebsockets_test_client-test-client.o -MD -MP -MF $(DEPDIR)/libwebsockets_test_client-test-client.Tpo -c -o libwebsockets_test_client-test-client.o `test -f 'test-client.c' || echo '$(srcdir)/'`test-client.c
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libwebsockets_test_client-test-client.Tpo $(DEPDIR)/libwebsockets_test_client-test-client.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='test-client.c' object='libwebsockets_test_client-test-client.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwebsockets_test_client_CFLAGS) $(CFLAGS) -c -o libwebsockets_test_client-test-client.o `test -f 'test-client.c' || echo '$(srcdir)/'`test-client.c
libwebsockets_test_client-test-client.obj: test-client.c
@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwebsockets_test_client_CFLAGS) $(CFLAGS) -MT libwebsockets_test_client-test-client.obj -MD -MP -MF $(DEPDIR)/libwebsockets_test_client-test-client.Tpo -c -o libwebsockets_test_client-test-client.obj `if test -f 'test-client.c'; then $(CYGPATH_W) 'test-client.c'; else $(CYGPATH_W) '$(srcdir)/test-client.c'; fi`
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libwebsockets_test_client-test-client.Tpo $(DEPDIR)/libwebsockets_test_client-test-client.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='test-client.c' object='libwebsockets_test_client-test-client.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwebsockets_test_client_CFLAGS) $(CFLAGS) -c -o libwebsockets_test_client-test-client.obj `if test -f 'test-client.c'; then $(CYGPATH_W) 'test-client.c'; else $(CYGPATH_W) '$(srcdir)/test-client.c'; fi`
libwebsockets_test_server-test-server.o: test-server.c
@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwebsockets_test_server_CFLAGS) $(CFLAGS) -MT libwebsockets_test_server-test-server.o -MD -MP -MF $(DEPDIR)/libwebsockets_test_server-test-server.Tpo -c -o libwebsockets_test_server-test-server.o `test -f 'test-server.c' || echo '$(srcdir)/'`test-server.c
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libwebsockets_test_server-test-server.Tpo $(DEPDIR)/libwebsockets_test_server-test-server.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='test-server.c' object='libwebsockets_test_server-test-server.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwebsockets_test_server_CFLAGS) $(CFLAGS) -c -o libwebsockets_test_server-test-server.o `test -f 'test-server.c' || echo '$(srcdir)/'`test-server.c
libwebsockets_test_server-test-server.obj: test-server.c
@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwebsockets_test_server_CFLAGS) $(CFLAGS) -MT libwebsockets_test_server-test-server.obj -MD -MP -MF $(DEPDIR)/libwebsockets_test_server-test-server.Tpo -c -o libwebsockets_test_server-test-server.obj `if test -f 'test-server.c'; then $(CYGPATH_W) 'test-server.c'; else $(CYGPATH_W) '$(srcdir)/test-server.c'; fi`
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libwebsockets_test_server-test-server.Tpo $(DEPDIR)/libwebsockets_test_server-test-server.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='test-server.c' object='libwebsockets_test_server-test-server.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwebsockets_test_server_CFLAGS) $(CFLAGS) -c -o libwebsockets_test_server-test-server.obj `if test -f 'test-server.c'; then $(CYGPATH_W) 'test-server.c'; else $(CYGPATH_W) '$(srcdir)/test-server.c'; fi`
mostlyclean-libtool:
-rm -f *.lo
@ -514,6 +555,7 @@ uninstall-am: uninstall-binPROGRAMS
mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
tags uninstall uninstall-am uninstall-binPROGRAMS
#
# cook a random test cert and key
# notice your real cert and key will want to be 0600 permissions

View file

@ -35,11 +35,11 @@
* server just it simplifies the demo).
*
* dumb-increment-protocol: we connect to the server and print the number
* we are given
* we are given
*
* lws-mirror-protocol: draws random circles, which are mirrored on to every
* client (see them being drawn in every browser
* session also using the test server)
* client (see them being drawn in every browser
* session also using the test server)
*/
enum demo_protocols {
@ -62,7 +62,8 @@ callback_dumb_increment(struct libwebsocket *wsi,
switch (reason) {
case LWS_CALLBACK_CLIENT_RECEIVE:
fprintf(stderr, "rx %d '%s'\n", len, in);
((char *)in)[len] = '\0';
fprintf(stderr, "rx %d '%s'\n", (int)len, (char *)in);
break;
default:
@ -75,148 +76,49 @@ callback_dumb_increment(struct libwebsocket *wsi,
/* lws-mirror_protocol */
/* "how to draw a circle" */
struct coord {
int x;
int y;
};
static struct coord circle[] = {
{ 0, 240 },
{ 12, 239 },
{ 25, 238 },
{ 37, 237 },
{ 49, 234 },
{ 62, 231 },
{ 74, 228 },
{ 86, 224 },
{ 97, 219 },
{ 108, 213 },
{ 120, 207 },
{ 130, 201 },
{ 141, 194 },
{ 151, 186 },
{ 160, 178 },
{ 169, 169 },
{ 178, 160 },
{ 186, 151 },
{ 194, 141 },
{ 201, 130 },
{ 207, 120 },
{ 213, 108 },
{ 219, 97 },
{ 224, 86 },
{ 228, 74 },
{ 231, 62 },
{ 234, 49 },
{ 237, 37 },
{ 238, 25 },
{ 239, 12 },
{ 240, 0 },
{ 239, -12 },
{ 238, -25 },
{ 237, -37 },
{ 234, -49 },
{ 231, -62 },
{ 228, -74 },
{ 224, -86 },
{ 219, -97 },
{ 213, -108 },
{ 207, -120 },
{ 201, -130 },
{ 194, -141 },
{ 186, -151 },
{ 178, -160 },
{ 169, -169 },
{ 160, -178 },
{ 151, -186 },
{ 141, -194 },
{ 130, -201 },
{ 120, -207 },
{ 108, -213 },
{ 97, -219 },
{ 86, -224 },
{ 74, -228 },
{ 62, -231 },
{ 49, -234 },
{ 37, -237 },
{ 25, -238 },
{ 12, -239 },
{ 0, -240 },
{ -12, -239 },
{ -25, -238 },
{ -37, -237 },
{ -49, -234 },
{ -62, -231 },
{ -74, -228 },
{ -86, -224 },
{ -97, -219 },
{ -108, -213 },
{ -119, -207 },
{ -130, -201 },
{ -141, -194 },
{ -151, -186 },
{ -160, -178 },
{ -169, -169 },
{ -178, -160 },
{ -186, -151 },
{ -194, -141 },
{ -201, -130 },
{ -207, -120 },
{ -213, -108 },
{ -219, -97 },
{ -224, -86 },
{ -228, -74 },
{ -231, -62 },
{ -234, -49 },
{ -237, -37 },
{ -238, -25 },
{ -239, -12 },
{ -240, 0 },
{ -239, 12 },
{ -238, 25 },
{ -237, 37 },
{ -234, 49 },
{ -231, 62 },
{ -228, 74 },
{ -224, 86 },
{ -219, 97 },
{ -213, 108 },
{ -207, 120 },
{ -201, 130 },
{ -194, 141 },
{ -186, 151 },
{ -178, 160 },
{ -169, 169 },
{ -160, 178 },
{ -151, 186 },
{ -141, 194 },
{ -130, 201 },
{ -119, 207 },
{ -108, 213 },
{ -97, 219 },
{ -86, 224 },
{ -74, 228 },
{ -62, 231 },
{ -49, 234 },
{ -37, 237 },
{ -25, 238 },
{ -12, 239 },
{ 0, 240 },
};
static int
callback_lws_mirror(struct libwebsocket *wsi,
enum libwebsocket_callback_reasons reason,
void *user, void *in, size_t len)
{
unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 4096 +
LWS_SEND_BUFFER_POST_PADDING];
int l;
switch (reason) {
case LWS_CALLBACK_CLIENT_ESTABLISHED:
/*
* start the ball rolling,
* LWS_CALLBACK_CLIENT_WRITEABLE will come immediately
*/
libwebsocket_callback_on_writable(wsi);
break;
case LWS_CALLBACK_CLIENT_RECEIVE:
// fprintf(stderr, "rx %d '%s'\n", len, in);
/* fprintf(stderr, "rx %d '%s'\n", (int)len, (char *)in); */
break;
case LWS_CALLBACK_CLIENT_WRITEABLE:
l = sprintf((char *)&buf[LWS_SEND_BUFFER_PRE_PADDING],
"c #%06X %d %d %d;",
(int)random() & 0xffffff,
(int)random() % 500,
(int)random() % 250,
(int)random() % 24);
libwebsocket_write(wsi,
&buf[LWS_SEND_BUFFER_PRE_PADDING], l, LWS_WRITE_TEXT);
/* get notified as soon as we can write again */
libwebsocket_callback_on_writable(wsi);
usleep(200);
break;
default:
@ -245,9 +147,9 @@ static struct libwebsocket_protocols protocols[] = {
};
static struct option options[] = {
{ "help", no_argument, NULL, 'h' },
{ "port", required_argument, NULL, 'p' },
{ "ssl", no_argument, NULL, 's' },
{ "help", no_argument, NULL, 'h' },
{ "port", required_argument, NULL, 'p' },
{ "ssl", no_argument, NULL, 's' },
{ NULL, 0, 0, 0 }
};
@ -258,19 +160,10 @@ int main(int argc, char **argv)
int port = 7681;
int use_ssl = 0;
struct libwebsocket_context *context;
const char * address = argv[1];
const char *address = argv[1];
struct libwebsocket *wsi_dumb;
struct libwebsocket *wsi_mirror;
unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 1024 +
LWS_SEND_BUFFER_POST_PADDING];
int len;
int i = 0;
int xofs;
int yofs;
int oldx;
int oldy;
int scale;
int colour;
fprintf(stderr, "libwebsockets test client\n"
"(C) Copyright 2010 Andy Green <andy@warmcat.com> "
@ -287,7 +180,7 @@ int main(int argc, char **argv)
continue;
switch (n) {
case 's':
use_ssl = 1;
use_ssl = 2; /* 2 = allow selfsigned */
break;
case 'p':
port = atoi(optarg);
@ -315,8 +208,8 @@ int main(int argc, char **argv)
/* create a client websocket using dumb increment protocol */
wsi_dumb = libwebsocket_client_connect(context, address, port, "/",
"http://host", "origin",
wsi_dumb = libwebsocket_client_connect(context, address, port, use_ssl,
"/", "http://host", "origin",
protocols[PROTOCOL_DUMB_INCREMENT].name);
if (wsi_dumb == NULL) {
@ -326,8 +219,8 @@ int main(int argc, char **argv)
/* create a client websocket using mirror protocol */
wsi_mirror = libwebsocket_client_connect(context, address, port, "/",
"http://host", "origin",
wsi_mirror = libwebsocket_client_connect(context, address, port,
use_ssl, "/", "http://host", "origin",
protocols[PROTOCOL_LWS_MIRROR].name);
if (wsi_mirror == NULL) {
@ -343,39 +236,8 @@ int main(int argc, char **argv)
*/
n = 0;
while (n >= 0) {
usleep(10000);
if (i == sizeof circle / sizeof circle[0])
i = 0;
if (i == 0) {
xofs = random() % 500;
yofs = random() % 250;
scale = random() % 24;
if (!scale)
scale = 1;
oldx = xofs + (circle[i].x / scale);
oldy = yofs + (circle[i].y / scale);
colour = random() & 0xffffff;
}
len = sprintf(&buf[LWS_SEND_BUFFER_PRE_PADDING],
"d #%06X %d %d %d %d", colour, oldx, oldy,
xofs + (circle[i].x / scale),
yofs + (circle[i].y / scale));
oldx = xofs + (circle[i].x / scale);
oldy = yofs + (circle[i].y / scale);
i++;
libwebsocket_write(wsi_mirror,
&buf[LWS_SEND_BUFFER_PRE_PADDING], len, LWS_WRITE_TEXT);
n = libwebsocket_service(context, 0);
}
while (n >= 0)
n = libwebsocket_service(context, 1000);
libwebsocket_client_close(wsi_dumb);
libwebsocket_client_close(wsi_mirror);

View file

@ -24,6 +24,7 @@
#include <unistd.h>
#include <getopt.h>
#include <string.h>
#include <sys/time.h>
#include "../lib/libwebsockets.h"
@ -36,11 +37,11 @@
*
* dumb-increment-protocol: once the socket is opened, an incrementing
* ascii string is sent down it every 50ms.
* If you send "reset\n" on the websocket, then
* the incrementing number is reset to 0.
* If you send "reset\n" on the websocket, then
* the incrementing number is reset to 0.
*
* lws-mirror-protocol: copies any received packet to every connection also
* using this protocol, including the sender
* using this protocol, including the sender
*/
enum demo_protocols {
@ -55,7 +56,7 @@ enum demo_protocols {
};
#define LOCAL_RESOURCE_PATH "/usr/share/libwebsockets-test-server"
#define LOCAL_RESOURCE_PATH DATADIR"/libwebsockets-test-server"
/* this protocol server (always the first one) just knows how to do HTTP */
@ -65,7 +66,7 @@ static int callback_http(struct libwebsocket *wsi,
{
switch (reason) {
case LWS_CALLBACK_HTTP:
fprintf(stderr, "serving HTTP URI %s\n", in);
fprintf(stderr, "serving HTTP URI %s\n", (char *)in);
if (in && strcmp(in, "/favicon.ico") == 0) {
if (libwebsockets_serve_http_file(wsi,
@ -108,9 +109,9 @@ callback_dumb_increment(struct libwebsocket *wsi,
void *user, void *in, size_t len)
{
int n;
char buf[LWS_SEND_BUFFER_PRE_PADDING + 512 +
unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 512 +
LWS_SEND_BUFFER_POST_PADDING];
char *p = (char *)&buf[LWS_SEND_BUFFER_PRE_PADDING];
unsigned char *p = &buf[LWS_SEND_BUFFER_PRE_PADDING];
struct per_session_data__dumb_increment *pss = user;
switch (reason) {
@ -126,7 +127,7 @@ callback_dumb_increment(struct libwebsocket *wsi,
*/
case LWS_CALLBACK_BROADCAST:
n = sprintf(p, "%d", pss->number++);
n = sprintf((char *)p, "%d", pss->number++);
n = libwebsocket_write(wsi, p, n, LWS_WRITE_TEXT);
if (n < 0) {
fprintf(stderr, "ERROR writing to socket");
@ -135,7 +136,7 @@ callback_dumb_increment(struct libwebsocket *wsi,
break;
case LWS_CALLBACK_RECEIVE:
fprintf(stderr, "rx %d\n", len);
fprintf(stderr, "rx %d\n", (int)len);
if (len < 6)
break;
if (strcmp(in, "reset\n") == 0)
@ -152,33 +153,92 @@ callback_dumb_increment(struct libwebsocket *wsi,
/* lws-mirror_protocol */
#define MAX_MESSAGE_QUEUE 64
struct per_session_data__lws_mirror {
struct libwebsocket *wsi;
int ringbuffer_tail;
};
struct a_message {
void *payload;
size_t len;
};
static struct a_message ringbuffer[MAX_MESSAGE_QUEUE];
static int ringbuffer_head;
static int
callback_lws_mirror(struct libwebsocket *wsi,
enum libwebsocket_callback_reasons reason,
void *user, void *in, size_t len)
{
int n;
struct per_session_data__lws_mirror *pss = user;
switch (reason) {
case LWS_CALLBACK_ESTABLISHED:
pss->ringbuffer_tail = ringbuffer_head;
pss->wsi = wsi;
break;
case LWS_CALLBACK_CLIENT_WRITEABLE:
if (pss->ringbuffer_tail != ringbuffer_head) {
n = libwebsocket_write(wsi, (unsigned char *)
ringbuffer[pss->ringbuffer_tail].payload +
LWS_SEND_BUFFER_PRE_PADDING,
ringbuffer[pss->ringbuffer_tail].len,
LWS_WRITE_TEXT);
if (n < 0) {
fprintf(stderr, "ERROR writing to socket");
exit(1);
}
if (pss->ringbuffer_tail == (MAX_MESSAGE_QUEUE - 1))
pss->ringbuffer_tail = 0;
else
pss->ringbuffer_tail++;
if (((ringbuffer_head - pss->ringbuffer_tail) %
MAX_MESSAGE_QUEUE) < (MAX_MESSAGE_QUEUE - 15))
libwebsocket_rx_flow_control(wsi, 1);
libwebsocket_callback_on_writable(wsi);
}
break;
case LWS_CALLBACK_BROADCAST:
n = libwebsocket_write(wsi, in, len, LWS_WRITE_TEXT);
if (n < 0)
fprintf(stderr, "mirror write failed\n");
break;
case LWS_CALLBACK_RECEIVE:
/*
* copy the incoming packet to all other protocol users
*
* This demonstrates how easy it is to broadcast from inside
* a callback.
*
* How this works is it calls back to the callback for all
* connected sockets using this protocol with
* LWS_CALLBACK_BROADCAST reason. Our handler for that above
* writes the data down the socket.
*/
libwebsockets_broadcast(libwebsockets_get_protocol(wsi),
in, len);
if (ringbuffer[ringbuffer_head].payload)
free(ringbuffer[ringbuffer_head].payload);
ringbuffer[ringbuffer_head].payload =
malloc(LWS_SEND_BUFFER_PRE_PADDING + len +
LWS_SEND_BUFFER_POST_PADDING);
ringbuffer[ringbuffer_head].len = len;
memcpy((char *)ringbuffer[ringbuffer_head].payload +
LWS_SEND_BUFFER_PRE_PADDING, in, len);
if (ringbuffer_head == (MAX_MESSAGE_QUEUE - 1))
ringbuffer_head = 0;
else
ringbuffer_head++;
if (((ringbuffer_head - pss->ringbuffer_tail) %
MAX_MESSAGE_QUEUE) > (MAX_MESSAGE_QUEUE - 10))
libwebsocket_rx_flow_control(wsi, 0);
libwebsocket_callback_on_writable_all_protocol(
libwebsockets_get_protocol(wsi));
break;
default:
@ -206,6 +266,8 @@ static struct libwebsocket_protocols protocols[] = {
[PROTOCOL_LWS_MIRROR] = {
.name = "lws-mirror-protocol",
.callback = callback_lws_mirror,
.per_session_data_size =
sizeof(struct per_session_data__lws_mirror),
},
[DEMO_PROTOCOL_COUNT] = { /* end of list */
.callback = NULL
@ -213,9 +275,9 @@ static struct libwebsocket_protocols protocols[] = {
};
static struct option options[] = {
{ "help", no_argument, NULL, 'h' },
{ "port", required_argument, NULL, 'p' },
{ "ssl", no_argument, NULL, 's' },
{ "help", no_argument, NULL, 'h' },
{ "port", required_argument, NULL, 'p' },
{ "ssl", no_argument, NULL, 's' },
{ NULL, 0, 0, 0 }
};
@ -231,6 +293,9 @@ int main(int argc, char **argv)
int port = 7681;
int use_ssl = 0;
struct libwebsocket_context *context;
#ifdef LWS_NO_FORK
unsigned int oldus = 0;
#endif
fprintf(stderr, "libwebsockets test server\n"
"(C) Copyright 2010-2011 Andy Green <andy@warmcat.com> "
@ -275,13 +340,14 @@ int main(int argc, char **argv)
fprintf(stderr, " Using no-fork service loop\n");
while (1) {
usleep(50000);
struct timeval tv;
gettimeofday(&tv, NULL);
/*
* 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.
*
@ -291,8 +357,12 @@ int main(int argc, char **argv)
* We take care of pre-and-post padding allocation.
*/
libwebsockets_broadcast(&protocols[PROTOCOL_DUMB_INCREMENT],
if (((unsigned int)tv.tv_usec - oldus) > 50000) {
libwebsockets_broadcast(
&protocols[PROTOCOL_DUMB_INCREMENT],
&buf[LWS_SEND_BUFFER_PRE_PADDING], 1);
oldus = tv.tv_usec;
}
/*
* This example server does not fork or create a thread for
@ -304,7 +374,7 @@ int main(int argc, char **argv)
* immediately and quickly.
*/
libwebsocket_service(context, 0);
libwebsocket_service(context, 50);
}
#else
@ -327,13 +397,13 @@ int main(int argc, char **argv)
}
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.
*

View file

@ -7,7 +7,8 @@
<body>
<h2>libwebsockets "dumb-increment-protocol" test applet</h2>
The incrementing number is coming from the server.
The incrementing number is coming from the server and is individual for
each connection to the server... try opening a second browser window.
Click the button to send the server a websocket message to
reset the number.<br><br>
@ -27,6 +28,8 @@ well.
The lws-mirror protocol doesn't interpret what is being sent to it, it just
re-sends it to every other websocket it has a connection with using that
protocol, including the guy who sent the packet.
<p>libwebsockets-test-client spams circles on to this shared canvas when
run.</p>
<br><br>
<table>
@ -121,13 +124,25 @@ function reset() {
}
socket_lm.onmessage =function got_packet(msg) {
i = msg.data.split(' ');
if (i[0] == 'd') {
ctx.strokeStyle = i[1];
ctx.beginPath();
ctx.moveTo(+(i[2]), +(i[3]));
ctx.lineTo(+(i[4]), +(i[5]));
ctx.stroke();
j = msg.data.split(';');
f = 0;
while (f < j.length - 1) {
i = j[f].split(' ');
if (i[0] == 'd') {
ctx.strokeStyle = i[1];
ctx.beginPath();
ctx.moveTo(+(i[2]), +(i[3]));
ctx.lineTo(+(i[4]), +(i[5]));
ctx.stroke();
}
if (i[0] == 'c') {
ctx.strokeStyle = i[1];
ctx.beginPath();
ctx.arc(+(i[2]), +(i[3]), +(i[4]), 0, Math.PI*2, true);
ctx.stroke();
}
f++;
}
}
@ -192,7 +207,7 @@ function ev_mousemove (ev) {
last_y = y;
return;
}
socket_lm.send("d " + color + " " + last_x + " " + last_y + " " + x + ' ' + y);
socket_lm.send("d " + color + " " + last_x + " " + last_y + " " + x + ' ' + y + ';');
last_x = x;
last_y = y;