/*
* This is totally opaque to code using the library. It's exported as a
- * forward-reference pointer-only declaration.
+ * forward-reference pointer-only declaration; the user can use the pointer with
+ * other APIs to get information out of it.
*/
struct libwebsocket {
{ "\x0d\x0a", 2 },
};
+/**
+ * libwebsocket_create_server() - Create the listening websockets server
+ * @port: Port to listen on
+ * @callback: The callback in user code to perform actual serving
+ * @protocol: Which version of the websockets protocol (currently 76)
+ *
+ * This function forks to create the listening socket and takes care
+ * of all initialization in one step.
+ *
+ * The callback function is called for a handful of events including
+ * http requests coming in, websocket connections becoming
+ * established, and data arriving; it's also called periodically to allow
+ * async transmission.
+ *
+ * The server created is a simple http server by default; part of the
+ * websocket standard is upgrading this http connection to a websocket one.
+ *
+ * This allows the same server to provide files like scripts and favicon /
+ * images or whatever over http and dynamic data over websockets all in
+ * one place; they're all handled in the user callback.
+ */
int libwebsocket_create_server(int port,
int (*callback)(struct libwebsocket *,
}
}
-void libwebsocket_close(struct libwebsocket *wsi)
+static void libwebsocket_close(struct libwebsocket *wsi)
{
int n;
free(wsi->utf8_token[n].token);
}
+/**
+ * libwebsocket_get_uri() - Return the URI path being requested
+ * @wsi: Websocket instance
+ *
+ * The user code can find out the local path being opened from this
+ * call, it's valid on HTTP or established websocket connections.
+ * If the client opened the connection with "http://127.0.0.1/xyz/abc.d"
+ * then this call will return a pointer to "/xyz/abc.d"
+ */
+
const char * libwebsocket_get_uri(struct libwebsocket *wsi)
{
if (wsi->utf8_token[WSI_TOKEN_GET_URI].token)
* machine that is completely independent of packet size.
*/
-int libwebsocket_read(struct libwebsocket *wsi, unsigned char * buf, size_t len)
+static int
+libwebsocket_read(struct libwebsocket *wsi, unsigned char * buf, size_t len)
{
size_t n;
char *p;
return -1;
}
-
-/*
- * notice, we will use up to LWS_SEND_BUFFER_PRE_PADDING bytes BEFORE the
- * buffer pointer given and LWS_SEND_BUFFER_POST_PADDING bytes AFTER
- * buf + len !!! Caller must allocate and offset pointer accordingly!
+/**
+ * libwebsocket_write() - Apply protocol then write data to client
+ * @wsi: Websocket instance (available from user callback)
+ * @buf: The data to send. For data being sent on a websocket
+ * connection (ie, not default http), this buffer MUST have
+ * LWS_SEND_BUFFER_PRE_PADDING bytes valid BEFORE the pointer
+ * and an additional LWS_SEND_BUFFER_POST_PADDING bytes valid
+ * in the buffer after (buf + len). This is so the protocol
+ * header and trailer data can be added in-situ.
+ * @len: Count of the data bytes in the payload starting from buf
+ * @protocol: Use LWS_WRITE_HTTP to reply to an http connection, and one
+ * of LWS_WRITE_BINARY or LWS_WRITE_TEXT to send appropriate
+ * data on a websockets connection. Remember to allow the extra
+ * bytes before and after buf if LWS_WRITE_BINARY or LWS_WRITE_TEXT
+ * are used.
+ *
+ * This function provides the way to issue data back to the client
+ * for both http and websocket protocols.
*
- * This lets us send packets in one write() action including the protocol
- * pre- and post- data without copying the payload around.
+ * In the case of sending using websocket protocol, be sure to allocate
+ * valid storage before and after buf as explained above. This scheme
+ * allows maximum efficiency of sending data and protocol in a single
+ * packet while not burdening the user code with any protocol knowledge.
*/
int libwebsocket_write(struct libwebsocket * wsi, unsigned char *buf,
}
}
+/**
+ * libwebsockets_serve_http_file() - Send a file back to the client using http
+ * @wsi: Websocket instance (available from user callback)
+ * @file: The file to issue over http
+ * @content_type: The http content type, eg, text/html
+ *
+ * This function is intended to be called from the callback in response
+ * to http requests from the client. It allows the callback to issue
+ * local files down the http link in a single step.
+ */
+
int libwebsockets_serve_http_file(struct libwebsocket *wsi, const char * file,
const char * content_type)
{
+#ifndef __LIBWEBSOCKET_H__
+#define __LIBWEBSOCKET_H__
+
enum libwebsocket_callback_reasons {
LWS_CALLBACK_ESTABLISHED,
* So for example you need this kind of code to use libwebsocket_write with a
* 128-byte payload
*
- * char buf[LWS_SEND_BUFFER_PRE_PADDING + 128 + LWS_SEND_BUFFER_POST_PADDING];
+ * char buf[LWS_SEND_BUFFER_PRE_PADDING + 128 + LWS_SEND_BUFFER_POST_PADDING];
*
- * // fill your part of the buffer... for example here it's all zeros
- * memset(&buf[LWS_SEND_BUFFER_PRE_PADDING], 0, 128);
+ * // fill your part of the buffer... for example here it's all zeros
+ * memset(&buf[LWS_SEND_BUFFER_PRE_PADDING], 0, 128);
*
- * libwebsocket_write(wsi, &buf[LWS_SEND_BUFFER_PRE_PADDING], 128);
+ * libwebsocket_write(wsi, &buf[LWS_SEND_BUFFER_PRE_PADDING], 128);
*
* When sending LWS_WRITE_HTTP, there is no protocol addition and you can just
* use the whole buffer without taking care of the above.
enum libwebsocket_write_protocol protocol);
extern const char *
libwebsocket_get_uri(struct libwebsocket *wsi);
+
extern int
libwebsockets_serve_http_file(struct libwebsocket *wsi, const char * file,
const char * content_type);
+
+#endif
#include <getopt.h>
#include <string.h>
-
#include "libwebsockets.h"
/*
* Shows how to use libwebsocket
*/
-
static int port = 7681;
static int ws_protocol = 76;
+/*
+ * libwebsockets needs this one callback in your server application, it's
+ * called for a handful of different reasons during the connection lifecycle.
+ *
+ * All the serving actions occur in the callback but the websocket protocol
+ * stuff is already handled by the library.
+ */
+
static int websocket_callback(struct libwebsocket * wsi,
- enum libwebsocket_callback_reasons reason, void *in, size_t len)
+ enum libwebsocket_callback_reasons reason, void *in, size_t len)
{
int n;
- char buf[LWS_SEND_BUFFER_PRE_PADDING + 512 + LWS_SEND_BUFFER_POST_PADDING];
+ char buf[LWS_SEND_BUFFER_PRE_PADDING + 512 +
+ LWS_SEND_BUFFER_POST_PADDING];
static int bump;
- static int slow;
char *p = &buf[LWS_SEND_BUFFER_PRE_PADDING];
const char *uri;
switch (reason) {
+ /*
+ * Websockets session handshake completed and is established
+ */
case LWS_CALLBACK_ESTABLISHED:
fprintf(stderr, "Websocket connection established\n");
- slow = 100;
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:
-// slow--;
-// if (slow) {
-// usleep(10000);
-// break;
-// }
-// slow = 20;
n = sprintf(p, "%d", bump++);
n = libwebsocket_write(wsi, (unsigned char *)p, n, 0);
if (n < 0) {
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);
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:
- /*
- * 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.
- */
+
uri = libwebsocket_get_uri(wsi);
- if (uri == NULL)
- fprintf(stderr, "LWS_CALLBACK_HTTP NULL URI\n");
- else
- fprintf(stderr, "LWS_CALLBACK_HTTP '%s'\n", uri);
-
if (uri && strcmp(uri, "/favicon.ico") == 0) {
- if (libwebsockets_serve_http_file(wsi, "./favicon.ico", "image/x-icon")) {
- fprintf(stderr, "Failed to send favicon file\n");
- }
+ if (libwebsockets_serve_http_file(wsi, "./favicon.ico",
+ "image/x-icon"))
+ fprintf(stderr, "Failed to send favicon\n");
break;
}
/* send the script... when it runs it'll start websockets */
- if (libwebsockets_serve_http_file(wsi, "./test.html", "text/html")) {
+ if (libwebsockets_serve_http_file(wsi, "./test.html",
+ "text/html")) {
fprintf(stderr, "Failed to send HTTP file\n");
}
break;
}
+
return 0;
}
{
int n = 0;
- fprintf(stderr, "libwebsockets test server\nCopyright 2010 Andy Green <andy@warmcat.com> licensed under GPL2\n");
+ fprintf(stderr, "libwebsockets test server\n"
+ "Copyright 2010 Andy Green <andy@warmcat.com> "
+ "licensed under GPL2\n");
while (n >= 0) {
n = getopt_long(argc, argv, "hp:r:", options, NULL);
ws_protocol = atoi(optarg);
break;
case 'h':
- fprintf(stderr, "Usage: test-server [--port=<p>] [--protocol=<v>]\n");
+ fprintf(stderr, "Usage: test-server "
+ "[--port=<p>] [--protocol=<v>]\n");
exit(1);
}
-
}
- if (libwebsocket_create_server(port, websocket_callback, ws_protocol) < 0) {
+ if (libwebsocket_create_server(port, websocket_callback, ws_protocol) <
+ 0) {
fprintf(stderr, "libwebsocket init failed\n");
return -1;
}
+
+ /* just sit there until killed */
while (1)
- sleep(1);
+ sleep(10);
return 0;
}