move-to-automatic-protocol-list-scheme.patch
Signed-off-by: Andy Green <andy@warmcat.com>
diff --git a/lib/libwebsockets.c b/lib/libwebsockets.c
index 11ab790..60ecde2 100644
--- a/lib/libwebsockets.c
+++ b/lib/libwebsockets.c
@@ -31,6 +31,48 @@
libwebsocket_read(struct libwebsocket *wsi, unsigned char * buf, size_t len);
+/* document the generic callback (it's a fake prototype under this) */
+/**
+ * callback() - User server actions
+ * @wsi: Opaque websocket instance pointer
+ * @reason: The reason for the call
+ * @user: Pointer to per-session user data allocated by library
+ * @in: Pointer used for some callback reasons
+ * @len: Length set for some callback reasons
+ *
+ * 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_ESTABLISHED: after successful websocket handshake
+ *
+ * LWS_CALLBACK_CLOSED: when the websocket session ends
+ *
+ * LWS_CALLBACK_SEND: opportunity 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_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
+ * 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,
+ void *in, size_t len);
+
void
libwebsocket_close_and_free_session(struct libwebsocket *wsi)
@@ -39,8 +81,8 @@
wsi->state = WSI_STATE_DEAD_SOCKET;
- if (wsi->callback && n == WSI_STATE_ESTABLISHED)
- wsi->callback(wsi, LWS_CALLBACK_CLOSED, &wsi->user_space[0],
+ if (wsi->protocol->callback && n == WSI_STATE_ESTABLISHED)
+ wsi->protocol->callback(wsi, LWS_CALLBACK_CLOSED, &wsi->user_space,
NULL, 0);
for (n = 0; n < WSI_TOKEN_COUNT; n++)
@@ -62,17 +104,18 @@
#ifdef LWS_OPENSSL_SUPPORT
}
#endif
+ if (wsi->user_space)
+ free(wsi->user_space);
+
free(wsi);
}
/**
* libwebsocket_create_server() - Create the listening websockets server
* @port: Port to listen on
- * @callback: The callback in user code to perform actual serving
- * @user_area_size: How much memory to allocate per connection session
- * which will be used by the user application to store
- * per-session data. A pointer to this space is given
- * when the user callback is called.
+ * @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.
* @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
@@ -98,10 +141,7 @@
*/
int libwebsocket_create_server(int port,
- int (*callback)(struct libwebsocket *,
- enum libwebsocket_callback_reasons,
- void *, void *, size_t),
- size_t user_area_size,
+ const struct libwebsocket_protocols *protocols,
const char * ssl_cert_filepath,
const char * ssl_private_key_filepath,
int gid, int uid)
@@ -185,14 +225,7 @@
/* SSL is happy and has a cert it's content with */
}
#endif
-
- if (!callback) {
- fprintf(stderr, "callback is not optional!\n");
- return -1;
- }
-
- /* sit there listening for connects, accept and spawn session servers */
-
+
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
fprintf(stderr, "ERROR opening socket");
@@ -226,7 +259,7 @@
if (n)
return sockfd;
- // drop any root privs for this thread
+ /* drop any root privs for this thread */
if (gid != -1)
if (setgid(gid))
@@ -235,8 +268,11 @@
if (setuid(uid))
fprintf(stderr, "setuid: %s\n", strerror(errno));
- /* we are running in a forked subprocess now */
-
+ /*
+ * sit there listening for connects, accept and service connections
+ * in a poll loop, without any further forking
+ */
+
listen(sockfd, 5);
fprintf(stderr, " Listening on port %d\n", port);
@@ -273,8 +309,7 @@
continue;
}
- wsi[fds_count] = malloc(sizeof(struct libwebsocket) +
- user_area_size);
+ wsi[fds_count] = malloc(sizeof(struct libwebsocket));
if (!wsi[fds_count])
return -1;
@@ -313,11 +348,10 @@
ntohs(cli_addr.sin_port), fd,
SSL_get_version(wsi[fds_count]->ssl));
- } else {
-// fprintf(stderr, "accepted new conn port %u on fd=%d\n",
-// ntohs(cli_addr.sin_port), fd);
- }
+ } else
#endif
+ debug("accepted new conn port %u on fd=%d\n",
+ ntohs(cli_addr.sin_port), fd);
/* intialize the instance struct */
@@ -330,11 +364,20 @@
wsi[fds_count]->utf8_token[n].token_len = 0;
}
- wsi[fds_count]->callback = callback;
+ /*
+ * these can only be set once the protocol is known
+ * we set an unestablished connection's protocol pointer
+ * to the start of the supported list, so it can look
+ * for matching ones during the handshake
+ */
+ wsi[fds_count]->protocol = protocols;
+ wsi[fds_count]->user_space = NULL;
+
/*
* Default protocol is 76
* After 76, there's a header specified to inform which
- * draft the client wants
+ * draft the client wants, when that's seen we modify
+ * the individual connection's spec revision accordingly
*/
wsi[fds_count]->ietf_spec_revision = 76;
@@ -361,8 +404,6 @@
if (!(fds[client].revents & POLLIN))
continue;
-
-// fprintf(stderr, "POLLIN\n");
#ifdef LWS_OPENSSL_SUPPORT
if (use_ssl)
@@ -371,8 +412,6 @@
#endif
n = recv(fds[client].fd, buf, sizeof(buf), 0);
-// fprintf(stderr, "read returned %d\n", n);
-
if (n < 0) {
fprintf(stderr, "Socket read returned %d\n", n);
continue;
@@ -389,7 +428,10 @@
if (libwebsocket_read(wsi[client], buf, n) >= 0)
continue;
- /* it closed and nuked wsi[client] */
+ /*
+ * it closed and nuked wsi[client], so remove the
+ * socket handle and wsi from our service list
+ */
nuke_this:
for (n = client; n < fds_count - 1; n++) {
fds[n] = fds[n + 1];
@@ -404,12 +446,9 @@
if (wsi[client]->state != WSI_STATE_ESTABLISHED)
continue;
-
- if (!wsi[client]->callback)
- continue;
- wsi[client]->callback(wsi[client], LWS_CALLBACK_SEND,
- &wsi[client]->user_space[0], NULL, 0);
+ wsi[client]->protocol->callback(wsi[client], LWS_CALLBACK_SEND,
+ &wsi[client]->user_space, NULL, 0);
}
continue;