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:
parent
9293b05703
commit
90c7cbcc00
20 changed files with 758 additions and 351 deletions
|
@ -1,2 +1,2 @@
|
|||
SUBDIRS=lib test-server
|
||||
|
||||
SUBDIRS=lib test-server
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
24
configure
vendored
|
@ -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
|
||||
|
|
16
configure.ac
16
configure.ac
|
@ -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])
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
16
lib/sha-1.c
16
lib/sha-1.c
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Reference in a new issue