1 /*
2      This file is part of libmicrohttpd
3      Copyright (C) 2021 Christian Grothoff (and other contributing authors)
4 
5      This library is free software; you can redistribute it and/or
6      modify it under the terms of the GNU Lesser General Public
7      License as published by the Free Software Foundation; either
8      version 2.1 of the License, or (at your option) any later version.
9 
10      This library is distributed in the hope that it will be useful,
11      but WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      Lesser General Public License for more details.
14 
15      You should have received a copy of the GNU Lesser General Public
16      License along with this library; if not, write to the Free Software
17      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18 */
19 /**
20  * @file microhttpd_ws.h
21  * @brief interface for experimental web socket extension to libmicrohttpd
22  * @author David Gausmann
23  */
24 /*
25  *                            *** WARNING! ***
26  * *   The websockets interface is currenly in "experimental" stage.   *
27  * * It does not work on architectures with endianness different from  *
28  * * big endian and little endian and may have some portability issues.*
29  * * API and ABI are not yet stable.                                   *
30  */
31 #ifndef MHD_MICROHTTPD_WS_H
32 #define MHD_MICROHTTPD_WS_H
33 
34 
35 #ifdef __cplusplus
36 extern "C"
37 {
38 #if 0                           /* keep Emacsens' auto-indent happy */
39 }
40 #endif
41 #endif
42 
43 
44 /**
45  * @brief Handle for the encoding/decoding of websocket data
46  *        (one stream is used per websocket)
47  * @ingroup websocket
48  */
49 struct MHD_WebSocketStream;
50 
51 /**
52  * @brief Flags for the initialization of a websocket stream
53  *        `struct MHD_WebSocketStream` used by
54  *        #MHD_websocket_stream_init() or
55  *        #MHD_websocket_stream_init2().
56  * @ingroup websocket
57  */
58 enum MHD_WEBSOCKET_FLAG
59 {
60   /**
61    * The websocket stream is initialized in server mode (default).
62    * Thus all outgoing payload will not be "masked".
63    * All incoming payload must be masked.
64    * This flag cannot be used together with #MHD_WEBSOCKET_FLAG_CLIENT
65    */
66   MHD_WEBSOCKET_FLAG_SERVER = 0,
67   /**
68    * The websocket stream is initialized in client mode.
69    * You will usually never use that mode in combination with libmicrohttpd,
70    * because libmicrohttpd provides a server and not a client.
71    * In client mode all outgoing payload will be "masked"
72    * (XOR-ed with random values).
73    * All incoming payload must be unmasked.
74    * If you use this mode, you must always call #MHD_websocket_stream_init2()
75    * instead of #MHD_websocket_stream_init(), because you need
76    * to pass a random number generator callback function for masking.
77    * This flag cannot be used together with #MHD_WEBSOCKET_FLAG_SERVER
78    */
79   MHD_WEBSOCKET_FLAG_CLIENT = 1,
80   /**
81    * You don't want to get fragmented data while decoding (default).
82    * Fragmented frames will be internally put together until
83    * they are complete.
84    * Whether or not data is fragmented is decided
85    * by the sender of the data during encoding.
86    * This cannot be used together with #MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS
87    */
88   MHD_WEBSOCKET_FLAG_NO_FRAGMENTS = 0,
89   /**
90    * You want fragmented data, if it appears while decoding.
91    * You will receive the content of the fragmented frame,
92    * but if you are decoding text, you will never get an unfinished
93    * UTF-8 sequence (if the sequence appears between two fragments).
94    * Instead the text will end before the unfinished UTF-8 sequence.
95    * With the next fragment, which finishes the UTF-8 sequence,
96    * you will get the complete UTF-8 sequence.
97    * This cannot be used together with #MHD_WEBSOCKET_FLAG_NO_FRAGMENTS
98    */
99   MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS = 2,
100   /**
101    * If the websocket stream becomes invalid during decoding due to
102    * protocol errors, a matching close frame will automatically
103    * be generated.
104    * The close frame will be returned via the parameters
105    * `payload` and `payload_len` of #MHD_websocket_decode() and
106    * the return value is negative
107    * (a value of `enum MHD_WEBSOCKET_STATUS`).
108    * The generated close frame must be freed by the caller
109    * with #MHD_websocket_free().
110    */
111   MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR = 4
112 };
113 
114 /**
115  * @brief Enum to specify the fragmenting behavior
116  *        while encoding with #MHD_websocket_encode_text() or
117  *        #MHD_websocket_encode_binary().
118  * @ingroup websocket
119  */
120 enum MHD_WEBSOCKET_FRAGMENTATION
121 {
122   /**
123    * You don't want to use fragmentation.
124    * The encoded frame consists of only one frame.
125    */
126   MHD_WEBSOCKET_FRAGMENTATION_NONE = 0,
127   /**
128    * You want to use fragmentation.
129    * The encoded frame is the first frame of
130    * a series of data frames of the same type
131    * (text or binary).
132    * You may send control frames (ping, pong or close)
133    * between these data frames.
134    */
135   MHD_WEBSOCKET_FRAGMENTATION_FIRST = 1,
136   /**
137    * You want to use fragmentation.
138    * The encoded frame is not the first frame of
139    * the series of data frames, but also not the last one.
140    * You may send control frames (ping, pong or close)
141    * between these data frames.
142    */
143   MHD_WEBSOCKET_FRAGMENTATION_FOLLOWING = 2,
144   /**
145    * You want to use fragmentation.
146    * The encoded frame is the last frame of
147    * the series of data frames, but also not the first one.
148    * After this frame, you may send all types of frames again.
149    */
150   MHD_WEBSOCKET_FRAGMENTATION_LAST = 3
151 };
152 
153 /**
154  * @brief Enum of the return value for almost every MHD_websocket function.
155  *        Errors are negative and values equal to or above zero mean a success.
156  *        Positive values are only used by #MHD_websocket_decode().
157  * @ingroup websocket
158  */
159 enum MHD_WEBSOCKET_STATUS
160 {
161   /**
162    * The call succeeded.
163    * For #MHD_websocket_decode() this means that no error occurred,
164    * but also no frame has been completed yet.
165    * For other functions this means simply a success.
166    */
167   MHD_WEBSOCKET_STATUS_OK = 0,
168   /**
169    * #MHD_websocket_decode() has decoded a text frame.
170    * The parameters `payload` and `payload_len` are filled with
171    * the decoded text (if any).
172    */
173   MHD_WEBSOCKET_STATUS_TEXT_FRAME = 0x1,
174   /**
175    * #MHD_websocket_decode() has decoded a binary frame.
176    * The parameters `payload` and `payload_len` are filled with
177    * the decoded binary data (if any).
178    */
179   MHD_WEBSOCKET_STATUS_BINARY_FRAME = 0x2,
180   /**
181    * #MHD_websocket_decode() has decoded a close frame.
182    * This means you must close the socket using #MHD_upgrade_action()
183    * with #MHD_UPGRADE_ACTION_CLOSE.
184    * You may respond with a close frame before closing.
185    * The parameters `payload` and `payload_len` are filled with
186    * the close reason (if any).
187    * The close reason starts with a two byte sequence of close code
188    * in network byte order (see `enum MHD_WEBSOCKET_CLOSEREASON`).
189    * After these two bytes a UTF-8 encoded close reason may follow.
190    * You can call #MHD_websocket_split_close_reason() to split that
191    * close reason.
192    */
193   MHD_WEBSOCKET_STATUS_CLOSE_FRAME = 0x8,
194   /**
195    * #MHD_websocket_decode() has decoded a ping frame.
196    * You should respond to this with a pong frame.
197    * The pong frame must contain the same binary data as
198    * the corresponding ping frame (if it had any).
199    * The parameters `payload` and `payload_len` are filled with
200    * the binary ping data (if any).
201    */
202   MHD_WEBSOCKET_STATUS_PING_FRAME = 0x9,
203   /**
204    * #MHD_websocket_decode() has decoded a pong frame.
205    * You should usually only receive pong frames if you sent
206    * a ping frame before.
207    * The binary data should be equal to your ping frame and can be
208    * used to distinguish the response if you sent multiple ping frames.
209    * The parameters `payload` and `payload_len` are filled with
210    * the binary pong data (if any).
211    */
212   MHD_WEBSOCKET_STATUS_PONG_FRAME = 0xA,
213   /**
214    * #MHD_websocket_decode() has decoded a text frame fragment.
215    * The parameters `payload` and `payload_len` are filled with
216    * the decoded text (if any).
217    * This is like #MHD_WEBSOCKET_STATUS_TEXT_FRAME, but it can only
218    * appear if you specified #MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS during
219    * the call of #MHD_websocket_stream_init() or
220    * #MHD_websocket_stream_init2().
221    */
222   MHD_WEBSOCKET_STATUS_TEXT_FIRST_FRAGMENT = 0x11,
223   /**
224    * #MHD_websocket_decode() has decoded a binary frame fragment.
225    * The parameters `payload` and `payload_len` are filled with
226    * the decoded binary data (if any).
227    * This is like #MHD_WEBSOCKET_STATUS_BINARY_FRAME, but it can only
228    * appear if you specified #MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS during
229    * the call of #MHD_websocket_stream_init() or
230    * #MHD_websocket_stream_init2().
231    */
232   MHD_WEBSOCKET_STATUS_BINARY_FIRST_FRAGMENT = 0x12,
233   /**
234    * #MHD_websocket_decode() has decoded the next text frame fragment.
235    * The parameters `payload` and `payload_len` are filled with
236    * the decoded text (if any).
237    * This is like #MHD_WEBSOCKET_STATUS_TEXT_FIRST_FRAGMENT, but it appears
238    * only after the first and before the last fragment of a series of fragments.
239    * It can only appear if you specified #MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS
240    * during the call of #MHD_websocket_stream_init() or
241    * #MHD_websocket_stream_init2().
242    */
243   MHD_WEBSOCKET_STATUS_TEXT_NEXT_FRAGMENT = 0x21,
244   /**
245    * #MHD_websocket_decode() has decoded the next binary frame fragment.
246    * The parameters `payload` and `payload_len` are filled with
247    * the decoded binary data (if any).
248    * This is like #MHD_WEBSOCKET_STATUS_BINARY_FIRST_FRAGMENT, but it appears
249    * only after the first and before the last fragment of a series of fragments.
250    * It can only appear if you specified #MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS
251    * during the call of #MHD_websocket_stream_init() or
252    * #MHD_websocket_stream_init2().
253    */
254   MHD_WEBSOCKET_STATUS_BINARY_NEXT_FRAGMENT = 0x22,
255   /**
256    * #MHD_websocket_decode() has decoded the last text frame fragment.
257    * The parameters `payload` and `payload_len` are filled with
258    * the decoded text (if any).
259    * This is like #MHD_WEBSOCKET_STATUS_TEXT_FIRST_FRAGMENT, but it appears
260    * only for the last fragment of a series of fragments.
261    * It can only appear if you specified #MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS
262    * during the call of #MHD_websocket_stream_init() or
263    * #MHD_websocket_stream_init2().
264    */
265   MHD_WEBSOCKET_STATUS_TEXT_LAST_FRAGMENT = 0x41,
266   /**
267    * #MHD_websocket_decode() has decoded the last binary frame fragment.
268    * The parameters `payload` and `payload_len` are filled with
269    * the decoded binary data (if any).
270    * This is like #MHD_WEBSOCKET_STATUS_BINARY_FIRST_FRAGMENT, but it appears
271    * only for the last fragment of a series of fragments.
272    * It can only appear if you specified #MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS
273    * during the call of #MHD_websocket_stream_init() or
274    * #MHD_websocket_stream_init2().
275    */
276   MHD_WEBSOCKET_STATUS_BINARY_LAST_FRAGMENT = 0x42,
277   /**
278    * The call failed and the stream is invalid now for decoding.
279    * You must close the websocket now using #MHD_upgrade_action()
280    * with #MHD_UPGRADE_ACTION_CLOSE.
281    * You may send a close frame before closing.
282    * This is only used by #MHD_websocket_decode() and happens
283    * if the stream contains errors (i. e. invalid byte data).
284    */
285   MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR = -1,
286   /**
287    * You tried to decode something, but the stream has already
288    * been marked invalid.
289    * You must close the websocket now using #MHD_upgrade_action()
290    * with #MHD_UPGRADE_ACTION_CLOSE.
291    * You may send a close frame before closing.
292    * This is only used by #MHD_websocket_decode() and happens
293    * if you call #MDM_websocket_decode() again after
294    * has been invalidated.
295    * You can call #MHD_websocket_stream_is_valid() at any time
296    * to check whether a stream is invalid or not.
297    */
298   MHD_WEBSOCKET_STATUS_STREAM_BROKEN = -2,
299   /**
300    * A memory allocation failed. The stream remains valid.
301    * If this occurred while decoding, the decoding could be
302    * possible later if enough memory is available.
303    * This could happen while decoding if you received a too big data frame.
304    * You could try to specify max_payload_size during the call of
305    * #MHD_websocket_stream_init() or #MHD_websocket_stream_init2() to
306    * avoid this and close the websocket instead.
307    */
308   MHD_WEBSOCKET_STATUS_MEMORY_ERROR = -3,
309   /**
310    * You passed invalid parameters during the function call
311    * (i. e. a NULL pointer for a required parameter).
312    * The stream remains valid.
313    */
314   MHD_WEBSOCKET_STATUS_PARAMETER_ERROR = -4,
315   /**
316    * The maximum payload size has been exceeded.
317    * If you got this return code from #MHD_websocket_decode() then
318    * the stream becomes invalid and the websocket must be closed
319    * using #MHD_upgrade_action() with #MHD_UPGRADE_ACTION_CLOSE.
320    * You may send a close frame before closing.
321    * The maximum payload size is specified during the call of
322    * #MHD_websocket_stream_init() or #MHD_websocket_stream_init2().
323    * This can also appear if you specified 0 as maximum payload size
324    * when the message is greater than the maximum allocatable memory size
325    * (i. e. more than 4 GiB on 32 bit systems).
326    * If you got this return code from #MHD_websocket_encode_close(),
327    * #MHD_websocket_encode_ping() or #MHD_websocket_encode_pong() then
328    * you passed to much payload data. The stream remains valid then.
329    */
330   MHD_WEBSOCKET_STATUS_MAXIMUM_SIZE_EXCEEDED = -5,
331   /**
332    * An UTF-8 sequence is invalid.
333    * If you got this return code from #MHD_websocket_decode() then
334    * the stream becomes invalid and you must close the websocket
335    * using #MHD_upgrade_action() with #MHD_UPGRADE_ACTION_CLOSE.
336    * You may send a close frame before closing.
337    * If you got this from #MHD_websocket_encode_text() or
338    * #MHD_websocket_encode_close() then you passed invalid UTF-8 text.
339    * The stream remains valid then.
340    */
341   MHD_WEBSOCKET_STATUS_UTF8_ENCODING_ERROR = -6,
342   /**
343    * A check routine for the HTTP headers came to the conclusion that
344    * the header value isn't valid for a websocket handshake request.
345    * This value can only be returned from the following functions:
346    * * #MHD_websocket_check_http_version()
347    * * #MHD_websocket_check_connection_header()
348    * * #MHD_websocket_check_upgrade_header()
349    * * #MHD_websocket_check_version_header()
350    * * #MHD_websocket_create_accept_header()
351    */
352   MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER = -7
353 };
354 
355 /**
356  * @brief Enumeration of possible close reasons for close frames.
357  *
358  * The possible values are specified in RFC 6455 7.4.1
359  * These close reasons here are the default set specified by RFC 6455,
360  * but also other close reasons could be used.
361  *
362  * The definition is for short:
363  * 0-999 are never used (if you pass 0 in
364  *   #MHD_websocket_encode_close() then no close reason is used).
365  * 1000-2999 are specified by RFC 6455.
366  * 3000-3999 are specified by libraries, etc. but must be registered by IANA.
367  * 4000-4999 are reserved for private use.
368  *
369  * @ingroup websocket
370  */
371 enum MHD_WEBSOCKET_CLOSEREASON
372 {
373   /**
374    * This value is used as placeholder for #MHD_websocket_encode_close()
375    * to tell that you don't want to specify any reason.
376    * If you use this value then no reason text may be used.
377    * This value cannot be a result of decoding, because this value
378    * is not a valid close reason for the websocket protocol.
379    */
380   MHD_WEBSOCKET_CLOSEREASON_NO_REASON = 0,
381   /**
382    * You close the websocket because it fulfilled its purpose and shall
383    * now be closed in a normal, planned way.
384    */
385   MHD_WEBSOCKET_CLOSEREASON_REGULAR = 1000,
386   /**
387    * You close the websocket because you are shutting down the server or
388    * something similar.
389    */
390   MHD_WEBSOCKET_CLOSEREASON_GOING_AWAY = 1001,
391   /**
392    * You close the websocket because a protocol error occurred
393    * during decoding (i. e. invalid byte data).
394    */
395   MHD_WEBSOCKET_CLOSEREASON_PROTOCOL_ERROR = 1002,
396   /**
397    * You close the websocket because you received data which you don't accept.
398    * For example if you received a binary frame,
399    * but your application only expects text frames.
400    */
401   MHD_WEBSOCKET_CLOSEREASON_UNSUPPORTED_DATATYPE = 1003,
402   /**
403    * You close the websocket because it contains malformed UTF-8.
404    * The UTF-8 validity is automatically checked by #MHD_websocket_decode(),
405    * so you don't need to check it on your own.
406    * UTF-8 is specified in RFC 3629.
407    */
408   MHD_WEBSOCKET_CLOSEREASON_MALFORMED_UTF8 = 1007,
409   /**
410    * You close the websocket because of any reason.
411    * Usually this close reason is used if no other close reason
412    * is more specific or if you don't want to use any other close reason.
413    */
414   MHD_WEBSOCKET_CLOSEREASON_POLICY_VIOLATED = 1008,
415   /**
416    * You close the websocket because you received a frame which is too big
417    * to process.
418    * You can specify the maximum allowed payload size during the call of
419    * #MHD_websocket_stream_init() or #MHD_websocket_stream_init2().
420    */
421   MHD_WEBSOCKET_CLOSEREASON_MAXIMUM_ALLOWED_PAYLOAD_SIZE_EXCEEDED = 1009,
422   /**
423    * This status code can be sent by the client if it
424    * expected a specific extension, but this extension hasn't been negotiated.
425    */
426   MHD_WEBSOCKET_CLOSEREASON_MISSING_EXTENSION = 1010,
427   /**
428    * The server closes the websocket because it encountered
429    * an unexpected condition that prevented it from fulfilling the request.
430    */
431   MHD_WEBSOCKET_CLOSEREASON_UNEXPECTED_CONDITION = 1011
432 };
433 
434 /**
435  * @brief Enumeration of possible UTF-8 check steps
436  *
437  * These values are used during the encoding of fragmented text frames
438  * or for error analysis while encoding text frames.
439  * Its values specify the next step of the UTF-8 check.
440  * UTF-8 sequences consist of one to four bytes.
441  * This enumeration just says how long the current UTF-8 sequence is
442  * and what is the next expected byte.
443  *
444  * @ingroup websocket
445  */
446 enum MHD_WEBSOCKET_UTF8STEP
447 {
448   /**
449    * There is no open UTF-8 sequence.
450    * The next byte must be 0x00-0x7F or 0xC2-0xF4.
451    */
452   MHD_WEBSOCKET_UTF8STEP_NORMAL   = 0,
453   /**
454    * The second byte of a two byte UTF-8 sequence.
455    * The first byte was 0xC2-0xDF.
456    * The next byte must be 0x80-0xBF.
457    */
458   MHD_WEBSOCKET_UTF8STEP_UTF2TAIL_1OF1 = 1,
459   /**
460    * The second byte of a three byte UTF-8 sequence.
461    * The first byte was 0xE0.
462    * The next byte must be 0xA0-0xBF.
463    */
464   MHD_WEBSOCKET_UTF8STEP_UTF3TAIL1_1OF2 = 2,
465   /**
466   * The second byte of a three byte UTF-8 sequence.
467   * The first byte was 0xED.
468   * The next byte must by 0x80-0x9F.
469   */
470   MHD_WEBSOCKET_UTF8STEP_UTF3TAIL2_1OF2 = 3,
471   /**
472   * The second byte of a three byte UTF-8 sequence.
473   * The first byte was 0xE1-0xEC or 0xEE-0xEF.
474   * The next byte must be 0x80-0xBF.
475   */
476   MHD_WEBSOCKET_UTF8STEP_UTF3TAIL_1OF2 = 4,
477   /**
478   * The third byte of a three byte UTF-8 sequence.
479   * The next byte must be 0x80-0xBF.
480   */
481   MHD_WEBSOCKET_UTF8STEP_UTF3TAIL_2OF2 = 5,
482   /**
483    * The second byte of a four byte UTF-8 sequence.
484    * The first byte was 0xF0.
485    * The next byte must be 0x90-0xBF.
486    */
487   MHD_WEBSOCKET_UTF8STEP_UTF4TAIL1_1OF3 = 6,
488   /**
489    * The second byte of a four byte UTF-8 sequence.
490    * The first byte was 0xF4.
491    * The next byte must be 0x80-0x8F.
492    */
493   MHD_WEBSOCKET_UTF8STEP_UTF4TAIL2_1OF3 = 7,
494   /**
495    * The second byte of a four byte UTF-8 sequence.
496    * The first byte was 0xF1-0xF3.
497    * The next byte must be 0x80-0xBF.
498    */
499   MHD_WEBSOCKET_UTF8STEP_UTF4TAIL_1OF3 = 8,
500   /**
501    * The third byte of a four byte UTF-8 sequence.
502    * The next byte must be 0x80-0xBF.
503    */
504   MHD_WEBSOCKET_UTF8STEP_UTF4TAIL_2OF3 = 9,
505   /**
506   * The fourth byte of a four byte UTF-8 sequence.
507   * The next byte must be 0x80-0xBF.
508   */
509   MHD_WEBSOCKET_UTF8STEP_UTF4TAIL_3OF3 = 10
510 };
511 
512 /**
513 * @brief Enumeration of validity values
514 *
515 * These values are used for #MHD_websocket_stream_is_valid()
516 * and specify the validity status.
517 *
518 * @ingroup websocket
519 */
520 enum MHD_WEBSOCKET_VALIDITY
521 {
522   /**
523   * The stream is invalid.
524   * It cannot be used for decoding anymore.
525   */
526   MHD_WEBSOCKET_VALIDITY_INVALID = 0,
527   /**
528    * The stream is valid.
529    * Decoding works as expected.
530    */
531   MHD_WEBSOCKET_VALIDITY_VALID   = 1,
532   /**
533    * The stream has received a close frame and
534    * is partly invalid.
535    * You can still use the stream for decoding,
536    * but if a data frame is received an error will be reported.
537    * After a close frame has been sent, no data frames
538    * may follow from the sender of the close frame.
539    */
540   MHD_WEBSOCKET_VALIDITY_ONLY_VALID_FOR_CONTROL_FRAMES = 2
541 };
542 /**
543  * This callback function is used internally by many websocket functions
544  * for allocating data.
545  * By default `malloc()` is used.
546  * You can use your own allocation function with
547  * #MHD_websocket_stream_init2() if you wish to.
548  * This can be useful for operating systems like Windows
549  * where `malloc()`, `realloc()` and `free()` are compiler-dependent.
550  * You can call the associated `malloc()` callback of
551  * a websocket stream with #MHD_websocket_malloc().
552  *
553  * @param buf_len buffer size in bytes
554  * @return allocated memory
555  * @ingroup websocket
556  */
557 typedef void *
558 (*MHD_WebSocketMallocCallback) (size_t buf_len);
559 /**
560  * This callback function is used internally by many websocket
561  * functions for reallocating data.
562  * By default `realloc()` is used.
563  * You can use your own reallocation function with
564  * #MHD_websocket_stream_init2() if you wish to.
565  * This can be useful for operating systems like Windows
566  * where `malloc()`, `realloc()` and `free()` are compiler-dependent.
567  * You can call the associated `realloc()` callback of
568  * a websocket stream with #MHD_websocket_realloc().
569  *
570  * @param buf buffer
571  * @param new_buf_len new buffer size in bytes
572  * @return reallocated memory
573  * @ingroup websocket
574  */
575 typedef void *
576 (*MHD_WebSocketReallocCallback) (void *buf, size_t new_buf_len);
577 /**
578  * This callback function is used internally by many websocket
579  * functions for freeing data.
580  * By default `free()` is used.
581  * You can use your own free function with
582  * #MHD_websocket_stream_init2() if you wish to.
583  * This can be useful for operating systems like Windows
584  * where `malloc()`, `realloc()` and `free()` are compiler-dependent.
585  * You can call the associated `free()` callback of
586  * a websocket stream with #MHD_websocket_free().
587  *
588  * @param buf buffer
589  * @ingroup websocket
590  */
591 typedef void
592 (*MHD_WebSocketFreeCallback) (void *buf);
593 /**
594  * This callback function is used for generating random numbers
595  * for masking payload data in client mode.
596  * If you use websockets in server mode with libmicrohttpd then
597  * you don't need a random number generator, because
598  * the server doesn't mask its outgoing messageses.
599  * However if you wish to use a websocket stream in client mode,
600  * you must pass this callback function to #MHD_websocket_stream_init2().
601  *
602  * @param cls closure specified in #MHD_websocket_stream_init2()
603  * @param buf buffer to fill with random values
604  * @param buf_len size of buffer in bytes
605  * @return The number of generated random bytes.
606  *         Should usually equal to buf_len.
607  * @ingroup websocket
608  */
609 typedef size_t
610 (*MHD_WebSocketRandomNumberGenerator) (void *cls, void *buf, size_t buf_len);
611 
612 /**
613  * Checks the HTTP version of the incoming request.
614  * Websocket requests are only allowed for HTTP/1.1 or above.
615  *
616  * @param http_version The value of the 'version' parameter of your
617  *                     access_handler callback
618  * @return A value of `enum MHD_WEBSOCKET_STATUS`.
619  *         0 means the HTTP version is correct for a websocket request,
620  *         a value less than zero means that the HTTP version isn't
621  *         valid for a websocket request.
622  * @ingroup websocket
623  */
624 _MHD_EXTERN enum MHD_WEBSOCKET_STATUS
625 MHD_websocket_check_http_version (const char *http_version);
626 
627 /**
628  * Checks the value of the 'Connection' HTTP request header.
629  * Websocket requests require the token 'Upgrade' in
630  * the 'Connection' HTTP request header.
631  *
632  * @param connection_header The value of the 'Connection' request header.
633  *                          You can get this request header value by passing
634  *                          #MHD_HTTP_HEADER_CONNECTION to
635  *                          #MHD_lookup_connection_value().
636  * @return A value of `enum MHD_WEBSOCKET_STATUS`.
637  *         0 means the 'Connection' request header is correct
638  *         for a websocket request,
639  *         a value less than zero means that the 'Connection' header isn't
640  *         valid for a websocket request.
641  * @ingroup websocket
642  */
643 _MHD_EXTERN enum MHD_WEBSOCKET_STATUS
644 MHD_websocket_check_connection_header (const char *connection_header);
645 
646 /**
647  * Checks the value of the 'Upgrade' HTTP request header.
648  * Websocket requests require the value 'websocket' in
649  * the 'Upgrade' HTTP request header.
650  *
651  * @param upgrade_header The value of the 'Upgrade' request header.
652  *                       You can get this request header value by passing
653  *                       #MHD_HTTP_HEADER_UPGRADE to
654  *                       #MHD_lookup_connection_value().
655  * @return A value of `enum MHD_WEBSOCKET_STATUS`.
656  *         0 means the 'Upgrade' request header is correct
657  *         for a websocket request,
658  *         a value less than zero means that the 'Upgrade' header isn't
659  *         valid for a websocket request.
660  * @ingroup websocket
661  */
662 _MHD_EXTERN enum MHD_WEBSOCKET_STATUS
663 MHD_websocket_check_upgrade_header (const char *upgrade_header);
664 
665 /**
666  * Checks the value of the 'Sec-WebSocket-Version' HTTP request header.
667  * Websocket requests require the value '13'
668  * in the 'Sec-WebSocket-Version' HTTP request header.
669  *
670  * @param version_header The value of the 'Sec-WebSocket-Version'
671  *                       request header.
672  *                       You can get this request header value by passing
673  *                       #MHD_HTTP_HEADER_SEC_WEBSOCKET_VERSION to
674  *                       #MHD_lookup_connection_value().
675  * @return A value of `enum MHD_WEBSOCKET_STATUS`.
676  *         0 means the 'Sec-WebSocket-Version' request header is correct
677  *         for a websocket request,
678  *         a value less than zero means that the 'Sec-WebSocket-Version'
679  *         header isn't valid for a websocket request.
680  * @ingroup websocket
681  */
682 _MHD_EXTERN enum MHD_WEBSOCKET_STATUS
683 MHD_websocket_check_version_header (const char *version_header);
684 
685 /**
686  * Creates the response value for the 'Sec-WebSocket-Key' HTTP request header.
687  * The generated value must be sent to the client
688  * as 'Sec-WebSocket-Accept' HTTP response header.
689  *
690  * @param sec_websocket_key The value of the 'Sec-WebSocket-Key'
691  *                          request header.
692  *                          You can get this request header value by passing
693  *                          #MHD_HTTP_HEADER_SEC_WEBSOCKET_KEY to
694  *                          #MHD_lookup_connection_value().
695  * @param[out] sec_websocket_accept The response buffer, which will receive
696  *                                  the generated 'Sec-WebSocket-Accept' header.
697  *                                  This buffer must be at least 29 bytes long and
698  *                                  will contain the response value plus
699  *                                  a terminating NUL on success.
700  * @return A value of `enum MHD_WEBSOCKET_STATUS`.
701  *         Typically 0 on success or less than 0 on errors.
702  * @ingroup websocket
703  */
704 _MHD_EXTERN enum MHD_WEBSOCKET_STATUS
705 MHD_websocket_create_accept_header (const char *sec_websocket_key,
706                                     char *sec_websocket_accept);
707 
708 /**
709  * Creates a new websocket stream, used for decoding/encoding.
710  *
711  * @param[out] ws The websocket stream
712  * @param flags Combination of `enum MHD_WEBSOCKET_FLAG` values
713  *              to modify the behavior of the websocket stream.
714  * @param max_payload_size The maximum size for incoming payload
715  *                         data in bytes. Use 0 to allow each size.
716  * @return A value of `enum MHD_WEBSOCKET_STATUS`.
717  *         Typically 0 on success or less than 0 on errors.
718  * @ingroup websocket
719  */
720 _MHD_EXTERN enum MHD_WEBSOCKET_STATUS
721 MHD_websocket_stream_init (struct MHD_WebSocketStream **ws,
722                            int flags,
723                            size_t max_payload_size);
724 
725 /**
726  * Creates a new websocket stream, used for decoding/encoding,
727  * but with custom memory functions for malloc, realloc and free.
728  * Also a random number generator can be specified for client mode.
729  *
730  * @param[out] ws The websocket stream
731  * @param flags Combination of `enum MHD_WEBSOCKET_FLAG` values
732  *              to modify the behavior of the websocket stream.
733  * @param max_payload_size The maximum size for incoming payload
734  *                         data in bytes. Use 0 to allow each size.
735  * @param callback_malloc  The callback function for `malloc()`.
736  * @param callback_realloc The callback function for `realloc()`.
737  * @param callback_free    The callback function for `free()`.
738  * @param cls_rng          A closure for the random number generator callback.
739  *                         This is only required when
740  *                         MHD_WEBSOCKET_FLAG_CLIENT is passed in `flags`.
741  *                         The given value is passed to
742  *                         the random number generator.
743  *                         May be NULL if not needed.
744  *                         Should be NULL when you are
745  *                         not using MHD_WEBSOCKET_FLAG_CLIENT.
746  * @param callback_rng     A callback function for a
747  *                         secure random number generator.
748  *                         This is only required when
749  *                         MHD_WEBSOCKET_FLAG_CLIENT is passed in `flags`.
750  *                         Should be NULL otherwise.
751  * @return A value of `enum MHD_WEBSOCKET_STATUS`.
752  *         Typically 0 on success or less than 0 on errors.
753  * @ingroup websocket
754  */
755 _MHD_EXTERN enum MHD_WEBSOCKET_STATUS
756 MHD_websocket_stream_init2 (struct MHD_WebSocketStream **ws,
757                             int flags,
758                             size_t max_payload_size,
759                             MHD_WebSocketMallocCallback callback_malloc,
760                             MHD_WebSocketReallocCallback callback_realloc,
761                             MHD_WebSocketFreeCallback callback_free,
762                             void *cls_rng,
763                             MHD_WebSocketRandomNumberGenerator callback_rng);
764 
765 /**
766  * Frees a websocket stream
767  *
768  * @param ws The websocket stream. This value may be NULL.
769  * @return A value of `enum MHD_WEBSOCKET_STATUS`.
770  *         Typically 0 on success or less than 0 on errors.
771  * @ingroup websocket
772  */
773 _MHD_EXTERN enum MHD_WEBSOCKET_STATUS
774 MHD_websocket_stream_free (struct MHD_WebSocketStream *ws);
775 
776 /**
777  * Invalidates a websocket stream.
778  * After invalidation a websocket stream cannot be used for decoding anymore.
779  * Encoding is still possible.
780  *
781  * @param ws The websocket stream.
782  * @return A value of `enum MHD_WEBSOCKET_STATUS`.
783  *         Typically 0 on success or less than 0 on errors.
784  * @ingroup websocket
785  */
786 _MHD_EXTERN enum MHD_WEBSOCKET_STATUS
787 MHD_websocket_stream_invalidate (struct MHD_WebSocketStream *ws);
788 
789 /**
790  * Queries whether a websocket stream is valid.
791  * Invalidated websocket streams cannot be used for decoding anymore.
792  * Encoding is still possible.
793  *
794  * @param ws The websocket stream.
795  * @return A value of `enum MHD_WEBSOCKET_VALIDITY`.
796  * @ingroup websocket
797  */
798 _MHD_EXTERN enum MHD_WEBSOCKET_VALIDITY
799 MHD_websocket_stream_is_valid (struct MHD_WebSocketStream *ws);
800 
801 /**
802  * Decodes a byte sequence for a websocket stream.
803  * Decoding is done until either a frame is complete or
804  * the end of the byte sequence is reached.
805  *
806  * @param ws The websocket stream.
807  * @param streambuf The byte sequence for decoding.
808  *                  Typically that what you received via `recv()`.
809  * @param streambuf_len The length of the byte sequence @a streambuf
810  * @param[out] streambuf_read_len The number of bytes which has been processed
811  *                                by this call. This value may be less
812  *                                than @a streambuf_len when a frame is decoded
813  *                                before the end of the buffer is reached.
814  *                                The remaining bytes of @a buf must be passed
815  *                                to the next call of this function.
816  * @param[out] payload Pointer to a variable, which receives a buffer
817  *                     with the decoded payload data.
818  *                     If no decoded data is available this is NULL.
819  *                     When the returned value is not NULL then
820  *                     the buffer contains always @a payload_len bytes plus
821  *                     one terminating NUL character.
822  *                     The caller must free this buffer
823  *                     using #MHD_websocket_free().
824  *                     If you passed the flag
825  *                     #MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR
826  *                     upon creation of this websocket stream and
827  *                     a decoding error occurred
828  *                     (function return value less than 0), then this
829  *                     buffer contains a generated close frame
830  *                     which must be sent via the socket to the recipient.
831  *                     If you passed the flag #MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS
832  *                     upon creation of the websocket stream then
833  *                     this payload may only be a part of the complete message.
834  *                     Only complete UTF-8 sequences are returned
835  *                     for fragmented text frames.
836  *                     If necessary the UTF-8 sequence will be completed
837  *                     with the next text fragment.
838  * @param[out] payload_len The length of the result payload buffer in bytes.
839  *
840  * @return A value of `enum MHD_WEBSOCKET_STATUS`.
841  *         This is greater than 0 if a frame has is complete,
842  *         equal to 0 if more data is needed an less than 0 on errors.
843  * @ingroup websocket
844  */
845 _MHD_EXTERN enum MHD_WEBSOCKET_STATUS
846 MHD_websocket_decode (struct MHD_WebSocketStream *ws,
847                       const char *streambuf,
848                       size_t streambuf_len,
849                       size_t *streambuf_read_len,
850                       char **payload,
851                       size_t *payload_len);
852 
853 /**
854  * Splits the payload of a decoded close frame.
855  *
856  * @param payload The payload of the close frame.
857  *                This parameter may only be NULL if @a payload_len is 0.
858  * @param payload_len The length of @a payload.
859  * @param[out] reason_code The numeric close reason.
860  *                         If there was no close reason, this is
861  *                         #MHD_WEBSOCKET_CLOSEREASON_NO_REASON.
862  *                         Compare with `enum MHD_WEBSOCKET_CLOSEREASON`.
863  *                         This parameter is optional and may be NULL.
864  * @param[out] reason_utf8 The literal close reason.
865  *                         If there was no literal close reason, this is NULL.
866  *                         This parameter is optional and may be NULL.
867  *                         Please note that no memory is allocated
868  *                         in this function.
869  *                         If not NULL the returned value of this parameter
870  *                         points to a position in the specified @a payload.
871  * @param[out] reason_utf8_len The length of the literal close reason.
872  *                             If there was no literal close reason, this is 0.
873  *                             This parameter is optional and may be NULL.
874  *
875  * @return A value of `enum MHD_WEBSOCKET_STATUS`.
876  *         This is #MHD_WEBSOCKET_STATUS_OK (= 0) on success
877  *         or a value less than 0 on errors.
878  * @ingroup websocket
879  */
880 _MHD_EXTERN enum MHD_WEBSOCKET_STATUS
881 MHD_websocket_split_close_reason (const char *payload,
882                                   size_t payload_len,
883                                   unsigned short *reason_code,
884                                   const char **reason_utf8,
885                                   size_t *reason_utf8_len);
886 
887 /**
888  * Encodes an UTF-8 encoded text into websocket text frame.
889  *
890  * @param ws The websocket stream.
891  * @param payload_utf8 The UTF-8 encoded text to send.
892  *                     This may be NULL if payload_utf8_len is 0.
893  * @param payload_utf8_len The length of the UTF-8 encoded text in bytes.
894  * @param fragmentation A value of `enum MHD_WEBSOCKET_FRAGMENTATION`
895  *                      to specify the fragmentation behavior.
896  *                      Specify MHD_WEBSOCKET_FRAGMENTATION_NONE
897  *                      if you don't want to use fragmentation.
898  * @param[out] frame This variable receives a buffer with the encoded frame.
899  *                   This is what you typically send via `send()` to the recipient.
900  *                   If no encoded data is available this is NULL.
901  *                   When this variable is not NULL then the buffer contains always
902  *                   @a frame_len bytes plus one terminating NUL character.
903  *                   The caller must free this buffer using #MHD_websocket_free().
904  * @param[out] frame_len The length of the encoded frame in bytes.
905  * @param[out] utf8_step This parameter is required for fragmentation and
906  *                       should be NULL if no fragmentation is used.
907  *                       It contains information about the last encoded
908  *                       UTF-8 sequence and is required to continue a previous
909  *                       UTF-8 sequence when fragmentation is used.
910  *                       `enum MHD_WEBSOCKET_UTF8STEP` is for this value.
911  *                       If you start a new fragment using
912  *                       MHD_WEBSOCKET_FRAGMENTATION_NONE or
913  *                       MHD_WEBSOCKET_FRAGMENTATION_FIRST the value
914  *                       of this variable will be initialized
915  *                       to MHD_WEBSOCKET_UTF8STEP_NORMAL.
916  *
917  * @return A value of `enum MHD_WEBSOCKET_STATUS`.
918  *         This is #MHD_WEBSOCKET_STATUS_OK (= 0) on success
919  *         or a value less than 0 on errors.
920  * @ingroup websocket
921  */
922 _MHD_EXTERN enum MHD_WEBSOCKET_STATUS
923 MHD_websocket_encode_text (struct MHD_WebSocketStream *ws,
924                            const char *payload_utf8,
925                            size_t payload_utf8_len,
926                            int fragmentation,
927                            char **frame,
928                            size_t *frame_len,
929                            int *utf8_step);
930 
931 /**
932  * Encodes binary data into websocket binary frame.
933  *
934  * @param ws The websocket stream.
935  * @param payload The binary data to send.
936  * @param payload_len The length of the binary data in bytes.
937  * @param fragmentation A value of `enum MHD_WEBSOCKET_FRAGMENTATION`
938  *                      to specify the fragmentation behavior.
939  *                      Specify MHD_WEBSOCKET_FRAGMENTATION_NONE
940  *                      if you don't want to use fragmentation.
941  * @param[out] frame This variable receives a buffer with
942  *                   the encoded binary frame.
943  *                   This is what you typically send via `send()`
944  *                   to the recipient.
945  *                   If no encoded frame is available this is NULL.
946  *                   When this variable is not NULL then the allocated buffer
947  *                   contains always @a frame_len bytes plus one terminating
948  *                   NUL character.
949  *                   The caller must free this buffer using #MHD_websocket_free().
950  * @param[out] frame_len The length of the result frame buffer in bytes.
951  *
952  * @return A value of `enum MHD_WEBSOCKET_STATUS`.
953  *         This is #MHD_WEBSOCKET_STATUS_OK (= 0) on success
954  *         or a value less than 0 on errors.
955  * @ingroup websocket
956  */
957 _MHD_EXTERN enum MHD_WEBSOCKET_STATUS
958 MHD_websocket_encode_binary (struct MHD_WebSocketStream *ws,
959                              const char *payload,
960                              size_t payload_len,
961                              int fragmentation,
962                              char **frame,
963                              size_t *frame_len);
964 
965 /**
966  * Encodes a websocket ping frame
967  *
968  * @param ws The websocket stream.
969  * @param payload The binary ping payload data to send.
970  *                This may be NULL if @a payload_len is 0.
971  * @param payload_len The length of the payload data in bytes.
972  *                    This may not exceed 125 bytes.
973  * @param[out] frame This variable receives a buffer with the encoded ping frame data.
974  *                   This is what you typically send via `send()` to the recipient.
975  *                   If no encoded frame is available this is NULL.
976  *                   When this variable is not NULL then the buffer contains always
977  *                   @a frame_len bytes plus one terminating NUL character.
978  *                   The caller must free this buffer using #MHD_websocket_free().
979  * @param[out] frame_len The length of the result frame buffer in bytes.
980  *
981  * @return A value of `enum MHD_WEBSOCKET_STATUS`.
982  *         This is #MHD_WEBSOCKET_STATUS_OK (= 0) on success
983  *         or a value less than 0 on errors.
984  * @ingroup websocket
985  */
986 _MHD_EXTERN enum MHD_WEBSOCKET_STATUS
987 MHD_websocket_encode_ping (struct MHD_WebSocketStream *ws,
988                            const char *payload,
989                            size_t payload_len,
990                            char **frame,
991                            size_t *frame_len);
992 
993 /**
994  * Encodes a websocket pong frame
995  *
996  * @param ws The websocket stream.
997  * @param payload The binary pong payload data, which should be
998  *                the decoded payload from the received ping frame.
999  *                This may be NULL if @a payload_len is 0.
1000  * @param payload_len The length of the payload data in bytes.
1001  *                    This may not exceed 125 bytes.
1002  * @param[out] frame This variable receives a buffer with
1003  *                   the encoded pong frame data.
1004  *                   This is what you typically send via `send()`
1005  *                   to the recipient.
1006  *                   If no encoded frame is available this is NULL.
1007  *                   When this variable is not NULL then the buffer
1008  *                   contains always @a frame_len bytes plus one
1009  *                   terminating NUL character.
1010  *                   The caller must free this buffer
1011  *                   using #MHD_websocket_free().
1012  * @param[out] frame_len The length of the result frame buffer in bytes.
1013  *
1014  * @return A value of `enum MHD_WEBSOCKET_STATUS`.
1015  *         This is #MHD_WEBSOCKET_STATUS_OK (= 0) on success
1016  *         or a value less than 0 on errors.
1017  * @ingroup websocket
1018  */
1019 _MHD_EXTERN enum MHD_WEBSOCKET_STATUS
1020 MHD_websocket_encode_pong (struct MHD_WebSocketStream *ws,
1021                            const char *payload,
1022                            size_t payload_len,
1023                            char **frame,
1024                            size_t *frame_len);
1025 
1026 /**
1027  * Encodes a websocket close frame
1028  *
1029  * @param ws The websocket stream.
1030  * @param reason_code The reason for close.
1031  *                    You can use `enum MHD_WEBSOCKET_CLOSEREASON`
1032  *                    for typical reasons,
1033  *                    but you are not limited to these values.
1034  *                    The allowed values are specified in RFC 6455 7.4.
1035  *                    If you don't want to enter a reason, you can specify
1036  *                    #MHD_WEBSOCKET_CLOSEREASON_NO_REASON then
1037  *                    no reason is encoded.
1038  * @param reason_utf8 An UTF-8 encoded text reason why the connection is closed.
1039  *                    This may be NULL if @a reason_utf8_len is 0.
1040  *                    This must be NULL if @a reason_code is
1041  *                    #MHD_WEBSOCKET_CLOSEREASON_NO_REASON (= 0).
1042  * @param reason_utf8_len The length of the UTF-8 encoded text reason in bytes.
1043  *                        This may not exceed 123 bytes.
1044  * @param[out] frame This variable receives a buffer with
1045  *                   the encoded close frame.
1046  *                   This is what you typically send via `send()`
1047  *                   to the recipient.
1048  *                   If no encoded frame is available this is NULL.
1049  *                   When this variable is not NULL then the buffer
1050  *                   contains always @a frame_len bytes plus
1051  *                   one terminating NUL character.
1052  *                   The caller must free this buffer
1053  *                   using #MHD_websocket_free().
1054  * @param[out] frame_len The length of the result frame buffer in bytes.
1055  *
1056  * @return A value of `enum MHD_WEBSOCKET_STATUS`.
1057  *         This is #MHD_WEBSOCKET_STATUS_OK (= 0) on success
1058  *         or a value less than 0 on errors.
1059  * @ingroup websocket
1060  */
1061 _MHD_EXTERN enum MHD_WEBSOCKET_STATUS
1062 MHD_websocket_encode_close (struct MHD_WebSocketStream *ws,
1063                             unsigned short reason_code,
1064                             const char *reason_utf8,
1065                             size_t reason_utf8_len,
1066                             char **frame,
1067                             size_t *frame_len);
1068 
1069 /**
1070  * Allocates memory with the associated 'malloc' function
1071  * of the websocket stream
1072  *
1073  * @param ws The websocket stream.
1074  * @param buf_len The length of the memory to allocate in bytes
1075  *
1076  * @return The allocated memory on success or NULL on failure.
1077  * @ingroup websocket
1078  */
1079 _MHD_EXTERN void *
1080 MHD_websocket_malloc (struct MHD_WebSocketStream *ws,
1081                       size_t buf_len);
1082 
1083 /**
1084  * Reallocates memory with the associated 'realloc' function
1085  * of the websocket stream
1086  *
1087  * @param ws The websocket stream.
1088  * @param buf The previously allocated memory or NULL
1089  * @param new_buf_len The new length of the memory in bytes
1090  *
1091  * @return The allocated memory on success or NULL on failure.
1092  *         If NULL is returned the previously allocated buffer
1093  *         remains valid.
1094  * @ingroup websocket
1095  */
1096 _MHD_EXTERN void *
1097 MHD_websocket_realloc (struct MHD_WebSocketStream *ws,
1098                        void *buf,
1099                        size_t new_buf_len);
1100 
1101 /**
1102  * Frees memory with the associated 'free' function
1103  * of the websocket stream
1104  *
1105  * @param ws The websocket stream.
1106  * @param buf The previously allocated memory or NULL
1107  *
1108  * @return A value of `enum MHD_WEBSOCKET_STATUS`.
1109  *         This is #MHD_WEBSOCKET_STATUS_OK (= 0) on success
1110  *         or a value less than 0 on errors.
1111  * @ingroup websocket
1112  */
1113 _MHD_EXTERN int
1114 MHD_websocket_free (struct MHD_WebSocketStream *ws,
1115                     void *buf);
1116 
1117 #if 0                           /* keep Emacsens' auto-indent happy */
1118 {
1119 #endif
1120 #ifdef __cplusplus
1121 }
1122 #endif
1123 
1124 #endif
1125