1 --- libmicrohttpd-0.9.74/doc/chapters/websocket.inc.orig 1970-01-01 01:00:00.000000000 +0100
2 +++ libmicrohttpd-0.9.74/doc/chapters/websocket.inc 2021-12-23 21:39:46.569468012 +0100
4 +Websockets are a genuine way to implement push notifications,
5 +where the server initiates the communication while the client can be idle.
6 +Usually a HTTP communication is half-duplex and always requested by the client,
7 +but websockets are full-duplex and only initialized by the client.
8 +In the further communication both sites can use the websocket at any time
9 +to send data to the other site.
11 +To initialize a websocket connection the client sends a special HTTP request
12 +to the server and initializes
13 +a handshake between client and server which switches from the HTTP protocol
14 +to the websocket protocol.
15 +Thus both the server as well as the client must support websockets.
16 +If proxys are used, they must support websockets too.
17 +In this chapter we take a look on server and client, but with a focus on
18 +the server with @emph{libmicrohttpd}.
20 +Since version 0.9.52 @emph{libmicrohttpd} supports upgrading requests,
21 +which is required for switching from the HTTP protocol.
22 +Since version 0.9.74 the library @emph{libmicrohttpd_ws} has been added
23 +to support the websocket protocol.
25 +@heading Upgrading connections with libmicrohttpd
27 +To support websockets we need to enable upgrading of HTTP connections first.
28 +This is done by passing the flag @code{MHD_ALLOW_UPGRADE} to
29 +@code{MHD_start_daemon()}.
33 +daemon = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD |
34 + MHD_USE_THREAD_PER_CONNECTION |
38 + &access_handler, NULL,
44 +The next step is to turn a specific request into an upgraded connection.
45 +This done in our @code{access_handler} by calling
46 +@code{MHD_create_response_for_upgrade()}.
47 +An @code{upgrade_handler} will be passed to perform the low-level actions
50 +@emph{Please note that the socket here is just a regular socket as provided
51 +by the operating system.
52 +To use it as a websocket, some more steps from the following
53 +chapters are required.}
57 +static enum MHD_Result
58 +access_handler (void *cls,
59 + struct MHD_Connection *connection,
62 + const char *version,
63 + const char *upload_data,
64 + size_t *upload_data_size,
68 + /* some code to decide whether to upgrade or not */
71 + /* create the response for upgrade */
72 + response = MHD_create_response_for_upgrade (&upgrade_handler,
76 + /* additional headers, etc. */
79 + ret = MHD_queue_response (connection,
80 + MHD_HTTP_SWITCHING_PROTOCOLS,
82 + MHD_destroy_response (response);
90 +In the @code{upgrade_handler} we receive the low-level socket,
91 +which is used for the communication with the specific client.
92 +In addition to the low-level socket we get:
95 +Some data, which has been read too much while @emph{libmicrohttpd} was
96 +switching the protocols.
97 +This value is usually empty, because it would mean that the client
98 +has sent data before the handshake was complete.
101 +A @code{struct MHD_UpgradeResponseHandle} which is used to perform
102 +special actions like closing, corking or uncorking the socket.
103 +These commands are executed by passing the handle
104 +to @code{MHD_upgrade_action()}.
109 +Depending of the flags specified while calling @code{MHD_start_deamon()}
110 +our @code{upgrade_handler} is either executed in the same thread
111 +as our deamon or in a thread specific for each connection.
112 +If it is executed in the same thread then @code{upgrade_handler} is
113 +a blocking call for our webserver and
114 +we should finish it as fast as possible (i. e. by creating a thread and
115 +passing the information there).
116 +If @code{MHD_USE_THREAD_PER_CONNECTION} was passed to
117 +@code{MHD_start_daemon()} then a separate thread is used and
118 +thus our @code{upgrade_handler} needs not to start a separate thread.
120 +An @code{upgrade_handler}, which is called with a separate thread
121 +per connection, could look like this:
126 +upgrade_handler (void *cls,
127 + struct MHD_Connection *connection,
129 + const char *extra_in,
130 + size_t extra_in_size,
132 + struct MHD_UpgradeResponseHandle *urh)
135 + /* do something with the socket `fd` like `recv()` or `send()` */
138 + /* close the socket when it is not needed anymore */
139 + MHD_upgrade_action (urh,
140 + MHD_UPGRADE_ACTION_CLOSE);
146 +This is all you need to know for upgrading connections
147 +with @emph{libmicrohttpd}.
148 +The next chapters focus on using the websocket protocol
149 +with @emph{libmicrohttpd_ws}.
152 +@heading Websocket handshake with libmicrohttpd_ws
154 +To request a websocket connection the client must send
155 +the following information with the HTTP request:
159 +A @code{GET} request must be sent.
162 +The version of the HTTP protocol must be 1.1 or higher.
165 +A @code{Host} header field must be sent
168 +A @code{Upgrade} header field containing the keyword "websocket"
170 +Please note that the client could pass multiple protocols separated by comma.
173 +A @code{Connection} header field that includes the token "Upgrade"
175 +Please note that the client could pass multiple tokens separated by comma.
178 +A @code{Sec-WebSocket-Key} header field with a base64-encoded value.
179 +The decoded the value is 16 bytes long
180 +and has been generated randomly by the client.
183 +A @code{Sec-WebSocket-Version} header field with the value "13".
188 +Optionally the client can also send the following information:
193 +A @code{Origin} header field can be used to determine the source
194 +of the client (i. e. the website).
197 +A @code{Sec-WebSocket-Protocol} header field can contain a list
198 +of supported protocols by the client, which can be sent over the websocket.
201 +A @code{Sec-WebSocket-Extensions} header field which may contain extensions
202 +to the websocket protocol. The extensions must be registered by IANA.
207 +A valid example request from the client could look like this:
212 +Host: server.example.com
215 +Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
216 +Sec-WebSocket-Version: 13
221 +To complete the handshake the server must respond with
222 +some specific response headers:
226 +The HTTP response code @code{101 Switching Protocols} must be answered.
229 +An @code{Upgrade} header field containing the value "websocket" must be sent.
232 +A @code{Connection} header field containing the value "Upgrade" must be sent.
235 +A @code{Sec-WebSocket-Accept} header field containing a value, which
236 +has been calculated from the @code{Sec-WebSocket-Key} request header field,
242 +Optionally the server may send following headers:
247 +A @code{Sec-WebSocket-Protocol} header field containing a protocol
248 +of the list specified in the corresponding request header field.
251 +A @code{Sec-WebSocket-Extension} header field containing all used extensions
252 +of the list specified in the corresponding request header field.
257 +A valid websocket HTTP response could look like this:
260 +HTTP/1.1 101 Switching Protocols
263 +Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
268 +To upgrade a connection to a websocket the @emph{libmicrohttpd_ws} provides
269 +some helper functions for the @code{access_handler} callback function:
273 +@code{MHD_websocket_check_http_version()} checks whether the HTTP version
277 +@code{MHD_websocket_check_connection_header()} checks whether the value
278 +of the @code{Connection} request header field contains
279 +an "Upgrade" token (case-insensitive).
282 +@code{MHD_websocket_check_upgrade_header()} checks whether the value
283 +of the @code{Upgrade} request header field contains
284 +the "websocket" keyword (case-insensitive).
287 +@code{MHD_websocket_check_version_header()} checks whether the value
288 +of the @code{Sec-WebSocket-Version} request header field is "13".
291 +@code{MHD_websocket_create_accept_header()} takes the value from
292 +the @code{Sec-WebSocket-Key} request header and calculates the value
293 +for the @code{Sec-WebSocket-Accept} response header field.
298 +The @code{access_handler} example of the previous chapter can now be
299 +extended with these helper functions to perform the websocket handshake:
302 +static enum MHD_Result
303 +access_handler (void *cls,
304 + struct MHD_Connection *connection,
306 + const char *method,
307 + const char *version,
308 + const char *upload_data,
309 + size_t *upload_data_size,
313 + struct MHD_Response *response;
316 + (void) cls; /* Unused. Silent compiler warning. */
317 + (void) upload_data; /* Unused. Silent compiler warning. */
318 + (void) upload_data_size; /* Unused. Silent compiler warning. */
320 + if (0 != strcmp (method, "GET"))
321 + return MHD_NO; /* unexpected method */
324 + /* do never respond on first call */
328 + *ptr = NULL; /* reset when done */
330 + if (0 == strcmp (url, "/"))
332 + /* Default page for visiting the server */
333 + struct MHD_Response *response = MHD_create_response_from_buffer (
336 + MHD_RESPMEM_PERSISTENT);
337 + ret = MHD_queue_response (connection,
340 + MHD_destroy_response (response);
342 + else if (0 == strcmp (url, "/chat"))
345 + const char* value = NULL;
346 + char sec_websocket_accept[29];
348 + if (0 != MHD_websocket_check_http_version (version))
352 + value = MHD_lookup_connection_value (connection,
354 + MHD_HTTP_HEADER_CONNECTION);
355 + if (0 != MHD_websocket_check_connection_header (value))
359 + value = MHD_lookup_connection_value (connection,
361 + MHD_HTTP_HEADER_UPGRADE);
362 + if (0 != MHD_websocket_check_upgrade_header (value))
366 + value = MHD_lookup_connection_value (connection,
368 + MHD_HTTP_HEADER_SEC_WEBSOCKET_VERSION);
369 + if (0 != MHD_websocket_check_version_header (value))
373 + value = MHD_lookup_connection_value (connection,
375 + MHD_HTTP_HEADER_SEC_WEBSOCKET_KEY);
376 + if (0 != MHD_websocket_create_accept_header (value, sec_websocket_accept))
383 + /* upgrade the connection */
384 + response = MHD_create_response_for_upgrade (&upgrade_handler,
386 + MHD_add_response_header (response,
387 + MHD_HTTP_HEADER_CONNECTION,
389 + MHD_add_response_header (response,
390 + MHD_HTTP_HEADER_UPGRADE,
392 + MHD_add_response_header (response,
393 + MHD_HTTP_HEADER_SEC_WEBSOCKET_ACCEPT,
394 + sec_websocket_accept);
395 + ret = MHD_queue_response (connection,
396 + MHD_HTTP_SWITCHING_PROTOCOLS,
398 + MHD_destroy_response (response);
402 + /* return error page */
403 + struct MHD_Response*response = MHD_create_response_from_buffer (
404 + strlen (PAGE_INVALID_WEBSOCKET_REQUEST),
405 + PAGE_INVALID_WEBSOCKET_REQUEST,
406 + MHD_RESPMEM_PERSISTENT);
407 + ret = MHD_queue_response (connection,
408 + MHD_HTTP_BAD_REQUEST,
410 + MHD_destroy_response (response);
415 + struct MHD_Response*response = MHD_create_response_from_buffer (
416 + strlen (PAGE_NOT_FOUND),
418 + MHD_RESPMEM_PERSISTENT);
419 + ret = MHD_queue_response (connection,
420 + MHD_HTTP_NOT_FOUND,
422 + MHD_destroy_response (response);
430 +Please note that we skipped the check of the Host header field here,
431 +because we don't know the host for this example.
433 +@heading Decoding/encoding the websocket protocol with libmicrohttpd_ws
435 +Once the websocket connection is established you can receive/send frame data
436 +with the low-level socket functions @code{recv()} and @code{send()}.
437 +The frame data which goes over the low-level socket is encoded according
438 +to the websocket protocol.
439 +To use received payload data, you need to decode the frame data first.
440 +To send payload data, you need to encode it into frame data first.
442 +@emph{libmicrohttpd_ws} provides serveral functions for encoding of
443 +payload data and decoding of frame data:
447 +@code{MHD_websocket_decode()} decodes received frame data.
448 +The payload data may be of any kind, depending upon what the client has sent.
449 +So this decode function is used for all kind of frames and returns
450 +the frame type along with the payload data.
453 +@code{MHD_websocket_encode_text()} encodes text.
454 +The text must be encoded with UTF-8.
457 +@code{MHD_websocket_encode_binary()} encodes binary data.
460 +@code{MHD_websocket_encode_ping()} encodes a ping request to
461 +check whether the websocket is still valid and to test latency.
464 +@code{MHD_websocket_encode_ping()} encodes a pong response to
465 +answer a received ping request.
468 +@code{MHD_websocket_encode_close()} encodes a close request.
471 +@code{MHD_websocket_free()} frees data returned by the encode/decode functions.
475 +Since you could receive or send fragmented data (i. e. due to a too
476 +small buffer passed to @code{recv}) all of these encode/decode
477 +functions require a pointer to a @code{struct MHD_WebSocketStream} passed
479 +In this structure @emph{libmicrohttpd_ws} stores information
480 +about encoding/decoding of the particular websocket.
481 +For each websocket you need a unique @code{struct MHD_WebSocketStream}
482 +to encode/decode with this library.
484 +To create or destroy @code{struct MHD_WebSocketStream}
485 +we have additional functions:
489 +@code{MHD_websocket_stream_init()} allocates and initializes
490 +a new @code{struct MHD_WebSocketStream}.
491 +You can specify some options here to alter the behavior of the websocket stream.
494 +@code{MHD_websocket_stream_free()} frees a previously allocated
495 +@code{struct MHD_WebSocketStream}.
499 +With these encode/decode functions we can improve our @code{upgrade_handler}
500 +callback function from an earlier example to a working websocket:
505 +upgrade_handler (void *cls,
506 + struct MHD_Connection *connection,
508 + const char *extra_in,
509 + size_t extra_in_size,
511 + struct MHD_UpgradeResponseHandle *urh)
513 + /* make the socket blocking (operating-system-dependent code) */
514 + make_blocking (fd);
516 + /* create a websocket stream for this connection */
517 + struct MHD_WebSocketStream* ws;
518 + int result = MHD_websocket_stream_init (&ws,
523 + /* Couldn't create the websocket stream.
524 + * So we close the socket and leave
526 + MHD_upgrade_action (urh,
527 + MHD_UPGRADE_ACTION_CLOSE);
531 + /* Let's wait for incoming data */
532 + const size_t buf_len = 256;
535 + while (MHD_WEBSOCKET_VALIDITY_VALID == MHD_websocket_stream_is_valid (ws))
543 + /* the TCP/IP socket has been closed */
547 + /* parse the entire received data */
548 + size_t buf_offset = 0;
549 + while (buf_offset < (size_t) got)
551 + size_t new_offset = 0;
552 + char *frame_data = NULL;
553 + size_t frame_len = 0;
554 + int status = MHD_websocket_decode (ws,
556 + ((size_t) got) - buf_offset,
562 + /* an error occurred and the connection must be closed */
563 + if (NULL != frame_data)
565 + MHD_websocket_free (ws, frame_data);
571 + buf_offset += new_offset;
574 + /* the frame is complete */
577 + case MHD_WEBSOCKET_STATUS_TEXT_FRAME:
578 + /* The client has sent some text.
579 + * We will display it and answer with a text frame.
581 + if (NULL != frame_data)
583 + printf ("Received message: %s\n", frame_data);
584 + MHD_websocket_free (ws, frame_data);
587 + result = MHD_websocket_encode_text (ws,
589 + 5, /* length of "Hello" */
602 + case MHD_WEBSOCKET_STATUS_CLOSE_FRAME:
603 + /* if we receive a close frame, we will respond with one */
604 + MHD_websocket_free (ws,
608 + result = MHD_websocket_encode_close (ws,
622 + case MHD_WEBSOCKET_STATUS_PING_FRAME:
623 + /* if we receive a ping frame, we will respond */
624 + /* with the corresponding pong frame */
627 + size_t pong_len = 0;
628 + result = MHD_websocket_encode_pong (ws,
639 + MHD_websocket_free (ws,
645 + /* Other frame types are ignored
646 + * in this minimal example.
647 + * This is valid, because they become
648 + * automatically skipped if we receive them unexpectedly
653 + if (NULL != frame_data)
655 + MHD_websocket_free (ws, frame_data);
661 + /* free the websocket stream */
662 + MHD_websocket_stream_free (ws);
664 + /* close the socket when it is not needed anymore */
665 + MHD_upgrade_action (urh,
666 + MHD_UPGRADE_ACTION_CLOSE);
669 +/* This helper function is used for the case that
670 + * we need to resend some data
673 +send_all (MHD_socket fd,
680 + for (off = 0; off < len; off += ret)
688 + if (EAGAIN == errno)
700 +/* This helper function contains operating-system-dependent code and
701 + * is used to make a socket blocking.
704 +make_blocking (MHD_socket fd)
706 +#if defined(MHD_POSIX_SOCKETS)
709 + flags = fcntl (fd, F_GETFL);
712 + if ((flags & ~O_NONBLOCK) != flags)
713 + if (-1 == fcntl (fd, F_SETFL, flags & ~O_NONBLOCK))
715 +#elif defined(MHD_WINSOCK_SOCKETS)
716 + unsigned long flags = 0;
718 + ioctlsocket (fd, FIONBIO, &flags);
719 +#endif /* MHD_WINSOCK_SOCKETS */
726 +Please note that the websocket in this example is only half-duplex.
727 +It waits until the blocking @code{recv()} call returns and
728 +only does then something.
729 +In this example all frame types are decoded by @emph{libmicrohttpd_ws},
730 +but we only do something when a text, ping or close frame is received.
731 +Binary and pong frames are ignored in our code.
732 +This is legit, because the server is only required to implement at
733 +least support for ping frame or close frame (the other frame types
734 +could be skipped in theory, because they don't require an answer).
735 +The pong frame doesn't require an answer and whether text frames or
736 +binary frames get an answer simply belongs to your server application.
737 +So this is a valid minimal example.
739 +Until this point you've learned everything you need to basically
740 +use websockets with @emph{libmicrohttpd} and @emph{libmicrohttpd_ws}.
741 +These libraries offer much more functions for some specific cases.
744 +The further chapters of this tutorial focus on some specific problems
745 +and the client site programming.
748 +@heading Using full-duplex websockets
750 +To use full-duplex websockets you can simply create two threads
751 +per websocket connection.
752 +One of these threads is used for receiving data with
753 +a blocking @code{recv()} call and the other thread is triggered
754 +by the application internal codes and sends the data.
756 +A full-duplex websocket example is implemented in the example file
757 +@code{websocket_chatserver_example.c}.
759 +@heading Error handling
761 +The most functions of @emph{libmicrohttpd_ws} return a value
762 +of @code{enum MHD_WEBSOCKET_STATUS}.
763 +The values of this enumeration can be converted into an integer
764 +and have an easy interpretation:
768 +If the value is less than zero an error occurred and the call has failed.
769 +Check the enumeration values for more specific information.
772 +If the value is equal to zero, the call succeeded.
775 +If the value is greater than zero, the call succeeded and the value
776 +specifies the decoded frame type.
777 +Currently positive values are only returned by @code{MHD_websocket_decode()}
778 +(of the functions with this return enumeration type).
782 +A websocket stream can also get broken when invalid frame data is received.
783 +Also the other site could send a close frame which puts the stream into
784 +a state where it may not be used for regular communication.
785 +Whether a stream has become broken, can be checked with
786 +@code{MHD_websocket_stream_is_valid()}.
789 +@heading Fragmentation
791 +In addition to the regular TCP/IP fragmentation the websocket protocol also
792 +supports fragmentation.
793 +Fragmentation could be used for continuous payload data such as video data
795 +Whether or not you want to receive fragmentation is specified upon
796 +initialization of the websocket stream.
797 +If you pass @code{MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS} in the flags parameter
798 +of @code{MHD_websocket_stream_init()} then you can receive fragments.
799 +If you don't pass this flag (in the most cases you just pass zero as flags)
800 +then you don't want to handle fragments on your own.
801 +@emph{libmicrohttpd_ws} removes then the fragmentation for you
803 +You only get the completely assembled frames.
805 +Upon encoding you specify whether or not you want to create a fragmented frame
806 +by passing a flag to the corresponding encode function.
807 +Only @code{MHD_websocket_encode_text()} and @code{MHD_websocket_encode_binary()}
808 +can be used for fragmentation, because the other frame types may
810 +Encoding fragmented frames is independent of
811 +the @code{MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS} flag upon initialization.
813 +@heading Quick guide to websockets in JavaScript
815 +Websockets are supported in all modern web browsers.
816 +You initialize a websocket connection by creating an instance of
817 +the @code{WebSocket} class provided by the web browser.
819 +There are some simple rules for using websockets in the browser:
823 +When you initialize the instance of the websocket class you must pass an URL.
824 +The URL must either start with @code{ws://}
825 +(for not encrypted websocket protocol) or @code{wss://}
826 +(for TLS-encrypted websocket protocol).
828 +@strong{IMPORTANT:} If your website is accessed via @code{https://}
829 +then you are in a security context, which means that you are only allowed to
830 +access other secure protocols.
831 +So you can only use @code{wss://} for websocket connections then.
832 +If you try to @code{ws://} instead then your websocket connection will
836 +The WebSocket class uses events to handle the receiving of data.
837 +JavaScript is per definition a single-threaded language so
838 +the receiving events will never overlap.
839 +Sending is done directly by calling a method of the instance of
840 +the WebSocket class.
845 +Here is a short example for receiving/sending data to the same host
846 +as the website is running on:
852 +<meta charset="UTF-8">
853 +<title>Websocket Demo</title>
856 +let url = 'ws' + (window.location.protocol === 'https:' ? 's' : '') + '://' +
857 + window.location.host + '/chat';
860 +window.onload = function(event) {
861 + socket = new WebSocket(url);
862 + socket.onopen = function(event) {
863 + document.write('The websocket connection has been established.<br>');
866 + socket.send('Hello from JavaScript!');
869 + socket.onclose = function(event) {
870 + document.write('The websocket connection has been closed.<br>');
873 + socket.onerror = function(event) {
874 + document.write('An error occurred during the websocket communication.<br>');
877 + socket.onmessage = function(event) {
878 + document.write('Websocket message received: ' + event.data + '<br>');
890 --- libmicrohttpd-0.9.74/doc/examples/websocket.c.orig 1970-01-01 01:00:00.000000000 +0100
891 +++ libmicrohttpd-0.9.74/doc/examples/websocket.c 2021-12-23 22:49:44.536725673 +0100
893 +/* Feel free to use this example code in any way
894 + you see fit (Public Domain) */
896 +#include <sys/types.h>
898 +#include <sys/select.h>
899 +#include <sys/socket.h>
902 +#include <winsock2.h>
904 +#include <microhttpd.h>
905 +#include <microhttpd_ws.h>
915 + "<!DOCTYPE html>\n" \
918 + "<meta charset=\"UTF-8\">\n" \
919 + "<title>Websocket Demo</title>\n" \
922 + "let url = 'ws' + (window.location.protocol === 'https:' ? 's' : '')" \
924 + " window.location.host + '/chat';\n" \
925 + "let socket = null;\n" \
927 + "window.onload = function(event) {\n" \
928 + " socket = new WebSocket(url);\n" \
929 + " socket.onopen = function(event) {\n" \
930 + " document.write('The websocket connection has been " \
931 + "established.<br>');\n" \
933 + " // Send some text\n" \
934 + " socket.send('Hello from JavaScript!');\n" \
937 + " socket.onclose = function(event) {\n" \
938 + " document.write('The websocket connection has been closed.<br>');\n" \
941 + " socket.onerror = function(event) {\n" \
942 + " document.write('An error occurred during the websocket " \
943 + "communication.<br>');\n" \
946 + " socket.onmessage = function(event) {\n" \
947 + " document.write('Websocket message received: ' + " \
948 + "event.data + '<br>');\n" \
958 +#define PAGE_NOT_FOUND \
961 +#define PAGE_INVALID_WEBSOCKET_REQUEST \
962 + "Invalid WebSocket request!"
965 +send_all (MHD_socket fd,
970 +make_blocking (MHD_socket fd);
973 +upgrade_handler (void *cls,
974 + struct MHD_Connection *connection,
976 + const char *extra_in,
977 + size_t extra_in_size,
979 + struct MHD_UpgradeResponseHandle *urh)
981 + /* make the socket blocking (operating-system-dependent code) */
982 + make_blocking (fd);
984 + /* create a websocket stream for this connection */
985 + struct MHD_WebSocketStream *ws;
986 + int result = MHD_websocket_stream_init (&ws,
991 + /* Couldn't create the websocket stream.
992 + * So we close the socket and leave
994 + MHD_upgrade_action (urh,
995 + MHD_UPGRADE_ACTION_CLOSE);
999 + /* Let's wait for incoming data */
1000 + const size_t buf_len = 256;
1001 + char buf[buf_len];
1003 + while (MHD_WEBSOCKET_VALIDITY_VALID == MHD_websocket_stream_is_valid (ws))
1011 + /* the TCP/IP socket has been closed */
1015 + /* parse the entire received data */
1016 + size_t buf_offset = 0;
1017 + while (buf_offset < (size_t) got)
1019 + size_t new_offset = 0;
1020 + char *frame_data = NULL;
1021 + size_t frame_len = 0;
1022 + int status = MHD_websocket_decode (ws,
1024 + ((size_t) got) - buf_offset,
1030 + /* an error occurred and the connection must be closed */
1031 + if (NULL != frame_data)
1033 + MHD_websocket_free (ws, frame_data);
1039 + buf_offset += new_offset;
1042 + /* the frame is complete */
1045 + case MHD_WEBSOCKET_STATUS_TEXT_FRAME:
1046 + /* The client has sent some text.
1047 + * We will display it and answer with a text frame.
1049 + if (NULL != frame_data)
1051 + printf ("Received message: %s\n", frame_data);
1052 + MHD_websocket_free (ws, frame_data);
1053 + frame_data = NULL;
1055 + result = MHD_websocket_encode_text (ws,
1057 + 5, /* length of "Hello" */
1070 + case MHD_WEBSOCKET_STATUS_CLOSE_FRAME:
1071 + /* if we receive a close frame, we will respond with one */
1072 + MHD_websocket_free (ws,
1074 + frame_data = NULL;
1076 + result = MHD_websocket_encode_close (ws,
1090 + case MHD_WEBSOCKET_STATUS_PING_FRAME:
1091 + /* if we receive a ping frame, we will respond */
1092 + /* with the corresponding pong frame */
1094 + char *pong = NULL;
1095 + size_t pong_len = 0;
1096 + result = MHD_websocket_encode_pong (ws,
1107 + MHD_websocket_free (ws,
1113 + /* Other frame types are ignored
1114 + * in this minimal example.
1115 + * This is valid, because they become
1116 + * automatically skipped if we receive them unexpectedly
1121 + if (NULL != frame_data)
1123 + MHD_websocket_free (ws, frame_data);
1129 + /* free the websocket stream */
1130 + MHD_websocket_stream_free (ws);
1132 + /* close the socket when it is not needed anymore */
1133 + MHD_upgrade_action (urh,
1134 + MHD_UPGRADE_ACTION_CLOSE);
1138 +/* This helper function is used for the case that
1139 + * we need to resend some data
1142 +send_all (MHD_socket fd,
1149 + for (off = 0; off < len; off += ret)
1153 + (int) (len - off),
1157 + if (EAGAIN == errno)
1170 +/* This helper function contains operating-system-dependent code and
1171 + * is used to make a socket blocking.
1174 +make_blocking (MHD_socket fd)
1179 + flags = fcntl (fd, F_GETFL);
1182 + if ((flags & ~O_NONBLOCK) != flags)
1183 + if (-1 == fcntl (fd, F_SETFL, flags & ~O_NONBLOCK))
1186 + unsigned long flags = 0;
1188 + if (0 != ioctlsocket (fd, (int) FIONBIO, &flags))
1190 +#endif /* _WIN32 */
1194 +static enum MHD_Result
1195 +access_handler (void *cls,
1196 + struct MHD_Connection *connection,
1198 + const char *method,
1199 + const char *version,
1200 + const char *upload_data,
1201 + size_t *upload_data_size,
1205 + struct MHD_Response *response;
1208 + (void) cls; /* Unused. Silent compiler warning. */
1209 + (void) upload_data; /* Unused. Silent compiler warning. */
1210 + (void) upload_data_size; /* Unused. Silent compiler warning. */
1212 + if (0 != strcmp (method, "GET"))
1213 + return MHD_NO; /* unexpected method */
1214 + if (&aptr != *ptr)
1216 + /* do never respond on first call */
1220 + *ptr = NULL; /* reset when done */
1222 + if (0 == strcmp (url, "/"))
1224 + /* Default page for visiting the server */
1225 + struct MHD_Response *response = MHD_create_response_from_buffer (
1228 + MHD_RESPMEM_PERSISTENT);
1229 + ret = MHD_queue_response (connection,
1232 + MHD_destroy_response (response);
1234 + else if (0 == strcmp (url, "/chat"))
1236 + char is_valid = 1;
1237 + const char *value = NULL;
1238 + char sec_websocket_accept[29];
1240 + if (0 != MHD_websocket_check_http_version (version))
1244 + value = MHD_lookup_connection_value (connection,
1246 + MHD_HTTP_HEADER_CONNECTION);
1247 + if (0 != MHD_websocket_check_connection_header (value))
1251 + value = MHD_lookup_connection_value (connection,
1253 + MHD_HTTP_HEADER_UPGRADE);
1254 + if (0 != MHD_websocket_check_upgrade_header (value))
1258 + value = MHD_lookup_connection_value (connection,
1260 + MHD_HTTP_HEADER_SEC_WEBSOCKET_VERSION);
1261 + if (0 != MHD_websocket_check_version_header (value))
1265 + value = MHD_lookup_connection_value (connection,
1267 + MHD_HTTP_HEADER_SEC_WEBSOCKET_KEY);
1268 + if (0 != MHD_websocket_create_accept_header (value, sec_websocket_accept))
1273 + if (1 == is_valid)
1275 + /* upgrade the connection */
1276 + response = MHD_create_response_for_upgrade (&upgrade_handler,
1278 + MHD_add_response_header (response,
1279 + MHD_HTTP_HEADER_CONNECTION,
1281 + MHD_add_response_header (response,
1282 + MHD_HTTP_HEADER_UPGRADE,
1284 + MHD_add_response_header (response,
1285 + MHD_HTTP_HEADER_SEC_WEBSOCKET_ACCEPT,
1286 + sec_websocket_accept);
1287 + ret = MHD_queue_response (connection,
1288 + MHD_HTTP_SWITCHING_PROTOCOLS,
1290 + MHD_destroy_response (response);
1294 + /* return error page */
1295 + struct MHD_Response *response = MHD_create_response_from_buffer (
1296 + strlen (PAGE_INVALID_WEBSOCKET_REQUEST),
1297 + PAGE_INVALID_WEBSOCKET_REQUEST,
1298 + MHD_RESPMEM_PERSISTENT);
1299 + ret = MHD_queue_response (connection,
1300 + MHD_HTTP_BAD_REQUEST,
1302 + MHD_destroy_response (response);
1307 + struct MHD_Response *response = MHD_create_response_from_buffer (
1308 + strlen (PAGE_NOT_FOUND),
1310 + MHD_RESPMEM_PERSISTENT);
1311 + ret = MHD_queue_response (connection,
1312 + MHD_HTTP_NOT_FOUND,
1314 + MHD_destroy_response (response);
1323 + char *const *argv)
1325 + (void) argc; /* Unused. Silent compiler warning. */
1326 + (void) argv; /* Unused. Silent compiler warning. */
1327 + struct MHD_Daemon *daemon;
1329 + daemon = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD
1330 + | MHD_USE_THREAD_PER_CONNECTION
1331 + | MHD_ALLOW_UPGRADE
1332 + | MHD_USE_ERROR_LOG,
1334 + &access_handler, NULL,
1337 + if (NULL == daemon)
1339 + (void) getc (stdin);
1341 + MHD_stop_daemon (daemon);