move-to-automatic-protocol-list-scheme.patch
Signed-off-by: Andy Green <andy@warmcat.com>
This commit is contained in:
parent
ab7d933d9d
commit
4f3943a8f8
9 changed files with 329 additions and 208 deletions
|
@ -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
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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!
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,9 +1,72 @@
|
|||
<h2>callback - User server actions</h2>
|
||||
<i>int</i>
|
||||
<b>callback</b>
|
||||
(<i>struct libwebsocket *</i> <b>wsi</b>,
|
||||
<i>enum libwebsocket_callback_reasons</i> <b>reason</b>,
|
||||
<i>void *</i> <b>user</b>,
|
||||
<i>void *</i> <b>in</b>,
|
||||
<i>size_t</i> <b>len</b>)
|
||||
<h3>Arguments</h3>
|
||||
<dl>
|
||||
<dt><b>wsi</b>
|
||||
<dd>Opaque websocket instance pointer
|
||||
<dt><b>reason</b>
|
||||
<dd>The reason for the call
|
||||
<dt><b>user</b>
|
||||
<dd>Pointer to per-session user data allocated by library
|
||||
<dt><b>in</b>
|
||||
<dd>Pointer used for some callback reasons
|
||||
<dt><b>len</b>
|
||||
<dd>Length set for some callback reasons
|
||||
</dl>
|
||||
<h3>Description</h3>
|
||||
<blockquote>
|
||||
This callback is the way the user controls what is served. All the
|
||||
protocol detail is hidden and handled by the library.
|
||||
<p>
|
||||
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.
|
||||
<p>
|
||||
You get an opportunity to initialize user data when called back with
|
||||
LWS_CALLBACK_ESTABLISHED reason.
|
||||
</blockquote>
|
||||
<h3>LWS_CALLBACK_ESTABLISHED</h3>
|
||||
<blockquote>
|
||||
after successful websocket handshake
|
||||
</blockquote>
|
||||
<h3>LWS_CALLBACK_CLOSED</h3>
|
||||
<blockquote>
|
||||
when the websocket session ends
|
||||
</blockquote>
|
||||
<h3>LWS_CALLBACK_SEND</h3>
|
||||
<blockquote>
|
||||
opportunity to send to client (you would use
|
||||
<b>libwebsocket_write</b> taking care about the
|
||||
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
|
||||
</blockquote>
|
||||
<h3>LWS_CALLBACK_HTTP</h3>
|
||||
<blockquote>
|
||||
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.
|
||||
<tt><b>in</b></tt> points to the URI path requested and
|
||||
<b>libwebsockets_serve_http_file</b> makes it very
|
||||
simple to send back a file to the client.
|
||||
</blockquote>
|
||||
<hr>
|
||||
<h2>libwebsocket_create_server - Create the listening websockets server</h2>
|
||||
<i>int</i>
|
||||
<b>libwebsocket_create_server</b>
|
||||
(<i>int</i> <b>port</b>,
|
||||
<i>int (*</i><b>callback</b>) <i>(struct libwebsocket *, enum libwebsocket_callback_reasons, void *, void *, size_t)</i>,
|
||||
<i>size_t</i> <b>user_area_size</b>,
|
||||
<i>const struct libwebsocket_protocols *</i> <b>protocols</b>,
|
||||
<i>const char *</i> <b>ssl_cert_filepath</b>,
|
||||
<i>const char *</i> <b>ssl_private_key_filepath</b>,
|
||||
<i>int</i> <b>gid</b>,
|
||||
|
@ -12,13 +75,10 @@
|
|||
<dl>
|
||||
<dt><b>port</b>
|
||||
<dd>Port to listen on
|
||||
<dt><b>callback</b>
|
||||
<dd>The callback in user code to perform actual serving
|
||||
<dt><b>user_area_size</b>
|
||||
<dd>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.
|
||||
<dt><b>protocols</b>
|
||||
<dd>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.
|
||||
<dt><b>ssl_cert_filepath</b>
|
||||
<dd>If libwebsockets was compiled to use ssl, and you want
|
||||
to listen using SSL, set to the filepath to fetch the
|
||||
|
@ -109,3 +169,31 @@ to http requests from the client. It allows the callback to issue
|
|||
local files down the http link in a single step.
|
||||
</blockquote>
|
||||
<hr>
|
||||
<h2>struct libwebsocket_protocols - List of protocols and handlers server supports.</h2>
|
||||
<b>struct libwebsocket_protocols</b> {<br>
|
||||
<i>const char *</i> <b>name</b>;<br>
|
||||
<i>int (*</i><b>callback</b>) <i>(struct libwebsocket * wsi,enum libwebsocket_callback_reasons reason, void * user,void *in, size_t len)</i>;<br>
|
||||
<i>size_t</i> <b>per_session_data_size</b>;<br>
|
||||
};<br>
|
||||
<h3>Members</h3>
|
||||
<dl>
|
||||
<dt><b>name</b>
|
||||
<dd>Protocol name that must match the one given in the client
|
||||
Javascript new WebSocket(url, 'protocol') name
|
||||
<dt><b>callback</b>
|
||||
<dd>The service callback used for this protocol. It allows the
|
||||
service action for an entire protocol to be encapsulated in
|
||||
the protocol-specific callback
|
||||
<dt><b>per_session_data_size</b>
|
||||
<dd>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
|
||||
</dl>
|
||||
<h3>Description</h3>
|
||||
<blockquote>
|
||||
This structure represents one protocol supported by the server. An
|
||||
array of these structures is passed to <b>libwebsocket_create_server</b>
|
||||
allows as many protocols as you like to be handled by one server.
|
||||
</blockquote>
|
||||
<hr>
|
||||
|
|
|
@ -31,116 +31,14 @@
|
|||
static int port = 7681;
|
||||
static int use_ssl = 0;
|
||||
|
||||
struct per_session_data {
|
||||
int number;
|
||||
};
|
||||
/* this protocol server (always the first one) just knows how to do HTTP */
|
||||
|
||||
/**
|
||||
* libwebsocket_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.
|
||||
*
|
||||
* LWS_CALLBACK_PROTOCOL_FILTER: before the confirmation handshake is sent
|
||||
* the user callback is given a chance to confirm
|
||||
* it's OK with the protocol that was requested
|
||||
* from the client. The protocol string (which
|
||||
* may be NULL if no protocol header was sent)
|
||||
* can be found at parameter @in. Return 0 from
|
||||
* the callback to allow the connection or nonzero
|
||||
* to abort the connection.
|
||||
*/
|
||||
|
||||
static int websocket_callback(struct libwebsocket * wsi,
|
||||
static int callback_http(struct libwebsocket * wsi,
|
||||
enum libwebsocket_callback_reasons reason, void * user,
|
||||
void *in, size_t len)
|
||||
{
|
||||
int n;
|
||||
char buf[LWS_SEND_BUFFER_PRE_PADDING + 512 +
|
||||
LWS_SEND_BUFFER_POST_PADDING];
|
||||
char *p = &buf[LWS_SEND_BUFFER_PRE_PADDING];
|
||||
struct per_session_data * pss = user;
|
||||
|
||||
switch (reason) {
|
||||
/*
|
||||
* Websockets session handshake completed and is established
|
||||
*/
|
||||
case LWS_CALLBACK_ESTABLISHED:
|
||||
fprintf(stderr, "Websocket connection established\n");
|
||||
pss->number = 0;
|
||||
break;
|
||||
|
||||
/*
|
||||
* Websockets session is closed
|
||||
*/
|
||||
case LWS_CALLBACK_CLOSED:
|
||||
fprintf(stderr, "Websocket connection closed\n");
|
||||
break;
|
||||
|
||||
/*
|
||||
* Opportunity for us to send something on the connection
|
||||
*/
|
||||
case LWS_CALLBACK_SEND:
|
||||
n = sprintf(p, "%d", pss->number++);
|
||||
n = libwebsocket_write(wsi, (unsigned char *)p, n,
|
||||
LWS_WRITE_TEXT);
|
||||
if (n < 0) {
|
||||
fprintf(stderr, "ERROR writing to socket");
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
/*
|
||||
* Something has arrived for us on the connection, it's len bytes long
|
||||
* and is available at *in
|
||||
*/
|
||||
case LWS_CALLBACK_RECEIVE:
|
||||
fprintf(stderr, "Received %d bytes payload\n", (int)len);
|
||||
if (strcmp(in, "reset\n") == 0)
|
||||
pss->number = 0;
|
||||
break;
|
||||
|
||||
/*
|
||||
* The client has asked us for something in normal HTTP mode,
|
||||
* not websockets mode. Normally it means we want to send
|
||||
* our script / html to the client, and when that script runs
|
||||
* it will start up separate websocket connections.
|
||||
*
|
||||
* Interpret the URI string to figure out what is needed to send
|
||||
*/
|
||||
|
||||
case LWS_CALLBACK_HTTP:
|
||||
|
||||
fprintf(stderr, "serving HTTP URI %s\n", in);
|
||||
|
||||
if (in && strcmp(in, "/favicon.ico") == 0) {
|
||||
|
@ -157,34 +55,82 @@ static int websocket_callback(struct libwebsocket * wsi,
|
|||
fprintf(stderr, "Failed to send HTTP file\n");
|
||||
break;
|
||||
|
||||
/*
|
||||
* This is our chance to choose if we support one of the requested
|
||||
* protocols or not. in points to the protocol string. Nonzero return
|
||||
* aborts the connection handshake
|
||||
*/
|
||||
|
||||
case LWS_CALLBACK_PROTOCOL_FILTER:
|
||||
if (in == NULL) {
|
||||
fprintf(stderr, "Client did not request protocol\n");
|
||||
/* reject it */
|
||||
return 1;
|
||||
}
|
||||
fprintf(stderr, "Client requested protocol '%s'\n", in);
|
||||
if (strcmp(in, "dumb-increment-protocol") == 0)
|
||||
/* accept it */
|
||||
return 0;
|
||||
|
||||
/* reject the connection */
|
||||
return 1;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* dumb_increment protocol */
|
||||
|
||||
struct per_session_data__dumb_increment {
|
||||
int number;
|
||||
};
|
||||
|
||||
static int
|
||||
callback_dumb_increment(struct libwebsocket * wsi,
|
||||
enum libwebsocket_callback_reasons reason,
|
||||
void * user, void *in, size_t len)
|
||||
{
|
||||
int n;
|
||||
char buf[LWS_SEND_BUFFER_PRE_PADDING + 512 +
|
||||
LWS_SEND_BUFFER_POST_PADDING];
|
||||
unsigned char *p = (unsigned char *)&buf[LWS_SEND_BUFFER_PRE_PADDING];
|
||||
struct per_session_data__dumb_increment * pss = user;
|
||||
|
||||
switch (reason) {
|
||||
|
||||
case LWS_CALLBACK_ESTABLISHED:
|
||||
pss->number = 0;
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_SEND:
|
||||
n = sprintf(p, "%d", pss->number++);
|
||||
n = libwebsocket_write(wsi, p, n, LWS_WRITE_TEXT);
|
||||
if (n < 0) {
|
||||
fprintf(stderr, "ERROR writing to socket");
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_RECEIVE:
|
||||
if (len < 6)
|
||||
break;
|
||||
if (strcmp(in, "reset\n") == 0)
|
||||
pss->number = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* list of supported protocols and callbacks */
|
||||
|
||||
static const struct libwebsocket_protocols protocols[] = {
|
||||
{
|
||||
.name = "http-only",
|
||||
.callback = callback_http,
|
||||
.per_session_data_size = 0,
|
||||
},
|
||||
{
|
||||
.name = "dumb-increment-protocol",
|
||||
.callback = callback_dumb_increment,
|
||||
.per_session_data_size =
|
||||
sizeof(struct per_session_data__dumb_increment),
|
||||
},
|
||||
{ /* end of list */
|
||||
.callback = NULL
|
||||
}
|
||||
};
|
||||
|
||||
static struct option options[] = {
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "port", required_argument, NULL, 'p' },
|
||||
{ "protocol", required_argument, NULL, 'r' },
|
||||
{ "ssl", no_argument, NULL, 's' },
|
||||
{ NULL, 0, 0, 0 }
|
||||
};
|
||||
|
@ -202,7 +148,7 @@ int main(int argc, char **argv)
|
|||
"licensed under LGPL2.1\n");
|
||||
|
||||
while (n >= 0) {
|
||||
n = getopt_long(argc, argv, "hp:r:", options, NULL);
|
||||
n = getopt_long(argc, argv, "hp:", options, NULL);
|
||||
if (n < 0)
|
||||
continue;
|
||||
switch (n) {
|
||||
|
@ -214,7 +160,7 @@ int main(int argc, char **argv)
|
|||
break;
|
||||
case 'h':
|
||||
fprintf(stderr, "Usage: test-server "
|
||||
"[--port=<p>] [--protocol=<v>]\n");
|
||||
"[--port=<p>] [--ssl]\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
@ -222,9 +168,8 @@ int main(int argc, char **argv)
|
|||
if (!use_ssl)
|
||||
cert_path = key_path = NULL;
|
||||
|
||||
if (libwebsocket_create_server(port, websocket_callback,
|
||||
sizeof(struct per_session_data),
|
||||
cert_path, key_path, -1, -1) < 0) {
|
||||
if (libwebsocket_create_server(port, protocols,
|
||||
cert_path, key_path, -1, -1) < 0) {
|
||||
fprintf(stderr, "libwebsocket init failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue