summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorAndy Green <andy@warmcat.com>2010-11-12 10:44:16 +0000
committerAndy Green <andy@warmcat.com>2010-11-12 10:44:16 +0000
commit4f3943a8f818be392ac9f059589f341ff311affa (patch)
tree1da5d0d3a7b519d89b9d1ec7b464d7c917fcb903 /lib
parentab7d933d9d7aa961a3ae398adf42d401334e066e (diff)
move-to-automatic-protocol-list-scheme.patch
Signed-off-by: Andy Green <andy@warmcat.com>
Diffstat (limited to 'lib')
-rw-r--r--lib/Makefile.am4
-rw-r--r--lib/Makefile.in4
-rw-r--r--lib/handshake.c52
-rw-r--r--lib/libwebsockets.c119
-rw-r--r--lib/libwebsockets.h37
-rw-r--r--lib/parsers.c6
-rw-r--r--lib/private-libwebsockets.h6
7 files changed, 158 insertions, 70 deletions
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 78ced38..7cc2120 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -12,7 +12,7 @@ libwebsockets_la_LDFLAGS=-version-info 0:1
all-local:
../scripts/kernel-doc -html \
libwebsockets.c \
- parsers.c \
- ../test-server/test-server.c \
+ parsers.c \
+ libwebsockets.h \
> ../libwebsockets-api-doc.html
diff --git a/lib/Makefile.in b/lib/Makefile.in
index 493db5b..dcf4a67 100644
--- a/lib/Makefile.in
+++ b/lib/Makefile.in
@@ -578,8 +578,8 @@ uninstall-am: uninstall-includeHEADERS uninstall-libLTLIBRARIES
all-local:
../scripts/kernel-doc -html \
libwebsockets.c \
- parsers.c \
- ../test-server/test-server.c \
+ parsers.c \
+ libwebsockets.h \
> ../libwebsockets-api-doc.html
# Tell versions [3.59,3.63) of GNU make to not export all variables.
diff --git a/lib/handshake.c b/lib/handshake.c
index 2ca7938..7deb581 100644
--- a/lib/handshake.c
+++ b/lib/handshake.c
@@ -94,9 +94,9 @@ libwebsocket_read(struct libwebsocket *wsi, unsigned char * buf, size_t len)
if (!wsi->utf8_token[WSI_TOKEN_UPGRADE].token_len ||
!wsi->utf8_token[WSI_TOKEN_CONNECTION].token_len) {
- if (wsi->callback)
- (wsi->callback)(wsi, LWS_CALLBACK_HTTP,
- &wsi->user_space[0],
+ if (wsi->protocol->callback)
+ (wsi->protocol->callback)(wsi, LWS_CALLBACK_HTTP,
+ &wsi->user_space,
wsi->utf8_token[WSI_TOKEN_GET_URI].token, 0);
wsi->state = WSI_STATE_HTTP;
return 0;
@@ -132,11 +132,41 @@ libwebsocket_read(struct libwebsocket *wsi, unsigned char * buf, size_t len)
/* Make sure user side is happy about protocol */
- if (wsi->callback)
- wsi->callback(wsi, LWS_CALLBACK_PROTOCOL_FILTER,
- &wsi->user_space[0],
- wsi->utf8_token[WSI_TOKEN_PROTOCOL].token,
- 0);
+ while (wsi->protocol->callback) {
+
+ if (wsi->utf8_token[WSI_TOKEN_PROTOCOL].token == NULL) {
+ if (wsi->protocol->name == NULL)
+ break;
+ } else
+ if (strcmp(
+ wsi->utf8_token[WSI_TOKEN_PROTOCOL].token,
+ wsi->protocol->name) == 0)
+ break;
+
+ wsi->protocol++;
+ }
+ if (wsi->protocol->callback == NULL) {
+ if (wsi->utf8_token[WSI_TOKEN_PROTOCOL].token == NULL)
+ fprintf(stderr, "[no protocol] "
+ "not supported (use NULL .name)\n");
+ else
+ fprintf(stderr, "Requested protocol %s "
+ "not supported\n",
+ wsi->utf8_token[WSI_TOKEN_PROTOCOL].token);
+ goto bail;
+ }
+
+ /* allocate the per-connection user memory (if any) */
+
+ if (wsi->protocol->per_session_data_size) {
+ wsi->user_space = malloc(
+ wsi->protocol->per_session_data_size);
+ if (wsi->user_space == NULL) {
+ fprintf(stderr, "Out of memory for "
+ "conn user space\n");
+ goto bail;
+ }
+ }
/* create the response packet */
@@ -243,9 +273,9 @@ libwebsocket_read(struct libwebsocket *wsi, unsigned char * buf, size_t len)
/* notify user code that we're ready to roll */
- if (wsi->callback)
- wsi->callback(wsi, LWS_CALLBACK_ESTABLISHED,
- &wsi->user_space[0], NULL, 0);
+ if (wsi->protocol->callback)
+ wsi->protocol->callback(wsi, LWS_CALLBACK_ESTABLISHED,
+ &wsi->user_space, NULL, 0);
break;
case WSI_STATE_ESTABLISHED:
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 @@ extern int
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 @@ libwebsocket_close_and_free_session(struct libwebsocket *wsi)
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 @@ libwebsocket_close_and_free_session(struct libwebsocket *wsi)
#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 @@ libwebsocket_close_and_free_session(struct libwebsocket *wsi)
*/
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 @@ int libwebsocket_create_server(int port,
/* 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 @@ int libwebsocket_create_server(int port,
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 @@ int libwebsocket_create_server(int port,
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 @@ int libwebsocket_create_server(int port,
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 @@ int libwebsocket_create_server(int port,
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 @@ int libwebsocket_create_server(int port,
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 @@ int libwebsocket_create_server(int port,
if (!(fds[client].revents & POLLIN))
continue;
-
-// fprintf(stderr, "POLLIN\n");
#ifdef LWS_OPENSSL_SUPPORT
if (use_ssl)
@@ -371,8 +412,6 @@ int libwebsocket_create_server(int port,
#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 @@ int libwebsocket_create_server(int port,
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 @@ poll_out:
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;
diff --git a/lib/libwebsockets.h b/lib/libwebsockets.h
index b1588b1..24042fc 100644
--- a/lib/libwebsockets.h
+++ b/lib/libwebsockets.h
@@ -29,7 +29,6 @@ enum libwebsocket_callback_reasons {
LWS_CALLBACK_SEND,
LWS_CALLBACK_RECEIVE,
LWS_CALLBACK_HTTP,
- LWS_CALLBACK_PROTOCOL_FILTER,
};
enum libwebsocket_write_protocol {
@@ -40,14 +39,36 @@ enum libwebsocket_write_protocol {
struct libwebsocket;
+/**
+ * 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
+ * @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
+ * @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 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 {
+ const char *name;
+ int (*callback)(struct libwebsocket * wsi,
+ enum libwebsocket_callback_reasons reason, void * user,
+ void *in, size_t len);
+ size_t per_session_data_size;
+};
+
extern int libwebsocket_create_server(int port,
- int (*callback)(struct libwebsocket *wsi,
- enum libwebsocket_callback_reasons reason,
- void *user, void *in, size_t len),
- size_t user_space,
- const char * ssl_cert_filepath,
- const char * ssl_private_key_filepath,
- int gid, int uid);
+ const struct libwebsocket_protocols *protocols,
+ const char * ssl_cert_filepath,
+ const char * ssl_private_key_filepath, int gid, int uid);
/*
* IMPORTANT NOTICE!
diff --git a/lib/parsers.c b/lib/parsers.c
index 9a767f8..52cd126 100644
--- a/lib/parsers.c
+++ b/lib/parsers.c
@@ -210,9 +210,9 @@ static int libwebsocket_rx_sm(struct libwebsocket *wsi, unsigned char c)
if (wsi->rx_user_buffer_head != MAX_USER_RX_BUFFER)
break;
issue:
- if (wsi->callback)
- wsi->callback(wsi, LWS_CALLBACK_RECEIVE,
- &wsi->user_space[0],
+ if (wsi->protocol->callback)
+ wsi->protocol->callback(wsi, LWS_CALLBACK_RECEIVE,
+ &wsi->user_space,
&wsi->rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING],
wsi->rx_user_buffer_head);
wsi->rx_user_buffer_head = 0;
diff --git a/lib/private-libwebsockets.h b/lib/private-libwebsockets.h
index 27f495a..d3789f1 100644
--- a/lib/private-libwebsockets.h
+++ b/lib/private-libwebsockets.h
@@ -121,8 +121,7 @@ struct lws_tokens {
*/
struct libwebsocket {
- int (*callback)(struct libwebsocket *,
- enum libwebsocket_callback_reasons reason, void *, void *, size_t);
+ const struct libwebsocket_protocols *protocol;
enum lws_connection_states state;
@@ -145,8 +144,7 @@ struct libwebsocket {
SSL *ssl;
#endif
- /* last */
- char user_space[0];
+ void *user_space;
};
extern void