"61AC5F19-FBBA-4540-B96F-6561F1AB40A8";
char pkt[1024];
char *p = &pkt[0];
- const char * pc;
+ const char *pc;
int len;
int okay = 0;
struct libwebsocket *wsi;
int n;
- wsi = malloc(sizeof (struct libwebsocket));
+ wsi = malloc(sizeof(struct libwebsocket));
if (wsi == NULL)
return NULL;
}
wsi->sock = socket(AF_INET, SOCK_STREAM, 0);
-
+
if (wsi->sock < 0) {
fprintf(stderr, "Unable to open socket\n");
goto bail1;
sizeof(struct sockaddr)) == -1) {
fprintf(stderr, "Connect failed");
goto bail1;
- }
+ }
- /*
- * create the random key
- */
+ /*
+ * create the random key
+ */
fd = open(SYSTEM_RANDOM_FILEPATH, O_RDONLY);
if (fd < 1) {
}
close(fd);
- lws_b64_encode_string(hash, 16, key_b64, sizeof key_b64);
+ lws_b64_encode_string(hash, 16, key_b64, sizeof key_b64);
/*
* 04 example client handshake
" Upgrade header '%s'\n",
wsi->utf8_token[WSI_TOKEN_UPGRADE].token);
goto bail2;
- }
+ }
strtolower(wsi->utf8_token[WSI_TOKEN_CONNECTION].token);
if (strcmp(wsi->utf8_token[WSI_TOKEN_CONNECTION].token, "upgrade")) {
m += nonce_len;
strcpy(m, websocket_magic_guid_04_masking);
m += strlen(websocket_magic_guid_04_masking);
-
+
SHA1((unsigned char *)mask_summing_buf, m - mask_summing_buf,
wsi->masking_key_04);
return 0;
}
-
if (libwebsocket_interpret_incoming_packet(wsi, buf, len) < 0)
goto bail;
+
break;
default:
break;
bail:
libwebsocket_close_and_free_session(wsi);
+
return -1;
}
if (this->fds[client].revents & (POLLERR | POLLHUP)) {
debug("Session Socket %d %p (fd=%d) dead\n",
- client, this->wsi[client], this->fds[client]);
+ client, (void *)this->wsi[client],
+ this->fds[client].fd);
libwebsocket_close_and_free_session(this->wsi[client]);
goto nuke_this;
continue;
/* only to clients connected to us */
-
+
if (wsi->client_mode)
continue;
/* service incoming data */
- if (libwebsocket_read(this->wsi[client], buf, n) >= 0)
+ n = libwebsocket_read(this->wsi[client], buf, n);
+ if (n >= 0)
continue;
-
/*
* it closed and nuked wsi[client], so remove the
* socket handle and wsi from our service list
nuke_this:
debug("nuking wsi %p, fsd_count = %d\n",
- this->wsi[client], this->fds_count - 1);
+ (void *)this->wsi[client], this->fds_count - 1);
this->fds_count--;
for (n = client; n < this->fds_count; n++) {
this->fds[n] = this->fds[n + 1];
this->wsi[n] = this->wsi[n + 1];
}
- break;
+
+ return 0;
+
}
return 0;
}
+/**
+ * libwebsocket_context_destroy() - Destroy the websocket context
+ * @this: Websocket context
+ *
+ * This function closes any active connections and then frees the
+ * context. After calling this, any further use of the context is
+ * undefined.
+ */
+void
+libwebsocket_context_destroy(struct libwebsocket_context *this)
+{
+ int client;
+
+ /* close listening skt and per-protocol broadcast sockets */
+ for (client = 0; client < this->fds_count; client++)
+ libwebsocket_close_and_free_session(this->wsi[client]);
+
+#ifdef LWS_OPENSSL_SUPPORT
+ if (ssl_ctx)
+ SSL_CTX_free(ssl_ctx);
+#endif
+
+ if (this)
+ free(this);
+}
+
+/**
+ * libwebsocket_service() - Service any pending websocket activity
+ * @this: Websocket context
+ * @timeout_ms: Timeout for poll; 0 means return immediately if nothing needed
+ * service otherwise block and service immediately, returning
+ * after the timeout if nothing needed service.
+ *
+ * This function deals with any pending websocket traffic, for three
+ * kinds of event. It handles these events on both server and client
+ * types of connection the same.
+ *
+ * 1) Accept new connections to our context's server
+ *
+ * 2) Perform pending broadcast writes initiated from other forked
+ * processes (effectively serializing asynchronous broadcasts)
+ *
+ * 3) Call the receive callback for incoming frame data received by
+ * server or client connections.
+ *
+ * You need to call this service function periodically to all the above
+ * functions to happen; if your application is single-threaded you can
+ * just call it in your main event loop.
+ *
+ * Alternatively you can fork a new process that asynchronously handles
+ * calling this service in a loop. In that case you are happy if this
+ * call blocks your thread until it needs to take care of something and
+ * would call it with a large nonzero timeout. Your loop then takes no
+ * CPU while there is nothing happening.
+ *
+ * If you are calling it in a single-threaded app, you don't want it to
+ * wait around blocking other things in your loop from happening, so you
+ * 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.
+ */
+
int
libwebsocket_service(struct libwebsocket_context *this, int timeout_ms)
n = poll(this->fds, this->fds_count, timeout_ms);
else
n = poll(&this->fds[1], this->fds_count - 1, timeout_ms);
-
+
if (n < 0 || this->fds[0].revents & (POLLERR | POLLHUP)) {
fprintf(stderr, "Listen Socket dead\n");
fatal:
+ fprintf(stderr, "service hits fatal\n");
+
/* close listening skt and per-protocol broadcast sockets */
for (client = 0; client < this->fds_count; client++)
close(this->fds[0].fd);
#ifdef LWS_OPENSSL_SUPPORT
SSL_CTX_free(ssl_ctx);
#endif
- kill(0, SIGTERM);
if (this)
free(this);
/**
* libwebsocket_create_context() - Create the websocket handler
* @port: Port to listen on... you can use 0 to suppress listening on
- * any port, that's what you want if you are not running a
- * websocket server at all but just using it as a client
+ * any port, that's what you want if you are not running a
+ * websocket server at all but just using it as a client
* @protocols: Array of structures listing supported protocols and a protocol-
* specific callback for each one. The list is ended with an
* entry that has a NULL callback pointer.
- * It's not const because we write the owning_server member
+ * It's not const because we write the owning_server member
* @ssl_cert_filepath: If libwebsockets was compiled to use ssl, and you want
* to listen using SSL, set to the filepath to fetch the
* server cert from, otherwise NULL for unencrypted
/**
* libwebsockets_fork_service_loop() - Optional helper function forks off
* a process for the websocket server loop.
- * You don't have to use this but if not, you
- * have to make sure you are calling
- * libwebsocket_service periodically to service
- * the websocket traffic
+ * You don't have to use this but if not, you
+ * have to make sure you are calling
+ * libwebsocket_service periodically to service
+ * the websocket traffic
* @this: server context returned by creation function
*/
* set up when the websocket server initializes
*/
- n = send(protocol->broadcast_socket_user_fd, buf, len, 0);
+ n = send(protocol->broadcast_socket_user_fd, buf, len, MSG_NOSIGNAL);
return n;
}
*
* This callback is the way the user controls what is served. All the
* protocol detail is hidden and handled by the library.
- *
+ *
* For each connection / session there is user data allocated that is
* pointed to by "user". You set the size of this user data area when
* the library is initialized with libwebsocket_create_server.
- *
+ *
* You get an opportunity to initialize user data when called back with
* LWS_CALLBACK_ESTABLISHED reason.
*
* LWS_CALLBACK_RECEIVE: data has appeared for the server, 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
+ * LWS_CALLBACK_HTTP: an http request has come from a client that is not
* asking to upgrade the connection to a websocket
* one. This is a chance to serve http content,
* for example, to send a script to the client
* which will then open the websockets connection.
- * @in points to the URI path requested and
+ * @in points to the URI path requested and
* libwebsockets_serve_http_file() makes it very
* simple to send back a file to the client.
*/
-extern int callback(struct libwebsocket * wsi,
- enum libwebsocket_callback_reasons reason, void * user,
+extern int callback(struct libwebsocket *wsi,
+ enum libwebsocket_callback_reasons reason, void *user,
void *in, size_t len);
/**
- * struct libwebsocket_protocols - List of protocols and handlers server
- * supports.
+ * struct libwebsocket_protocols - List of protocols and handlers server
+ * supports.
* @name: Protocol name that must match the one given in the client
- * Javascript new WebSocket(url, 'protocol') name
+ * Javascript new WebSocket(url, 'protocol') name
* @callback: The service callback used for this protocol. It allows the
- * service action for an entire protocol to be encapsulated in
- * the protocol-specific callback
+ * service action for an entire protocol to be encapsulated in
+ * the protocol-specific callback
* @per_session_data_size: Each new connection using this protocol gets
- * this much memory allocated on connection establishment and
- * freed on connection takedown. A pointer to this per-connection
- * allocation is passed into the callback in the 'user' parameter
+ * this much memory allocated on connection establishment and
+ * freed on connection takedown. A pointer to this per-connection
+ * allocation is passed into the callback in the 'user' parameter
* @owning_server: the server init call fills in this opaque pointer when
- * registering this protocol with the server.
+ * registering this protocol with the server.
* @broadcast_socket_port: the server init call fills this in with the
- * localhost port number used to forward broadcasts for this
- * protocol
+ * localhost port number used to forward broadcasts for this
+ * protocol
* @broadcast_socket_user_fd: the server init call fills this in ... the main()
- * process context can write to this socket to perform broadcasts
- * (use the libwebsockets_broadcast() api to do this instead,
- * it works from any process context)
+ * process context can write to this socket to perform broadcasts
+ * (use the libwebsockets_broadcast() api to do this instead,
+ * it works from any process context)
* @protocol_index: which protocol we are starting from zero
*
- * This structure represents one protocol supported by the server. An
- * array of these structures is passed to libwebsocket_create_server()
- * allows as many protocols as you like to be handled by one server.
+ * This structure represents one protocol supported by the server. An
+ * array of these structures is passed to libwebsocket_create_server()
+ * allows as many protocols as you like to be handled by one server.
*/
struct libwebsocket_protocols {
* below are filled in on server init and can be left uninitialized,
* no need for user to use them directly either
*/
-
+
struct libwebsocket_context *owning_server;
int broadcast_socket_port;
int broadcast_socket_user_fd;
const char *ssl_cert_filepath,
const char *ssl_private_key_filepath, int gid, int uid);
+extern void
+libwebsocket_context_destroy(struct libwebsocket_context *this);
+
extern int
libwebsockets_fork_service_loop(struct libwebsocket_context *this);
/* notice - you need the pre- and post- padding allocation for buf below */
extern int
-libwebsockets_broadcast(const struct libwebsocket_protocols * protocol,
+libwebsockets_broadcast(const struct libwebsocket_protocols *protocol,
unsigned char *buf, size_t len);
extern const struct libwebsocket_protocols *
debug("known hdr '%s'\n", wsi->name_buffer);
wsi->parser_state = WSI_TOKEN_GET_URI + n;
wsi->current_alloc_len = LWS_INITIAL_HDR_ALLOC;
-
+
wsi->utf8_token[wsi->parser_state].token =
malloc(wsi->current_alloc_len);
wsi->utf8_token[wsi->parser_state].token_len = 0;
return 0;
}
-static unsigned char inline
+static inline unsigned char
xor_mask(struct libwebsocket *wsi, unsigned char c)
{
c ^= wsi->masking_key_04[wsi->frame_mask_index++];
* wsi->frame_mask_04 will be our recirculating 20-byte XOR key
* for this frame
*/
-
+
SHA1((unsigned char *)buf, 4 + 20, wsi->frame_mask_04);
/*
*/
wsi->frame_mask_index = 0;
-
+
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_1;
break;
*
* We ignore the possibility of extension data because we don't
* negotiate any extensions at the moment.
- *
+ *
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-------+-+-------------+-------------------------------+
* 04 spec defines the opcode like this: (1, 2, and 3 are
* "control frame" opcodes which may not be fragmented or
* have size larger than 126)
- *
+ *
* frame-opcode =
- * %x0 ; continuation frame
- * / %x1 ; connection close
- * / %x2 ; ping
- * / %x3 ; pong
- * / %x4 ; text frame
- * / %x5 ; binary frame
- * / %x6-F ; reserved
+ * %x0 ; continuation frame
+ * / %x1 ; connection close
+ * / %x2 ; ping
+ * / %x3 ; pong
+ * / %x4 ; text frame
+ * / %x5 ; binary frame
+ * / %x6-F ; reserved
*
- * FIN (b7)
+ * FIN (b7)
*/
c = xor_mask(wsi, c);
if (c & 0x70) {
- fprintf(stderr, "Frame has extensions set illegally 1\n");
+ fprintf(stderr,
+ "Frame has extensions set illegally 1\n");
/* kill the connection */
return -1;
}
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_8;
break;
default:
-// fprintf(stderr, "seen incoming 04 frame len %d\n", c);
wsi->rx_packet_length = c;
wsi->lws_rx_parse_state =
LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
}
break;
case 4:
- /*
- * 04 logical framing from the spec (all this is masked when incoming
- * and has to be unmasked)
- *
- * We ignore the possibility of extension data because we don't
- * negotiate any extensions at the moment.
- *
- * 0 1 2 3
- * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- * +-+-+-+-+-------+-+-------------+-------------------------------+
- * |F|R|R|R| opcode|R| Payload len | Extended payload length |
- * |I|S|S|S| (4) |S| (7) | (16/63) |
- * |N|V|V|V| |V| | (if payload len==126/127) |
- * | |1|2|3| |4| | |
- * +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
- * | Extended payload length continued, if payload len == 127 |
- * + - - - - - - - - - - - - - - - +-------------------------------+
- * | | Extension data |
- * +-------------------------------+ - - - - - - - - - - - - - - - +
- * : :
- * +---------------------------------------------------------------+
- * : Application data :
- * +---------------------------------------------------------------+
- *
- * We pass payload through to userland as soon as we get it, ignoring
- * FIN. It's up to userland to buffer it up if it wants to see a
- * whole unfragmented block of the original size (which may be up to
- * 2^63 long!)
- */
+ /*
+ * 04 logical framing from the spec (all this is masked when
+ * incoming and has to be unmasked)
+ *
+ * We ignore the possibility of extension data because we don't
+ * negotiate any extensions at the moment.
+ *
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-------+-+-------------+-------------------------------+
+ * |F|R|R|R| opcode|R| Payload len | Extended payload length |
+ * |I|S|S|S| (4) |S| (7) | (16/63) |
+ * |N|V|V|V| |V| | (if payload len==126/127) |
+ * | |1|2|3| |4| | |
+ * +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
+ * | Extended payload length continued, if payload len == 127 |
+ * + - - - - - - - - - - - - - - - +-------------------------------+
+ * | | Extension data |
+ * +-------------------------------+ - - - - - - - - - - - - - - - +
+ * : :
+ * +---------------------------------------------------------------+
+ * : Application data :
+ * +---------------------------------------------------------------+
+ *
+ * We pass payload through to userland as soon as we get it, ignoring
+ * FIN. It's up to userland to buffer it up if it wants to see a
+ * whole unfragmented block of the original size (which may be up to
+ * 2^63 long!)
+ */
/*
* 04 spec defines the opcode like this: (1, 2, and 3 are
* "control frame" opcodes which may not be fragmented or
* have size larger than 126)
- *
+ *
* frame-opcode =
- * %x0 ; continuation frame
- * / %x1 ; connection close
- * / %x2 ; ping
- * / %x3 ; pong
- * / %x4 ; text frame
- * / %x5 ; binary frame
- * / %x6-F ; reserved
+ * %x0 ; continuation frame
+ * / %x1 ; connection close
+ * / %x2 ; ping
+ * / %x3 ; pong
+ * / %x4 ; text frame
+ * / %x5 ; binary frame
+ * / %x6-F ; reserved
*
- * FIN (b7)
+ * FIN (b7)
*/
if (c & 0x70) {
if (use_ssl) {
n = SSL_write(wsi->ssl, buf - pre, len + pre + post);
if (n < 0) {
- fprintf(stderr, "ERROR writing to socket");
+ fprintf(stderr, "ERROR writing to socket\n");
return -1;
}
} else {
#endif
- n = send(wsi->sock, buf - pre, len + pre + post, 0);
+ n = send(wsi->sock, buf - pre, len + pre + post, MSG_NOSIGNAL);
if (n < 0) {
- fprintf(stderr, "ERROR writing to socket");
+ fprintf(stderr, "ERROR writing to socket\n");
return -1;
}
#ifdef LWS_OPENSSL_SUPPORT
/**
* libwebsockets_remaining_packet_payload() - Bytes to come before "overall"
- * rx packet is complete
+ * rx packet is complete
* @wsi: Websocket instance (available from user callback)
*
* This function is intended to be called from the callback if the
#include <openssl/sha.h>
#include "libwebsockets.h"
-//#define DEBUG
-
+#if 0
+#define DEBUG
+#endif
#ifdef DEBUG
-static inline void debug(const char *format, ...) {
+static inline void debug(const char *format, ...)
+{
va_list ap;
va_start(ap, format); vfprintf(stderr, format, ap); va_end(ap);
}
#else
-static inline void debug(const char *format, ...) { }
+static inline void debug(const char *format, ...)
+{
+}
#endif
#ifdef LWS_OPENSSL_SUPPORT
+<h2>libwebsocket_context_destroy - Destroy the websocket context</h2>
+<i>void</i>
+<b>libwebsocket_context_destroy</b>
+(<i>struct libwebsocket_context *</i> <b>this</b>)
+<h3>Arguments</h3>
+<dl>
+<dt><b>this</b>
+<dd>Websocket context
+</dl>
+<h3>Description</h3>
+<blockquote>
+This function closes any active connections and then frees the
+context. After calling this, any further use of the context is
+undefined.
+</blockquote>
+<hr>
+<h2>libwebsocket_service - Service any pending websocket activity</h2>
+<i>int</i>
+<b>libwebsocket_service</b>
+(<i>struct libwebsocket_context *</i> <b>this</b>,
+<i>int</i> <b>timeout_ms</b>)
+<h3>Arguments</h3>
+<dl>
+<dt><b>this</b>
+<dd>Websocket context
+<dt><b>timeout_ms</b>
+<dd>Timeout for poll; 0 means return immediately if nothing needed
+service otherwise block and service immediately, returning
+after the timeout if nothing needed service.
+</dl>
+<h3>Description</h3>
+<blockquote>
+This function deals with any pending websocket traffic, for three
+kinds of event. It handles these events on both server and client
+types of connection the same.
+<p>
+1) Accept new connections to our context's server
+<p>
+2) Perform pending broadcast writes initiated from other forked
+processes (effectively serializing asynchronous broadcasts)
+<p>
+3) Call the receive callback for incoming frame data received by
+server or client connections.
+<p>
+You need to call this service function periodically to all the above
+functions to happen; if your application is single-threaded you can
+just call it in your main event loop.
+<p>
+Alternatively you can fork a new process that asynchronously handles
+calling this service in a loop. In that case you are happy if this
+call blocks your thread until it needs to take care of something and
+would call it with a large nonzero timeout. Your loop then takes no
+CPU while there is nothing happening.
+<p>
+If you are calling it in a single-threaded app, you don't want it to
+wait around blocking other things in your loop from happening, so you
+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_create_context - Create the websocket handler</h2>
<i>struct libwebsocket_context *</i>
<b>libwebsocket_create_context</b>
libwebsocket_client_close(wsi_dumb);
libwebsocket_client_close(wsi_mirror);
+ libwebsocket_context_destroy(context);
+
return 0;
usage:
/*
* libwebsockets-test-server - libwebsockets test implementation
*
- * Copyright (C) 2010 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010-2011 Andy Green <andy@warmcat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
struct libwebsocket_context *context;
fprintf(stderr, "libwebsockets test server\n"
- "(C) Copyright 2010 Andy Green <andy@warmcat.com> "
+ "(C) Copyright 2010-2011 Andy Green <andy@warmcat.com> "
"licensed under LGPL2.1\n");
while (n >= 0) {
#endif
+ libwebsocket_context_destroy(context);
+
return 0;
}